#include #include "glu.h" #include "tess.h" #include #include #include "tessellate.h" void skip_vertex(Vertex *v, TessContext *ctx); /******************************************************************************/ TessContext *new_tess_context() { TessContext *result = (TessContext *) malloc(sizeof(struct TessContext)); result->latest_t = NULL; result->latest_v = NULL; result->n_tris = 0; result->v_prev = NULL; result->v_prevprev = NULL; result->v_prev = NULL; result->v_prev = NULL; result->vertex_cb = &skip_vertex; result->odd_even_strip = 0; result->reversed = 0; return result; } void destroy_tess_context(TessContext *ctx) { free(ctx); } Vertex *new_vertex(TessContext *ctx, double x, double y) { Vertex *result = (Vertex *) malloc(sizeof(Vertex)); result->prev = ctx->latest_v; result->pt[0] = x; result->pt[1] = y; result->pt[2] = 0; if (ctx->latest_v == NULL) { result->index = 0; } else { result->index = ctx->latest_v->index + 1; } return ctx->latest_v = result; } Triangle *new_triangle(TessContext *ctx, int v1, int v2, int v3) { Triangle *result = (Triangle *) malloc(sizeof(Triangle)); result->prev = ctx->latest_t; result->v[0] = v1; result->v[1] = v2; result->v[2] = v3; ctx->n_tris++; return ctx->latest_t = result; } /******************************************************************************/ void skip_vertex(Vertex *v, TessContext *ctx) { } ; void fan_vertex(Vertex *v, TessContext *ctx) { if (ctx->v_prevprev == NULL) { ctx->v_prevprev = v; return; } if (ctx->v_prev == NULL) { ctx->v_prev = v; return; } new_triangle(ctx, ctx->v_prevprev->index, ctx->v_prev->index, v->index); ctx->v_prev = v; } void strip_vertex(Vertex *v, TessContext *ctx) { if (ctx->v_prev == NULL) { ctx->v_prev = v; return; } if (ctx->v_prevprev == NULL) { ctx->v_prevprev = v; return; } if (ctx->odd_even_strip) { new_triangle(ctx, ctx->v_prevprev->index, ctx->v_prev->index, v->index); } else { new_triangle(ctx, ctx->v_prev->index, ctx->v_prevprev->index, v->index); } ctx->odd_even_strip = !ctx->odd_even_strip; ctx->v_prev = ctx->v_prevprev; ctx->v_prevprev = v; } void triangle_vertex(Vertex *v, TessContext *ctx) { if (ctx->v_prevprev == NULL) { ctx->v_prevprev = v; return; } if (ctx->v_prev == NULL) { ctx->v_prev = v; return; } new_triangle(ctx, ctx->v_prevprev->index, ctx->v_prev->index, v->index); ctx->v_prev = ctx->v_prevprev = NULL; } void vertex(void *vertex_data, void *poly_data) { Vertex *ptr = (Vertex *) vertex_data; TessContext *ctx = (TessContext *) poly_data; ctx->vertex_cb(ptr, ctx); } void begin(GLenum which, void *poly_data) { TessContext *ctx = (TessContext *) poly_data; ctx->v_prev = ctx->v_prevprev = NULL; ctx->odd_even_strip = 0; switch (which) { case GL_TRIANGLES: ctx->vertex_cb = &triangle_vertex; break; case GL_TRIANGLE_STRIP: ctx->vertex_cb = &strip_vertex; break; case GL_TRIANGLE_FAN: ctx->vertex_cb = &fan_vertex; break; default: //printf(stderr, "ERROR, can't handle %d\n", (int) which); ctx->vertex_cb = &skip_vertex; break; } } void combine(const GLdouble newVertex[3], const void *neighborVertex[4], const GLfloat neighborWeight[4], void **outData, void *polyData) { TessContext *ctx = (TessContext *) polyData; Vertex *result = new_vertex(ctx, newVertex[0], newVertex[1]); *outData = result; } void write_output(TessContext *ctx, float **coordinates_out, int **tris_out, int *vc, int *tc) { int n_verts = 1 + ctx->latest_v->index; *vc = n_verts; int n_tris_copy = ctx->n_tris; *tc = ctx->n_tris; *coordinates_out = malloc(n_verts * sizeof(float) * 2); *tris_out = (ctx->n_tris ? malloc(ctx->n_tris * sizeof(int) * 3) : NULL); while (ctx->latest_v) { (*coordinates_out)[2 * ctx->latest_v->index] = ctx->latest_v->pt[0]; (*coordinates_out)[2 * ctx->latest_v->index + 1] = ctx->latest_v->pt[1]; Vertex *prev = ctx->latest_v->prev; free(ctx->latest_v); ctx->latest_v = prev; } while (ctx->latest_t) { (*tris_out)[3 * (n_tris_copy - 1)] = ctx->latest_t->v[0]; (*tris_out)[3 * (n_tris_copy - 1) + 1] = ctx->latest_t->v[1]; (*tris_out)[3 * (n_tris_copy - 1) + 2] = ctx->latest_t->v[2]; Triangle *prev = ctx->latest_t->prev; free(ctx->latest_t); ctx->latest_t = prev; n_tris_copy--; } } void write_outputD(TessContext *ctx, double **coordinates_out, int **tris_out, int *vc, int *tc) { int n_verts = 1 + ctx->latest_v->index; *vc = n_verts; int n_tris_copy = ctx->n_tris; *tc = ctx->n_tris; *coordinates_out = malloc(n_verts * sizeof(double) * 2); *tris_out = (ctx->n_tris ? malloc(ctx->n_tris * sizeof(int) * 3) : NULL); while (ctx->latest_v) { (*coordinates_out)[2 * ctx->latest_v->index] = ctx->latest_v->pt[0]; (*coordinates_out)[2 * ctx->latest_v->index + 1] = ctx->latest_v->pt[1]; Vertex *prev = ctx->latest_v->prev; free(ctx->latest_v); ctx->latest_v = prev; } while (ctx->latest_t) { (*tris_out)[3 * (n_tris_copy - 1)] = ctx->latest_t->v[0]; (*tris_out)[3 * (n_tris_copy - 1) + 1] = ctx->latest_t->v[1]; (*tris_out)[3 * (n_tris_copy - 1) + 2] = ctx->latest_t->v[2]; Triangle *prev = ctx->latest_t->prev; free(ctx->latest_t); ctx->latest_t = prev; n_tris_copy--; } } TessContext *tessellate( float **verts, int *nverts, int **tris, int *ntris, const float **contoursbegin, const float **contoursend) { const float *contourbegin, *contourend; Vertex *current_vertex; GLUtesselator *tess; TessContext *ctx; tess = gluNewTess(); ctx = new_tess_context(); gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (GLvoid (*)()) &vertex); gluTessCallback(tess, GLU_TESS_BEGIN_DATA, (GLvoid (*)()) &begin); gluTessCallback(tess, GLU_TESS_COMBINE_DATA, (GLvoid (*)()) &combine); gluTessBeginPolygon(tess, ctx); do { contourbegin = *contoursbegin++; contourend = *contoursbegin; gluTessBeginContour(tess); while (contourbegin != contourend) { current_vertex = new_vertex(ctx, contourbegin[0], contourbegin[1]); contourbegin += 2; gluTessVertex(tess, current_vertex->pt, current_vertex); } gluTessEndContour(tess); } while (contoursbegin != (contoursend - 1)); gluTessEndPolygon(tess); #ifdef TEST write_output(ctx, verts, tris, nverts, ntris); destroy_tess_context(ctx); #else gluDeleteTess(tess); #endif return ctx; } TessContext *tessellateD( double **verts, int *nverts, int **tris, int *ntris, const double **contoursbegin, const double **contoursend) { const double *contourbegin, *contourend; Vertex *current_vertex; GLUtesselator *tess; TessContext *ctx; tess = gluNewTess(); ctx = new_tess_context(); //tess->normal[2] = -1; gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (GLvoid (*)()) &vertex); gluTessCallback(tess, GLU_TESS_BEGIN_DATA, (GLvoid (*)()) &begin); gluTessCallback(tess, GLU_TESS_COMBINE_DATA, (GLvoid (*)()) &combine); gluTessBeginPolygon(tess, ctx); do { //printf("begin contour\n"); contourbegin = *contoursbegin++; contourend = *contoursbegin; gluTessBeginContour(tess); while (contourbegin != contourend) { //printf("add point %f %f \n", contourbegin[0], contourbegin[1]); current_vertex = new_vertex(ctx, contourbegin[0], contourbegin[1]); contourbegin += 2; gluTessVertex(tess, current_vertex->pt, current_vertex); } gluTessEndContour(tess); } while (contoursbegin != (contoursend - 1)); gluTessEndPolygon(tess); #ifdef TEST write_outputD(ctx, verts, tris, nverts, ntris); destroy_tess_context(ctx); #else gluDeleteTess(tess); #endif return ctx; }