Files
FC1/Editor/LightmapCompiler/RasterTable.h
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

463 lines
10 KiB
C++

#pragma once
#include <assert.h> // assert()
#include "SimpleTriangleRasterizer.h" // CSimpleTriangleRasterizer
// This class is to speed up raycasting queries.
// each element in a 2D raster has a pointer (or zero) to a few elements in a second memory(elemets: void *) (0 teminated)
// The raster can be used to query elements on a 3D line - if you project the 3D World down to that raster from one side.
// To get the maximum speedup you shoudl do this from 3 sides.
template <class T>
class CRasterTable
{
public:
//! constructor
CRasterTable( void );
//! destructor
virtual ~CRasterTable( void );
//! alloc raster, after that Phase 1 has started
//! /param indwXSize 1..
//! /param indwYSize 1..
//! /return true=success, false otherwise
bool Init( const DWORD indwXSize, const DWORD indwYSize );
//!
//! free data
void DeInit( void );
//! Has to be called in Phase 1, after Phase 2 has started
//! /return true=success, false otherwise
bool PreProcess( void );
//! call this per triangle after Init and before PreProcess
//! after PreProcess call it again for every triangle
//! /param infX[3] x coordiantes of the 3 vertices in raster units
//! /param infX[3] y coordiantes of the 3 vertices in raster units
//! /param inElement element you want to store
void PutInTriangle( float infX[3], float infY[3], T &inElement );
//! returns pointer to zero terminated array of pointers
//! /param iniX 0..m_dwXSize-1
//! /param iniY 0..m_dwYSize-1
//! /return
T *GetElementsAt( int iniX, int iniY );
//!
//! /return memory consumption in bytes O(1)
DWORD CalcMemoryConsumption( void );
//!
//! /param inPathFileName filename with path and extension
void Debug( const char *inPathFileName ) const;
//!
//! /param outPitchInBytes
//! /return
DWORD *GetDebugData( DWORD &outPitchInBytes ) const;
//!
//! /return width in raster elements
DWORD GetWidth( void );
//!
//! /return height in raster elements
DWORD GetHeight( void );
//! to save memory and make it faster - less cache misses)
// IF YOU WANNA USE THIS FUNCTION, CLEAR IT FIRST BECAUSE IT SIMPLY DOES NOT WORK
void Compress( void );
// **************************************************************
union
{
DWORD * m_pDataCounter; //!< used in Phase 1 [m_dwXSize*m_dwYSize]
T ** m_pDataPtr; //!< used in Phase 2 [m_dwXSize*m_dwYSize]
};
private:
T * m_pExtraMemoryPool; //!< for the pointers to store (zero terminated) (sorted in ascending order) [m_ExtraMemorySize]
DWORD m_ExtraMemorySize; //!< extra memroy pool size in StoredElementPtr elements
DWORD m_dwXSize; //!< width of the buffer 1.. if allocated, otherwise 0
DWORD m_dwYSize; //!< height of the buffer 1.. if allocated, otherwise 0
//! callback function
class CPixelIncrement: public CSimpleTriangleRasterizer::IRasterizeSink
{
public:
//! constructor
CPixelIncrement( DWORD *inpBuffer, DWORD indwWidth, DWORD indwHeight )
{
m_pBuffer=inpBuffer;
m_dwWidth=indwWidth;
m_dwHeight=indwHeight;
}
//!
virtual void Line( const float infXLeft, const float infXRight,
const int iniLeft, const int iniRight, const int iniY )
{
assert(iniLeft>=0);
assert(iniY>=0);
assert(iniRight<=(int)m_dwWidth);
assert(iniY<(int)m_dwHeight);
DWORD *pMem=&m_pBuffer[iniLeft+iniY*m_dwWidth];
for(int x=iniLeft;x<iniRight;x++)
{
*pMem=*pMem+1;
pMem++;
}
}
DWORD * m_pBuffer; //!<
DWORD m_dwWidth; //!< x= [0,m_dwWidth[
DWORD m_dwHeight; //!< y= [0,m_dwHeight[
};
//! callback function
template <class T>
class CPixelAddArrayElement: public CSimpleTriangleRasterizer::IRasterizeSink
{
public:
//! constructor
CPixelAddArrayElement( T **inpBuffer, DWORD indwWidth, T *inElementPtr )
{
m_pBuffer=inpBuffer;
m_dwWidth=indwWidth;
m_ElementPtr=inElementPtr;
}
//!
__forceinline void ReturnPixel( T * &rPtr )
{
--rPtr;
*rPtr=*m_ElementPtr;
}
//!
virtual void Line( const float infXLeft, const float infXRight,
const int iniLeft, const int iniRight, const int iniY )
{
T **pMem=&m_pBuffer[iniLeft+iniY*m_dwWidth];
for(int x=iniLeft;x<iniRight;x++)
ReturnPixel(*pMem++);
}
T * m_ElementPtr; //!< element to store
T ** m_pBuffer; //!< pointer to the array buffer
DWORD m_dwWidth; //!< width of the buffer
};
};
// constructor
template <class T>
CRasterTable<T>::CRasterTable( void )
{
assert(sizeof(DWORD)==sizeof(DWORD *)); // only for 32 Bit compiler
m_pDataPtr=0;
m_pExtraMemoryPool=0;
m_ExtraMemorySize=0;
}
// destructor
template <class T>
CRasterTable<T>::~CRasterTable( void )
{
DeInit();
}
// free data
template <class T>
void CRasterTable<T>::DeInit( void )
{
delete [] m_pDataCounter;m_pDataCounter=0;
delete [] m_pExtraMemoryPool;m_pExtraMemoryPool=0;
m_ExtraMemorySize=0;
m_dwXSize=0;
m_dwYSize=0;
}
// alloc raster, after that Phase 1 has started
template <class T>
bool CRasterTable<T>::Init( const DWORD indwXSize, const DWORD indwYSize )
{
assert(!m_pDataCounter);
assert(!m_pExtraMemoryPool); DeInit();
assert(indwXSize);
assert(indwYSize);
m_dwXSize=indwXSize;
m_dwYSize=indwYSize;
assert(sizeof(DWORD)==sizeof(T *));
m_pDataCounter=new DWORD[m_dwXSize*m_dwYSize];
if(m_pDataCounter)
memset(m_pDataCounter,0,m_dwXSize*m_dwYSize*sizeof(DWORD));
return(m_pDataPtr!=0);
}
// Has to be called in Phase1, after that Phase 2 has started
template <class T>
bool CRasterTable<T>::PreProcess( void )
{
assert(m_pDataCounter);
assert(!m_pExtraMemoryPool);
assert(!m_ExtraMemorySize);
DWORD dwSum=0; // extra memroy pool size in StoredElementPtr elements
{
DWORD *ptr=m_pDataCounter;
for(DWORD i=0;i<m_dwXSize*m_dwYSize;i++)
{
DWORD dwNumEl=*ptr++;
if(dwNumEl!=0)
dwSum+=dwNumEl+1; // Elements + NullTermination
}
}
if(dwSum==0)return(true); // no information to store - no problem
m_pExtraMemoryPool=new T[dwSum];
m_ExtraMemorySize=dwSum;
if(!m_pExtraMemoryPool)return(false);
memset(m_pExtraMemoryPool,0,dwSum*sizeof(T));
// build the access structure for compressing the elements in a vector (pointer is in the beginning on the last element)
// after filing in the triangles once again the pointer is on the first element
{
DWORD *ptr1=m_pDataCounter;
T **ptr2=m_pDataPtr;
T *dest=m_pExtraMemoryPool;
for(DWORD i=0;i<m_dwXSize*m_dwYSize;i++)
{
DWORD dwNumEl=*ptr1++;
if(dwNumEl!=0)
{
dest+=dwNumEl;
*ptr2++=dest;
dest++; // Elements + NullTermination
}
else *ptr2++=0;
}
}
return(true);
}
// call this per triangle after Init and before PreProcess
// after PreProcess call it again for every triangle
template <class T>
void CRasterTable<T>::PutInTriangle( float infX[3], float infY[3], T &inElement )
{
float fU[3],fV[3];
for(int i=0;i<3;i++)
{
fU[i]=infX[i];fV[i]=infY[i];
}
CSimpleTriangleRasterizer Rasterizer(m_dwXSize,m_dwYSize);
if(m_pExtraMemoryPool==0) // Phase 1
{
CPixelIncrement pix(m_pDataCounter,m_dwXSize,m_dwYSize);
Rasterizer.CallbackFillConservative(fU,fV,&pix);
}
else // Phase 2
{
CPixelAddArrayElement<T> pix(m_pDataPtr,m_dwXSize,&inElement);
Rasterizer.CallbackFillConservative(fU,fV,&pix);
}
}
// returns pointer to zero terminated array of pointers
template <class T>
T *CRasterTable<T>::GetElementsAt( int iniX, int iniY )
{
assert(iniX>=0);
assert(iniX<(int)m_dwXSize);
assert(iniY>=0);
assert(iniY<(int)m_dwYSize);
T *pRet=m_pDataPtr[iniY*m_dwXSize+iniX];
if(pRet)
assert(*pRet); // no pointer in the raster should point to empty list
return(pRet);
}
// returns pointer to zero terminated array of pointers
// IF YOU WANNA USE THIS FUNCTION, CLEAR IT FIRST BECAUSE IT SIMPLY DOES NOT WORK
template <class T>
void CRasterTable<T>::Compress( void )
{
if(!m_pExtraMemoryPool)return;
T *pDestStart=0;
DWORD dwNewMemorySize=0;
for(DWORD i=0;i<m_dwXSize*m_dwYSize;i++)
{
T *pSrcStart=m_pDataPtr[i]; // pointer from the raster element
if(!pSrcStart)continue; // no elements there
{
bool bAddBucket=true;
T *pSrc=pSrcStart, *pDest=pDestStart;
if(pDestStart)
while(*pSrc == *pDest)
{
if(*pSrc==0)
{
// buckets are fully identical
bAddBucket=false;
break;
}
pDest++;pSrc++;
}
if(bAddBucket)
{
if(!pDestStart) pDestStart=m_pExtraMemoryPool;
else
{
while(*pDestStart)pDestStart++; pDestStart++;
}
// copy bucket
T *pSrc=pSrcStart, *pDest=pDestStart;
while(*pSrc)
{ *pDest++=*pSrc++;dwNewMemorySize++; }
*pDest++=0; // 0 terminate
assert(*pDestStart); // no pointer in the raster should point to empty list
m_pDataPtr[i]=pDestStart;
}
else m_pDataPtr[i]=pDestStart;
}
}
T *newMem=new T[dwNewMemorySize];
if(!newMem)return; // no memory - no compression
// copy in new buffer
memcpy(newMem,m_pExtraMemoryPool,dwNewMemorySize*sizeof(T));
// correct the pointers to the new buffer
for(i=0;i<m_dwXSize*m_dwYSize;i++)
{
if(m_pDataPtr[i])
{
assert(*m_pDataPtr[i]); // no pointer in the raster should point to empty list
m_pDataPtr[i]=(T *)( (DWORD)(m_pDataPtr[i]) - (DWORD)m_pExtraMemoryPool + (DWORD)newMem);
assert(*m_pDataPtr[i]); // no pointer in the raster should point to empty list
}
}
delete [] m_pExtraMemoryPool;
// set new buffer
m_pExtraMemoryPool=newMem;
float fRatio=(float)dwNewMemorySize/(float)m_ExtraMemorySize;
}
// calculates memory consumption in bytes O(1)
template <class T>
DWORD CRasterTable<T>::CalcMemoryConsumption( void )
{
return(m_dwXSize*m_dwYSize*sizeof(m_pDataCounter)+m_ExtraMemorySize*sizeof(T));
}
template <class T>
void CRasterTable<T>::Debug( const char *inPathFileName ) const
{
#ifdef _TGA_LOADER_INCLUDED
for(DWORD i=0;i<m_dwXSize*m_dwYSize;i++)
m_pDataCounter[i]=m_pDataCounter[i]*10+0x0800;
PIX_SaveTGA32(inPathFileName,(unsigned char *)m_pDataCounter,m_dwXSize,m_dwYSize,false,false);
for(DWORD i=0;i<m_dwXSize*m_dwYSize;i++)
m_pDataCounter[i]=(m_pDataCounter[i]-0x0800)/10;
#endif
}
template <class T>
DWORD *CRasterTable<T>::GetDebugData( DWORD &outPitchInBytes ) const
{
outPitchInBytes=m_dwXSize*sizeof(DWORD);
return(m_pDataCounter);
}
template <class T>
DWORD CRasterTable<T>::GetWidth( void )
{
return(m_dwXSize);
}
template <class T>
DWORD CRasterTable<T>::GetHeight( void )
{
return(m_dwYSize);
}