1 //////////////////////////////////////////////////////////////////////
2 //
3 // Pixie
4 //
5 // Copyright � 1999 - 2003, Okan Arikan
6 //
7 // Contact: okan@cs.utexas.edu
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 //
23 ///////////////////////////////////////////////////////////////////////
24 ///////////////////////////////////////////////////////////////////////
25 //
26 // File : hcshader.cpp
27 // Classes : -
28 // Description : This file holds the hardcoded shaders
29 //
30 ////////////////////////////////////////////////////////////////////////
31 #include <math.h>
32
33 #include "common/os.h"
34 #include "hcshader.h"
35 #include "shading.h"
36 #include "memory.h"
37 #include "attributes.h"
38 #include "object.h"
39 #include "renderer.h"
40 #include "ri_config.h"
41
42
43 ///////////////////////////////////////////////////////////////////////
44 // Class : CSphereLight
45 // Method : CSphereLight
46 // Description : Ctor
47 // Return Value : -
48 // Comments :
CSphereLight(CAttributes * a,CXform * x)49 CSphereLight::CSphereLight(CAttributes *a,CXform *x) : CShaderInstance(a,x) {
50 vector P;
51
52 initv(P,0,0,0);
53 mulmp(from,xform->from,P);
54 initv(lightColor,1,1,1);
55 intensity = 1;
56 radius = 0;
57 numSamples = 1;
58 flags = SHADERFLAGS_NONAMBIENT;
59 }
60
61 ///////////////////////////////////////////////////////////////////////
62 // Class : CSphereLight
63 // Method : ~CSphereLight
64 // Description : Dtor
65 // Return Value : -
66 // Comments :
~CSphereLight()67 CSphereLight::~CSphereLight() {
68 }
69
70
71 ///////////////////////////////////////////////////////////////////////
72 // Class : CSphereLight
73 // Method : illuminate
74 // Description : Called when we need to illuminate a point
75 // Return Value : -
76 // Comments :
illuminate(CShadingContext * context,float ** locals)77 void CSphereLight::illuminate(CShadingContext *context,float **locals) {
78 CShadingState *currentShadingState = context->currentShadingState;
79
80 #define sampleSphere(cP) \
81 while(TRUE) { \
82 cP[COMP_X] = 2*context->urand()-1; \
83 cP[COMP_Y] = 2*context->urand()-1; \
84 cP[COMP_Z] = 2*context->urand()-1; \
85 \
86 if (dotvv(cP,cP) < 1) break; \
87 }
88
89
90 if (CRenderer::hiderFlags & HIDER_ILLUMINATIONHOOK) {
91 const int numVertices = currentShadingState->numVertices;
92 float *Pf = (float *) alloca(numVertices*3*sizeof(float));
93 float *Nf = (float *) alloca(numVertices*3*sizeof(float));
94 float *thetaf = (float *) alloca(numVertices*sizeof(float));
95 int i;
96 float *cP = Pf;
97 float *cN = Nf;
98 float *L;
99 float *CL;
100
101 // Generate points on the surface
102 for (i=numVertices;i>0;i--,cP+=3,cN+=3) {
103 sampleSphere(cP);
104 normalizev(cP);
105 movvv(cN,cP);
106 mulvf(cP,radius);
107 addvv(cP,from);
108 }
109
110 // Call the hook handle
111 context->illuminateBegin(Pf,Nf,thetaf);
112
113 // Compute the intensity
114 L = currentShadingState->varying[VARIABLE_L];
115 CL = currentShadingState->varying[VARIABLE_CL];
116 for (i=numVertices;i>0;i--,L+=3,CL+=3,Nf+=3) {
117 // The L must be unit vector
118 assert((dotvv(L,L) - 1)*(dotvv(L,L) - 1) < 0.00001);
119 assert(dotvv(Nf,L) >= 0);
120
121 mulvf(CL,lightColor,intensity);
122 mulvf(CL,dotvv(Nf,L));
123 }
124
125 // Call the hook handle
126 context->illuminateEnd();
127 } else {
128 CShadedLight **lights = ¤tShadingState->lights;
129 const int *tags = currentShadingState->tags;
130 float *Ps = currentShadingState->varying[VARIABLE_PS];
131 int j;
132 CRay ray;
133 const float bias = currentShadingState->currentObject->attributes->bias;
134 int numVertices = currentShadingState->numRealVertices;
135 CShadedLight *cLight;
136
137 if (currentShadingState->numActive == 0)
138 return;
139
140 cLight = (CShadedLight*) ralloc(sizeof(CShadedLight),context->threadMemory);
141 cLight->lightTags = (int*) ralloc(sizeof(int)*numVertices,context->threadMemory);
142 cLight->savedState = (float**) ralloc(2*sizeof(float*),context->threadMemory);
143 cLight->savedState[0] = (float*) ralloc(3*sizeof(float)*numVertices,context->threadMemory);
144 cLight->savedState[1] = (float*) ralloc(3*sizeof(float)*numVertices,context->threadMemory);
145 cLight->instance = this;
146 cLight->next = *lights;
147 *lights = cLight;
148 memcpy(cLight->lightTags,tags,sizeof(int)*numVertices);
149 float *L = cLight->savedState[0];
150 float *Cl = cLight->savedState[1];
151 const float *time = currentShadingState->varying[VARIABLE_TIME];
152
153 for (int i=numVertices;i>0;i--,Ps+=3,time++){
154 if (*tags++ == 0) {
155 vector P;
156 float visibility = 0;
157
158 for (j=numSamples;j>0;j--) {
159 sampleSphere(P);
160 normalizev(P);
161 mulvf(P,radius);
162 addvv(P,from);
163
164 // Evaluate visibility between P and Ps
165 movvv(ray.from,Ps);
166 subvv(ray.dir,P,Ps);
167 const float len = lengthv(ray.dir);
168 mulvf(ray.dir,1 / len);
169
170 ray.flags = ATTRIBUTES_FLAGS_TRANSMISSION_VISIBLE;
171 ray.tmin = bias;
172 ray.t = len - bias;
173 ray.time = *time;
174
175 // Figure out the ray differential
176 const float sina = radius / len;
177 const float cosa = sqrtf(1 - sina*sina);
178 const float da = sina / (cosa + C_EPSILON);
179 ray.da = min(DEFAULT_RAY_DA,da);
180 ray.db = DEFAULT_RAY_DB;
181
182 context->trace(&ray);
183
184 if (ray.object == NULL) {
185 subvv(P,Ps);
186 visibility += intensity / dotvv(P,P);
187 }
188 }
189
190 visibility /= (float) numSamples;
191
192 subvv(L,from,Ps);
193 normalizev(L);
194 mulvf(Cl,lightColor,visibility);
195 }
196 L += 3;
197 Cl += 3;
198 }
199 }
200 #undef sampleSphere
201 }
202
203 ///////////////////////////////////////////////////////////////////////
204 // Class : CSphereLight
205 // Method : setParameters
206 // Description : Set shader parameters
207 // Return Value : -
208 // Comments :
setParameters(int n,const char ** params,const void ** vals)209 void CSphereLight::setParameters(int n,const char **params,const void **vals) {
210 int i;
211
212 for (i=0;i<n;i++) {
213 if (strcmp(params[i],"from") == 0) {
214 const float *val = (const float *) vals[i];
215
216 mulmp(from,xform->from,val);
217 } else if (strcmp(params[i],"radius") == 0) {
218 const float *val = (const float *) vals[i];
219
220 radius = val[0]*powf(determinantm(xform->from),1.0f / 3.0f);
221 } else if (strcmp(params[i],"lightcolor") == 0) {
222 const float *val = (const float *) vals[i];
223
224 movvv(lightColor,val);
225 } else if (strcmp(params[i],"intensity") == 0) {
226 const float *val = (const float *) vals[i];
227
228 intensity = val[0];
229 } else if (strcmp(params[i],"numSamples") == 0) {
230 const float *val = (const float *) vals[i];
231
232 numSamples = (int) val[0];
233 }
234 }
235 }
236
237 ///////////////////////////////////////////////////////////////////////
238 // Class : CSphereLight
239 // Method : getParameter
240 // Description : Query a shader parameter
241 // Return Value : -
242 // Comments :
getParameter(const char * param,void * val,CVariable **,int *)243 int CSphereLight::getParameter(const char *param,void *val,CVariable**,int*) {
244 if (strcmp(param,"from") == 0) {
245 float *cval = (float *) val;
246
247 movvv(cval,from);
248 return TRUE;
249 } else if (strcmp(param,"radius") == 0) {
250 float *cval = (float *) val;
251
252 cval[0] = radius;
253 return TRUE;
254 } else if (strcmp(param,"lightcolor") == 0) {
255 float *cval = (float *) val;
256
257 movvv(cval,lightColor);
258 return TRUE;
259 } else if (strcmp(param,"intensity") == 0) {
260 float *cval = (float *) val;
261
262 cval[0] = intensity;
263 return TRUE;
264 } else if (strcmp(param,"numSamples") == 0) {
265 float *cval = (float *) val;
266
267 cval[0] = (float) numSamples;
268 return TRUE;
269 }
270
271 return FALSE;
272 }
273
274 ///////////////////////////////////////////////////////////////////////
275 // Class : CSphereLight
276 // Method : execute
277 // Description : Execute the shader
278 // Return Value : -
279 // Comments : Should never be called
execute(CShadingContext * context,float ** locals)280 void CSphereLight::execute(CShadingContext *context,float **locals) {
281 // Should never be called
282 assert(FALSE);
283 }
284
285 ///////////////////////////////////////////////////////////////////////
286 // Class : CSphereLight
287 // Method : requiredParameters
288 // Description : Get the required parameters
289 // Return Value : -
290 // Comments :
requiredParameters()291 unsigned int CSphereLight::requiredParameters() {
292 return 0;
293 }
294
295 ///////////////////////////////////////////////////////////////////////
296 // Class : CSphereLight
297 // Method : getName
298 // Description : Get the name of the shader
299 // Return Value : -
300 // Comments :
getName()301 const char *CSphereLight::getName() {
302 return "spherelight";
303 }
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328 ///////////////////////////////////////////////////////////////////////
329 // Class : CQuadLight
330 // Method : CQuadLight
331 // Description : Ctor
332 // Return Value : -
333 // Comments :
CQuadLight(CAttributes * a,CXform * x)334 CQuadLight::CQuadLight(CAttributes *a,CXform *x) : CShaderInstance(a,x) {
335 vector P;
336 vector D0,D1;
337
338 initv(P,-1,-1,0);
339 mulmp(corners[0],xform->from,P);
340 initv(P,1,-1,0);
341 mulmp(corners[1],xform->from,P);
342 initv(P,-1,1,0);
343 mulmp(corners[2],xform->from,P);
344 initv(P,1,1,0);
345 mulmp(corners[3],xform->from,P);
346
347 initv(lightColor,1,1,1);
348 intensity = 1;
349 numSamples = 1;
350 reverse = (a->flags & ATTRIBUTES_FLAGS_INSIDE);
351 flags = SHADERFLAGS_NONAMBIENT;
352
353 subvv(D0,corners[1],corners[0]);
354 subvv(D1,corners[2],corners[0]);
355 crossvv(N,D0,D1);
356 normalizev(N);
357
358 if (reverse) mulvf(N,-1);
359
360 // Find the center point of the light
361 addvv(center,corners[0],corners[1]);
362 addvv(center,corners[2]);
363 addvv(center,corners[3]);
364 mulvf(center,1 / (float) 4);
365
366 // Find the radius of the light
367 vector tmp;
368 subvv(tmp,corners[0],center);
369 r = lengthv(tmp);
370 subvv(tmp,corners[1],center);
371 r += lengthv(tmp);
372 subvv(tmp,corners[2],center);
373 r += lengthv(tmp);
374 subvv(tmp,corners[3],center);
375 r += lengthv(tmp);
376 r *= 0.25f;
377 }
378
379 ///////////////////////////////////////////////////////////////////////
380 // Class : CQuadLight
381 // Method : ~CQuadLight
382 // Description : Dtor
383 // Return Value : -
384 // Comments :
~CQuadLight()385 CQuadLight::~CQuadLight() {
386 }
387
388
389 ///////////////////////////////////////////////////////////////////////
390 // Class : CQuadLight
391 // Method : illuminate
392 // Description : Called chen we need to illuminate a point
393 // Return Value : -
394 // Comments :
illuminate(CShadingContext * context,float ** locals)395 void CQuadLight::illuminate(CShadingContext *context,float **locals) {
396 CShadingState *currentShadingState = context->currentShadingState;
397
398 if (CRenderer::hiderFlags & HIDER_ILLUMINATIONHOOK) {
399 const int numVertices = currentShadingState->numVertices;
400 float *Pf = (float *) alloca(numVertices*3*sizeof(float));
401 float *Nf = (float *) alloca(numVertices*3*sizeof(float));
402 float *thetaf = (float *) alloca(numVertices*sizeof(float));
403 int i;
404 float *cP = Pf;
405 float *cN = Nf;
406 float *cTheta = thetaf;
407 float *L;
408 float *CL;
409
410 // Generate points on the surface
411 for (i=numVertices;i>0;i--,cP+=3,cN+=3) {
412 vector P0,P1;
413 const float u = context->urand();
414 const float v = context->urand();
415
416 interpolatev(P0,corners[0],corners[1],u);
417 interpolatev(P1,corners[2],corners[3],u);
418 interpolatev(cP,P0,P1,v);
419
420 movvv(cN,N);
421
422 *cTheta++ = (float) (C_PI / 2.0);
423 }
424
425 // Call the hook handle
426 context->illuminateBegin(Pf,Nf,thetaf);
427
428 // Compute the intensity
429 L = currentShadingState->varying[VARIABLE_L];
430 CL = currentShadingState->varying[VARIABLE_CL];
431 for (i=numVertices;i>0;i--,L+=3,CL+=3) {
432 // The L must be unit vector
433 assert((dotvv(L,L) - 1)*(dotvv(L,L) - 1) < 0.00001);
434 assert(dotvv(N,L) >= 0);
435
436 mulvf(CL,lightColor,intensity);
437 mulvf(CL,dotvv(N,L));
438 }
439
440 // Call the hook handle
441 context->illuminateEnd();
442 } else {
443 CShadedLight **lights = ¤tShadingState->lights;
444 CShadedLight **freeLights = ¤tShadingState->freeLights;
445 const int *tags = currentShadingState->tags;
446 float *Ps = currentShadingState->varying[VARIABLE_PS];
447 CRay ray;
448 const float bias = currentShadingState->currentObject->attributes->bias;
449 vector D;
450 int j;
451 int numVertices = currentShadingState->numRealVertices;
452 int numLitPoints = 0;
453 CShadedLight *cLight;
454 int *lightTags;
455
456 if (currentShadingState->numActive == 0)
457 return;
458
459 cLight = (CShadedLight*) ralloc(sizeof(CShadedLight),context->threadMemory);
460 cLight->lightTags = (int*) ralloc(sizeof(int)*numVertices,context->threadMemory);
461 cLight->savedState = (float**) ralloc(2*sizeof(float*),context->threadMemory);
462 cLight->savedState[0] = (float*) ralloc(3*sizeof(float)*numVertices,context->threadMemory);
463 cLight->savedState[1] = (float*) ralloc(3*sizeof(float)*numVertices,context->threadMemory);
464 cLight->instance = this;
465 memcpy(cLight->lightTags,tags,sizeof(int)*numVertices);
466 float *L = cLight->savedState[0];
467 float *Cl = cLight->savedState[1];
468 const float *time = currentShadingState->varying[VARIABLE_TIME];
469
470 // GSHTODO: do something to check Ps vs N angle before allocating light
471
472
473
474
475 lightTags = cLight->lightTags;
476 for (int i=currentShadingState->numRealVertices;i>0;i--,Ps+=3,time++) {
477 if (*lightTags == 0) {
478 subvv(D,Ps,center);
479 if (dotvv(D,N) > 0) {
480 vector P,P0,P1;
481 float visibility = 0;
482
483 for (j=numSamples;j>0;j--) {
484 const float u = context->urand();
485
486 interpolatev(P0,corners[0],corners[1],u);
487 interpolatev(P1,corners[2],corners[3],u);
488 interpolatev(P,P0,P1,context->urand());
489
490 // Evaluate visibility between P and Ps
491 movvv(ray.from,Ps);
492 subvv(ray.dir,P,Ps);
493 const float len = lengthv(ray.dir);
494 mulvf(ray.dir,1 / len);
495
496 ray.flags = ATTRIBUTES_FLAGS_TRANSMISSION_VISIBLE;
497 ray.tmin = bias;
498 ray.t = len - bias;
499 ray.time = *time;
500
501 // Figure out the ray differential
502 const float sina = r / len;
503 const float cosa = sqrtf(1 - sina*sina);
504 const float da = sina / (cosa + C_EPSILON);
505 ray.da = min(DEFAULT_RAY_DA,da);
506 ray.db = DEFAULT_RAY_DB;
507
508 context->trace(&ray);
509
510 if (ray.object == NULL) {
511 visibility++;
512 }
513 }
514
515 visibility /= (float) numSamples;
516 subvv(L,center,Ps);
517 visibility /= dotvv(L,L);
518 normalizev(L);
519 visibility *= -dotvv(N,L)*intensity;
520 mulvf(Cl,lightColor,visibility);
521 numLitPoints++;
522 } else {
523 (*lightTags)++;
524 }
525 lightTags++;
526 L += 3;
527 Cl += 3;
528 }
529 }
530
531 if (numLitPoints > 0) {
532 // Only save the light if it has active points
533 cLight->next = *lights;
534 *lights = cLight;
535 } else {
536 // Otherwise put it on the free list
537 cLight->next = *freeLights;
538 *freeLights = cLight;
539 }
540 }
541 }
542
543 ///////////////////////////////////////////////////////////////////////
544 // Class : CQuadLight
545 // Method : setParameters
546 // Description : Set shader parameters
547 // Return Value : -
548 // Comments :
setParameters(int n,const char ** params,const void ** vals)549 void CQuadLight::setParameters(int n,const char **params,const void **vals) {
550 int i;
551
552 for (i=0;i<n;i++) {
553 if (strcmp(params[i],"P0") == 0) {
554 const float *val = (const float *) vals[i];
555
556 mulmp(corners[0],xform->from,val);
557 } else if (strcmp(params[i],"P1") == 0) {
558 const float *val = (const float *) vals[i];
559
560 mulmp(corners[1],xform->from,val);
561 } else if (strcmp(params[i],"P2") == 0) {
562 const float *val = (const float *) vals[i];
563
564 mulmp(corners[2],xform->from,val);
565 } else if (strcmp(params[i],"P3") == 0) {
566 const float *val = (const float *) vals[i];
567
568 mulmp(corners[3],xform->from,val);
569 } else if (strcmp(params[i],"direction") == 0) {
570 const float *val = (const float *) vals[i];
571
572 mulmn(N,xform->to,val);
573 } else if (strcmp(params[i],"lightcolor") == 0) {
574 const float *val = (const float *) vals[i];
575
576 movvv(lightColor,val);
577 } else if (strcmp(params[i],"intensity") == 0) {
578 const float *val = (const float *) vals[i];
579
580 intensity = val[0];
581 } else if (strcmp(params[i],"numSamples") == 0) {
582 const float *val = (const float *) vals[i];
583
584 numSamples = (int) val[0];
585 }
586 }
587 }
588
589 ///////////////////////////////////////////////////////////////////////
590 // Class : CQuadLight
591 // Method : getParameter
592 // Description : Query a shader parameter
593 // Return Value : -
594 // Comments :
getParameter(const char * param,void * val,CVariable **,int *)595 int CQuadLight::getParameter(const char *param,void *val,CVariable**,int*) {
596 if (strcmp(param,"P0") == 0) {
597 float *cval = (float *) val;
598
599 movvv(cval,corners[0]);
600 return TRUE;
601 } else if (strcmp(param,"P1") == 0) {
602 float *cval = (float *) val;
603
604 movvv(cval,corners[1]);
605 return TRUE;
606 } else if (strcmp(param,"P2") == 0) {
607 float *cval = (float *) val;
608
609 movvv(cval,corners[1]);
610 return TRUE;
611 } else if (strcmp(param,"P3") == 0) {
612 float *cval = (float *) val;
613
614 movvv(cval,corners[1]);
615 return TRUE;
616 } else if (strcmp(param,"direction") == 0) {
617 float *cval = (float *) val;
618
619 movvv(cval,N);
620 return TRUE;
621 } else if (strcmp(param,"lightColor") == 0) {
622 float *cval = (float *) val;
623
624 movvv(cval,lightColor);
625 return TRUE;
626 } else if (strcmp(param,"intensity") == 0) {
627 float *cval = (float *) val;
628
629 cval[0] = intensity;
630 return TRUE;
631 } else if (strcmp(param,"numSamples") == 0) {
632 float *cval = (float *) val;
633
634 cval[0] = (float) numSamples;
635 return TRUE;
636 }
637
638 return FALSE;
639 }
640
641 ///////////////////////////////////////////////////////////////////////
642 // Class : CQuadLight
643 // Method : execute
644 // Description : Execute the shader
645 // Return Value : -
646 // Comments : Should never be called
execute(CShadingContext * context,float ** locals)647 void CQuadLight::execute(CShadingContext *context,float **locals) {
648 // Should never be called
649 assert(FALSE);
650 }
651
652 ///////////////////////////////////////////////////////////////////////
653 // Class : CQuadLight
654 // Method : requiredParameters
655 // Description : Get the required parameters
656 // Return Value : -
657 // Comments :
requiredParameters()658 unsigned int CQuadLight::requiredParameters() {
659 return 0;
660 }
661
662 ///////////////////////////////////////////////////////////////////////
663 // Class : CQuadLight
664 // Method : getName
665 // Description : Get the name of the shader
666 // Return Value : -
667 // Comments :
getName()668 const char *CQuadLight::getName() {
669 return "quadlight";
670 }
671
672