//The class emulating the GPU's vertex cache
class CVertexCache{
unsigned int Size; //Quantity of indices the cache can fit
int* Indices; //FIFO buffer storing the vertex indices
public:
int VerticesProcessed; //Stats: total amount of entered indices
int VerticesTransformed; //Stats: amount of indices pushed into the buffer
private:
//Do not allow copying as there is a dynamic array inside
void operator = (CVertexCache){};
CVertexCache(const CVertexCache&){};
public:
//Destructor frees the dynamic array
inline ~CVertexCache(){ free(Indices); memset(this,0,sizeof(CVertexCache)); }
//Check the index-capacity of the cache
inline int GetSize()const{ return Size; }
//Set the desired cache-capacity; returned value is true unless malloc fails
bool SetSize(unsigned int QuantityOfIndexSlots){
this->~CVertexCache();
if(!QuantityOfIndexSlots)return true;
if((Indices=(int*)malloc(QuantityOfIndexSlots*4))==NULL)return false;
Size = QuantityOfIndexSlots;
for(unsigned i=0;i<Size;i++)Indices[i]=-1;
return true;
}//SetSize---------------------------------------------------------------------
//Default constructor
inline CVertexCache(){ memset(this,0,sizeof(CVertexCache)); }
//Constructor that allows to specify the cache size at initialization
inline CVertexCache(unsigned int QuantityOfIndexSlots){
memset(this,0,sizeof(CVertexCache));
SetSize(QuantityOfIndexSlots);
}//Constructor-----------------------------------------------------------------
//Empty the cache buffer and reset the statistics
void Clear(){
VerticesProcessed=0; VerticesTransformed=0;
for(unsigned i=0;i<Size;i++)Indices[i]=-1;
}//Clear-----------------------------------------------------------------------
//Return the index value stored in the specified slot; -1 returned for
//out-of-bounds requests or if the specified slot is empty
inline int operator[](unsigned int SlotID)const{
if(SlotID<0||SlotID>=Size)return -1;
else return Indices[SlotID];
}//Operator[]------------------------------------------------------------------
//Return the number in range [1.0...0.0] representing the relative position of
//the given vertex in the cache; the value 1.0 corresponds to the first
//position, the value (1.f/Position) is for the last one and 0.0 returned if
//the given index is not in the cache
double GetPosition(int Index)const{
for(unsigned i=0;i<Size;i++)if(Indices[i]==Index)
return double(Size-i)/double(Size);
return 0.0;
}//GetPosition-----------------------------------------------------------------
//Introduce a new index; if it is not in the cache already, it will be pushed
//into the FIFO buffer shifting all indices by one position; if the index is
//the restart index, it is silently ignored
void InputVertex(int Index, int PrimitiveRestartIndexValue=0xffffffff){
if(Index==PrimitiveRestartIndexValue)return;
VerticesProcessed++;
if(!Size)return;
for(unsigned i=0;i<Size;i++)if(Indices[i]==Index)return;
VerticesTransformed++;
for(unsigned i=Size-1;i>0;i--)Indices[i]=Indices[i-1];
Indices[0]=Index;
}//InputVertex-----------------------------------------------------------------
//Process all the indices of the given buffer; refer to the stats afterwards;
//the returned value indicates how many times in average each different vertex
//was transformed
double Process(int* IndexBuffer, unsigned int IndexCount,
int PrimitiveRestartIndexValue=0xffffffff){
Clear();
if(!IndexBuffer||!IndexCount)return 0.0;
unsigned VertexCount=0;
for(unsigned i=0;i<IndexCount;i++){
int Index = IndexBuffer[i];
if(Index==PrimitiveRestartIndexValue)continue;
InputVertex(Index,PrimitiveRestartIndexValue);
unsigned s = i;
for(unsigned v=i+1;v<IndexCount;v++)if(IndexBuffer[v]==Index)s=v;
if(s==i)VertexCount++;
}
if(!VertexCount)return 0.0;
return double(VerticesTransformed)/double(VertexCount);
}//Process---------------------------------------------------------------------
};//CVertexCache________________________________________________________________