Remove CVS keywords.
[mesa.git] / src / glu / mini / tess.c
1
2 /*
3 * Mesa 3-D graphics library
4 * Version: 3.3
5 * Copyright (C) 1995-2000 Brian Paul
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22
23 /*
24 * This file is part of the polygon tesselation code contributed by
25 * Bogdan Sikorski
26 */
27
28
29 #ifdef PC_HEADER
30 #include "all.h"
31 #else
32 #include <math.h>
33 #include <stdlib.h>
34 #include "tess.h"
35 #endif
36
37
38 /*
39 * This is ugly, but seems the easiest way to do things to make the
40 * code work under YellowBox for Windows
41 */
42 #if defined(OPENSTEP) && defined(CALLBACK)
43 #undef CALLBACK
44 #define CALLBACK
45 #endif
46
47
48 static void delete_contours(GLUtriangulatorObj *);
49
50 #ifdef __CYGWIN32__
51 #define _CALLBACK
52 #else
53 #define _CALLBACK GLCALLBACK
54 #endif
55
56
57 static void
58 init_callbacks(tess_callbacks * callbacks)
59 {
60 callbacks->begin = (void (_CALLBACK *) (GLenum)) 0;
61 callbacks->edgeFlag = (void (_CALLBACK *) (GLboolean)) 0;
62 callbacks->vertex = (void (_CALLBACK *) (void *)) 0;
63 callbacks->end = (void (_CALLBACK *) (void)) 0;
64 callbacks->error = (void (_CALLBACK *) (GLenum)) 0;
65 }
66
67 void
68 tess_call_user_error(GLUtriangulatorObj * tobj, GLenum gluerr)
69 {
70 if (tobj->error == GLU_NO_ERROR)
71 tobj->error = gluerr;
72 if (tobj->callbacks.error != NULL)
73 (tobj->callbacks.error) (gluerr);
74 }
75
76 GLUtriangulatorObj *GLAPIENTRY
77 gluNewTess(void)
78 {
79 GLUtriangulatorObj *tobj;
80
81 if ((tobj = (GLUtriangulatorObj *)
82 malloc(sizeof(struct GLUtesselator))) == NULL)
83 return NULL;
84 tobj->contours = tobj->last_contour = NULL;
85 init_callbacks(&tobj->callbacks);
86 tobj->error = GLU_NO_ERROR;
87 tobj->current_polygon = NULL;
88 tobj->contour_cnt = 0;
89 return tobj;
90 }
91
92
93 void GLAPIENTRY
94 gluTessCallback(GLUtriangulatorObj * tobj, GLenum which,
95 void (GLCALLBACK * fn) ())
96 {
97 switch (which) {
98 case GLU_BEGIN:
99 tobj->callbacks.begin = (void (_CALLBACK *) (GLenum)) fn;
100 break;
101 case GLU_EDGE_FLAG:
102 tobj->callbacks.edgeFlag = (void (_CALLBACK *) (GLboolean)) fn;
103 break;
104 case GLU_VERTEX:
105 tobj->callbacks.vertex = (void (_CALLBACK *) (void *)) fn;
106 break;
107 case GLU_END:
108 tobj->callbacks.end = (void (_CALLBACK *) (void)) fn;
109 break;
110 case GLU_ERROR:
111 tobj->callbacks.error = (void (_CALLBACK *) (GLenum)) fn;
112 break;
113 default:
114 tobj->error = GLU_INVALID_ENUM;
115 break;
116 }
117 }
118
119
120
121 void GLAPIENTRY
122 gluDeleteTess(GLUtriangulatorObj * tobj)
123 {
124 if (tobj->error == GLU_NO_ERROR && tobj->contour_cnt)
125 /* was gluEndPolygon called? */
126 tess_call_user_error(tobj, GLU_TESS_ERROR1);
127 /* delete all internal structures */
128 delete_contours(tobj);
129 free(tobj);
130 }
131
132
133 void GLAPIENTRY
134 gluBeginPolygon(GLUtriangulatorObj * tobj)
135 {
136 /*
137 if(tobj->error!=GLU_NO_ERROR)
138 return;
139 */
140 tobj->error = GLU_NO_ERROR;
141 if (tobj->current_polygon != NULL) {
142 /* gluEndPolygon was not called */
143 tess_call_user_error(tobj, GLU_TESS_ERROR1);
144 /* delete all internal structures */
145 delete_contours(tobj);
146 }
147 else {
148 if ((tobj->current_polygon =
149 (tess_polygon *) malloc(sizeof(tess_polygon))) == NULL) {
150 tess_call_user_error(tobj, GLU_OUT_OF_MEMORY);
151 return;
152 }
153 tobj->current_polygon->vertex_cnt = 0;
154 tobj->current_polygon->vertices =
155 tobj->current_polygon->last_vertex = NULL;
156 }
157 }
158
159
160 void GLAPIENTRY
161 gluEndPolygon(GLUtriangulatorObj * tobj)
162 {
163 /*tess_contour *contour_ptr; */
164
165 /* there was an error */
166 if (tobj->error != GLU_NO_ERROR)
167 goto end;
168
169 /* check if gluBeginPolygon was called */
170 if (tobj->current_polygon == NULL) {
171 tess_call_user_error(tobj, GLU_TESS_ERROR2);
172 return;
173 }
174 tess_test_polygon(tobj);
175 /* there was an error */
176 if (tobj->error != GLU_NO_ERROR)
177 goto end;
178
179 /* any real contours? */
180 if (tobj->contour_cnt == 0) {
181 /* delete all internal structures */
182 delete_contours(tobj);
183 return;
184 }
185 tess_find_contour_hierarchies(tobj);
186 /* there was an error */
187 if (tobj->error != GLU_NO_ERROR)
188 goto end;
189
190 tess_handle_holes(tobj);
191 /* there was an error */
192 if (tobj->error != GLU_NO_ERROR)
193 goto end;
194
195 /* if no callbacks, nothing to do */
196 if (tobj->callbacks.begin != NULL && tobj->callbacks.vertex != NULL &&
197 tobj->callbacks.end != NULL) {
198 if (tobj->callbacks.edgeFlag == NULL)
199 tess_tesselate(tobj);
200 else
201 tess_tesselate_with_edge_flag(tobj);
202 }
203
204 end:
205 /* delete all internal structures */
206 delete_contours(tobj);
207 }
208
209
210 void GLAPIENTRY
211 gluNextContour(GLUtriangulatorObj * tobj, GLenum type)
212 {
213 if (tobj->error != GLU_NO_ERROR)
214 return;
215 if (tobj->current_polygon == NULL) {
216 tess_call_user_error(tobj, GLU_TESS_ERROR2);
217 return;
218 }
219 /* first contour? */
220 if (tobj->current_polygon->vertex_cnt)
221 tess_test_polygon(tobj);
222 }
223
224
225 void GLAPIENTRY
226 gluTessVertex(GLUtriangulatorObj * tobj, GLdouble v[3], void *data)
227 {
228 tess_polygon *polygon = tobj->current_polygon;
229 tess_vertex *last_vertex_ptr;
230
231 if (tobj->error != GLU_NO_ERROR)
232 return;
233 if (polygon == NULL) {
234 tess_call_user_error(tobj, GLU_TESS_ERROR2);
235 return;
236 }
237 last_vertex_ptr = polygon->last_vertex;
238 if (last_vertex_ptr == NULL) {
239 if ((last_vertex_ptr = (tess_vertex *)
240 malloc(sizeof(tess_vertex))) == NULL) {
241 tess_call_user_error(tobj, GLU_OUT_OF_MEMORY);
242 return;
243 }
244 polygon->vertices = last_vertex_ptr;
245 polygon->last_vertex = last_vertex_ptr;
246 last_vertex_ptr->data = data;
247 last_vertex_ptr->location[0] = v[0];
248 last_vertex_ptr->location[1] = v[1];
249 last_vertex_ptr->location[2] = v[2];
250 last_vertex_ptr->next = NULL;
251 last_vertex_ptr->previous = NULL;
252 ++(polygon->vertex_cnt);
253 }
254 else {
255 tess_vertex *vertex_ptr;
256
257 /* same point twice? */
258 if (fabs(last_vertex_ptr->location[0] - v[0]) < EPSILON &&
259 fabs(last_vertex_ptr->location[1] - v[1]) < EPSILON &&
260 fabs(last_vertex_ptr->location[2] - v[2]) < EPSILON) {
261 tess_call_user_error(tobj, GLU_TESS_ERROR6);
262 return;
263 }
264 if ((vertex_ptr = (tess_vertex *)
265 malloc(sizeof(tess_vertex))) == NULL) {
266 tess_call_user_error(tobj, GLU_OUT_OF_MEMORY);
267 return;
268 }
269 vertex_ptr->data = data;
270 vertex_ptr->location[0] = v[0];
271 vertex_ptr->location[1] = v[1];
272 vertex_ptr->location[2] = v[2];
273 vertex_ptr->next = NULL;
274 vertex_ptr->previous = last_vertex_ptr;
275 ++(polygon->vertex_cnt);
276 last_vertex_ptr->next = vertex_ptr;
277 polygon->last_vertex = vertex_ptr;
278 }
279 }
280
281
282 static void
283 delete_contours(GLUtriangulatorObj * tobj)
284 {
285 tess_polygon *polygon = tobj->current_polygon;
286 tess_contour *contour, *contour_tmp;
287 tess_vertex *vertex, *vertex_tmp;
288
289 /* remove current_polygon list - if exists due to detected error */
290 if (polygon != NULL) {
291 if (polygon->vertices) {
292 for (vertex = polygon->vertices; vertex != polygon->last_vertex;) {
293 vertex_tmp = vertex->next;
294 free(vertex);
295 vertex = vertex_tmp;
296 }
297 free(vertex);
298 }
299 free(polygon);
300 tobj->current_polygon = NULL;
301 }
302 /* remove all contour data */
303 for (contour = tobj->contours; contour != NULL;) {
304 for (vertex = contour->vertices; vertex != contour->last_vertex;) {
305 vertex_tmp = vertex->next;
306 free(vertex);
307 vertex = vertex_tmp;
308 }
309 free(vertex);
310 contour_tmp = contour->next;
311 free(contour);
312 contour = contour_tmp;
313 }
314 tobj->contours = tobj->last_contour = NULL;
315 tobj->contour_cnt = 0;
316 }
317
318
319 void GLAPIENTRY
320 gluTessNormal(GLUtesselator *tess, GLdouble valueX, GLdouble valueY, GLdouble valueZ)
321 {
322 /* dummy function */
323 (void) tess;
324 (void) valueX;
325 (void) valueY;
326 (void) valueZ;
327 }