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

# Content
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 #include "sm_flag.h"
12 #include "sm_list.h"
13 #include "sm_geom.h"
14 #include "sm_qtree.h"
15 #include "sm_stree.h"
16 #include "sm.h"
17
18
19 SM *smMesh = NULL;
20 double smDist_sum=0;
21 int smNew_tri_cnt=0;
22 double smMinSampDiff = 1.7e-3; /* min edge length in radians */
23
24 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 static int smTri_verts[4][3] = { {0,1,2},{0,2,3},{0,3,1},{1,3,2}};
29
30 static int smBase_nbrs[4][3] = { {3,1,2},{3,2,0},{3,0,1},{1,0,2}};
31
32 #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 int Pick_tri = -1,Picking = FALSE,Pick_samp=-1;
36 FVECT Pick_point[500],Pick_origin,Pick_dir;
37 FVECT Pick_v0[500], Pick_v1[500], Pick_v2[500];
38 int Pick_q[500];
39 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 VSUB(ps,SM_NTH_WV(sm,id),SM_VIEW_CENTER(sm));
50 normalize(ps);
51 }
52
53 smDir_in_cone(sm,ps,id)
54 SM *sm;
55 FVECT ps;
56 int id;
57 {
58
59 VSUB(ps,SM_NTH_WV(sm,id),SM_VIEW_CENTER(sm));
60 normalize(ps);
61 }
62
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 bzero(SM_NTH_FLAGS(sm,i),FLAG_BYTES(SM_MAX_TRIS(sm)));
72 else
73 bzero(SM_NTH_FLAGS(sm,which),FLAG_BYTES(SM_MAX_TRIS(sm)));
74 }
75
76 /* Given an allocated mesh- initialize */
77 smInit_mesh(sm)
78 SM *sm;
79 {
80 /* 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 }
86
87
88 /* Clear the SM for reuse: free any extra allocated memory:does initialization
89 as well
90 */
91 smClear(sm)
92 SM *sm;
93 {
94 smClear_samples(sm);
95 smClear_locator(sm);
96 smInit_mesh(sm);
97 }
98
99 static int realloc_cnt=0;
100
101 int
102 smRealloc_mesh(sm)
103 SM *sm;
104 {
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 int max_verts,max_tris;
132 {
133 int fbytes,i;
134
135 fbytes = FLAG_BYTES(max_tris);
136
137 if(!(SM_TRIS(sm) = (TRI *)realloc(NULL,max_tris*sizeof(TRI))))
138 goto memerr;
139
140 if(!(SM_VERTS(sm) = (VERT *)realloc(NULL,max_verts*sizeof(VERT))))
141 goto memerr;
142
143 for(i=0; i< T_FLAGS; i++)
144 if(!(SM_NTH_FLAGS(sm,i)=(int4 *)realloc(NULL,fbytes)))
145 goto memerr;
146
147 SM_MAX_VERTS(sm) = max_verts;
148 SM_MAX_TRIS(sm) = max_tris;
149
150 realloc_cnt = max_verts >> 1;
151
152 smInit_mesh(sm);
153
154 return(max_tris);
155 memerr:
156 error(SYSTEM, "out of memory in smAlloc_mesh()");
157 }
158
159
160 int
161 smAlloc_tri(sm)
162 SM *sm;
163 {
164 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 }
181
182 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 /* 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 int max_tris,n;
205
206 n = max_samples;
207 /* If this is the first call, allocate sample,vertex and triangle lists */
208 if(!smMesh)
209 {
210 if(!(smMesh = (SM *)malloc(sizeof(SM))))
211 error(SYSTEM,"smAlloc():Unable to allocate memory\n");
212 bzero(smMesh,sizeof(SM));
213 }
214 else
215 { /* If existing structure: first deallocate */
216 smFree_mesh(smMesh);
217 smFree_samples(smMesh);
218 smFree_locator(smMesh);
219 }
220
221 /* First allocate at least n samples + extra points:at least enough
222 necessary to form the BASE MESH- Default = 4;
223 */
224 SM_SAMP(smMesh) = sAlloc(&n,SM_EXTRA_POINTS);
225
226 total_points = n + SM_EXTRA_POINTS;
227
228 max_tris = total_points*4;
229 /* Now allocate space for mesh vertices and triangles */
230 max_tris = smAlloc_mesh(smMesh, total_points, max_tris);
231
232 /* Initialize the structure for point,triangle location.
233 */
234 smAlloc_locator(smMesh);
235 }
236
237
238
239 smInit_sm(sm,vp)
240 SM *sm;
241 FVECT vp;
242 {
243
244 smDist_sum = 0;
245 smNew_tri_cnt = 0;
246
247 VCOPY(SM_VIEW_CENTER(sm),vp);
248 smInit_locator(sm,vp);
249 smInit_samples(sm);
250 smInit_mesh(sm);
251 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
272 /* 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 if(smMesh && (max_vertices <= SM_MAX_VERTS(smMesh)) && SM_MAX_SAMP(smMesh) <=
286 n && SM_MAX_POINTS(smMesh) <= max_vertices)
287 {
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 smLocator_apply_func(sm,v0,v1,v2,edge_func,tri_func,argptr)
301 SM *sm;
302 FVECT v0,v1,v2;
303 int (*edge_func)();
304 int (*tri_func)();
305 int *argptr;
306 {
307 STREE *st;
308 FVECT p0,p1,p2;
309
310 st = SM_LOCATOR(sm);
311
312 VSUB(p0,v0,SM_VIEW_CENTER(sm));
313 VSUB(p1,v1,SM_VIEW_CENTER(sm));
314 VSUB(p2,v2,SM_VIEW_CENTER(sm));
315
316 stApply_to_tri(st,p0,p1,p2,edge_func,tri_func,argptr);
317
318 }
319
320 QUADTREE
321 delete_tri_set(qt,optr,del_set)
322 QUADTREE qt;
323 OBJECT *optr,*del_set;
324 {
325
326 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 QUADTREE *qtptr;
408 int *f;
409 ADD_ARGS *argptr;
410 FVECT q0,q1,q2;
411 FVECT t0,t1,t2;
412 int n;
413 {
414 int t_id;
415 OBJECT *optr,*del_set;
416
417 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 optr = qtqueryset(*qtptr);
427
428 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 }
439
440
441
442 add_tri(qtptr,fptr,argptr)
443 QUADTREE *qtptr;
444 int *fptr;
445 ADD_ARGS *argptr;
446 {
447
448 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 {
471 optr = qtqueryset(*qtptr);
472 if(QT_SET_CNT(optr) >= QT_SET_THRESHOLD)
473 (*fptr) |= QT_EXPAND;
474 }
475 if(!QT_FLAG_FILL_TRI(*fptr))
476 (*fptr)++;
477 *qtptr = qtaddelem(*qtptr,t_id);
478
479 }
480
481
482 smLocator_add_tri(sm,t_id,v0_id,v1_id,v2_id,del_set)
483 SM *sm;
484 int t_id;
485 int v0_id,v1_id,v2_id;
486 OBJECT *del_set;
487 {
488 STREE *st;
489 FVECT v0,v1,v2;
490 ADD_ARGS args;
491
492 st = SM_LOCATOR(sm);
493
494 #ifdef DEBUG
495 if((v0_id == INVALID) || (v1_id == INVALID) || (v2_id == INVALID))
496 error(CONSISTENCY,"Invalid ids 1\n");
497 #endif
498
499 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
503 qtClearAllFlags();
504 args.t_id = t_id;
505 args.del_set = del_set;
506
507 stApply_to_tri(st,v0,v1,v2,add_tri,add_tri_expand,&args);
508
509 }
510
511 /* Add a triangle to the base array with vertices v1-v2-v3 */
512 int
513 smAdd_tri(sm, v0_id,v1_id,v2_id)
514 SM *sm;
515 int v0_id,v1_id,v2_id;
516 {
517 int t_id;
518 TRI *t;
519 #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 t_id = smAlloc_tri(sm);
527
528 if(t_id == -1)
529 return(t_id);
530
531 t = SM_NTH_TRI(sm,t_id);
532
533 T_CLEAR_NBRS(t);
534 /* 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
539 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 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 SM_CLR_NTH_T_BASE(sm,t_id);
551 SM_SET_NTH_T_ACTIVE(sm,t_id);
552 SM_SET_NTH_T_NEW(sm,t_id);
553 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 smNew_tri_cnt++;
558 }
559
560 /* return initialized triangle */
561 return(t_id);
562 }
563
564
565 void
566 smTris_swap_edge(sm,t_id,t1_id,e,e1,tn_id,tn1_id,add_ptr,delptr)
567 SM *sm;
568 int t_id,t1_id;
569 int e,e1;
570 int *tn_id,*tn1_id;
571 LIST **add_ptr;
572 QUADTREE *delptr;
573
574 {
575 int verts[3],enext,eprev,e1next,e1prev;
576 TRI *n,*ta,*tb,*t,*t1;
577 FVECT p1,p2,p3;
578 int ta_id,tb_id;
579 /* 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 */
582 enext = (e+1)%3;
583 eprev = (e+2)%3;
584 e1next = (e1+1)%3;
585 e1prev = (e1+2)%3;
586 verts[e] = T_NTH_V(SM_NTH_TRI(sm,t_id),e);
587 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 ta_id = smAdd_tri(sm,verts[0],verts[1],verts[2]);
590 *add_ptr = push_data(*add_ptr,ta_id);
591 verts[e1] = T_NTH_V(SM_NTH_TRI(sm,t1_id),e1);
592 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 tb_id = smAdd_tri(sm,verts[0],verts[1],verts[2]);
595 *add_ptr = push_data(*add_ptr,tb_id);
596
597 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 /* set the neighbors */
602 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
609 /* Reset neighbor pointers of original neighbors */
610 n = SM_NTH_TRI(sm,T_NTH_NBR(t,enext));
611 T_NTH_NBR(n,T_NTH_NBR_PTR(t_id,n)) = tb_id;
612 n = SM_NTH_TRI(sm,T_NTH_NBR(t,eprev));
613 T_NTH_NBR(n,T_NTH_NBR_PTR(t_id,n)) = ta_id;
614
615 n = SM_NTH_TRI(sm,T_NTH_NBR(t1,e1next));
616 T_NTH_NBR(n,T_NTH_NBR_PTR(t1_id,n)) = ta_id;
617 n = SM_NTH_TRI(sm,T_NTH_NBR(t1,e1prev));
618 T_NTH_NBR(n,T_NTH_NBR_PTR(t1_id,n)) = tb_id;
619
620 /* Delete two parent triangles */
621 if(remove_from_list(t_id,add_ptr))
622 smDelete_tri(sm,t_id);
623 else
624 *delptr = qtaddelem(*delptr,t_id);
625
626 if(remove_from_list(t1_id,add_ptr))
627 smDelete_tri(sm,t1_id);
628 else
629 *delptr = qtaddelem(*delptr,t1_id);
630
631 *tn_id = ta_id;
632 *tn1_id = tb_id;
633 }
634
635 smUpdate_locator(sm,add_list,del_set)
636 SM *sm;
637 LIST *add_list;
638 OBJECT *del_set;
639 {
640 int t_id,i;
641 TRI *t;
642 OBJECT *optr;
643
644 while(add_list)
645 {
646 t_id = pop_list(&add_list);
647 t = SM_NTH_TRI(sm,t_id);
648 smLocator_add_tri(sm,t_id,T_NTH_V(t,0),T_NTH_V(t,1),T_NTH_V(t,2),del_set);
649 }
650
651 optr = QT_SET_PTR(del_set);
652 for(i = QT_SET_CNT(del_set); i > 0; i--)
653 {
654 t_id = QT_SET_NEXT_ELEM(optr);
655 #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 smDelete_tri(sm,t_id);
660 }
661 }
662 /* MUST add check for constrained edges */
663 int
664 smFix_tris(sm,id,tlist,add_list,delptr)
665 SM *sm;
666 int id;
667 LIST *tlist,*add_list;
668 QUADTREE *delptr;
669 {
670 TRI *t,*t_opp;
671 FVECT p,p0,p1,p2;
672 int e,e1,swapped = 0;
673 int t_id,t_opp_id;
674
675 VSUB(p,SM_NTH_WV(sm,id),SM_VIEW_CENTER(sm));
676 while(tlist)
677 {
678 t_id = pop_list(&tlist);
679 #ifdef DEBUG
680 if(t_id==INVALID || t_id > smMesh->num_tri)
681 error(CONSISTENCY,"Invalid tri id smFix_tris()\n");
682 #endif
683 t = SM_NTH_TRI(sm,t_id);
684 e = T_WHICH_V(t,id);
685 t_opp_id = T_NTH_NBR(t,e);
686 #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 {
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 smTris_swap_edge(sm,t_id,t_opp_id,e,e1,&t_id,&t_opp_id,
702 &add_list,delptr);
703 tlist = push_data(tlist,t_id);
704 tlist = push_data(tlist,t_opp_id);
705 }
706 }
707 smUpdate_locator(sm,add_list,qtqueryset(*delptr));
708 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 int nbr_id;
722
723 /* Want the edge for which "id" is the destination */
724 t_id = (T_WHICH_V(t,id)+ 1)% 3;
725 nbr_id = T_NTH_NBR(t,t_id);
726 return(nbr_id);
727 }
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 SM_CLR_NTH_T_FLAG(sm,id,i);
737
738 }
739
740 /* Locate the point-id in the point location structure: */
741 int
742 smInsert_samp(sm,s_id,tri_id)
743 SM *sm;
744 int s_id,tri_id;
745 {
746 int v0_id,v1_id,v2_id;
747 int t0_id,t1_id,t2_id,replaced;
748 LIST *tlist,*add_list;
749 OBJECT del_set[2];
750 QUADTREE delnode;
751 FVECT npt;
752 TRI *tri,*nbr;
753
754 add_list = NULL;
755
756 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 /* Add triangle to the locator */
762
763 add_list = push_data(add_list,t0_id);
764
765 t1_id = smAdd_tri(sm,s_id,v1_id,v2_id);
766 add_list = push_data(add_list,t1_id);
767
768 t2_id = smAdd_tri(sm,s_id,v2_id,v0_id);
769 add_list = push_data(add_list,t2_id);
770
771 /* CAUTION: tri must be assigned after Add_tri: pointers may change*/
772 tri = SM_NTH_TRI(sm,tri_id);
773
774 /* Set the neighbor pointers for the new tris */
775 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
785 /* Reset the neigbor pointers for the neighbors of the original */
786 nbr = SM_NTH_TRI(sm,T_NTH_NBR(tri,0));
787 T_NTH_NBR(nbr,T_NTH_NBR_PTR(tri_id,nbr)) = t1_id;
788 nbr = SM_NTH_TRI(sm,T_NTH_NBR(tri,1));
789 T_NTH_NBR(nbr,T_NTH_NBR_PTR(tri_id,nbr)) = t2_id;
790 nbr = SM_NTH_TRI(sm,T_NTH_NBR(tri,2));
791 T_NTH_NBR(nbr,T_NTH_NBR_PTR(tri_id,nbr)) = t0_id;
792
793 del_set[0] = 1; del_set[1] = tri_id;
794 delnode = qtnewleaf(del_set);
795
796 /* 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 smFix_tris(sm,s_id,tlist,add_list,&delnode);
802
803 qtfreeleaf(delnode);
804
805 return(TRUE);
806 }
807
808
809 int
810 smTri_in_set(sm,p,optr)
811 SM *sm;
812 FVECT p;
813 OBJECT *optr;
814 {
815 int i,t_id;
816 FVECT n,v0,v1,v2;
817 TRI *t;
818
819 for (i = QT_SET_CNT(optr),optr = QT_SET_PTR(optr);i > 0; i--)
820 {
821 /* 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 VCROSS(n,v0,v1);
834 if(DOT(n,p) >0.0)
835 continue;
836 VCROSS(n,v1,v2);
837 if(DOT(n,p) > 0.0)
838 continue;
839
840 VCROSS(n,v2,v0);
841 if(DOT(n,p) > 0.0)
842 continue;
843
844 return(t_id);
845 }
846 return(INVALID);
847 }
848
849 int
850 smPointLocateTri(sm,p)
851 SM *sm;
852 FVECT p;
853 {
854 QUADTREE qt,*optr;
855 FVECT tpt;
856
857 VSUB(tpt,p,SM_VIEW_CENTER(sm));
858 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
866
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 smTest_sample(sm,tri_id,c,dir,p,o_id,rptr)
900 SM *sm;
901 int tri_id;
902 COLR c;
903 FVECT dir,p;
904 int o_id;
905 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 int tonemap;
912
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 if(FZERO_VEC3(diff[i]))
935 {
936 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 }
940 }
941 if(!dir)
942 return(TRUE);
943 /* 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 d2 = 2. - 2.*DOT(dir,spt);
975 /* 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 /* 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
1056 return(FALSE);
1057 }
1058
1059
1060 int
1061 smAlloc_samp(sm,c,dir,pt,o_id)
1062 SM *sm;
1063 COLR c;
1064 FVECT dir,pt;
1065 int o_id;
1066 {
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 {
1077 if(smRemoveVertex(sm,s_id))
1078 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
1085 /* 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 return(s_id);
1092 }
1093
1094 int
1095 smAdd_samp(sm,c,dir,p,o_id)
1096 SM *sm;
1097 COLR c;
1098 FVECT dir,p;
1099 int o_id;
1100 {
1101 int t_id,s_id,r_id;
1102 double d;
1103 FVECT wpt;
1104
1105 r_id = INVALID;
1106 /* If sample is a world space point */
1107 if(p)
1108 {
1109 t_id = smPointLocateTri(sm,p);
1110 if(t_id == INVALID)
1111 {
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 {
1120 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 #ifdef DEBUG
1136 eputs("smAddSamp(): unable to locate tri containing sample \n");
1137 #endif
1138 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 }
1146 if(!SM_BASE_ID(sm,s_id) && !SM_DIR_ID(sm,s_id))
1147 {
1148 /* 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 }
1153 smInsert_samp(smMesh,s_id,t_id);
1154
1155 /* 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 }
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
1183 /* First check if this the first sample: if so initialize mesh */
1184 if(SM_NUM_SAMP(smMesh) == 0)
1185 {
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
1192 return(s_id);
1193
1194 }
1195 int
1196 smAdd_base_vertex(sm,v)
1197 SM *sm;
1198 FVECT v;
1199 {
1200 int id;
1201
1202 /* First add coordinate to the sample array */
1203 id = sAdd_base_point(SM_SAMP(sm),v);
1204 if(id == INVALID)
1205 return(INVALID);
1206 /* 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 int i,s_id,tri_id,nbr_id;
1224 int p[4],ids[4];
1225 int v0_id,v1_id,v2_id;
1226 FVECT d,pt,cntr,v0,v1,v2;
1227
1228 /* First insert the base vertices into the sample point array */
1229
1230 for(i=0; i < 4; i++)
1231 {
1232 VCOPY(cntr,smDefault_base[i]);
1233 cntr[0] += .01;
1234 cntr[1] += .02;
1235 cntr[2] += .03;
1236 VADD(cntr,cntr,SM_VIEW_CENTER(sm));
1237 p[i] = smAdd_base_vertex(sm,cntr);
1238 }
1239 /* Create the base triangles */
1240 for(i=0;i < 4; i++)
1241 {
1242 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 smLocator_add_tri(sm,ids[i],v0_id,v1_id,v2_id,NULL);
1247 }
1248
1249 /* Set neighbors */
1250
1251 for(tri_id=0;tri_id < 4; tri_id++)
1252 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
1255 /* 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 smAdd_samp(sm,NULL,NULL,cntr,s_id);
1267 }
1268 return(1);
1269
1270 }
1271
1272
1273 int
1274 smNext_tri_flag_set(sm,i,which,b)
1275 SM *sm;
1276 int i,which;
1277 int b;
1278 {
1279
1280 for(; i < SM_NUM_TRI(sm);i++)
1281 {
1282
1283 if(!T_IS_VALID(SM_NTH_TRI(sm,i)))
1284 continue;
1285 if(!SM_IS_NTH_T_FLAG(sm,i,which))
1286 continue;
1287 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 while( i < SM_NUM_TRI(sm) && !T_IS_VALID(SM_NTH_TRI(sm,i)))
1306 i++;
1307
1308 return(i);
1309 }
1310
1311
1312
1313 qtTri_from_id(t_id,v0,v1,v2)
1314 int t_id;
1315 FVECT v0,v1,v2;
1316 {
1317 TRI *t;
1318
1319 t = SM_NTH_TRI(smMesh,t_id);
1320 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 }
1327
1328
1329 smRebuild_mesh(sm,v)
1330 SM *sm;
1331 VIEW *v;
1332 {
1333 int i,j,cnt;
1334 FVECT p,ov,dir;
1335 double d;
1336
1337 #ifdef DEBUG
1338 eputs("smRebuild_mesh(): rebuilding....");
1339 #endif
1340 /* Clear the mesh- and rebuild using the current sample array */
1341 /* 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 VCOPY(ov,SM_VIEW_CENTER(sm));
1346 /* Initialize the mesh to 0 samples and the base triangles */
1347
1348 /* 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 smInit_sm(sm,v->vp);
1352 for(i=0; i < cnt; i++)
1353 {
1354 /* 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 decodedir(dir,SM_NTH_W_DIR(sm,i));
1365 d = 2. - 2.*DOT(dir,p);
1366 if (d > MAXDIFF2)
1367 continue;
1368 VCOPY(p,SM_NTH_WV(sm,i));
1369 smAdd_samp(sm,NULL,dir,p,i);
1370 }
1371 else
1372 {
1373 VSUB(dir,SM_NTH_WV(sm,i),ov);
1374 smAdd_samp(sm,NULL,dir,NULL,i);
1375 }
1376
1377 }
1378 smNew_tri_cnt = SM_SAMPLE_TRIS(sm);
1379 #ifdef DEBUG
1380 eputs("smRebuild_mesh():done\n");
1381 #endif
1382 }
1383
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 if(SM_IS_NTH_T_BASE(smMesh,t_id))
1400 continue;
1401 t = SM_NTH_TRI(smMesh,t_id);
1402 if(!T_IS_VALID(t))
1403 continue;
1404 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 /* 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 QUADTREE *qtptr;
1433 int *fptr;
1434 RT_ARGS *argptr;
1435 {
1436 OBJECT tset[QT_MAXSET+1],*tptr;
1437 double dt,t;
1438 int found;
1439
1440 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 if(!QT_IS_EMPTY(*qtptr))
1449 {
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 /* Check triangles in set against those seen so far(os):only
1460 check new triangles for intersection (t_set')
1461 */
1462 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 }
1471 if(tptr != tset)
1472 free(tptr);
1473 }
1474 return;
1475 memerr:
1476 error(SYSTEM,"ray_trace_check_set():Unable to allocate memory");
1477 }
1478
1479
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 int
1489 smFindSamp(orig,dir)
1490 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 #ifdef TEST_DRIVER
1517 Picking= TRUE;
1518 #endif
1519 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 qt = smPointLocateCell(smMesh,dir);
1524 /* Test triangles in the set for intersection with Ray:returns
1525 first found
1526 */
1527 #ifdef DEBUG
1528 if(QT_IS_EMPTY(qt))
1529 {
1530 eputs("smFindSamp(): point not found");
1531 return;
1532 }
1533 #endif
1534 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 OBJECT t_set[QT_MAXCSET + 1];
1543 RT_ARGS rt;
1544
1545 /* 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 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 }
1556 return(s_id);
1557 }
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568