Skip to content
Snippets Groups Projects
Commit 342c1969 authored by Jonathan Lambrechts's avatar Jonathan Lambrechts
Browse files

cairo string now faster than native (at least on my laptop : 35x)

parent c9c76a5f
No related branches found
No related tags found
No related merge requests found
......@@ -10,61 +10,127 @@
#if defined(HAVE_CAIRO)
#include <cairo/cairo.h>
//mostly borrowed from fltk function gl_texture_fifo::display_texture
static void _data2gl (int width, int height, unsigned char *data,
int Lx, int Ly, unsigned int _textureId)
{
//setup matrices
GLint matrixMode;
glGetIntegerv (GL_MATRIX_MODE, &matrixMode);
glMatrixMode (GL_PROJECTION);
glPushMatrix();
glLoadIdentity ();
glMatrixMode (GL_MODELVIEW);
glPushMatrix();
glLoadIdentity ();
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
GLfloat pos[4];
glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
class drawContextFltkCairo::queueString {
public :
typedef struct {
std::string text;
GLfloat x, y, z;
GLfloat r, g, b, alpha;
int fontSize;
cairo_font_face_t *fontFace;
cairo_text_extents_t extent;
} element;
private:
std::vector<element> _elements;
double _totalWidth, _maxHeight;
public:
queueString()
{
_totalWidth = 0;
_maxHeight = 0;
}
~queueString()
{
for(std::vector<element>::iterator it = _elements.begin(); it != _elements.end(); ++it) {
cairo_font_face_destroy(it->fontFace);
}
}
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);
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, _textureId);
glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_ALPHA, width, height, 0,
GL_ALPHA, GL_UNSIGNED_BYTE, data);
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_SRC0_ALPHA);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTranslatef(pos[0] /*+ rect->x_bearing*/, pos[1] /*+ rect->y_bearing*/, pos[2]);
glBegin (GL_QUADS);
glTexCoord2f (0, 0);
glVertex2f (0.0f, Ly);
glTexCoord2f (Lx, 0);
glVertex2f (Lx, Ly);
glTexCoord2f (Lx, Ly);
glVertex2f (Lx, 0.0f);
glTexCoord2f (0, Ly);
glVertex2f (0.0f, 0.0f);
glEnd ();
glPopAttrib();
// reset original matrices
glPopMatrix(); // GL_MODELVIEW
glMatrixMode (GL_PROJECTION);
glPopMatrix();
glMatrixMode (matrixMode);
}
void append(const element &elem)
{
if (_totalWidth + elem.extent.width > 1000)
flush();
_elements.push_back(elem);
_totalWidth += elem.extent.width;
_maxHeight = std::max(_maxHeight, elem.extent.height);
}
void flush()
{
cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_A8, _totalWidth, _maxHeight);
cairo_t *cr = cairo_create(surface);
float pos = 0;
cairo_set_source_rgba (cr, 0., 0., 0., 0);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_paint(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_set_source_rgba(cr, 1, 1, 1, 1);
for(std::vector<element>::iterator it = _elements.begin(); it != _elements.end(); ++it) {
cairo_move_to(cr, pos - it->extent.x_bearing, -it->extent.y_bearing);
cairo_set_font_size(cr, it->fontSize);
cairo_set_font_face(cr, it->fontFace);
cairo_show_text(cr, it->text.c_str());
cairo_font_face_destroy(it->fontFace);
pos += it->extent.width;
}
cairo_destroy(cr);
//setup matrices
GLint matrixMode;
GLuint textureId;
glGetIntegerv (GL_MATRIX_MODE, &matrixMode);
glMatrixMode (GL_PROJECTION);
glPushMatrix();
glLoadIdentity ();
glMatrixMode (GL_MODELVIEW);
glPushMatrix();
glLoadIdentity ();
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, cairo_image_surface_get_width(surface), cairo_image_surface_get_height(surface), 0,
GL_ALPHA, GL_UNSIGNED_BYTE, cairo_image_surface_get_data(surface));
//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(std::vector<element>::iterator it = _elements.begin(); it != _elements.end(); ++it) {
glTranslatef(it->x, it->y, it->z);
glColor4f(it->r, it->g, it->b, it->alpha);
float Lx = it->extent.width;
float Ly = it->extent.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;
cairo_surface_destroy(surface);
}
};
double drawContextFltkCairo::getStringWidth(const char *str)
{
......@@ -78,48 +144,24 @@ void drawContextFltkCairo::draw()
drawContextFltk::draw();
}
//ensure the surface is large enough
void drawContextFltkCairo::_resizeSurface(int w, int h)
void drawContextFltkCairo::flushString()
{
if (w > cairo_image_surface_get_width(_surface) ||
h > cairo_image_surface_get_height(_surface)) {
cairo_font_face_t *face = cairo_get_font_face(_cr);
cairo_matrix_t matrix;
cairo_get_font_matrix(_cr, &matrix);
cairo_destroy(_cr);
cairo_surface_destroy(_surface);
_surface = cairo_image_surface_create(CAIRO_FORMAT_A8, w, h);
_cr = cairo_create(_surface);
cairo_set_font_face(_cr, face);
cairo_set_font_matrix(_cr, &matrix);
}
_queue->flush();
}
//ensure the surface is large enough
void drawContextFltkCairo::drawString(const char *str)
{
GLfloat pos[4], color[4];
glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
glGetFloatv(GL_CURRENT_COLOR, color);
cairo_set_font_size(_cr, _currentFontSize);
cairo_text_extents_t extent;
cairo_text_extents(_cr, str, &extent);
_resizeSurface(extent.width + 2, extent.height + 2);
cairo_surface_t *surface = _surface;
cairo_t *cr = _cr;
cairo_set_source_rgba (cr, 0., 0., 0., 0);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_paint(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
extent.width +=1;
extent.height +=1;
cairo_move_to(cr, 1-extent.x_bearing, 1-extent.y_bearing);
cairo_set_source_rgba(cr, 1, 1, 1, 1);
cairo_show_text(cr, str);
if(!_textureId) glGenTextures (1, &_textureId);
_data2gl(cairo_image_surface_get_width(surface),
cairo_image_surface_get_height(surface),
cairo_image_surface_get_data(surface),
extent.width + 1, extent.height + 1, _textureId);
queueString::element elem = {str, pos[0], pos[1], pos[2], color[0], color[1], color[2], color[3],
_currentFontSize, cairo_get_font_face(_cr), extent};
cairo_font_face_reference(elem.fontFace);
_queue->append(elem);
// fltk version (fl_read_image is too slow)
/*Fl_Offscreen offscreen = fl_create_offscreen(100, 100);
fl_begin_offscreen(offscreen);
......@@ -144,14 +186,14 @@ drawContextFltkCairo::~drawContextFltkCairo()
{
cairo_destroy(_cr);
cairo_surface_destroy(_surface);
if(_textureId) glDeleteTextures(1, &_textureId);
delete _queue;
}
drawContextFltkCairo::drawContextFltkCairo()
{
_surface = cairo_image_surface_create(CAIRO_FORMAT_A8, 100, 100);
_surface = cairo_image_surface_create(CAIRO_FORMAT_A8, 1, 1);
_queue = new queueString;
_cr = cairo_create(_surface);
_textureId = 0;
_currentFontId = -1;
}
......@@ -189,6 +231,7 @@ void drawContextFltkCairo::setFont(int fontid, int fontsize)
_currentFontId = fontid;
}
cairo_set_font_size(_cr, fontsize);
_currentFontSize = fontsize;
}
#endif
......@@ -17,12 +17,12 @@ typedef struct _cairo_surface cairo_surface_t;
typedef struct _cairo cairo_t;
class drawContextFltkCairo : public drawContextFltk {
class queueString;
queueString *_queue;
cairo_surface_t *_surface;
cairo_t *_cr;
unsigned int _textureId;
int _currentFontId;
int _currentFontSize;
void _resizeSurface(int w, int h);
public:
void draw();
drawContextFltkCairo();
......@@ -30,6 +30,7 @@ class drawContextFltkCairo : public drawContextFltk {
double getStringWidth(const char *str);
//int getStringHeight();
//int getStringDescent();
void flushString();
void drawString(const char *str);
void setFont(int fontid, int fontsize);
std::string getName(){ return "Cairo"; }
......
......@@ -312,6 +312,7 @@ void openglWindow::draw()
_drawBorder();
}
}
drawContext::global()->flushString();
_lock = false;
}
......
......@@ -98,6 +98,7 @@ class drawContextGlobal {
virtual int getStringDescent(){ return 3; }
virtual void drawString(const char *str){}
virtual void resetFontTextures(){}
virtual void flushString(){}
virtual std::string getName(){ return "None"; }
};
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment