| /* $Id: tess.c,v 1.1 1999/08/19 00:55:42 jtg Exp $ */ |
| |
| /* |
| * Mesa 3-D graphics library |
| * Version: 3.1 |
| * Copyright (C) 1995-1999 Brian Paul |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public |
| * License along with this library; if not, write to the Free |
| * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| */ |
| |
| |
| /* |
| * $Log: tess.c,v $ |
| * Revision 1.1 1999/08/19 00:55:42 jtg |
| * Initial revision |
| * |
| * Revision 1.11 1999/02/27 13:55:31 brianp |
| * fixed BeOS-related GLU typedef problems |
| * |
| * Revision 1.10 1999/01/03 03:23:15 brianp |
| * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump) |
| * |
| * Revision 1.9 1998/06/01 01:10:29 brianp |
| * small update for Next/OpenStep from Alexander Mai |
| * |
| * Revision 1.8 1998/02/04 00:27:58 brianp |
| * cygnus changes from Stephane Rehel |
| * |
| * Revision 1.7 1998/01/16 03:35:26 brianp |
| * fixed Windows compilation warnings (Theodore Jump) |
| * |
| * Revision 1.6 1997/09/17 01:51:48 brianp |
| * changed glu*Callback() functions to match prototype in glu.h |
| * |
| * Revision 1.5 1997/07/24 01:28:44 brianp |
| * changed precompiled header symbol from PCH to PC_HEADER |
| * |
| * Revision 1.4 1997/05/28 02:29:38 brianp |
| * added support for precompiled headers (PCH), inserted APIENTRY keyword |
| * |
| * Revision 1.3 1996/11/12 01:23:02 brianp |
| * added test to prevent free(vertex) when vertex==NULL in delete_contours() |
| * |
| * Revision 1.2 1996/10/22 22:57:19 brianp |
| * better error handling in gluBegin/EndPolygon() from Erich Eder |
| * |
| * Revision 1.1 1996/09/27 01:19:39 brianp |
| * Initial revision |
| * |
| */ |
| |
| |
| /* |
| * This file is part of the polygon tesselation code contributed by |
| * Bogdan Sikorski |
| */ |
| |
| |
| #ifdef PC_HEADER |
| #include "all.h" |
| #else |
| #include <math.h> |
| #include <stdlib.h> |
| #include "tess.h" |
| #endif |
| |
| |
| /* |
| * This is ugly, but seems the easiest way to do things to make the |
| * code work under YellowBox for Windows |
| */ |
| #if defined(OPENSTEP) && defined(GLCALLBACK) |
| #undef GLCALLBACK |
| #define GLCALLBACK |
| #endif |
| |
| |
| extern void tess_test_polygon(GLUtriangulatorObj *); |
| extern void tess_find_contour_hierarchies(GLUtriangulatorObj *); |
| extern void tess_handle_holes(GLUtriangulatorObj *); |
| extern void tess_tesselate(GLUtriangulatorObj *); |
| extern void tess_tesselate_with_edge_flag(GLUtriangulatorObj *); |
| static void delete_contours(GLUtriangulatorObj *); |
| |
| #ifdef __CYGWIN32__ |
| #define _CALLBACK |
| #else |
| #define _CALLBACK GLCALLBACK |
| #endif |
| |
| void init_callbacks(tess_callbacks *callbacks) |
| { |
| callbacks->begin = ( void (_CALLBACK*)(GLenum) ) 0; |
| callbacks->edgeFlag = ( void (_CALLBACK*)(GLboolean) ) 0; |
| callbacks->vertex = ( void (_CALLBACK*)(void*) ) 0; |
| callbacks->end = ( void (_CALLBACK*)(void) ) 0; |
| callbacks->error = ( void (_CALLBACK*)(GLenum) ) 0; |
| } |
| |
| void tess_call_user_error(GLUtriangulatorObj *tobj, GLenum gluerr) |
| { |
| if(tobj->error==GLU_NO_ERROR) |
| tobj->error=gluerr; |
| if(tobj->callbacks.error!=NULL) |
| (tobj->callbacks.error)(gluerr); |
| } |
| |
| GLUtriangulatorObj* GLAPIENTRY gluNewTess( void ) |
| { |
| GLUtriangulatorObj *tobj; |
| tobj = (GLUtriangulatorObj *) malloc(sizeof(struct GLUtesselator)); |
| if (!tobj) |
| return NULL; |
| tobj->contours=tobj->last_contour=NULL; |
| init_callbacks(&tobj->callbacks); |
| tobj->error=GLU_NO_ERROR; |
| tobj->current_polygon=NULL; |
| tobj->contour_cnt=0; |
| return tobj; |
| } |
| |
| |
| void GLAPIENTRY gluTessCallback( GLUtriangulatorObj *tobj, GLenum which, |
| void (GLCALLBACK *fn)() ) |
| { |
| switch(which) |
| { |
| case GLU_BEGIN: |
| tobj->callbacks.begin = (void (_CALLBACK*)(GLenum)) fn; |
| break; |
| case GLU_EDGE_FLAG: |
| tobj->callbacks.edgeFlag = (void (_CALLBACK*)(GLboolean)) fn; |
| break; |
| case GLU_VERTEX: |
| tobj->callbacks.vertex = (void (_CALLBACK*)(void *)) fn; |
| break; |
| case GLU_END: |
| tobj->callbacks.end = (void (_CALLBACK*)(void)) fn; |
| break; |
| case GLU_ERROR: |
| tobj->callbacks.error = (void (_CALLBACK*)(GLenum)) fn; |
| break; |
| default: |
| tobj->error=GLU_INVALID_ENUM; |
| break; |
| } |
| } |
| |
| |
| |
| void GLAPIENTRY gluDeleteTess( GLUtriangulatorObj *tobj ) |
| { |
| if(tobj->error==GLU_NO_ERROR && tobj->contour_cnt) |
| /* was gluEndPolygon called? */ |
| tess_call_user_error(tobj,GLU_TESS_ERROR1); |
| /* delete all internal structures */ |
| delete_contours(tobj); |
| free(tobj); |
| } |
| |
| |
| void GLAPIENTRY gluBeginPolygon( GLUtriangulatorObj *tobj ) |
| { |
| /* |
| if(tobj->error!=GLU_NO_ERROR) |
| return; |
| */ |
| tobj->error = GLU_NO_ERROR; |
| if(tobj->current_polygon!=NULL) |
| { |
| /* gluEndPolygon was not called */ |
| tess_call_user_error(tobj,GLU_TESS_ERROR1); |
| /* delete all internal structures */ |
| delete_contours(tobj); |
| } |
| else |
| { |
| if((tobj->current_polygon= |
| (tess_polygon *)malloc(sizeof(tess_polygon)))==NULL) |
| { |
| tess_call_user_error(tobj,GLU_OUT_OF_MEMORY); |
| return; |
| } |
| tobj->current_polygon->vertex_cnt=0; |
| tobj->current_polygon->vertices= |
| tobj->current_polygon->last_vertex=NULL; |
| } |
| } |
| |
| |
| void GLAPIENTRY gluEndPolygon( GLUtriangulatorObj *tobj ) |
| { |
| /*tess_contour *contour_ptr;*/ |
| |
| /* there was an error */ |
| if(tobj->error!=GLU_NO_ERROR) goto end; |
| |
| /* check if gluBeginPolygon was called */ |
| if(tobj->current_polygon==NULL) |
| { |
| tess_call_user_error(tobj,GLU_TESS_ERROR2); |
| return; |
| } |
| tess_test_polygon(tobj); |
| /* there was an error */ |
| if(tobj->error!=GLU_NO_ERROR) goto end; |
| |
| /* any real contours? */ |
| if(tobj->contour_cnt==0) |
| { |
| /* delete all internal structures */ |
| delete_contours(tobj); |
| return; |
| } |
| tess_find_contour_hierarchies(tobj); |
| /* there was an error */ |
| if(tobj->error!=GLU_NO_ERROR) goto end; |
| |
| tess_handle_holes(tobj); |
| /* there was an error */ |
| if(tobj->error!=GLU_NO_ERROR) goto end; |
| |
| /* if no callbacks, nothing to do */ |
| if(tobj->callbacks.begin!=NULL && tobj->callbacks.vertex!=NULL && |
| tobj->callbacks.end!=NULL) |
| { |
| if(tobj->callbacks.edgeFlag==NULL) |
| tess_tesselate(tobj); |
| else |
| tess_tesselate_with_edge_flag(tobj); |
| } |
| |
| end: |
| /* delete all internal structures */ |
| delete_contours(tobj); |
| } |
| |
| |
| void GLAPIENTRY gluNextContour( GLUtriangulatorObj *tobj, GLenum type ) |
| { |
| if(tobj->error!=GLU_NO_ERROR) |
| return; |
| if(tobj->current_polygon==NULL) |
| { |
| tess_call_user_error(tobj,GLU_TESS_ERROR2); |
| return; |
| } |
| /* first contour? */ |
| if(tobj->current_polygon->vertex_cnt) |
| tess_test_polygon(tobj); |
| } |
| |
| |
| void GLAPIENTRY gluTessVertex( GLUtriangulatorObj *tobj, GLdouble v[3], void *data ) |
| { |
| tess_polygon *polygon=tobj->current_polygon; |
| tess_vertex *last_vertex_ptr; |
| |
| if(tobj->error!=GLU_NO_ERROR) |
| return; |
| if(polygon==NULL) |
| { |
| tess_call_user_error(tobj,GLU_TESS_ERROR2); |
| return; |
| } |
| last_vertex_ptr=polygon->last_vertex; |
| if(last_vertex_ptr==NULL) |
| { |
| if((last_vertex_ptr=(tess_vertex *) |
| malloc(sizeof(tess_vertex)))==NULL) |
| { |
| tess_call_user_error(tobj,GLU_OUT_OF_MEMORY); |
| return; |
| } |
| polygon->vertices=last_vertex_ptr; |
| polygon->last_vertex=last_vertex_ptr; |
| last_vertex_ptr->data=data; |
| last_vertex_ptr->location[0]=v[0]; |
| last_vertex_ptr->location[1]=v[1]; |
| last_vertex_ptr->location[2]=v[2]; |
| last_vertex_ptr->next=NULL; |
| last_vertex_ptr->previous=NULL; |
| ++(polygon->vertex_cnt); |
| } |
| else |
| { |
| tess_vertex *vertex_ptr; |
| |
| /* same point twice? */ |
| if(fabs(last_vertex_ptr->location[0]-v[0]) < EPSILON && |
| fabs(last_vertex_ptr->location[1]-v[1]) < EPSILON && |
| fabs(last_vertex_ptr->location[2]-v[2]) < EPSILON) |
| { |
| tess_call_user_error(tobj,GLU_TESS_ERROR6); |
| return; |
| } |
| if((vertex_ptr=(tess_vertex *) |
| malloc(sizeof(tess_vertex)))==NULL) |
| { |
| tess_call_user_error(tobj,GLU_OUT_OF_MEMORY); |
| return; |
| } |
| vertex_ptr->data=data; |
| vertex_ptr->location[0]=v[0]; |
| vertex_ptr->location[1]=v[1]; |
| vertex_ptr->location[2]=v[2]; |
| vertex_ptr->next=NULL; |
| vertex_ptr->previous=last_vertex_ptr; |
| ++(polygon->vertex_cnt); |
| last_vertex_ptr->next=vertex_ptr; |
| polygon->last_vertex=vertex_ptr; |
| } |
| } |
| |
| |
| static void delete_contours(GLUtriangulatorObj *tobj) |
| { |
| tess_polygon *polygon=tobj->current_polygon; |
| tess_contour *contour,*contour_tmp; |
| tess_vertex *vertex,*vertex_tmp; |
| |
| /* remove current_polygon list - if exists due to detected error */ |
| if(polygon!=NULL) |
| { |
| if (polygon->vertices) |
| { |
| for(vertex=polygon->vertices;vertex!=polygon->last_vertex;) |
| { |
| vertex_tmp=vertex->next; |
| free(vertex); |
| vertex=vertex_tmp; |
| } |
| free(vertex); |
| } |
| free(polygon); |
| tobj->current_polygon=NULL; |
| } |
| /* remove all contour data */ |
| for(contour=tobj->contours;contour!=NULL;) |
| { |
| for(vertex=contour->vertices;vertex!=contour->last_vertex;) |
| { |
| vertex_tmp=vertex->next; |
| free(vertex); |
| vertex=vertex_tmp; |
| } |
| free(vertex); |
| contour_tmp=contour->next; |
| free(contour); |
| contour=contour_tmp; |
| } |
| tobj->contours=tobj->last_contour=NULL; |
| tobj->contour_cnt=0; |
| } |
| |
| |
| |