ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/gen/mkillum2.c
Revision: 2.19
Committed: Tue Sep 18 03:35:09 2007 UTC (17 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.18: +5 -5 lines
Log Message:
Corrected calls from o_default() to my_default()

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: mkillum2.c,v 2.18 2007/09/13 06:31:21 greg Exp $";
3 #endif
4 /*
5 * Routines to do the actual calculation for mkillum
6 */
7
8 #include <string.h>
9
10 #include "mkillum.h"
11 #include "face.h"
12 #include "cone.h"
13 #include "random.h"
14
15
16 static void mkaxes(FVECT u, FVECT v, FVECT n);
17 static void rounddir(FVECT dv, double alt, double azi);
18 static void flatdir(FVECT dv, double alt, double azi);
19
20
21 static COLORV * distarr = NULL; /* distribution array */
22 static int distsiz = 0;
23
24
25 static void
26 newdist( /* allocate & clear distribution array */
27 int siz
28 )
29 {
30 if (siz == 0) {
31 if (distsiz > 0)
32 free((void *)distarr);
33 distarr = NULL;
34 distsiz = 0;
35 return;
36 }
37 if (distsiz < siz) {
38 free((void *)distarr);
39 distarr = (COLORV *)malloc(sizeof(COLORV)*3*siz);
40 if (distarr == NULL)
41 error(SYSTEM, "Out of memory in newdist");
42 distsiz = siz;
43 }
44 memset(distarr, '\0', sizeof(COLORV)*3*siz);
45 }
46
47
48 static int
49 process_ray(RAY *r, int rv)
50 {
51 COLORV *colp;
52
53 if (rv == 0)
54 return(0);
55 if (rv < 0)
56 error(USER, "Ray tracing process died");
57 if (r->rno >= distsiz)
58 error(INTERNAL, "Bad returned index in process_ray");
59 colp = &distarr[r->rno * 3];
60 addcolor(colp, r->rcol);
61 return(1);
62 }
63
64
65 static void
66 raysamp( /* queue a ray sample */
67 int ndx,
68 FVECT org,
69 FVECT dir
70 )
71 {
72 RAY myRay;
73 int rv;
74
75 if ((ndx < 0) | (ndx >= distsiz))
76 error(INTERNAL, "Bad index in raysamp");
77 VCOPY(myRay.rorg, org);
78 VCOPY(myRay.rdir, dir);
79 myRay.rmax = .0;
80 rayorigin(&myRay, PRIMARY, NULL, NULL);
81 myRay.rno = ndx;
82 /* queue ray, check result */
83 process_ray(&myRay, ray_pqueue(&myRay));
84 }
85
86
87 static void
88 rayclean() /* finish all pending rays */
89 {
90 RAY myRay;
91
92 while (process_ray(&myRay, ray_presult(&myRay, 0)))
93 ;
94 }
95
96
97 int
98 my_default( /* default illum action */
99 OBJREC *ob,
100 struct illum_args *il,
101 char *nm
102 )
103 {
104 sprintf(errmsg, "(%s): cannot make illum for %s \"%s\"",
105 nm, ofun[ob->otype].funame, ob->oname);
106 error(WARNING, errmsg);
107 printobj(il->altmat, ob);
108 return(1);
109 }
110
111
112 int
113 my_face( /* make an illum face */
114 OBJREC *ob,
115 struct illum_args *il,
116 char *nm
117 )
118 {
119 #define MAXMISS (5*n*il->nsamps)
120 int dim[3];
121 int n, nalt, nazi, h;
122 double sp[2], r1, r2;
123 FVECT dn, org, dir;
124 FVECT u, v;
125 double ur[2], vr[2];
126 int nmisses;
127 register FACE *fa;
128 register int i, j;
129 /* get/check arguments */
130 fa = getface(ob);
131 if (fa->area == 0.0) {
132 freeface(ob);
133 return(my_default(ob, il, nm));
134 }
135 /* set up sampling */
136 if (il->sampdens <= 0)
137 nalt = nazi = 1;
138 else {
139 n = PI * il->sampdens;
140 nalt = sqrt(n/PI) + .5;
141 nazi = PI*nalt + .5;
142 }
143 n = nalt*nazi;
144 newdist(n);
145 /* take first edge longer than sqrt(area) */
146 for (j = fa->nv-1, i = 0; i < fa->nv; j = i++) {
147 u[0] = VERTEX(fa,i)[0] - VERTEX(fa,j)[0];
148 u[1] = VERTEX(fa,i)[1] - VERTEX(fa,j)[1];
149 u[2] = VERTEX(fa,i)[2] - VERTEX(fa,j)[2];
150 if ((r1 = DOT(u,u)) >= fa->area-FTINY)
151 break;
152 }
153 if (i < fa->nv) { /* got one! -- let's align our axes */
154 r2 = 1.0/sqrt(r1);
155 u[0] *= r2; u[1] *= r2; u[2] *= r2;
156 fcross(v, fa->norm, u);
157 } else /* oh well, we'll just have to wing it */
158 mkaxes(u, v, fa->norm);
159 /* now, find limits in (u,v) coordinates */
160 ur[0] = vr[0] = FHUGE;
161 ur[1] = vr[1] = -FHUGE;
162 for (i = 0; i < fa->nv; i++) {
163 r1 = DOT(VERTEX(fa,i),u);
164 if (r1 < ur[0]) ur[0] = r1;
165 if (r1 > ur[1]) ur[1] = r1;
166 r2 = DOT(VERTEX(fa,i),v);
167 if (r2 < vr[0]) vr[0] = r2;
168 if (r2 > vr[1]) vr[1] = r2;
169 }
170 dim[0] = random();
171 /* sample polygon */
172 nmisses = 0;
173 for (dim[1] = 0; dim[1] < nalt; dim[1]++)
174 for (dim[2] = 0; dim[2] < nazi; dim[2]++)
175 for (i = 0; i < il->nsamps; i++) {
176 /* random direction */
177 h = ilhash(dim, 3) + i;
178 multisamp(sp, 2, urand(h));
179 r1 = (dim[1] + sp[0])/nalt;
180 r2 = (dim[2] + sp[1] - .5)/nazi;
181 flatdir(dn, r1, r2);
182 for (j = 0; j < 3; j++)
183 dir[j] = -dn[0]*u[j] - dn[1]*v[j] - dn[2]*fa->norm[j];
184 /* random location */
185 do {
186 multisamp(sp, 2, urand(h+4862+nmisses));
187 r1 = ur[0] + (ur[1]-ur[0]) * sp[0];
188 r2 = vr[0] + (vr[1]-vr[0]) * sp[1];
189 for (j = 0; j < 3; j++)
190 org[j] = r1*u[j] + r2*v[j]
191 + fa->offset*fa->norm[j];
192 } while (!inface(org, fa) && nmisses++ < MAXMISS);
193 if (nmisses > MAXMISS) {
194 objerror(ob, WARNING, "bad aspect");
195 rayclean();
196 freeface(ob);
197 free((void *)distarr);
198 return(my_default(ob, il, nm));
199 }
200 for (j = 0; j < 3; j++)
201 org[j] += .001*fa->norm[j];
202 /* send sample */
203 raysamp(dim[1]*nazi+dim[2], org, dir);
204 }
205 rayclean();
206 /* write out the face and its distribution */
207 if (average(il, distarr, nalt*nazi)) {
208 if (il->sampdens > 0)
209 flatout(il, distarr, nalt, nazi, u, v, fa->norm);
210 illumout(il, ob);
211 } else
212 printobj(il->altmat, ob);
213 /* clean up */
214 freeface(ob);
215 return(0);
216 #undef MAXMISS
217 }
218
219
220 int
221 my_sphere( /* make an illum sphere */
222 register OBJREC *ob,
223 struct illum_args *il,
224 char *nm
225 )
226 {
227 int dim[3];
228 int n, nalt, nazi;
229 double sp[4], r1, r2, r3;
230 FVECT org, dir;
231 FVECT u, v;
232 register int i, j;
233 /* check arguments */
234 if (ob->oargs.nfargs != 4)
235 objerror(ob, USER, "bad # of arguments");
236 /* set up sampling */
237 if (il->sampdens <= 0)
238 nalt = nazi = 1;
239 else {
240 n = 4.*PI * il->sampdens;
241 nalt = sqrt(2./PI*n) + .5;
242 nazi = PI/2.*nalt + .5;
243 }
244 n = nalt*nazi;
245 newdist(n);
246 dim[0] = random();
247 /* sample sphere */
248 for (dim[1] = 0; dim[1] < nalt; dim[1]++)
249 for (dim[2] = 0; dim[2] < nazi; dim[2]++)
250 for (i = 0; i < il->nsamps; i++) {
251 /* next sample point */
252 multisamp(sp, 4, urand(ilhash(dim,3)+i));
253 /* random direction */
254 r1 = (dim[1] + sp[0])/nalt;
255 r2 = (dim[2] + sp[1] - .5)/nazi;
256 rounddir(dir, r1, r2);
257 /* random location */
258 mkaxes(u, v, dir); /* yuck! */
259 r3 = sqrt(sp[2]);
260 r2 = 2.*PI*sp[3];
261 r1 = r3*ob->oargs.farg[3]*cos(r2);
262 r2 = r3*ob->oargs.farg[3]*sin(r2);
263 r3 = ob->oargs.farg[3]*sqrt(1.01-r3*r3);
264 for (j = 0; j < 3; j++) {
265 org[j] = ob->oargs.farg[j] + r1*u[j] + r2*v[j] +
266 r3*dir[j];
267 dir[j] = -dir[j];
268 }
269 /* send sample */
270 raysamp(dim[1]*nazi+dim[2], org, dir);
271 }
272 rayclean();
273 /* write out the sphere and its distribution */
274 if (average(il, distarr, nalt*nazi)) {
275 if (il->sampdens > 0)
276 roundout(il, distarr, nalt, nazi);
277 else
278 objerror(ob, WARNING, "diffuse distribution");
279 illumout(il, ob);
280 } else
281 printobj(il->altmat, ob);
282 /* clean up */
283 return(1);
284 }
285
286
287 int
288 my_ring( /* make an illum ring */
289 OBJREC *ob,
290 struct illum_args *il,
291 char *nm
292 )
293 {
294 int dim[3];
295 int n, nalt, nazi;
296 double sp[4], r1, r2, r3;
297 FVECT dn, org, dir;
298 FVECT u, v;
299 register CONE *co;
300 register int i, j;
301 /* get/check arguments */
302 co = getcone(ob, 0);
303 /* set up sampling */
304 if (il->sampdens <= 0)
305 nalt = nazi = 1;
306 else {
307 n = PI * il->sampdens;
308 nalt = sqrt(n/PI) + .5;
309 nazi = PI*nalt + .5;
310 }
311 n = nalt*nazi;
312 newdist(n);
313 mkaxes(u, v, co->ad);
314 dim[0] = random();
315 /* sample disk */
316 for (dim[1] = 0; dim[1] < nalt; dim[1]++)
317 for (dim[2] = 0; dim[2] < nazi; dim[2]++)
318 for (i = 0; i < il->nsamps; i++) {
319 /* next sample point */
320 multisamp(sp, 4, urand(ilhash(dim,3)+i));
321 /* random direction */
322 r1 = (dim[1] + sp[0])/nalt;
323 r2 = (dim[2] + sp[1] - .5)/nazi;
324 flatdir(dn, r1, r2);
325 for (j = 0; j < 3; j++)
326 dir[j] = -dn[0]*u[j] - dn[1]*v[j] - dn[2]*co->ad[j];
327 /* random location */
328 r3 = sqrt(CO_R0(co)*CO_R0(co) +
329 sp[2]*(CO_R1(co)*CO_R1(co) - CO_R0(co)*CO_R0(co)));
330 r2 = 2.*PI*sp[3];
331 r1 = r3*cos(r2);
332 r2 = r3*sin(r2);
333 for (j = 0; j < 3; j++)
334 org[j] = CO_P0(co)[j] + r1*u[j] + r2*v[j] +
335 .001*co->ad[j];
336
337 /* send sample */
338 raysamp(dim[1]*nazi+dim[2], org, dir);
339 }
340 rayclean();
341 /* write out the ring and its distribution */
342 if (average(il, distarr, nalt*nazi)) {
343 if (il->sampdens > 0)
344 flatout(il, distarr, nalt, nazi, u, v, co->ad);
345 illumout(il, ob);
346 } else
347 printobj(il->altmat, ob);
348 /* clean up */
349 freecone(ob);
350 return(1);
351 }
352
353
354 static void
355 mkaxes( /* compute u and v to go with n */
356 FVECT u,
357 FVECT v,
358 FVECT n
359 )
360 {
361 register int i;
362
363 v[0] = v[1] = v[2] = 0.0;
364 for (i = 0; i < 3; i++)
365 if (n[i] < 0.6 && n[i] > -0.6)
366 break;
367 v[i] = 1.0;
368 fcross(u, v, n);
369 normalize(u);
370 fcross(v, n, u);
371 }
372
373
374 static void
375 rounddir( /* compute uniform spherical direction */
376 register FVECT dv,
377 double alt,
378 double azi
379 )
380 {
381 double d1, d2;
382
383 dv[2] = 1. - 2.*alt;
384 d1 = sqrt(1. - dv[2]*dv[2]);
385 d2 = 2.*PI * azi;
386 dv[0] = d1*cos(d2);
387 dv[1] = d1*sin(d2);
388 }
389
390
391 static void
392 flatdir( /* compute uniform hemispherical direction */
393 register FVECT dv,
394 double alt,
395 double azi
396 )
397 {
398 double d1, d2;
399
400 d1 = sqrt(alt);
401 d2 = 2.*PI * azi;
402 dv[0] = d1*cos(d2);
403 dv[1] = d1*sin(d2);
404 dv[2] = sqrt(1. - alt);
405 }