fixed a security bug in logging, added basic xml support to as3 compiler
[swftools.git] / lib / devices / opengl.c
index a9459a1..fd1b745 100644 (file)
@@ -1,17 +1,23 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <math.h>
 
 #include "../gfxdevice.h"
 #include "../gfxtools.h"
+#include "../MD5.h"
+#include "../types.h"
 
+#include <math.h>
 #include <time.h>
 #include <GL/gl.h>
 #include <GL/glut.h>
 
 #include <stdarg.h>
 
-#define ZSTEP (1/65536.0)
+//#define ZSTEP (1/65536.0)
+#define ZSTEP (1/32.0)
+//#define ZSTEP (1/4.0)
 
 typedef struct _fontlist {
     gfxfont_t*font;
@@ -25,11 +31,14 @@ typedef struct _internal {
     int width, height;
     int currentz;
    
+    int config_polygonoutlines;
+   
     GLUtesselator *tesselator;
+    GLUtesselator *tesselator_line;
     GLUtesselator *tesselator_tex;
 } internal_t;
 
-static int verbose = 1;
+static int verbose = 0;
 static void dbg(char*format, ...)
 {
     char buf[1024];
@@ -38,7 +47,7 @@ static void dbg(char*format, ...)
     if(!verbose)
        return;
     va_start(arglist, format);
-    vsprintf(buf, format, arglist);
+    vsnprintf(buf, sizeof(buf)-1, format, arglist);
     va_end(arglist);
     l = strlen(buf);
     while(l && buf[l-1]=='\n') {
@@ -59,16 +68,16 @@ void CALLBACK errorCallback(GLenum errorCode)
 {
    const GLubyte *estring;
    estring = gluErrorString(errorCode);
-   dbg("Tessellation Error: %s\n", estring);
+   printf("Tessellation Error: %s\n", estring);
    exit(0);
 }
 void CALLBACK beginCallback(GLenum which)
 {
-   glBegin(which);
+    glBegin(which);
 }
 void CALLBACK endCallback(void)
 {
-   glEnd();
+    glEnd();
 }
 void CALLBACK vertexCallback(GLvoid *vertex)
 {
@@ -92,20 +101,28 @@ void CALLBACK vertexCallbackTex(GLvoid *vertex)
 }
 void CALLBACK combineCallbackTex(GLdouble coords[3], GLdouble *data[4], GLfloat w[4], GLdouble **out)
 {
-   GLdouble *vertex, *texCoord;
+   GLdouble *vertex;
    vertex = (GLdouble *) malloc(5 * sizeof(GLdouble));
    vertex[0] = coords[0];
    vertex[1] = coords[1];
    vertex[2] = coords[2];
-   texCoord = &vertex[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];
+   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;
 }
 
@@ -132,11 +149,20 @@ void opengl_stroke(struct _gfxdevice*dev, gfxline_t*line, gfxcoord_t width, gfxc
 {
     dbg("stroke");
     internal_t*i = (internal_t*)dev->internal;
+    i->currentz++;
     char running = 0;
     gfxline_t*l=0;
-    dbg("stroke");
+
     glColor4f(color->r/255.0, color->g/255.0, color->b/255.0, color->a/255.0);
+    
+    //glLineWidth(width*64);
+    if(width <= 0) {
+        width = 1.0;
+    }
     glLineWidth(width);
+    double z = i->currentz*ZSTEP;
+
+    glPolygonOffset(0.0, 500.0);
 
     l = line;
     while(l) {
@@ -150,34 +176,31 @@ void opengl_stroke(struct _gfxdevice*dev, gfxline_t*line, gfxcoord_t width, gfxc
            running = 1;
            glBegin(GL_LINE_STRIP);
        }
-       glVertex3d(l->x, l->y, (i->currentz*ZSTEP));
+       glVertex3d(l->x, l->y, z);
        l=l->next;
     }
     if(running) {
        running = 0;
        glEnd();
     }
-    i->currentz ++;
+    glLineWidth(1.0);
 }
 
-void opengl_fill(struct _gfxdevice*dev, gfxline_t*line, gfxcolor_t*color)
+#define SPLINE_SUBDIVISION 2
+
+void tesselatePolygon(GLUtesselator*tesselator, double z, gfxline_t*line)
 {
-    dbg("fill");
-    internal_t*i = (internal_t*)dev->internal;
-    char running = 0;
     int len = 0;
-    double*xyz=0;
-    double lastx=0,lasty=0;
     gfxline_t*l=0;
-    dbg("fill");
-    glColor4f(color->r/255.0, color->g/255.0, color->b/255.0, color->a/255.0);
-
-    gluTessBeginPolygon(i->tesselator, NULL);
+    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))/2;
+            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;
@@ -187,7 +210,6 @@ void opengl_fill(struct _gfxdevice*dev, gfxline_t*line, gfxcolor_t*color)
        l = l->next;
     }
     //printf("full len:%d\n", len);
-    double z = (i->currentz*ZSTEP);
     xyz = malloc(sizeof(double)*3*len);
     l = line;
     len = 0;
@@ -195,17 +217,17 @@ void opengl_fill(struct _gfxdevice*dev, gfxline_t*line, gfxcolor_t*color)
        if(l->type == gfx_moveTo) {
            if(running) {
                running = 0;
-               gluTessEndContour(i->tesselator);
+               gluTessEndContour(tesselator);
            }
        }
        if(!running) {
            running = 1;
-           gluTessBeginContour(i->tesselator);
+           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))/2;
+            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);
@@ -217,7 +239,7 @@ void opengl_fill(struct _gfxdevice*dev, gfxline_t*line, gfxcolor_t*color)
                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(i->tesselator, &xyz[len*3], &xyz[len*3]);
+               gluTessVertex(tesselator, &xyz[len*3], &xyz[len*3]);
                len++;
            }
            //printf("%d\n", len);
@@ -225,7 +247,7 @@ void opengl_fill(struct _gfxdevice*dev, gfxline_t*line, gfxcolor_t*color)
            xyz[len*3+0] = l->x;
            xyz[len*3+1] = l->y;
            xyz[len*3+2] = z;
-           gluTessVertex(i->tesselator, &xyz[len*3], &xyz[len*3]);
+           gluTessVertex(tesselator, &xyz[len*3], &xyz[len*3]);
            len++;
        }
        lastx = l->x;
@@ -235,26 +257,79 @@ void opengl_fill(struct _gfxdevice*dev, gfxline_t*line, gfxcolor_t*color)
     }
     if(running) {
        running = 0;
-       gluTessEndContour(i->tesselator);
+       gluTessEndContour(tesselator);
     }
-    gluTessEndPolygon(i->tesselator);
-    i->currentz ++;
+    gluTessEndPolygon(tesselator);
     free(xyz);
 }
 
-void opengl_fillbitmap(struct _gfxdevice*dev, gfxline_t*line, gfximage_t*img, gfxmatrix_t*matrix, gfxcxform_t*cxform)
+void opengl_fill(struct _gfxdevice*dev, gfxline_t*line, gfxcolor_t*color)
 {
-    dbg("fillbitmap");
+    double z;
+    dbg("fill %02x%02x%02x%02x", color->a, color->r, color->g, color->b);
     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,1.0);
+
+    glDisable(GL_TEXTURE_2D);
+    glColor4f(color->r/255.0, color->g/255.0, color->b/255.0, color->a/255.0);
     
-    GLuint texIDs[1];
-    glGenTextures(1, texIDs);
+    i->currentz ++;
+    z = (i->currentz*ZSTEP);
+    tesselatePolygon(i->tesselator, z, line);
+
+    //tesselatePolygon(i->tesselator_line, z, line);
+}
+
+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);
+}
+
+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_bits < img->width)
@@ -264,7 +339,27 @@ void opengl_fillbitmap(struct _gfxdevice*dev, gfxline_t*line, gfximage_t*img, gf
     int newwidth = 1<<width_bits;
     int newheight = 1<<height_bits;
 
+    while(i) {
+        if(gfxhash_compare(&hash, &i->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;y<img->height;y++) {
        for(x=0;x<img->width;x++) {
@@ -273,29 +368,62 @@ void opengl_fillbitmap(struct _gfxdevice*dev, gfxline_t*line, gfximage_t*img, gf
            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(;x<newwidth;x++) {
+           data[(y*newwidth+x)*4+0] = img->data[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(;y<newheight;y++) {
+        for(x=0;x<newwidth;x++) {
+           data[(y*newwidth+x)*4+0] = img->data[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 /= newwidth;
-    m2.m10 /= newwidth;
-    m2.tx /= newwidth;
-    m2.m01 /= newheight;
-    m2.m11 /= newheight;
-    m2.ty /= newheight;
+    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, texIDs[0]);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, newwidth, newheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
-    
-    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;
@@ -336,7 +464,6 @@ void opengl_fillbitmap(struct _gfxdevice*dev, gfxline_t*line, gfximage_t*img, gf
        gluTessEndContour(i->tesselator_tex);
     }
     gluTessEndPolygon(i->tesselator_tex);
-    i->currentz ++;
     free(xyz);
     
     glDisable(GL_TEXTURE_2D);
@@ -372,6 +499,8 @@ void opengl_addfont(gfxdevice_t*dev, gfxfont_t*font)
 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
@@ -386,8 +515,10 @@ void opengl_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*co
            l = l->next;
        }
        if(i->font == 0) {
-           fprintf(stderr, "Unknown font id: %s", font->id);
-           return;
+            opengl_addfont(dev, font);
+            i->font = font;
+           //fprintf(stderr, "Unknown font id: %s", font->id);
+           //return;
        }
     }
 
@@ -398,12 +529,14 @@ void opengl_drawchar(gfxdevice_t*dev, gfxfont_t*font, int glyphnr, gfxcolor_t*co
     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");
 }
@@ -413,12 +546,12 @@ void opengl_endpage(struct _gfxdevice*dev)
     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;
@@ -427,6 +560,7 @@ void opengl_result_destroy(struct _gfxresult*gfx)
 {
     dbg("result:destroy");
     free(gfx);
+    delTextures();
 }
 
 gfxresult_t*opengl_finish(struct _gfxdevice*dev)
@@ -448,6 +582,8 @@ void gfxdevice_opengl_init(gfxdevice_t*dev)
     dbg("init");
     internal_t*i = (internal_t*)rfx_calloc(sizeof(internal_t));
     memset(dev, 0, sizeof(gfxdevice_t));
+    
+    dev->name = "opengl";
 
     dev->internal = i;
     
@@ -470,7 +606,14 @@ void gfxdevice_opengl_init(gfxdevice_t*dev)
     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_END, (callbackfunction_t)combineCallback);
+    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);