ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/sm_ogl.c
Revision: 3.8
Committed: Tue Oct 6 18:16:54 1998 UTC (25 years, 6 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.7: +162 -93 lines
Log Message:
new triangulate routine
added smTestSample to check for occlusion
added frustum culling before rebuild
changed base quadtree to use octahedron and created new point locate
added "sample active" flags and implemented LRU replacement
started handling case of too many triangles
set sizes are now unbounded
changed all quadtree pointers to quadtrees

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 #include "standard.h"
11
12 #include <GL/gl.h>
13
14 #ifdef TEST_DRIVER
15 #include <gl/device.h>
16 #include <GL/glu.h>
17 #include <glut.h>
18 #endif
19 #include "sm_flag.h"
20 #include "sm_list.h"
21 #include "sm_geom.h"
22 #include "sm_qtree.h"
23 #include "sm_stree.h"
24 #include "sm.h"
25
26 #ifdef TEST_DRIVER
27 #include "sm_draw.h"
28 /*static char smClean_notify = TRUE;
29 MAKE STATIC LATER: ui.c using for now;
30 */
31 char smClean_notify = TRUE;
32 #else
33 static int smClean_notify = TRUE;
34 #endif
35
36 typedef struct {
37 float dist; /* average distance */
38 BYTE rgb[3]; /* average color */
39 } QTRAVG; /* average quadtree value */
40
41 typedef struct {
42 QUADTREE qt; /* quadtree node (key & hash value) */
43 QTRAVG av; /* node average */
44 } QT_LUENT; /* lookup table entry */
45
46 static QT_LUENT *qt_htbl = NULL; /* quadtree cache */
47 static int qt_hsiz = 0; /* quadtree cache size */
48
49
50
51 mark_active_tris(qtptr,fptr)
52 QUADTREE *qtptr;
53 int *fptr;
54 {
55 QUADTREE qt = *qtptr;
56 OBJECT *os,*optr;
57 register int i,t_id;
58 TRI *tri;
59
60
61 if(!QT_FLAG_FILL_TRI(*fptr))
62 (*fptr)++;
63
64 if(QT_IS_EMPTY(qt) || QT_LEAF_IS_FLAG(qt))
65 return;
66 /* For each triangle in the set, set the which flag*/
67 os = qtqueryset(qt);
68
69 for (i = QT_SET_CNT(os), optr = QT_SET_PTR(os); i > 0; i--)
70 {
71 t_id = QT_SET_NEXT_ELEM(optr);
72 /* Set the render flag */
73 tri = SM_NTH_TRI(smMesh,t_id);
74 if(!T_IS_VALID(tri) || SM_IS_NTH_T_BASE(smMesh,t_id))
75 continue;
76 SM_SET_NTH_T_ACTIVE(smMesh,t_id);
77 /* Set the Active bits of the Vertices */
78 S_SET_FLAG(T_NTH_V(tri,0));
79 S_SET_FLAG(T_NTH_V(tri,1));
80 S_SET_FLAG(T_NTH_V(tri,2));
81
82 }
83 }
84
85 #define mark_active_interior mark_active_tris
86
87 mark_tris_in_frustum(view)
88 VIEW *view;
89 {
90 FVECT nr[4],far[4];
91 FPEQ peq;
92 int debug=0;
93 /* Mark triangles in approx. view frustum as being active:set
94 LRU counter: for use in discarding samples when out
95 of space
96 Radiance often has no far clipping plane: but driver will set
97 dev_zmin,dev_zmax to satisfy OGL
98 */
99
100 /* First clear all the quadtree node and triangle active flags */
101 qtClearAllFlags();
102 smClear_flags(smMesh,T_ACTIVE_FLAG);
103 /* Clear all of the active sample flags*/
104 sClear_all_flags(smMesh->samples);
105
106
107 /* calculate the world space coordinates of the view frustum */
108 calculate_view_frustum(view->vp,view->hvec,view->vvec,view->horiz,
109 view->vert, dev_zmin,dev_zmax,nr,far);
110
111 #ifdef TEST_DRIVER
112 VCOPY(FrustumFar[0],far[0]);
113 VCOPY(FrustumFar[1],far[1]);
114 VCOPY(FrustumFar[2],far[2]);
115 VCOPY(FrustumFar[3],far[3]);
116 VCOPY(FrustumNear[0],nr[0]);
117 VCOPY(FrustumNear[1],nr[1]);
118 VCOPY(FrustumNear[2],nr[2]);
119 VCOPY(FrustumNear[3],nr[3]);
120 #endif
121 /* Project the view frustum onto the spherical quadtree */
122 /* For every cell intersected by the projection of the faces
123
124 of the frustum: mark all triangles in the cell as ACTIVE-
125 Also set the triangles LRU clock counter
126 */
127
128 if(EQUAL_VEC3(view->vp,SM_VIEW_CENTER(smMesh)))
129 {/* Near face triangles */
130 smLocator_apply_func(smMesh,nr[3],nr[2],nr[0],mark_active_tris,
131 mark_active_interior,NULL);
132 smLocator_apply_func(smMesh,nr[1],nr[0],nr[2],mark_active_tris,
133 mark_active_interior,NULL);
134 return;
135 }
136
137 /* Test the view against the planes: and swap orientation if inside:*/
138 tri_plane_equation(nr[0],nr[2],nr[3], &peq,FALSE);
139 if(PT_ON_PLANE(SM_VIEW_CENTER(smMesh),peq) > 0.0)
140 {/* Near face triangles */
141 smLocator_apply_func(smMesh,nr[3],nr[2],nr[0],mark_active_tris,
142 mark_active_interior,NULL);
143 smLocator_apply_func(smMesh,nr[1],nr[0],nr[2],mark_active_tris,
144 mark_active_interior,NULL);
145 }
146 else
147 {/* Near face triangles */
148 smLocator_apply_func(smMesh,nr[0],nr[2],nr[3],mark_active_tris,
149 mark_active_interior,NULL);
150 smLocator_apply_func(smMesh,nr[2],nr[0],nr[1],mark_active_tris,
151 mark_active_interior,NULL);
152 }
153 tri_plane_equation(nr[0],far[3],far[0], &peq,FALSE);
154 if(PT_ON_PLANE(SM_VIEW_CENTER(smMesh),peq) > 0.0)
155 { /* Right face triangles */
156 smLocator_apply_func(smMesh,far[0],far[3],nr[0],mark_active_tris,
157 mark_active_interior,NULL);
158 smLocator_apply_func(smMesh,nr[3],nr[0],far[3],mark_active_tris,
159 mark_active_interior,NULL);
160 }
161 else
162 {/* Right face triangles */
163 smLocator_apply_func(smMesh,nr[0],far[3],far[0],mark_active_tris,
164 mark_active_interior,NULL);
165 smLocator_apply_func(smMesh,far[3],nr[0],nr[3],mark_active_tris,
166 mark_active_interior,NULL);
167 }
168
169 tri_plane_equation(nr[1],far[2],nr[2], &peq,FALSE);
170 if(PT_ON_PLANE(SM_VIEW_CENTER(smMesh),peq) > 0.0)
171 { /* Left face triangles */
172 smLocator_apply_func(smMesh,nr[2],far[2],nr[1],mark_active_tris,
173 mark_active_interior,NULL);
174 smLocator_apply_func(smMesh,far[1],nr[1],far[2],mark_active_tris,
175 mark_active_interior,NULL);
176 }
177 else
178 { /* Left face triangles */
179 smLocator_apply_func(smMesh,nr[1],far[2],nr[2],mark_active_tris,
180 mark_active_interior,NULL);
181 smLocator_apply_func(smMesh,far[2],nr[1],far[1],mark_active_tris,
182 mark_active_interior,NULL);
183
184 }
185 tri_plane_equation(nr[0],far[0],nr[1], &peq,FALSE);
186 if(PT_ON_PLANE(SM_VIEW_CENTER(smMesh),peq) > 0.0)
187 {/* Top face triangles */
188 smLocator_apply_func(smMesh,nr[1],far[0],nr[0],mark_active_tris,
189 mark_active_interior,NULL);
190 smLocator_apply_func(smMesh,far[1],far[0],nr[1],mark_active_tris,
191 mark_active_interior,NULL);
192 }
193 else
194 {/* Top face triangles */
195 smLocator_apply_func(smMesh,nr[0],far[0],nr[1],mark_active_tris,
196 mark_active_interior,NULL);
197 smLocator_apply_func(smMesh,nr[1],far[0],far[1],mark_active_tris,
198 mark_active_interior,NULL);
199 }
200 tri_plane_equation(nr[3],nr[2],far[3], &peq,FALSE);
201 if(PT_ON_PLANE(SM_VIEW_CENTER(smMesh),peq) > 0.0)
202 {/* Bottom face triangles */
203 smLocator_apply_func(smMesh,far[3],nr[2],nr[3],mark_active_tris,
204 mark_active_interior,NULL);
205 smLocator_apply_func(smMesh,far[3],far[2],nr[2],mark_active_tris,
206 mark_active_interior,NULL);
207 }
208 else
209 { /* Bottom face triangles */
210 smLocator_apply_func(smMesh,nr[3],nr[2],far[3],mark_active_tris,
211 mark_active_interior,NULL);
212 smLocator_apply_func(smMesh,nr[2],far[2],far[3],mark_active_tris,
213 mark_active_interior,NULL);
214 }
215 tri_plane_equation(far[2],far[0],far[1], &peq,FALSE);
216 if(PT_ON_PLANE(SM_VIEW_CENTER(smMesh),peq) > 0.0)
217 {/* Far face triangles */
218 smLocator_apply_func(smMesh,far[0],far[2],far[1],mark_active_tris,
219 mark_active_interior,NULL);
220 smLocator_apply_func(smMesh,far[2],far[0],far[3],mark_active_tris,
221 mark_active_interior,NULL);
222 }
223 else
224 {/* Far face triangles */
225 smLocator_apply_func(smMesh,far[1],far[2],far[0],mark_active_tris,
226 mark_active_interior,NULL);
227 smLocator_apply_func(smMesh,far[3],far[0],far[2],mark_active_tris,
228 mark_active_interior,NULL);
229 }
230
231 }
232
233 /*
234 * smClean() : display has been wiped clean
235 *
236 * Called after display has been effectively cleared, meaning that all
237 * geometry must be resent down the pipeline in the next call to smUpdate().
238 */
239 smClean()
240 {
241 smClean_notify = TRUE;
242 }
243
244 int
245 qtCache_init(nel) /* initialize for at least nel elements */
246 int nel;
247 {
248 static int hsiztab[] = {
249 8191, 16381, 32749, 65521, 131071, 262139, 524287, 1048573, 0
250 };
251 register int i;
252
253 if (nel <= 0) { /* call to free table */
254 if (qt_hsiz) {
255 free((char *)qt_htbl);
256 qt_htbl = NULL;
257 qt_hsiz = 0;
258 }
259 return(0);
260 }
261 nel += nel>>1; /* 66% occupancy */
262 for (i = 0; hsiztab[i]; i++)
263 if (hsiztab[i] > nel)
264 break;
265 if (!(qt_hsiz = hsiztab[i]))
266 qt_hsiz = nel*2 + 1; /* not always prime */
267 qt_htbl = (QT_LUENT *)calloc(qt_hsiz, sizeof(QT_LUENT));
268 if (qt_htbl == NULL)
269 qt_hsiz = 0;
270 for (i = qt_hsiz; i--; )
271 qt_htbl[i].qt = EMPTY;
272 return(qt_hsiz);
273 }
274
275 QT_LUENT *
276 qtCache_find(qt) /* find a quadtree table entry */
277 QUADTREE qt;
278 {
279 int i, n;
280 register int ndx;
281 register QT_LUENT *le;
282
283 if (qt_hsiz == 0 && !qtCache_init(1))
284 return(NULL);
285 tryagain: /* hash table lookup */
286 ndx = (unsigned long)qt % qt_hsiz;
287 for (i = 0, n = 1; i < qt_hsiz; i++, n += 2) {
288 le = &qt_htbl[ndx];
289 if (QT_IS_EMPTY(le->qt) || le->qt == qt)
290 return(le);
291 if ((ndx += n) >= qt_hsiz) /* this happens rarely */
292 ndx = ndx % qt_hsiz;
293 }
294 /* table is full, reallocate */
295 le = qt_htbl;
296 ndx = qt_hsiz;
297 if (!qtCache_init(ndx+1)) { /* no more memory! */
298 qt_htbl = le;
299 qt_hsiz = ndx;
300 return(NULL);
301 }
302 /* copy old table to new and free */
303 while (ndx--)
304 if (!QT_IS_EMPTY(le[ndx].qt))
305 copystruct(qtCache_find(le[ndx].qt), &le[ndx]);
306 free((char *)le);
307 goto tryagain; /* should happen only once! */
308 }
309
310 stCount_level_leaves(lcnt, qt) /* count quadtree leaf nodes at each level */
311 int lcnt[];
312 register QUADTREE qt;
313 {
314 if (QT_IS_EMPTY(qt))
315 return;
316 if (QT_IS_TREE(qt)) {
317 if (!QT_IS_FLAG(qt)) /* not in our frustum */
318 return;
319 stCount_level_leaves(lcnt+1, QT_NTH_CHILD(qt,0));
320 stCount_level_leaves(lcnt+1, QT_NTH_CHILD(qt,1));
321 stCount_level_leaves(lcnt+1, QT_NTH_CHILD(qt,2));
322 stCount_level_leaves(lcnt+1, QT_NTH_CHILD(qt,3));
323 }
324 else
325 lcnt[0]++;
326 }
327
328
329 QTRAVG *
330 qtRender_level(qt,v0,v1,v2,sm,lvl)
331 QUADTREE qt;
332 FVECT v0,v1,v2;
333 SM *sm;
334 int lvl;
335 {
336 FVECT a,b,c;
337 register QT_LUENT *le;
338 QTRAVG *rc[4];
339 TRI *tri;
340
341 if (QT_IS_EMPTY(qt)) /* empty leaf node */
342 return(NULL);
343 if (QT_IS_TREE(qt) && !QT_IS_FLAG(qt)) /* not in our frustum */
344 return(NULL);
345 /* else look up node */
346 if ((le = qtCache_find(qt)) == NULL)
347 error(SYSTEM, "out of memory in qtRender_level");
348 if (QT_IS_TREE(qt) && (QT_IS_EMPTY(le->qt) || lvl > 0))
349 { /* compute children */
350 qtSubdivide_tri(v0,v1,v2,a,b,c);
351 rc[0] = qtRender_level(QT_NTH_CHILD(qt,0),v0,a,c,sm,lvl-1);
352 rc[1] = qtRender_level(QT_NTH_CHILD(qt,1),a,v1,b,sm,lvl-1);
353 rc[2] = qtRender_level(QT_NTH_CHILD(qt,2),c,b,v2,sm,lvl-1);
354 rc[3] = qtRender_level(QT_NTH_CHILD(qt,3),b,c,a,sm,lvl-1);
355 }
356 if (QT_IS_EMPTY(le->qt))
357 { /* let's make some data! */
358 int rgbs[3];
359 double distsum;
360 register int i, n;
361 /* average our triangle vertices */
362 rgbs[0] = rgbs[1] = rgbs[2] = 0;
363 distsum = 0.; n = 0;
364 if(QT_IS_TREE(qt))
365 { /* from subtree */
366 for (i = 4; i--; )
367 if (rc[i] != NULL)
368 {
369 rgbs[0] += rc[i]->rgb[0]; rgbs[1] += rc[i]->rgb[1];
370 rgbs[2] += rc[i]->rgb[2]; distsum += rc[i]->dist; n++;
371 }
372 }
373 else
374 { /* from triangle set */
375 OBJECT *os;
376 int s0, s1, s2;
377
378 os = qtqueryset(qt);
379 for (n = os[0]; n; n--)
380 {
381 tri = SM_NTH_TRI(sm,os[n]);
382 if(!T_IS_VALID(tri))
383 continue;
384
385 s0 = T_NTH_V(tri,0);
386 s1 = T_NTH_V(tri,1);
387 s2 = T_NTH_V(tri,2);
388 VCOPY(a,SM_NTH_WV(sm,s0));
389 VCOPY(b,SM_NTH_WV(sm,s1));
390 VCOPY(c,SM_NTH_WV(sm,s2));
391 distsum += SM_BG_SAMPLE(sm,s0) ? dev_zmax
392 : sqrt(dist2(a,SM_VIEW_CENTER(sm)));
393 distsum += SM_BG_SAMPLE(sm,s1) ? dev_zmax
394 : sqrt(dist2(b,SM_VIEW_CENTER(sm)));
395 distsum += SM_BG_SAMPLE(sm,s2) ? dev_zmax
396 : sqrt(dist2(c,SM_VIEW_CENTER(sm)));
397 rgbs[0] += SM_NTH_RGB(sm,s0)[0] + SM_NTH_RGB(sm,s1)[0]
398 + SM_NTH_RGB(sm,s2)[0];
399 rgbs[1] += SM_NTH_RGB(sm,s0)[1] + SM_NTH_RGB(sm,s1)[1]
400 + SM_NTH_RGB(sm,s2)[1];
401 rgbs[2] += SM_NTH_RGB(sm,s0)[2] + SM_NTH_RGB(sm,s1)[2]
402 + SM_NTH_RGB(sm,s2)[2];
403 }
404 n = 3*os[0];
405 }
406 if (!n)
407 return(NULL);
408 le->qt = qt;
409 le->av.rgb[0] = rgbs[0]/n; le->av.rgb[1] = rgbs[1]/n;
410 le->av.rgb[2] = rgbs[2]/n; le->av.dist = distsum/(double)n;
411 }
412 if (lvl == 0 || (lvl > 0 && QT_IS_LEAF(qt)))
413 { /* render this node */
414 /* compute pseudo vertices */
415 VCOPY(a,v0); VCOPY(b,v1); VCOPY(c,v2);
416 normalize(a); normalize(b); normalize(c);
417 VSUM(a,SM_VIEW_CENTER(sm),a,le->av.dist);
418 VSUM(b,SM_VIEW_CENTER(sm),b,le->av.dist);
419 VSUM(c,SM_VIEW_CENTER(sm),c,le->av.dist);
420 /* draw triangle */
421 glColor3ub(le->av.rgb[0],le->av.rgb[1],le->av.rgb[2]);
422 /* NOTE: Triangle vertex order may change */
423 glVertex3d(c[0],c[1],c[2]);
424 glVertex3d(b[0],b[1],b[2]);
425 glVertex3d(a[0],a[1],a[2]);
426 }
427 return(&le->av);
428 }
429
430
431 smRender_stree_level(sm,lvl)
432 SM *sm;
433 int lvl;
434 {
435 QUADTREE root;
436 int i;
437 FVECT t0,t1,t2;
438 STREE *st;
439
440
441 if (lvl < 1)
442 return;
443 st = SM_LOCATOR(sm);
444 glPushAttrib(GL_LIGHTING_BIT);
445 glShadeModel(GL_FLAT);
446 glBegin(GL_TRIANGLES);
447 for(i=0; i < ST_NUM_ROOT_NODES; i++)
448 {
449 root = ST_NTH_ROOT(st,i);
450 qtRender_level(root,ST_NTH_V(st,i,0),ST_NTH_V(st,i,1),ST_NTH_V(st,i,2),
451 sm,lvl-1);
452 }
453 glEnd();
454 glPopAttrib();
455 }
456
457
458 smRender_stree(sm, qual) /* render some quadtree triangles */
459 SM *sm;
460 int qual;
461 {
462 int i, ntarget;
463 int lvlcnt[QT_MAX_LEVELS];
464
465 if (qual <= 0)
466 return;
467 /* compute rendering target */
468 ntarget = 0;
469 SM_FOR_ALL_ACTIVE_TRIS(sm,i)
470 ntarget++;
471 ntarget = ntarget*qual/100;
472 if (!ntarget)
473 return;
474 for (i = QT_MAX_LEVELS; i--; )
475 lvlcnt[i] = 0;
476 stCount_level_leaves(lvlcnt, ST_TOP_ROOT(SM_LOCATOR(sm)));
477 stCount_level_leaves(lvlcnt, ST_BOTTOM_ROOT(SM_LOCATOR(sm)));
478 for (ntarget -= lvlcnt[i=0]; i < QT_MAX_LEVELS-1; ntarget -= lvlcnt[++i])
479 if (ntarget < lvlcnt[i+1])
480 break;
481 /* compute and render target level */
482 smRender_stree_level(sm,i);
483 }
484
485
486 smRender_tri(sm,i,vp,clr)
487 SM *sm;
488 int i;
489 FVECT vp;
490 int clr;
491 {
492 TRI *tri;
493 double ptr[3];
494 int j;
495
496 tri = SM_NTH_TRI(sm,i);
497 if (clr) SM_CLR_NTH_T_NEW(sm,i);
498
499 /* NOTE:Triangles are defined clockwise:historical relative to spherical
500 tris: could change
501 */
502 for(j=2; j>= 0; j--)
503 {
504 #ifdef DEBUG
505 if(SM_BG_SAMPLE(sm,T_NTH_V(tri,j)))
506 eputs("SmRenderTri(): shouldnt have bg samples\n");
507 #endif
508 glColor3ub(SM_NTH_RGB(sm,T_NTH_V(tri,j))[0],
509 SM_NTH_RGB(sm,T_NTH_V(tri,j))[1],
510 SM_NTH_RGB(sm,T_NTH_V(tri,j))[2]);
511 VCOPY(ptr,SM_T_NTH_WV(sm,tri,j));
512 glVertex3d(ptr[0],ptr[1],ptr[2]);
513 }
514 }
515
516 smRender_mixed_tri(sm,i,vp,clr)
517 SM *sm;
518 int i;
519 FVECT vp;
520 int clr;
521 {
522 TRI *tri;
523 double p[3],d;
524 int j,ids[3],cnt;
525 int rgb[3];
526
527 tri = SM_NTH_TRI(sm,i);
528 if (clr) SM_CLR_NTH_T_NEW(sm,i);
529
530 /* NOTE:Triangles are defined clockwise:historical relative to spherical
531 tris: could change
532 */
533 cnt = 0;
534 d = 0.0;
535 rgb[0] = rgb[1] = rgb[2] = 0;
536 for(j=0;j < 3;j++)
537 {
538 ids[j] = T_NTH_V(tri,j);
539 if(!SM_BG_SAMPLE(sm,ids[j]))
540 {
541 rgb[0] += SM_NTH_RGB(sm,ids[j])[0];
542 rgb[1] += SM_NTH_RGB(sm,ids[j])[1];
543 rgb[2] += SM_NTH_RGB(sm,ids[j])[2];
544 cnt++;
545 d += DIST(vp,SM_NTH_WV(sm,ids[j]));
546 }
547 }
548 if(cnt > 1)
549 {
550 rgb[0]/=cnt; rgb[1]/=cnt; rgb[2]/=cnt;
551 d /= (double)cnt;
552 }
553 for(j=2; j>= 0; j--)
554 {
555 if(SM_BG_SAMPLE(sm,ids[j]))
556 {
557 glColor3ub(rgb[0],rgb[1],rgb[2]);
558 VSUB(p,SM_NTH_WV(sm,ids[j]),SM_VIEW_CENTER(sm));
559 p[0] *= d;
560 p[1] *= d;
561 p[2] *= d;
562 VADD(p,p,SM_VIEW_CENTER(sm));
563 }
564 else
565 {
566 glColor3ub(SM_NTH_RGB(sm,ids[j])[0],SM_NTH_RGB(sm,ids[j])[1],
567 SM_NTH_RGB(sm,ids[j])[2]);
568 VCOPY(p,SM_NTH_WV(sm,ids[j]));
569 }
570 glVertex3d(p[0],p[1],p[2]);
571 }
572 }
573
574 smRender_bg_tri(sm,i,vp,d,clr)
575 SM *sm;
576 int i;
577 FVECT vp;
578 double d;
579 int clr;
580 {
581 double p[3];
582 int j,id;
583 TRI *tri;
584
585 tri = SM_NTH_TRI(sm,i);
586 if (clr) SM_CLR_NTH_T_NEW(sm,i);
587
588 /* NOTE:Triangles are defined clockwise:historical relative to spherical
589 tris: could change
590 */
591 for(j=2; j>= 0; j--)
592 {
593 id = T_NTH_V(tri,j);
594 glColor3ub(SM_NTH_RGB(sm,id)[0],SM_NTH_RGB(sm,id)[1],
595 SM_NTH_RGB(sm,id)[2]);
596 VSUB(p,SM_NTH_WV(sm,id),SM_VIEW_CENTER(sm));
597 if(dev_zmin >= 0.99)
598 {
599 p[0] *= d;
600 p[1] *= d;
601 p[2] *= d;
602 }
603 VADD(p,p,vp);
604 glVertex3d(p[0],p[1],p[2]);
605 }
606 }
607
608 smRender_mesh(sm,vp,clr)
609 SM *sm;
610 FVECT vp;
611 int clr;
612 {
613 int i;
614 TRI *tri;
615 double ptr[3],d;
616 int j;
617
618 d = (dev_zmin+dev_zmax)/2.0;
619 glPushAttrib(GL_DEPTH_BUFFER_BIT);
620
621 /* First draw background polygons */
622 glDisable(GL_DEPTH_TEST);
623 glBegin(GL_TRIANGLES);
624 SM_FOR_ALL_ACTIVE_BG_TRIS(sm,i)
625 smRender_bg_tri(sm,i,vp,d,clr);
626 glEnd();
627 glEnable(GL_DEPTH_TEST);
628 glBegin(GL_TRIANGLES);
629 SM_FOR_ALL_ACTIVE_FG_TRIS(sm,i)
630 {
631 if(SM_BG_TRI(sm,i))
632 continue;
633 if(!SM_MIXED_TRI(sm,i))
634 smRender_tri(sm,i,vp,clr);
635 else
636 smRender_mixed_tri(sm,i,vp,clr);
637 }
638 glEnd();
639
640 glPopAttrib();
641 }
642
643 smRender_tri_edges(sm,i)
644 SM *sm;
645 int i;
646 {
647 TRI *tri;
648 int j;
649 double ptr[3];
650
651
652 tri = SM_NTH_TRI(sm,i);
653
654 /* Triangles are defined clockwise:historical relative to spherical
655 tris: could change
656 */
657 for(j=2; j >=0; j--)
658 {
659 VCOPY(ptr,SM_NTH_WV(sm,T_NTH_V(tri,j)));
660 glVertex3d(ptr[0],ptr[1],ptr[2]);
661 VCOPY(ptr,SM_NTH_WV(sm,T_NTH_V(tri,(j+1)%3)));
662 glVertex3d(ptr[0],ptr[1],ptr[2]);
663 }
664 }
665
666 int
667 compare_tri_depths(T_DEPTH *td1,T_DEPTH *td2)
668 {
669 double d;
670
671 d = td2->depth-td1->depth;
672
673 if(d > 0.0)
674 return(1);
675 if(d < 0.0)
676 return(-1);
677
678 return(0);
679 }
680
681 LIST
682 *smDepth_sort_tris(sm,vp,td)
683 SM *sm;
684 FVECT vp;
685 T_DEPTH *td;
686 {
687 int i,j,t_id,v;
688 TRI *tri;
689 double d,min_d;
690 LIST *tlist=NULL;
691
692 i = 0;
693 SM_FOR_ALL_NEW_TRIS(sm,t_id)
694 {
695 if(SM_BG_TRI(sm,t_id))
696 {
697 tlist = push_data(tlist,t_id);
698 continue;
699 }
700 tri = SM_NTH_TRI(sm,t_id);
701 #ifdef DEBUG
702 if(i >= smNew_tri_cnt)
703 {
704 eputs("smDepth_sort_tris():More tris than reported by smNew_tri_cnt\n");
705 break;
706 }
707 #endif
708 td[i].tri = t_id;
709 min_d = -1;
710 for(j=0;j < 3;j++)
711 {
712 v = T_NTH_V(tri,j);
713 if(!SM_BG_SAMPLE(sm,v))
714 {
715 d = DIST(vp,SM_NTH_WV(sm,v));
716 if(min_d == -1 || d < min_d)
717 min_d = d;
718 }
719 }
720 td[i].depth = min_d;
721 i++;
722 }
723 td[i].tri = -1;
724 if(i)
725 qsort((void *)td,i,sizeof(T_DEPTH),compare_tri_depths);
726 return(tlist);
727 }
728
729
730 smUpdate_Rendered_mesh(sm,vp,clr)
731 SM *sm;
732 FVECT vp;
733 int clr;
734 {
735 static T_DEPTH *td= NULL;
736 static int tsize = 0;
737 int i;
738 GLint depth_test;
739 double d;
740 LIST *bglist;
741 /* For all of the NEW triangles (since last update): assume
742 ACTIVE. Go through and sort on depth value (from vp). Turn
743 Depth Buffer test off and render back-front
744 */
745 /* NOTE: could malloc each time or hard code */
746 if(smNew_tri_cnt > tsize)
747 {
748 if(td)
749 free((char *)td);
750 td = (T_DEPTH *)malloc(smNew_tri_cnt*sizeof(T_DEPTH));
751 tsize = smNew_tri_cnt;
752 }
753 if(!td)
754 {
755 error(SYSTEM,"smUpdate_Rendered_mesh:Cannot allocate memory\n");
756 }
757 bglist = smDepth_sort_tris(sm,vp,td);
758
759 /* Turn Depth Test off -- using Painter's algorithm */
760 glPushAttrib(GL_DEPTH_BUFFER_BIT);
761 glDisable(GL_DEPTH_TEST);
762 d = (dev_zmin+dev_zmax)/2.0;
763 /* Now render back-to front */
764 /* First render bg triangles */
765 glBegin(GL_TRIANGLES);
766 while(bglist)
767 smRender_bg_tri(sm,pop_list(&bglist),vp,d,clr);
768 glEnd();
769
770
771 glBegin(GL_TRIANGLES);
772 i=0;
773 while(td[i].tri != -1)
774 if(!SM_MIXED_TRI(sm,td[i].tri))
775 smRender_tri(sm,td[i++].tri,vp,clr);
776 else
777 smRender_mixed_tri(sm,td[i++].tri,vp,clr);
778 glEnd();
779
780 /* Restore Depth Test */
781 glPopAttrib();
782 }
783
784 /*
785 * smUpdate(view, qua) : update OpenGL output geometry for view vp
786 * VIEW *view; : desired view
787 * int qual; : quality level (percentage on linear time scale)
788 *
789 * Draw new geometric representation using OpenGL calls. Assume that the
790 * view has already been set up and the correct frame buffer has been
791 * selected for drawing. The quality level is on a linear scale, where 100%
792 * is full (final) quality. It is not necessary to redraw geometry that has
793 * been output since the last call to smClean(). (The last view drawn will
794 * be view==&odev.v each time.)
795 */
796 smUpdate(view,qual)
797 VIEW *view;
798 int qual;
799 {
800 double d;
801 int last_update;
802 int t;
803
804 /* If view has moved beyond epsilon from canonical: must rebuild -
805 epsilon is calculated as running avg of distance of sample points
806 from canonical view: m = 1/(AVG(1/r)): some fraction of this
807 */
808
809 if(!smMesh)
810 return;
811 d = DIST(view->vp,SM_VIEW_CENTER(smMesh));
812 if(qual >= 100 && d > SM_ALLOWED_VIEW_CHANGE(smMesh))
813 {
814 /* Re-build the mesh */
815 #ifdef TEST_DRIVER
816 odev.v = *view;
817 #endif
818 mark_tris_in_frustum(view);
819 smRebuild_mesh(smMesh,view);
820 }
821 /* This is our final update iff qual==100 and view==&odev.v */
822 last_update = qual>=100 && view==&(odev.v);
823 /* Check if we should draw ALL triangles in current frustum */
824 if(smClean_notify || smNew_tri_cnt > SM_SAMPLE_TRIS(smMesh)*SM_INC_PERCENT)
825 {
826 #ifdef TEST_DRIVER
827 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
828 #else
829 if ( SM_TONE_MAP(smMesh) < SM_NUM_SAMP(smMesh))
830 {
831 tmClearHisto();
832 tmAddHisto(SM_BRT(smMesh),SM_NUM_SAMP(smMesh),1);
833 if(tmComputeMapping(0.,0.,0.) != TM_E_OK ||
834 tmMapPixels(SM_RGB(smMesh),SM_BRT(smMesh),SM_CHR(smMesh),
835 SM_NUM_SAMP(smMesh)) != TM_E_OK)
836 return;
837 }
838 #endif
839 mark_tris_in_frustum(view);
840 if (qual <= 75)
841 smRender_stree(smMesh,qual);
842 else
843 smRender_mesh(smMesh,view->vp,last_update);
844 #ifdef TEST_DRIVER
845 glFlush();
846 glutSwapBuffers();
847 #endif
848 }
849 /* Do an incremental update instead */
850 else
851 {
852 if(!smNew_tri_cnt)
853 return;
854 #ifdef TEST_DRIVER
855 glDrawBuffer(GL_FRONT);
856 #else
857 t = SM_TONE_MAP(smMesh);
858 if(t == 0)
859 {
860 tmClearHisto();
861 tmAddHisto(SM_BRT(smMesh),SM_NUM_SAMP(smMesh),1);
862 if(tmComputeMapping(0.,0.,0.) != TM_E_OK)
863 return;
864 }
865 if(tmMapPixels(SM_NTH_RGB(smMesh,t),&SM_NTH_BRT(smMesh,t),
866 SM_NTH_CHR(smMesh,t), SM_NUM_SAMP(smMesh)-t) != TM_E_OK)
867 return;
868 #endif
869 smUpdate_Rendered_mesh(smMesh,view->vp,last_update);
870
871 #ifdef TEST_DRIVER
872 glDrawBuffer(GL_BACK);
873 #endif
874 }
875 SM_TONE_MAP(smMesh) = SM_NUM_SAMP(smMesh);
876 if (last_update)
877 {
878 smClean_notify = FALSE;
879 smNew_tri_cnt = 0;
880 smClear_flags(smMesh,T_NEW_FLAG);
881 qtCache_init(0);
882 }
883
884 }