#pragma once #include "RasterTable.h" // CRasterTable #include // assert() #include #include template class _Matrix34C; template class _Vector2dC; template < class T > class _Vector3dC { public: T p[3]; // default constructor _Vector3dC (); // constructor _Vector3dC ( T x, T y, T z ); _Vector3dC ( const _Vector3dC &x ); _Vector3dC ( const _Vector2dC &x ); _Vector3dC ( const Vec3d &x ) { p[0]=(T)x.x;p[1]=(T)x.y;p[2]=(T)x.z; } _Vector3dC ( const T &x ); void Set ( T x, T y, T z ); void Max ( const _Vector3dC &c ); void Min ( const _Vector3dC &c ); const _Vector3dC operator- ( void ) const; _Vector3dC operator- ( const _Vector3dC &other ) const; _Vector3dC operator-= ( const _Vector3dC &other ); _Vector3dC operator+ ( const _Vector3dC &other ) const; _Vector3dC operator+= ( const _Vector3dC &other ); T operator* ( const _Vector3dC &other ) const; _Vector3dC operator* ( const T fak ) const; _Vector3dC operator*= ( const T fak ); _Vector3dC operator/= ( const T fak ); bool operator== ( const _Vector3dC &outher ) const; T Length ( void ) const; double LengthQuad ( void ) const; void Normalize ( void ); // a=thumb, b=zeigefinger, b=mittelfinger mit rechter Hand friend _Vector3dC CrossProd ( const _Vector3dC &a, const _Vector3dC &b ); // Kreuzprodukt friend _Vector3dC operator* ( const T t, const _Vector3dC &a ); }; template _Vector3dC::_Vector3dC() {} template _Vector3dC::_Vector3dC( T x, T y, T z ) { p[0]=x;p[1]=y;p[2]=z; } template _Vector3dC::_Vector3dC( const T &x ) { assert(x==0); // sonst macht das glaub ich keinen Sinn p[0]=x;p[1]=x;p[2]=x; } template _Vector3dC::_Vector3dC( const _Vector3dC &x ) { p[0]=x.p[0];p[1]=x.p[1];p[2]=x.p[2]; } template _Vector3dC::_Vector3dC( const _Vector2dC &x ) { p[0]=x.p[0];p[1]=x.p[1];p[2]=0; } template void _Vector3dC::Set( T x, T y, T z ) { p[0]=x;p[1]=y;p[2]=z; } template _Vector3dC _Vector3dC::operator-( const _Vector3dC &b ) const { return _Vector3dC(p[0]-b.p[0],p[1]-b.p[1],p[2]-b.p[2] ); }; template _Vector3dC _Vector3dC::operator-=( const _Vector3dC &b ) { p[0]-=b.p[0];p[1]-=b.p[1];p[2]-=b.p[2]; return *this; } template _Vector3dC _Vector3dC::operator+( const _Vector3dC &b ) const { return _Vector3dC(p[0]+b.p[0],p[1]+b.p[1],p[2]+b.p[2] ); } template _Vector3dC _Vector3dC::operator+=( const _Vector3dC &b ) { p[0]+=b.p[0];p[1]+=b.p[1];p[2]+=b.p[2]; return *this; } template _Vector3dC _Vector3dC::operator*( const T f ) const { return _Vector3dC(p[0]*f,p[1]*f,p[2]*f ); } template T _Vector3dC::operator*( const _Vector3dC &b ) const { return(p[0]*b.p[0]+p[1]*b.p[1]+p[2]*b.p[2]); } template bool _Vector3dC::operator==( const _Vector3dC &other ) const { if(p[0]!=other.p[0])return(false); if(p[1]!=other.p[1])return(false); if(p[2]!=other.p[2])return(false); return(true); } template _Vector3dC _Vector3dC::operator*=( const T f ) { p[0]*=f;p[1]*=f;p[2]*=f; return(*this); } template _Vector3dC _Vector3dC::operator/=( const T f ) { T fInv=1/f; p[0]*=fInv;p[1]*=fInv;p[2]*=fInv; return(*this); } template _Vector3dC CrossProd( const _Vector3dC &a, const _Vector3dC &b ) { _Vector3dC ret; ret.p[0]=a.p[1]*b.p[2] - a.p[2]*b.p[1]; ret.p[1]=a.p[2]*b.p[0] - a.p[0]*b.p[2]; ret.p[2]=a.p[0]*b.p[1] - a.p[1]*b.p[0]; return(ret); } template void _Vector3dC::Normalize( void ) { T len=1.0f/Length(); p[0]*=len;p[1]*=len;p[2]*=len; } template T _Vector3dC::Length( void ) const { return( (T)sqrt(p[0]*p[0]+p[1]*p[1]+p[2]*p[2]) ); } // unary negation template const _Vector3dC _Vector3dC::operator-( void ) const { return(_Vector3dC(-p[0],-p[1],-p[2])); } typedef _Vector3dC CVector3D; template class CPossibleIntersectionSink { public: //! return one element from the bucket //! /param inObject //! /param inoutfRayMaxDist in and out value for max. shooting distance or FLT_MAX, if you found a interesection you may update this because further intersections are no longer interesting //! /return true=do further processing, false=stop I found what I need (e.g. any intersection for shadow testing) bool ReturnElement( T &inObject, float &inoutfRayMaxDist ); //! void EndReturningBucket( void ) {} }; template class CRasterCube { public: //! default constructor CRasterCube( void ); //! destructor virtual ~CRasterCube( void ); //! alloc raster, after that Phase 1 has started //! /param invMin minimum values for the bounding box //! /param invMax maximum values for the bounding box //! /param inElementCount element count for the data structure size estimation //! /param infMagnifier scale factor for internal data structures (scales ~ quadratic in memory consumptions) //! /return true=success, false otherwise bool Init( const CVector3D invMin, const CVector3D invMax, DWORD inElementCount, float infMagnifier=1.0f ); //! free data void DeInit( void ); //! Has to be called in Phase1, after that Phase 2 has started //! /param inbDebug debug output is generated //! /return true=success, false otherwise bool PreProcess( const bool inbDebug ); //! Has to be called after Phase2 void Compress( void ); //! call this per triangle after Init and before PreProcess //! after PreProcess call it again for every triangle //! /param invVertex //! /param inpElement void PutInTriangle( const Vec3d invVertex[3], const T &inElement ); //! //! /param outdwSize //! /return memory consumption in bytes O(1) DWORD CalcMemoryConsumption( DWORD outdwSize[3] ); // this works because m_pExtraMemoryPool is sorted in ascending order // returns true if inSink.ReturnElement returns false(meaning stop processing), does not bother if bBreakAfterFirstHit = false template const bool GatherElementsAt( int iniPos[3], Sink &inSink, float& rfRet ) { rfRet=FLT_MAX; DWORD *pElX = 0; if(bUseXRaster) { pElX=m_XRaster.GetElementsAt(iniPos[1],iniPos[2]); // YZ if(!pElX)return(false); } DWORD *pElY=m_YRaster.GetElementsAt(iniPos[2],iniPos[0]); // ZX if(!pElY)return(false); DWORD *pElZ=m_ZRaster.GetElementsAt(iniPos[0],iniPos[1]); // XY if(!pElZ)return(false); if(bUseXRaster) assert(*pElX); assert(*pElY); assert(*pElZ); // get the intersection of all three lists for(;;) { // increase pointer to the biggest values if(bUseXRaster) { if(*pElY>*pElX) { if(*pElZ>*pElY){ pElZ++;if(*pElZ==0)break; } else { pElY++;if(*pElY==0)break; } } else { if(*pElZ>*pElX){ pElZ++;if(*pElZ==0)break; } else { if(*pElX==*pElY && *pElY==*pElZ) { if(bBreakAfterFirstHit) { if(!inSink.ReturnElement(m_vElements[(*pElX++)-1],rfRet)) { inSink.EndReturningBucket(); return true; } } else inSink.ReturnElement(m_vElements[(*pElX++)-1],rfRet); // -1 because 0 is used for termination if(*pElX==0)break; pElY++;if(*pElY==0)break; pElZ++;if(*pElZ==0)break; } else { pElX++;if(*pElX==0)break; } } } } else//bUseXRaster = false { if(*pElZ > *pElY) { pElZ++; if(*pElZ==0) break; } else { if(*pElZ < *pElY) { pElY++; if(*pElY==0) break; } else //*pElY == *pElZ { if(bBreakAfterFirstHit) { if(!inSink.ReturnElement(m_vElements[(*pElY++)-1],rfRet)) { inSink.EndReturningBucket(); return true; } } else inSink.ReturnElement(m_vElements[(*pElY++)-1],rfRet); // -1 because 0 is used for termination if(*pElY==0) break; pElZ++; if(*pElZ==0) break; } } } } inSink.EndReturningBucket(); return(false); } // raytracing, gather unsorted hits (sorted could give faster access to the first hit) // call ClearListBefore and GetHitList afterwards // if bBreakAfterFirstHit=true it returns immediately if GatherElementsAt returns true (this is when inSink.ReturnElement returns false(meaning stop processing)) template void GatherRayHitsDirection( const CVector3D _invStart, const CVector3D _invDir, Sink &inSink, const float infRayMax=FLT_MAX ) { CVector3D invStart,vDirRelative; // scaled to the internal representation // tranform the ray into the RasterCubeSpace for(int i=0;i<3;i++) { double fScale=(((double)(m_iSize[i]))/((double)m_vMax.p[i]-(double)m_vMin.p[i])); invStart.p[i]=(_invStart.p[i]-m_vMin.p[i])*fScale; vDirRelative.p[i]=_invDir.p[i]*fScale; } CVector3D vDir=vDirRelative; int iPos[3]={ (int)floor(invStart.p[0]),(int)floor(invStart.p[1]),(int)floor(invStart.p[2]) }; // floor done // integer direction int iDir[3]={ -1,-1,-1 }; CVector3D vPosInCube( fmod(fabs(invStart.p[0]),1),fmod(fabs(invStart.p[1]),1),fmod(fabs(invStart.p[2]),1) ); if(vDir.p[0]>0){ iDir[0]=1;vDir.p[0]=-vDir.p[0];vPosInCube.p[0]=1.0f-vPosInCube.p[0]; } if(vDir.p[1]>0){ iDir[1]=1;vDir.p[1]=-vDir.p[1];vPosInCube.p[1]=1.0f-vPosInCube.p[1]; } if(vDir.p[2]>0){ iDir[2]=1;vDir.p[2]=-vDir.p[2];vPosInCube.p[2]=1.0f-vPosInCube.p[2]; } // make sure it's in the range 0..1 if(vPosInCube.p[0]<=0)vPosInCube.p[0]++; if(vPosInCube.p[1]<=0)vPosInCube.p[1]++; if(vPosInCube.p[2]<=0)vPosInCube.p[2]++; assert(vPosInCube.p[0]>0); assert(vPosInCube.p[1]>0); assert(vPosInCube.p[2]>0); assert(vPosInCube.p[0]<=1.0f); assert(vPosInCube.p[1]<=1.0f); assert(vPosInCube.p[2]<=1.0f); // calculate T and StepT double fT[3],fTStep[3]; if(vDir.p[0]!=0.0) { fTStep[0]=1.0/vDir.p[0];fT[0]=vPosInCube.p[0]*fTStep[0]; } else { fTStep[0]=0.0;fT[0]=-FLT_MAX; } if(vDir.p[1]!=0.0) { fTStep[1]=1.0/vDir.p[1];fT[1]=vPosInCube.p[1]*fTStep[1]; } else { fTStep[1]=0.0;fT[1]=-FLT_MAX; } if(vDir.p[2]!=0.0) { fTStep[2]=1.0/vDir.p[2];fT[2]=vPosInCube.p[2]*fTStep[2]; } else { fTStep[2]=0.0;fT[2]=-FLT_MAX; } float fRayMax=infRayMax; int iEndBorder[3]; CalcNewBorder(invStart,vDirRelative,fRayMax,iDir,iEndBorder); float fNewRayMax; for(;;) { // get elements if we are in the block if((DWORD)iPos[0]<(DWORD)m_iSize[0]) if((DWORD)iPos[1]<(DWORD)m_iSize[1]) if((DWORD)iPos[2]<(DWORD)m_iSize[2]) { if(bBreakAfterFirstHit) { if(GatherElementsAt(iPos,inSink, fNewRayMax)) return;//one valid hit found, stop here } else GatherElementsAt(iPos,inSink, fNewRayMax); // Baustelle // new Border if(fNewRayMax0){ if(iPos[0]>=iEndBorder[0])break; } else { if(iPos[0]<=iEndBorder[0])break; } if(iDir[1]>0){ if(iPos[1]>=iEndBorder[1])break; } else { if(iPos[1]<=iEndBorder[1])break; } if(iDir[2]>0){ if(iPos[2]>=iEndBorder[2])break; } else { if(iPos[2]<=iEndBorder[2])break; } } } template void GatherRayHitsTo( const CVector3D _invStart, const CVector3D _invEnd, Sink &inSink ) { CVector3D vDir=_invEnd-_invStart; float fRayMax=(float)vDir.Length(); vDir.Normalize(); // Baustelle GatherRayHitsDirection(_invStart,vDir,inSink,fRayMax); } private: CVector3D m_vMin; //!< bounding box min from Init() parameters) CVector3D m_vMax; //!< bounding box max from Init() parameters) int m_iSize[3]; //!< integer size of the internal raster images std::vector m_vElements; //!< index to the elements that are put in CRasterTable m_XRaster; //!< YZ internal raster images - index-1 to m_vElements because 0 is used for termination CRasterTable m_YRaster; //!< ZX internal raster images - index-1 to m_vElements because 0 is used for termination CRasterTable m_ZRaster; //!< XY internal raster images - index-1 to m_vElements because 0 is used for termination void CalcNewBorder( CVector3D &invStart, CVector3D &invDirRelative, float infRayMax, int iniDir[3], int outiNewBorder[3] ) { if(infRayMax==FLT_MAX) { if(iniDir[0]>0)outiNewBorder[0]=m_iSize[0]; else outiNewBorder[0]=-1; if(iniDir[1]>0)outiNewBorder[1]=m_iSize[1]; else outiNewBorder[1]=-1; if(iniDir[2]>0)outiNewBorder[2]=m_iSize[2]; else outiNewBorder[2]=-1; return; } CVector3D vNewEnd=invStart + invDirRelative*infRayMax; for(int i=0;i<3;i++) { outiNewBorder[i]=(int)floor(vNewEnd.p[i])+iniDir[i]; if(outiNewBorder[i]<-1)outiNewBorder[i]=-1; if(outiNewBorder[i]>m_iSize[i])outiNewBorder[i]=m_iSize[i]; } } }; // constructor template CRasterCube::CRasterCube( void ) { DeInit(); } // destructor template CRasterCube::~CRasterCube( void ) { DeInit(); } // free data template void CRasterCube::DeInit( void ) { if(bUseXRaster) m_XRaster.DeInit(); m_YRaster.DeInit(); m_ZRaster.DeInit(); m_iSize[0]=m_iSize[1]=m_iSize[2]=0; } // alloc raster, after that Phase 1 has started template bool CRasterCube::Init( const CVector3D invMin, const CVector3D invMax, DWORD inElementCount, float infMagnifier ) { m_vElements.reserve(inElementCount); CVector3D vSize; m_vMin=invMin; m_vMax=invMax; vSize=m_vMax-m_vMin; float fAvgSize=((float)vSize.p[0]+(float)vSize.p[1]+(float)vSize.p[2])/3.0f; if(fAvgSize==0.0f)return(false); float fMassSideLength=(float)sqrt((double)inElementCount) * infMagnifier; m_iSize[0]=(int)(vSize.p[0]/fAvgSize * fMassSideLength)+2; m_iSize[1]=(int)(vSize.p[1]/fAvgSize * fMassSideLength)+2; m_iSize[2]=(int)(vSize.p[2]/fAvgSize * fMassSideLength)+2; /* char str[256]; sprintf(str,"CRasterCube::Init %dx%dx%d\n",m_iSize[0],m_iSize[1],m_iSize[2]); OutputDebugString(str); */ CVector3D vBorder=CVector3D((vSize.p[0]+1.0f)/(float)m_iSize[0],(vSize.p[1]+1.0f)/(float)m_iSize[1],(vSize.p[2]+1.0f)/(float)m_iSize[2]); m_vMin-=vBorder*2; m_vMax+=vBorder*2; const int iMinimumSize=3; if(m_iSize[0] void CRasterCube::PutInTriangle( const Vec3d invVertices[3], const T &inpElement ) { float fX[3],fY[3]; double fScale[3]; DWORD dwElementNo=(DWORD)(m_vElements.size()+1); // +1 because 0 is used for termination fScale[0]=(((double)(m_iSize[0]))/(m_vMax.p[0]-m_vMin.p[0])); fScale[1]=(((double)(m_iSize[1]))/(m_vMax.p[1]-m_vMin.p[1])); fScale[2]=(((double)(m_iSize[2]))/(m_vMax.p[2]-m_vMin.p[2])); if(bUseXRaster) { fX[0]=(float)((invVertices[0].y-m_vMin.p[1])*fScale[1]);fY[0]=(float)((invVertices[0].z-m_vMin.p[2])*fScale[2]); fX[1]=(float)((invVertices[1].y-m_vMin.p[1])*fScale[1]);fY[1]=(float)((invVertices[1].z-m_vMin.p[2])*fScale[2]); fX[2]=(float)((invVertices[2].y-m_vMin.p[1])*fScale[1]);fY[2]=(float)((invVertices[2].z-m_vMin.p[2])*fScale[2]); m_XRaster.PutInTriangle(fX,fY,dwElementNo); } fX[0]=(float)((invVertices[0].z-m_vMin.p[2])*fScale[2]);fY[0]=(float)((invVertices[0].x-m_vMin.p[0])*fScale[0]); fX[1]=(float)((invVertices[1].z-m_vMin.p[2])*fScale[2]);fY[1]=(float)((invVertices[1].x-m_vMin.p[0])*fScale[0]); fX[2]=(float)((invVertices[2].z-m_vMin.p[2])*fScale[2]);fY[2]=(float)((invVertices[2].x-m_vMin.p[0])*fScale[0]); m_YRaster.PutInTriangle(fX,fY,dwElementNo); fX[0]=(float)((invVertices[0].x-m_vMin.p[0])*fScale[0]);fY[0]=(float)((invVertices[0].y-m_vMin.p[1])*fScale[1]); fX[1]=(float)((invVertices[1].x-m_vMin.p[0])*fScale[0]);fY[1]=(float)((invVertices[1].y-m_vMin.p[1])*fScale[1]); fX[2]=(float)((invVertices[2].x-m_vMin.p[0])*fScale[0]);fY[2]=(float)((invVertices[2].y-m_vMin.p[1])*fScale[1]); m_ZRaster.PutInTriangle(fX,fY,dwElementNo); m_vElements.push_back(inpElement); } // Has to be called in Phase1, after that Phase 2 has started template bool CRasterCube::PreProcess( const bool inbDebug ) { if(inbDebug) { if(bUseXRaster) m_XRaster.Debug("CRasterCubeDebugX.tga"); m_YRaster.Debug("CRasterCubeDebugY.tga"); m_ZRaster.Debug("CRasterCubeDebugZ.tga"); } if(bUseXRaster) if(!m_XRaster.PreProcess()) return(false); if(!m_YRaster.PreProcess()) return(false); if(!m_ZRaster.PreProcess()) return(false); return(true); } // Has to be called in Phase1, after that Phase 2 has started template void CRasterCube::Compress( void ) { if(bUseXRaster) m_XRaster.Compress(); m_YRaster.Compress(); m_ZRaster.Compress(); } //! /param inT //! /return 0/1/2 plane axis that was hit __forceinline int GetBiggestValue( double inT[3] ) { // get the biggest value if(inT[0]>inT[1]) { if(inT[2]>inT[0]) return(2); else return(0); } else { if(inT[2]>inT[1]) return(2); else return(1); } } // calculates memory consumption in bytes O(1) template DWORD CRasterCube::CalcMemoryConsumption( DWORD outdwSize[3] ) { outdwSize[0]=m_iSize[0]; outdwSize[1]=m_iSize[1]; outdwSize[2]=m_iSize[2]; if(bUseXRaster) return(m_XRaster.CalcMemoryConsumption()+m_YRaster.CalcMemoryConsumption()+m_ZRaster.CalcMemoryConsumption()+sizeof(*this)); else return(m_YRaster.CalcMemoryConsumption()+m_ZRaster.CalcMemoryConsumption()+sizeof(*this)); }