6 #include "../gfxdevice.h"
7 #include "../gfxtools.h"
15 #define ZSTEP (1/65536.0)
17 typedef struct _fontlist {
19 struct _fontlist*next;
22 typedef struct _internal {
29 GLUtesselator *tesselator;
30 GLUtesselator *tesselator_tex;
33 static int verbose = 1;
34 static void dbg(char*format, ...)
41 va_start(arglist, format);
42 vsprintf(buf, format, arglist);
45 while(l && buf[l-1]=='\n') {
49 printf("(device-opengl) %s\n", buf);
57 typedef void(*callbackfunction_t)();
59 void CALLBACK errorCallback(GLenum errorCode)
61 const GLubyte *estring;
62 estring = gluErrorString(errorCode);
63 dbg("Tessellation Error: %s\n", estring);
66 void CALLBACK beginCallback(GLenum which)
70 void CALLBACK endCallback(void)
74 void CALLBACK vertexCallback(GLvoid *vertex)
76 double*xyz = (GLdouble*)vertex;
77 glVertex3d(xyz[0],xyz[1],xyz[2]);
79 void CALLBACK combineCallback(GLdouble coords[3], GLdouble *data[4], GLfloat w[4], GLdouble **out)
82 vertex = (GLdouble *) malloc(6 * sizeof(GLdouble));
83 vertex[0] = coords[0];
84 vertex[1] = coords[1];
85 vertex[2] = coords[2];
88 void CALLBACK vertexCallbackTex(GLvoid *vertex)
90 double*v = (GLdouble*)vertex;
91 glTexCoord2f(v[3],v[4]);
92 glVertex3d(v[0],v[1],v[2]);
94 void CALLBACK combineCallbackTex(GLdouble coords[3], GLdouble *data[4], GLfloat w[4], GLdouble **out)
96 GLdouble *vertex, *texCoord;
97 vertex = (GLdouble *) malloc(5 * sizeof(GLdouble));
98 vertex[0] = coords[0];
99 vertex[1] = coords[1];
100 vertex[2] = coords[2];
101 texCoord = &vertex[3];
102 vertex[3] = w[0]*data[0][3] + w[1]*data[1][3] + w[2]*data[2][3] + w[3]*data[3][3];
103 vertex[4] = w[0]*data[0][4] + w[1]*data[1][4] + w[2]*data[2][4] + w[3]*data[3][4];
107 int opengl_setparameter(struct _gfxdevice*dev, const char*key, const char*value)
109 dbg("setparameter %s=%s", key, value);
113 void opengl_startpage(struct _gfxdevice*dev, int width, int height)
115 dbg("startpage %d %d", width, height);
116 internal_t*i = (internal_t*)dev->internal;
122 void opengl_startclip(struct _gfxdevice*dev, gfxline_t*line)
127 void opengl_endclip(struct _gfxdevice*dev)
132 void opengl_stroke(struct _gfxdevice*dev, gfxline_t*line, gfxcoord_t width, gfxcolor_t*color, gfx_capType cap_style, gfx_joinType joint_style, gfxcoord_t miterLimit)
135 internal_t*i = (internal_t*)dev->internal;
139 glColor4f(color->r/255.0, color->g/255.0, color->b/255.0, color->a/255.0);
144 if(l->type == gfx_moveTo) {
152 glBegin(GL_LINE_STRIP);
154 glVertex3d(l->x, l->y, (i->currentz*ZSTEP));
164 void opengl_fill(struct _gfxdevice*dev, gfxline_t*line, gfxcolor_t*color)
167 internal_t*i = (internal_t*)dev->internal;
171 double lastx=0,lasty=0;
174 glColor4f(color->r/255.0, color->g/255.0, color->b/255.0, color->a/255.0);
176 gluTessBeginPolygon(i->tesselator, NULL);
180 if(l->type == gfx_splineTo) {
181 double c = sqrt(abs(l->x-2*l->sx+lastx) + abs(l->y-2*l->sy+lasty))/2;
183 if(steps<1) steps = 1;
190 //printf("full len:%d\n", len);
191 double z = (i->currentz*ZSTEP);
192 xyz = malloc(sizeof(double)*3*len);
196 if(l->type == gfx_moveTo) {
199 gluTessEndContour(i->tesselator);
204 gluTessBeginContour(i->tesselator);
207 if(l->type == gfx_splineTo) {
209 double c = sqrt(abs(l->x-2*l->sx+lastx) + abs(l->y-2*l->sy+lasty))/2;
211 if(steps<1) steps = 1;
212 //printf("c=%f d1=%f (%f/%f) d2=%f (%f/%f)\n", c,d1,l->x-l->sx,l->y-l->sy,d2,lastx-l->sx,lasty-l->sy);
213 //printf("%f %f %f\n", lastx, l->sx, l->x);
214 //printf("%f %f %f\n", lasty, l->sy, l->y);
215 for(j=1;j<=steps;j++) {
217 double t = (double)j / (double)steps;
218 xyz[len*3+0] = lastx*(1-t)*(1-t) + 2*l->sx*(1-t)*t + l->x*t*t;
219 xyz[len*3+1] = lasty*(1-t)*(1-t) + 2*l->sy*(1-t)*t + l->y*t*t;
221 gluTessVertex(i->tesselator, &xyz[len*3], &xyz[len*3]);
224 //printf("%d\n", len);
229 gluTessVertex(i->tesselator, &xyz[len*3], &xyz[len*3]);
239 gluTessEndContour(i->tesselator);
241 gluTessEndPolygon(i->tesselator);
246 void opengl_fillbitmap(struct _gfxdevice*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*matrix, gfxcxform_t*cxform)
249 internal_t*i = (internal_t*)dev->internal;
254 glColor4f(1.0,0,0,1.0);
257 glGenTextures(1, texIDs);
261 while(1<<width_bits < img->width)
263 while(1<<height_bits < img->height)
265 int newwidth = 1<<width_bits;
266 int newheight = 1<<height_bits;
268 unsigned char*data = malloc(newwidth*newheight*4);
270 for(y=0;y<img->height;y++) {
271 for(x=0;x<img->width;x++) {
272 data[(y*newwidth+x)*4+0] = img->data[y*img->width+x].r;
273 data[(y*newwidth+x)*4+1] = img->data[y*img->width+x].g;
274 data[(y*newwidth+x)*4+2] = img->data[y*img->width+x].b;
275 data[(y*newwidth+x)*4+3] = img->data[y*img->width+x].a;
280 gfxmatrix_invert(matrix, &m2);
288 glEnable(GL_TEXTURE_2D);
289 glBindTexture(GL_TEXTURE_2D, texIDs[0]);
290 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, newwidth, newheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
292 glEnable(GL_TEXTURE_2D);
293 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
294 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
295 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
296 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
297 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
300 gluTessBeginPolygon(i->tesselator_tex, NULL);
307 xyz = malloc(sizeof(double)*5*len);
311 if(l->type == gfx_moveTo) {
314 gluTessEndContour(i->tesselator_tex);
319 gluTessBeginContour(i->tesselator_tex);
324 xyz[len*5+2] = (i->currentz*ZSTEP);
327 gfxmatrix_transform(&m2, /*src*/&xyz[len*5+0], /*dest*/&xyz[len*5+3]);
329 gluTessVertex(i->tesselator_tex, &xyz[len*5], &xyz[len*5]);
337 gluTessEndContour(i->tesselator_tex);
339 gluTessEndPolygon(i->tesselator_tex);
343 glDisable(GL_TEXTURE_2D);
346 void opengl_fillgradient(struct _gfxdevice*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
351 void opengl_addfont(gfxdevice_t*dev, gfxfont_t*font)
353 internal_t*i = (internal_t*)dev->internal;
355 fontlist_t*last=0,*l = i->fontlist;
358 if(!strcmp((char*)l->font->id, font->id)) {
359 return; // we already know this font
363 l = (fontlist_t*)rfx_calloc(sizeof(fontlist_t));
373 void opengl_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix)
375 internal_t*i = (internal_t*)dev->internal;
377 if(i->font && i->font->id && !strcmp(font->id, i->font->id)) {
378 // current font is correct
380 fontlist_t*l = i->fontlist;
383 if(!strcmp((char*)l->font->id, font->id)) {
390 fprintf(stderr, "Unknown font id: %s", font->id);
395 gfxglyph_t*glyph = &i->font->glyphs[glyphnr];
397 gfxline_t*line2 = gfxline_clone(glyph->line);
398 gfxline_transform(line2, matrix);
399 opengl_fill(dev, line2, color);
407 void opengl_drawlink(struct _gfxdevice*dev, gfxline_t*line, char*action)
412 void opengl_endpage(struct _gfxdevice*dev)
417 int opengl_result_save(struct _gfxresult*gfx, char*filename)
422 void* opengl_result_get(struct _gfxresult*gfx, char*name)
427 void opengl_result_destroy(struct _gfxresult*gfx)
429 dbg("result:destroy");
433 gfxresult_t*opengl_finish(struct _gfxdevice*dev)
436 internal_t*i = (internal_t*)dev->internal;
437 gluDeleteTess(i->tesselator);i->tesselator=0;
438 gluDeleteTess(i->tesselator_tex);i->tesselator_tex=0;
439 gfxresult_t*result = (gfxresult_t*)malloc(sizeof(gfxresult_t));
440 memset(result, 0, sizeof(gfxresult_t));
441 result->save = opengl_result_save;
442 result->get = opengl_result_get;
443 result->destroy = opengl_result_destroy;
447 void gfxdevice_opengl_init(gfxdevice_t*dev)
450 internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t));
451 memset(dev, 0, sizeof(gfxdevice_t));
453 dev->name = "opengl";
457 dev->setparameter = opengl_setparameter;
458 dev->startpage = opengl_startpage;
459 dev->startclip = opengl_startclip;
460 dev->endclip = opengl_endclip;
461 dev->stroke = opengl_stroke;
462 dev->fill = opengl_fill;
463 dev->fillbitmap = opengl_fillbitmap;
464 dev->fillgradient = opengl_fillgradient;
465 dev->addfont = opengl_addfont;
466 dev->drawchar = opengl_drawchar;
467 dev->drawlink = opengl_drawlink;
468 dev->endpage = opengl_endpage;
469 dev->finish = opengl_finish;
471 i->tesselator = gluNewTess();
472 gluTessCallback(i->tesselator, GLU_TESS_ERROR, (callbackfunction_t)errorCallback);
473 gluTessCallback(i->tesselator, GLU_TESS_VERTEX, (callbackfunction_t)vertexCallback);
474 gluTessCallback(i->tesselator, GLU_TESS_BEGIN, (callbackfunction_t)beginCallback);
475 gluTessCallback(i->tesselator, GLU_TESS_END, (callbackfunction_t)endCallback);
476 //gluTessCallback(i->tesselator, GLU_TESS_END, (callbackfunction_t)combineCallback);
478 i->tesselator_tex = gluNewTess();
479 gluTessCallback(i->tesselator_tex, GLU_TESS_ERROR, (callbackfunction_t)errorCallback);
480 gluTessCallback(i->tesselator_tex, GLU_TESS_VERTEX, (callbackfunction_t)vertexCallbackTex);
481 gluTessCallback(i->tesselator_tex, GLU_TESS_BEGIN, (callbackfunction_t)beginCallback);
482 gluTessCallback(i->tesselator_tex, GLU_TESS_END, (callbackfunction_t)endCallback);
483 gluTessCallback(i->tesselator_tex, GLU_TESS_COMBINE, (callbackfunction_t)combineCallbackTex);
485 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);