diff --git a/gtk4/inc/TGtk4PadPainter.h b/gtk4/inc/TGtk4PadPainter.h index d3eb04d..a5b4e48 100644 --- a/gtk4/inc/TGtk4PadPainter.h +++ b/gtk4/inc/TGtk4PadPainter.h @@ -81,7 +81,9 @@ friend class TGtk4Canvas; void DrawPolyMarker(Int_t n, const Double_t *x, const Double_t *y) override; void DrawPolyMarker(Int_t n, const Float_t *x, const Float_t *y) override; - void DrawTTFglyphs(Int_t x, Int_t y, TTFhandle &ttf, ETextMode mode) override; + void DrawTTFglyphs(Int_t x, Int_t y, TTFhandle &ttf, ETextMode mode) override; + + void DrawImage(TImage *img, Int_t x, Int_t y, Int_t flags = 0) override; Bool_t IsSupportAlpha() const override { return kTRUE; } diff --git a/gtk4/src/TGtk4PadPainter.cxx b/gtk4/src/TGtk4PadPainter.cxx index 9e39274..dc95db3 100644 --- a/gtk4/src/TGtk4PadPainter.cxx +++ b/gtk4/src/TGtk4PadPainter.cxx @@ -19,8 +19,8 @@ #include "TROOT.h" #include "TColor.h" #include "RStipples.h" - #include "TTFhandle.h" +#include "TImage.h" #include #include @@ -28,6 +28,7 @@ #include "Gtk4DrawArea.h" #include +#include #include @@ -553,3 +554,34 @@ void TGtk4PadPainter::DrawTTFglyphs(Int_t px, Int_t py, TTFhandle &ttf, ETextMod ctx->mask(surface, px + bx, py + by); } } + + +//////////////////////////////////////////////////////////////////////////////// +/// Render TTF glyphs on drawable area + +void TGtk4PadPainter::DrawImage(TImage *img, Int_t px, Int_t py, Int_t) +{ + // position inside the pad is provided, therefore shift it to global image + px += fPad->UtoAbsPixel(0); + py += fPad->VtoAbsPixel(1); + + auto width = img->GetWidth(); + auto height = img->GetHeight(); + auto argbBuffer = (unsigned char*) img->GetArgbArray(); + + auto ctx = fDrawArea->GetContext(); + + int stride = Cairo::ImageSurface::format_stride_for_width(Cairo::Surface::Format::ARGB32, width); + + // 2. Wrap your raw memory pointer into a Cairo Surface. + // This borrows the memory pointer without making a deep copy. + Cairo::RefPtr surface = + Cairo::ImageSurface::create(argbBuffer, Cairo::Surface::Format::ARGB32, width, height, stride); + + // 3. Set the surface as the source pattern in the context + // (0, 0) specifies the top-left offset to place the image + ctx->set_source(surface, px, py); + + // 4. Paint the pattern onto the context canvas + ctx->paint(); +} diff --git a/qt6/inc/TQt6PadPainter.h b/qt6/inc/TQt6PadPainter.h index d92e57b..4a1544c 100644 --- a/qt6/inc/TQt6PadPainter.h +++ b/qt6/inc/TQt6PadPainter.h @@ -93,6 +93,8 @@ friend class TQt6Canvas; void DrawTTFglyphs(Int_t px, Int_t py, TTFhandle &ttf, [[maybe_unused]] ETextMode mode) override; + void DrawImage(TImage *img, Int_t x, Int_t y, Int_t flags = 0) override; + private: //Let's make this clear: TQt6PadPainter(const TQt6PadPainter &rhs) = delete; diff --git a/qt6/src/TQt6PadPainter.cxx b/qt6/src/TQt6PadPainter.cxx index b524627..32b244f 100644 --- a/qt6/src/TQt6PadPainter.cxx +++ b/qt6/src/TQt6PadPainter.cxx @@ -19,18 +19,16 @@ #include "TROOT.h" #include "TColor.h" #include "RStipples.h" +#include "TTFhandle.h" +#include "TImage.h" #include #include #include "QPaintWidget.h" -#include "TTFhandle.h" - - -#include -#include #include +#include #include using namespace ROOT::Experimental; @@ -492,3 +490,33 @@ void TQt6PadPainter::DrawTTFglyphs(Int_t px, Int_t py, TTFhandle &ttf, [[maybe_u } } +void TQt6PadPainter::DrawImage(TImage *img, Int_t px, Int_t py, Int_t) +{ + // position inside the pad is provided, therefore shift it to global image + px += fPad->UtoAbsPixel(0); + py += fPad->VtoAbsPixel(1); + + auto width = img->GetWidth(); + auto height = img->GetHeight(); + auto argbBuffer = (const uchar*) img->GetArgbArray(); + + auto painter = fPaintWidget->getPainter(); + + int bytesPerLine = width * 4; + + // 1. Wrap the raw memory array into a QImage. + // This constructor does NOT copy the pixel data; it points directly to your buffer. + QImage image( + argbBuffer, + width, + height, + bytesPerLine, + QImage::Format_ARGB32 + ); + + // 2. Draw the image using QPainter + // (0, 0) is the top-left coordinate where the image will be drawn + painter->drawImage(px, py, image); +} + + diff --git a/raylib/inc/TRaylibPadPainter.h b/raylib/inc/TRaylibPadPainter.h index 4085315..59303b5 100644 --- a/raylib/inc/TRaylibPadPainter.h +++ b/raylib/inc/TRaylibPadPainter.h @@ -97,6 +97,8 @@ friend class TRaylibCanvas; void DrawTTFglyphs(Int_t px, Int_t py, TTFhandle &ttf, [[maybe_unused]] ETextMode mode) override; + void DrawImage(TImage *img, Int_t x, Int_t y, Int_t flags = 0) override; + private: TRaylibPadPainter(const TRaylibPadPainter &) = delete; TRaylibPadPainter(TRaylibPadPainter &&) = delete; diff --git a/raylib/src/TRaylibPadPainter.cxx b/raylib/src/TRaylibPadPainter.cxx index e06d631..fa8a10c 100644 --- a/raylib/src/TRaylibPadPainter.cxx +++ b/raylib/src/TRaylibPadPainter.cxx @@ -19,9 +19,8 @@ #include "TPoint.h" #include "TROOT.h" #include "TColor.h" - -#include "RStipples.h" #include "TTFhandle.h" +#include "TImage.h" #include @@ -501,6 +500,57 @@ void TRaylibPadPainter::DrawTTFglyphs(Int_t px, Int_t py, TTFhandle &ttf, [[mayb } } +//////////////////////////////////////////////////////////////////////////////// +/// Render image on drawable area + +void TRaylibPadPainter::DrawImage(TImage *img, Int_t px, Int_t py, Int_t) +{ + px += fPad->UtoAbsPixel(0); + py += fPad->VtoAbsPixel(1); + + auto width = img->GetWidth(); + auto height = img->GetHeight(); + auto argbBuffer = (unsigned char*) img->GetArgbArray(); + + int pixelCount = width * height; + + std::vector rgbaData(pixelCount * 4); + + // Convert ARGB/BGRA to RGBA in-memory + for (int i = 0; i < pixelCount; i++) { + int srcIdx = i * 4; + int dstIdx = i * 4; + + // Assuming source is Cairo's Little-Endian BGRA format [B, G, R, A]: + rgbaData[dstIdx + 0] = argbBuffer[srcIdx + 2]; // Red + rgbaData[dstIdx + 1] = argbBuffer[srcIdx + 1]; // Green + rgbaData[dstIdx + 2] = argbBuffer[srcIdx + 0]; // Blue + rgbaData[dstIdx + 3] = argbBuffer[srcIdx + 3]; // Alpha + } + + Image rayimg = { + .data = rgbaData.data(), + .width = (int)width, + .height = (int)height, + .mipmaps = 1, + .format =PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 + }; + + // Upload to GPU memory + Texture2D texture = LoadTextureFromImage(rayimg); + + DrawTexture(texture, px, py, WHITE); + + // Always unload transient textures to avoid GPU memory leaks! + // but we should wait until rendering is finished + fTextures.push_back(texture); +} + + + +//////////////////////////////////////////////////////////////////////////////// +/// Cleanup context + void TRaylibPadPainter::CleanupTextures() { for (auto &texture : fTextures)