6 #include "../gfxdevice.h"
7 #include "../gfxtools.h"
18 //#define ZSTEP (1/65536.0)
19 #define ZSTEP (1/32.0)
20 //#define ZSTEP (1/4.0)
22 typedef struct _fontlist {
24 struct _fontlist*next;
27 typedef struct _internal {
34 int config_polygonoutlines;
36 GLUtesselator *tesselator;
37 GLUtesselator *tesselator_line;
38 GLUtesselator *tesselator_tex;
41 static int verbose = 0;
42 static void dbg(char*format, ...)
49 va_start(arglist, format);
50 vsprintf(buf, format, arglist);
53 while(l && buf[l-1]=='\n') {
57 printf("(device-opengl) %s\n", buf);
65 typedef void(*callbackfunction_t)();
67 void CALLBACK errorCallback(GLenum errorCode)
69 const GLubyte *estring;
70 estring = gluErrorString(errorCode);
71 printf("Tessellation Error: %s\n", estring);
74 void CALLBACK beginCallback(GLenum which)
78 void CALLBACK endCallback(void)
82 void CALLBACK vertexCallback(GLvoid *vertex)
84 double*xyz = (GLdouble*)vertex;
85 glVertex3d(xyz[0],xyz[1],xyz[2]);
87 void CALLBACK combineCallback(GLdouble coords[3], GLdouble *data[4], GLfloat w[4], GLdouble **out)
90 vertex = (GLdouble *) malloc(6 * sizeof(GLdouble));
91 vertex[0] = coords[0];
92 vertex[1] = coords[1];
93 vertex[2] = coords[2];
96 void CALLBACK vertexCallbackTex(GLvoid *vertex)
98 double*v = (GLdouble*)vertex;
99 glTexCoord2f(v[3],v[4]);
100 glVertex3d(v[0],v[1],v[2]);
102 void CALLBACK combineCallbackTex(GLdouble coords[3], GLdouble *data[4], GLfloat w[4], GLdouble **out)
105 vertex = (GLdouble *) malloc(5 * sizeof(GLdouble));
106 vertex[0] = coords[0];
107 vertex[1] = coords[1];
108 vertex[2] = coords[2];
109 if(data[2] && data[3]) {
110 vertex[3] = w[0]*data[0][3] + w[1]*data[1][3] + w[2]*data[2][3] + w[3]*data[3][3];
111 vertex[4] = w[0]*data[0][4] + w[1]*data[1][4] + w[2]*data[2][4] + w[3]*data[3][4];
113 vertex[3] = w[0]*data[0][3] + w[1]*data[1][3];
114 vertex[4] = w[0]*data[0][4] + w[1]*data[1][4];
119 int opengl_setparameter(struct _gfxdevice*dev, const char*key, const char*value)
121 internal_t*i = (internal_t*)dev->internal;
122 dbg("setparameter %s=%s", key, value);
123 if(!strcmp(key, "polygonoutlines")) {
124 i->config_polygonoutlines = atoi(value);
129 void opengl_startpage(struct _gfxdevice*dev, int width, int height)
131 dbg("startpage %d %d", width, height);
132 internal_t*i = (internal_t*)dev->internal;
138 void opengl_startclip(struct _gfxdevice*dev, gfxline_t*line)
143 void opengl_endclip(struct _gfxdevice*dev)
148 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)
151 internal_t*i = (internal_t*)dev->internal;
156 glColor4f(color->r/255.0, color->g/255.0, color->b/255.0, color->a/255.0);
158 //glLineWidth(width*64);
163 double z = i->currentz*ZSTEP;
165 glPolygonOffset(0.0, 500.0);
169 if(l->type == gfx_moveTo) {
177 glBegin(GL_LINE_STRIP);
179 glVertex3d(l->x, l->y, z);
189 #define SPLINE_SUBDIVISION 2
191 void tesselatePolygon(GLUtesselator*tesselator, double z, gfxline_t*line)
195 double lastx=0,lasty=0;
198 gluTessBeginPolygon(tesselator, NULL);
202 if(l->type == gfx_splineTo) {
203 double c = sqrt(abs(l->x-2*l->sx+lastx) + abs(l->y-2*l->sy+lasty))*SPLINE_SUBDIVISION;
205 if(steps<1) steps = 1;
212 //printf("full len:%d\n", len);
213 xyz = malloc(sizeof(double)*3*len);
217 if(l->type == gfx_moveTo) {
220 gluTessEndContour(tesselator);
225 gluTessBeginContour(tesselator);
228 if(l->type == gfx_splineTo) {
230 double c = sqrt(abs(l->x-2*l->sx+lastx) + abs(l->y-2*l->sy+lasty))*SPLINE_SUBDIVISION;
232 if(steps<1) steps = 1;
233 //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);
234 //printf("%f %f %f\n", lastx, l->sx, l->x);
235 //printf("%f %f %f\n", lasty, l->sy, l->y);
236 for(j=1;j<=steps;j++) {
238 double t = (double)j / (double)steps;
239 xyz[len*3+0] = lastx*(1-t)*(1-t) + 2*l->sx*(1-t)*t + l->x*t*t;
240 xyz[len*3+1] = lasty*(1-t)*(1-t) + 2*l->sy*(1-t)*t + l->y*t*t;
242 gluTessVertex(tesselator, &xyz[len*3], &xyz[len*3]);
245 //printf("%d\n", len);
250 gluTessVertex(tesselator, &xyz[len*3], &xyz[len*3]);
260 gluTessEndContour(tesselator);
262 gluTessEndPolygon(tesselator);
266 void opengl_fill(struct _gfxdevice*dev, gfxline_t*line, gfxcolor_t*color)
269 dbg("fill %02x%02x%02x%02x", color->a, color->r, color->g, color->b);
270 internal_t*i = (internal_t*)dev->internal;
272 glDisable(GL_TEXTURE_2D);
273 glColor4f(color->r/255.0, color->g/255.0, color->b/255.0, color->a/255.0);
276 z = (i->currentz*ZSTEP);
277 tesselatePolygon(i->tesselator, z, line);
279 //tesselatePolygon(i->tesselator_line, z, line);
282 typedef struct _gfxhash
287 char gfxhash_compare(gfxhash_t*h1, gfxhash_t*h2)
289 return !memcmp(h1->d, h2->d, 16);
292 typedef struct _imgopengl
298 struct _imgopengl*next;
301 static imgopengl_t*img2texid = 0;
303 static gfxhash_t gfximage_hash(gfximage_t*img)
306 int size = img->width*img->height*4;
307 U8*data = (U8*)img->data;
309 hash_md5(data, size, hash.d);
313 static void delTextures()
315 imgopengl_t*i = img2texid;
317 imgopengl_t*next = i->next;
319 glDeleteTextures(1, &i->texID);
322 memset(i, 0, sizeof(imgopengl_t));
328 static imgopengl_t*addTexture(gfximage_t*img)
330 gfxhash_t hash = gfximage_hash(img);
331 imgopengl_t*i = img2texid;
335 while(1<<width_bits < img->width)
337 while(1<<height_bits < img->height)
339 int newwidth = 1<<width_bits;
340 int newheight = 1<<height_bits;
343 if(gfxhash_compare(&hash, &i->hash) && newwidth==i->width && newheight==i->height) {
350 glGenTextures(1, texIDs);
352 i = malloc(sizeof(imgopengl_t));
354 i->texID = texIDs[0];
359 i->height = newheight;
361 unsigned char*data = malloc(newwidth*newheight*4);
364 for(y=0;y<img->height;y++) {
365 for(x=0;x<img->width;x++) {
366 data[(y*newwidth+x)*4+0] = img->data[y*img->width+x].r;
367 data[(y*newwidth+x)*4+1] = img->data[y*img->width+x].g;
368 data[(y*newwidth+x)*4+2] = img->data[y*img->width+x].b;
369 data[(y*newwidth+x)*4+3] = img->data[y*img->width+x].a;
371 int lastx = img->width - 1;
372 for(;x<newwidth;x++) {
373 data[(y*newwidth+x)*4+0] = img->data[y*img->width+lastx].r;
374 data[(y*newwidth+x)*4+1] = img->data[y*img->width+lastx].g;
375 data[(y*newwidth+x)*4+2] = img->data[y*img->width+lastx].b;
376 data[(y*newwidth+x)*4+3] = img->data[y*img->width+lastx].a;
379 int lasty = img->height - 1;
380 for(;y<newheight;y++) {
381 for(x=0;x<newwidth;x++) {
382 data[(y*newwidth+x)*4+0] = img->data[lasty*img->width+x].r;
383 data[(y*newwidth+x)*4+1] = img->data[lasty*img->width+x].g;
384 data[(y*newwidth+x)*4+2] = img->data[lasty*img->width+x].b;
385 data[(y*newwidth+x)*4+3] = img->data[lasty*img->width+x].a;
389 glEnable(GL_TEXTURE_2D);
390 glBindTexture(GL_TEXTURE_2D, i->texID);
391 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, i->width, i->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
396 void opengl_fillbitmap(struct _gfxdevice*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*matrix, gfxcxform_t*cxform)
399 internal_t*i = (internal_t*)dev->internal;
404 glColor4f(1.0,0,0.7,1.0);
408 imgopengl_t* txt = addTexture(img);
411 gfxmatrix_invert(matrix, &m2);
412 m2.m00 /= txt->width;
413 m2.m10 /= txt->width;
415 m2.m01 /= txt->height;
416 m2.m11 /= txt->height;
417 m2.ty /= txt->height;
419 glEnable(GL_TEXTURE_2D);
420 glBindTexture(GL_TEXTURE_2D, txt->texID);
421 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
422 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
423 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
424 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
425 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
427 gluTessBeginPolygon(i->tesselator_tex, NULL);
434 xyz = malloc(sizeof(double)*5*len);
438 if(l->type == gfx_moveTo) {
441 gluTessEndContour(i->tesselator_tex);
446 gluTessBeginContour(i->tesselator_tex);
451 xyz[len*5+2] = (i->currentz*ZSTEP);
454 gfxmatrix_transform(&m2, /*src*/&xyz[len*5+0], /*dest*/&xyz[len*5+3]);
456 gluTessVertex(i->tesselator_tex, &xyz[len*5], &xyz[len*5]);
464 gluTessEndContour(i->tesselator_tex);
466 gluTessEndPolygon(i->tesselator_tex);
469 glDisable(GL_TEXTURE_2D);
472 void opengl_fillgradient(struct _gfxdevice*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix)
477 void opengl_addfont(gfxdevice_t*dev, gfxfont_t*font)
479 internal_t*i = (internal_t*)dev->internal;
481 fontlist_t*last=0,*l = i->fontlist;
484 if(!strcmp((char*)l->font->id, font->id)) {
485 return; // we already know this font
489 l = (fontlist_t*)rfx_calloc(sizeof(fontlist_t));
499 void opengl_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix)
501 internal_t*i = (internal_t*)dev->internal;
505 if(i->font && i->font->id && !strcmp(font->id, i->font->id)) {
506 // current font is correct
508 fontlist_t*l = i->fontlist;
511 if(!strcmp((char*)l->font->id, font->id)) {
518 opengl_addfont(dev, font);
520 //fprintf(stderr, "Unknown font id: %s", font->id);
525 gfxglyph_t*glyph = &i->font->glyphs[glyphnr];
527 gfxline_t*line2 = gfxline_clone(glyph->line);
528 gfxline_transform(line2, matrix);
529 opengl_fill(dev, line2, color);
539 void opengl_drawlink(struct _gfxdevice*dev, gfxline_t*line, const char*action)
544 void opengl_endpage(struct _gfxdevice*dev)
549 int opengl_result_save(struct _gfxresult*gfx, const char*filename)
554 void* opengl_result_get(struct _gfxresult*gfx, const char*name)
559 void opengl_result_destroy(struct _gfxresult*gfx)
561 dbg("result:destroy");
566 gfxresult_t*opengl_finish(struct _gfxdevice*dev)
569 internal_t*i = (internal_t*)dev->internal;
570 gluDeleteTess(i->tesselator);i->tesselator=0;
571 gluDeleteTess(i->tesselator_tex);i->tesselator_tex=0;
572 gfxresult_t*result = (gfxresult_t*)malloc(sizeof(gfxresult_t));
573 memset(result, 0, sizeof(gfxresult_t));
574 result->save = opengl_result_save;
575 result->get = opengl_result_get;
576 result->destroy = opengl_result_destroy;
580 void gfxdevice_opengl_init(gfxdevice_t*dev)
583 internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t));
584 memset(dev, 0, sizeof(gfxdevice_t));
586 dev->name = "opengl";
590 dev->setparameter = opengl_setparameter;
591 dev->startpage = opengl_startpage;
592 dev->startclip = opengl_startclip;
593 dev->endclip = opengl_endclip;
594 dev->stroke = opengl_stroke;
595 dev->fill = opengl_fill;
596 dev->fillbitmap = opengl_fillbitmap;
597 dev->fillgradient = opengl_fillgradient;
598 dev->addfont = opengl_addfont;
599 dev->drawchar = opengl_drawchar;
600 dev->drawlink = opengl_drawlink;
601 dev->endpage = opengl_endpage;
602 dev->finish = opengl_finish;
604 i->tesselator = gluNewTess();
605 gluTessCallback(i->tesselator, GLU_TESS_ERROR, (callbackfunction_t)errorCallback);
606 gluTessCallback(i->tesselator, GLU_TESS_VERTEX, (callbackfunction_t)vertexCallback);
607 gluTessCallback(i->tesselator, GLU_TESS_BEGIN, (callbackfunction_t)beginCallback);
608 gluTessCallback(i->tesselator, GLU_TESS_END, (callbackfunction_t)endCallback);
609 gluTessCallback(i->tesselator, GLU_TESS_COMBINE, (callbackfunction_t)combineCallback);
611 i->tesselator_line = gluNewTess();
612 gluTessCallback(i->tesselator_line, GLU_TESS_ERROR, (callbackfunction_t)errorCallback);
613 gluTessCallback(i->tesselator_line, GLU_TESS_VERTEX, (callbackfunction_t)vertexCallback);
614 gluTessCallback(i->tesselator_line, GLU_TESS_BEGIN, (callbackfunction_t)beginCallback);
615 gluTessCallback(i->tesselator_line, GLU_TESS_END, (callbackfunction_t)endCallback);
616 gluTessProperty(i->tesselator_line, GLU_TESS_BOUNDARY_ONLY, 1.0);
618 i->tesselator_tex = gluNewTess();
619 gluTessCallback(i->tesselator_tex, GLU_TESS_ERROR, (callbackfunction_t)errorCallback);
620 gluTessCallback(i->tesselator_tex, GLU_TESS_VERTEX, (callbackfunction_t)vertexCallbackTex);
621 gluTessCallback(i->tesselator_tex, GLU_TESS_BEGIN, (callbackfunction_t)beginCallback);
622 gluTessCallback(i->tesselator_tex, GLU_TESS_END, (callbackfunction_t)endCallback);
623 gluTessCallback(i->tesselator_tex, GLU_TESS_COMBINE, (callbackfunction_t)combineCallbackTex);
625 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);