1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
|
// Gmsh - Copyright (C) 1997-2021 C. Geuzaine, J.-F. Remacle
//
// See the LICENSE.txt file for license information. Please report all
// issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
//
// Contributed by Jonathan Lambrechts
#include "drawContextFltkStringTexture.h"
#include <algorithm>
// FIXME: hack for current version of mingw
#if defined(WIN32) && !defined(GL_TEXTURE_RECTANGLE_ARB)
#define GL_TEXTURE_RECTANGLE_ARB 0x84F5
#endif
class drawContextFltkStringTexture::queueString {
public:
typedef struct {
std::string text;
GLfloat x, y, z;
GLfloat r, g, b, alpha;
int fontSize, fontId;
int width;
int height;
} element;
private:
std::vector<element> _elements;
int _totalWidth, _maxHeight;
public:
queueString()
{
_totalWidth = 0;
_maxHeight = 0;
}
void append(const element &elem)
{
if(_totalWidth + elem.width > 1000) flush();
_elements.push_back(elem);
_totalWidth += elem.width;
_maxHeight = std::max(_maxHeight, elem.height);
}
void flush()
{
if(_elements.empty()) return;
// 1000 should be _totalWidth but it does not work
int w = 1000, h = _maxHeight;
Fl_Offscreen offscreen = fl_create_offscreen(w, h);
fl_begin_offscreen(offscreen);
fl_color(0, 0, 0);
fl_rectf(0, 0, w, h);
fl_color(255, 255, 255);
int pos = 0;
for(auto it = _elements.begin(); it != _elements.end(); ++it) {
fl_font(it->fontId, it->fontSize);
fl_draw(it->text.c_str(), pos, it->height - fl_descent());
pos += it->width;
}
uchar *data = fl_read_image(nullptr, 0, 0, w, h);
for(int i = 0; i < w * h; ++i) { data[i] = data[i * 3]; }
fl_end_offscreen();
fl_delete_offscreen(offscreen);
// setup matrices
GLint matrixMode;
GLuint textureId;
glGetIntegerv(GL_MATRIX_MODE, &matrixMode);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
// FIXME: this is not correct with high-resolution graphics, as w(), h() are
// in FLTK coordinates, and glRasterPos uses true pixels.
// The size of the QUAD needs to be changed, too.
float winw = Fl_Window::current()->w();
float winh = Fl_Window::current()->h();
glScalef(2.0f / winw, 2.0f / winh, 1.0f);
glTranslatef(-winw / 2.0f, -winh / 2.0f, 0.0f);
// write the texture on screen
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glPushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, textureId);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_ALPHA, w, h, 0, GL_ALPHA,
GL_UNSIGNED_BYTE, data);
// glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_SRC0_ALPHA);
// printf("error %i %s\n", __LINE__, gluErrorString(glGetError()));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
pos = 0;
for(auto it = _elements.begin(); it != _elements.end(); ++it) {
glTranslatef(it->x, it->y, it->z);
glColor4f(it->r, it->g, it->b, it->alpha);
int Lx = it->width;
int Ly = it->height;
glBegin(GL_QUADS);
glTexCoord2f(pos, 0);
glVertex2f(0.0f, Ly);
glTexCoord2f(pos + Lx, 0);
glVertex2f(Lx, Ly);
glTexCoord2f(pos + Lx, Ly);
glVertex2f(Lx, 0.0f);
glTexCoord2f(pos, Ly);
glVertex2f(0.0f, 0.0f);
glEnd();
pos += Lx;
glTranslatef(-it->x, -it->y, -it->z);
}
glDeleteTextures(1, &textureId);
glPopAttrib();
// reset original matrices
glPopMatrix(); // GL_MODELVIEW
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(matrixMode);
_elements.clear();
_maxHeight = 0;
_totalWidth = 0;
delete[] data;
}
};
void drawContextFltkStringTexture::flushString() { _queue->flush(); }
// ensure the surface is large enough
void drawContextFltkStringTexture::drawString(const char *str)
{
GLfloat pos[4], color[4];
glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
glGetFloatv(GL_CURRENT_COLOR, color);
queueString::element elem = {str,
pos[0],
pos[1],
pos[2],
color[0],
color[1],
color[2],
color[3],
_currentFontSize,
_currentFontId,
(int)getStringWidth(str) + 1,
getStringHeight()};
_queue->append(elem);
}
drawContextFltkStringTexture::~drawContextFltkStringTexture() { delete _queue; }
drawContextFltkStringTexture::drawContextFltkStringTexture()
{
_queue = new queueString;
}
void drawContextFltkStringTexture::setFont(int fontid, int fontsize)
{
drawContextFltk::setFont(fontid, fontsize);
_currentFontId = fontid;
_currentFontSize = fontsize;
}
|