////////////////////////////////////////////////////////////////////// // // Pixie // // Copyright © 1999 - 2003, Okan Arikan // // Contact: okan@cs.berkeley.edu // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // // File : quadrics.cpp // Classes : CSphere // CDisk // CCone ... // Description : Implementation // // FIXME: The quadrics implementation has not been heavily optimized // FIXME: Re-optimize //////////////////////////////////////////////////////////////////////// #include #include "quadrics.h" #include "renderer.h" #include "common/os.h" #include "object.h" #include "stats.h" #include "memory.h" #include "shading.h" #define checkRay(rv) \ if (! (rv->flags & attributes->flags) ) return; \ \ if (attributes->flags & ATTRIBUTES_FLAGS_LOD) { \ const float importance = attributes->lodImportance; \ if (rv->jimp < 0) rv->jimp = urand(); \ if (importance >= 0) { \ if (rv->jimp > importance) return; \ } else { \ if ((1-rv->jimp) >= -importance) return; \ } \ } \ \ if (rv->lastXform != xform) { \ if (xform->next != NULL) { \ vector tmp[4]; \ vector to; \ addvv(to,rv->from,rv->dir); \ \ mulmp(tmp[0],xform->to,rv->from); \ mulmp(tmp[1],xform->to,to); \ \ mulmp(tmp[2],xform->next->to,rv->from); \ mulmp(tmp[3],xform->next->to,to); \ \ interpolatev(rv->oFrom,tmp[0],tmp[2],rv->time); \ interpolatev(rv->oTo,tmp[1],tmp[3],rv->time); \ subvv(rv->oDir,rv->oTo,rv->oFrom); \ } else { \ vector to; \ addvv(to,rv->from,rv->dir); \ \ mulmp(rv->oFrom,xform->to,rv->from); \ mulmp(rv->oTo,xform->to,to); \ subvv(rv->oDir,rv->oTo,rv->oFrom); \ } \ \ rv->lastXform = xform; \ } #define transformPoints() \ if ((xform->next != NULL) && (!(up & (PARAMETER_BEGIN_SAMPLE | PARAMETER_END_SAMPLE)))) { \ \ transform(&varying[VARIABLE_P][start*3],numVertices,xform->from,xform->next->from,&varying[VARIABLE_TIME][start]); \ \ if (up & PARAMETER_DPDU) { \ vtransform(&varying[VARIABLE_DPDU][start*3],numVertices,xform->from,xform->next->from,&varying[VARIABLE_TIME][start]); \ } \ \ if (up & PARAMETER_DPDV) { \ vtransform(&varying[VARIABLE_DPDV][start*3],numVertices,xform->from,xform->next->from,&varying[VARIABLE_TIME][start]); \ } \ \ if (up & PARAMETER_NG) { \ ntransform(&varying[VARIABLE_NG][start*3],numVertices,xform->to,xform->next->to,&varying[VARIABLE_TIME][start]); \ } \ } else { \ float *from = xform->from; \ float *to = xform->to; \ \ if ((up & PARAMETER_END_SAMPLE) && (xform->next != NULL)) { \ from = xform->next->from; \ to = xform->next->to; \ } \ \ \ transform(&varying[VARIABLE_P][start*3],numVertices,from); \ \ if (up & PARAMETER_DPDU) { \ vtransform(&varying[VARIABLE_DPDU][start*3],numVertices,from); \ } \ \ if (up & PARAMETER_DPDV) { \ vtransform(&varying[VARIABLE_DPDV][start*3],numVertices,from); \ } \ \ if (up & PARAMETER_NG) { \ ntransform(&varying[VARIABLE_NG][start*3],numVertices,to); \ } \ } #define normalFix() { \ float *Ng = varying[VARIABLE_NG]; \ int i; \ \ for (i=numVertices;i>0;i--,Ng+=3) { \ if (dotvv(Ng,Ng) == 0) { \ const float *u = varying[VARIABLE_U]; \ const float *v = varying[VARIABLE_V]; \ const float *cNg = varying[VARIABLE_NG]; \ const float cu = u[numVertices-i]; \ const float cv = v[numVertices-i]; \ float cd = C_INFINITY; \ const float *closest; \ int j; \ \ for (j=numVertices;j>0;j--,cNg+=3,u++,v++) { \ if (dotvv(cNg,cNg) > 0) { \ const float du = cu - u[0]; \ const float dv = cv - v[0]; \ float d; \ \ d = du*du + dv*dv; \ if (d < cd) { \ cd = d; \ closest = cNg; \ } \ } \ } \ \ assert(cd < C_INFINITY); \ movvv(Ng,closest); \ } \ } \ } //////////////////////////////////////////// S P H E R E /////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // Class : CSphere // Method : CSphere // Description : Ctor // Return Value : - // Comments : // Date last edited : 3/17/2001 CSphere::CSphere(CAttributes *a,CXform *x,CParameter *c,unsigned int pf,float ra,float vmina,float vmaxa,float anglea) : CSurface(a,x) { stats.gprimMemory += sizeof(CSphere); stats.numGprims++; r = ra; vmin = vmina; vmax = vmaxa; umax = anglea; parameters = c; parametersF = PARAMETER_P | PARAMETER_NG | PARAMETER_DPDU | PARAMETER_DPDV | pf; nextData = NULL; computeObjectBound(bmin,bmax,r,vmin,vmax,umax); xform->transformBound(bmin,bmax); makeBound(bmin,bmax); } /////////////////////////////////////////////////////////////////////// // Class : CSphere // Method : CSphere // Description : Ctor // Return Value : - // Comments : // Date last edited : 3/17/2001 CSphere::CSphere(CAttributes *a,CXform *x,CParameter *c,unsigned int pf,float r0,float vmin0,float vmax0,float angle0,float r1,float vmin1,float vmax1,float angle1) : CSurface(a,x) { vector tbmin,tbmax; stats.gprimMemory += sizeof(CSphere); stats.gprimMemory += sizeof(float)*4; stats.numGprims++; r = r0; vmin = vmin0; vmax = vmax0; umax = angle0; parameters = c; parametersF = PARAMETER_P | PARAMETER_NG | PARAMETER_DPDU | PARAMETER_DPDV | pf; nextData = new float[4]; nextData[0] = r1; nextData[1] = vmin1; nextData[2] = vmax1; nextData[3] = angle1; computeObjectBound(bmin,bmax,r,vmin,vmax,umax); computeObjectBound(tbmin,tbmax,nextData[0],nextData[1],nextData[2],nextData[3]); addBox(bmin,bmax,tbmin); addBox(bmin,bmax,tbmax); xform->transformBound(bmin,bmax); makeBound(bmin,bmax); } /////////////////////////////////////////////////////////////////////// // Class : CSphere // Method : ~CSphere // Description : Dtor // Return Value : - // Comments : // Date last edited : 3/17/2001 CSphere::~CSphere() { stats.gprimMemory -= sizeof(CSphere); stats.gprimMemory -= (nextData != NULL ? 4*sizeof(float) : 0); stats.numGprims--; if (parameters != NULL) delete parameters; if (nextData != NULL) delete [] nextData; } /////////////////////////////////////////////////////////////////////// // Class : CSphere // Method : tesselate // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CSphere::tesselate(CShadingContext *context) { if ((attributes->flags & ATTRIBUTES_FLAGS_DISPLACEMENTS) || (context->flags & OPTIONS_FLAGS_USE_RADIANCE_CACHE)) context->tesselate2D(this); else context->addTracable(this,this); } /////////////////////////////////////////////////////////////////////// // Class : CSphere // Method : intersect // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 int CSphere::intersect(const float *bmin,const float *bmax) const { //FIXME: a more accurate intersection computation is possible return intersectBox(bmin,bmax,this->bmin,this->bmax); } /////////////////////////////////////////////////////////////////////// // Class : CSphere // Method : intersect // Description : Compute the intersection with a ray // Return Value : TRUE if intersects // Comments : // Date last edited : 3/17/2001 void CSphere::intersect(CRay *rv) { unsigned int ns,i; double s[2]; double r,umax,vmin,vmax; checkRay(rv); if (nextData != NULL) { r = this->r * (1-rv->time) + nextData[0] * rv->time; vmin = this->vmin * (1-rv->time) + nextData[1] * rv->time; vmax = this->vmax * (1-rv->time) + nextData[2] * rv->time; umax = this->umax * (1-rv->time) + nextData[3] * rv->time; } else { r = this->r; vmin = this->vmin; vmax = this->vmax; umax = this->umax; } const double a = dotvv(rv->oDir,rv->oDir); const double b = 2*dotvv(rv->oDir,rv->oFrom); const double c = dotvv(rv->oFrom,rv->oFrom) - r*r; if ((ns = solveQuadric(a,b,c,s)) == 0) return; for (i=0;itmin) continue; if (t >= rv->t) return; P[0] = rv->oDir[0]*t + rv->oFrom[0]; P[1] = rv->oDir[1]*t + rv->oFrom[1]; P[2] = rv->oDir[2]*t + rv->oFrom[2]; if (r > 0) { u = atan2(P[COMP_Y],P[COMP_X]); if (P[COMP_Z] < -r) P[COMP_Z] = -r; if (P[COMP_Z] > r) P[COMP_Z] = r; } else { u = atan2(-P[COMP_Y],-P[COMP_X]); if (P[COMP_Z] < r) P[COMP_Z] = r; if (P[COMP_Z] > -r) P[COMP_Z] = -r; } if (u < 0) u = 2*C_PI + u; if (umax < 0) { u = u - 2*C_PI; if (u < umax) continue; } else { if (u > umax) continue; } v = asin(P[COMP_Z] / r); v = (v - vmin) / (vmax - vmin); if (v < 0) continue; if (v > 1) continue; const double f = r*umax*(vmax-vmin); P[0] *= f; P[1] *= f; P[2] *= f; if ((attributes->flags & ATTRIBUTES_FLAGS_INSIDE) ^ xform->flip) { P[0] = -P[0]; P[1] = -P[1]; P[2] = -P[2]; } if (attributes->nSides == 1) { if ((rv->oDir[0]*P[0] + rv->oDir[1]*P[1] + rv->oDir[2]*P[2]) > 0) continue; } tmp[0] = (float) P[0]; tmp[1] = (float) P[1]; tmp[2] = (float) P[2]; rv->object = this; rv->u = (float) (u / umax); rv->v = (float) v; rv->t = (float) t; mulmn(rv->N,xform->to,tmp); return; } } /////////////////////////////////////////////////////////////////////// // Class : CSphere // Method : bound // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CSphere::bound(float *bmin,float *bmax) const { movvv(bmin,this->bmin); movvv(bmax,this->bmax); } /////////////////////////////////////////////////////////////////////// // Class : CSphere // Method : sample // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CSphere::sample(int start,int numVertices,float **varying,unsigned int &up) const { int currentVertex; float *dest; const float *u = varying[VARIABLE_U] + start; const float *v = varying[VARIABLE_V] + start; float *sinu; float *cosu; float *sinv; float *cosv; float *memBase; memBegin(); memBase = (float *) ralloc(numVertices*4*sizeof(float)); sinu = memBase; cosu = sinu + numVertices; sinv = cosu + numVertices; cosv = sinv + numVertices; if ((nextData != NULL) && (!(up & (PARAMETER_BEGIN_SAMPLE | PARAMETER_END_SAMPLE)))) { const float *time = &varying[VARIABLE_TIME][start]; float *r,*umax,*vmax,*vmin; memBase = (float *) ralloc(numVertices*4*sizeof(float)); r = memBase; umax = r + numVertices; vmax = umax + numVertices; vmin = vmax + numVertices; dest = varying[VARIABLE_P] + start; // Precompute sinu cosu sinv and cosv for (currentVertex = 0; currentVertex < numVertices; currentVertex++) { const float ctime = *time++; const float cumax = umax[currentVertex] = this->umax * (1 - ctime) + nextData[3] * ctime; const float cvmax = vmax[currentVertex] = this->vmax * (1 - ctime) + nextData[2] * ctime; const float cvmin = vmin[currentVertex] = this->vmin * (1 - ctime) + nextData[1] * ctime; r[currentVertex] = this->r * (1 - ctime) + nextData[0] * ctime; // Precompute sinu cosu sinv and cosv const float cu = *u++; const float cv = *v++; const float uAngle = cumax*cu; const float vAngle = cvmax*cv + cvmin*(1-cv); sinu[currentVertex] = sinf(uAngle); cosu[currentVertex] = cosf(uAngle); sinv[currentVertex] = sinf(vAngle); cosv[currentVertex] = cosf(vAngle); const float tmp = r[currentVertex]*cosv[currentVertex]; dest[COMP_Z] = r[currentVertex]*sinv[currentVertex]; dest[COMP_X] = tmp*cosu[currentVertex]; dest[COMP_Y] = tmp*sinu[currentVertex]; dest += 3; } // Set dPdu if (up & PARAMETER_DPDU) { float *src = &varying[VARIABLE_P][start*3]; dest = &varying[VARIABLE_DPDU][start*3]; for (currentVertex = 0; currentVertex < numVertices; currentVertex++) { dest[COMP_X] = -umax[currentVertex]*src[COMP_Y]; dest[COMP_Y] = umax[currentVertex]*src[COMP_X]; dest[COMP_Z] = 0; dest += 3; src += 3; } } // Set dPdv if (up & PARAMETER_DPDV) { dest = &varying[VARIABLE_DPDV][start*3]; for (currentVertex = 0; currentVertex < numVertices; currentVertex++) { dest[COMP_X] = -r[currentVertex]*cosu[currentVertex]*sinv[currentVertex]*(vmax[currentVertex]-vmin[currentVertex]); dest[COMP_Y] = -r[currentVertex]*sinu[currentVertex]*sinv[currentVertex]*(vmax[currentVertex]-vmin[currentVertex]); dest[COMP_Z] = r[currentVertex]*cosv[currentVertex]*(vmax[currentVertex]-vmin[currentVertex]); dest += 3; } } } else { float r = this->r; float umax = this->umax; float vmin = this->vmin; float vmax = this->vmax; if ((up & PARAMETER_END_SAMPLE) && (nextData != NULL)) { r = nextData[0]; vmin = nextData[1]; vmax = nextData[2]; umax = nextData[3]; } // Precompute sinu cosu sinv and cosv dest = &varying[VARIABLE_P][start*3]; for (currentVertex = 0; currentVertex < numVertices; currentVertex++) { const float uAngle = umax*u[currentVertex]; const float vAngle = vmax*v[currentVertex] + vmin*(1-v[currentVertex]); sinu[currentVertex] = sinf(uAngle); cosu[currentVertex] = cosf(uAngle); sinv[currentVertex] = sinf(vAngle); cosv[currentVertex] = cosf(vAngle); const float tmp = r*cosv[currentVertex]; dest[COMP_Z] = r*sinv[currentVertex]; dest[COMP_X] = tmp*cosu[currentVertex]; dest[COMP_Y] = tmp*sinu[currentVertex]; dest += 3; } // Set dPdu if (up & PARAMETER_DPDU) { const float *src = &varying[VARIABLE_P][start*3]; dest = &varying[VARIABLE_DPDU][start*3]; for (currentVertex = 0; currentVertex < numVertices; currentVertex++) { dest[COMP_X] = -umax*src[COMP_Y]; dest[COMP_Y] = umax*src[COMP_X]; dest[COMP_Z] = 0; dest += 3; src += 3; } } // Set dPdv if (up & PARAMETER_DPDV) { dest = &varying[VARIABLE_DPDV][start*3]; for (currentVertex = 0; currentVertex < numVertices; currentVertex++) { dest[COMP_X] = -r*cosu[currentVertex]*sinv[currentVertex]*(vmax-vmin); dest[COMP_Y] = -r*sinu[currentVertex]*sinv[currentVertex]*(vmax-vmin); dest[COMP_Z] = r*cosv[currentVertex]*(vmax-vmin); dest += 3; } } } // Set Ng if (up & PARAMETER_NG) { float *N = varying[VARIABLE_NG] + start*3; const float *P = varying[VARIABLE_P] + start*3; float f = r*umax*(vmax-vmin); if (xform->flip) f *= -1; for (int i=numVertices;i>0;i--,N+=3,P+=3) { mulvf(N,P,f); } } // Transform the points transformPoints(); up &= ~parametersF; memEnd(); } /////////////////////////////////////////////////////////////////////// // Class : CSphere // Method : interpolate // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CSphere::interpolate(int numVertices,float **varying) const { if (parameters != NULL) parameters->dispatch(numVertices,varying); } /////////////////////////////////////////////////////////////////////// // Class : CSphere // Method : copy // Description : See object.h // Return Value : - // Comments : // Date last edited : 6/11/2003 void CSphere::copy(CAttributes *a,CXform *x,CRendererContext *cx) const { CXform *nx = new CXform(x); nx->concat(xform); // Concetenate the local xform if (a == NULL) a = attributes; if (nextData == NULL) cx->addObject(new CSphere(a,nx,(parameters == NULL ? NULL : parameters->clone()),parametersF,r,vmin,vmax,umax)); else cx->addObject(new CSphere(a,nx,(parameters == NULL ? NULL : parameters->clone()),parametersF,r,vmin,vmax,umax,nextData[0],nextData[1],nextData[2],nextData[3])); } /////////////////////////////////////////////////////////////////////// // Class : CSphere // Method : computeObjectBound // Description : Compute the bounding box in the object space // Return Value : - // Comments : // Date last edited : 3/17/2001 void CSphere::computeObjectBound(float *bmin,float *bmax,float r,float vmin,float vmax,float umax) { float maxRadius; float vmi = min(vmin,vmax); float vma = max(vmin,vmax); float zmin; float zmax; r = absf(r); zmin = r*sinf(vmin); zmax = r*sinf(vmax); if (vmi > 0) { maxRadius = (float) cos(vmi)*r; } else if (vma < 0) { maxRadius = (float) cos(vma)*r; } else { maxRadius = r; } initv(bmin,-maxRadius,-maxRadius,min(zmin,zmax)); initv(bmax,maxRadius,maxRadius,max(zmin,zmax)); } //////////////////////////////////////////// D I S K /////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // Class : CDisk // Method : CDisk // Description : Ctor // Return Value : - // Comments : // Date last edited : 3/17/2001 CDisk::CDisk(CAttributes *a,CXform *x,CParameter *c,unsigned int pf,float ra,float za,float anglea) : CSurface(a,x) { stats.gprimMemory += sizeof(CDisk); stats.numGprims++; r = ra; z = za; umax = anglea; parameters = c; parametersF = PARAMETER_P | PARAMETER_NG | PARAMETER_DPDU | PARAMETER_DPDV | pf; nextData = NULL; computeObjectBound(bmin,bmax,r,z,umax); xform->transformBound(bmin,bmax); makeBound(bmin,bmax); } /////////////////////////////////////////////////////////////////////// // Class : CDisk // Method : CDisk // Description : Ctor // Return Value : - // Comments : // Date last edited : 3/17/2001 CDisk::CDisk(CAttributes *a,CXform *x,CParameter *c,unsigned int pf,float r0,float z0,float angle0,float r1,float z1,float angle1) : CSurface(a,x) { vector tbmin,tbmax; stats.gprimMemory += sizeof(CDisk); stats.gprimMemory += sizeof(float)*3; stats.numGprims++; r = r0; z = z0; umax = angle0; parameters = c; parametersF = PARAMETER_P | PARAMETER_NG | PARAMETER_DPDU | PARAMETER_DPDV | pf; nextData = new float[3]; nextData[0] = r1; nextData[1] = z1; nextData[2] = angle1; computeObjectBound(bmin,bmax,r,z,umax); computeObjectBound(tbmin,tbmax,nextData[0],nextData[1],nextData[2]); addBox(bmin,bmax,tbmin); addBox(bmin,bmax,tbmax); xform->transformBound(bmin,bmax); makeBound(bmin,bmax); } /////////////////////////////////////////////////////////////////////// // Class : CDisk // Method : ~CDisk // Description : Dtor // Return Value : - // Comments : // Date last edited : 3/17/2001 CDisk::~CDisk() { stats.gprimMemory -= sizeof(CDisk); stats.gprimMemory -= (nextData != NULL ? 3*sizeof(float) : 0); stats.numGprims--; if (parameters != NULL) delete parameters; if (nextData != NULL) delete [] nextData; } /////////////////////////////////////////////////////////////////////// // Class : CDisk // Method : tesselate // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CDisk::tesselate(CShadingContext *context) { if ((attributes->flags & ATTRIBUTES_FLAGS_DISPLACEMENTS) || (context->flags & OPTIONS_FLAGS_USE_RADIANCE_CACHE)) context->tesselate2D(this); else context->addTracable(this,this); } /////////////////////////////////////////////////////////////////////// // Class : CDisk // Method : intersect // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 int CDisk::intersect(const float *bmin,const float *bmax) const { //FIXME: a more accurate intersection computation is possible return intersectBox(bmin,bmax,this->bmin,this->bmax); } /////////////////////////////////////////////////////////////////////// // Class : CDisk // Method : intersect // Description : Compute the intersection with a ray // Return Value : TRUE if intersects // Comments : // Date last edited : 3/17/2001 void CDisk::intersect(CRay *rv) { float t; double u; double x,y; double r,z,umax; vector Nt; checkRay(rv); // Convert to the object coordinate system if (nextData != NULL) { r = this->r * (1-rv->time) + nextData[0] * rv->time; z = this->z * (1-rv->time) + nextData[1] * rv->time; umax = this->umax * (1-rv->time) + nextData[2] * rv->time; } else { r = this->r; z = this->z; umax = this->umax; } t = (float) (z - rv->oFrom[COMP_Z])/rv->oDir[COMP_Z]; if ((t <= rv->tmin) || (t >= rv->t)) return; x = rv->oFrom[COMP_X] + rv->oDir[COMP_X]*t; y = rv->oFrom[COMP_Y] + rv->oDir[COMP_Y]*t; if ((x*x+y*y) > r*r) return; if (r < 0) u = atan2(-y,-x); else u = atan2(y,x); if (u < 0) u = 2*C_PI + u; if (umax < 0) { u = u - 2*C_PI; if (u < umax) return; } else { if (u > umax) return; } initv(Nt,0,0,(float) umax); if ((attributes->flags & ATTRIBUTES_FLAGS_INSIDE) ^ xform->flip) { mulvf(Nt,-1); } if (attributes->nSides == 1) { if (dotvv(rv->oDir,Nt) > 0) { return; } } rv->object = this; rv->u = (float) (u / umax); if (r > 0) { rv->v = (float) (((r-sqrt(x*x + y*y))) / r); } else { rv->v = (float) (((r+sqrt(x*x + y*y))) / r); } rv->t = (float) t; mulmn(rv->N,xform->to,Nt); } /////////////////////////////////////////////////////////////////////// // Class : CDisk // Method : bound // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CDisk::bound(float *bmin,float *bmax) const { movvv(bmin,this->bmin); movvv(bmax,this->bmax); } /////////////////////////////////////////////////////////////////////// // Class : CDisk // Method : sample // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CDisk::sample(int start,int numVertices,float **varying,unsigned int &up) const { float *sinu; float *cosu; int i; const float *u = &varying[VARIABLE_U][start]; const float *v = &varying[VARIABLE_V][start]; float *dest; float *memBase; memBegin(); // Allocate memory for precomputing sin(u) , cos(u) memBase = (float *) ralloc(numVertices*2*sizeof(float)); sinu = memBase; cosu = sinu + numVertices; if ((nextData != NULL) && (!(up & (PARAMETER_BEGIN_SAMPLE | PARAMETER_END_SAMPLE)))) { const float *time = &varying[VARIABLE_TIME][start]; float *r; float *z; float *umax; memBase = (float *) ralloc(numVertices*3*sizeof(float)); r = memBase; z = r + numVertices; umax = z + numVertices; dest = varying[VARIABLE_P] + start*3; // Precompute sinu cosu sinv and cosv for (i=0;ir * (1 - ctime) + nextData[0] * ctime; z[i] = this->z * (1 - ctime) + nextData[1] * ctime; umax[i] = this->umax * (1 - ctime) + nextData[2] * ctime; cosu[i] = cosf(u[i]*umax[i]); sinu[i] = sinf(u[i]*umax[i]); dest[COMP_X] = r[i]*(1-v[i])*cosu[i]; dest[COMP_Y] = r[i]*(1-v[i])*sinu[i]; dest[COMP_Z] = z[i]; } // Set dPdu/dPdv if needed if (up & (PARAMETER_DPDU | PARAMETER_DPDU)) { float *dPdu = &varying[VARIABLE_DPDU][start*3]; float *dPdv = &varying[VARIABLE_DPDV][start*3]; for (i=0;ir; float z = this->z; float umax = this->umax; if ((up & PARAMETER_END_SAMPLE) && (nextData != NULL)) { r = nextData[0]; z = nextData[1]; umax = nextData[2]; } // Precompute the sin/cos for u points dest = varying[VARIABLE_P] + start*3; for (i=0;iflip) f = -umax; for (i=numVertices;i>0;i--,Ng+=3) { initv(Ng,0,0,f); } } // Transform the points transformPoints(); up &= ~parametersF; memEnd(); } /////////////////////////////////////////////////////////////////////// // Class : CDisk // Method : interpolate // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CDisk::interpolate(int numVertices,float **varying) const { if (parameters != NULL) parameters->dispatch(numVertices,varying); } /////////////////////////////////////////////////////////////////////// // Class : CDisk // Method : copy // Description : See object.h // Return Value : - // Comments : // Date last edited : 6/11/2003 void CDisk::copy(CAttributes *a,CXform *x,CRendererContext *cx) const { CXform *nx = new CXform(x); nx->concat(xform); // Concetenate the local xform if (a == NULL) a = attributes; if (nextData == NULL) cx->addObject(new CDisk(a,nx,parameters,parametersF,r,z,umax)); else cx->addObject(new CDisk(a,nx,parameters,parametersF,r,z,umax,nextData[0],nextData[1],nextData[2])); } /////////////////////////////////////////////////////////////////////// // Class : CDisk // Method : computeObjectBound // Description : Compute the bounding box in the object space // Return Value : - // Comments : // Date last edited : 3/17/2001 void CDisk::computeObjectBound(float *bmin,float *bmax,float r,float z,float umax) { r = absf(r); initv(bmin,-r,-r,z); initv(bmax,r,r,z); } //////////////////////////////////////////// C O N E /////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // Class : CCone // Method : CCone // Description : Ctor // Return Value : - // Comments : // Date last edited : 3/17/2001 CCone::CCone(CAttributes *a,CXform *x,CParameter *c,unsigned int pf,float ra,float heighta,float anglea) : CSurface(a,x) { stats.gprimMemory += sizeof(CCone); stats.numGprims++; r = ra; height = heighta; umax = anglea; parameters = c; parametersF = PARAMETER_P | PARAMETER_NG | PARAMETER_DPDU | PARAMETER_DPDV | pf; nextData = NULL; computeObjectBound(bmin,bmax,r,height,umax); xform->transformBound(bmin,bmax); makeBound(bmin,bmax); } /////////////////////////////////////////////////////////////////////// // Class : CCone // Method : CCone // Description : Ctor // Return Value : - // Comments : // Date last edited : 3/17/2001 CCone::CCone(CAttributes *a,CXform *x,CParameter *c,unsigned int pf,float r0,float height0,float angle0,float r1,float height1,float angle1) : CSurface(a,x) { vector tbmin,tbmax; stats.gprimMemory += sizeof(CCone); stats.gprimMemory += sizeof(float)*3; stats.numGprims++; r = r0; height = height0; umax = angle0; parameters = c; parametersF = PARAMETER_P | PARAMETER_NG | PARAMETER_DPDU | PARAMETER_DPDV | pf; nextData = new float[3]; nextData[0] = r1; nextData[1] = height1; nextData[2] = angle1; computeObjectBound(bmin,bmax,r,height,umax); computeObjectBound(tbmin,tbmax,nextData[0],nextData[1],nextData[2]); addBox(bmin,bmax,tbmin); addBox(bmin,bmax,tbmax); xform->transformBound(bmin,bmax); makeBound(bmin,bmax); } /////////////////////////////////////////////////////////////////////// // Class : CCone // Method : ~CCone // Description : Dtor // Return Value : - // Comments : // Date last edited : 3/17/2001 CCone::~CCone() { stats.gprimMemory -= sizeof(CCone); stats.gprimMemory -= (nextData != NULL ? 3*sizeof(float) : 0); stats.numGprims--; if (parameters != NULL) delete parameters; if (nextData != NULL) delete [] nextData; } /////////////////////////////////////////////////////////////////////// // Class : CCone // Method : tesselate // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CCone::tesselate(CShadingContext *context) { if ((attributes->flags & ATTRIBUTES_FLAGS_DISPLACEMENTS) || (context->flags & OPTIONS_FLAGS_USE_RADIANCE_CACHE)) context->tesselate2D(this); else context->addTracable(this,this); } /////////////////////////////////////////////////////////////////////// // Class : CCone // Method : intersect // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 int CCone::intersect(const float *bmin,const float *bmax) const { //FIXME: a more accurate intersection computation is possible return intersectBox(bmin,bmax,this->bmin,this->bmax); } /////////////////////////////////////////////////////////////////////// // Class : CCone // Method : intersect // Description : Compute the intersection with a ray // Return Value : TRUE if intersects // Comments : // Date last edited : 3/17/2001 void CCone::intersect(CRay *rv) { float *from; float *dir; double s[2]; unsigned int ns,i; double height,r,umax; vector Nt; checkRay(rv); from = rv->oFrom; dir = rv->oDir; if (nextData != NULL) { r = this->r * (1-rv->time) + nextData[0] * rv->time; height = this->height * (1-rv->time) + nextData[1] * rv->time; umax = this->umax * (1-rv->time) + nextData[2] * rv->time; } else { r = this->r; height = this->height; umax = this->umax; } if (height*height < C_EPSILON) { // We're a disc ns = 1; s[0] = -from[COMP_Z] / dir[COMP_Z]; } else { const double a = height*height*(dir[COMP_X]*dir[COMP_X] + dir[COMP_Y]*dir[COMP_Y]) - r*r*dir[COMP_Z]*dir[COMP_Z]; const double b = height*height*2*(from[COMP_X]*dir[COMP_X] + from[COMP_Y]*dir[COMP_Y]) - r*r*2*(from[COMP_Z]-height)*dir[COMP_Z]; const double c = height*height*(from[COMP_X]*from[COMP_X] + from[COMP_Y]*from[COMP_Y]) - r*r*(from[COMP_Z]-height)*(from[COMP_Z]-height); if ((ns = solveQuadric(a,b,c,s)) == 0) return; } for (i=0;itmin) continue; if (t >= rv->t) return; P[COMP_Z] = rv->oDir[COMP_Z]*t + rv->oFrom[COMP_Z]; if (height < 0) { if (P[COMP_Z] < height) continue; if (P[COMP_Z] > 0) continue; } else if (height > 0) { if (P[COMP_Z] > height) continue; if (P[COMP_Z] < 0) continue; } P[COMP_X] = rv->oDir[COMP_X]*t + rv->oFrom[COMP_X]; P[COMP_Y] = rv->oDir[COMP_Y]*t + rv->oFrom[COMP_Y]; if (r > 0) u = atan2(P[COMP_Y],P[COMP_X]); else u = atan2(-P[COMP_Y],-P[COMP_X]); if (u < 0) u = 2*C_PI + u; if (umax < 0) { u = u - 2*C_PI; if (u < umax) { continue; } } else { if (u > umax) { continue; } } if (r*r > height*height) v = 1 - sqrt((P[COMP_X]*P[COMP_X] + P[COMP_Y]*P[COMP_Y]) / (r*r)); else v = P[COMP_Z] / height; if (v < 0) { continue; } Nt[COMP_X] = (float) (P[COMP_X]*height*umax); Nt[COMP_Y] = (float) (P[COMP_Y]*height*umax); Nt[COMP_Z] = (float) (r*r*umax*(1 - v)); if ((attributes->flags & ATTRIBUTES_FLAGS_INSIDE) ^ xform->flip) { mulvf(Nt,-1); } if (attributes->nSides == 1) { if (dotvv(rv->oDir,Nt) > 0) { continue; } } rv->object = this; rv->u = (float) (u / umax); rv->v = (float) v; rv->t = (float) t; mulmn(rv->N,xform->to,Nt); return; } } /////////////////////////////////////////////////////////////////////// // Class : CCone // Method : bound // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CCone::bound(float *bmin,float *bmax) const { movvv(bmin,this->bmin); movvv(bmax,this->bmax); } /////////////////////////////////////////////////////////////////////// // Class : CCone // Method : sample // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CCone::sample(int start,int numVertices,float **varying,unsigned int &up) const { float *cosu; float *sinu; int i; const float *u = varying[VARIABLE_U] + start; const float *v = varying[VARIABLE_V] + start; float *dest; float *memBase; memBegin(); // Allocate memory for precomputing sin(u) , cos(u) memBase = (float *) ralloc(numVertices*2*sizeof(float)); sinu = memBase; cosu = sinu + numVertices; // Precompute the sin/cos for u points for (i=0;ir * (1 - time[i]) + nextData[0] * time[i]; height[i] = this->height * (1 - time[i]) + nextData[1] * time[i]; umax[i] = this->umax * (1 - time[i]) + nextData[2] * time[i]; dest[COMP_X] = r[i]*(1-v[i])*cosu[i]; dest[COMP_Y] = r[i]*(1-v[i])*sinu[i]; dest[COMP_Z] = v[i]*height[i]; } // Set Ng if needed if (up & PARAMETER_NG) { float *Ng = varying[VARIABLE_NG] + start*3; const float *P = varying[VARIABLE_P] + start*3; for (i=0;ir; float height = this->height; float umax = this->umax; if ((up & PARAMETER_END_SAMPLE) && (nextData != NULL)) { r = nextData[0]; height = nextData[1]; umax = nextData[2]; } // Set u/v/P for (i=0,dest=&varying[VARIABLE_P][start*3];iflip == 1) { float *N = varying[VARIABLE_NG] + start*3; for (int i=numVertices;i>0;i--,N+=3) { mulvf(N,-1); } } // Transform the points transformPoints(); up &= ~parametersF; memEnd(); } /////////////////////////////////////////////////////////////////////// // Class : CCone // Method : interpolate // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CCone::interpolate(int numVertices,float **varying) const { if (parameters != NULL) parameters->dispatch(numVertices,varying); } /////////////////////////////////////////////////////////////////////// // Class : CCone // Method : copy // Description : See object.h // Return Value : - // Comments : // Date last edited : 6/11/2003 void CCone::copy(CAttributes *a,CXform *x,CRendererContext *cx) const { CXform *nx = new CXform(x); nx->concat(xform); // Concetenate the local xform if (a == NULL) a = attributes; if (nextData == NULL) cx->addObject(new CCone(a,nx,parameters,parametersF,r,height,umax)); else cx->addObject(new CCone(a,nx,parameters,parametersF,r,height,umax,nextData[0],nextData[1],nextData[2])); } /////////////////////////////////////////////////////////////////////// // Class : CCone // Method : computeObjectBound // Description : Compute the bounding box in the object space // Return Value : - // Comments : // Date last edited : 3/17/2001 void CCone::computeObjectBound(float *bmin,float *bmax,float r,float height,float umax) { r = absf(r); initv(bmin,-r,-r,min(height,0)); initv(bmax,r,r,max(height,0)); } //////////////////////////////////////////// P A R A B O L O I D /////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // Class : CParaboloid // Method : CParaboloid // Description : Ctor // Return Value : - // Comments : // Date last edited : 3/17/2001 CParaboloid::CParaboloid(CAttributes *a,CXform *x,CParameter *c,unsigned int pf,float ra,float zmina,float zmaxa,float anglea) : CSurface(a,x) { stats.gprimMemory += sizeof(CParaboloid); stats.numGprims++; r = ra; zmin = zmina; zmax = zmaxa; umax = anglea; parameters = c; parametersF = PARAMETER_P | PARAMETER_NG | PARAMETER_DPDU | PARAMETER_DPDV | pf; nextData = NULL; computeObjectBound(bmin,bmax,r,zmin,zmax,umax); xform->transformBound(bmin,bmax); makeBound(bmin,bmax); } /////////////////////////////////////////////////////////////////////// // Class : CParaboloid // Method : CParaboloid // Description : Ctor // Return Value : - // Comments : // Date last edited : 3/17/2001 CParaboloid::CParaboloid(CAttributes *a,CXform *x,CParameter *c,unsigned int pf,float r0,float zmin0,float zmax0,float angle0,float r1,float zmin1,float zmax1,float angle1) : CSurface(a,x) { vector tbmin,tbmax; stats.gprimMemory += sizeof(CParaboloid); stats.gprimMemory += sizeof(float)*4; stats.numGprims++; r = r0; zmin = zmin0; zmax = zmax0; umax = angle0; parameters = c; parametersF = PARAMETER_P | PARAMETER_NG | PARAMETER_DPDU | PARAMETER_DPDV | pf; nextData = new float[4]; nextData[0] = r1; nextData[1] = zmin1; nextData[2] = zmax1; nextData[3] = angle1; computeObjectBound(bmin,bmax,r,zmin,zmax,umax); computeObjectBound(tbmin,tbmax,nextData[0],nextData[1],nextData[2],nextData[3]); addBox(bmin,bmax,tbmin); addBox(bmin,bmax,tbmax); xform->transformBound(bmin,bmax); makeBound(bmin,bmax); } /////////////////////////////////////////////////////////////////////// // Class : CParaboloid // Method : ~CParaboloid // Description : Dtor // Return Value : - // Comments : // Date last edited : 3/17/2001 CParaboloid::~CParaboloid() { stats.gprimMemory -= sizeof(CParaboloid); stats.gprimMemory -= (nextData != NULL ? 4*sizeof(float) : 0); stats.numGprims--; if (parameters != NULL) delete parameters; if (nextData != NULL) delete [] nextData; } /////////////////////////////////////////////////////////////////////// // Class : CParaboloid // Method : tesselate // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CParaboloid::tesselate(CShadingContext *context) { if ((attributes->flags & ATTRIBUTES_FLAGS_DISPLACEMENTS) || (context->flags & OPTIONS_FLAGS_USE_RADIANCE_CACHE)) context->tesselate2D(this); else context->addTracable(this,this); } /////////////////////////////////////////////////////////////////////// // Class : CParaboloid // Method : intersect // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 int CParaboloid::intersect(const float *bmin,const float *bmax) const { //FIXME: a more accurate intersection computation is possible return intersectBox(bmin,bmax,this->bmin,this->bmax); } /////////////////////////////////////////////////////////////////////// // Class : CParaboloid // Method : intersect // Description : Compute the intersection with a ray // Return Value : TRUE if intersects // Comments : // Date last edited : 3/17/2001 void CParaboloid::intersect(CRay *rv) { vector Nt; checkRay(rv); float *from = rv->oFrom; float *dir = rv->oDir; double a,b,c,s[2]; unsigned int ns,i; float zmi,zma; float zmin,zmax; float r,umax; if (nextData != NULL) { zmin = this->zmin * (1 - rv->time) + nextData[1] * rv->time; zmax = this->zmax * (1 - rv->time) + nextData[2] * rv->time; r = this->r * (1 - rv->time) + nextData[0] * rv->time; umax = this->umax * (1 - rv->time) + nextData[3] * rv->time; } else { zmin = this->zmin; zmax = this->zmax; r = this->r; umax = this->umax; } a = dir[COMP_X]*dir[COMP_X] + dir[COMP_Y]*dir[COMP_Y]; b = 2*dir[COMP_X]*from[COMP_X] + 2*dir[COMP_Y]*from[COMP_Y] - r*r*dir[COMP_Z]/zmax; c = from[COMP_X]*from[COMP_X] + from[COMP_Y]*from[COMP_Y] - r*r*from[COMP_Z]/zmax; if (a < C_EPSILON) { if (b == 0) return; s[0] = -c/b; ns = 1; } else { if ((ns = solveQuadric(a,b,c,s)) == 0) return; } if (zmin < zmax) { zmi = zmin; zma = zmax; } else { zmi = zmax; zma = zmin; } for (i=0;itmin) continue; if (t >= rv->t) return; P[0] = from[0] + dir[0]*t; P[1] = from[1] + dir[1]*t; P[2] = from[2] + dir[2]*t; if (P[COMP_Z] < zmi) continue; if (P[COMP_Z] > zma) continue; if (r > 0) u = atan2(P[COMP_Y],P[COMP_X]); else u = atan2(-P[COMP_Y],-P[COMP_X]); if (u < 0) u = 2*C_PI + u; if (umax < 0) { u = u - 2*C_PI; if (u < umax) continue; } else { if (u > umax) continue; } const float tmp = umax*(zmax-zmin); Nt[COMP_X] = (float) (P[COMP_X]*tmp); Nt[COMP_Y] = (float) (P[COMP_Y]*tmp); Nt[COMP_Z] = (float) (-r*r*tmp / (2*zmax)); if ((attributes->flags & ATTRIBUTES_FLAGS_INSIDE) ^ xform->flip) { mulvf(Nt,-1); } if (attributes->nSides == 1) { if (dotvv(rv->oDir,Nt) > 0) continue; } rv->object = this; rv->u = (float) (u / umax); rv->v = (float) ((P[COMP_Z] - zmin) / (zmax - zmin)); rv->t = (float) t; mulmn(rv->N,xform->to,Nt); return; } } /////////////////////////////////////////////////////////////////////// // Class : CParaboloid // Method : bound // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CParaboloid::bound(float *bmin,float *bmax) const { movvv(bmin,this->bmin); movvv(bmax,this->bmax); } /////////////////////////////////////////////////////////////////////// // Class : CParaboloid // Method : sample // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CParaboloid::sample(int start,int numVertices,float **varying,unsigned int &up) const { float *cosu; float *sinu; float *sqrtz; int i; float *u = &varying[VARIABLE_U][start]; float *v = &varying[VARIABLE_V][start]; float *dest; memBegin(); // Allocate memory for precomputing sin(u) , cos(u) sinu = (float *) ralloc(numVertices*sizeof(float)); cosu = (float *) ralloc(numVertices*sizeof(float)); sqrtz = (float *) ralloc(numVertices*sizeof(float)); if ((nextData != NULL) && (!(up & (PARAMETER_BEGIN_SAMPLE | PARAMETER_END_SAMPLE)))) { float *r = (float *) ralloc(numVertices*sizeof(float)); float *umax = (float *) ralloc(numVertices*sizeof(float)); float *zmax = (float *) ralloc(numVertices*sizeof(float)); float *zmin = (float *) ralloc(numVertices*sizeof(float)); float *time = &varying[VARIABLE_TIME][start]; // Precompute the sin/cos for u points dest = varying[VARIABLE_P] + start*3; for (i=0;ir * (1 - time[i]) + nextData[0] * time[i]; zmin[i] = this->zmin * (1 - time[i]) + nextData[1] * time[i]; zmax[i] = this->zmax * (1 - time[i]) + nextData[2] * time[i]; umax[i] = this->umax * (1 - time[i]) + nextData[3] * time[i]; cosu[i] = cosf(u[i]*umax[i]); sinu[i] = sinf(u[i]*umax[i]); sqrtz[i] = sqrtf(((zmax[i]-zmin[i])*v[i]+zmin[i])/zmax[i]); dest[COMP_Z] = (zmax[i] - zmin[i])*v[i] + zmin[i]; dest[COMP_X] = r[i]*sqrtz[i]*cosu[i]; dest[COMP_Y] = r[i]*sqrtz[i]*sinu[i]; dest += 3; } // Set Ng if needed if (up & PARAMETER_NG) { float *Ng = &varying[VARIABLE_NG][start*3]; float *P = &varying[VARIABLE_P][start*3]; for (i=0;ir; float zmin = this->zmin; float zmax = this->zmax; float umax = this->umax; if ((up & PARAMETER_END_SAMPLE) && (nextData != NULL)) { r = nextData[0]; zmin = nextData[1]; zmax = nextData[2]; umax = nextData[3]; } // Precompute the sin/cos for u points dest = varying[VARIABLE_P] + start*3; for (i=0;iflip == 1) { float *N = varying[VARIABLE_NG] + start*3; for (int i=numVertices;i>0;i--,N+=3) { mulvf(N,-1); } } // Transform the points transformPoints(); up &= ~parametersF; memEnd(); } /////////////////////////////////////////////////////////////////////// // Class : CParaboloid // Method : interpolate // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CParaboloid::interpolate(int numVertices,float **varying) const { if (parameters != NULL) parameters->dispatch(numVertices,varying); } /////////////////////////////////////////////////////////////////////// // Class : CParaboloid // Method : copy // Description : See object.h // Return Value : - // Comments : // Date last edited : 6/11/2003 void CParaboloid::copy(CAttributes *a,CXform *x,CRendererContext *cx) const { CXform *nx = new CXform(x); nx->concat(xform); // Concetenate the local xform if (a == NULL) a = attributes; if (nextData == NULL) cx->addObject(new CParaboloid(a,nx,parameters,parametersF,r,zmin,zmax,umax)); else cx->addObject(new CParaboloid(a,nx,parameters,parametersF,r,zmin,zmax,umax,nextData[0],nextData[1],nextData[2],nextData[3])); } /////////////////////////////////////////////////////////////////////// // Class : CParaboloid // Method : computeObjectBound // Description : Compute the bounding box in the object space // Return Value : - // Comments : // Date last edited : 3/17/2001 void CParaboloid::computeObjectBound(float *bmin,float *bmax,float r,float zmin,float zmax,float umax) { r = absf(r); initv(bmin,-r,-r,min(zmin,zmax)); initv(bmax,r,r,max(zmin,zmax)); } //////////////////////////////////////////// C Y L I N D E R /////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // Class : CCylinder // Method : CCylinder // Description : Ctor // Return Value : - // Comments : // Date last edited : 3/17/2001 CCylinder::CCylinder(CAttributes *a,CXform *x,CParameter *c,unsigned int pf,float ra,float zmina,float zmaxa,float anglea) : CSurface(a,x) { stats.gprimMemory += sizeof(CCylinder); stats.numGprims++; r = ra; zmin = zmina; zmax = zmaxa; umax = anglea; parameters = c; parametersF = PARAMETER_P | PARAMETER_NG | PARAMETER_DPDU | PARAMETER_DPDV | pf; nextData = NULL; computeObjectBound(bmin,bmax,r,zmin,zmax,umax); xform->transformBound(bmin,bmax); makeBound(bmin,bmax); } /////////////////////////////////////////////////////////////////////// // Class : CCylinder // Method : CCylinder // Description : Ctor // Return Value : - // Comments : // Date last edited : 3/17/2001 CCylinder::CCylinder(CAttributes *a,CXform *x,CParameter *c,unsigned int pf,float r0,float zmin0,float zmax0,float angle0,float r1,float zmin1,float zmax1,float angle1) : CSurface(a,x) { vector tbmin,tbmax; stats.gprimMemory += sizeof(CCylinder); stats.gprimMemory += sizeof(float)*4; stats.numGprims++; r = r0; zmin = zmin0; zmax = zmax0; umax = angle0; parameters = c; parametersF = PARAMETER_P | PARAMETER_NG | PARAMETER_DPDU | PARAMETER_DPDV | pf; nextData = new float[4]; nextData[0] = r1; nextData[1] = zmin1; nextData[2] = zmax1; nextData[3] = angle1; computeObjectBound(bmin,bmax,r,zmin,zmax,umax); computeObjectBound(tbmin,tbmax,nextData[0],nextData[1],nextData[2],nextData[3]); addBox(bmin,bmax,tbmin); addBox(bmin,bmax,tbmax); xform->transformBound(bmin,bmax); makeBound(bmin,bmax); } /////////////////////////////////////////////////////////////////////// // Class : CCylinder // Method : ~CCylinder // Description : Dtor // Return Value : - // Comments : // Date last edited : 3/17/2001 CCylinder::~CCylinder() { stats.gprimMemory -= sizeof(CCylinder); stats.gprimMemory -= (nextData != NULL ? 4*sizeof(float) : 0); stats.numGprims--; if (parameters != NULL) delete parameters; if (nextData != NULL) delete [] nextData; } /////////////////////////////////////////////////////////////////////// // Class : CCylinder // Method : tesselate // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CCylinder::tesselate(CShadingContext *context) { if ((attributes->flags & ATTRIBUTES_FLAGS_DISPLACEMENTS) || (context->flags & OPTIONS_FLAGS_USE_RADIANCE_CACHE)) context->tesselate2D(this); else context->addTracable(this,this); } /////////////////////////////////////////////////////////////////////// // Class : CCylinder // Method : intersect // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 int CCylinder::intersect(const float *bmin,const float *bmax) const { //FIXME: a more accurate intersection computation is possible return intersectBox(bmin,bmax,this->bmin,this->bmax); } /////////////////////////////////////////////////////////////////////// // Class : CCylinder // Method : intersect // Description : Compute the intersection with a ray // Return Value : TRUE if intersects // Comments : // Date last edited : 3/17/2001 void CCylinder::intersect(CRay *rv) { vector Nt; checkRay(rv); float *from = rv->oFrom; float *dir = rv->oDir; double a,b,c,s[2]; unsigned int ns,i; float r,zmin,zmax,umax; if (nextData != NULL) { zmin = this->zmin * (1 - rv->time) + nextData[1] * rv->time; zmax = this->zmax * (1 - rv->time) + nextData[2] * rv->time; r = this->r * (1 - rv->time) + nextData[0] * rv->time; umax = this->umax * (1 - rv->time) + nextData[3] * rv->time; } else { zmin = this->zmin; zmax = this->zmax; r = this->r; umax = this->umax; } a = dir[COMP_X]*dir[COMP_X] + dir[COMP_Y]*dir[COMP_Y]; b = 2*dir[COMP_X]*from[COMP_X] + 2*dir[COMP_Y]*from[COMP_Y]; c = from[COMP_X]*from[COMP_X] + from[COMP_Y]*from[COMP_Y] - r*r; if (a == 0) { if (b == 0) return; s[0] = -c/b; ns = 1; } else { if ((ns = solveQuadric(a,b,c,s)) == 0) return; } for (i=0;itmin) continue; if (t >= rv->t) return; P[0] = from[0] + dir[0]*t; P[1] = from[1] + dir[1]*t; P[2] = from[2] + dir[2]*t; if (zmin < zmax) { if (P[COMP_Z] < zmin) continue; if (P[COMP_Z] > zmax) continue; } else { if (P[COMP_Z] < zmax) continue; if (P[COMP_Z] > zmin) continue; } if (r > 0) u = atan2(P[COMP_Y],P[COMP_X]); else u = atan2(-P[COMP_Y],-P[COMP_X]); if (u < 0) u = 2*C_PI + u; if (umax < 0) { u = u - 2*C_PI; if (u < umax) continue; } else { if (u > umax) continue; } Nt[COMP_X] = (float) (P[COMP_X]*umax*(zmax-zmin)); Nt[COMP_Y] = (float) (P[COMP_Y]*umax*(zmax-zmin)); Nt[COMP_Z] = 0; if ((attributes->flags & ATTRIBUTES_FLAGS_INSIDE) ^ xform->flip) { mulvf(Nt,-1); } if (attributes->nSides == 1) { if (dotvv(rv->oDir,Nt) > 0) continue; } rv->object = this; rv->u = (float) (u/umax); rv->v = (float) (P[COMP_Z] - zmin) / (zmax - zmin); rv->t = (float) t; mulmn(rv->N,xform->to,Nt); return; } } /////////////////////////////////////////////////////////////////////// // Class : CCylinder // Method : bound // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CCylinder::bound(float *bmin,float *bmax) const { movvv(bmin,this->bmin); movvv(bmax,this->bmax); } /////////////////////////////////////////////////////////////////////// // Class : CCylinder // Method : sample // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CCylinder::sample(int start,int numVertices,float **varying,unsigned int &up) const { float *cosu; float *sinu; int i; float *u = varying[VARIABLE_U]; float *v = varying[VARIABLE_V]; float *dest; memBegin(); // Allocate memory for precomputing sin(u) , cos(u) sinu = (float *) ralloc(numVertices*sizeof(float)); cosu = (float *) ralloc(numVertices*sizeof(float)); if ((nextData != NULL) && (!(up & (PARAMETER_BEGIN_SAMPLE | PARAMETER_END_SAMPLE)))) { float *r = (float *) ralloc(numVertices*sizeof(float)); float *umax = (float *) ralloc(numVertices*sizeof(float)); float *zmax = (float *) ralloc(numVertices*sizeof(float)); float *zmin = (float *) ralloc(numVertices*sizeof(float)); float *time = &varying[VARIABLE_TIME][start]; // Precompute the sin/cos for u points dest = varying[VARIABLE_P] + start*3; for (i=0;ir * (1 - time[i]) + nextData[0] * time[i]; zmin[i] = this->zmin * (1 - time[i]) + nextData[1] * time[i]; zmax[i] = this->zmax * (1 - time[i]) + nextData[2] * time[i]; umax[i] = this->umax * (1 - time[i]) + nextData[3] * time[i]; cosu[i] = (cosf(u[i]*umax[i]))*r[i]; sinu[i] = (sinf(u[i]*umax[i]))*r[i]; dest[COMP_X] = cosu[i]; dest[COMP_Y] = sinu[i]; dest[COMP_Z] = (zmax[i] - zmin[i])*v[i] + zmin[i]; dest += 3; } // Set Ng if needed if (up & PARAMETER_NG) { float *Ng = varying[VARIABLE_NG] + start*3; float *P = varying[VARIABLE_P] + start*3; for (i=0;ir; float zmin = this->zmin; float zmax = this->zmax; float umax = this->umax; if ((up & PARAMETER_END_SAMPLE) && (nextData != NULL)) { r = nextData[0]; zmin = nextData[1]; zmax = nextData[2]; umax = nextData[3]; } // Precompute the sin/cos for u points for (i=0;iflip) { float *N = varying[VARIABLE_NG] + start*3; for (int i=numVertices;i>0;i--,N+=3) { mulvf(N,-1); } } // Transform the points transformPoints(); up &= ~parametersF; memEnd(); } /////////////////////////////////////////////////////////////////////// // Class : CCylinder // Method : interpolate // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CCylinder::interpolate(int numVertices,float **varying) const { if (parameters != NULL) parameters->dispatch(numVertices,varying); } /////////////////////////////////////////////////////////////////////// // Class : CCylinder // Method : copy // Description : See object.h // Return Value : - // Comments : // Date last edited : 6/11/2003 void CCylinder::copy(CAttributes *a,CXform *x,CRendererContext *cx) const { CXform *nx = new CXform(x); nx->concat(xform); // Concetenate the local xform if (a == NULL) a = attributes; if (nextData == NULL) cx->addObject(new CCylinder(a,nx,parameters,parametersF,r,zmin,zmax,umax)); else cx->addObject(new CCylinder(a,nx,parameters,parametersF,r,zmin,zmax,umax,nextData[0],nextData[1],nextData[2],nextData[3])); } /////////////////////////////////////////////////////////////////////// // Class : CCylinder // Method : computeObjectBound // Description : Compute the bounding box in the object space // Return Value : - // Comments : // Date last edited : 3/17/2001 void CCylinder::computeObjectBound(float *bmin,float *bmax,float r,float zmin,float zmax,float umax) { r = absf(r); initv(bmin,-r,-r,min(zmin,zmax)); initv(bmax,r,r,max(zmin,zmax)); } //////////////////////////////////////////// H Y P E R B O L O I D /////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // Class : CHyperboloid // Method : CHyperboloid // Description : Ctor // Return Value : - // Comments : // Date last edited : 3/17/2001 CHyperboloid::CHyperboloid(CAttributes *a,CXform *x,CParameter *c,unsigned int pf,const float *p1a,const float *p2a,float anglea) : CSurface(a,x) { stats.gprimMemory += sizeof(CHyperboloid); stats.numGprims++; umax = anglea; movvv(p1,p1a); movvv(p2,p2a); parameters = c; parametersF = PARAMETER_P | PARAMETER_NG | PARAMETER_DPDU | PARAMETER_DPDV | pf; nextData = NULL; computeObjectBound(bmin,bmax,p1,p2,umax); xform->transformBound(bmin,bmax); makeBound(bmin,bmax); } /////////////////////////////////////////////////////////////////////// // Class : CHyperboloid // Method : CHyperboloid // Description : Ctor // Return Value : - // Comments : // Date last edited : 3/17/2001 CHyperboloid::CHyperboloid(CAttributes *a,CXform *x,CParameter *c,unsigned int pf,const float *p10,const float *p20,float angle0,const float *p11,const float *p21,float angle1) : CSurface(a,x) { vector tbmin,tbmax; stats.gprimMemory += sizeof(CHyperboloid); stats.gprimMemory += sizeof(float)*7; stats.numGprims++; umax = angle0; movvv(p1,p10); movvv(p2,p20); parameters = c; parametersF = PARAMETER_P | PARAMETER_NG | PARAMETER_DPDU | PARAMETER_DPDV | pf; nextData = new float[7]; movvv(&nextData[0],p11); movvv(&nextData[3],p21); nextData[6] = angle1; computeObjectBound(bmin,bmax,p1,p2,umax); computeObjectBound(tbmin,tbmax,&nextData[0],&nextData[3],nextData[6]); addBox(bmin,bmax,tbmin); addBox(bmin,bmax,tbmax); xform->transformBound(bmin,bmax); makeBound(bmin,bmax); } /////////////////////////////////////////////////////////////////////// // Class : CHyperboloid // Method : ~CHyperboloid // Description : Dtor // Return Value : - // Comments : // Date last edited : 3/17/2001 CHyperboloid::~CHyperboloid() { stats.gprimMemory -= sizeof(CHyperboloid); stats.gprimMemory -= (nextData != NULL ? 7*sizeof(float) : 0); stats.numGprims--; if (parameters != NULL) delete parameters; if (nextData != NULL) delete [] nextData; } /////////////////////////////////////////////////////////////////////// // Class : CHyperboloid // Method : tesselate // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CHyperboloid::tesselate(CShadingContext *context) { if ((attributes->flags & ATTRIBUTES_FLAGS_DISPLACEMENTS) || (context->flags & OPTIONS_FLAGS_USE_RADIANCE_CACHE)) context->tesselate2D(this); else context->addTracable(this,this); } /////////////////////////////////////////////////////////////////////// // Class : CHyperboloid // Method : intersect // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 int CHyperboloid::intersect(const float *bmin,const float *bmax) const { //FIXME: a more accurate intersection computation is possible return intersectBox(bmin,bmax,this->bmin,this->bmax); } /////////////////////////////////////////////////////////////////////// // Class : CHyperboloid // Method : intersect // Description : Compute the intersection with a ray // Return Value : TRUE if intersects // Comments : // Date last edited : 3/17/2001 void CHyperboloid::intersect(CRay *rv) { checkRay(rv); float *from = rv->oFrom; float *dir = rv->oDir; unsigned int ns,i; double ts[2]; double P[3]; double a,b,c; vector p1,p2; float umax; vector Nt; if (nextData != NULL) { interpolatev(p1,this->p1,&nextData[0],rv->time); interpolatev(p2,this->p2,&nextData[3],rv->time); umax = this->umax * (1 - rv->time) + nextData[6] * rv->time; } else { movvv(p1,this->p1); movvv(p2,this->p2); umax = this->umax; } const double dx = p2[COMP_X] - p1[COMP_X]; const double dy = p2[COMP_Y] - p1[COMP_Y]; const double dz = p2[COMP_Z] - p1[COMP_Z]; if (p1[COMP_Z] == p2[COMP_Z]) { // We're a disc ns = 1; ts[0] = (p1[COMP_Z] - from[COMP_Z]) / dir[COMP_Z]; } else { double x; double y; double zmin,d,dmin; if ((dx*dx + dy*dy) < C_EPSILON) { // Make sure we don't crash if we're a cylinder x = p1[COMP_X]; y = p1[COMP_Y]; zmin = p1[COMP_Z]; } else { double tmin = (-dx*p1[COMP_X] - dy*p1[COMP_Y]) / (dx*dx + dy*dy); // Nearest we come to the z axis x = p1[COMP_X] + dx*tmin; y = p1[COMP_Y] + dy*tmin; zmin = p1[COMP_Z] + dz*tmin; } dmin = sqrt(x*x + y*y); if (fabs(p2[COMP_Z]-zmin) > fabs(p1[COMP_Z]-zmin)) { d = sqrt((p2[COMP_X]*p2[COMP_X] + p2[COMP_Y]*p2[COMP_Y]) - dmin*dmin)/(p2[COMP_Z]-zmin); } else { d = sqrt((p1[COMP_X]*p1[COMP_X] + p1[COMP_Y]*p1[COMP_Y]) - dmin*dmin)/(p1[COMP_Z]-zmin); } a = dir[COMP_X]*dir[COMP_X] + dir[COMP_Y]*dir[COMP_Y] - dir[COMP_Z]*dir[COMP_Z]*d*d; b = 2*dir[COMP_X]*from[COMP_X] + 2*dir[COMP_Y]*from[COMP_Y] - 2*dir[COMP_Z]*(from[COMP_Z]-zmin)*d*d; c = from[COMP_X]*from[COMP_X] + from[COMP_Y]*from[COMP_Y] - dmin*dmin - (from[COMP_Z]-zmin)*(from[COMP_Z]-zmin)*d*d; if (a == 0) { if (b == 0) return; ns = 1; ts[0] = -c / b; } else { if ((ns = solveQuadric(a,b,c,ts)) == 0) return; } } for (i = 0;i < ns;i++) { double t = ts[i]; double x,y; double ustart; double u,v; if (t >= rv->t) return; if (t <= rv->tmin) continue; P[0] = from[0] + dir[0]*t; P[1] = from[1] + dir[1]*t; P[2] = from[2] + dir[2]*t; if (p1[COMP_Z] < p2[COMP_Z]) { if (P[COMP_Z] < p1[COMP_Z]) continue; if (P[COMP_Z] > p2[COMP_Z]) continue; v = (P[COMP_Z] - p1[COMP_Z]) / (p2[COMP_Z] - p1[COMP_Z]); } else if (p1[COMP_Z] > p2[COMP_Z]) { if (P[COMP_Z] < p2[COMP_Z]) continue; if (P[COMP_Z] > p1[COMP_Z]) continue; v = (P[COMP_Z] - p1[COMP_Z]) / (p2[COMP_Z] - p1[COMP_Z]); } else { const double r1 = sqrt(p1[COMP_X]*p1[COMP_X] + p1[COMP_Y]*p1[COMP_Y]); const double r2 = sqrt(p2[COMP_X]*p2[COMP_X] + p2[COMP_Y]*p2[COMP_Y]); const double r = sqrt(P[COMP_X]*P[COMP_X] + P[COMP_Y]*P[COMP_Y]); // We're a disc v = (r - r1) / (r2 - r1); if (v < 0) continue; if (v > 1) continue; } x = p1[COMP_X]*(1-v) + p2[COMP_X]*v; y = p1[COMP_Y]*(1-v) + p2[COMP_Y]*v; u = atan2(P[COMP_Y],P[COMP_X]); ustart = atan2(y,x); if (u < 0) u = 2*C_PI + u; if (ustart < 0) ustart = 2*C_PI + ustart; u -= ustart; if (u < 0) u = 2*C_PI + u; if (umax < 0) { u = u - 2*C_PI; if (u < umax) continue; } else { if (u > umax) continue; } { Nt[COMP_X] = (float) ((p2[COMP_Z] - p1[COMP_Z])*umax*P[COMP_X]); Nt[COMP_Y] = (float) ((p2[COMP_Z] - p1[COMP_Z])*umax*P[COMP_Y]); Nt[COMP_Z] = (float) (-umax*( (-1+v)*p1[COMP_X]*p1[COMP_X] + p1[COMP_X]*(p2[COMP_X] - 2*v*p2[COMP_X]) + v*(p2[COMP_X]*p2[COMP_X] + (p2[COMP_Y]-p1[COMP_Y])*(p2[COMP_Y]-p1[COMP_Y])) + p1[COMP_Y]*(p2[COMP_Y] - p1[COMP_Y]))); if ((attributes->flags & ATTRIBUTES_FLAGS_INSIDE) ^ xform->flip) { mulvf(Nt,-1); } if (attributes->nSides == 1) { if (dotvv(rv->oDir,Nt) > 0) continue; } } rv->object = this; rv->u = (float) (u / umax); rv->v = (float) (v); rv->t = (float) t; mulmn(rv->N,xform->to,Nt); return; } } /////////////////////////////////////////////////////////////////////// // Class : CHyperboloid // Method : bound // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CHyperboloid::bound(float *bmin,float *bmax) const { movvv(bmin,this->bmin); movvv(bmax,this->bmax); } /////////////////////////////////////////////////////////////////////// // Class : CHyperboloid // Method : sample // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CHyperboloid::sample(int start,int numVertices,float **varying,unsigned int &up) const { float *cosu; float *sinu; int i; float *u = &varying[VARIABLE_U][start]; float *v = &varying[VARIABLE_V][start]; float *dest; memBegin(); sinu = (float *) ralloc(numVertices*sizeof(float)); cosu = (float *) ralloc(numVertices*sizeof(float)); if ((nextData != NULL) && (!(up & (PARAMETER_BEGIN_SAMPLE | PARAMETER_END_SAMPLE)))) { float *umax = (float *) ralloc(numVertices*sizeof(float)); float *p1 = (float *) ralloc(numVertices*sizeof(float)*3); float *p2 = (float *) ralloc(numVertices*sizeof(float)*3); float *dx = (float *) ralloc(numVertices*sizeof(float)); float *dy = (float *) ralloc(numVertices*sizeof(float)); float *dz = (float *) ralloc(numVertices*sizeof(float)); const float *tp1 = this->p1; float *np1 = &nextData[0]; const float *tp2 = this->p2; float *np2 = &nextData[3]; float *cp1 = p1; float *cp2 = p2; float *time = &varying[VARIABLE_TIME][start]; // Precompute the sin/cos for u points for (i=0;iumax * (1 - time[i]) + nextData[6] * time[i]; cp1[COMP_X] = tp1[COMP_X] * (1 - time[i]) + np1[COMP_X] * time[i]; cp1[COMP_Y] = tp1[COMP_Y] * (1 - time[i]) + np1[COMP_Y] * time[i]; cp1[COMP_Z] = tp1[COMP_Z] * (1 - time[i]) + np1[COMP_Z] * time[i]; cp2[COMP_X] = tp2[COMP_X] * (1 - time[i]) + np2[COMP_X] * time[i]; cp2[COMP_Y] = tp2[COMP_Y] * (1 - time[i]) + np2[COMP_Y] * time[i]; cp2[COMP_Z] = tp2[COMP_Z] * (1 - time[i]) + np2[COMP_Z] * time[i]; dx[i] = cp2[COMP_X] - cp1[COMP_X]; dy[i] = cp2[COMP_Y] - cp1[COMP_Y]; dz[i] = cp2[COMP_Z] - cp1[COMP_Z]; cosu[i] = cosf(u[i]*umax[i]); sinu[i] = sinf(u[i]*umax[i]); cp1 += 3; cp2 += 3; } // Set u/v/P cp1 = p1; cp2 = p2; for (i=0,dest=&varying[VARIABLE_P][start*3];ip1; const float *p2 = this->p2; float umax = this->umax; if ((up & PARAMETER_END_SAMPLE) && (nextData != NULL)) { p1 = &nextData[0]; p2 = &nextData[3]; umax = nextData[6]; } const float dx = p2[COMP_X] - p1[COMP_X]; const float dy = p2[COMP_Y] - p1[COMP_Y]; const float dz = p2[COMP_Z] - p1[COMP_Z]; // Precompute the sin/cos for u points for (i=0;iflip == 1) { float *N = varying[VARIABLE_NG] + start*3; for (int i = numVertices;i>0;i--,N+=3) { mulvf(N,-1); } } // Transform the points transformPoints(); up &= ~parametersF; memEnd(); } /////////////////////////////////////////////////////////////////////// // Class : CHyperboloid // Method : interpolate // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CHyperboloid::interpolate(int numVertices,float **varying) const { if (parameters != NULL) parameters->dispatch(numVertices,varying); } /////////////////////////////////////////////////////////////////////// // Class : CHyperboloid // Method : copy // Description : See object.h // Return Value : - // Comments : // Date last edited : 6/11/2003 void CHyperboloid::copy(CAttributes *a,CXform *x,CRendererContext *cx) const { CXform *nx = new CXform(x); nx->concat(xform); // Concetenate the local xform if (a == NULL) a = attributes; if (nextData == NULL) cx->addObject(new CHyperboloid(a,nx,parameters,parametersF,p1,p2,umax)); else cx->addObject(new CHyperboloid(a,nx,parameters,parametersF,p1,p2,umax,nextData,nextData+3,nextData[6])); } /////////////////////////////////////////////////////////////////////// // Class : CHyperboloid // Method : computeObjectBound // Description : Compute the bounding box in the object space // Return Value : - // Comments : // Date last edited : 3/17/2001 void CHyperboloid::computeObjectBound(float *bmin,float *bmax,float *p1,float *p2,float umax) { float d = p1[COMP_X] * p1[COMP_X] + p1[COMP_Y] * p1[COMP_Y]; float d2 = p2[COMP_X] * p2[COMP_X] + p2[COMP_Y] * p2[COMP_Y]; if (d2 > d) d = d2; d = sqrtf(d); // FIXME: smaller bound is possible bmin[COMP_X] = -d; bmin[COMP_Y] = -d; bmin[COMP_Z] = min(p1[COMP_Z],p2[COMP_Z]); bmax[COMP_X] = +d; bmax[COMP_Y] = +d; bmax[COMP_Z] = max(p1[COMP_Z],p2[COMP_Z]); } //////////////////////////////////////////// T O R O I D /////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // Class : CToroid // Method : CToroid // Description : Ctor // Return Value : - // Comments : // Date last edited : 3/17/2001 CToroid::CToroid(CAttributes *a,CXform *x,CParameter *c,unsigned int pf,float rmina,float rmaxa,float vmina,float vmaxa,float umaxa) : CSurface(a,x) { stats.gprimMemory += sizeof(CToroid); stats.numGprims++; rmin = rmina; rmax = rmaxa; vmin = vmina; vmax = vmaxa; umax = umaxa; parameters = c; parametersF = PARAMETER_P | PARAMETER_NG | PARAMETER_DPDU | PARAMETER_DPDV | pf; nextData = NULL; computeObjectBound(bmin,bmax,rmin,rmax,vmin,vmax,umax); xform->transformBound(bmin,bmax); makeBound(bmin,bmax); } /////////////////////////////////////////////////////////////////////// // Class : CToroid // Method : CToroid // Description : Ctor // Return Value : - // Comments : // Date last edited : 3/17/2001 CToroid::CToroid(CAttributes *a,CXform *x,CParameter *c,unsigned int pf,float rmin0,float rmax0,float vmin0,float vmax0,float umax0,float rmin1,float rmax1,float vmin1,float vmax1,float umax1) : CSurface(a,x) { vector tbmin,tbmax; stats.gprimMemory += sizeof(CToroid); stats.gprimMemory += sizeof(float)*5; stats.numGprims++; rmin = rmin0; rmax = rmax0; vmin = vmin0; vmax = vmax0; umax = umax0; parameters = c; parametersF = PARAMETER_P | PARAMETER_NG | PARAMETER_DPDU | PARAMETER_DPDV | pf; nextData = new float[5]; nextData[0] = rmin1; nextData[1] = rmax1; nextData[2] = vmin1; nextData[3] = vmax1; nextData[4] = umax1; computeObjectBound(bmin,bmax,rmin,rmax,vmin,vmax,umax); computeObjectBound(tbmin,tbmax,nextData[0],nextData[1],nextData[2],nextData[3],nextData[4]); addBox(bmin,bmax,tbmin); addBox(bmin,bmax,tbmax); xform->transformBound(bmin,bmax); makeBound(bmin,bmax); } /////////////////////////////////////////////////////////////////////// // Class : CToroid // Method : ~CToroid // Description : Dtor // Return Value : - // Comments : // Date last edited : 3/17/2001 CToroid::~CToroid() { stats.gprimMemory -= sizeof(CToroid); stats.gprimMemory -= (nextData != NULL ? 5*sizeof(float) : 0); stats.numGprims--; if (parameters != NULL) delete parameters; if (nextData != NULL) delete [] nextData; } /////////////////////////////////////////////////////////////////////// // Class : CToroid // Method : tesselate // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CToroid::tesselate(CShadingContext *context) { // FIXME: Do the correct ray torus intersection context->tesselate2D(this); return; if ((attributes->flags & ATTRIBUTES_FLAGS_DISPLACEMENTS) || (context->flags & OPTIONS_FLAGS_USE_RADIANCE_CACHE)) context->tesselate2D(this); else context->addTracable(this,this); } /////////////////////////////////////////////////////////////////////// // Class : CToroid // Method : intersect // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 int CToroid::intersect(const float *bmin,const float *bmax) const { //FIXME: a more accurate intersection computation is possible return intersectBox(bmin,bmax,this->bmin,this->bmax); } /////////////////////////////////////////////////////////////////////// // Class : CToroid // Method : intersect // Description : Compute the intersection with a ray // Return Value : TRUE if intersects // Comments : // Date last edited : 3/17/2001 void CToroid::intersect(CRay *rv) { checkRay(rv); double rmin,rmax,umax,vmin,vmax; if (nextData != NULL) { rmin = this->rmin * (1 - rv->time) + nextData[0] * rv->time; rmax = this->rmax * (1 - rv->time) + nextData[1] * rv->time; umax = this->umax * (1 - rv->time) + nextData[2] * rv->time; vmax = this->vmax * (1 - rv->time) + nextData[3] * rv->time; vmin = this->vmin * (1 - rv->time) + nextData[4] * rv->time; } else { rmin = this->rmin; rmax = this->rmax; umax = this->umax; vmax = this->vmax; vmin = this->vmin; } { int ns; double s[5]; double c[5]; int i; const float *from = rv->oFrom; const float *dir = rv->oDir; double R2 = rmax*rmax; double r2 = rmin*rmin; double Py2 = from[COMP_Y] * from[COMP_Y]; double Dy2 = dir[COMP_Y] * dir[COMP_Y]; double PDy2 = from[COMP_Y] * dir[COMP_Y]; double k1 = from[COMP_X] * from[COMP_X] + from[COMP_Z] * from[COMP_Z] + Py2 - R2 - r2; double k2 = from[COMP_X] * dir[COMP_X] + from[COMP_Z] * dir[COMP_Z] + PDy2; c[4] = 1.0; c[3] = 4.0 * k2; c[2] = 2.0 * (k1 + 2.0 * (k2 * k2 + R2 * Dy2)); c[1] = 4.0 * (k2 * k1 + 2.0 * R2 * PDy2); c[0] = k1 * k1 + 4.0 * R2 * (Py2 - r2); /* double ab = dotvv(from,dir); double aa = dotvv(from,from); double K = aa - rmin*rmin - rmax*rmax; c[4] = 1; c[3] = 4*ab; c[2] = 2*(2*ab*ab + K + 2*rmax*rmax*dir[COMP_Z]*dir[COMP_Z]); c[1] = 4*(K*ab + 2*rmax*rmax*from[COMP_Z]*dir[COMP_Z]); c[0] = K*K + 4*rmax*rmax*(from[COMP_Z]*from[COMP_Z] - rmin*rmin); */ // Solve the polynomial ns = solveQuartic(c,s); for (i=0;itmin) continue; //if (t >= rv->t) return; P[0] = from[0] + dir[0]*t; P[1] = from[1] + dir[1]*t; P[2] = from[2] + dir[2]*t; if (rmax > 0) u = atan2(P[COMP_Y],P[COMP_X]); else u = atan2(-P[COMP_Y],-P[COMP_X]); if (u < 0) u = 2*C_PI + u; if (umax < 0) { u = u - 2*C_PI; //if (u < umax) continue; } else { //if (u > umax) continue; } r = sqrt(P[COMP_X]*P[COMP_X] + P[COMP_Y]*P[COMP_Y]) - fabs(rmax); if (rmin > 0) v = atan2(P[COMP_Z],r); else v = atan2(-P[COMP_Z],-r); if (v < 0) v = 2*C_PI + v; if (vmin < vmax) { //if (v < vmin) continue; //if (v > vmax) continue; } else { //if (v < vmax) continue; //if (v > vmin) continue; } // compute the normal vector Nt[COMP_X] = (float) (rmin*umax*(vmax-vmin)*cos(u)*cos(v)*(rmax + rmin*cos(v))); Nt[COMP_Y] = (float) (rmin*umax*(vmax-vmin)*cos(v)*(rmax + rmin*cos(v))*sin(u)); Nt[COMP_Z] = (float) (rmin*umax*(vmax-vmin)*(rmax + rmin*cos(v))*sin(v)); if ((attributes->flags & ATTRIBUTES_FLAGS_INSIDE) ^ xform->flip) { mulvf(Nt,-1); } if (attributes->nSides == 1) { //if (dotvv(rv->oDir,Nt) > 0) continue; } u = u / umax; v = (v - vmin) / (vmax - vmin); rv->object = this; rv->u = (float) u; rv->v = (float) v; rv->t = (float) t; mulmn(rv->N,xform->to,Nt); return; } } } /////////////////////////////////////////////////////////////////////// // Class : CToroid // Method : bound // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CToroid::bound(float *bmin,float *bmax) const { movvv(bmin,this->bmin); movvv(bmax,this->bmax); } /////////////////////////////////////////////////////////////////////// // Class : CToroid // Method : sample // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CToroid::sample(int start,int numVertices,float **varying,unsigned int &up) const { float *cosu; float *sinu; float *sinv; float *cosv; int i; float *u = &varying[VARIABLE_U][start]; float *v = &varying[VARIABLE_V][start]; float *dest; memBegin(); sinu = (float *) ralloc(numVertices*sizeof(float)); cosu = (float *) ralloc(numVertices*sizeof(float)); sinv = (float *) ralloc(numVertices*sizeof(float)); cosv = (float *) ralloc(numVertices*sizeof(float)); if ((nextData != NULL) && (!(up & (PARAMETER_BEGIN_SAMPLE | PARAMETER_END_SAMPLE)))) { float *rmin = (float *) ralloc(numVertices*sizeof(float)); float *rmax = (float *) ralloc(numVertices*sizeof(float)); float *vmin = (float *) ralloc(numVertices*sizeof(float)); float *vmax = (float *) ralloc(numVertices*sizeof(float)); float *umax = (float *) ralloc(numVertices*sizeof(float)); float *time = &varying[VARIABLE_TIME][start]; // Precompute the sin/cos for u points for (i=0;irmin * (1 - time[i]) + nextData[0] * time[i]; rmax[i] = this->rmax * (1 - time[i]) + nextData[1] * time[i]; vmin[i] = this->vmin * (1 - time[i]) + nextData[2] * time[i]; vmax[i] = this->vmax * (1 - time[i]) + nextData[3] * time[i]; umax[i] = this->umax * (1 - time[i]) + nextData[4] * time[i]; cosu[i] = cosf(u[i]*umax[i]); sinu[i] = sinf(u[i]*umax[i]); cosv[i] = cosf(v[i]*(vmax[i]-vmin[i]) + vmin[i]); sinv[i] = sinf(v[i]*(vmax[i]-vmin[i]) + vmin[i]); } // Set u/v/P for (i=0,dest=&varying[VARIABLE_P][start*3];irmin; float rmax = this->rmax; float vmin = this->vmin; float vmax = this->vmax; float umax = this->umax; if ((up & PARAMETER_END_SAMPLE) && (nextData != NULL)) { rmin = nextData[0]; rmax = nextData[1]; vmin = nextData[2]; vmax = nextData[3]; umax = nextData[4]; } // Precompute the sin/cos for u points for (i=0;iflip == 1) { float *N = varying[VARIABLE_NG] + start*3; for (int i=numVertices;i>0;i--,N+=3) { mulvf(N,-1); } } // Transform the points transformPoints(); // Note that the normals are computed by dPdu x dPdv, meaning that the normal vector may be degenerate normalFix(); up &= ~parametersF; memEnd(); } /////////////////////////////////////////////////////////////////////// // Class : CToroid // Method : interpolate // Description : See object.h // Return Value : - // Comments : // Date last edited : 3/17/2001 void CToroid::interpolate(int numVertices,float **varying) const { if (parameters != NULL) parameters->dispatch(numVertices,varying); } /////////////////////////////////////////////////////////////////////// // Class : CToroid // Method : copy // Description : See object.h // Return Value : - // Comments : // Date last edited : 6/11/2003 void CToroid::copy(CAttributes *a,CXform *x,CRendererContext *cx) const { CXform *nx = new CXform(x); nx->concat(xform); // Concetenate the local xform if (a == NULL) a = attributes; if (nextData == NULL) cx->addObject(new CToroid(a,nx,parameters,parametersF,rmin,rmax,vmin,vmax,umax)); else cx->addObject(new CToroid(a,nx,parameters,parametersF,rmin,rmax,vmin,vmax,umax,nextData[0],nextData[1],nextData[2],nextData[3],nextData[4])); } /////////////////////////////////////////////////////////////////////// // Class : CToroid // Method : computeObjectBound // Description : Compute the bounding box in the object space // Return Value : - // Comments : // Date last edited : 3/17/2001 void CToroid::computeObjectBound(float *bmin,float *bmax,float rmin,float rmax,float vmin,float vmax,float umax) { float r = absf(rmin) + absf(rmax); bmin[COMP_X] = -r; bmin[COMP_Y] = -r; bmax[COMP_X] = r; bmax[COMP_Y] = r; bmin[COMP_Z] = -absf(rmin); bmax[COMP_Z] = absf(rmin); }