Add support of RGB image and Pixmap drawing to class Fl_OpenGL_Graphics_Driver.
Build and Test / build-linux (push) Has been cancelled
Build and Test / build-wayland (push) Has been cancelled
Build and Test / build-macos (push) Has been cancelled
Build and Test / build-windows (push) Has been cancelled

This allows to add RGB (and derived classes) or Pixmap images to widgets
layed over a GL scene.
This commit is contained in:
ManoloFLTK
2026-03-27 17:29:25 +01:00
parent ed2238bc2a
commit a692c91524
2 changed files with 113 additions and 0 deletions
@@ -97,6 +97,9 @@ public:
void text_extents(const char*, int n, int& dx, int& dy, int& w, int& h) FL_OVERRIDE;
int height() FL_OVERRIDE;
int descent() FL_OVERRIDE;
void cache_size(Fl_Image* img, int &width, int &height) override;
void draw_rgb(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) override;
void draw_pixmap(Fl_Pixmap *img, int XP, int YP, int WP, int HP, int cx, int cy) override;
};
#endif // FL_OPENGL_GRAPHICS_DRIVER_H
@@ -224,4 +224,114 @@ void Fl_OpenGL_Graphics_Driver::text_extents(const char *str, int n, int& dx, in
Fl_Surface_Device::pop_current();
}
void Fl_OpenGL_Graphics_Driver::cache_size(Fl_Image* img, int &width, int &height) {
width *= pixels_per_unit_; // useful at least for Fl_SVG_Image's
height *= pixels_per_unit_;
}
#ifndef GL_TEXTURE_RECTANGLE_ARB
# define GL_TEXTURE_RECTANGLE_ARB 0x84F5
#endif
#ifndef GL_UNSIGNED_INT_8_8_8_8_REV
# define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
#endif
static GLuint compute_texture_rectangle(Fl_RGB_Image *rgb)
{
GLuint texName;
glGenTextures(1, &texName);
// save GL parameters GL_UNPACK_ROW_LENGTH and GL_UNPACK_ALIGNMENT
GLint row_length, alignment;
glGetIntegerv(GL_UNPACK_ROW_LENGTH, &row_length);
glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
// put the bitmap in a texture
glPushAttrib(GL_TEXTURE_BIT);
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, texName);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ROW_LENGTH, (rgb->ld() ? rgb->ld() / rgb->d() : rgb->data_w()));
glPixelStorei(GL_UNPACK_ALIGNMENT, (rgb->d() == 3 ? 1 : 4));
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, (rgb->d() == 3 ? GL_RGB : GL_RGBA8),
rgb->data_w(), rgb->data_h(), 0,
(rgb->d() == 3 ? GL_RGB : GL_RGBA),
(rgb->d() == 3 ? GL_UNSIGNED_BYTE : GL_UNSIGNED_INT_8_8_8_8_REV),
rgb->array);
glPopAttrib();
// restore saved GL parameters
glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
return texName;
}
void Fl_OpenGL_Graphics_Driver::draw_rgb(Fl_RGB_Image *img,
int XP, int YP, int WP, int HP, int cx, int cy) {
int X, Y, W, H;
// Don't draw an empty image. Gray-scale image drawing not implemented yet.
if (!img->d() || !img->array || img->d() < 3) {
Fl_Graphics_Driver::draw_empty(img, XP, YP);
return;
}
if (start_image(img, XP, YP, WP, HP, cx, cy, X, Y, W, H)) {
return;
}
Fl_RGB_Image *partial_rgb = NULL;
if (cx || cy || W < img->w() || H < img->h()) { // Partial image drawing.
int d = img->d();
int ld = d * img->data_w();
float sx = img->data_w() / float(img->w()), sy = img->data_h() / float(img->h());
cx *= sx; cy *= sy;
partial_rgb = new Fl_RGB_Image(img->array + cy * ld + cx * d, W * sx, H * sy, d, ld);
img = partial_rgb;
}
GLuint texName = compute_texture_rectangle(img);
// GL_TRANSFORM_BIT for GL_PROJECTION
// GL_TEXTURE_BIT for GL_TEXTURE_RECTANGLE_ARB
glPushAttrib(GL_TRANSFORM_BIT | GL_TEXTURE_BIT /*|GL_COLOR_BUFFER_BIT*/);
//setup matrices
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glColor4ub(0xff, 0xff, 0xff, 0xff); // the color drawn through the texture seen as a kind of mask
float winw = Fl_Window::current()->as_gl_window()->pixel_w();
float winh = Fl_Window::current()->as_gl_window()->pixel_h();
float R = 2;
glScalef(R/winw, R/winh, 1.0f);
glTranslatef(-winw/R, -winh/R, 0.0f);
float s = Fl_Window::current()->as_gl_window()->pixels_per_unit();
int HH = s * H, WW = s * W;
float ox = s * X;
float oy = winh - s * Y;
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texName);
//write the texture on screen
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f); // draw lower left in world coordinates
glVertex2f(ox, oy);
glTexCoord2f(0.0f, (GLfloat)img->data_h()); // draw upper left in world coordinates
glVertex2f(ox, oy - HH);
glTexCoord2f((GLfloat)img->data_w(), (GLfloat)img->data_h()); // draw upper right in world coordinates
glVertex2f(ox + WW, oy - HH);
glTexCoord2f((GLfloat)img->data_w(), 0.0f); // draw lower right in world coordinates
glVertex2f(ox + WW, oy);
glEnd();
glDeleteTextures(1, &texName);
color(color()); // reset current color
// reset original matrices
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPopAttrib(); // GL_TRANSFORM_BIT | GL_TEXTURE_BIT
if (partial_rgb) delete partial_rgb;
}
void Fl_OpenGL_Graphics_Driver::draw_pixmap(Fl_Pixmap *img,
int XP, int YP, int WP, int HP, int cx, int cy) {
Fl_RGB_Image rgb(img);
draw_rgb(&rgb, XP, YP, WP, HP, cx, cy);
}
#endif