ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/sm_ogl.c
Revision: 3.9
Committed: Wed Nov 11 12:05:39 1998 UTC (25 years, 5 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.8: +24 -29 lines
Log Message:
new triangulation code
changed triangle vertex order to CCW
changed numbering of triangle neighbors to match quadtree
fixed tone-mapping bug
removed errant printf() statements
redid logic for adding and testing samples with new epsilon

File Contents

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