ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/sm_ogl.c
Revision: 3.14
Committed: Fri Mar 5 16:33:32 1999 UTC (25 years, 2 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.13: +937 -322 lines
Log Message:
Added display list rendering

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