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
Branches
Tags
No related merge requests found
...@@ -10,12 +10,66 @@ ...@@ -10,12 +10,66 @@
#if defined(HAVE_CAIRO) #if defined(HAVE_CAIRO)
#include <cairo/cairo.h> #include <cairo/cairo.h>
//mostly borrowed from fltk function gl_texture_fifo::display_texture class drawContextFltkCairo::queueString {
static void _data2gl (int width, int height, unsigned char *data, public :
int Lx, int Ly, unsigned int _textureId) 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);
}
}
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 //setup matrices
GLint matrixMode; GLint matrixMode;
GLuint textureId;
glGetIntegerv (GL_MATRIX_MODE, &matrixMode); glGetIntegerv (GL_MATRIX_MODE, &matrixMode);
glMatrixMode (GL_PROJECTION); glMatrixMode (GL_PROJECTION);
glPushMatrix(); glPushMatrix();
...@@ -28,34 +82,41 @@ static void _data2gl (int width, int height, unsigned char *data, ...@@ -28,34 +82,41 @@ static void _data2gl (int width, int height, unsigned char *data,
glScalef (2.0f / winw, 2.0f / winh, 1.0f); glScalef (2.0f / winw, 2.0f / winh, 1.0f);
glTranslatef (-winw / 2.0f, -winh / 2.0f, 0.0f); glTranslatef (-winw / 2.0f, -winh / 2.0f, 0.0f);
//write the texture on screen //write the texture on screen
GLfloat pos[4];
glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
glEnable (GL_TEXTURE_RECTANGLE_ARB); glEnable (GL_TEXTURE_RECTANGLE_ARB);
glPushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT); glPushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT);
glDisable(GL_LIGHTING); glDisable(GL_LIGHTING);
glDisable (GL_DEPTH_TEST); glDisable (GL_DEPTH_TEST);
glEnable (GL_BLEND); glEnable (GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glGenTextures (1, &textureId);
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, _textureId); glBindTexture (GL_TEXTURE_RECTANGLE_ARB, textureId);
glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_ALPHA, width, height, 0, 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, data); GL_ALPHA, GL_UNSIGNED_BYTE, cairo_image_surface_get_data(surface));
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_SRC0_ALPHA); //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); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTranslatef(pos[0] /*+ rect->x_bearing*/, pos[1] /*+ rect->y_bearing*/, pos[2]); 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); glBegin (GL_QUADS);
glTexCoord2f (0, 0); glTexCoord2f (pos, 0);
glVertex2f (0.0f, Ly); glVertex2f (0.0f, Ly);
glTexCoord2f (Lx, 0); glTexCoord2f (pos + Lx, 0);
glVertex2f (Lx, Ly); glVertex2f (Lx, Ly);
glTexCoord2f (Lx, Ly); glTexCoord2f (pos + Lx, Ly);
glVertex2f (Lx, 0.0f); glVertex2f (Lx, 0.0f);
glTexCoord2f (0, Ly); glTexCoord2f (pos, Ly);
glVertex2f (0.0f, 0.0f); glVertex2f (0.0f, 0.0f);
glEnd (); glEnd ();
pos += Lx;
glTranslatef(-it->x, -it->y, -it->z);
}
glDeleteTextures(1, &textureId);
glPopAttrib(); glPopAttrib();
...@@ -64,7 +125,12 @@ static void _data2gl (int width, int height, unsigned char *data, ...@@ -64,7 +125,12 @@ static void _data2gl (int width, int height, unsigned char *data,
glMatrixMode (GL_PROJECTION); glMatrixMode (GL_PROJECTION);
glPopMatrix(); glPopMatrix();
glMatrixMode (matrixMode); glMatrixMode (matrixMode);
_elements.clear();
_maxHeight = 0;
_totalWidth = 0;
cairo_surface_destroy(surface);
} }
};
double drawContextFltkCairo::getStringWidth(const char *str) double drawContextFltkCairo::getStringWidth(const char *str)
{ {
...@@ -78,48 +144,24 @@ void drawContextFltkCairo::draw() ...@@ -78,48 +144,24 @@ void drawContextFltkCairo::draw()
drawContextFltk::draw(); drawContextFltk::draw();
} }
//ensure the surface is large enough void drawContextFltkCairo::flushString()
void drawContextFltkCairo::_resizeSurface(int w, int h)
{ {
if (w > cairo_image_surface_get_width(_surface) || _queue->flush();
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);
}
} }
//ensure the surface is large enough
void drawContextFltkCairo::drawString(const char *str) 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_t extent;
cairo_text_extents(_cr, str, &extent); cairo_text_extents(_cr, str, &extent);
_resizeSurface(extent.width + 2, extent.height + 2); queueString::element elem = {str, pos[0], pos[1], pos[2], color[0], color[1], color[2], color[3],
cairo_surface_t *surface = _surface; _currentFontSize, cairo_get_font_face(_cr), extent};
cairo_t *cr = _cr; cairo_font_face_reference(elem.fontFace);
_queue->append(elem);
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);
// fltk version (fl_read_image is too slow) // fltk version (fl_read_image is too slow)
/*Fl_Offscreen offscreen = fl_create_offscreen(100, 100); /*Fl_Offscreen offscreen = fl_create_offscreen(100, 100);
fl_begin_offscreen(offscreen); fl_begin_offscreen(offscreen);
...@@ -144,14 +186,14 @@ drawContextFltkCairo::~drawContextFltkCairo() ...@@ -144,14 +186,14 @@ drawContextFltkCairo::~drawContextFltkCairo()
{ {
cairo_destroy(_cr); cairo_destroy(_cr);
cairo_surface_destroy(_surface); cairo_surface_destroy(_surface);
if(_textureId) glDeleteTextures(1, &_textureId); delete _queue;
} }
drawContextFltkCairo::drawContextFltkCairo() 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); _cr = cairo_create(_surface);
_textureId = 0;
_currentFontId = -1; _currentFontId = -1;
} }
...@@ -189,6 +231,7 @@ void drawContextFltkCairo::setFont(int fontid, int fontsize) ...@@ -189,6 +231,7 @@ void drawContextFltkCairo::setFont(int fontid, int fontsize)
_currentFontId = fontid; _currentFontId = fontid;
} }
cairo_set_font_size(_cr, fontsize); cairo_set_font_size(_cr, fontsize);
_currentFontSize = fontsize;
} }
#endif #endif
...@@ -17,12 +17,12 @@ typedef struct _cairo_surface cairo_surface_t; ...@@ -17,12 +17,12 @@ typedef struct _cairo_surface cairo_surface_t;
typedef struct _cairo cairo_t; typedef struct _cairo cairo_t;
class drawContextFltkCairo : public drawContextFltk { class drawContextFltkCairo : public drawContextFltk {
class queueString;
queueString *_queue;
cairo_surface_t *_surface; cairo_surface_t *_surface;
cairo_t *_cr; cairo_t *_cr;
unsigned int _textureId;
int _currentFontId; int _currentFontId;
int _currentFontSize; int _currentFontSize;
void _resizeSurface(int w, int h);
public: public:
void draw(); void draw();
drawContextFltkCairo(); drawContextFltkCairo();
...@@ -30,6 +30,7 @@ class drawContextFltkCairo : public drawContextFltk { ...@@ -30,6 +30,7 @@ class drawContextFltkCairo : public drawContextFltk {
double getStringWidth(const char *str); double getStringWidth(const char *str);
//int getStringHeight(); //int getStringHeight();
//int getStringDescent(); //int getStringDescent();
void flushString();
void drawString(const char *str); void drawString(const char *str);
void setFont(int fontid, int fontsize); void setFont(int fontid, int fontsize);
std::string getName(){ return "Cairo"; } std::string getName(){ return "Cairo"; }
......
...@@ -312,6 +312,7 @@ void openglWindow::draw() ...@@ -312,6 +312,7 @@ void openglWindow::draw()
_drawBorder(); _drawBorder();
} }
} }
drawContext::global()->flushString();
_lock = false; _lock = false;
} }
......
...@@ -98,6 +98,7 @@ class drawContextGlobal { ...@@ -98,6 +98,7 @@ class drawContextGlobal {
virtual int getStringDescent(){ return 3; } virtual int getStringDescent(){ return 3; }
virtual void drawString(const char *str){} virtual void drawString(const char *str){}
virtual void resetFontTextures(){} virtual void resetFontTextures(){}
virtual void flushString(){}
virtual std::string getName(){ return "None"; } 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