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				:	object.cpp
27 //  Classes				:	CGeometry
28 //  Description			:	Implementation
29 //
30 ////////////////////////////////////////////////////////////////////////
31 #include <math.h>
32 
33 #include "object.h"
34 #include "error.h"
35 #include "ri.h"
36 #include "shading.h"
37 #include "stats.h"
38 #include "memory.h"
39 #include "surface.h"
40 #include "rendererContext.h"
41 #include "renderer.h"
42 #include "random.h"
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 ///////////////////////////////////////////////////////////////////////
54 // Class				:	CObject
55 // Method				:	CObject
56 // Description			:	Ctor
57 // Return Value			:	-
58 // Comments				:
CObject(CAttributes * a,CXform * x)59 CObject::CObject(CAttributes *a,CXform *x) {
60 	atomicIncrement(&stats.numObjects);
61 
62 	flags		=	0;
63 	attributes	=	a;
64 	xform		=	x;
65 
66 	attributes->attach();
67 	xform->attach();
68 
69 	children	=	NULL;
70 	sibling		=	NULL;
71 }
72 
73 
74 ///////////////////////////////////////////////////////////////////////
75 // Class				:	CObject
76 // Method				:	~CObject
77 // Description			:	Dtor
78 // Return Value			:	-
79 // Comments				:
~CObject()80 CObject::~CObject() {
81 	atomicDecrement(&stats.numObjects);
82 
83 	attributes->detach();
84 	xform->detach();
85 }
86 
87 
88 ///////////////////////////////////////////////////////////////////////
89 // Class				:	CObject
90 // Method				:	dice
91 // Description			:	Dice the children objects
92 // Return Value			:	-
93 // Comments				:
dice(CShadingContext * rasterizer)94 void			CObject::dice(CShadingContext *rasterizer) {
95 	CObject	*cObject,*nObject;
96 	for (cObject=children;cObject!=NULL;cObject=nObject) {
97 		nObject	=	cObject->sibling;
98 
99 		cObject->attach();
100 
101 		rasterizer->drawObject(cObject);
102 
103 		cObject->detach();
104 	}
105 }
106 
107 
getDisp(const float * mat,float disp)108 static	float	getDisp(const float *mat,float disp) {
109 	float	tmp[4],tmp2[4];
110 	int		i;
111 	float	alpha;
112 
113 	tmp[0]	=	_urand();
114 	tmp[1]	=	_urand();
115 	tmp[2]	=	_urand();
116 	tmp[3]	=	_urand();
117 
118 	for (i=0;i<10;i++) {
119 		mulmp4(tmp2,mat,tmp);
120 
121 		alpha	=	max(absf(tmp2[0]),absf(tmp2[1]));
122 		alpha	=	max(alpha,absf(tmp2[2]));
123 		alpha	=	max(alpha,absf(tmp2[3]));
124 
125 		tmp[0]	=	tmp2[0]	/	alpha;
126 		tmp[1]	=	tmp2[1]	/	alpha;
127 		tmp[2]	=	tmp2[2]	/	alpha;
128 		tmp[3]	=	tmp2[3]	/	alpha;
129 	}
130 
131 	return	alpha;
132 
133 #undef urand
134 }
135 
136 
137 ///////////////////////////////////////////////////////////////////////
138 // Class				:	CObject
139 // Method				:	cluster
140 // Description			:	Cluster the objects
141 // Return Value			:
142 // Comments				:
cluster(CShadingContext * context)143 void		CObject::cluster(CShadingContext *context) {
144 	int		numChildren;
145 	CObject	*cObject;
146 
147 	// Count the number of children
148 	for (numChildren=0,cObject=children;cObject!=NULL;cObject=cObject->sibling,numChildren++);
149 
150 	// If we have too few children, continue
151 	if (numChildren <= 2)	return;
152 
153 	// These are the two children
154 	CObject	*front,*frontChildren;
155 	CObject	*back,*backChildren;
156 
157 	// Begin a memory page
158 	memBegin(context->threadMemory);
159 
160 	// Cluster the midpoints of the objects
161 	float	*P			=	(float *)	ralloc(numChildren*3*sizeof(float),context->threadMemory);
162 	int		*indices	=	(int *)		ralloc(numChildren*sizeof(int),context->threadMemory);
163 
164 
165 	// For 5 iterations
166 	for (int iteration=0;iteration<15;iteration++) {
167 
168 		// Compute a slightly jittered center position for the object
169 		for (numChildren=0,cObject=children;cObject!=NULL;cObject=cObject->sibling,numChildren++) {
170 			initv(P + numChildren*3	,	(cObject->bmax[0] - cObject->bmin[0])*(context->urand()*0.2f + 0.4f) +  cObject->bmin[0]
171 									,	(cObject->bmax[1] - cObject->bmin[1])*(context->urand()*0.2f + 0.4f) +  cObject->bmin[1]
172 									,	(cObject->bmax[2] - cObject->bmin[2])*(context->urand()*0.2f + 0.4f) +  cObject->bmin[2]);
173 			indices[numChildren]	=	-1;
174 		}
175 
176 		// The random cluster centers
177 		vector	P1,P2;
178 		initv(P1,	(bmax[0] - bmin[0])*context->urand() + bmin[0]
179 				,	(bmax[1] - bmin[1])*context->urand() + bmin[1]
180 				,	(bmax[2] - bmin[2])*context->urand() + bmin[2]);
181 		initv(P2,	(bmax[0] - bmin[0])*context->urand() + bmin[0]
182 				,	(bmax[1] - bmin[1])*context->urand() + bmin[1]
183 				,	(bmax[2] - bmin[2])*context->urand() + bmin[2]);
184 
185 		// The main clustering loop
186 		int	done;
187 		for (done=FALSE;done==FALSE;) {
188 			int		i;
189 			vector	nP1,nP2;
190 			int		num1,num2;
191 
192 			done	=	TRUE;
193 
194 			initv(nP1,0);
195 			initv(nP2,0);
196 			num1	=	0;
197 			num2	=	0;
198 			for (i=0;i<numChildren;i++) {
199 				vector	D1,D2;
200 
201 				subvv(D1,P + i*3,P1);
202 				subvv(D2,P + i*3,P2);
203 				if (dotvv(D1,D1) < dotvv(D2,D2)) {
204 					if (indices[i] != 0) {
205 						done		=	FALSE;
206 						indices[i]	=	0;
207 					}
208 
209 					addvv(nP1,P+i*3);
210 					num1++;
211 				} else {
212 					if (indices[i] != 1) {
213 						done		=	FALSE;
214 						indices[i]	=	1;
215 					}
216 
217 					addvv(nP2,P+i*3);
218 					num2++;
219 				}
220 			}
221 
222 			if ((num1 == 0) || (num2 == 0))	break;
223 
224 			mulvf(P1,nP1,1/(float) num1);
225 			mulvf(P2,nP2,1/(float) num2);
226 		}
227 
228 		if (done == TRUE)	break;
229 	}
230 
231 
232 	// Cluster the rest of the objects
233 	front	=	new CDummyObject(attributes,xform);
234 	back	=	new CDummyObject(attributes,xform);
235 	initv(front->bmin,C_INFINITY);
236 	initv(front->bmax,-C_INFINITY);
237 	initv(back->bmin,C_INFINITY);
238 	initv(back->bmax,-C_INFINITY);
239 
240 	frontChildren	=	NULL;
241 	backChildren	=	NULL;
242 
243 	// Create the clusters
244 	for (numChildren=0,cObject=children;cObject!=NULL;numChildren++) {
245 		CObject	*nObject	=	cObject->sibling;
246 
247 		if (indices[numChildren] == 0) {
248 			cObject->sibling	=	frontChildren;
249 			frontChildren		=	cObject;
250 			addBox(front->bmin,front->bmax,cObject->bmin);
251 			addBox(front->bmin,front->bmax,cObject->bmax);
252 		} else {
253 			cObject->sibling	=	backChildren;
254 			backChildren		=	cObject;
255 			addBox(back->bmin,back->bmax,cObject->bmin);
256 			addBox(back->bmin,back->bmax,cObject->bmax);
257 		}
258 
259 		cObject	=	nObject;
260 	}
261 
262 	memEnd(context->threadMemory);
263 
264 	// Recurse
265 	front->children	=	frontChildren;
266 	back->children	=	backChildren;
267 
268 	front->attach();
269 	back->attach();
270 
271 	front->sibling	=	back;
272 	back->sibling	=	NULL;
273 	children		=	front;
274 }
275 
276 ///////////////////////////////////////////////////////////////////////
277 // Class				:	CObject
278 // Method				:	setChildren
279 // Description			:	Set the children objects
280 // Return Value			:
281 // Comments				:
setChildren(CShadingContext * context,CObject * allChildren)282 void			CObject::setChildren(CShadingContext *context,CObject *allChildren) {
283 
284 	// If raytraced, attach to the children
285 	if (raytraced()) {
286 		for (CObject *cObject=allChildren;cObject!=NULL;cObject=cObject->sibling)	cObject->attach();
287 	}
288 
289 	children	=	allChildren;
290 }
291 
292 ///////////////////////////////////////////////////////////////////////
293 // Class				:	CObject
294 // Method				:	destroy
295 // Description			:	Destroy the entire tree
296 // Return Value			:
297 // Comments				:
destroy()298 void		CObject::destroy() {
299 	if (sibling != NULL)	sibling->destroy();
300 	if (children != NULL)	children->destroy();
301 
302 	delete this;
303 }
304 
305 ///////////////////////////////////////////////////////////////////////
306 // Class				:	CObject
307 // Method				:	makeBound
308 // Description			:	Make sure we do not have empty bounding box
309 // Return Value			:
310 // Comments				:
makeBound(float * bmin,float * bmax) const311 void		CObject::makeBound(float *bmin,float *bmax) const {
312 	vector	D;
313 	float	maxD;
314 	float	maxDisp = attributes->maxDisplacement;
315 
316 	subvv(D,bmax,bmin);
317 	maxD	=	D[0];
318 	maxD	=	max(D[1],maxD);
319 	maxD	=	max(D[2],maxD);
320 	maxD	*=	attributes->bexpand;
321 
322 	// Add the displacement amount of the surface
323 	if (attributes->maxDisplacementSpace != NULL) {
324 		const float			*from,*to;
325 		ECoordinateSystem	sys;
326 
327 		if (CRenderer::findCoordinateSystem(attributes->maxDisplacementSpace,from,to,sys)) {
328 			maxDisp	=	attributes->maxDisplacement	* getDisp(from,attributes->maxDisplacement);
329 		}
330 
331 		free(attributes->maxDisplacementSpace);
332 		attributes->maxDisplacementSpace	=	NULL;
333 	}
334 
335 	maxD	+=	maxDisp;
336 
337 	// Expand the bound accordingly
338 	subvf(bmin,maxD);
339 	addvf(bmax,maxD);
340 }
341 
342 ///////////////////////////////////////////////////////////////////////
343 // Class			   :   CObject
344 // Method			   :   estimateDicing
345 // Description		   :   Estimate the dicing size on the screen
346 // Return Value		   :
347 // Comments			   :   P must be in pixels
estimateDicing(float * P,int udiv,int vdiv,int & nudiv,int & nvdiv,float shadingRate,int nonrasterorient)348 void			   CObject::estimateDicing(float *P,int udiv,int vdiv,int &nudiv,int &nvdiv,float shadingRate,int nonrasterorient) {
349    float	   uMin,vMin;  // The minimum edge length
350    float	   uMax,vMax;  // The maximum edge length
351    int		   i,j;
352    const float *cP,*nP,*tP;
353    float	   dx,dy;
354 
355    uMax	   =   vMax	   =   0;
356    uMin	   =   vMin	   =   C_INFINITY;
357 
358    if (!nonrasterorient) {
359 
360 	   // Project to pixels
361 	   camera2pixels((udiv+1)*(vdiv+1),P);
362 
363 	   // U stats
364 	   cP  =   P;
365 	   for (j=(vdiv+1);j>0;--j) {
366 
367 		   float	total	=	0;
368 		   for (i=udiv;i>0;--i,cP+=3) {
369 			   dx		=   cP[3 + COMP_X] - cP[COMP_X];
370 			   dy		=   cP[3 + COMP_Y] - cP[COMP_Y];
371 			   total	+=	sqrtf(dx*dx + dy*dy);
372 		   }
373 		   cP  +=  3;
374 		   uMax	=	max(uMax,total);
375 		   uMin	=	min(uMin,total);
376 	   }
377 
378 	   // V stats
379 	   cP  =   P;
380 	   for (i=(udiv+1);i>0;--i,cP+=3) {
381 		   nP  =   cP;
382 		   tP  =   nP  +   (udiv+1)*3;
383 		   float	total	=	0;
384 		   for (j=vdiv;j>0;--j,nP=tP,tP+=(udiv+1)*3) {
385 			   dx		=   tP[COMP_X] - nP[COMP_X];
386 			   dy		=   tP[COMP_Y] - nP[COMP_Y];
387 			   total	+=	sqrtf(dx*dx + dy*dy);
388 		   }
389 
390 		   vMax	=	max(vMax,total);
391 		   vMin	=	min(vMin,total);
392 	   }
393 	} else {	// non raster oriented
394 	   vector tmp;
395 
396 	   float maxDim = max(CRenderer::dPixeldx,CRenderer::dPixeldy);
397 	   	if(CRenderer::projection == OPTIONS_PROJECTION_PERSPECTIVE) {
398 			for (j=0;j<(vdiv+1)*(udiv+1);++j) {
399 				float x,y;
400 				x	=	(CRenderer::imagePlane*P[j*3+COMP_X]/P[j*3+COMP_Z]);
401 				y	=	(CRenderer::imagePlane*P[j*3+COMP_Y]/P[j*3+COMP_Z]);
402 				initv(tmp,x-P[j*3+COMP_X],y-P[j*3+COMP_Y],P[j*3+COMP_Z]-1);
403 				P[j*3+COMP_X]	=	x*maxDim;
404 				P[j*3+COMP_Y]	=	y*maxDim;
405 				P[j*3+COMP_Z]	=	lengthv(tmp)*maxDim;
406 			}
407 		} else {
408 			for (j=0;j<(vdiv+1)*(udiv+1);++j) {
409 				P[j*3+COMP_X]	=	P[j*3+COMP_X]*CRenderer::dPixeldx;
410 				P[j*3+COMP_Y]	=	P[j*3+COMP_Y]*CRenderer::dPixeldy;
411 				P[j*3+COMP_Z]	*=	maxDim;
412 			}
413 		}
414 
415 	   // U stats
416 	   cP  =   P;
417 	   for (j=(vdiv+1);j>0;--j) {
418 
419 		   float	total	=	0;
420 		   for (i=udiv;i>0;--i,cP+=3) {
421 			   subvv(tmp,cP+3,cP);
422 			   total	+=	lengthv(tmp);
423 		   }
424 		   cP  +=  3;
425 		   uMax	=	max(uMax,total);
426 		   uMin	=	min(uMin,total);
427 	   }
428 
429 	   // V stats
430 	   cP  =   P;
431 	   for (i=(udiv+1);i>0;--i,cP+=3) {
432 		   nP  =   cP;
433 		   tP  =   nP  +   (udiv+1)*3;
434 		   float	total	=	0;
435 		   for (j=vdiv;j>0;--j,nP=tP,tP+=(udiv+1)*3) {
436 			   subvv(tmp,tP,nP);
437 			   total	+=	lengthv(tmp);
438 		   }
439 
440 		   vMax	=	max(vMax,total);
441 		   vMin	=	min(vMin,total);
442 	   }
443 	}
444    float	udivf,vdivf;
445 
446    // Compute the new grid size based on the maximum size
447    udivf   =	uMax / shadingRate;
448    vdivf   =	vMax / shadingRate;
449 
450    // Clamp the division amount
451    udivf	=   max(1,udivf);
452    vdivf	=   max(1,vdivf);
453    udivf	=	min(10000,udivf);
454    vdivf	=	min(10000,vdivf);
455 
456    // Estimate the dicing amount
457    if (attributes->flags & ATTRIBUTES_FLAGS_BINARY_DICE) {
458 		const double	log2		=	log(2.0);
459 
460 		nudiv	=	1 << (unsigned int) (ceil(log(udivf) / log2));
461 		nvdiv	=	1 << (unsigned int) (ceil(log(vdivf) / log2));
462 	} else {
463 		nudiv   =   (int) ceil(udivf);
464 		nvdiv   =   (int) ceil(vdivf);
465 	}
466 }
467 
468 
469 
470 
471 
472 
473 
474 ///////////////////////////////////////////////////////////////////////
475 // Class				:	CDummyObject
476 // Method				:	CDummyObject
477 // Description			:	Ctor
478 // Return Value			:
479 // Comments				:
CDummyObject(CAttributes * a,CXform * x)480 CDummyObject::CDummyObject(CAttributes *a,CXform *x) : CObject(a,x) {
481 	flags	|=	OBJECT_DUMMY;
482 }
483 
484 ///////////////////////////////////////////////////////////////////////
485 // Class				:	CDummyObject
486 // Method				:	~CDummyObject
487 // Description			:	Dtor
488 // Return Value			:
489 // Comments				:
~CDummyObject()490 CDummyObject::~CDummyObject() {
491 }
492 
493 ///////////////////////////////////////////////////////////////////////
494 // Class				:	CDummyObject
495 // Method				:	intersect
496 // Description			:	Intersect a ray
497 // Return Value			:
498 // Comments				:
intersect(CShadingContext *,CRay *)499 void			CDummyObject::intersect(CShadingContext *,CRay *) {
500 	// Should never reach this point
501 	//assert(FALSE);
502 }
503 
504 
505 
506 
507 
508 
509 
510 
511 
512 ///////////////////////////////////////////////////////////////////////
513 // Class				:	CSurface
514 // Method				:	intersect
515 // Description			:	Intersect the surface
516 // Return Value			:
517 // Comments				:
intersect(CShadingContext * context,CRay * cRay)518 void				CSurface::intersect(CShadingContext *context,CRay *cRay) {
519 
520 	if (! (cRay->flags & attributes->flags) )	return;
521 
522 	if (attributes->flags & ATTRIBUTES_FLAGS_LOD) {
523 		const float importance = attributes->lodImportance;
524 		if (importance >= 0) {
525 			if (cRay->jimp > importance)			return;
526 		} else {
527 			if ((1-cRay->jimp) >= -importance)		return;
528 		}
529 	}
530 
531 	// Do we have a grid ?
532 	if (children == NULL) {
533 		// Intersect with our bounding box
534 		float t = nearestBox(bmin,bmax,cRay->from,cRay->invDir,cRay->tmin,cRay->t);
535 
536 		// Bail out if the hit point is already further than the ray got
537 		// Note: this avoids unneeded top level tesselations
538 		if (!(t < cRay->t)) return;
539 
540 		// We must lock the tesselateMutex so that the list of known tesselation patches
541 		// is maintained in a thread safe manner
542 		osLock(CRenderer::tesselateMutex);
543 
544 		if (children == NULL) {
545 
546 			CTesselationPatch	*tesselation	=	new CTesselationPatch(attributes,xform,this,0,1,0,1,0,0,-1);
547 
548 			tesselation->initTesselation(context);
549 			tesselation->attach();
550 			children				=	tesselation;
551 		}
552 
553 		osUnlock(CRenderer::tesselateMutex);
554 	}
555 }
556 
557 ///////////////////////////////////////////////////////////////////////
558 // Class				:	CSurface
559 // Method				:	dice
560 // Description			:	Dice the object into smaller ones
561 // Return Value			:
562 // Comments				:
dice(CShadingContext * rasterizer)563 void				CSurface::dice(CShadingContext *rasterizer) {
564 
565 	int minU,minV;
566 	int minSplits = max(attributes->minSplits,getDicingStats(0,minU,minV));
567 
568 	CPatch	*cSurface	=	new CPatch(attributes,xform,this,0,1,0,1,0,minSplits);
569 	cSurface->attach();
570 	cSurface->dice(rasterizer);
571 	cSurface->detach();
572 
573 	// Note we tesselate for raytracing on demand - so we do not automatically emit a CTesselationPatch here
574 }
575 
576 ///////////////////////////////////////////////////////////////////////
577 // Class				:	CSurface
578 // Method				:	moving
579 // Description			:	TRUE if the object is moving
580 // Return Value			:
581 // Comments				:
moving() const582 int					CSurface::moving() const {
583 	return FALSE;
584 }
585 
586 ///////////////////////////////////////////////////////////////////////
587 // Class				:	CSurface
588 // Method				:	sample
589 // Description			:	Sample a bunch of points on the surface
590 // Return Value			:	TRUE if the sampling was done and shaders need to be executed
591 // Comments				:
sample(int,int,float **,float ***,unsigned int &) const592 void				CSurface::sample(int,int,float **,float ***,unsigned int &) const {
593 	error(CODE_BUG,"An object is missing the \"sample\" function\n");
594 	assert(FALSE);
595 }
596 
597 ///////////////////////////////////////////////////////////////////////
598 // Class				:	CSurface
599 // Method				:	interpolate
600 // Description			:	Interpolate the varying data and set the uniform data
601 // Return Value			:
602 // Comments				:
interpolate(int,float **,float ***) const603 void				CSurface::interpolate(int,float **,float ***)	const {
604 	error(CODE_BUG,"An object is missing the \"interpolate\" function\n");
605 	assert(FALSE);
606 }
607 
608 
609 ///////////////////////////////////////////////////////////////////////
610 // Class				:	CSurface
611 // Method				:	split
612 // Description			:	Split an object
613 // Return Value			:
614 // Comments				:
shade(CShadingContext * context,int numRays,CRay ** rays)615 void				CSurface::shade(CShadingContext *context,int numRays,CRay **rays) {
616 	float	**varying	=	context->currentShadingState->varying;
617 	float	*u			=	varying[VARIABLE_U];
618 	float	*v			=	varying[VARIABLE_V];
619 	float	*time		=	varying[VARIABLE_TIME];
620 	float	*I			=	varying[VARIABLE_I];
621 	float	*du			=	varying[VARIABLE_DU];
622 	int		i;
623 
624 	for (i=numRays;i>0;i--) {
625 		const CRay	*cRay	=	*rays++;
626 
627 		*u++	=	cRay->u;						// The intersection u
628 		*v++	=	cRay->v;						// The intersection v
629 		*time++	=	cRay->time;						// The intersection time
630 		*du++	=	cRay->da*cRay->t + cRay->db;	// The ray differential
631 		mulvf(I,cRay->dir,cRay->t);					// Compute the I vector
632 		I		+=	3;
633 	}
634 
635 	context->shade(this,numRays,1,SHADING_2D,0);
636 }
637 
638 
639 
640