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