FreeWRL / FreeX3D 4.3.0
Tess.c
1/*
2
3
4???
5
6*/
7
8/****************************************************************************
9 This file is part of the FreeWRL/FreeX3D Distribution.
10
11 Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
12
13 FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
14 it under the terms of the GNU Lesser Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 FreeWRL/FreeX3D is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
25****************************************************************************/
26
27#include <config.h>
28#include <system.h>
29#include <display.h>
30#include <internal.h>
31
32#include <libFreeWRL.h>
33
34#include "../vrml_parser/Structs.h"
35#include "../main/headers.h"
36
37
38
39#if defined(_MSC_VER)
40typedef void (__stdcall *_GLUfuncptr)();
41#endif
42
43/* WIN32 p.411 openGL programmers guide - windows needs CALLBACK, unix not */
44#ifndef CALLBACK
45#define CALLBACK
46#endif
47
48
49/*********************************************************************
50 * General tessellation functions
51 *
52 * to use the tessellation function, you have to
53 * let global_tess_polyrep point towards a structure.
54 * global_tess_polyrep->ntri is the first index number which will
55 * be filled by the routines (which is the number of triangles
56 * already represented in global_tess_polyrep)
57 * global_tess_polyrep->cindex and global_tess_polyrep->coords have
58 * to point towards enough memory.
59 * (And you have to give gluTessVertex a third argument, in which
60 * the new coords are written, it has to be a vector of
61 * GLDOUBLE s with enough space)
62 * After calling gluTessEndPolygon() these vector will be filled.
63 * global_tess_polyrep->ntri will contain the absolute
64 * number of triangles in global_tess_polyrep after tessellation.
65 */
66
67
68typedef struct pTess{
69 int global_IFS_Coords[TESS_MAX_COORDS]; //200,000
70}* ppTess;
71void *Tess_constructor(){
72 void *v = MALLOCV(sizeof(struct pTess));
73 memset(v,0,sizeof(struct pTess));
74 return v;
75}
76void Tess_init(struct tTess *t){
77 //public
78//int global_IFS_Coord_count=0;
79
80 //private
81 t->prv = Tess_constructor();
82 {
83 ppTess p = (ppTess)t->prv;
84 t->global_IFS_Coords = p->global_IFS_Coords;
85 t->text_IFS_Coords = p->global_IFS_Coords;
86 }
87}
88//ppTess p = (ppTess)gglobal()->Tess.prv;
89
90/* OpenGL-ES 2.0 does not have tessellator */
91/* and now all the callback functions, which will be called
92 by OpenGL automatically, if the Polygon is specified */
93
94void CALLBACK FW_tess_begin(GLenum e) {
95 /*printf(" FW_tess_begin e = %s\n", (e == GL_TRIANGLES ? "GL_TRIANGLES" : "UNKNOWN")); */
96 /* we only should get GL_TRIANGLES as type, because
97 we defined the edge_flag callback */
98 /* check, if the structure is there */
99 if(e!=GL_TRIANGLES)
100 freewrlDie("Something went wrong while tessellating!");
101}
102
103void CALLBACK FW_tess_end(void) {
104 /*printf("FW_tess_end: Tesselation done.\n"); */
105 /* nothing to do */
106}
107
108void CALLBACK FW_tess_edgeflag(GLenum flag) {
109 /*printf("FW_tess_edgeflag: An edge was done (flag = %d).\n", flag); */
110 /* nothing to do, this function has to be registered
111 so that only GL_TRIANGLES are used */
112}
113
114void CALLBACK FW_IFS_tess_vertex(void *p) {
115 int *dp;
116 ttglobal tg = gglobal();
117 dp =(int*)p;
118
119 if (tg->Tess.global_IFS_Coord_count == TESS_MAX_COORDS) {
120 /* printf ("FW_IFS_tess_vertex, too many coordinates in this face, change TESS_MAX_COORDS\n"); */
121 /*
122 global_IFS_Coord_count++;
123 global_IFS_Coords[global_IFS_Coord_count] =
124 global_IFS_Coords[global_IFS_Coord_count-1];
125 */
126 } else {
127 //printf ("FW_IFS_tess_vertex, global_ifs_coord count %d, pointer %d\n",tg->Tess.global_IFS_Coord_count,*dp);
128 //if(*dp < 0){
129 // printf("dp pointer = %p\n",dp);
130 //}
131 tg->Tess.global_IFS_Coords[tg->Tess.global_IFS_Coord_count++] = *dp;
132 }
133
134}
135
136void CALLBACK FW_tess_error(GLenum e) {
137 /* Prints out tesselation errors. Older versions of at least MESA would
138 give errors, so for now at least, lets just ignore them.
139 */
140 printf("FW_tess_error %d: >%s<\n",(int) e,GL_ERROR_MSG);
141}
142
143
144
145void CALLBACK FW_tess_combine_text_data (GLDOUBLE c[3], GLfloat *d[4], GLfloat w[4], void **out,void *polygondata) {
146/* Component_Text Combiner
147 printf("FW_tess_combine data\n");
148 printf("combine c:%lf %lf %lf\ndw: %f %f %f %f\n\n",
149 c[0],c[1],c[2],w[0],w[1],w[2],w[3]);
150 printf ("vertex 0 %lf %lf %lf, 1 %lf %lf %lf, 2 %lf %lf %lf, 3 %lf %lf %lf\n",
151 *d[0]->x,*d[0]->y,*d[0]->z,
152 *d[1]->x,*d[1]->y,*d[1]->z,
153 *d[2]->x,*d[2]->y,*d[2]->z,
154 *d[3]->x,*d[3]->y,*d[3]->z);
155
156 printf ("d %d %d %d %d\n",d[0],d[1],d[2],d[3]);
157 printf ("d %f %f %f %f\n",*d[0],*d[1],*d[2],*d[3]);
158 printf ("new coord %d\n",nv);
159*/
160 if(0){
161 GLDOUBLE *nv = MALLOC(GLDOUBLE *, sizeof(GLDOUBLE)*3);
162
163 nv[0] = c[0];
164 nv[1] = c[1];
165 nv[2] = c[2];
166 *out = nv;
167 }else{
168 int FW_pointctr, RAI_indx;
169 text_combiner_data *cbdata;
170 float *coords;
171 //GLDOUBLE *nv = MALLOC(GLDOUBLE *, sizeof(GLDOUBLE)*6);
172 ttglobal tg = gglobal();
173 cbdata = (text_combiner_data*) polygondata;
174
175 //OpenGL Redbook says we must malloc a new point.
176 //but in our Component_Text system, that just means adding it to our
177 //over-malloced list of points actualCoords[]
178 // and to a few other lists of indexes etc as we do in FW_NewVertexPoint() in Component_Text
179 FW_pointctr = *(cbdata->counter);
180 RAI_indx = *(cbdata->riaindex);
181 tg->Tess.global_IFS_Coords[RAI_indx] = FW_pointctr;
182 coords = (float *)cbdata->coords;
183 coords[FW_pointctr*3+0] = (float)c[0];
184 coords[FW_pointctr*3+1] = (float)c[1];
185 coords[FW_pointctr*3+2] = (float)c[2];
186 cbdata->ria[(*cbdata->riaindex)] = FW_pointctr;
187 *out = &cbdata->ria[(*cbdata->riaindex)]; //tell FW_IFS_tess_vertex the index of the new point
188 //printf("combiner, out pointer = %p nv pointer = %p\n",out,*out);
189 //THE SECRET TO COMBINDER SUCCESS? *out == (p) in FW_IFS_tess_vertex(void *p)
190 *(cbdata->counter) = FW_pointctr + 1;
191 (*cbdata->riaindex)++;
192 }
193}
194
195void CALLBACK FW_tess_combine_polyrep_data (GLDOUBLE c[3], GLfloat *d[4], GLfloat w[4], void **out,void *polygondata) {
196/* PolyRep Combiner (not properly implemented as of Aug 5, 2016)
197 printf("FW_tess_combine data\n");
198 printf("combine c:%lf %lf %lf\ndw: %f %f %f %f\n\n",
199 c[0],c[1],c[2],w[0],w[1],w[2],w[3]);
200 printf ("vertex 0 %lf %lf %lf, 1 %lf %lf %lf, 2 %lf %lf %lf, 3 %lf %lf %lf\n",
201 *d[0]->x,*d[0]->y,*d[0]->z,
202 *d[1]->x,*d[1]->y,*d[1]->z,
203 *d[2]->x,*d[2]->y,*d[2]->z,
204 *d[3]->x,*d[3]->y,*d[3]->z);
205
206 printf ("d %d %d %d %d\n",d[0],d[1],d[2],d[3]);
207 printf ("d %f %f %f %f\n",*d[0],*d[1],*d[2],*d[3]);
208 printf ("new coord %d\n",nv);
209*/
210 if(1){
211 GLDOUBLE *nv = MALLOC(GLDOUBLE *, sizeof(GLDOUBLE)*3);
212
213 nv[0] = c[0];
214 nv[1] = c[1];
215 nv[2] = c[2];
216 *out = nv;
217 // doesn't render right: http://dug9.users.sourceforge.net/web3d/tests/CAD/test_IFS_concave_combiner.x3d
218 /*
219 geometry DEF FUNNYU IndexedFaceSet {
220 convex FALSE
221 solid FALSE
222 coordIndex [ 0 1 2 3 4 5 6 7 -1]
223 coord Coordinate {
224 # x-swap-x inner bottom u point criss crossed to force combiner
225 point [ -2 -2 0, -2 2 0, -1 2 0, 1 -1 0, -1 -1 0, 1 2 0, 2 2 0, 2 -2 0,]
226 }
227 }
228 */
229 printf("$"); //debugging
230 }else{
231 //Aug 3, 2016 this doesn't work, didn't pick through polyrep, don't use.
232 /*
233 Current polyrep Algo: ignor opengl tips on combiner, and instead try and capture the index into
234 the original node coord, texcoord, normal via
235 tg->Tess.global_IFS_Coords[tg->Tess.global_IFS_Coord_count++] = *dp;
236 in the vertex callback, as we do for Text
237 Complication: when adding a point, the result may be more triangles, for which there needs to be more
238 normals and texcoords etc.
239
240 Hypothesis: the node orig-to-triangle approach in genpolyrep was to save memory back in 2003. We don't need it now.
241 Proposed polyrep algo A:
242 1. copy node orig data to packed
243 a) de-index
244 b) convert to double for tess
245 c) pack ie [double xyz float rgb float norm float texcoord] for tess, in over-malloced packed array
246 2. tesselate
247 a) add combiner generated pack-points to the bottom of packed array
248 b) out= weighted combined as redbook shows
249 3. copy tesselated to polyrep
250 a) convert to float
251 b) un-pack
252 c) copy unpacked to polyrep for shader
253
254 Proposed polyrep algo B:
255 1. in combiner, malloc combiner points, texcoords, normals, color-per-vertex on extension arrays
256 pass index into extension arrays to *out with a -ve sentinal value, for capture by global_IFS_Coords[] in vertex callback
257 2. in make_polyrep and make_extrusion, when using global_IFS_Coords[] array, watch for -ve index and
258 de-index from the extension arrays
259
260 Proposed polyrep algo C?
261 - when setting the vertexes, instead of giving [double xyz float rgb], give [double xyz int index]
262 - then in here, the 4 float *d points coming in will deliver index.
263 - then (somehow) use those indexes
264
265
266 */
267 //polyrep_combiner_data *cbdata;
268 }
269}
270
271/* Some tesselators will give back garbage. Lets try and remove it */
272/* Text handles errors better itself, so this is just used for Extrusions and IndexedFaceSets */
273void verify_global_IFS_Coords(int max) {
274 int count;
275 ttglobal tg = gglobal();
276
277 for (count = 0; count < tg->Tess.global_IFS_Coord_count; count++) {
278 /*printf ("verifying count %d; val is %d, max %d\n",
279 count,global_IFS_Coords[count],max); */
280 if ((tg->Tess.global_IFS_Coords[count] < 0) ||
281 (tg->Tess.global_IFS_Coords[count] >= max)) {
282
283 if (count == 0) {
284 tg->Tess.global_IFS_Coords[count] = 0;
285 } else {
286 tg->Tess.global_IFS_Coords[count] = tg->Tess.global_IFS_Coords[count-1];
287 }
288
289 }
290 }
291}
292
293void CALLBACK FW_tess_combine (GLDOUBLE c[3], void *d[4], GLfloat w[4], void **out) {
294 GLDOUBLE *nv = MALLOC(GLDOUBLE *, sizeof(GLDOUBLE)*3);
295 /*printf("FW_tess_combine c:%lf %lf %lf\ndw: %f %f %f %f\n\n",
296 c[0],c[1],c[2],w[0],w[1],w[2],w[3]); */
297 nv[0] = c[0];
298 nv[1] = c[1];
299 nv[2] = c[2];
300 *out = nv;
301}
302
303
304/* next function has to be called once, after an OpenGL context is made
305 and before tessellation is started */
306
307void CALLBACK XXtessA() { printf ("GLU_TESS_BEGIN\n"); }
308void CALLBACK XXtessB() { printf ("GLU_TESS_BEGIN_DATA\n"); }
309void CALLBACK XXtessC() { printf ("GLU_TESS_EDGE\n"); }
310void CALLBACK XXtessD() { printf ("GLU_TESS_EDGE_FLAG_DATA\n"); }
311void CALLBACK XXtessE() { printf ("GLU_TESS_VERTEX\n"); }
312void CALLBACK XXtessF() { printf ("GLU_TESS_VERTEX_DATA\n"); }
313void CALLBACK XXtessG() { printf ("GLU_TESS_END\n"); }
314void CALLBACK XXtessH() { printf ("GLU_TESS_END_DATA\n"); }
315void CALLBACK XXtessI() { printf ("GLU_TESS_COMBINE_DATA\n"); }
316void CALLBACK XXtessJ() { printf ("GLU_TESS_ERROR\n"); }
317void CALLBACK XXtessK() { printf ("GLU_TESS_ERROR_DATA\n"); }
318
319
320void new_tessellation(void) {
321 ttglobal tg = gglobal();
322 tg->Tess.global_tessobj=FW_GLU_NEW_TESS();
323 if(!tg->Tess.global_tessobj)
324 freewrlDie("Got no memory for Tessellation Object!");
325
326 /* register the CallBackfunctions */
327 FW_GLU_TESS_CALLBACK(tg->Tess.global_tessobj,GLU_TESS_BEGIN,(_GLUfuncptr)FW_tess_begin);
328 FW_GLU_TESS_CALLBACK(tg->Tess.global_tessobj,GLU_TESS_EDGE_FLAG,(_GLUfuncptr)FW_tess_edgeflag);
329 //FW_GLU_TESS_CALLBACK(tg->Tess.global_tessobj,GLU_VERTEX,(_GLUfuncptr)FW_IFS_tess_vertex);
330 FW_GLU_TESS_CALLBACK(tg->Tess.global_tessobj,GLU_TESS_VERTEX,(_GLUfuncptr)FW_IFS_tess_vertex);
331 FW_GLU_TESS_CALLBACK(tg->Tess.global_tessobj,GLU_TESS_ERROR,(_GLUfuncptr)FW_tess_error);
332 FW_GLU_TESS_CALLBACK(tg->Tess.global_tessobj,GLU_TESS_END,(_GLUfuncptr)FW_tess_end);
333 FW_GLU_TESS_CALLBACK(tg->Tess.global_tessobj, GLU_TESS_COMBINE_DATA,(_GLUfuncptr)FW_tess_combine_polyrep_data); //default combiner, Text must reset to this after doing its own FW_tess_combine_text_data
334 //FW_GLU_TESS_CALLBACK(tg->Tess.global_tessobj, GLU_TESS_COMBINE,(_GLUfuncptr)FW_tess_combine);
335
336 /* Unused right now. */
337/*
338 FW_GLU_TESS_CALLBACK(global_tessobj, GLU_TESS_BEGIN, (_GLUfuncptr)XXtessA);
339 FW_GLU_TESS_CALLBACK(global_tessobj, GLU_TESS_BEGIN_DATA,(_GLUfuncptr)XXtessB);
340 FW_GLU_TESS_CALLBACK(global_tessobj, GLU_TESS_EDGE_FLAG,(_GLUfuncptr)XXtessC);
341 FW_GLU_TESS_CALLBACK(global_tessobj, GLU_TESS_EDGE_FLAG_DATA,(_GLUfuncptr)XXtessD);
342 FW_GLU_TESS_CALLBACK(global_tessobj, GLU_TESS_VERTEX,(_GLUfuncptr)XXtessE);
343 FW_GLU_TESS_CALLBACK(global_tessobj, GLU_TESS_VERTEX_DATA,(_GLUfuncptr)XXtessF);
344 FW_GLU_TESS_CALLBACK(global_tessobj, GLU_TESS_END,(_GLUfuncptr)XXtessG);
345 FW_GLU_TESS_CALLBACK(global_tessobj, GLU_TESS_END_DATA,(_GLUfuncptr)XXtessH);
346 FW_GLU_TESS_CALLBACK(global_tessobj, GLU_TESS_COMBINE_DATA,(_GLUfuncptr)XXtessI);
347 FW_GLU_TESS_CALLBACK(global_tessobj, GLU_TESS_ERROR,(_GLUfuncptr)XXtessJ);
348 FW_GLU_TESS_CALLBACK(global_tessobj, GLU_TESS_ERROR_DATA,(_GLUfuncptr)XXtessK);
349*/
350/* */
351}
352//void register_Text_combiner(){
353// //called before tesselating Text in Component_Text.c
354// ttglobal tg = gglobal();
355// if(tg->Tess.text_tessobj){
356// //FW_GLU_TESS_CALLBACK(tg->Tess.global_tessobj, GLU_TESS_COMBINE_DATA,(_GLUfuncptr)NULL);
357// FW_GLU_TESS_CALLBACK(tg->Tess.text_tessobj, GLU_TESS_COMBINE_DATA,(_GLUfuncptr)FW_tess_combine_text_data);
358// }
359//}
360//void register_Polyrep_combiner(){
361// //called after tesselating Text in Component_Text.c, so in make_polyrep and make_extrusion in GenPolyrep.c this will be the default
362// ttglobal tg = gglobal();
363// if(tg->Tess.global_tessobj){
364// //FW_GLU_TESS_CALLBACK(tg->Tess.global_tessobj, GLU_TESS_COMBINE_DATA,(_GLUfuncptr)NULL);
365// FW_GLU_TESS_CALLBACK(tg->Tess.global_tessobj, GLU_TESS_COMBINE_DATA,(_GLUfuncptr)FW_tess_combine_polyrep_data);
366// }
367//}
368/* next function should be called once at the end, but where? */
369void destruct_tessellation(void) {
370 ttglobal tg = gglobal();
371 FW_GLU_DELETETESS(tg->Tess.global_tessobj);
372 printf("Tessellation Object deleted!\n");
373}
374
375void destruct_text_tessellation(void) {
376 ttglobal tg = gglobal();
377 FW_GLU_DELETETESS(tg->Tess.text_tessobj);
378 printf("Tessellation Object deleted!\n");
379}
380
381void CALLBACK FW_text_tess_vertex(void *p) {
382 int *dp;
383 ttglobal tg = gglobal();
384 dp =(int*)p;
385
386 if (tg->Tess.text_IFS_Coord_count == TESS_MAX_COORDS) {
387 /* printf ("FW_IFS_tess_vertex, too many coordinates in this face, change TESS_MAX_COORDS\n"); */
388 /*
389 global_IFS_Coord_count++;
390 global_IFS_Coords[global_IFS_Coord_count] =
391 global_IFS_Coords[global_IFS_Coord_count-1];
392 */
393 } else {
394 //printf ("FW_IFS_tess_vertex, global_ifs_coord count %d, pointer %d\n",tg->Tess.global_IFS_Coord_count,*dp);
395 //if(*dp < 0){
396 // printf("dp pointer = %p\n",dp);
397 //}
398 tg->Tess.text_IFS_Coords[tg->Tess.text_IFS_Coord_count++] = *dp;
399 }
400
401}
402
403
404void new_text_tessellation(void) {
405 ttglobal tg = gglobal();
406 tg->Tess.text_tessobj=FW_GLU_NEW_TESS();
407 if(!tg->Tess.text_tessobj)
408 freewrlDie("Got no memory for Tessellation Object!");
409
410 /* register the CallBackfunctions */
411 FW_GLU_TESS_CALLBACK(tg->Tess.text_tessobj,GLU_TESS_BEGIN,(_GLUfuncptr)FW_tess_begin);
412 FW_GLU_TESS_CALLBACK(tg->Tess.text_tessobj,GLU_TESS_EDGE_FLAG,(_GLUfuncptr)FW_tess_edgeflag);
413 //FW_GLU_TESS_CALLBACK(tg->Tess.global_tessobj,GLU_VERTEX,(_GLUfuncptr)FW_IFS_tess_vertex);
414 FW_GLU_TESS_CALLBACK(tg->Tess.text_tessobj,GLU_TESS_VERTEX,(_GLUfuncptr)FW_text_tess_vertex);
415 FW_GLU_TESS_CALLBACK(tg->Tess.text_tessobj,GLU_TESS_ERROR,(_GLUfuncptr)FW_tess_error);
416 FW_GLU_TESS_CALLBACK(tg->Tess.text_tessobj,GLU_TESS_END,(_GLUfuncptr)FW_tess_end);
417 FW_GLU_TESS_CALLBACK(tg->Tess.text_tessobj, GLU_TESS_COMBINE_DATA,(_GLUfuncptr)FW_tess_combine_text_data); //default combiner, Text must reset to this after doing its own FW_tess_combine_text_data
418 //FW_GLU_TESS_CALLBACK(tg->Tess.global_tessobj, GLU_TESS_COMBINE,(_GLUfuncptr)FW_tess_combine);
419
420}
Definition Tess.c:68