ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/sm.c
Revision: 3.9
Committed: Wed Nov 11 12:05:37 1998 UTC (25 years, 5 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.8: +185 -153 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.c
9     */
10     #include "standard.h"
11 gwlarson 3.8 #include "sm_flag.h"
12 gwlarson 3.1 #include "sm_list.h"
13     #include "sm_geom.h"
14 gwlarson 3.8 #include "sm_qtree.h"
15     #include "sm_stree.h"
16 gwlarson 3.1 #include "sm.h"
17    
18    
19     SM *smMesh = NULL;
20     double smDist_sum=0;
21     int smNew_tri_cnt=0;
22 gwlarson 3.9 double smMinSampDiff = 1.7e-3; /* min edge length in radians */
23 gwlarson 3.1
24 gwlarson 3.8 static FVECT smDefault_base[4] = { {SQRT3_INV, SQRT3_INV, SQRT3_INV},
25     {-SQRT3_INV, -SQRT3_INV, SQRT3_INV},
26     {-SQRT3_INV, SQRT3_INV, -SQRT3_INV},
27     {SQRT3_INV, -SQRT3_INV, -SQRT3_INV}};
28 gwlarson 3.9 static int smTri_verts[4][3] = { {0,1,2},{0,2,3},{0,3,1},{1,3,2}};
29 gwlarson 3.8
30 gwlarson 3.9 static int smBase_nbrs[4][3] = { {3,1,2},{3,2,0},{3,0,1},{1,0,2}};
31 gwlarson 3.5
32 gwlarson 3.1 #ifdef TEST_DRIVER
33     VIEW Current_View = {0,{0,0,0},{0,0,-1},{0,1,0},60,60,0};
34     int Pick_cnt =0;
35 gwlarson 3.5 int Pick_tri = -1,Picking = FALSE,Pick_samp=-1;
36 gwlarson 3.1 FVECT Pick_point[500],Pick_origin,Pick_dir;
37     FVECT Pick_v0[500], Pick_v1[500], Pick_v2[500];
38 gwlarson 3.9 int Pick_q[500];
39 gwlarson 3.1 FVECT P0,P1,P2;
40     FVECT FrustumNear[4],FrustumFar[4];
41     double dev_zmin=.01,dev_zmax=1000;
42     #endif
43    
44     smDir(sm,ps,id)
45     SM *sm;
46     FVECT ps;
47     int id;
48     {
49 gwlarson 3.8 VSUB(ps,SM_NTH_WV(sm,id),SM_VIEW_CENTER(sm));
50     normalize(ps);
51 gwlarson 3.1 }
52 gwlarson 3.8
53 gwlarson 3.7 smDir_in_cone(sm,ps,id)
54     SM *sm;
55     FVECT ps;
56     int id;
57     {
58    
59 gwlarson 3.8 VSUB(ps,SM_NTH_WV(sm,id),SM_VIEW_CENTER(sm));
60     normalize(ps);
61 gwlarson 3.7 }
62 gwlarson 3.1
63     smClear_flags(sm,which)
64     SM *sm;
65     int which;
66     {
67     int i;
68    
69     if(which== -1)
70     for(i=0; i < T_FLAGS;i++)
71 gwlarson 3.8 bzero(SM_NTH_FLAGS(sm,i),FLAG_BYTES(SM_MAX_TRIS(sm)));
72 gwlarson 3.1 else
73 gwlarson 3.8 bzero(SM_NTH_FLAGS(sm,which),FLAG_BYTES(SM_MAX_TRIS(sm)));
74 gwlarson 3.1 }
75    
76 gwlarson 3.8 /* Given an allocated mesh- initialize */
77     smInit_mesh(sm)
78     SM *sm;
79 gwlarson 3.1 {
80 gwlarson 3.8 /* Reset the triangle counters */
81     SM_NUM_TRI(sm) = 0;
82     SM_SAMPLE_TRIS(sm) = 0;
83     SM_FREE_TRIS(sm) = -1;
84     smClear_flags(sm,-1);
85 gwlarson 3.1 }
86    
87    
88 gwlarson 3.8 /* Clear the SM for reuse: free any extra allocated memory:does initialization
89     as well
90     */
91 gwlarson 3.1 smClear(sm)
92     SM *sm;
93     {
94     smClear_samples(sm);
95     smClear_locator(sm);
96 gwlarson 3.8 smInit_mesh(sm);
97 gwlarson 3.1 }
98    
99 gwlarson 3.8 static int realloc_cnt=0;
100    
101 gwlarson 3.1 int
102 gwlarson 3.8 smRealloc_mesh(sm)
103 gwlarson 3.1 SM *sm;
104 gwlarson 3.8 {
105     int fbytes,i,max_tris,max_verts;
106    
107     if(realloc_cnt <=0)
108     realloc_cnt = SM_MAX_TRIS(sm);
109    
110     max_tris = SM_MAX_TRIS(sm) + realloc_cnt;
111     fbytes = FLAG_BYTES(max_tris);
112    
113     if(!(SM_TRIS(sm) = (TRI *)realloc(SM_TRIS(sm),max_tris*sizeof(TRI))))
114     goto memerr;
115    
116     for(i=0; i< T_FLAGS; i++)
117     if(!(SM_NTH_FLAGS(sm,i)=(int4 *)realloc((char *)SM_NTH_FLAGS(sm,i),fbytes)))
118     goto memerr;
119    
120     SM_MAX_TRIS(sm) = max_tris;
121     return(max_tris);
122    
123     memerr:
124     error(SYSTEM, "out of memory in smRealloc_mesh()");
125     }
126    
127     /* Allocate and initialize a new mesh with max_verts and max_tris */
128     int
129     smAlloc_mesh(sm,max_verts,max_tris)
130     SM *sm;
131 gwlarson 3.1 int max_verts,max_tris;
132     {
133 gwlarson 3.8 int fbytes,i;
134 gwlarson 3.1
135 gwlarson 3.8 fbytes = FLAG_BYTES(max_tris);
136 gwlarson 3.1
137 gwlarson 3.8 if(!(SM_TRIS(sm) = (TRI *)realloc(NULL,max_tris*sizeof(TRI))))
138     goto memerr;
139 gwlarson 3.1
140 gwlarson 3.8 if(!(SM_VERTS(sm) = (VERT *)realloc(NULL,max_verts*sizeof(VERT))))
141     goto memerr;
142 gwlarson 3.1
143 gwlarson 3.8 for(i=0; i< T_FLAGS; i++)
144     if(!(SM_NTH_FLAGS(sm,i)=(int4 *)realloc(NULL,fbytes)))
145     goto memerr;
146    
147 gwlarson 3.1 SM_MAX_VERTS(sm) = max_verts;
148     SM_MAX_TRIS(sm) = max_tris;
149    
150 gwlarson 3.8 realloc_cnt = max_verts >> 1;
151 gwlarson 3.1
152 gwlarson 3.8 smInit_mesh(sm);
153    
154 gwlarson 3.1 return(max_tris);
155 gwlarson 3.8 memerr:
156     error(SYSTEM, "out of memory in smAlloc_mesh()");
157 gwlarson 3.1 }
158    
159    
160     int
161 gwlarson 3.8 smAlloc_tri(sm)
162 gwlarson 3.1 SM *sm;
163     {
164 gwlarson 3.8 int id;
165    
166     /* First check if there are any tris on the free list */
167     /* Otherwise, have we reached the end of the list yet?*/
168     if(SM_NUM_TRI(sm) < SM_MAX_TRIS(sm))
169     return(SM_NUM_TRI(sm)++);
170    
171     if((id = SM_FREE_TRIS(sm)) != -1)
172     {
173     SM_FREE_TRIS(sm) = T_NEXT_FREE(SM_NTH_TRI(sm,id));
174     return(id);
175     }
176    
177     /*Else: realloc */
178     smRealloc_mesh(sm);
179     return(SM_NUM_TRI(sm)++);
180 gwlarson 3.1 }
181    
182 gwlarson 3.8 smFree_mesh(sm)
183     SM *sm;
184     {
185     int i;
186    
187     if(SM_TRIS(sm))
188     free(SM_TRIS(sm));
189     if(SM_VERTS(sm))
190     free(SM_VERTS(sm));
191     for(i=0; i< T_FLAGS; i++)
192     if(SM_NTH_FLAGS(sm,i))
193     free(SM_NTH_FLAGS(sm,i));
194     }
195    
196    
197 gwlarson 3.1 /* Initialize/clear global smL sample list for at least n samples */
198     smAlloc(max_samples)
199     register int max_samples;
200     {
201     unsigned nbytes;
202     register unsigned i;
203     int total_points;
204 gwlarson 3.8 int max_tris,n;
205 gwlarson 3.1
206 gwlarson 3.8 n = max_samples;
207 gwlarson 3.1 /* If this is the first call, allocate sample,vertex and triangle lists */
208     if(!smMesh)
209     {
210     if(!(smMesh = (SM *)malloc(sizeof(SM))))
211 gwlarson 3.8 error(SYSTEM,"smAlloc():Unable to allocate memory\n");
212 gwlarson 3.1 bzero(smMesh,sizeof(SM));
213     }
214     else
215     { /* If existing structure: first deallocate */
216 gwlarson 3.8 smFree_mesh(smMesh);
217     smFree_samples(smMesh);
218     smFree_locator(smMesh);
219     }
220 gwlarson 3.1
221     /* First allocate at least n samples + extra points:at least enough
222     necessary to form the BASE MESH- Default = 4;
223     */
224 gwlarson 3.8 SM_SAMP(smMesh) = sAlloc(&n,SM_EXTRA_POINTS);
225 gwlarson 3.1
226 gwlarson 3.8 total_points = n + SM_EXTRA_POINTS;
227 gwlarson 3.1
228 gwlarson 3.8 max_tris = total_points*4;
229 gwlarson 3.1 /* Now allocate space for mesh vertices and triangles */
230 gwlarson 3.8 max_tris = smAlloc_mesh(smMesh, total_points, max_tris);
231 gwlarson 3.1
232     /* Initialize the structure for point,triangle location.
233     */
234     smAlloc_locator(smMesh);
235     }
236    
237    
238    
239 gwlarson 3.8 smInit_sm(sm,vp)
240 gwlarson 3.1 SM *sm;
241     FVECT vp;
242     {
243    
244     smDist_sum = 0;
245     smNew_tri_cnt = 0;
246    
247 gwlarson 3.8 VCOPY(SM_VIEW_CENTER(sm),vp);
248     smInit_locator(sm,vp);
249     smInit_samples(sm);
250     smInit_mesh(sm);
251 gwlarson 3.1 smCreate_base_mesh(sm,SM_DEFAULT);
252     }
253    
254     /*
255     * int
256     * smInit(n) : Initialize/clear data structures for n entries
257     * int n;
258     *
259     * This routine allocates/initializes the sample, mesh, and point-location
260     * structures for at least n samples.
261     * If n is <= 0, then clear data structures. Returns number samples
262     * actually allocated.
263     */
264    
265     int
266     smInit(n)
267     register int n;
268     {
269     int max_vertices;
270    
271 gwlarson 3.8
272 gwlarson 3.1 /* If n <=0, Just clear the existing structures */
273     if(n <= 0)
274     {
275     smClear(smMesh);
276     return(0);
277     }
278    
279     /* Total mesh vertices includes the sample points and the extra vertices
280     to form the base mesh
281     */
282     max_vertices = n + SM_EXTRA_POINTS;
283    
284     /* If the current mesh contains enough room, clear and return */
285 gwlarson 3.8 if(smMesh && (max_vertices <= SM_MAX_VERTS(smMesh)) && SM_MAX_SAMP(smMesh) <=
286     n && SM_MAX_POINTS(smMesh) <= max_vertices)
287 gwlarson 3.1 {
288     smClear(smMesh);
289     return(SM_MAX_SAMP(smMesh));
290     }
291     /* Otherwise- mesh must be allocated with the appropriate number of
292     samples
293     */
294     smAlloc(n);
295    
296     return(SM_MAX_SAMP(smMesh));
297     }
298    
299    
300 gwlarson 3.8 smLocator_apply_func(sm,v0,v1,v2,edge_func,tri_func,argptr)
301 gwlarson 3.7 SM *sm;
302     FVECT v0,v1,v2;
303     int (*edge_func)();
304 gwlarson 3.8 int (*tri_func)();
305     int *argptr;
306 gwlarson 3.1 {
307     STREE *st;
308     FVECT p0,p1,p2;
309    
310     st = SM_LOCATOR(sm);
311    
312 gwlarson 3.5 VSUB(p0,v0,SM_VIEW_CENTER(sm));
313     VSUB(p1,v1,SM_VIEW_CENTER(sm));
314     VSUB(p2,v2,SM_VIEW_CENTER(sm));
315 gwlarson 3.1
316 gwlarson 3.8 stApply_to_tri(st,p0,p1,p2,edge_func,tri_func,argptr);
317 gwlarson 3.1
318     }
319    
320 gwlarson 3.8 QUADTREE
321     delete_tri_set(qt,optr,del_set)
322     QUADTREE qt;
323     OBJECT *optr,*del_set;
324     {
325 gwlarson 3.1
326 gwlarson 3.8 int set_size,i,t_id;
327     OBJECT *rptr,r_set[QT_MAXSET+1];
328     OBJECT *tptr,t_set[QT_MAXSET+1],*sptr;
329    
330     /* First need to check if set size larger than QT_MAXSET: if so
331     need to allocate larger array
332     */
333     if((set_size = MAX(QT_SET_CNT(optr),QT_SET_CNT(del_set))) >QT_MAXSET)
334     rptr = (OBJECT *)malloc((set_size+1)*sizeof(OBJECT));
335     else
336     rptr = r_set;
337     if(!rptr)
338     goto memerr;
339     setintersect(rptr,del_set,optr);
340    
341     if(QT_SET_CNT(rptr) > 0)
342     {
343     /* First need to check if set size larger than QT_MAXSET: if so
344     need to allocate larger array
345     */
346     sptr = QT_SET_PTR(rptr);
347     for(i = QT_SET_CNT(rptr); i > 0; i--)
348     {
349     t_id = QT_SET_NEXT_ELEM(sptr);
350     qt = qtdelelem(qt,t_id);
351     }
352     }
353     /* If we allocated memory: free it */
354     if(rptr != r_set)
355     free(rptr);
356    
357     return(qt);
358     memerr:
359     error(SYSTEM,"delete_tri_set():Unable to allocate memory");
360     }
361    
362     QUADTREE
363     expand_node(qt,q0,q1,q2,optr,n)
364     QUADTREE qt;
365     FVECT q0,q1,q2;
366     OBJECT *optr;
367     int n;
368     {
369     OBJECT *tptr,t_set[QT_MAXSET+1];
370     int i,t_id,found;
371     TRI *t;
372     FVECT v0,v1,v2;
373    
374     if(QT_SET_CNT(optr) > QT_MAXSET)
375     tptr = (OBJECT *)malloc((QT_SET_CNT(optr)+1)*sizeof(OBJECT));
376     else
377     tptr = t_set;
378     if(!tptr)
379     goto memerr;
380    
381     qtgetset(tptr,qt);
382     /* If set size exceeds threshold: subdivide cell and reinsert tris*/
383     qtfreeleaf(qt);
384     qtSubdivide(qt);
385    
386     for(optr = QT_SET_PTR(tptr),i=QT_SET_CNT(tptr); i > 0; i--)
387     {
388     t_id = QT_SET_NEXT_ELEM(optr);
389     t = SM_NTH_TRI(smMesh,t_id);
390     if(!T_IS_VALID(t))
391     continue;
392     VSUB(v0,SM_T_NTH_WV(smMesh,t,0),SM_VIEW_CENTER(smMesh));
393     VSUB(v1,SM_T_NTH_WV(smMesh,t,1),SM_VIEW_CENTER(smMesh));
394     VSUB(v2,SM_T_NTH_WV(smMesh,t,2),SM_VIEW_CENTER(smMesh));
395     qt = qtAdd_tri(qt,q0,q1,q2,v0,v1,v2,t_id,n);
396     }
397     /* If we allocated memory: free it */
398     if( tptr != t_set)
399     free(tptr);
400    
401     return(qt);
402     memerr:
403     error(SYSTEM,"expand_node():Unable to allocate memory");
404     }
405    
406     add_tri_expand(qtptr,f,argptr,q0,q1,q2,t0,t1,t2,n)
407 gwlarson 3.5 QUADTREE *qtptr;
408 gwlarson 3.8 int *f;
409     ADD_ARGS *argptr;
410 gwlarson 3.5 FVECT q0,q1,q2;
411     FVECT t0,t1,t2;
412     int n;
413     {
414 gwlarson 3.8 int t_id;
415     OBJECT *optr,*del_set;
416 gwlarson 3.7
417 gwlarson 3.8 t_id = argptr->t_id;
418    
419     if(QT_IS_EMPTY(*qtptr))
420     {
421     *qtptr = qtaddelem(*qtptr,t_id);
422     return;
423     }
424     if(!QT_LEAF_IS_FLAG(*qtptr))
425     {
426 gwlarson 3.5 optr = qtqueryset(*qtptr);
427    
428 gwlarson 3.8 if(del_set=argptr->del_set)
429     *qtptr = delete_tri_set(*qtptr,optr,del_set);
430     *qtptr = qtaddelem(*qtptr,t_id);
431     }
432     if (n >= QT_MAX_LEVELS)
433     return;
434     optr = qtqueryset(*qtptr);
435     if(QT_SET_CNT(optr) < QT_SET_THRESHOLD)
436     return;
437     *qtptr = expand_node(*qtptr,q0,q1,q2,optr,n);
438 gwlarson 3.5 }
439    
440    
441 gwlarson 3.8
442     add_tri(qtptr,fptr,argptr)
443 gwlarson 3.5 QUADTREE *qtptr;
444     int *fptr;
445 gwlarson 3.8 ADD_ARGS *argptr;
446 gwlarson 3.5 {
447    
448 gwlarson 3.8 OBJECT *optr,*del_set;
449     int t_id;
450    
451     t_id = argptr->t_id;
452    
453    
454     if(QT_IS_EMPTY(*qtptr))
455     {
456     *qtptr = qtaddelem(*qtptr,t_id);
457     if(!QT_FLAG_FILL_TRI(*fptr))
458     (*fptr)++;
459     return;
460     }
461     if(QT_LEAF_IS_FLAG(*qtptr))
462     return;
463    
464     optr = qtqueryset(*qtptr);
465    
466     if(del_set = argptr->del_set)
467     *qtptr = delete_tri_set(*qtptr,optr,del_set);
468    
469     if(!QT_IS_EMPTY(*qtptr))
470 gwlarson 3.5 {
471 gwlarson 3.8 optr = qtqueryset(*qtptr);
472     if(QT_SET_CNT(optr) >= QT_SET_THRESHOLD)
473     (*fptr) |= QT_EXPAND;
474 gwlarson 3.5 }
475 gwlarson 3.8 if(!QT_FLAG_FILL_TRI(*fptr))
476     (*fptr)++;
477     *qtptr = qtaddelem(*qtptr,t_id);
478    
479 gwlarson 3.5 }
480    
481    
482 gwlarson 3.7 smLocator_add_tri(sm,t_id,v0_id,v1_id,v2_id,del_set)
483 gwlarson 3.1 SM *sm;
484     int t_id;
485 gwlarson 3.7 int v0_id,v1_id,v2_id;
486     OBJECT *del_set;
487 gwlarson 3.1 {
488     STREE *st;
489 gwlarson 3.5 FVECT v0,v1,v2;
490 gwlarson 3.8 ADD_ARGS args;
491    
492 gwlarson 3.1 st = SM_LOCATOR(sm);
493    
494 gwlarson 3.9 #ifdef DEBUG
495     if((v0_id == INVALID) || (v1_id == INVALID) || (v2_id == INVALID))
496     error(CONSISTENCY,"Invalid ids 1\n");
497     #endif
498 gwlarson 3.8
499 gwlarson 3.5 VSUB(v0,SM_NTH_WV(sm,v0_id),SM_VIEW_CENTER(sm));
500     VSUB(v1,SM_NTH_WV(sm,v1_id),SM_VIEW_CENTER(sm));
501     VSUB(v2,SM_NTH_WV(sm,v2_id),SM_VIEW_CENTER(sm));
502 gwlarson 3.1
503 gwlarson 3.7 qtClearAllFlags();
504 gwlarson 3.8 args.t_id = t_id;
505     args.del_set = del_set;
506 gwlarson 3.1
507 gwlarson 3.8 stApply_to_tri(st,v0,v1,v2,add_tri,add_tri_expand,&args);
508    
509 gwlarson 3.1 }
510    
511     /* Add a triangle to the base array with vertices v1-v2-v3 */
512     int
513 gwlarson 3.8 smAdd_tri(sm, v0_id,v1_id,v2_id)
514 gwlarson 3.1 SM *sm;
515     int v0_id,v1_id,v2_id;
516     {
517     int t_id;
518     TRI *t;
519 gwlarson 3.9 #ifdef DEBUG
520     if(v0_id==v1_id || v0_id==v2_id || v1_id==v2_id)
521     {
522     eputs("smAdd_tri: invalid vertex ids\n");
523     return(INVALID);
524     }
525     #endif
526 gwlarson 3.8 t_id = smAlloc_tri(sm);
527 gwlarson 3.1
528     if(t_id == -1)
529     return(t_id);
530    
531     t = SM_NTH_TRI(sm,t_id);
532 gwlarson 3.8
533 gwlarson 3.1 T_CLEAR_NBRS(t);
534 gwlarson 3.8 /* set the triangle vertex ids */
535     T_NTH_V(t,0) = v0_id;
536     T_NTH_V(t,1) = v1_id;
537     T_NTH_V(t,2) = v2_id;
538 gwlarson 3.1
539 gwlarson 3.8 SM_NTH_VERT(sm,v0_id) = t_id;
540     SM_NTH_VERT(sm,v1_id) = t_id;
541     SM_NTH_VERT(sm,v2_id) = t_id;
542    
543 gwlarson 3.1 if(SM_BASE_ID(sm,v0_id) || SM_BASE_ID(sm,v1_id) || SM_BASE_ID(sm,v2_id))
544     {
545     smClear_tri_flags(sm,t_id);
546     SM_SET_NTH_T_BASE(sm,t_id);
547     }
548     else
549     {
550 gwlarson 3.8 SM_CLR_NTH_T_BASE(sm,t_id);
551 gwlarson 3.1 SM_SET_NTH_T_ACTIVE(sm,t_id);
552     SM_SET_NTH_T_NEW(sm,t_id);
553 gwlarson 3.8 S_SET_FLAG(T_NTH_V(t,0));
554     S_SET_FLAG(T_NTH_V(t,1));
555     S_SET_FLAG(T_NTH_V(t,2));
556     SM_SAMPLE_TRIS(sm)++;
557 gwlarson 3.1 smNew_tri_cnt++;
558     }
559    
560     /* return initialized triangle */
561     return(t_id);
562     }
563    
564    
565     void
566 gwlarson 3.8 smTris_swap_edge(sm,t_id,t1_id,e,e1,tn_id,tn1_id,add_ptr,delptr)
567 gwlarson 3.1 SM *sm;
568     int t_id,t1_id;
569     int e,e1;
570 gwlarson 3.5 int *tn_id,*tn1_id;
571 gwlarson 3.7 LIST **add_ptr;
572 gwlarson 3.8 QUADTREE *delptr;
573 gwlarson 3.1
574     {
575     int verts[3],enext,eprev,e1next,e1prev;
576 gwlarson 3.9 TRI *n,*ta,*tb,*t,*t1;
577 gwlarson 3.1 FVECT p1,p2,p3;
578     int ta_id,tb_id;
579 gwlarson 3.9 /* form new diagonal (e relative to t, and e1 relative to t1)
580     defined by quadrilateral formed by t,t1- swap for the opposite diagonal
581 gwlarson 3.1 */
582     enext = (e+1)%3;
583     eprev = (e+2)%3;
584     e1next = (e1+1)%3;
585     e1prev = (e1+2)%3;
586 gwlarson 3.8 verts[e] = T_NTH_V(SM_NTH_TRI(sm,t_id),e);
587 gwlarson 3.9 verts[enext] = T_NTH_V(SM_NTH_TRI(sm,t_id),enext);
588     verts[eprev] = T_NTH_V(SM_NTH_TRI(sm,t1_id),e1);
589 gwlarson 3.8 ta_id = smAdd_tri(sm,verts[0],verts[1],verts[2]);
590 gwlarson 3.7 *add_ptr = push_data(*add_ptr,ta_id);
591 gwlarson 3.8 verts[e1] = T_NTH_V(SM_NTH_TRI(sm,t1_id),e1);
592 gwlarson 3.9 verts[e1next] = T_NTH_V(SM_NTH_TRI(sm,t1_id),e1next);
593     verts[e1prev] = T_NTH_V(SM_NTH_TRI(sm,t_id),e);
594 gwlarson 3.8 tb_id = smAdd_tri(sm,verts[0],verts[1],verts[2]);
595 gwlarson 3.7 *add_ptr = push_data(*add_ptr,tb_id);
596 gwlarson 3.3
597 gwlarson 3.9 ta = SM_NTH_TRI(sm,ta_id);
598     tb = SM_NTH_TRI(sm,tb_id);
599     t = SM_NTH_TRI(sm,t_id);
600     t1 = SM_NTH_TRI(sm,t1_id);
601 gwlarson 3.1 /* set the neighbors */
602 gwlarson 3.9 T_NTH_NBR(ta,e) = T_NTH_NBR(t1,e1next);
603     T_NTH_NBR(tb,e1) = T_NTH_NBR(t,enext);
604     T_NTH_NBR(ta,enext)= tb_id;
605     T_NTH_NBR(tb,e1next)= ta_id;
606     T_NTH_NBR(ta,eprev)=T_NTH_NBR(t,eprev);
607     T_NTH_NBR(tb,e1prev)=T_NTH_NBR(t1,e1prev);
608 gwlarson 3.1
609     /* Reset neighbor pointers of original neighbors */
610 gwlarson 3.9 n = SM_NTH_TRI(sm,T_NTH_NBR(t,enext));
611 gwlarson 3.1 T_NTH_NBR(n,T_NTH_NBR_PTR(t_id,n)) = tb_id;
612 gwlarson 3.9 n = SM_NTH_TRI(sm,T_NTH_NBR(t,eprev));
613 gwlarson 3.1 T_NTH_NBR(n,T_NTH_NBR_PTR(t_id,n)) = ta_id;
614    
615 gwlarson 3.9 n = SM_NTH_TRI(sm,T_NTH_NBR(t1,e1next));
616 gwlarson 3.1 T_NTH_NBR(n,T_NTH_NBR_PTR(t1_id,n)) = ta_id;
617 gwlarson 3.9 n = SM_NTH_TRI(sm,T_NTH_NBR(t1,e1prev));
618 gwlarson 3.1 T_NTH_NBR(n,T_NTH_NBR_PTR(t1_id,n)) = tb_id;
619    
620     /* Delete two parent triangles */
621 gwlarson 3.7 if(remove_from_list(t_id,add_ptr))
622     smDelete_tri(sm,t_id);
623     else
624 gwlarson 3.8 *delptr = qtaddelem(*delptr,t_id);
625 gwlarson 3.5
626 gwlarson 3.7 if(remove_from_list(t1_id,add_ptr))
627     smDelete_tri(sm,t1_id);
628     else
629 gwlarson 3.8 *delptr = qtaddelem(*delptr,t1_id);
630 gwlarson 3.7
631 gwlarson 3.1 *tn_id = ta_id;
632     *tn1_id = tb_id;
633     }
634    
635 gwlarson 3.7 smUpdate_locator(sm,add_list,del_set)
636 gwlarson 3.3 SM *sm;
637 gwlarson 3.7 LIST *add_list;
638     OBJECT *del_set;
639 gwlarson 3.3 {
640 gwlarson 3.7 int t_id,i;
641 gwlarson 3.3 TRI *t;
642 gwlarson 3.7 OBJECT *optr;
643    
644 gwlarson 3.3 while(add_list)
645     {
646     t_id = pop_list(&add_list);
647 gwlarson 3.6 t = SM_NTH_TRI(sm,t_id);
648 gwlarson 3.7 smLocator_add_tri(sm,t_id,T_NTH_V(t,0),T_NTH_V(t,1),T_NTH_V(t,2),del_set);
649 gwlarson 3.3 }
650 gwlarson 3.7
651     optr = QT_SET_PTR(del_set);
652     for(i = QT_SET_CNT(del_set); i > 0; i--)
653 gwlarson 3.3 {
654 gwlarson 3.7 t_id = QT_SET_NEXT_ELEM(optr);
655 gwlarson 3.8 #if 0
656     t = SM_NTH_TRI(sm,t_id);
657     smLocator_remove_tri(sm,t_id,T_NTH_V(t,0),T_NTH_V(t,1),T_NTH_V(t,2));
658     #endif
659 gwlarson 3.7 smDelete_tri(sm,t_id);
660 gwlarson 3.3 }
661     }
662 gwlarson 3.1 /* MUST add check for constrained edges */
663 gwlarson 3.3 int
664 gwlarson 3.8 smFix_tris(sm,id,tlist,add_list,delptr)
665 gwlarson 3.1 SM *sm;
666     int id;
667 gwlarson 3.8 LIST *tlist,*add_list;
668     QUADTREE *delptr;
669 gwlarson 3.1 {
670     TRI *t,*t_opp;
671 gwlarson 3.9 FVECT p,p0,p1,p2;
672 gwlarson 3.3 int e,e1,swapped = 0;
673 gwlarson 3.1 int t_id,t_opp_id;
674 gwlarson 3.3
675     VSUB(p,SM_NTH_WV(sm,id),SM_VIEW_CENTER(sm));
676 gwlarson 3.1 while(tlist)
677     {
678 gwlarson 3.3 t_id = pop_list(&tlist);
679 gwlarson 3.9 #ifdef DEBUG
680     if(t_id==INVALID || t_id > smMesh->num_tri)
681     error(CONSISTENCY,"Invalid tri id smFix_tris()\n");
682     #endif
683 gwlarson 3.1 t = SM_NTH_TRI(sm,t_id);
684 gwlarson 3.9 e = T_WHICH_V(t,id);
685 gwlarson 3.1 t_opp_id = T_NTH_NBR(t,e);
686 gwlarson 3.9 #ifdef DEBUG
687     if(t_opp_id==INVALID || t_opp_id > smMesh->num_tri)
688     error(CONSISTENCY,"Invalid tri id smFix_tris()\n");
689     #endif
690     t_opp = SM_NTH_TRI(sm,t_opp_id);
691    
692     smDir_in_cone(sm,p0,T_NTH_V(t_opp,0));
693     smDir_in_cone(sm,p1,T_NTH_V(t_opp,1));
694     smDir_in_cone(sm,p2,T_NTH_V(t_opp,2));
695     if(point_in_cone(p,p0,p1,p2))
696 gwlarson 3.1 {
697     swapped = 1;
698     e1 = T_NTH_NBR_PTR(t_id,t_opp);
699     /* check list for t_opp and Remove if there */
700     remove_from_list(t_opp_id,&tlist);
701 gwlarson 3.3 smTris_swap_edge(sm,t_id,t_opp_id,e,e1,&t_id,&t_opp_id,
702 gwlarson 3.8 &add_list,delptr);
703 gwlarson 3.1 tlist = push_data(tlist,t_id);
704     tlist = push_data(tlist,t_opp_id);
705     }
706     }
707 gwlarson 3.8 smUpdate_locator(sm,add_list,qtqueryset(*delptr));
708 gwlarson 3.1 return(swapped);
709     }
710    
711     /* Give the vertex "id" and a triangle "t" that it belongs to- return the
712     next nbr in a counter clockwise order about vertex "id"
713     */
714     int
715     smTri_next_ccw_nbr(sm,t,id)
716     SM *sm;
717     TRI *t;
718     int id;
719     {
720     int t_id;
721 gwlarson 3.8 int nbr_id;
722 gwlarson 3.1
723     /* Want the edge for which "id" is the destination */
724 gwlarson 3.9 t_id = (T_WHICH_V(t,id)+ 1)% 3;
725 gwlarson 3.8 nbr_id = T_NTH_NBR(t,t_id);
726     return(nbr_id);
727 gwlarson 3.1 }
728    
729     smClear_tri_flags(sm,id)
730     SM *sm;
731     int id;
732     {
733     int i;
734    
735     for(i=0; i < T_FLAGS; i++)
736 gwlarson 3.8 SM_CLR_NTH_T_FLAG(sm,id,i);
737 gwlarson 3.1
738     }
739    
740     /* Locate the point-id in the point location structure: */
741     int
742 gwlarson 3.8 smInsert_samp(sm,s_id,tri_id)
743 gwlarson 3.1 SM *sm;
744     int s_id,tri_id;
745     {
746 gwlarson 3.8 int v0_id,v1_id,v2_id;
747     int t0_id,t1_id,t2_id,replaced;
748 gwlarson 3.7 LIST *tlist,*add_list;
749 gwlarson 3.8 OBJECT del_set[2];
750     QUADTREE delnode;
751 gwlarson 3.1 FVECT npt;
752 gwlarson 3.8 TRI *tri,*nbr;
753 gwlarson 3.1
754 gwlarson 3.7 add_list = NULL;
755 gwlarson 3.1
756 gwlarson 3.8 v0_id = T_NTH_V(SM_NTH_TRI(sm,tri_id),0);
757     v1_id = T_NTH_V(SM_NTH_TRI(sm,tri_id),1);
758     v2_id = T_NTH_V(SM_NTH_TRI(sm,tri_id),2);
759    
760     t0_id = smAdd_tri(sm,s_id,v0_id,v1_id);
761 gwlarson 3.3 /* Add triangle to the locator */
762 gwlarson 3.6
763     add_list = push_data(add_list,t0_id);
764 gwlarson 3.3
765 gwlarson 3.8 t1_id = smAdd_tri(sm,s_id,v1_id,v2_id);
766 gwlarson 3.6 add_list = push_data(add_list,t1_id);
767    
768 gwlarson 3.8 t2_id = smAdd_tri(sm,s_id,v2_id,v0_id);
769 gwlarson 3.6 add_list = push_data(add_list,t2_id);
770 gwlarson 3.3
771 gwlarson 3.8 /* CAUTION: tri must be assigned after Add_tri: pointers may change*/
772     tri = SM_NTH_TRI(sm,tri_id);
773    
774 gwlarson 3.1 /* Set the neighbor pointers for the new tris */
775 gwlarson 3.9 T_NTH_NBR(SM_NTH_TRI(sm,t0_id),0) = T_NTH_NBR(tri,2);
776     T_NTH_NBR(SM_NTH_TRI(sm,t0_id),1) = t1_id;
777     T_NTH_NBR(SM_NTH_TRI(sm,t0_id),2) = t2_id;
778     T_NTH_NBR(SM_NTH_TRI(sm,t1_id),0) = T_NTH_NBR(tri,0);
779     T_NTH_NBR(SM_NTH_TRI(sm,t1_id),1) = t2_id;
780     T_NTH_NBR(SM_NTH_TRI(sm,t1_id),2) = t0_id;
781     T_NTH_NBR(SM_NTH_TRI(sm,t2_id),0) = T_NTH_NBR(tri,1);
782     T_NTH_NBR(SM_NTH_TRI(sm,t2_id),1) = t0_id;
783     T_NTH_NBR(SM_NTH_TRI(sm,t2_id),2) = t1_id;
784 gwlarson 3.1
785     /* Reset the neigbor pointers for the neighbors of the original */
786     nbr = SM_NTH_TRI(sm,T_NTH_NBR(tri,0));
787 gwlarson 3.9 T_NTH_NBR(nbr,T_NTH_NBR_PTR(tri_id,nbr)) = t1_id;
788 gwlarson 3.1 nbr = SM_NTH_TRI(sm,T_NTH_NBR(tri,1));
789 gwlarson 3.9 T_NTH_NBR(nbr,T_NTH_NBR_PTR(tri_id,nbr)) = t2_id;
790 gwlarson 3.1 nbr = SM_NTH_TRI(sm,T_NTH_NBR(tri,2));
791 gwlarson 3.9 T_NTH_NBR(nbr,T_NTH_NBR_PTR(tri_id,nbr)) = t0_id;
792 gwlarson 3.1
793 gwlarson 3.8 del_set[0] = 1; del_set[1] = tri_id;
794     delnode = qtnewleaf(del_set);
795 gwlarson 3.6
796 gwlarson 3.1 /* Fix up the new triangles*/
797     tlist = push_data(NULL,t0_id);
798     tlist = push_data(tlist,t1_id);
799     tlist = push_data(tlist,t2_id);
800    
801 gwlarson 3.8 smFix_tris(sm,s_id,tlist,add_list,&delnode);
802 gwlarson 3.1
803 gwlarson 3.8 qtfreeleaf(delnode);
804 gwlarson 3.1
805 gwlarson 3.8 return(TRUE);
806 gwlarson 3.1 }
807    
808    
809     int
810 gwlarson 3.8 smTri_in_set(sm,p,optr)
811 gwlarson 3.1 SM *sm;
812 gwlarson 3.8 FVECT p;
813     OBJECT *optr;
814 gwlarson 3.1 {
815 gwlarson 3.8 int i,t_id;
816     FVECT n,v0,v1,v2;
817     TRI *t;
818 gwlarson 3.1
819 gwlarson 3.8 for (i = QT_SET_CNT(optr),optr = QT_SET_PTR(optr);i > 0; i--)
820 gwlarson 3.1 {
821 gwlarson 3.8 /* Find the first triangle that pt falls */
822     t_id = QT_SET_NEXT_ELEM(optr);
823     t = SM_NTH_TRI(sm,t_id);
824     if(!T_IS_VALID(t))
825     continue;
826     VSUB(v0,SM_T_NTH_WV(sm,t,0),SM_VIEW_CENTER(sm));
827     VSUB(v1,SM_T_NTH_WV(sm,t,1),SM_VIEW_CENTER(sm));
828     VSUB(v2,SM_T_NTH_WV(sm,t,2),SM_VIEW_CENTER(sm));
829    
830     if(EQUAL_VEC3(v0,p) || EQUAL_VEC3(v1,p) || EQUAL_VEC3(v2,p))
831     return(t_id);
832    
833 gwlarson 3.9 VCROSS(n,v0,v1);
834 gwlarson 3.8 if(DOT(n,p) >0.0)
835     continue;
836 gwlarson 3.9 VCROSS(n,v1,v2);
837 gwlarson 3.8 if(DOT(n,p) > 0.0)
838     continue;
839    
840 gwlarson 3.9 VCROSS(n,v2,v0);
841 gwlarson 3.8 if(DOT(n,p) > 0.0)
842     continue;
843    
844     return(t_id);
845 gwlarson 3.1 }
846 gwlarson 3.8 return(INVALID);
847 gwlarson 3.1 }
848    
849 gwlarson 3.8 int
850 gwlarson 3.9 smPointLocateTri(sm,p)
851 gwlarson 3.1 SM *sm;
852 gwlarson 3.9 FVECT p;
853 gwlarson 3.1 {
854 gwlarson 3.9 QUADTREE qt,*optr;
855 gwlarson 3.8 FVECT tpt;
856 gwlarson 3.9
857     VSUB(tpt,p,SM_VIEW_CENTER(sm));
858 gwlarson 3.8 qt = smPointLocateCell(sm,tpt);
859     if(QT_IS_EMPTY(qt))
860     return(INVALID);
861    
862     optr = qtqueryset(qt);
863     return(smTri_in_set(sm,tpt,optr));
864     }
865 gwlarson 3.1
866 gwlarson 3.8
867     /*
868     Determine whether this sample should:
869     a) be added to the mesh by subdividing the triangle
870     b) ignored
871     c) replace values of an existing mesh vertex
872    
873     In case a, the routine will return TRUE, for b,c will return FALSE
874     In case a, also determine if this sample should cause the deletion of
875     an existing vertex. If so *rptr will contain the id of the sample to delete
876     after the new sample has been added.
877    
878     ASSUMPTION: this will not be called with a new sample that is
879     a BASE point.
880    
881     The following tests are performed (in order) to determine the fate
882     of the sample:
883    
884     1) If the world space point of the sample coincides with one of the
885     triangle vertex samples: The values of the triangle sample are
886     replaced with the new values and FALSE is returned
887     2) If the new sample is close in ws, and close in the spherical projection
888     to one of the triangle vertex samples:
889     pick the point with dir closest to that of the canonical view
890     If it is the new point: mark existing point for deletion,and return
891     TRUE,else return FALSE
892     3) If the spherical projection of new is < REPLACE_EPS from a base point:
893     add new and mark the base for deletion: return TRUE
894     4) If the addition of the new sample point would introduce a "puncture"
895     or cause new triangles with large depth differences:return FALSE
896     This attempts to throw out points that should be occluded
897     */
898     int
899 gwlarson 3.9 smTest_sample(sm,tri_id,c,dir,p,o_id,rptr)
900 gwlarson 3.8 SM *sm;
901 gwlarson 3.9 int tri_id;
902     COLR c;
903     FVECT dir,p;
904     int o_id;
905 gwlarson 3.8 int *rptr;
906     {
907     TRI *tri;
908     double d,d2,dnear,dspt,d01,d12,d20,s0,s1,s2,ds,dv;
909     int vid[3],i,nearid,norm,dcnt,bcnt;
910     FVECT diff[3],spt,npt;
911 gwlarson 3.9 int tonemap;
912 gwlarson 3.8
913     *rptr = INVALID;
914     bcnt = dcnt = 0;
915     tri = SM_NTH_TRI(sm,tri_id);
916     vid[0] = T_NTH_V(tri,0);
917     vid[1] = T_NTH_V(tri,1);
918     vid[2] = T_NTH_V(tri,2);
919    
920     /* TEST 1: Test if the new point has the same world space point as
921     one of the existing triangle vertices
922     */
923     for(i=0; i<3; i++)
924     {
925     if(SM_BASE_ID(sm,vid[i]))
926     {
927     bcnt++;
928     continue;
929     }
930     if(SM_DIR_ID(sm,vid[i]))
931     dcnt++;
932     VSUB(diff[i],SM_NTH_WV(sm,vid[i]),p);
933     /* If same world point: replace */
934 gwlarson 3.9 if(FZERO_VEC3(diff[i]))
935 gwlarson 3.8 {
936 gwlarson 3.9 tonemap = (SM_TONE_MAP(sm) > vid[i]);
937     sInit_samp(SM_SAMP(sm),vid[i],c,dir,p,o_id,tonemap);
938     return(FALSE);
939 gwlarson 3.8 }
940     }
941 gwlarson 3.9 if(!dir)
942     return(TRUE);
943 gwlarson 3.8 /* TEST 2: If the new sample is close in ws, and close in the spherical
944     projection to one of the triangle vertex samples
945     */
946     norm = FALSE;
947     if(bcnt + dcnt != 3)
948     {
949     VSUB(spt,p,SM_VIEW_CENTER(sm));
950     ds = DOT(spt,spt);
951     dnear = FHUGE;
952     for(i=0; i<3; i++)
953     {
954     if(SM_BASE_ID(sm,vid[i]) || SM_DIR_ID(sm,vid[i]))
955     continue;
956     d = DOT(diff[i],diff[i])/ds;
957     if(d < dnear)
958     {
959     dnear = d;
960     nearid=vid[i];
961     }
962     }
963    
964     if(dnear <= smMinSampDiff*smMinSampDiff)
965     {
966     /* Pick the point with dir closest to that of the canonical view
967     if it is the new sample: mark existing point for deletion
968     */
969     normalize(spt);
970     norm = TRUE;
971     VSUB(npt,SM_NTH_WV(sm,nearid),SM_VIEW_CENTER(sm));
972     normalize(npt);
973     d = fdir2diff(SM_NTH_W_DIR(sm,nearid), npt);
974 gwlarson 3.9 d2 = 2. - 2.*DOT(dir,spt);
975 gwlarson 3.8 /* The existing sample is a better sample:punt */
976     if(d2 > d)
977     return(FALSE);
978     else
979     {
980     /* The new sample is better: mark the existing one
981     for deletion after the new one is added*/
982     *rptr = nearid;
983     return(TRUE);
984     }
985     }
986     }
987     /* TEST 3: If the spherical projection of new is < S_REPLACE_EPS
988     from a base point
989     */
990     if(bcnt)
991     {
992     dnear = FHUGE;
993     if(bcnt + dcnt ==3)
994     VSUB(spt,p,SM_VIEW_CENTER(sm));
995     if(!norm)
996     normalize(spt);
997    
998     for(i=0; i<3; i++)
999     {
1000     if(!SM_BASE_ID(sm,vid[i]))
1001     continue;
1002     VSUB(npt,SM_NTH_WV(sm,vid[i]),SM_VIEW_CENTER(sm));
1003     d = DIST_SQ(npt,spt);
1004     if(d < S_REPLACE_EPS && d < dnear)
1005     {
1006     dnear = d;
1007     nearid = vid[i];
1008     }
1009     }
1010     if(dnear != FHUGE)
1011     {
1012     /* add new and mark the base for deletion */
1013     *rptr = nearid;
1014     return(TRUE);
1015     }
1016     }
1017    
1018     /* TEST 4:
1019     If the addition of the new sample point would introduce a "puncture"
1020     or cause new triangles with large depth differences:dont add:
1021     */
1022     if(bcnt || dcnt)
1023     return(TRUE);
1024     /* If the new point is in front of the existing points- add */
1025     dv = DIST_SQ(SM_NTH_WV(sm,vid[0]),SM_VIEW_CENTER(sm));
1026     if(ds < dv)
1027     return(TRUE);
1028    
1029     d01 = DIST_SQ(SM_NTH_WV(sm,vid[1]),SM_NTH_WV(sm,vid[0]));
1030     s0 = DOT(diff[0],diff[0]);
1031     if(s0 < S_REPLACE_SCALE*d01)
1032     return(TRUE);
1033     d12 = DIST_SQ(SM_NTH_WV(sm,vid[2]),SM_NTH_WV(sm,vid[1]));
1034     if(s0 < S_REPLACE_SCALE*d12)
1035     return(TRUE);
1036     d20 = DIST_SQ(SM_NTH_WV(sm,vid[0]),SM_NTH_WV(sm,vid[2]));
1037     if(s0 < S_REPLACE_SCALE*d20)
1038     return(TRUE);
1039     d = MIN3(d01,d12,d20);
1040     s1 = DOT(diff[1],diff[1]);
1041     if(s1 < S_REPLACE_SCALE*d)
1042     return(TRUE);
1043     s2 = DOT(diff[2],diff[2]);
1044     if(s2 < S_REPLACE_SCALE*d)
1045     return(TRUE);
1046    
1047 gwlarson 3.9 /* TEST 5:
1048     Check to see if triangle is relatively large and should therefore
1049     be subdivided anyway.
1050     */
1051     dv *= DIST_SQ(SM_NTH_WV(sm,vid[1]),SM_VIEW_CENTER(sm));
1052     dv *= DIST_SQ(SM_NTH_WV(sm,vid[2]),SM_VIEW_CENTER(sm));
1053     if (d01*d12*d20/dv > S_REPLACE_TRI)
1054     return(TRUE);
1055 gwlarson 3.8
1056     return(FALSE);
1057     }
1058    
1059    
1060     int
1061 gwlarson 3.9 smAlloc_samp(sm,c,dir,pt,o_id)
1062 gwlarson 3.8 SM *sm;
1063     COLR c;
1064     FVECT dir,pt;
1065 gwlarson 3.9 int o_id;
1066 gwlarson 3.8 {
1067     int s_id,replaced,cnt;
1068     SAMP *s;
1069     FVECT p;
1070    
1071     s = SM_SAMP(sm);
1072     s_id = sAlloc_samp(s,&replaced);
1073    
1074     cnt=0;
1075     while(replaced)
1076 gwlarson 3.1 {
1077 gwlarson 3.9 if(smRemoveVertex(sm,s_id))
1078 gwlarson 3.8 break;
1079     s_id = sAlloc_samp(s,&replaced);
1080     cnt++;
1081     if(cnt > S_MAX_SAMP(s))
1082     error(CONSISTENCY,"smAlloc_samp():unable to find free samp\n");
1083     }
1084 gwlarson 3.1
1085 gwlarson 3.9 /* If sample is being added in the middle of the sample array: tone
1086     map individually
1087     */
1088     /* Initialize sample */
1089     sInit_samp(s,s_id,c,dir,pt,o_id,(SM_TONE_MAP(sm)>s_id));
1090    
1091 gwlarson 3.8 return(s_id);
1092 gwlarson 3.1 }
1093    
1094     int
1095 gwlarson 3.9 smAdd_samp(sm,c,dir,p,o_id)
1096 gwlarson 3.1 SM *sm;
1097 gwlarson 3.9 COLR c;
1098     FVECT dir,p;
1099     int o_id;
1100 gwlarson 3.1 {
1101 gwlarson 3.9 int t_id,s_id,r_id;
1102     double d;
1103     FVECT wpt;
1104 gwlarson 3.8
1105 gwlarson 3.9 r_id = INVALID;
1106     /* If sample is a world space point */
1107     if(p)
1108     {
1109     t_id = smPointLocateTri(sm,p);
1110 gwlarson 3.8 if(t_id == INVALID)
1111 gwlarson 3.9 {
1112     #ifdef DEBUG
1113     eputs("smAddSamp(): unable to locate tri containing sample \n");
1114     #endif
1115     return(INVALID);
1116     }
1117     /* if not a base id, Test to see if this sample should be added */
1118     if(!SM_BASE_ID(sm,o_id))
1119 gwlarson 3.1 {
1120 gwlarson 3.9 if(!smTest_sample(sm,t_id,c,dir,p,o_id,&r_id))
1121     return(INVALID);
1122     /* Allocate space for a sample and initialize */
1123     s_id = smAlloc_samp(smMesh,c,dir,p,o_id);
1124     }
1125     else
1126     s_id = o_id;
1127     }
1128     /* If sample is a direction vector */
1129     else
1130     {
1131     VADD(wpt,dir,SM_VIEW_CENTER(smMesh));
1132     t_id = smPointLocateTri(sm,wpt);
1133     if(t_id == INVALID)
1134     {
1135 gwlarson 3.1 #ifdef DEBUG
1136 gwlarson 3.9 eputs("smAddSamp(): unable to locate tri containing sample \n");
1137 gwlarson 3.1 #endif
1138 gwlarson 3.9 return(INVALID);
1139     }
1140     /* Test to see if this sample should be added */
1141     if(!smTest_sample(sm,t_id,c,NULL,wpt,o_id,&r_id))
1142     return(INVALID);
1143     /* Allocate space for a sample and initialize */
1144     s_id = smAlloc_samp(smMesh,c,NULL,wpt,o_id);
1145 gwlarson 3.1 }
1146 gwlarson 3.9 if(!SM_BASE_ID(sm,s_id) && !SM_DIR_ID(sm,s_id))
1147 gwlarson 3.1 {
1148 gwlarson 3.9 /* If not a base or sky point, add distance from the
1149     viewcenter to average*/
1150     d = DIST(SM_NTH_WV(sm,s_id),SM_VIEW_CENTER(smMesh));
1151     smDist_sum += 1.0/d;
1152 gwlarson 3.1 }
1153 gwlarson 3.9 smInsert_samp(smMesh,s_id,t_id);
1154 gwlarson 3.5
1155 gwlarson 3.9 /* If new sample replaces existing one- remove that vertex now */
1156     if(r_id != INVALID)
1157     {
1158     smRemoveVertex(sm,r_id);
1159     sDelete_samp(SM_SAMP(sm),r_id);
1160     }
1161     return(s_id);
1162 gwlarson 3.1 }
1163    
1164     /*
1165     * int
1166     * smNewSamp(c, dir, p) : register new sample point and return index
1167     * COLR c; : pixel color (RGBE)
1168     * FVECT dir; : ray direction vector
1169     * FVECT p; : world intersection point
1170     *
1171     * Add new sample point to data structures, removing old values as necessary.
1172     * New sample representation will be output in next call to smUpdate().
1173     * If the point is a sky point: then v=NULL
1174     */
1175     int
1176     smNewSamp(c,dir,p)
1177     COLR c;
1178     FVECT dir;
1179     FVECT p;
1180     {
1181     int s_id;
1182 gwlarson 3.9
1183 gwlarson 3.1 /* First check if this the first sample: if so initialize mesh */
1184     if(SM_NUM_SAMP(smMesh) == 0)
1185 gwlarson 3.9 {
1186     smInit_sm(smMesh,odev.v.vp);
1187     sClear_all_flags(SM_SAMP(smMesh));
1188     }
1189     /* Add the sample to the mesh */
1190     s_id = smAdd_samp(smMesh,c,dir,p,INVALID);
1191 gwlarson 3.8
1192 gwlarson 3.1 return(s_id);
1193    
1194     }
1195     int
1196 gwlarson 3.8 smAdd_base_vertex(sm,v)
1197 gwlarson 3.1 SM *sm;
1198 gwlarson 3.8 FVECT v;
1199 gwlarson 3.1 {
1200     int id;
1201    
1202     /* First add coordinate to the sample array */
1203 gwlarson 3.8 id = sAdd_base_point(SM_SAMP(sm),v);
1204     if(id == INVALID)
1205     return(INVALID);
1206 gwlarson 3.1 /* Initialize triangle pointer to -1 */
1207     smClear_vert(sm,id);
1208     return(id);
1209     }
1210    
1211    
1212    
1213     /* Initialize a the point location DAG based on a 6 triangle tesselation
1214     of the unit sphere centered on the view center. The DAG structure
1215     contains 6 roots: one for each initial base triangle
1216     */
1217    
1218     int
1219     smCreate_base_mesh(sm,type)
1220     SM *sm;
1221     int type;
1222     {
1223 gwlarson 3.8 int i,s_id,tri_id,nbr_id;
1224 gwlarson 3.1 int p[4],ids[4];
1225     int v0_id,v1_id,v2_id;
1226 gwlarson 3.8 FVECT d,pt,cntr,v0,v1,v2;
1227 gwlarson 3.1
1228     /* First insert the base vertices into the sample point array */
1229    
1230     for(i=0; i < 4; i++)
1231     {
1232 gwlarson 3.8 VCOPY(cntr,smDefault_base[i]);
1233 gwlarson 3.5 cntr[0] += .01;
1234     cntr[1] += .02;
1235     cntr[2] += .03;
1236 gwlarson 3.6 VADD(cntr,cntr,SM_VIEW_CENTER(sm));
1237 gwlarson 3.8 p[i] = smAdd_base_vertex(sm,cntr);
1238 gwlarson 3.1 }
1239     /* Create the base triangles */
1240     for(i=0;i < 4; i++)
1241     {
1242 gwlarson 3.8 v0_id = p[smTri_verts[i][0]];
1243     v1_id = p[smTri_verts[i][1]];
1244     v2_id = p[smTri_verts[i][2]];
1245     ids[i] = smAdd_tri(sm, v0_id,v1_id,v2_id);
1246 gwlarson 3.7 smLocator_add_tri(sm,ids[i],v0_id,v1_id,v2_id,NULL);
1247 gwlarson 3.1 }
1248 gwlarson 3.8
1249 gwlarson 3.1 /* Set neighbors */
1250    
1251 gwlarson 3.5 for(tri_id=0;tri_id < 4; tri_id++)
1252 gwlarson 3.8 for(nbr_id=0; nbr_id < 3; nbr_id++)
1253     T_NTH_NBR(SM_NTH_TRI(sm,ids[tri_id]),nbr_id) = smBase_nbrs[tri_id][nbr_id];
1254 gwlarson 3.1
1255 gwlarson 3.8 /* Now add the centroids of the faces */
1256     for(tri_id=0;tri_id < 4; tri_id++)
1257     {
1258     VCOPY(v0,SM_T_NTH_WV(sm,SM_NTH_TRI(sm,ids[tri_id]),0));
1259     VCOPY(v1,SM_T_NTH_WV(sm,SM_NTH_TRI(sm,ids[tri_id]),1));
1260     VCOPY(v2,SM_T_NTH_WV(sm,SM_NTH_TRI(sm,ids[tri_id]),2));
1261     tri_centroid(v0,v1,v2,cntr);
1262     VSUB(cntr,cntr,SM_VIEW_CENTER(sm));
1263     normalize(cntr);
1264     VADD(cntr,cntr,SM_VIEW_CENTER(sm));
1265     s_id = smAdd_base_vertex(sm,cntr);
1266 gwlarson 3.9 smAdd_samp(sm,NULL,NULL,cntr,s_id);
1267 gwlarson 3.8 }
1268     return(1);
1269 gwlarson 3.1
1270     }
1271    
1272    
1273     int
1274     smNext_tri_flag_set(sm,i,which,b)
1275     SM *sm;
1276     int i,which;
1277 gwlarson 3.5 int b;
1278 gwlarson 3.1 {
1279    
1280 gwlarson 3.8 for(; i < SM_NUM_TRI(sm);i++)
1281 gwlarson 3.1 {
1282    
1283 gwlarson 3.8 if(!T_IS_VALID(SM_NTH_TRI(sm,i)))
1284 gwlarson 3.5 continue;
1285 gwlarson 3.8 if(!SM_IS_NTH_T_FLAG(sm,i,which))
1286     continue;
1287 gwlarson 3.1 if(!b)
1288     break;
1289     if((b==1) && !SM_BG_TRI(sm,i))
1290     break;
1291     if((b==2) && SM_BG_TRI(sm,i))
1292     break;
1293     }
1294    
1295     return(i);
1296     }
1297    
1298    
1299     int
1300     smNext_valid_tri(sm,i)
1301     SM *sm;
1302     int i;
1303     {
1304    
1305 gwlarson 3.8 while( i < SM_NUM_TRI(sm) && !T_IS_VALID(SM_NTH_TRI(sm,i)))
1306 gwlarson 3.1 i++;
1307    
1308     return(i);
1309     }
1310    
1311    
1312    
1313 gwlarson 3.8 qtTri_from_id(t_id,v0,v1,v2)
1314 gwlarson 3.1 int t_id;
1315     FVECT v0,v1,v2;
1316     {
1317     TRI *t;
1318    
1319     t = SM_NTH_TRI(smMesh,t_id);
1320 gwlarson 3.8 if(!T_IS_VALID(t))
1321     return(0);
1322     VSUB(v0,SM_T_NTH_WV(smMesh,t,0),SM_VIEW_CENTER(smMesh));
1323     VSUB(v1,SM_T_NTH_WV(smMesh,t,1),SM_VIEW_CENTER(smMesh));
1324     VSUB(v2,SM_T_NTH_WV(smMesh,t,2),SM_VIEW_CENTER(smMesh));
1325     return(1);
1326 gwlarson 3.1 }
1327    
1328    
1329 gwlarson 3.8 smRebuild_mesh(sm,v)
1330 gwlarson 3.1 SM *sm;
1331 gwlarson 3.8 VIEW *v;
1332 gwlarson 3.1 {
1333 gwlarson 3.8 int i,j,cnt;
1334     FVECT p,ov,dir;
1335     double d;
1336 gwlarson 3.1
1337 gwlarson 3.8 #ifdef DEBUG
1338     eputs("smRebuild_mesh(): rebuilding....");
1339     #endif
1340 gwlarson 3.1 /* Clear the mesh- and rebuild using the current sample array */
1341 gwlarson 3.8 /* Remember the current number of samples */
1342     cnt = SM_NUM_SAMP(sm);
1343     /* Calculate the difference between the current and new viewpoint*/
1344     /* Will need to subtract this off of sky points */
1345 gwlarson 3.9 VCOPY(ov,SM_VIEW_CENTER(sm));
1346 gwlarson 3.8 /* Initialize the mesh to 0 samples and the base triangles */
1347 gwlarson 3.1
1348 gwlarson 3.8 /* Go through all samples and add in if in the new view frustum, and
1349     the dir is <= 30 degrees from new view
1350     */
1351 gwlarson 3.9 smInit_sm(sm,v->vp);
1352 gwlarson 3.8 for(i=0; i < cnt; i++)
1353 gwlarson 3.1 {
1354 gwlarson 3.8 /* First check if sample visible(conservative approx: if one of tris
1355     attached to sample is in frustum) */
1356     if(!S_IS_FLAG(i))
1357     continue;
1358    
1359     /* Next test if direction > 30 from current direction */
1360     if(SM_NTH_W_DIR(sm,i)!=-1)
1361     {
1362     VSUB(p,SM_NTH_WV(sm,i),v->vp);
1363     normalize(p);
1364 gwlarson 3.9 decodedir(dir,SM_NTH_W_DIR(sm,i));
1365     d = 2. - 2.*DOT(dir,p);
1366 gwlarson 3.8 if (d > MAXDIFF2)
1367     continue;
1368 gwlarson 3.9 VCOPY(p,SM_NTH_WV(sm,i));
1369     smAdd_samp(sm,NULL,dir,p,i);
1370 gwlarson 3.8 }
1371 gwlarson 3.9 else
1372     {
1373     VSUB(dir,SM_NTH_WV(sm,i),ov);
1374     smAdd_samp(sm,NULL,dir,NULL,i);
1375     }
1376    
1377 gwlarson 3.1 }
1378 gwlarson 3.9 smNew_tri_cnt = SM_SAMPLE_TRIS(sm);
1379 gwlarson 3.8 #ifdef DEBUG
1380     eputs("smRebuild_mesh():done\n");
1381     #endif
1382 gwlarson 3.1 }
1383 gwlarson 3.5
1384     int
1385     intersect_tri_set(t_set,orig,dir,pt)
1386     OBJECT *t_set;
1387     FVECT orig,dir,pt;
1388     {
1389     OBJECT *optr;
1390     int i,t_id,id;
1391     int pid0,pid1,pid2;
1392     FVECT p0,p1,p2,p;
1393     TRI *t;
1394    
1395     optr = QT_SET_PTR(t_set);
1396     for(i = QT_SET_CNT(t_set); i > 0; i--)
1397     {
1398     t_id = QT_SET_NEXT_ELEM(optr);
1399 gwlarson 3.9 if(SM_IS_NTH_T_BASE(smMesh,t_id))
1400     continue;
1401 gwlarson 3.5 t = SM_NTH_TRI(smMesh,t_id);
1402 gwlarson 3.8 if(!T_IS_VALID(t))
1403     continue;
1404 gwlarson 3.5 pid0 = T_NTH_V(t,0);
1405     pid1 = T_NTH_V(t,1);
1406     pid2 = T_NTH_V(t,2);
1407     VCOPY(p0,SM_NTH_WV(smMesh,pid0));
1408     VCOPY(p1,SM_NTH_WV(smMesh,pid1));
1409     VCOPY(p2,SM_NTH_WV(smMesh,pid2));
1410     if(ray_intersect_tri(orig,dir,p0,p1,p2,p))
1411     {
1412     id = closest_point_in_tri(p0,p1,p2,p,pid0,pid1,pid2);
1413    
1414     if(pt)
1415     VCOPY(pt,p);
1416     #ifdef DEBUG_TEST_DRIVER
1417     Pick_tri = t_id;
1418     Pick_samp = id;
1419     VCOPY(Pick_point[0],p);
1420     #endif
1421     return(id);
1422     }
1423     }
1424     return(-1);
1425     }
1426    
1427 gwlarson 3.8 /* OS is constrained to be <= QT_MAXCSET : if the set exceeds this, the
1428     results of check_set are conservative
1429     */
1430    
1431     ray_trace_check_set(qtptr,fptr,argptr)
1432 gwlarson 3.5 QUADTREE *qtptr;
1433 gwlarson 3.8 int *fptr;
1434     RT_ARGS *argptr;
1435 gwlarson 3.5 {
1436 gwlarson 3.8 OBJECT tset[QT_MAXSET+1],*tptr;
1437 gwlarson 3.5 double dt,t;
1438     int found;
1439    
1440 gwlarson 3.8 if(QT_LEAF_IS_FLAG(*qtptr))
1441     {
1442     QT_FLAG_SET_DONE(*fptr);
1443     #if DEBUG
1444     eputs("ray_trace_check_set():Already visited this node:aborting\n");
1445     #endif
1446     return;
1447     }
1448 gwlarson 3.5 if(!QT_IS_EMPTY(*qtptr))
1449 gwlarson 3.8 {
1450     tptr = qtqueryset(*qtptr);
1451     if(QT_SET_CNT(tptr) > QT_MAXSET)
1452     tptr = (OBJECT *)malloc((QT_SET_CNT(tptr)+1)*sizeof(OBJECT));
1453     else
1454     tptr = tset;
1455     if(!tptr)
1456     goto memerr;
1457    
1458     qtgetset(tptr,*qtptr);
1459 gwlarson 3.5 /* Check triangles in set against those seen so far(os):only
1460     check new triangles for intersection (t_set')
1461     */
1462 gwlarson 3.8 check_set_large(tptr,argptr->os);
1463     if((found = intersect_tri_set(tptr,argptr->orig,argptr->dir,NULL))!= -1)
1464     {
1465     argptr->t_id = found;
1466     if(tptr != tset)
1467     free(tptr);
1468     QT_FLAG_SET_DONE(*fptr);
1469     return;
1470 gwlarson 3.5 }
1471 gwlarson 3.8 if(tptr != tset)
1472     free(tptr);
1473     }
1474     return;
1475     memerr:
1476     error(SYSTEM,"ray_trace_check_set():Unable to allocate memory");
1477 gwlarson 3.5 }
1478    
1479 gwlarson 3.8
1480     /*
1481     * int
1482     * smFindSamp(FVECT orig, FVECT dir)
1483     *
1484     * Find the closest sample to the given ray. Returns sample id, -1 on failure.
1485     * "dir" is assumed to be normalized
1486     */
1487    
1488 gwlarson 3.5 int
1489 gwlarson 3.6 smFindSamp(orig,dir)
1490 gwlarson 3.5 FVECT orig,dir;
1491     {
1492     FVECT b,p,o;
1493     OBJECT *ts;
1494     QUADTREE qt;
1495     int s_id;
1496     double d;
1497    
1498     /* r is the normalized vector from the view center to the current
1499     * ray point ( starting with "orig"). Find the cell that r falls in,
1500     * and test the ray against all triangles stored in the cell. If
1501     * the test fails, trace the projection of the ray across to the
1502     * next cell it intersects: iterate until either an intersection
1503     * is found, or the projection ray is // to the direction. The sample
1504     * corresponding to the triangle vertex closest to the intersection
1505     * point is returned.
1506     */
1507    
1508     /* First test if "orig" coincides with the View_center or if "dir" is
1509     parallel to r formed by projecting "orig" on the sphere. In
1510     either case, do a single test against the cell containing the
1511     intersection of "dir" and the sphere
1512     */
1513     /* orig will be updated-so preserve original value */
1514     if(!smMesh)
1515     return;
1516 gwlarson 3.9 #ifdef TEST_DRIVER
1517     Picking= TRUE;
1518     #endif
1519 gwlarson 3.5 point_on_sphere(b,orig,SM_VIEW_CENTER(smMesh));
1520     d = -DOT(b,dir);
1521     if(EQUAL_VEC3(orig,SM_VIEW_CENTER(smMesh)) || EQUAL(fabs(d),1.0))
1522     {
1523 gwlarson 3.8 qt = smPointLocateCell(smMesh,dir);
1524 gwlarson 3.5 /* Test triangles in the set for intersection with Ray:returns
1525     first found
1526     */
1527 gwlarson 3.8 #ifdef DEBUG
1528     if(QT_IS_EMPTY(qt))
1529     {
1530     eputs("smFindSamp(): point not found");
1531     return;
1532     }
1533     #endif
1534 gwlarson 3.5 ts = qtqueryset(qt);
1535     s_id = intersect_tri_set(ts,orig,dir,p);
1536     #ifdef DEBUG_TEST_DRIVER
1537     VCOPY(Pick_point[0],p);
1538     #endif
1539     }
1540     else
1541     {
1542 gwlarson 3.8 OBJECT t_set[QT_MAXCSET + 1];
1543     RT_ARGS rt;
1544    
1545 gwlarson 3.5 /* Test each of the root triangles against point id */
1546     QT_CLEAR_SET(t_set);
1547     VSUB(o,orig,SM_VIEW_CENTER(smMesh));
1548     ST_CLEAR_FLAGS(SM_LOCATOR(smMesh));
1549 gwlarson 3.8 rt.t_id = -1;
1550     rt.os = t_set;
1551     VCOPY(rt.orig,orig);
1552     VCOPY(rt.dir,dir);
1553     stTrace_ray(SM_LOCATOR(smMesh),o,dir,ray_trace_check_set,&rt);
1554     s_id = rt.t_id;
1555 gwlarson 3.5 }
1556     return(s_id);
1557     }
1558    
1559    
1560    
1561    
1562    
1563    
1564    
1565    
1566    
1567 gwlarson 3.1
1568