ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/sm_ogl.c
Revision: 3.1
Committed: Wed Aug 19 17:45:24 1998 UTC (25 years, 8 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Log Message:
Initial revision

File Contents

# Content
1 /* Copyright (c) 1998 Silicon Graphics, Inc. */
2
3 #ifndef lint
4 static char SCCSid[] = "$SunId$ SGI";
5 #endif
6
7 /*
8 * sm_ogl.c
9 */
10 #include "standard.h"
11
12 #include <GL/gl.h>
13
14 #ifdef TEST_DRIVER
15 #include <gl/device.h>
16 #include <GL/glu.h>
17 #include <glut.h>
18 #endif
19 #include "object.h"
20 #include "sm_geom.h"
21 #include "sm.h"
22
23 #ifdef TEST_DRIVER
24 #include "sm_draw.h"
25 /*static char smClean_notify = TRUE;
26 MAKE STATIC LATER: ui.c using for now;
27 */
28 char smClean_notify = TRUE;
29 #else
30 static char smClean_notify = TRUE;
31 #endif
32
33 int
34 mark_active_tris(qtptr,arg)
35 QUADTREE *qtptr;
36 char *arg;
37 {
38 OBJECT os[MAXSET+1],*optr;
39 int i,t_id;
40 SM *sm;
41
42
43 sm = (SM *)arg;
44
45 /* For each triangle in the set, set the which flag*/
46 if(QT_IS_EMPTY(*qtptr))
47 {
48 return(FALSE);
49 }
50 else
51 {
52 qtgetset(os,*qtptr);
53
54 for (i = QT_SET_CNT(os),optr = QT_SET_PTR(os); i > 0; i--)
55 {
56 t_id = QT_SET_NEXT_ELEM(optr);
57 /* Set the render flag */
58 if(SM_IS_NTH_T_BASE(sm,t_id))
59 continue;
60 SM_SET_NTH_T_ACTIVE(sm,t_id);
61 /* FOR NOW:Also set the LRU clock bit: MAY WANT TO CHANGE: */
62 SM_SET_NTH_T_LRU(sm,t_id);
63 }
64 }
65 return(TRUE);
66 }
67
68
69 smMark_tris_in_frustum(sm,vp)
70 SM *sm;
71 VIEW *vp;
72 {
73 FVECT nr[4],far[4];
74
75 /* Mark triangles in approx. view frustum as being active:set
76 LRU counter: for use in discarding samples when out
77 of space
78 Radiance often has no far clipping plane: but driver will set
79 dev_zmin,dev_zmax to satisfy OGL
80 */
81
82 /* First clear all the triangle active flags */
83 smClear_flags(sm,T_ACTIVE_FLAG);
84
85 /* calculate the world space coordinates of the view frustum */
86 calculate_view_frustum(vp->vp,vp->hvec,vp->vvec,vp->horiz,vp->vert,
87 dev_zmin,dev_zmax,nr,far);
88
89 /* Project the view frustum onto the spherical quadtree */
90 /* For every cell intersected by the projection of the faces
91 of the frustum: mark all triangles in the cell as ACTIVE-
92 Also set the triangles LRU clock counter
93 */
94 /* Need to do tonemap call */
95 /* Near face triangles */
96 smLocator_apply_func(sm,nr[0],nr[2],nr[3],mark_active_tris,(char *)(sm));
97 smLocator_apply_func(sm,nr[2],nr[0],nr[1],mark_active_tris,(char *)(sm));
98 /* Right face triangles */
99 smLocator_apply_func(sm,nr[0],far[3],far[0],mark_active_tris,(char *)(sm));
100 smLocator_apply_func(sm,far[3],nr[0],nr[3],mark_active_tris,(char *)(sm));
101 /* Left face triangles */
102 smLocator_apply_func(sm,nr[1],far[2],nr[2],mark_active_tris,(char *)(sm));
103 smLocator_apply_func(sm,far[2],nr[1],far[1],mark_active_tris,(char *)(sm));
104 /* Top face triangles */
105 smLocator_apply_func(sm,nr[0],far[0],nr[1],mark_active_tris,(char *)(sm));
106 smLocator_apply_func(sm,nr[1],far[0],far[1],mark_active_tris,(char *)(sm));
107 /* Bottom face triangles */
108 smLocator_apply_func(sm,nr[3],nr[2],far[3],mark_active_tris,(char *)(sm));
109 smLocator_apply_func(sm,nr[2],far[2],far[3],mark_active_tris,(char *)(sm));
110 /* Far face triangles */
111 smLocator_apply_func(sm,far[0],far[2],far[1],mark_active_tris,(char *)(sm));
112 smLocator_apply_func(sm,far[2],far[0],far[3],mark_active_tris,(char *)(sm));
113
114 #ifdef TEST_DRIVER
115 VCOPY(FrustumFar[0],far[0]);
116 VCOPY(FrustumFar[1],far[1]);
117 VCOPY(FrustumFar[2],far[2]);
118 VCOPY(FrustumFar[3],far[3]);
119 VCOPY(FrustumNear[0],nr[0]);
120 VCOPY(FrustumNear[1],nr[1]);
121 VCOPY(FrustumNear[2],nr[2]);
122 VCOPY(FrustumNear[3],nr[3]);
123 #endif
124 }
125
126 /*
127 * smClean() : display has been wiped clean
128 *
129 * Called after display has been effectively cleared, meaning that all
130 * geometry must be resent down the pipeline in the next call to smUpdate().
131 */
132 smClean()
133 {
134 /* Mark all triangles in the frustum as active */
135 if(!smMesh || SM_NUM_TRIS(smMesh)==0)
136 return;
137
138 #ifdef TEST_DRIVER
139 smMark_tris_in_frustum(smMesh,&Current_View);
140 #else
141 smMark_tris_in_frustum(smMesh,&(odev.v));
142 #endif
143 smClean_notify = TRUE;
144 }
145
146
147 smRender_tri(sm,i,vp)
148 SM *sm;
149 int i;
150 FVECT vp;
151 {
152 TRI *tri;
153 double ptr[3];
154 int j;
155
156 tri = SM_NTH_TRI(sm,i);
157 SM_CLEAR_NTH_T_NEW(sm,i);
158 if(smNew_tri_cnt)
159 smNew_tri_cnt--;
160 /* NOTE:Triangles are defined clockwise:historical relative to spherical
161 tris: could change
162 */
163 for(j=2; j>= 0; j--)
164 {
165 glColor3ub(SM_NTH_RGB(sm,T_NTH_V(tri,j))[0],
166 SM_NTH_RGB(sm,T_NTH_V(tri,j))[1],
167 SM_NTH_RGB(sm,T_NTH_V(tri,j))[2]);
168 VCOPY(ptr,SM_T_NTH_WV(sm,tri,j));
169 glVertex3d(ptr[0],ptr[1],ptr[2]);
170 }
171 }
172
173 /* NOTE SEEMS BAD TO PENALIZE POLYGONS INFRONT BY LETTING
174 ADJACENT TRIANGLES TO BG be BG
175 */
176 smRender_bg_tri(sm,i,vp)
177 SM *sm;
178 int i;
179 FVECT vp;
180 {
181 TRI *tri;
182 FVECT p;
183 int j,ids[3],cnt;
184 BYTE rgb[3];
185
186 tri = SM_NTH_TRI(sm,i);
187 SM_CLEAR_NTH_T_NEW(sm,i);
188 if(smNew_tri_cnt)
189 smNew_tri_cnt--;
190 /* NOTE:Triangles are defined clockwise:historical relative to spherical
191 tris: could change
192 */
193 cnt = 0;
194 rgb[0] = rgb[1] = rgb[2] = 0;
195 for(j=0;j<3;j++)
196 {
197 ids[j] = T_NTH_V(tri,j);
198 if(SM_BG_SAMPLE(sm,ids[j]))
199 {
200 rgb[0] += SM_NTH_RGB(sm,ids[j])[0];
201 rgb[1] += SM_NTH_RGB(sm,ids[j])[1];
202 rgb[2] += SM_NTH_RGB(sm,ids[j])[2];
203 cnt++;
204 }
205 }
206 if(cnt)
207 {
208 rgb[0]/=cnt; rgb[1]/=cnt; rgb[2]/=cnt;
209 }
210 for(j=2; j>= 0; j--)
211 {
212 if(SM_BG_SAMPLE(sm,ids[j]))
213 glColor3ub(SM_NTH_RGB(sm,ids[j])[0],SM_NTH_RGB(sm,ids[j])[1],
214 SM_NTH_RGB(sm,ids[j])[2]);
215 else
216 glColor3ub(rgb[0],rgb[1],rgb[2]);
217 VSUB(p,SM_NTH_WV(sm,ids[j]),SM_VIEW_CENTER(sm));
218 VADD(p,p,vp);
219 glVertex3d(p[0],p[1],p[2]);
220 }
221 }
222
223 smRender_mesh(sm,vp)
224 SM *sm;
225 FVECT vp;
226 {
227 int i;
228 TRI *tri;
229 double ptr[3];
230 int j;
231
232 glPushAttrib(GL_DEPTH_BUFFER_BIT);
233
234 /* First draw background polygons */
235 glDisable(GL_DEPTH_TEST);
236 glBegin(GL_TRIANGLES);
237 SM_FOR_ALL_ACTIVE_BG_TRIS(sm,i)
238 smRender_bg_tri(sm,i,vp);
239 glEnd();
240
241 glEnable(GL_DEPTH_TEST);
242 glBegin(GL_TRIANGLES);
243 SM_FOR_ALL_ACTIVE_FG_TRIS(sm,i)
244 smRender_tri(sm,i,vp);
245 glEnd();
246
247 glPopAttrib();
248 }
249 smRender_tri_edges(sm,i)
250 SM *sm;
251 int i;
252 {
253 TRI *tri;
254 int j;
255 double ptr[3];
256
257
258 tri = SM_NTH_TRI(sm,i);
259
260 /* Triangles are defined clockwise:historical relative to spherical
261 tris: could change
262 */
263 for(j=2; j >=0; j--)
264 {
265 VCOPY(ptr,SM_NTH_WV(sm,T_NTH_V(tri,j)));
266 glVertex3d(ptr[0],ptr[1],ptr[2]);
267 VCOPY(ptr,SM_NTH_WV(sm,T_NTH_V(tri,(j+1)%3)));
268 glVertex3d(ptr[0],ptr[1],ptr[2]);
269 }
270 }
271
272 int
273 compare_tri_depths(T_DEPTH *td1,T_DEPTH *td2)
274 {
275 double d;
276
277 d = td2->depth-td1->depth;
278
279 if(d > 0.0)
280 return(1);
281 if(d < 0.0)
282 return(-1);
283
284 return(0);
285 }
286
287 smDepth_sort_tris(sm,vp,td)
288 SM *sm;
289 VIEW *vp;
290 T_DEPTH *td;
291 {
292 int i,j,t_id;
293 TRI *tri;
294 double d[3];
295
296 i = 0;
297 SM_FOR_ALL_NEW_TRIS(sm,t_id)
298 {
299 if(i >= smNew_tri_cnt)
300 {
301 #ifdef DEBUG
302 eputs("smDepth_sort_tris(): more new tris then counted\n");
303 #endif
304 break;
305 }
306 tri = SM_NTH_TRI(sm,t_id);
307 td[i].tri = t_id;
308 for(j=0;j < 3;j++)
309 d[j] = DIST(vp->vp,SM_T_NTH_WV(sm,tri,j));
310 td[i].depth = MIN_VEC3(d);
311 i++;
312 }
313 qsort((void *)td,smNew_tri_cnt,sizeof(T_DEPTH),compare_tri_depths);
314 }
315
316
317 smUpdate_Rendered_mesh(sm,vp)
318 SM *sm;
319 VIEW *vp;
320 {
321 static T_DEPTH *td= NULL;
322 static int tsize = 0;
323 int i;
324 GLint depth_test;
325
326 /* For all of the NEW triangles (since last update): assume
327 ACTIVE. Go through and sort on depth value (from vp). Turn
328 Depth Buffer test off and render back-front
329 */
330 /* NOTE: could malloc each time or hard code */
331 if(smNew_tri_cnt > tsize)
332 {
333 if(td)
334 free(td);
335 td = (T_DEPTH *)malloc(smNew_tri_cnt*sizeof(T_DEPTH));
336 tsize = smNew_tri_cnt;
337 }
338 if(!td)
339 {
340 error(SYSTEM,"smUpdate_Rendered_mesh:Cannot allocate memory\n");
341 }
342 smDepth_sort_tris(sm,vp,td);
343
344 /* Turn Depth Test off */
345 glPushAttrib(GL_DEPTH_BUFFER_BIT);
346 glDepthFunc(GL_ALWAYS); /* Turn off Depth-painter's algorithm */
347
348 /* Now render back-to front */
349 /* First render bg triangles */
350 glDisable(GL_DEPTH_TEST);
351 glBegin(GL_TRIANGLES);
352 for(i=0; i< smNew_tri_cnt; i++)
353 if(SM_BG_TRI(sm,td[i].tri))
354 smRender_bg_tri(sm,td[i].tri,vp);
355 glEnd();
356
357 glEnable(GL_DEPTH_TEST);
358 glBegin(GL_TRIANGLES);
359 for(i=0; i< smNew_tri_cnt; i++)
360 if(!SM_BG_TRI(sm,td[i].tri))
361 smRender_tri(sm,td[i].tri,vp);
362 glEnd();
363
364 /* Restore Depth Test */
365 glPopAttrib();
366 }
367
368 /*
369 * smUpdate(vp, qua) : update OpenGL output geometry for view vp
370 * VIEW *vp; : desired view
371 * int qual; : quality level (percentage on linear time scale)
372 *
373 * Draw new geometric representation using OpenGL calls. Assume that the
374 * view has already been set up and the correct frame buffer has been
375 * selected for drawing. The quality level is on a linear scale, where 100%
376 * is full (final) quality. It is not necessary to redraw geometry that has
377 * been output since the last call to smClean().
378 */
379 smUpdate(vp,qual)
380 VIEW *vp;
381 int qual;
382 {
383 double d;
384 int t;
385 #ifdef TEST_DRIVER
386 Current_View = (*vp);
387 #endif
388 /* If view has moved beyond epsilon from canonical: must rebuild -
389 epsilon is calculated as running avg of distance of sample points
390 from canonical view: m = 1/(SUM1/r): some fraction of this
391 */
392 d = DIST(vp->vp,SM_VIEW_CENTER(smMesh));
393 if(qual >= 100 && d > SM_ALLOWED_VIEW_CHANGE(smMesh))
394 {
395 smNew_tri_cnt = 0;
396 /* Re-build the mesh */
397 smRebuild_mesh(smMesh,vp);
398 }
399 /* Check if should draw ALL triangles in current frustum */
400 if(smClean_notify || (smNew_tri_cnt > SM_NUM_TRIS(smMesh)*SM_INC_PERCENT))
401 {
402 #ifdef TEST_DRIVER
403 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
404 #else
405 tmClearHisto();
406 tmAddHisto(SM_BRT(smMesh),SM_NUM_SAMP(smMesh),1);
407 if(tmComputeMapping(0.,0.,0.) != TM_E_OK)
408 return;
409 if(tmMapPixels(SM_RGB(smMesh),SM_BRT(smMesh),SM_CHR(smMesh),
410 SM_NUM_SAMP(smMesh))!=TM_E_OK)
411 return;
412 #endif
413 smRender_mesh(smMesh,vp->vp);
414 smClean_notify = FALSE;
415 #ifdef TEST_DRIVER
416 glFlush();
417 glutSwapBuffers();
418 #endif
419 }
420 /* Do an incremental update instead */
421 else
422 {
423 if(!smNew_tri_cnt)
424 return;
425 #ifdef TEST_DRIVER
426 glDrawBuffer(GL_FRONT);
427 #else
428 t = SM_TONE_MAP(smMesh);
429 if(t == 0)
430 {
431 tmClearHisto();
432 tmAddHisto(SM_BRT(smMesh),SM_NUM_SAMP(smMesh),1);
433 if(tmComputeMapping(0.,0.,0.) != TM_E_OK)
434 return;
435 }
436 if(tmMapPixels(SM_NTH_RGB(smMesh,t),&SM_NTH_BRT(smMesh,t),
437 SM_NTH_CHR(smMesh,t), SM_NUM_SAMP(smMesh)-t) != TM_E_OK)
438 return;
439 #endif
440 smUpdate_Rendered_mesh(smMesh,vp);
441
442 #ifdef TEST_DRIVER
443 glDrawBuffer(GL_BACK);
444 #endif
445 }
446 SM_TONE_MAP(smMesh) = SM_NUM_SAMP(smMesh);
447 }
448
449 /* LATER:If quality < 100 should draw approximation because it indicates
450 the user is moving
451 */
452
453