ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/sm_ogl.c
Revision: 3.15
Committed: Thu Jun 10 15:22:23 1999 UTC (24 years, 10 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.14: +321 -264 lines
Log Message:
Implemented sample quadtree in place of triangle quadtree
Made geometric predicates more robust
Added #define LORES which utilizes a single precision floating point
  sample array, the default is a double sample array
Added topology DEBUG commands (for DEBUG > 1)
Made code optimizations

File Contents

# Content
1 /* Copyright (c) 1998 Silicon Graphics, Inc. */
2
3 #ifndef lint
4 static char SCCSid[] = "$SunId$ SGI";
5 #endif
6
7 /*
8 * sm_ogl.c
9 *
10 * Rendering routines for triangle mesh representation utilizing OpenGL
11 */
12 #include "standard.h"
13
14 #include <GL/gl.h>
15
16 #include "sm_flag.h"
17 #include "sm_list.h"
18 #include "sm_geom.h"
19 #include "sm.h"
20
21 int smClean_notify = TRUE; /*If true:Do full redraw on next update*/
22 static int smCompute_mapping = TRUE;/*If true:re-tonemap on next update */
23 static int smIncremental = FALSE; /*If true: there has been incremental
24 rendering since last full draw */
25 #define MAX_NEW_TRIS 1000
26 #define SM_RENDER_FG 0 /* Render foreground tris only*/
27 #define SM_RENDER_BG 1 /* Render background tris only */
28 #define SM_RENDER_CULL 8 /* Perform view frustum culling */
29 #define BASE 1 /* Indicates base triangle */
30 #define DIR 2 /* Indicates triangle w/directional pts*/
31 /* FOR DISPLAY LIST RENDERING: **********************************************/
32 #define SM_DL_LEVELS 2 /* # of levels down to create display lists */
33 #define SM_DL_LISTS 42 /* # of qtree nodes in tree at above level:
34 should be 2*(4^(SM_DL_LEVELS+1)-1)/(4-1) */
35 static GLuint Display_lists[SM_DL_LISTS][2] = {0};
36 /****************************************************************************/
37
38 /* FOR APPROXIMATION RENDERING **********************************************/
39 typedef struct {
40 float dist; /* average distance */
41 BYTE rgb[3]; /* average color */
42 } QTRAVG; /* average quadtree value */
43
44 typedef struct {
45 QUADTREE qt; /* quadtree node (key & hash value) */
46 QTRAVG av; /* node average */
47 } QT_LUENT; /* lookup table entry */
48
49 static QT_LUENT *qt_htbl = NULL; /* quadtree cache */
50 static int qt_hsiz = 0; /* quadtree cache size */
51 /****************************************************************************/
52
53 /* For DEPTH SORTING ********************************************************/
54 typedef struct _T_DEPTH {
55 int tri;
56 double depth;
57 }T_DEPTH;
58 /**********************************************************************/
59
60 /*
61 * smClean(tmflag) : display has been wiped clean
62 * int tmflag;
63 * Called after display has been effectively cleared, meaning that all
64 * geometry must be resent down the pipeline in the next call to smUpdate().
65 * If tmflag is set, tone-mapping should be performed
66 */
67 smClean(tmflag)
68 int tmflag;
69 {
70 smClean_notify = TRUE;
71 if(tmflag)
72 smCompute_mapping = TRUE;
73 }
74
75 int
76 qtCache_init(nel) /* initialize for at least nel elements */
77 int nel;
78 {
79 static int hsiztab[] = {
80 8191, 16381, 32749, 65521, 131071, 262139, 524287, 1048573, 0
81 };
82 register int i;
83
84 if (nel <= 0) { /* call to free table */
85 if (qt_hsiz) {
86 free((char *)qt_htbl);
87 qt_htbl = NULL;
88 qt_hsiz = 0;
89 }
90 return(0);
91 }
92 nel += nel>>1; /* 66% occupancy */
93 for (i = 0; hsiztab[i]; i++)
94 if (hsiztab[i] > nel)
95 break;
96 if (!(qt_hsiz = hsiztab[i]))
97 qt_hsiz = nel*2 + 1; /* not always prime */
98 qt_htbl = (QT_LUENT *)calloc(qt_hsiz, sizeof(QT_LUENT));
99 if (qt_htbl == NULL)
100 qt_hsiz = 0;
101 for (i = qt_hsiz; i--; )
102 qt_htbl[i].qt = EMPTY;
103 return(qt_hsiz);
104 }
105
106 QT_LUENT *
107 qtCache_find(qt) /* find a quadtree table entry */
108 QUADTREE qt;
109 {
110 int i, n;
111 register int ndx;
112 register QT_LUENT *le;
113
114 if (qt_hsiz == 0 && !qtCache_init(1))
115 return(NULL);
116 tryagain: /* hash table lookup */
117 ndx = (unsigned long)qt % qt_hsiz;
118 for (i = 0, n = 1; i < qt_hsiz; i++, n += 2) {
119 le = &qt_htbl[ndx];
120 if (QT_IS_EMPTY(le->qt) || le->qt == qt)
121 return(le);
122 if ((ndx += n) >= qt_hsiz) /* this happens rarely */
123 ndx = ndx % qt_hsiz;
124 }
125 /* table is full, reallocate */
126 le = qt_htbl;
127 ndx = qt_hsiz;
128 if (!qtCache_init(ndx+1)) { /* no more memory! */
129 qt_htbl = le;
130 qt_hsiz = ndx;
131 return(NULL);
132 }
133 /* copy old table to new and free */
134 while (ndx--)
135 if (!QT_IS_EMPTY(le[ndx].qt))
136 copystruct(qtCache_find(le[ndx].qt), &le[ndx]);
137 free((char *)le);
138 goto tryagain; /* should happen only once! */
139 }
140
141 stCount_level_leaves(lcnt, qt) /* count quadtree leaf nodes at each level */
142 int lcnt[];
143 register QUADTREE qt;
144 {
145 if (QT_IS_EMPTY(qt))
146 return;
147 if (QT_IS_TREE(qt)) {
148 if (!QT_IS_FLAG(qt)) /* not in our frustum */
149 return;
150 stCount_level_leaves(lcnt+1, QT_NTH_CHILD(qt,0));
151 stCount_level_leaves(lcnt+1, QT_NTH_CHILD(qt,1));
152 stCount_level_leaves(lcnt+1, QT_NTH_CHILD(qt,2));
153 stCount_level_leaves(lcnt+1, QT_NTH_CHILD(qt,3));
154 }
155 else
156 if(QT_LEAF_IS_FLAG(qt))
157 lcnt[0]++;
158 }
159
160 QTRAVG *
161 qtRender_level(qt,v0,v1,v2,sm,lvl)
162 QUADTREE qt;
163 FVECT v0,v1,v2;
164 SM *sm;
165 int lvl;
166 {
167 FVECT a,b,c;
168 register QT_LUENT *le;
169 QTRAVG *rc[4];
170 TRI *tri;
171
172 if (QT_IS_EMPTY(qt)) /* empty leaf node */
173 return(NULL);
174 if (QT_IS_TREE(qt) && !QT_IS_FLAG(qt)) /* not in our frustum */
175 return(NULL);
176 if(QT_IS_LEAF(qt) && !QT_LEAF_IS_FLAG(qt)) /* not in our frustum */
177 return(NULL);
178 /* else look up node */
179 if ((le = qtCache_find(qt)) == NULL)
180 error(SYSTEM, "out of memory in qtRender_level");
181 if (QT_IS_TREE(qt) && (QT_IS_EMPTY(le->qt) || lvl > 0))
182 { /* compute children */
183 qtSubdivide_tri(v0,v1,v2,a,b,c);
184 rc[0] = qtRender_level(QT_NTH_CHILD(qt,0),v0,c,b,sm,lvl-1);
185 rc[1] = qtRender_level(QT_NTH_CHILD(qt,1),c,v1,a,sm,lvl-1);
186 rc[2] = qtRender_level(QT_NTH_CHILD(qt,2),b,a,v2,sm,lvl-1);
187 rc[3] = qtRender_level(QT_NTH_CHILD(qt,3),a,b,c,sm,lvl-1);
188 }
189 if (QT_IS_EMPTY(le->qt))
190 { /* let's make some data! */
191 int rgbs[3];
192 double distsum;
193 register int i, n;
194 /* average our triangle vertices */
195 rgbs[0] = rgbs[1] = rgbs[2] = 0;
196 distsum = 0.; n = 0;
197 if(QT_IS_TREE(qt))
198 { /* from subtree */
199 for (i = 4; i--; )
200 if (rc[i] != NULL)
201 {
202 rgbs[0] += rc[i]->rgb[0]; rgbs[1] += rc[i]->rgb[1];
203 rgbs[2] += rc[i]->rgb[2]; distsum += rc[i]->dist; n++;
204 }
205 }
206 else
207 { /* from triangle set */
208 OBJECT *os;
209 int s0, s1, s2,s_id,t_id;
210 TRI *tri,*t;
211
212 os = qtqueryset(qt);
213 for (i = os[0]; i; i--)
214 {
215 s_id = os[i];
216 t_id = SM_NTH_VERT(smMesh,s_id);
217 tri = t = SM_NTH_TRI(smMesh,t_id);
218 do
219 {
220 if(!SM_IS_NTH_T_BASE(sm,t_id))
221 {
222 n++;
223 s0 = T_NTH_V(t,0);
224 s1 = T_NTH_V(t,1);
225 s2 = T_NTH_V(t,2);
226 VCOPY(a,SM_NTH_WV(sm,s0));
227 VCOPY(b,SM_NTH_WV(sm,s1));
228 VCOPY(c,SM_NTH_WV(sm,s2));
229 distsum += SM_BG_SAMPLE(sm,s0) ? dev_zmax
230 : sqrt(dist2(a,SM_VIEW_CENTER(sm)));
231 distsum += SM_BG_SAMPLE(sm,s1) ? dev_zmax
232 : sqrt(dist2(b,SM_VIEW_CENTER(sm)));
233 distsum += SM_BG_SAMPLE(sm,s2) ? dev_zmax
234 : sqrt(dist2(c,SM_VIEW_CENTER(sm)));
235 rgbs[0] += SM_NTH_RGB(sm,s0)[0] + SM_NTH_RGB(sm,s1)[0]
236 + SM_NTH_RGB(sm,s2)[0];
237 rgbs[1] += SM_NTH_RGB(sm,s0)[1] + SM_NTH_RGB(sm,s1)[1]
238 + SM_NTH_RGB(sm,s2)[1];
239 rgbs[2] += SM_NTH_RGB(sm,s0)[2] + SM_NTH_RGB(sm,s1)[2]
240 + SM_NTH_RGB(sm,s2)[2];
241 }
242
243 t_id = smTri_next_ccw_nbr(smMesh,t,s_id);
244 t = SM_NTH_TRI(smMesh,t_id);
245
246 }while(t != tri);
247 }
248 n *= 3;
249 }
250 if (!n)
251 return(NULL);
252 le->qt = qt;
253 le->av.rgb[0] = rgbs[0]/n; le->av.rgb[1] = rgbs[1]/n;
254 le->av.rgb[2] = rgbs[2]/n; le->av.dist = distsum/(double)n;
255 }
256 if (lvl == 0 || (lvl > 0 && QT_IS_LEAF(qt)))
257 { /* render this node */
258 /* compute pseudo vertices */
259 VCOPY(a,v0); VCOPY(b,v1); VCOPY(c,v2);
260 normalize(a); normalize(b); normalize(c);
261 VSUM(a,SM_VIEW_CENTER(sm),a,le->av.dist);
262 VSUM(b,SM_VIEW_CENTER(sm),b,le->av.dist);
263 VSUM(c,SM_VIEW_CENTER(sm),c,le->av.dist);
264 /* draw triangle */
265 glColor3ub(le->av.rgb[0],le->av.rgb[1],le->av.rgb[2]);
266 glVertex3d(a[0],a[1],a[2]);
267 glVertex3d(b[0],b[1],b[2]);
268 glVertex3d(c[0],c[1],c[2]);
269
270 }
271 return(&le->av);
272 }
273
274
275
276
277 smRender_approx_stree_level(sm,lvl)
278 SM *sm;
279 int lvl;
280 {
281 QUADTREE qt;
282 int i;
283 FVECT t0,t1,t2;
284 STREE *st;
285
286
287 if (lvl < 0)
288 return;
289 st = SM_LOCATOR(sm);
290 glPushAttrib(GL_LIGHTING_BIT);
291 glShadeModel(GL_FLAT);
292 glBegin(GL_TRIANGLES);
293 for(i=0; i < ST_NUM_ROOT_NODES; i++)
294 {
295 qt = ST_ROOT_QT(st,i);
296 qtRender_level(qt,ST_NTH_V(st,i,0),ST_NTH_V(st,i,1),ST_NTH_V(st,i,2),
297 sm,lvl);
298 }
299 glEnd();
300 glPopAttrib();
301 }
302
303 /*
304 * smRender_approx(sm,qual,view)
305 * SM *sm; : mesh
306 * int qual; : quality level
307 * VIEW *view; : current view
308 *
309 * Renders an approximation to the current mesh based on the quadtree
310 * subdivision. The quadtree is traversed to a level (based upon the quality:
311 * the lower the quality, the fewer levels visited, and the coarser, and
312 * faster, the approximation). The quadtree triangles are drawn relative to
313 * the current viewpoint, with a depth and color averaged from all of the
314 * triangles that lie beneath the node.
315 */
316 smRender_approx(sm, qual,view)
317 SM *sm;
318 int qual;
319 VIEW *view;
320 {
321 int i, n,ntarget;
322 int lvlcnt[QT_MAX_LEVELS];
323 STREE *st;
324 int4 *active_flag;
325
326 if (qual <= 0)
327 return;
328 smCull(sm,view,SM_ALL_LEVELS);
329 /* compute rendering target */
330 ntarget = 0;
331
332 active_flag = SM_NTH_FLAGS(sm,T_ACTIVE_FLAG);
333 for(n=((SM_NUM_TRI(sm)+31)>>5) +1; --n;)
334 if(active_flag[n])
335 for(i=0; i < 32; i++)
336 if(active_flag[n] & (1L << i))
337 ntarget++;
338
339 ntarget = ntarget*qual/MAXQUALITY;
340 if (!ntarget)
341 return;
342 for (i = QT_MAX_LEVELS; i--; )
343 lvlcnt[i] = 0;
344
345 st = SM_LOCATOR(sm);
346 for(i=0; i < ST_NUM_ROOT_NODES;i++)
347 stCount_level_leaves(lvlcnt, ST_ROOT_QT(st,i));
348
349 for (ntarget -= lvlcnt[i=0]; i < QT_MAX_LEVELS-1; ntarget -= lvlcnt[++i])
350 if (ntarget < lvlcnt[i+1])
351 break;
352 /* compute and render target level */
353 smRender_approx_stree_level(sm,i);
354 }
355
356 #ifndef LORES
357 #define GLVERTEX3V(v) glVertex3dv(v)
358 #else
359 #define GLVERTEX3V(v) glVertex3fv(v)
360 #endif
361
362 #define render_tri(v0,v1,v2,rgb0,rgb1,rgb2) \
363 {glColor3ub(rgb0[0],rgb0[1],rgb0[2]); GLVERTEX3V(v0); \
364 glColor3ub(rgb1[0],rgb1[1],rgb1[2]); GLVERTEX3V(v1); \
365 glColor3ub(rgb2[0],rgb2[1],rgb2[2]); GLVERTEX3V(v2);}
366
367 /*
368 * render_mixed_tri(v0,v1,v2,rgb0,rgb1,rgb2,b0,b1,b2)
369 * SFLOAT v0[3],v1[3],v2[3]; : triangle vertex coordinates
370 * BYTE rgb0[3],rgb1[3],rgb2[3]; : vertex RGBs
371 * int b0,b1,b2; : background or base vertex flag
372 *
373 * For triangles with one or more base or directional vertices.
374 * render base vertex color as average of the background and foreground
375 * vertex RGBs. The coordinates for a fg vertex are calculated by
376 * subtracting off the current view,normalizing, then scaling to fit
377 * into the current frustum.
378 */
379 render_mixed_tri(v0,v1,v2,rgb0,rgb1,rgb2,vp,vc,bg0,bg1,bg2)
380 SFLOAT v0[3],v1[3],v2[3];
381 BYTE rgb0[3],rgb1[3],rgb2[3];
382 FVECT vp,vc;
383 int bg0,bg1,bg2;
384 {
385 double d,p[3];
386 int j,cnt,rgb[3];
387
388 /* Average color from bg vertices */
389 cnt = 0;
390 if(bg0 == BASE || bg1==BASE || bg2 == BASE)
391 {
392 rgb[0] = rgb[1] = rgb[2] = 0;
393 if(bg0 != BASE)
394 {
395 IADDV3(rgb,rgb0);
396 cnt++;
397 }
398 if(bg1 != BASE)
399 {
400 IADDV3(rgb,rgb1);
401 cnt++;
402 }
403 if(bg2 != BASE)
404 {
405 IADDV3(rgb,rgb2);
406 cnt++;
407 }
408 IDIVV3(rgb,cnt);
409 }
410 if(bg0 == BASE)
411 glColor3i(rgb[0],rgb[1],rgb[2]);
412 else
413 glColor3ub(rgb0[0],rgb0[1],rgb0[2]);
414
415 if(!bg0)
416 {
417 VSUB(p,v0,vp);
418 normalize(p);
419 IADDV3(p,vc);
420 glVertex3dv(p);
421 }
422 else
423 GLVERTEX3V(v0);
424
425 if(bg1 == BASE)
426 glColor3i(rgb[0],rgb[1],rgb[2]);
427 else
428 glColor3ub(rgb1[0],rgb1[1],rgb1[2]);
429
430 if(!bg1)
431 {
432 VSUB(p,v1,vp);
433 normalize(p);
434 IADDV3(p,vc);
435 glVertex3dv(p);
436 }
437 else
438 GLVERTEX3V(v1);
439
440 if(bg2 == BASE)
441 glColor3i(rgb[0],rgb[1],rgb[2]);
442 else
443 glColor3ub(rgb2[0],rgb2[1],rgb2[2]);
444
445 if(!bg2)
446 {
447 VSUB(p,v2,vp);
448 normalize(p);
449 IADDV3(p,vc);
450 glVertex3dv(p);
451 }
452 else
453 GLVERTEX3V(v2);
454 }
455
456 /*
457 * smRender_bg_tris(sm,vp,t_flag,bg_flag,wp,rgb)
458 * SM *sm; : mesh
459 * FVECT vp; : current viewpoint
460 * int4 *t_flag,*bg_flag; : triangle flags: t_flag is generic,
461 * and bg_flag indicates if background tri;
462 * SFLOAT (*wp)[3];BYTE (*rgb)[3]; : arrays of sample points and RGB colors
463 *
464 * Sequentially traverses triangle list and renders all valid tris who
465 * have t_flag set, and bg_flag set.
466 */
467
468 smRender_bg_tris(sm,vp,t_flag,bg_flag,wp,rgb)
469 SM *sm;
470 FVECT vp;
471 int4 *t_flag,*bg_flag;
472 SFLOAT (*wp)[3];
473 BYTE (*rgb)[3];
474 {
475 double d;
476 int v0_id,v1_id,v2_id;
477 int i,n,bg0,bg1,bg2;
478 TRI *tri;
479
480 glMatrixMode(GL_MODELVIEW);
481
482 glPushMatrix();
483 glTranslated(vp[0],vp[1],vp[2]);
484 /* The points are a distance of 1 away from the origin: if necessary scale
485 so that they fit in frustum and are therefore not clipped away
486 */
487 if(dev_zmin >= 0.99)
488 {
489 d = (dev_zmin+dev_zmax)/2.0;
490 glScaled(d,d,d);
491 }
492 /* move relative to the new view */
493 /* move points to unit sphere at origin */
494 glTranslated(-SM_VIEW_CENTER(sm)[0],-SM_VIEW_CENTER(sm)[1],
495 -SM_VIEW_CENTER(sm)[2]);
496 glBegin(GL_TRIANGLES);
497 for(n=((SM_NUM_TRI(sm)+31)>>5) +1; --n;)
498 if(t_flag[n] & bg_flag[n])
499 for(i=0; i < 32; i++)
500 if(t_flag[n] & bg_flag[n] & (1L << i))
501 {
502 tri = SM_NTH_TRI(sm,(n<<5)+i);
503 v0_id = T_NTH_V(tri,0);
504 v1_id = T_NTH_V(tri,1);
505 v2_id = T_NTH_V(tri,2);
506 bg0 = SM_DIR_ID(sm,v0_id)?DIR:SM_BASE_ID(sm,v0_id)?BASE:0;
507 bg1 = SM_DIR_ID(sm,v1_id)?DIR:SM_BASE_ID(sm,v1_id)?BASE:0;
508 bg2 = SM_DIR_ID(sm,v2_id)?DIR:SM_BASE_ID(sm,v2_id)?BASE:0;
509 if(bg0==DIR && bg1==DIR && bg2==DIR)
510 render_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
511 rgb[v2_id])
512 else
513 render_mixed_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],
514 rgb[v1_id],rgb[v2_id],vp,SM_VIEW_CENTER(sm),bg0,bg1,bg2);
515 }
516 glEnd();
517
518 glPopMatrix();
519
520 }
521 /*
522 * smRender_new_bg_tris(sm,vp,t_flag,bg_flag,wp,rgb)
523 * SM *sm; : mesh
524 * FVECT vp; : current viewpoint
525 * int4 *t_flag,*bg_flag; : triangle flags: t_flag is generic,
526 * and bg_flag indicates if background tri;
527 * SFLOAT (*wp)[3];BYTE (*rgb)[3]; : arrays of sample points and RGB colors
528 *
529 * Sequentially traverses triangle list and renders all valid tris who
530 * have t_flag set, and bg_flag set.
531 */
532
533 smRender_new_bg_tris(sm,vp,new_flag,active_flag,bg_flag,wp,rgb)
534 SM *sm;
535 FVECT vp;
536 int4 *new_flag,*active_flag,*bg_flag;
537 SFLOAT (*wp)[3];
538 BYTE (*rgb)[3];
539 {
540 double d;
541 int v0_id,v1_id,v2_id;
542 int i,n,bg0,bg1,bg2;
543 TRI *tri;
544
545 glMatrixMode(GL_MODELVIEW);
546
547 glPushMatrix();
548 glTranslated(vp[0],vp[1],vp[2]);
549 /* The points are a distance of 1 away from the origin: if necessary scale
550 so that they fit in frustum and are therefore not clipped away
551 */
552 if(dev_zmin >= 0.99)
553 {
554 d = (dev_zmin+dev_zmax)/2.0;
555 glScaled(d,d,d);
556 }
557 /* move relative to the new view */
558 /* move points to unit sphere at origin */
559 glTranslated(-SM_VIEW_CENTER(sm)[0],-SM_VIEW_CENTER(sm)[1],
560 -SM_VIEW_CENTER(sm)[2]);
561 glBegin(GL_TRIANGLES);
562 for(n=((SM_NUM_TRI(sm)+31)>>5) +1; --n;)
563 if(new_flag[n] & active_flag[n] & bg_flag[n])
564 for(i=0; i < 32; i++)
565 if(new_flag[n] & active_flag[n] & bg_flag[n] & (1L << i))
566 {
567 tri = SM_NTH_TRI(sm,(n<<5)+i);
568 v0_id = T_NTH_V(tri,0);
569 v1_id = T_NTH_V(tri,1);
570 v2_id = T_NTH_V(tri,2);
571 bg0 = SM_DIR_ID(sm,v0_id)?DIR:SM_BASE_ID(sm,v0_id)?BASE:0;
572 bg1 = SM_DIR_ID(sm,v1_id)?DIR:SM_BASE_ID(sm,v1_id)?BASE:0;
573 bg2 = SM_DIR_ID(sm,v2_id)?DIR:SM_BASE_ID(sm,v2_id)?BASE:0;
574 if(bg0==DIR && bg1==DIR && bg2==DIR)
575 render_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
576 rgb[v2_id])
577 else
578 render_mixed_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],
579 rgb[v1_id],rgb[v2_id],vp,SM_VIEW_CENTER(sm),bg0,bg1,bg2);
580 }
581 glEnd();
582
583 glPopMatrix();
584
585 }
586
587 /*
588 * render_base_tri(v0,v1,v2,rgb0,rgb1,rgb2,vp,b0,b1,b2)
589 * SFLOAT v0[3],v1[3],v2[3]; : triangle vertex coordinates
590 * BYTE rgb0[3],rgb1[3],rgb2[3]; : vertex RGBs
591 * FVECT vp; : current viewpoint
592 * int b0,b1,b2; : vertex base flag
593 *
594 * render base vertex color as average of the non-base vertex RGBs. The
595 * base vertex coordinate is taken as the stored vector, scaled out by
596 * the average distance to the non-base vertices
597 */
598 render_base_tri(v0,v1,v2,rgb0,rgb1,rgb2,vp,b0,b1,b2)
599 SFLOAT v0[3],v1[3],v2[3];
600 BYTE rgb0[3],rgb1[3],rgb2[3];
601 FVECT vp;
602 int b0,b1,b2;
603 {
604 int cnt;
605 int rgb[3];
606 double d;
607 double p[3];
608
609 cnt = 0;
610 rgb[0] = rgb[1] = rgb[2] = 0;
611 d = 0.0;
612
613 if(b0&&b1&&b2)
614 return;
615 /* First calculate color and coordinates
616 for base vertices based on world space vertices*/
617 if(!b0)
618 {
619 IADDV3(rgb,rgb0);
620 d += DIST(v0,vp);
621 cnt++;
622 }
623 if(!b1)
624 {
625 IADDV3(rgb,rgb1);
626 d += DIST(v1,vp);
627 cnt++;
628 }
629 if(!b2)
630 {
631 IADDV3(rgb,rgb2);
632 d += DIST(v2,vp);
633 cnt++;
634 }
635 IDIVV3(rgb,cnt);
636 d /= (double)cnt;
637
638 /* Now render triangle */
639 if(b0)
640 {
641 glColor3ub(rgb[0],rgb[1],rgb[2]);
642 SUBV3(p,v0,vp);
643 ISCALEV3(p,d);
644 IADDV3(p,vp);
645 glVertex3dv(p);
646 }
647 else
648 {
649 glColor3ub(rgb0[0],rgb0[1],rgb0[2]);
650 GLVERTEX3V(v0);
651 }
652 if(b1)
653 {
654 glColor3ub(rgb[0],rgb[1],rgb[2]);
655 SUBV3(p,v1,vp);
656 ISCALEV3(p,d);
657 IADDV3(p,vp);
658 glVertex3dv(p);
659 }
660 else
661 {
662 glColor3ub(rgb1[0],rgb1[1],rgb1[2]);
663 GLVERTEX3V(v1);
664 }
665 if(b2)
666 {
667 glColor3ub(rgb[0],rgb[1],rgb[2]);
668 SUBV3(p,v2,vp);
669 ISCALEV3(p,d);
670 IADDV3(p,vp);
671 glVertex3dv(p);
672 }
673 else
674 {
675 glColor3ub(rgb2[0],rgb2[1],rgb2[2]);
676 GLVERTEX3V(v2);
677 }
678 }
679 /*
680 * smRender_fg_tris(sm,vp,t_flag,bg_flag,wp,rgb)
681 * SM *sm; : mesh
682 * FVECT vp; : current viewpoint
683 * int4 *t_flag,*bg_flag; : triangle flags: t_flag is generic,bg_flag
684 * indicates if background tri;
685 * SFLOAT (*wp)[3];BYTE (*rgb)[3]; : arrays of sample points and RGB colors
686 *
687 * Sequentially gos through triangle list and renders all valid tris who
688 * have t_flag set, and NOT bg_flag set.
689 */
690 smRender_fg_tris(sm,vp,t_flag,bg_flag,wp,rgb)
691 SM *sm;
692 FVECT vp;
693 int4 *t_flag,*bg_flag;
694 SFLOAT (*wp)[3];
695 BYTE (*rgb)[3];
696 {
697 TRI *tri;
698 int i,n,b0,b1,b2;
699 int v0_id,v1_id,v2_id;
700
701 glBegin(GL_TRIANGLES);
702 for(n=((SM_NUM_TRI(sm)+31)>>5) +1; --n;)
703 if(t_flag[n])
704 for(i=0; i < 32; i++)
705 if(t_flag[n] & (1L << i) & ~bg_flag[n])
706 {
707 tri = SM_NTH_TRI(sm,(n<<5)+i);
708 v0_id = T_NTH_V(tri,0);
709 v1_id = T_NTH_V(tri,1);
710 v2_id = T_NTH_V(tri,2);
711 b0 = SM_BASE_ID(sm,v0_id);
712 b1 = SM_BASE_ID(sm,v1_id);
713 b2 = SM_BASE_ID(sm,v2_id);
714 if(b0 || b1 || b2)
715 render_base_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],
716 rgb[v1_id],rgb[v2_id],SM_VIEW_CENTER(sm),b0,b1,b2);
717 else
718 render_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
719 rgb[v2_id])
720
721 }
722 glEnd();
723
724 }
725
726 /*
727 * smRender_fg_tris(sm,vp,t_flag,bg_flag,wp,rgb)
728 * SM *sm; : mesh
729 * FVECT vp; : current viewpoint
730 * int4 *t_flag,*bg_flag; : triangle flags: t_flag is generic,bg_flag
731 * indicates if background tri;
732 * SFLOAT (*wp)[3];BYTE (*rgb)[3]; : arrays of sample points and RGB colors
733 *
734 * Sequentially gos through triangle list and renders all valid tris who
735 * have t_flag set, and NOT bg_flag set.
736 */
737 smRender_new_fg_tris(sm,vp,new_flag,active_flag,bg_flag,wp,rgb)
738 SM *sm;
739 FVECT vp;
740 int4 *new_flag,*active_flag,*bg_flag;
741 SFLOAT (*wp)[3];
742 BYTE (*rgb)[3];
743 {
744 TRI *tri;
745 int i,n,b0,b1,b2;
746 int v0_id,v1_id,v2_id;
747
748 glBegin(GL_TRIANGLES);
749 for(n=((SM_NUM_TRI(sm)+31)>>5) +1; --n;)
750 if(new_flag[n] & active_flag[n])
751 for(i=0; i < 32; i++)
752 if(new_flag[n] & active_flag[n] & (1L << i) & ~bg_flag[n])
753 {
754 tri = SM_NTH_TRI(sm,(n<<5)+i);
755 v0_id = T_NTH_V(tri,0);
756 v1_id = T_NTH_V(tri,1);
757 v2_id = T_NTH_V(tri,2);
758 b0 = SM_BASE_ID(sm,v0_id);
759 b1 = SM_BASE_ID(sm,v1_id);
760 b2 = SM_BASE_ID(sm,v2_id);
761 if(b0 || b1 || b2)
762 render_base_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],
763 rgb[v1_id],rgb[v2_id],SM_VIEW_CENTER(sm),b0,b1,b2);
764 else
765 render_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
766 rgb[v2_id])
767
768 }
769 glEnd();
770
771 }
772
773
774 int
775 compare_tri_depths(T_DEPTH *td1,T_DEPTH *td2)
776 {
777 double d;
778
779 d = td2->depth-td1->depth;
780 if(d > 0.0)
781 return(1);
782 if(d < 0.0)
783 return(-1);
784 return(0);
785 }
786
787
788 /*
789 * smOrder_new_tris(sm,vp,td)
790 * SM *sm; : mesh
791 * FVECT vp; : current viewpoint
792 * T_DEPTH *td; : holds returned list of depth sorted tris
793 *
794 * Creates list of all new tris, with their distance from the current
795 * viewpoint, and sorts the list based on this distance
796 */
797 T_DEPTH
798 *smOrder_new_tris(sm,vp)
799 SM *sm;
800 FVECT vp;
801 {
802 T_DEPTH *td;
803 int n,i,j,tcnt,v,size;
804 TRI *tri;
805 double d,min_d;
806 FVECT diff;
807 int4 *new_flag,*bg_flag,*active_flag;
808
809 td = (T_DEPTH *)tempbuf(MAX_NEW_TRIS*sizeof(T_DEPTH),FALSE);
810 size = MAX_NEW_TRIS;
811
812 tcnt=0;
813 new_flag = SM_NTH_FLAGS(sm,T_NEW_FLAG);
814 bg_flag = SM_NTH_FLAGS(sm,T_BG_FLAG);
815 active_flag = SM_NTH_FLAGS(sm,T_ACTIVE_FLAG);
816 for(n=((SM_NUM_TRI(sm)+31)>>5) +1; --n;)
817 if(active_flag[n] & new_flag[n] & ~bg_flag[n])
818 for(i=0; i < 32; i++)
819 if(active_flag[n] & new_flag[n] & (1L << i) & ~bg_flag[n])
820 {
821 tri = SM_NTH_TRI(sm,(n<<5)+i);
822 if(tcnt+1 >= size)
823 {
824 size += 100;
825 td = (T_DEPTH *)tempbuf(size*sizeof(T_DEPTH),TRUE);
826 }
827 td[tcnt].tri = (n << 5)+i;
828 min_d = -1;
829 for(j=0;j < 3;j++)
830 {
831 v = T_NTH_V(tri,j);
832 VSUB(diff,SM_NTH_WV(sm,v),vp);
833 d = DOT(diff,diff);
834 if(min_d == -1 || d < min_d)
835 min_d = d;
836 }
837 td[tcnt++].depth = min_d;
838 }
839 td[tcnt].tri = -1;
840 if(tcnt)
841 qsort((void *)td,tcnt,sizeof(T_DEPTH),compare_tri_depths);
842 return(td);
843 }
844
845 /*
846 * smUpdate_tm(sm) : Update the tone-mapping
847 * SM *sm; : mesh
848 *
849 */
850 smUpdate_tm(sm)
851 SM *sm;
852 {
853 int t = SM_TONE_MAP(sm);
854
855 if(t==0 || smCompute_mapping)
856 {
857 tmClearHisto();
858 tmAddHisto(SM_BRT(sm),SM_NUM_SAMP(sm),1);
859 if(tmComputeMapping(0.,0.,0.) != TM_E_OK)
860 return;
861 t = 0;
862 smCompute_mapping = FALSE;
863 }
864 tmMapPixels(SM_NTH_RGB(sm,t),&SM_NTH_BRT(sm,t),SM_NTH_CHR(sm,t),
865 SM_NUM_SAMP(sm)-t);
866 SM_TONE_MAP(sm) = SM_NUM_SAMP(sm);
867 }
868
869 /*
870 * smRender_inc(sm,vp) : Incremental update of mesh
871 * SM * sm; : mesh
872 * FVECT vp; : current view point
873 *
874 * If a relatively small number of new triangles have been created,
875 * do an incremental update. Render new triangles with depth buffering
876 * turned off, if the current viewpoint is not the same as canonical view-
877 * point, must use painter's approach to resolve visibility:first depth sort
878 * triangles, then render back-to-front.
879 */
880 smRender_inc(sm,vp)
881 SM *sm;
882 FVECT vp;
883 {
884 int i,n,v0_id,v1_id,v2_id,b0,b1,b2;
885 TRI *tri;
886 SFLOAT (*wp)[3];
887 BYTE (*rgb)[3];
888 int4 *new_flag,*bg_flag,*active_flag;
889 T_DEPTH *td = NULL;
890
891
892 /* For all of the NEW triangles (since last update): assume
893 ACTIVE. Go through and sort on depth value (from vp). Turn
894 Depth Buffer test off and render back-front
895 */
896
897 /* Must depth sort if view points do not coincide */
898 if(!EQUAL_VEC3(SM_VIEW_CENTER(sm),vp))
899 td = smOrder_new_tris(sm,vp);
900 wp = SM_WP(sm);
901 rgb =SM_RGB(sm);
902 new_flag = SM_NTH_FLAGS(sm,T_NEW_FLAG);
903 active_flag = SM_NTH_FLAGS(sm,T_ACTIVE_FLAG);
904 bg_flag = SM_NTH_FLAGS(sm,T_BG_FLAG);
905 /* Turn Depth Test off -- using Painter's algorithm */
906 glPushAttrib(GL_DEPTH_BUFFER_BIT);
907 glDepthFunc(GL_ALWAYS);
908
909 smRender_new_bg_tris(sm,vp,new_flag,active_flag,bg_flag,wp,rgb);
910 if(!td)
911 smRender_new_fg_tris(sm,vp,new_flag,active_flag,bg_flag,wp,rgb);
912 else
913 {
914 glBegin(GL_TRIANGLES);
915 for(i=0; td[i].tri != -1;i++)
916 {
917 tri = SM_NTH_TRI(sm,td[i].tri);
918 /* Dont need to check for valid tri because flags are
919 cleared on delete
920 */
921 v0_id = T_NTH_V(tri,0);
922 v1_id = T_NTH_V(tri,1);
923 v2_id = T_NTH_V(tri,2);
924 b0 = SM_BASE_ID(sm,v0_id);
925 b1 = SM_BASE_ID(sm,v1_id);
926 b2 = SM_BASE_ID(sm,v2_id);
927 if(b0 || b1 || b2)
928 render_base_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],
929 rgb[v1_id],rgb[v2_id],SM_VIEW_CENTER(sm),b0,b1,b2);
930 else
931 render_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
932 rgb[v2_id])
933 }
934 glEnd();
935 freebuf(td);
936 }
937 /* Restore Depth Test */
938 glPopAttrib();
939 }
940
941 /*
942 * smRender_qtree_dl(sm,qt,vp,wp,rgb,i,level_i,max_level,leaf_cnt,which)
943 * SM *sm; : mesh
944 * QUADTREE qt; : quadtree base node
945 * FVECT vp; : current viewpoint
946 * SFLOAT (*wp)[3]; : array of sample points
947 * BYTE (*rgb)[3]; : array of RGB values for samples
948 * int i,level_i,level,max_level,leaf_cnt;
949 * : variables to keep track of where
950 * we are in the quadtree traversal in order to map nodes to
951 * corresponding array locations, where nodes are stored in breadth-
952 * first order. i is the index of the current node,level_i is the
953 * index of the first node on the current quadtree level, max_level is
954 * the maximum number of levels to traverse, and leaf_cnt is the number
955 * of leaves on the current level
956 * int which; flag indicates whether to render fg or bg tris
957 *
958 *
959 * Render the tris stored in qtree using display lists. For each node at
960 * the leaf or max_level, call the display_list if it exists, else traverse
961 * down the subtree and render the nodes into a new display list which is
962 * stored for future use.
963 */
964 smRender_qtree_dl(sm,qt,vp,wp,rgb,i,level_i,level,max_level,leaf_cnt,which)
965 SM *sm;
966 QUADTREE qt;
967 FVECT vp;
968 SFLOAT (*wp)[3];
969 BYTE (*rgb)[3];
970 int i,level_i,level,max_level,leaf_cnt;
971 int which;
972 {
973 int j;
974
975 if(QT_IS_EMPTY(qt))
976 return;
977
978 if(QT_IS_LEAF(qt) || level == max_level)
979 {
980 if(QT_IS_LEAF(qt))
981 {
982 if(!QT_LEAF_IS_FLAG(qt))
983 return;
984 }
985 else
986 if(!QT_IS_FLAG(qt))
987 return;
988
989 if(!Display_lists[i][which])
990 {
991 Display_lists[i][which] = i+1 + which*SM_DL_LISTS;
992 glNewList(Display_lists[i][which],GL_COMPILE_AND_EXECUTE);
993 smClear_flags(sm,T_NEW_FLAG);
994 glBegin(GL_TRIANGLES);
995 smRender_qtree(sm,qt,vp,wp,rgb,which,FALSE);
996 glEnd();
997 glEndList();
998 }
999 else
1000 {
1001 glCallList(Display_lists[i][which]);
1002 }
1003 }
1004 else
1005 if(QT_IS_FLAG(qt))
1006 {
1007 i = ((i - level_i)<< 2) + level_i + leaf_cnt;
1008 level_i += leaf_cnt;
1009 leaf_cnt <<= 2;
1010 for(j=0; j < 4; j++)
1011 smRender_qtree_dl(sm,QT_NTH_CHILD(qt,j),vp,wp,rgb,
1012 i+j,level_i,level+1,max_level,leaf_cnt,which);
1013 }
1014
1015 }
1016
1017 /*
1018 * smRender_qtree(sm,qt,vp,wp,rgb,which,cull) : Render the tris stored in qtree
1019 * SM *sm; : mesh
1020 * QUADTREE qt; : quadtree base node
1021 * FVECT vp; : current viewpoint
1022 * SFLOAT (*wp)[3] : array of sample points
1023 * BYTE (*rgb)[3] : array of RGB values for samples
1024 * int which; : flag indicates whether to render fg or bg tris
1025 * int cull; : if true, only traverse active (flagged) nodes
1026 *
1027 */
1028 smRender_qtree(sm,qt,vp,wp,rgb,which,cull)
1029 SM *sm;
1030 QUADTREE qt;
1031 FVECT vp;
1032 SFLOAT (*wp)[3];
1033 BYTE (*rgb)[3];
1034 int which,cull;
1035 {
1036 int i;
1037
1038 if(QT_IS_EMPTY(qt))
1039 return;
1040
1041 if(QT_IS_LEAF(qt))
1042 {
1043 TRI *t,*tri;
1044 OBJECT *optr;
1045 int v0_id,v1_id,v2_id,bg0,bg1,bg2;
1046 int t_id,s_id;
1047
1048 if(cull && !QT_LEAF_IS_FLAG(qt))
1049 return;
1050
1051 optr = qtqueryset(qt);
1052 for (i = QT_SET_CNT(optr);i > 0; i--)
1053 {
1054 s_id = QT_SET_NEXT_ELEM(optr);
1055 t_id = SM_NTH_VERT(smMesh,s_id);
1056 tri = t = SM_NTH_TRI(smMesh,t_id);
1057 do
1058 {
1059 if((!cull || SM_IS_NTH_T_ACTIVE(sm,t_id)) && !SM_IS_NTH_T_NEW(sm,t_id))
1060 {
1061 bg0 = SM_IS_NTH_T_BG(sm,t_id);
1062 if((which == SM_RENDER_FG && !bg0) || (which== SM_RENDER_BG && bg0))
1063 {
1064 v0_id = T_NTH_V(t,0);
1065 v1_id = T_NTH_V(t,1);
1066 v2_id = T_NTH_V(t,2);
1067 if(bg0)
1068 {
1069 bg0 = SM_DIR_ID(sm,v0_id)?DIR:SM_BASE_ID(sm,v0_id)?BASE:0;
1070 bg1 = SM_DIR_ID(sm,v1_id)?DIR:SM_BASE_ID(sm,v1_id)?BASE:0;
1071 bg2 = SM_DIR_ID(sm,v2_id)?DIR:SM_BASE_ID(sm,v2_id)?BASE:0;
1072 SM_SET_NTH_T_NEW(sm,t_id);
1073 if(bg0==DIR && bg1==DIR && bg2==DIR)
1074 render_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
1075 rgb[v2_id])
1076 else
1077 render_mixed_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],
1078 rgb[v1_id],rgb[v2_id],vp,SM_VIEW_CENTER(sm),bg0,bg1,bg2);
1079 }
1080 else
1081 {
1082 SM_SET_NTH_T_NEW(sm,t_id);
1083 bg0 = SM_BASE_ID(sm,v0_id);
1084 bg1 = SM_BASE_ID(sm,v1_id);
1085 bg2 = SM_BASE_ID(sm,v2_id);
1086 if(bg0 || bg1 || bg2)
1087 render_base_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],
1088 rgb[v1_id],rgb[v2_id],SM_VIEW_CENTER(sm),bg0,bg1,bg2);
1089 else
1090 render_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
1091 rgb[v2_id])
1092 }
1093 }
1094 }
1095 t_id = smTri_next_ccw_nbr(smMesh,t,s_id);
1096 t = SM_NTH_TRI(smMesh,t_id);
1097 }while(t!=tri);
1098 }
1099 }
1100 else
1101 if(!cull || QT_IS_FLAG(qt))
1102 for(i=0; i < 4; i++)
1103 smRender_qtree(sm,QT_NTH_CHILD(qt,i),vp,wp,rgb,which,cull);
1104 }
1105
1106
1107 /*
1108 * smRender_mesh(sm,view,cull) : Render mesh Triangles
1109 * SM *sm; : mesh
1110 * VIEW *view; : current view
1111 * int cull; : cull Flag
1112 *
1113 * If cull is TRUE, first mark tris in current
1114 * frustum and only render them. Normally, cull will be FALSE only if
1115 * it is known that all tris lie in frustum, e.g. after a rebuild
1116 *
1117 */
1118 smRender_mesh(sm,view,cull)
1119 SM *sm;
1120 VIEW *view;
1121 int cull;
1122 {
1123 SFLOAT (*wp)[3];
1124 BYTE (*rgb)[3];
1125 int i;
1126 STREE *st= SM_LOCATOR(sm);
1127
1128
1129 wp = SM_WP(sm);
1130 rgb =SM_RGB(sm);
1131
1132 smClear_flags(sm,T_NEW_FLAG);
1133
1134
1135 if(cull)
1136 smCull(sm,view,SM_ALL_LEVELS);
1137
1138
1139 glPushAttrib(GL_DEPTH_BUFFER_BIT);
1140 glDisable(GL_DEPTH_TEST);
1141
1142 glMatrixMode(GL_MODELVIEW);
1143 glPushMatrix();
1144 /* move relative to the new view */
1145 glTranslated(view->vp[0],view->vp[1],view->vp[2]);
1146
1147
1148 /* The points are a distance of 1 away from the origin: if necessary
1149 scale so that they fit in frustum and are therefore not clipped away
1150 */
1151 if(dev_zmin >= 0.99)
1152 {
1153 double d;
1154
1155 d = (dev_zmin+dev_zmax)/2.0;
1156 glScaled(d,d,d);
1157 }
1158 /* move points to unit sphere at origin */
1159 glTranslated(-SM_VIEW_CENTER(sm)[0],-SM_VIEW_CENTER(sm)[1],
1160 -SM_VIEW_CENTER(sm)[2]);
1161
1162 glBegin(GL_TRIANGLES);
1163 for(i=0; i < ST_NUM_ROOT_NODES; i++)
1164 smRender_qtree(sm,ST_ROOT_QT(st,i),view->vp,wp,rgb,SM_RENDER_BG,cull);
1165 glEnd();
1166
1167 glPopMatrix();
1168
1169 glEnable(GL_DEPTH_TEST);
1170
1171 glBegin(GL_TRIANGLES);
1172 for(i=0; i < ST_NUM_ROOT_NODES; i++)
1173 smRender_qtree(sm,ST_ROOT_QT(st,i),view->vp,wp,rgb,SM_RENDER_FG,cull);
1174 glEnd();
1175
1176 glPopAttrib();
1177 }
1178
1179 /*
1180 * smRender_mesh_dl(sm,view) : Render stree utilizing display lists
1181 * SM *sm; : mesh
1182 * VIEW *view; : current view
1183 */
1184 smRender_mesh_dl(sm,view)
1185 SM *sm;
1186 VIEW *view;
1187 {
1188 SFLOAT (*wp)[3];
1189 BYTE (*rgb)[3];
1190 STREE *st;
1191 int i;
1192
1193 if(SM_DL_LEVELS == 0)
1194 {
1195 if(!Display_lists[0][0])
1196 {
1197 Display_lists[0][0] = 1;
1198 glNewList(Display_lists[0][0],GL_COMPILE_AND_EXECUTE);
1199 smRender_mesh(sm,view,FALSE);
1200 glEndList();
1201 }
1202 else
1203 glCallList(Display_lists[0][0]);
1204
1205 return;
1206 }
1207 smClear_flags(sm,T_NEW_FLAG);
1208
1209 smCull(sm,view,SM_DL_LEVELS);
1210
1211 st = SM_LOCATOR(sm);
1212
1213 wp = SM_WP(sm);
1214 rgb =SM_RGB(sm);
1215
1216 /* For all active quadtree nodes- first render bg tris, then fg */
1217 /* If display list exists, use otherwise create/display list */
1218 glPushAttrib(GL_DEPTH_BUFFER_BIT);
1219 glDisable(GL_DEPTH_TEST);
1220
1221 glMatrixMode(GL_MODELVIEW);
1222 glPushMatrix();
1223
1224 /* move relative to the new view */
1225 glTranslated(view->vp[0],view->vp[1],view->vp[2]);
1226
1227 /* The points are a distance of 1 away from the origin: if necessary
1228 scale so that they fit in frustum and are therefore not clipped away
1229 */
1230 if(dev_zmin >= 0.99)
1231 {
1232 double d;
1233 d = (dev_zmin+dev_zmax)/2.0;
1234 glScaled(d,d,d);
1235 }
1236 /* move points to unit sphere at origin */
1237 glTranslated(-SM_VIEW_CENTER(sm)[0],-SM_VIEW_CENTER(sm)[1],
1238 -SM_VIEW_CENTER(sm)[2]);
1239 for(i=0; i < ST_NUM_ROOT_NODES; i++)
1240 smRender_qtree_dl(sm,ST_ROOT_QT(st,i),view->vp,wp,rgb,i,0,1,
1241 SM_DL_LEVELS,8,SM_RENDER_BG);
1242 glPopMatrix();
1243
1244 glEnable(GL_DEPTH_TEST);
1245 for(i=0; i < ST_NUM_ROOT_NODES; i++)
1246 smRender_qtree_dl(sm,ST_ROOT_QT(st,i),view->vp,wp,rgb,i,0,1,
1247 SM_DL_LEVELS,8,SM_RENDER_FG);
1248 glPopAttrib();
1249 }
1250
1251
1252
1253 /*
1254 * smRender_tris(sm,view,render_flag) : Render all of the mesh triangles
1255 * SM *sm : current geometry
1256 * VIEW *view : current view
1257 * int render_flag : if render_flag & SM_RENDER_CULL: do culling first
1258 *
1259 * Renders mesh by traversing triangle list and drawing all active tris-
1260 * background tris first, then foreground and mixed tris
1261 */
1262 smRender_tris(sm,view,render_flag)
1263 SM *sm;
1264 VIEW *view;
1265 int render_flag;
1266 {
1267 int4 *active_flag,*bg_flag;
1268 SFLOAT (*wp)[3];
1269 BYTE (*rgb)[3];
1270
1271 wp = SM_WP(sm);
1272 rgb = SM_RGB(sm);
1273 active_flag = SM_NTH_FLAGS(sm,T_ACTIVE_FLAG);
1274 bg_flag = SM_NTH_FLAGS(sm,T_BG_FLAG);
1275
1276 if(render_flag & SM_RENDER_CULL)
1277 smCull(sm,view,SM_ALL_LEVELS);
1278
1279 /* Render triangles made up of points at infinity by turning off
1280 depth-buffering and projecting the points onto a sphere around the view*/
1281 glPushAttrib(GL_DEPTH_BUFFER_BIT);
1282 glDisable(GL_DEPTH_TEST);
1283 smRender_bg_tris(sm,view->vp,active_flag,bg_flag,wp,rgb);
1284
1285 /* Render triangles containing world-space points */
1286 glEnable(GL_DEPTH_TEST);
1287 smRender_fg_tris(sm,view->vp,active_flag,bg_flag,wp,rgb);
1288
1289 glPopAttrib();
1290
1291 }
1292
1293 /* Clear all of the display lists */
1294 clear_display_lists()
1295 {
1296 int i;
1297 for(i=0; i< SM_DL_LISTS; i++)
1298 {
1299 if(Display_lists[i][0])
1300 { /* Clear the foreground display list */
1301 glDeleteLists(Display_lists[i][0],1);
1302 Display_lists[i][0] = 0;
1303 }
1304 if(Display_lists[i][1])
1305 { /* Clear the background display list */
1306 glDeleteLists(Display_lists[i][1],1);
1307 Display_lists[i][1] = 0;
1308 }
1309 }
1310 }
1311
1312 /*
1313 * qtClear_dl(qt,i,level_i,level,max_level,leaf_cnt) :clear display lists
1314 * QUADTREE *qt; : Quadtree node
1315 * int i; : index into list of display lists for this node
1316 * int level_i; : index for first node at this level
1317 * int level,max_level; : current level, maximum level to descend
1318 * int leaf_cnt; : number of leaves at this level
1319 *
1320 * For each node under this node that has its flag set: delete all
1321 * existing display lists. Display lists are stored in an array indexed as
1322 * if the quadtree was traversed in a breadth first order (indices 0-7 are
1323 * the 8 quadtree roots, indices 8-11 the first level children of root 0,
1324 * indices 12-15 the children of root 1, etc). It is assumes that the display
1325 * lists will only be stored for a small number of levels: if this is not
1326 * true, a hashing scheme would work better for storing/retrieving the
1327 * display lists
1328 */
1329 qtClear_dl(qt,i,level_i,level,max_level,leaf_cnt)
1330 QUADTREE qt;
1331 int i,level_i,level,max_level,leaf_cnt;
1332 {
1333 int j;
1334
1335 if(QT_IS_EMPTY(qt))
1336 return;
1337 if(QT_IS_LEAF(qt) || level== max_level)
1338 {
1339 if(QT_IS_LEAF(qt))
1340 {
1341 if(!QT_LEAF_IS_FLAG(qt))
1342 return;
1343 }
1344 else
1345 if(!QT_IS_FLAG(qt))
1346 return;
1347 if(Display_lists[i][0])
1348 {
1349 glDeleteLists(Display_lists[i][0],1);
1350 Display_lists[i][0] = 0;
1351 }
1352 if(Display_lists[i][1])
1353 {
1354 glDeleteLists(Display_lists[i][1],1);
1355 Display_lists[i][1] = 0;
1356 }
1357 }
1358 else
1359 if(QT_IS_FLAG(qt))
1360 {
1361 /* Calculate the index for the first child given the values
1362 of the parent at the current level
1363 */
1364 i = ((i - level_i)<< 2) + level_i + leaf_cnt;
1365 level_i += leaf_cnt;
1366 leaf_cnt <<= 2;
1367 for(j=0; j < 4; j++)
1368 qtClear_dl(QT_NTH_CHILD(qt,j),i+j,level_i,level+1,max_level,
1369 leaf_cnt);
1370 }
1371 }
1372
1373 /*
1374 * smInvalidate_view(sm,view) : Invalidate rendering representation for view
1375 * SM *sm; : mesh
1376 * VIEW *view; : current view
1377 *
1378 * Delete the existing display lists for geometry in the current
1379 * view frustum: Called when the geometry in the frustum has been changed
1380 */
1381 smInvalidate_view(sm,view)
1382 SM *sm;
1383 VIEW *view;
1384 {
1385 int i;
1386
1387 if(SM_DL_LEVELS == 0)
1388 {
1389 if(Display_lists[0][0])
1390 {
1391 glDeleteLists(Display_lists[0][0],1);
1392 Display_lists[0][0] = 0;
1393 }
1394 return;
1395 }
1396 /* Mark qtree nodes/tris in frustum */
1397 smCull(sm,view,SM_DL_LEVELS);
1398
1399 /* Invalidate display_lists in marked qtree nodes */
1400 for(i=0; i < ST_NUM_ROOT_NODES; i++)
1401 qtClear_dl(ST_ROOT_QT(SM_LOCATOR(sm),i),i,0,1,SM_DL_LEVELS,8);
1402
1403 }
1404
1405
1406 /*
1407 * smRender(sm,view, qual): render OpenGL output geometry
1408 * SM *sm; : current mesh representation
1409 * VIEW *view; : desired view
1410 * int qual; : quality level (percentage on linear time scale)
1411 *
1412 * Render the current mesh:
1413 * recompute tone mapping if full redraw and specified:
1414 * if moving (i.e. qual < MAXQUALITY)
1415 * render the cached display lists, if quality drops
1416 * below threshold, render approximation instead
1417 * if stationary
1418 * render mesh geometry without display lists, unless up-to-date
1419 * display lists already exist.
1420 */
1421 smRender(sm,view,qual)
1422 SM *sm;
1423 VIEW *view;
1424 int qual;
1425 {
1426 /* Unless quality > MAXQUALITY, render using display lists */
1427 if(qual <= MAXQUALITY)
1428 {
1429 /* If quality above threshold: render mesh*/
1430 if(qual > (MAXQUALITY*2/4) )
1431 /* render stree using display lists */
1432 smRender_mesh_dl(sm,view);
1433 else
1434 {
1435 /* If quality below threshold, use approximate rendering */
1436 smRender_approx(sm,qual,view);
1437 }
1438 }
1439 else
1440 {
1441 /* render stree without display lists */
1442 smRender_mesh(sm,view,TRUE);
1443 }
1444 }
1445
1446
1447 /*
1448 * smUpdate(view, qual) : update OpenGL output geometry
1449 * VIEW *view; : desired view
1450 * int qual; : quality level (percentage on linear time scale)
1451 *
1452 * Draw new geometric representation using OpenGL calls. Assume that the
1453 * view has already been set up and the correct frame buffer has been
1454 * selected for drawing. The quality level is on a linear scale, where 100%
1455 * is full (final) quality. It is not necessary to redraw geometry that has
1456 * been output since the last call to smClean().(The last view drawn will
1457 * be view==&odev.v each time.)
1458 */
1459 smUpdate(view,qual)
1460 VIEW *view;
1461 int qual;
1462 {
1463 /* Is there anything to render? */
1464 if(!smMesh || SM_NUM_TRI(smMesh)<=0)
1465 return;
1466
1467 /* Is viewer MOVING?*/
1468 if(qual < MAXQUALITY)
1469 {
1470 if(smIncremental)
1471 smUpdate_tm(smMesh);
1472 smIncremental = FALSE;
1473 /* Render mesh using display lists */
1474 smRender(smMesh,view,qual);
1475 return;
1476 }
1477 /* Viewer is STATIONARY */
1478 /* Has view moved epsilon from canonical view? (epsilon= percentage
1479 (SM_VIEW_FRAC) of running average of the distance of the sample points
1480 from the canonical view */
1481 if(DIST(view->vp,SM_VIEW_CENTER(smMesh)) > SM_ALLOWED_VIEW_CHANGE(smMesh))
1482 {
1483 /* Must rebuild mesh with current view as new canonical view */
1484 smRebuild(smMesh,view);
1485 /* Existing display lists and tonemapping are no longer valid */
1486 clear_display_lists();
1487 smCompute_mapping = FALSE;
1488 smUpdate_tm(smMesh);
1489 /* Render all the triangles in the new mesh */
1490 smRender(smMesh,view,qual+1);
1491 }
1492 else
1493 /* Has a complete redraw been requested ?*/
1494 if(smClean_notify)
1495 {
1496 if(smIncremental)
1497 smUpdate_tm(smMesh);
1498 smIncremental = FALSE;
1499 smRender(smMesh,view,qual);
1500 }
1501 else
1502 {
1503 smUpdate_tm(smMesh);
1504 /* If number of new triangles relatively small: do incremental update */
1505 /* Mark Existing display lists in frustum invalid */
1506 if(!smIncremental)
1507 {
1508 smInvalidate_view(smMesh,view);
1509 smIncremental = TRUE;
1510 }
1511 smRender_inc(smMesh,view->vp);
1512 }
1513 /* This is our final update iff qual==MAXQUALITY and view==&odev.v */
1514 if( (qual >= MAXQUALITY) && (view == &(odev.v)))
1515 {
1516 /* reset rendering flags */
1517 smClean_notify = FALSE;
1518 if(smIncremental)
1519 smClear_flags(smMesh,T_NEW_FLAG);
1520 qtCache_init(0);
1521 }
1522
1523 }
1524
1525
1526
1527
1528
1529