home *** CD-ROM | disk | FTP | other *** search
- // Copyright (c)1995 Ray Dream, Inc. All Rights Reserved.
- /* $Id: COMSphr.cpp 1.10 1997/06/20 22:32:28 damien Exp $ */
-
- ////////////////////////////////////////////////////////////////////////
- // Geometric Primitive Example : Sphere //
- //--------------------------------------------------------------------//
- // Implementation of the Sphere Interface //
- ////////////////////////////////////////////////////////////////////////
-
- #include "math.h"
-
- #ifndef __COMSPHR__
- #include "COMSPHR.h"
- #endif
-
- #ifndef __3DCOFAIL__
- #include "3DCoFail.h"
- #endif
-
- // Constante values
- NUM3D kDefaultSphereRadius = 3.0;
- NUM3D kUmax = 360.0;
- NUM3D kVmax = 180.0;
-
-
- // Functions to create the Patches of the Sphere
- // -- Inverse a Patch
- void InversePatch(PATCH3D *aPatch) {
- VECTOR3D swapPoint;
-
- for (short uu=0;uu<=1;uu++) {
- for (short vv=0;vv<4;vv++) {
- for (int i=0; i<3; i++) {
- swapPoint[i]=aPatch->fVertices[uu][vv][i];
- aPatch->fVertices[uu][vv][i]=aPatch->fVertices[3-uu][vv][i];
- aPatch->fVertices[3-uu][vv][i]=swapPoint[i];
- }
- }
- }
- }
-
- // Create Default Patches of the Sphere
- void MakeSpherePatch(PATCH3D *aPatch,NUM3D di,NUM3D dj,NUM3D dk)
- {
- NUM3D magicFactor=0.552284749830793398;
- NUM3D swapUV;
-
- aPatch->fVertices[0][3][0]=0.0;
- aPatch->fVertices[0][3][1]=0.0;
- aPatch->fVertices[0][3][2]=dk;
-
- aPatch->fVertices[0][2][0]=magicFactor*di;
- aPatch->fVertices[0][2][1]=0.0;
- aPatch->fVertices[0][2][2]=dk;
-
- aPatch->fVertices[0][1][0]=di;
- aPatch->fVertices[0][1][1]=0.0;
- aPatch->fVertices[0][1][2]=magicFactor*dk;
-
- aPatch->fVertices[0][0][0]=di;
- aPatch->fVertices[0][0][1]=0.0;
- aPatch->fVertices[0][0][2]=0.0;
-
- aPatch->fVertices[1][0][0]=di;
- aPatch->fVertices[1][0][1]=magicFactor*dj;
- aPatch->fVertices[1][0][2]=0.0;
-
- aPatch->fVertices[2][0][0]=magicFactor*di;
- aPatch->fVertices[2][0][1]=dj;
- aPatch->fVertices[2][0][2]=0.0;
-
- aPatch->fVertices[3][0][0]=0.0;
- aPatch->fVertices[3][0][1]=dj;
- aPatch->fVertices[3][0][2]=0.0;
-
- aPatch->fVertices[3][1][0]=0.0;
- aPatch->fVertices[3][1][1]=dj;
- aPatch->fVertices[3][1][2]=magicFactor*dk;
-
- aPatch->fVertices[3][2][0]=0.0;
- aPatch->fVertices[3][2][1]=magicFactor*dj;
- aPatch->fVertices[3][2][2]=dk;
-
- aPatch->fVertices[3][3][0]=0.0;
- aPatch->fVertices[3][3][1]=0.0;
- aPatch->fVertices[3][3][2]=dk;
-
- aPatch->fVertices[2][3][0]=0.0;
- aPatch->fVertices[2][3][1]=0.0;
- aPatch->fVertices[2][3][2]=dk;
-
- aPatch->fVertices[1][3][0]=0.0;
- aPatch->fVertices[1][3][1]=0.0;
- aPatch->fVertices[1][3][2]=dk;
-
- //middle of the Patch (control points)
- aPatch->fVertices[1][2][0]=magicFactor*di;
- aPatch->fVertices[1][2][1]=magicFactor*magicFactor*dj;
- aPatch->fVertices[1][2][2]=dk;
-
- aPatch->fVertices[2][2][0]=magicFactor*magicFactor*di;
- aPatch->fVertices[2][2][1]=magicFactor*dj;
- aPatch->fVertices[2][2][2]=dk;
-
-
- aPatch->fVertices[1][1][0]=di;
- aPatch->fVertices[1][1][1]=magicFactor*dj;
- aPatch->fVertices[1][1][2]=magicFactor*dk;
-
- aPatch->fVertices[2][1][0]=magicFactor*di;
- aPatch->fVertices[2][1][1]=dj;
- aPatch->fVertices[2][1][2]=magicFactor*dk;
-
- // Patch's uv-space information
- if (di>0.0)
- {
- if (dj>0.0)
- {
- aPatch->fu[0]=0.0; // 0
- aPatch->fu[1]=kUmax/4; // to 90∞
- }
- else {
- aPatch->fu[0]=(kUmax+kUmax+kUmax)/4; // 270∞
- aPatch->fu[1]=kUmax; // to 360∞
- }
- }
- else
- {
- if (dj>0.0)
- {
- aPatch->fu[0]=kUmax/4; // 90∞
- aPatch->fu[1]=kUmax/2; // to 180∞
- }
- else
- {
- aPatch->fu[0]=kUmax/2; // 180∞
- aPatch->fu[1]=(kUmax+kUmax+kUmax)/4; // to 270∞
- }
- }
-
- if (dk>0.0)
- {
- aPatch->fv[0]=kVmax/2; // 90∞
- aPatch->fv[1]=kVmax; // to 180∞
- }
- else
- {
- swapUV=aPatch->fu[0];
- aPatch->fu[0]=aPatch->fu[1];
- aPatch->fu[1]=swapUV;
-
- aPatch->fv[0]=kVmax/2;
- aPatch->fv[1]=0.0;
- }
-
- int signi=(di>0.0?1:-1);
- int signj=(dj>0.0?1:-1);
- int signk=(dk>0.0?1:-1);
- if (signi*signj*signk<0)
- {
- InversePatch(aPatch);
- }
-
- aPatch->fUVSpace=0;
- aPatch->fReserved=0;
- }
-
-
- //***********************************************************************
-
-
-
- // Constructor / Destructor of the C++ Object :
- Sphere::Sphere() {
- fCRef=0; // Reference Counter
- }
-
- Sphere::~Sphere() {
- global_count_Obj--;
- }
-
- // IUnknown Interface :
- HRESULT Sphere::QueryInterface(THIS_ REFIID riid,LPVOID FAR* ppvObj) {
- *ppvObj=NULL;
-
- // The Sphere knows the interfaces of the parent Objects
- if (IsEqualIID(riid, IID_IUnknown))
- *ppvObj=(IUnknown*)(I3DExGeometricPrimitive*)this; // this is OK because QueryInterface is only used on PC with C++ and COM
- else if (IsEqualIID(riid, IID_I3DExGeometricPrimitive))
- *ppvObj=(I3DExGeometricPrimitive*)this;
- else if (IsEqualIID(riid, IID_I3DExDataExchanger))
- *ppvObj=(I3DExDataExchanger*)this;
- else if (IsEqualIID(riid, IID_I3DExtension))
- *ppvObj=(I3DExtension*)this;
-
- // we must add reference if we return an interface
- if (*ppvObj!=NULL) {
- ((LPUNKNOWN)*ppvObj)->AddRef();
- return NOERROR;
- }
- else {
- return ResultFromScode(E_NOINTERFACE);
- }
- }
-
- ULONG Sphere::AddRef(THIS) {
- return fCRef++;
- }
-
- ULONG Sphere::Release(THIS) {
- ULONG UnreleaseObject=fCRef--;
-
- if (fCRef==0)
- delete this; // No reference left, so destroy the object
-
- return UnreleaseObject;
- // local variable used, because fCRef can be destroyed before.
- }
-
- // I3DExtension methods :
- I3DExtension* Sphere::Clone(THIS) {
- Sphere* theClone = new Sphere;
- if (theClone) {
- theClone->AddRef();
- }
- return (I3DExtension*)theClone;
- }
-
- HRESULT Sphere::ShellUtilitiesInit(THIS_ IShUtilities* shellUtilities) {
- InitCoFailure(shellUtilities);
- return NOERROR;
- }
-
- // I3DExDataExchanger methods :
- ExtensionDataMap* Sphere::GetExtensionDataMap(THIS) {
- return NULL;
- }
-
- void* Sphere::GetExtensionDataBuffer(THIS) {
- return NULL;
- }
-
- HRESULT Sphere::ExtensionDataChanged(THIS) {
- return NOERROR;
- }
-
- HRESULT Sphere::HandleEvent(THIS_ ULONG SourceID) {
- return ResultFromScode(E_NOTIMPL);
- }
-
- short Sphere::GetResID(THIS) {
- return -1; // always return -1, if you do not have a view
- // Here, we have a view to change the number of branches of the Star
- }
-
- // I3DExGeometricPrimitive methods
- // -- Geometry calls
- HRESULT Sphere::EnumPatches(THIS_ EnumPatchesCallback callback, void* privData) {
- PATCH3D aPatch;
-
- MakeSpherePatch(&aPatch,kDefaultSphereRadius,kDefaultSphereRadius,kDefaultSphereRadius);
- callback(&aPatch,privData);
- MakeSpherePatch(&aPatch,-kDefaultSphereRadius,kDefaultSphereRadius,kDefaultSphereRadius);
- callback(&aPatch,privData);
- MakeSpherePatch(&aPatch,kDefaultSphereRadius,-kDefaultSphereRadius,kDefaultSphereRadius);
- callback(&aPatch,privData);
- MakeSpherePatch(&aPatch,-kDefaultSphereRadius,-kDefaultSphereRadius,kDefaultSphereRadius);
- callback(&aPatch,privData);
- MakeSpherePatch(&aPatch,kDefaultSphereRadius,kDefaultSphereRadius,-kDefaultSphereRadius);
- callback(&aPatch,privData);
- MakeSpherePatch(&aPatch,-kDefaultSphereRadius,kDefaultSphereRadius,-kDefaultSphereRadius);
- callback(&aPatch,privData);
- MakeSpherePatch(&aPatch,kDefaultSphereRadius,-kDefaultSphereRadius,-kDefaultSphereRadius);
- callback(&aPatch,privData);
- MakeSpherePatch(&aPatch,-kDefaultSphereRadius,-kDefaultSphereRadius,-kDefaultSphereRadius);
- callback(&aPatch,privData);
-
- return NOERROR;
- }
-
- HRESULT Sphere::EnumFacets(THIS_ EnumFacetsCallback callback, void* privData, NUM3D fidelity) {
- return ResultFromScode(E_NOTIMPL);
- }
-
- HRESULT Sphere::GetNbrLOD(short &nbrLod) {
- return ResultFromScode(E_NOTIMPL);
- }
-
- HRESULT Sphere::GetLOD(short lodIndex, NUM3D &lod) {
- return ResultFromScode(E_NOTIMPL);
- }
-
- HRESULT Sphere::MakeFacetMesh(short index, FacetMesh &amesh) {
- return ResultFromScode(E_NOTIMPL);
- }
-
- HRESULT Sphere::MakeFacetMesh(NUM3D lod, FacetMesh &amesh) {
- return ResultFromScode(E_NOTIMPL);
- }
-
- // Give the boundary Box
- HRESULT Sphere::GetBBox(THIS_ BOX3D* bbox)
- { bbox->fMin[0]=-kDefaultSphereRadius;
- bbox->fMax[0]=kDefaultSphereRadius;
- bbox->fMin[1]=-kDefaultSphereRadius;
- bbox->fMax[1]=kDefaultSphereRadius;
- bbox->fMin[2]=-kDefaultSphereRadius;
- bbox->fMax[2]=kDefaultSphereRadius;
- return NOERROR;
- }
-
- // -- Shading calls
- ULONG Sphere::GetUVSpaceCount(THIS)
- {
- return 1; // the Sphere is describe with only 1 UV-Space
- }
-
- HRESULT Sphere::GetUVSpace(THIS_ ULONG uvSpaceID, UVSpaceInfo* uvSpaceInfo)
- {
- if (uvSpaceID == 0)
- {
- // UV-Space is equivalent to Spherical Coordinates
- uvSpaceInfo->fMin[0] = 0.0; // u coordinate goes from 0 to 360
- uvSpaceInfo->fMax[0] = kUmax;
- uvSpaceInfo->fMin[1] = 0.0; // v coordinate goes from 0 to 180
- uvSpaceInfo->fMax[1] = kVmax;
-
- uvSpaceInfo->fWraparound[0] = TRUE;
- uvSpaceInfo->fWraparound[1] = FALSE;
- // uvSpaceInfo->fIsFlatSurface = FALSE; // the surface is not flat
- }
- return NOERROR;
- }
-
- // We use the default interpolation method to get all the coordinate of a point in UV Coordinates
- HRESULT Sphere::UV2XYZ(THIS_ VECTOR2D* uv,ULONG uvSpaceID, VECTOR3D* resultPosition, BOOLEAN* inUVSpace) {
- NUM3D phi,theta;
- NUM3D sinphi,cosphi;
- NUM3D sintheta,costheta;
-
- *inUVSpace=TRUE;
- if (((*uv)[0]<0.0) || ((*uv)[0]>=kUmax)) *inUVSpace=FALSE;
- if (((*uv)[1]<0.0) || ((*uv)[1]>=kVmax)) *inUVSpace=FALSE;
-
- if (*inUVSpace==TRUE)
- {
- phi=(*uv)[0];
- theta=(*uv)[1]-(kVmax/2);
-
- // Spherical Coordinates To XYZ-Coordinates
- sinphi=sin(phi);
- cosphi=cos(phi); //phi.DegreeGetSinCos(sinphi,cosphi);
- sintheta=sin(theta);
- costheta=cos(theta); //theta.DegreeGetSinCos(sintheta,costheta);
-
- (*resultPosition)[0]=cosphi*costheta;
- (*resultPosition)[1]=sinphi*costheta;
- (*resultPosition)[2]=sintheta;
- (*resultPosition)[0] *= kDefaultSphereRadius;
- (*resultPosition)[1] *= kDefaultSphereRadius;
- (*resultPosition)[2] *= kDefaultSphereRadius;
- }
-
- return NOERROR;
- }
-
- // -- Ray Tracing calls
- HRESULT Sphere::RayHit(THIS_ BOOLEAN* didHit, Ray3D* aR, RayHitParameters* RayHitParams, RayHit3D* hit)
- {
- VECTOR3D OriginToCenter;
- NUM3D DirectionNorm2;
- NUM3D dotProduct;
- NUM3D t; // Sphere Center = Ray Origin + t * Ray Direction
- VECTOR3D CH; // position of the center projected on the ray
- NUM3D distCH2; // square of the distance of the projected point
- NUM3D resT;
- NUM3D delta,delta2;
- NUM3D radius2=kDefaultSphereRadius*kDefaultSphereRadius;
-
- OriginToCenter[0]=-aR->fOrigin[0];
- OriginToCenter[1]=-aR->fOrigin[1];
- OriginToCenter[2]=-aR->fOrigin[2];
-
- DirectionNorm2=aR->fDirection[0]*aR->fDirection[0] +
- aR->fDirection[1]*aR->fDirection[1] +
- aR->fDirection[2]*aR->fDirection[2];
- dotProduct =aR->fDirection[0]*OriginToCenter[0] +
- aR->fDirection[1]*OriginToCenter[1] +
- aR->fDirection[2]*OriginToCenter[2];
- t=dotProduct/DirectionNorm2;
-
- CH[0]=aR->fOrigin[0]+aR->fDirection[0]*t;
- CH[1]=aR->fOrigin[1]+aR->fDirection[1]*t;
- CH[2]=aR->fOrigin[2]+aR->fDirection[2]*t;
- distCH2=SQR(CH[0]) + SQR(CH[1]) + SQR(CH[2]);
- if (distCH2>radius2) {
- *didHit=FALSE;
- }
- else if (distCH2==radius2) {
- resT=t;
- *didHit=TRUE;
- }
- else { // distCH2<radius2
- *didHit=TRUE;
- delta2=(radius2-distCH2)/DirectionNorm2;
- delta=sqrt(delta2); //delta2.GetSquareRoot(delta);
- resT=t-delta;
- if (resT<=RayHitParams->tmin) {
- resT=t+delta;
- }
- }
- if (resT<=RayHitParams->tmin) {
- *didHit=FALSE;
- }
-
- if (resT>RayHitParams->tmax) {
- *didHit=FALSE;
- }
-
- if (*didHit==TRUE) {
- hit->fPosition[0]=aR->fOrigin[0]+aR->fDirection[0]*resT;
- hit->fPosition[1]=aR->fOrigin[1]+aR->fDirection[1]*resT;
- hit->fPosition[2]=aR->fOrigin[2]+aR->fDirection[2]*resT;
- hit->fNormal[0]=hit->fPosition[0]/kDefaultSphereRadius;
- hit->fNormal[1]=hit->fPosition[1]/kDefaultSphereRadius;
- hit->fNormal[2]=hit->fPosition[2]/kDefaultSphereRadius;
- hit->ft=resT;
- GetDetails(hit);
- }
-
- return NOERROR;
- }
-
- void Sphere::GetDetails(RayHit3D* hit) {
- NUM3D phi,theta,rxy;
- NUM3D sinphi,cosphi,sintheta,costheta;
-
- if (!hit->fShouldSetUV && !hit->fShouldSetIsoUV) return;
-
- phi=atan2(hit->fNormal[1],hit->fNormal[0]); //phi.DegreeSetFromSinCos(hit->fNormal[1],hit->fNormal[0]);
- rxy=hit->fNormal[0]*hit->fNormal[0]+hit->fNormal[1]*hit->fNormal[1];
- rxy=sqrt(rxy); //rxy.GetSquareRoot(rxy);
- theta=atan2(hit->fNormal[2],rxy); //theta.DegreeSetFromSinCos(hit->fNormal[2],rxy);
-
- if (hit->fShouldSetUV) {
- hit->fUV[0]=phi;
- if (theta>kVmax) {
- theta = theta - (kVmax*2);
- }
- hit->fUV[1]=theta+(kVmax/2);
- }
- if (hit->fShouldSetIsoUV) {
- sinphi=sin(phi);
- cosphi=cos(phi); //phi.DegreeGetSinCos(sinphi,cosphi);
- sintheta=sin(theta);
- costheta=cos(theta); //theta.DegreeGetSinCos(sintheta,costheta);
-
- hit->fIsoU[0]=-sinphi*kDefaultSphereRadius;
- hit->fIsoU[1]=cosphi*kDefaultSphereRadius;
- hit->fIsoV[2]=0.0;
- hit->fIsoV[0]=cosphi*sintheta*kDefaultSphereRadius;
- hit->fIsoV[1]=sinphi*sintheta*kDefaultSphereRadius;
- hit->fIsoV[2]=costheta*kDefaultSphereRadius;
- }
-
- }
-
- HRESULT Sphere::GetRayHitDetails(RayHit3D* hit) {
- return ResultFromScode(E_NOTIMPL);
- }
-
- HRESULT Sphere::RayAllHits(THIS_ Ray3D* aR, NUM3D tmin, NUM3D tmax, RayHit3D* hit, RayHitCallback callback, void* privData) {
- return ResultFromScode(E_NOTIMPL);
- }
-
-