X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fdevices%2Fopengl.c;h=fd1b745681eac6872bf10836f1b110649a15d7c1;hb=e4687b3aa2aed49fb16ba9e9561344d808750297;hp=bf9c1d18f493292ae4290308cbf70a1cfc5761e0;hpb=4e8fc32aa9cb30e15aa74c33a960563c53ae3621;p=swftools.git diff --git a/lib/devices/opengl.c b/lib/devices/opengl.c index bf9c1d1..fd1b745 100644 --- a/lib/devices/opengl.c +++ b/lib/devices/opengl.c @@ -1,19 +1,26 @@ #include #include #include +#include #include "../gfxdevice.h" #include "../gfxtools.h" +#include "../MD5.h" +#include "../types.h" +#include #include #include #include -#include +#include + +//#define ZSTEP (1/65536.0) +#define ZSTEP (1/32.0) +//#define ZSTEP (1/4.0) typedef struct _fontlist { gfxfont_t*font; - char*id; struct _fontlist*next; } fontlist_t; @@ -21,127 +28,547 @@ typedef struct _internal { gfxfont_t*font; char*fontid; fontlist_t* fontlist; + int width, height; + int currentz; + + int config_polygonoutlines; + + GLUtesselator *tesselator; + GLUtesselator *tesselator_line; + GLUtesselator *tesselator_tex; } internal_t; +static int verbose = 0; +static void dbg(char*format, ...) +{ + char buf[1024]; + int l; + va_list arglist; + if(!verbose) + return; + va_start(arglist, format); + vsnprintf(buf, sizeof(buf)-1, format, arglist); + va_end(arglist); + l = strlen(buf); + while(l && buf[l-1]=='\n') { + buf[l-1] = 0; + l--; + } + printf("(device-opengl) %s\n", buf); + fflush(stdout); +} + +#ifndef CALLBACK +#define CALLBACK +#endif + +typedef void(*callbackfunction_t)(); + +void CALLBACK errorCallback(GLenum errorCode) +{ + const GLubyte *estring; + estring = gluErrorString(errorCode); + printf("Tessellation Error: %s\n", estring); + exit(0); +} +void CALLBACK beginCallback(GLenum which) +{ + glBegin(which); +} +void CALLBACK endCallback(void) +{ + glEnd(); +} +void CALLBACK vertexCallback(GLvoid *vertex) +{ + double*xyz = (GLdouble*)vertex; + glVertex3d(xyz[0],xyz[1],xyz[2]); +} +void CALLBACK combineCallback(GLdouble coords[3], GLdouble *data[4], GLfloat w[4], GLdouble **out) +{ + GLdouble *vertex; + vertex = (GLdouble *) malloc(6 * sizeof(GLdouble)); + vertex[0] = coords[0]; + vertex[1] = coords[1]; + vertex[2] = coords[2]; + *out = vertex; +} +void CALLBACK vertexCallbackTex(GLvoid *vertex) +{ + double*v = (GLdouble*)vertex; + glTexCoord2f(v[3],v[4]); + glVertex3d(v[0],v[1],v[2]); +} +void CALLBACK combineCallbackTex(GLdouble coords[3], GLdouble *data[4], GLfloat w[4], GLdouble **out) +{ + GLdouble *vertex; + vertex = (GLdouble *) malloc(5 * sizeof(GLdouble)); + vertex[0] = coords[0]; + vertex[1] = coords[1]; + vertex[2] = coords[2]; + if(data[2] && data[3]) { + vertex[3] = w[0]*data[0][3] + w[1]*data[1][3] + w[2]*data[2][3] + w[3]*data[3][3]; + vertex[4] = w[0]*data[0][4] + w[1]*data[1][4] + w[2]*data[2][4] + w[3]*data[3][4]; + } else { + vertex[3] = w[0]*data[0][3] + w[1]*data[1][3]; + vertex[4] = w[0]*data[0][4] + w[1]*data[1][4]; + } + *out = vertex; +} + int opengl_setparameter(struct _gfxdevice*dev, const char*key, const char*value) { + internal_t*i = (internal_t*)dev->internal; + dbg("setparameter %s=%s", key, value); + if(!strcmp(key, "polygonoutlines")) { + i->config_polygonoutlines = atoi(value); + } return 0; } -jmp_buf env; -//jmp_buf env2; +void opengl_startpage(struct _gfxdevice*dev, int width, int height) +{ + dbg("startpage %d %d", width, height); + internal_t*i = (internal_t*)dev->internal; + i->width = width; + i->height = height; + i->currentz = 0; +} -void display() +void opengl_startclip(struct _gfxdevice*dev, gfxline_t*line) { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - /*if(!setjmp(env2)) - longjmp(env, 1);*/ - longjmp(env, 1); + dbg("startclip"); } -void opengl_startpage(struct _gfxdevice*dev, int width, int height) +void opengl_endclip(struct _gfxdevice*dev) { - glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); - glutInitWindowSize(width,height); - glutInitWindowPosition(100,100); - glutCreateWindow("gfxdevice_opengl"); - glutDisplayFunc(display); + dbg("endclip"); +} - glClearColor(1.0,0.0,0.0,0.0); - glShadeModel(GL_FLAT); - glEnable(GL_DEPTH_TEST); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +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) +{ + dbg("stroke"); + internal_t*i = (internal_t*)dev->internal; + i->currentz++; + char running = 0; + gfxline_t*l=0; + + glColor4f(color->r/255.0, color->g/255.0, color->b/255.0, color->a/255.0); - glViewport(0,0, width, height); + //glLineWidth(width*64); + if(width <= 0) { + width = 1.0; + } + glLineWidth(width); + double z = i->currentz*ZSTEP; - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - //gluPerspective(/*angle*/60.0, (GLfloat)width/(GLfloat)height, /*nearclip*/1.0, /*farclip*/30.0); + glPolygonOffset(0.0, 500.0); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glScalef(1.0/width,1.0/height,1.0); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - int ret=0; - ret = setjmp(env); - if(!ret) { - glutMainLoop(); + l = line; + while(l) { + if(l->type == gfx_moveTo) { + if(running) { + running = 0; + glEnd(); + } + } + if(!running) { + running = 1; + glBegin(GL_LINE_STRIP); + } + glVertex3d(l->x, l->y, z); + l=l->next; } + if(running) { + running = 0; + glEnd(); + } + glLineWidth(1.0); } -void opengl_startclip(struct _gfxdevice*dev, gfxline_t*line) +#define SPLINE_SUBDIVISION 2 + +void tesselatePolygon(GLUtesselator*tesselator, double z, gfxline_t*line) { - int t; - for(t=1;t<100;t++) { - glColor3f(1.0,1.0,1.0); - glBegin(GL_POLYGON); - glVertex3f(-t*10,-t*10,0); - glVertex3f(-t*10,t*10,0); - glVertex3f(t*10,t*10,0); - glVertex3f(t*10,-t*10,0); - glEnd(); + int len = 0; + gfxline_t*l=0; + double lastx=0,lasty=0; + double*xyz=0; + char running = 0; + gluTessBeginPolygon(tesselator, NULL); + l = line; + len = 0; + while(l) { + if(l->type == gfx_splineTo) { + double c = sqrt(abs(l->x-2*l->sx+lastx) + abs(l->y-2*l->sy+lasty))*SPLINE_SUBDIVISION; + int steps = (int)c; + if(steps<1) steps = 1; + len += steps; + } else { + len++; + } + l = l->next; + } + //printf("full len:%d\n", len); + xyz = malloc(sizeof(double)*3*len); + l = line; + len = 0; + while(l) { + if(l->type == gfx_moveTo) { + if(running) { + running = 0; + gluTessEndContour(tesselator); + } + } + if(!running) { + running = 1; + gluTessBeginContour(tesselator); + } + + if(l->type == gfx_splineTo) { + int j; + double c = sqrt(abs(l->x-2*l->sx+lastx) + abs(l->y-2*l->sy+lasty))*SPLINE_SUBDIVISION; + int steps = (int)c; + if(steps<1) steps = 1; + //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); + //printf("%f %f %f\n", lastx, l->sx, l->x); + //printf("%f %f %f\n", lasty, l->sy, l->y); + for(j=1;j<=steps;j++) { + //printf("%d\n", j); + double t = (double)j / (double)steps; + xyz[len*3+0] = lastx*(1-t)*(1-t) + 2*l->sx*(1-t)*t + l->x*t*t; + xyz[len*3+1] = lasty*(1-t)*(1-t) + 2*l->sy*(1-t)*t + l->y*t*t; + xyz[len*3+2] = z; + gluTessVertex(tesselator, &xyz[len*3], &xyz[len*3]); + len++; + } + //printf("%d\n", len); + } else { + xyz[len*3+0] = l->x; + xyz[len*3+1] = l->y; + xyz[len*3+2] = z; + gluTessVertex(tesselator, &xyz[len*3], &xyz[len*3]); + len++; + } + lastx = l->x; + lasty = l->y; + + l=l->next; + } + if(running) { + running = 0; + gluTessEndContour(tesselator); } - //glRectf(-50,-50,0.0,0.0); + gluTessEndPolygon(tesselator); + free(xyz); } -void opengl_endclip(struct _gfxdevice*dev) +void opengl_fill(struct _gfxdevice*dev, gfxline_t*line, gfxcolor_t*color) { + double z; + dbg("fill %02x%02x%02x%02x", color->a, color->r, color->g, color->b); + internal_t*i = (internal_t*)dev->internal; + + glDisable(GL_TEXTURE_2D); + glColor4f(color->r/255.0, color->g/255.0, color->b/255.0, color->a/255.0); + + i->currentz ++; + z = (i->currentz*ZSTEP); + tesselatePolygon(i->tesselator, z, line); + + //tesselatePolygon(i->tesselator_line, z, line); } -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) +typedef struct _gfxhash { + unsigned char d[16]; +} gfxhash_t; + +char gfxhash_compare(gfxhash_t*h1, gfxhash_t*h2) +{ + return !memcmp(h1->d, h2->d, 16); } -void opengl_fill(struct _gfxdevice*dev, gfxline_t*line, gfxcolor_t*color) +typedef struct _imgopengl +{ + gfxhash_t hash; + GLuint texID; + int width, height; + unsigned char*data; + struct _imgopengl*next; +} imgopengl_t; + +static imgopengl_t*img2texid = 0; + +static gfxhash_t gfximage_hash(gfximage_t*img) { + int t; + int size = img->width*img->height*4; + U8*data = (U8*)img->data; + gfxhash_t hash; + hash_md5(data, size, hash.d); + return hash; } +static void delTextures() +{ + imgopengl_t*i = img2texid; + while(i) { + imgopengl_t*next = i->next; + if(i->data) { + glDeleteTextures(1, &i->texID); + free(i->data); + } + memset(i, 0, sizeof(imgopengl_t)); + free(i); + i = next; + } +} + +static imgopengl_t*addTexture(gfximage_t*img) +{ + gfxhash_t hash = gfximage_hash(img); + imgopengl_t*i = img2texid; + + int width_bits = 0; + int height_bits = 0; + while(1<width) + width_bits++; + while(1<height) + height_bits++; + int newwidth = 1<hash) && newwidth==i->width && newheight==i->height) { + return i; + } + i = i->next; + } + + GLuint texIDs[1]; + glGenTextures(1, texIDs); + + i = malloc(sizeof(imgopengl_t)); + i->hash = hash; + i->texID = texIDs[0]; + i->next = img2texid; + img2texid = i; + + i->width = newwidth; + i->height = newheight; + + unsigned char*data = malloc(newwidth*newheight*4); + i->data = data; + int x,y; + for(y=0;yheight;y++) { + for(x=0;xwidth;x++) { + data[(y*newwidth+x)*4+0] = img->data[y*img->width+x].r; + data[(y*newwidth+x)*4+1] = img->data[y*img->width+x].g; + data[(y*newwidth+x)*4+2] = img->data[y*img->width+x].b; + data[(y*newwidth+x)*4+3] = img->data[y*img->width+x].a; + } + int lastx = img->width - 1; + for(;xdata[y*img->width+lastx].r; + data[(y*newwidth+x)*4+1] = img->data[y*img->width+lastx].g; + data[(y*newwidth+x)*4+2] = img->data[y*img->width+lastx].b; + data[(y*newwidth+x)*4+3] = img->data[y*img->width+lastx].a; + } + } + int lasty = img->height - 1; + for(;ydata[lasty*img->width+x].r; + data[(y*newwidth+x)*4+1] = img->data[lasty*img->width+x].g; + data[(y*newwidth+x)*4+2] = img->data[lasty*img->width+x].b; + data[(y*newwidth+x)*4+3] = img->data[lasty*img->width+x].a; + } + } + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, i->texID); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, i->width, i->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + + return i; +}; + void opengl_fillbitmap(struct _gfxdevice*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*matrix, gfxcxform_t*cxform) { + dbg("fillbitmap"); + internal_t*i = (internal_t*)dev->internal; + char running = 0; + int len = 0; + double*xyz=0; + gfxline_t*l=0; + glColor4f(1.0,0,0.7,1.0); + + i->currentz ++; + + imgopengl_t* txt = addTexture(img); + + gfxmatrix_t m2; + gfxmatrix_invert(matrix, &m2); + m2.m00 /= txt->width; + m2.m10 /= txt->width; + m2.tx /= txt->width; + m2.m01 /= txt->height; + m2.m11 /= txt->height; + m2.ty /= txt->height; + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, txt->texID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + + gluTessBeginPolygon(i->tesselator_tex, NULL); + l = line; + len = 0; + while(l) { + len++; + l = l->next; + } + xyz = malloc(sizeof(double)*5*len); + l = line; + len = 0; + while(l) { + if(l->type == gfx_moveTo) { + if(running) { + running = 0; + gluTessEndContour(i->tesselator_tex); + } + } + if(!running) { + running = 1; + gluTessBeginContour(i->tesselator_tex); + } + + xyz[len*5+0] = l->x; + xyz[len*5+1] = l->y; + xyz[len*5+2] = (i->currentz*ZSTEP); + xyz[len*5+3] = 0; + xyz[len*5+4] = 0; + gfxmatrix_transform(&m2, /*src*/&xyz[len*5+0], /*dest*/&xyz[len*5+3]); + + gluTessVertex(i->tesselator_tex, &xyz[len*5], &xyz[len*5]); + len++; + + l=l->next; + } + + if(running) { + running = 0; + gluTessEndContour(i->tesselator_tex); + } + gluTessEndPolygon(i->tesselator_tex); + free(xyz); + + glDisable(GL_TEXTURE_2D); } void opengl_fillgradient(struct _gfxdevice*dev, gfxline_t*line, gfxgradient_t*gradient, gfxgradienttype_t type, gfxmatrix_t*matrix) { + dbg("fillgradient"); } -void opengl_addfont(struct _gfxdevice*dev, char*fontid, gfxfont_t*font) +void opengl_addfont(gfxdevice_t*dev, gfxfont_t*font) { + internal_t*i = (internal_t*)dev->internal; + + fontlist_t*last=0,*l = i->fontlist; + while(l) { + last = l; + if(!strcmp((char*)l->font->id, font->id)) { + return; // we already know this font + } + l = l->next; + } + l = (fontlist_t*)rfx_calloc(sizeof(fontlist_t)); + l->font = font; + l->next = 0; + if(last) { + last->next = l; + } else { + i->fontlist = l; + } } -void opengl_drawchar(struct _gfxdevice*dev, char*fontid, int glyph, gfxcolor_t*color, gfxmatrix_t*matrix) +void opengl_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*color, gfxmatrix_t*matrix) { + internal_t*i = (internal_t*)dev->internal; + if(!font) + return; + + if(i->font && i->font->id && !strcmp(font->id, i->font->id)) { + // current font is correct + } else { + fontlist_t*l = i->fontlist; + i->font = 0; + while(l) { + if(!strcmp((char*)l->font->id, font->id)) { + i->font = l->font; + break; + } + l = l->next; + } + if(i->font == 0) { + opengl_addfont(dev, font); + i->font = font; + //fprintf(stderr, "Unknown font id: %s", font->id); + //return; + } + } + + gfxglyph_t*glyph = &i->font->glyphs[glyphnr]; + + gfxline_t*line2 = gfxline_clone(glyph->line); + gfxline_transform(line2, matrix); + opengl_fill(dev, line2, color); + gfxline_free(line2); + + i->currentz --; + + return; } -void opengl_drawlink(struct _gfxdevice*dev, gfxline_t*line, char*action) + + +void opengl_drawlink(struct _gfxdevice*dev, gfxline_t*line, const char*action) { + dbg("link"); } void opengl_endpage(struct _gfxdevice*dev) { - glFlush(); - //longjmp(env2, 1); - glutMainLoop(); + dbg("endpage"); } - -int opengl_result_save(struct _gfxresult*gfx, char*filename) +int opengl_result_save(struct _gfxresult*gfx, const char*filename) { + dbg("result:save"); return 0; } -void* opengl_result_get(struct _gfxresult*gfx, char*name) +void* opengl_result_get(struct _gfxresult*gfx, const char*name) { + dbg("result:get"); return 0; } void opengl_result_destroy(struct _gfxresult*gfx) { + dbg("result:destroy"); free(gfx); + delTextures(); } gfxresult_t*opengl_finish(struct _gfxdevice*dev) { + dbg("finish"); internal_t*i = (internal_t*)dev->internal; + gluDeleteTess(i->tesselator);i->tesselator=0; + gluDeleteTess(i->tesselator_tex);i->tesselator_tex=0; gfxresult_t*result = (gfxresult_t*)malloc(sizeof(gfxresult_t)); memset(result, 0, sizeof(gfxresult_t)); result->save = opengl_result_save; @@ -152,12 +579,11 @@ gfxresult_t*opengl_finish(struct _gfxdevice*dev) void gfxdevice_opengl_init(gfxdevice_t*dev) { + dbg("init"); internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t)); - int argc=1; - char*argv[]={"gfxdevice_opengl", 0}; - glutInit(&argc, argv); - memset(dev, 0, sizeof(gfxdevice_t)); + + dev->name = "opengl"; dev->internal = i; @@ -174,4 +600,27 @@ void gfxdevice_opengl_init(gfxdevice_t*dev) dev->drawlink = opengl_drawlink; dev->endpage = opengl_endpage; dev->finish = opengl_finish; + + i->tesselator = gluNewTess(); + gluTessCallback(i->tesselator, GLU_TESS_ERROR, (callbackfunction_t)errorCallback); + gluTessCallback(i->tesselator, GLU_TESS_VERTEX, (callbackfunction_t)vertexCallback); + gluTessCallback(i->tesselator, GLU_TESS_BEGIN, (callbackfunction_t)beginCallback); + gluTessCallback(i->tesselator, GLU_TESS_END, (callbackfunction_t)endCallback); + gluTessCallback(i->tesselator, GLU_TESS_COMBINE, (callbackfunction_t)combineCallback); + + i->tesselator_line = gluNewTess(); + gluTessCallback(i->tesselator_line, GLU_TESS_ERROR, (callbackfunction_t)errorCallback); + gluTessCallback(i->tesselator_line, GLU_TESS_VERTEX, (callbackfunction_t)vertexCallback); + gluTessCallback(i->tesselator_line, GLU_TESS_BEGIN, (callbackfunction_t)beginCallback); + gluTessCallback(i->tesselator_line, GLU_TESS_END, (callbackfunction_t)endCallback); + gluTessProperty(i->tesselator_line, GLU_TESS_BOUNDARY_ONLY, 1.0); + + i->tesselator_tex = gluNewTess(); + gluTessCallback(i->tesselator_tex, GLU_TESS_ERROR, (callbackfunction_t)errorCallback); + gluTessCallback(i->tesselator_tex, GLU_TESS_VERTEX, (callbackfunction_t)vertexCallbackTex); + gluTessCallback(i->tesselator_tex, GLU_TESS_BEGIN, (callbackfunction_t)beginCallback); + gluTessCallback(i->tesselator_tex, GLU_TESS_END, (callbackfunction_t)endCallback); + gluTessCallback(i->tesselator_tex, GLU_TESS_COMBINE, (callbackfunction_t)combineCallbackTex); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); }