Code:
void CScreenGrid::RenderEx(float fTimeDelta)
{
//Starting x and y
int iStartX=(-m_iScrollX % m_iTileWidth);
int iStartY=(-m_iScrollY % m_iTileHeight);
//Set positions to start x and y
int iPosX=iStartX;
int iPosY=iStartY;
//Get the map size from our manager
//All maps are same size regardless of content to speed up renders
//Map 0 will do fine
int iMapWidth=m_pMapManager->GetWidth(0);
int iMapHeight=m_pMapManager->GetHeight(0);
//Compute starting row and column in map
int iStartCol=m_iScrollX/m_iTileWidth;
int iStartRow=m_iScrollY/m_iTileHeight;
//Clamp to 0 to resolve scroll issues
if (iStartCol<=0) iStartCol=0;
if (iStartRow<=0) iStartRow=0;
//Clamp start row and col for scroll issues
if (iStartCol>iMapWidth) iStartCol=iMapWidth;
if (iStartRow>iMapHeight) iStartRow=iMapHeight;
//Set row and col to start row and col
int iRow=iStartRow;
int iCol=iStartCol;
//Compute offset into map and save
//StartOffset is the original offset
UINT uStartOffset=iRow*iMapWidth+iCol;
//Save start offset for a simple and fast way to move down one row
UINT uMapStartOffset=uStartOffset;
//This is the actual offset to pass to the map class
UINT uMapOffset=uStartOffset;
//Current tile ID and last tile ID
UINT nTileID=0,nLastID=0;
//Only 4 vertices are ever rendered at any time
TLVertex Vertices[4];
//Our tile counter - this will become our U texture coord for our quad
//To make it appear as though there are iTileCount tiles being rendered
int iTileCount=0;
//Housekeeping variables
//Indicates we are in a run of identical tiles
bool bRunMode=false;
//Tells the increment portion of the code whether or not to increment
//We don't increment if we just got done drawing
//This way the new vertex positions can be set the next time through
//the loop and they in the correct position
bool bIncrement=true;
//Set our FVF for the entire render
m_pDevice->SetFVF(TLVERTEX_FVF);
//Enable this to see the wireframe mode
//and exactly what the algorithm does
//m_pDevice->SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME);
//Loop through all maps
for (UINT i=0;i<m_pMapManager->GetSize();i++)
{
//Set starting variables for this map
//We need a 3rd map offset var because we change the 2nd (uMapStartOffset)
//in the render. This resets all offsets to the start of the current map
//based on our scroll values
uMapOffset=uStartOffset;
uMapStartOffset=uMapOffset;
iPosX=iStartX;
iPosY=iStartY;
iCol=iStartCol;
iRow=iStartRow;
nLastID=0;
do
{
//Set increment to true
bIncrement=true;
//Grab a tile id at uMapOffset in map i
nTileID=m_pMapManager->GetMapValue(i,uMapOffset);
//Are we in run mode?
if (bRunMode==false)
{
//No so we must be at the start of the process
//Set the first 2 vertices for this quad
Vertices[0]=TLVertex((float)iPosX,
(float)iPosY,
1.0f,
0.0f,0.0f);
Vertices[2]=TLVertex((float)iPosX,
(float)iPosY+(float)m_iTileHeight,
1.0f,
0.0f,1.0f);
//Set last id to current id and increment to true
nLastID=nTileID;
bIncrement=true;
}
//Check if id's match
if (nTileID!=nLastID)
{
//They don't so we must draw something
if (bRunMode)
{
//We were in runmode so we must draw the run now
//However if these are blank tiles, do nothing
if (nLastID!=0xFFFFFFFF)
{
//These are not blank tiles so set the texture
m_pDevice->SetTexture(0,m_pTexManager->GetTexture(nLastID));
//Set the last 2 vertices for the quad
//Use iTileCount as the U coord for this quad
Vertices[1]=TLVertex((float)iPosX,
(float)iPosY,
1.0f,
(float)iTileCount,0.0f);
Vertices[3]=TLVertex((float)iPosX,
(float)iPosY+(float)m_iTileHeight,
1.0f,
(float)iTileCount,1.0f);
//Draw the sucker
m_pDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP,2,&Vertices,sizeof(TLVertex));
}
}
else
{
//We still must draw, but it's only going to be one tile
//No run here
//Do nothing if tile is blank
if (nLastID!=0xFFFFFFFF)
{
//Set texture
m_pDevice->SetTexture(0,m_pTexManager->GetTexture(nLastID));
//Set last 2 vertices
//Use U,V of 1.0f and 1.0f to draw 1 tile
Vertices[1]=TLVertex((float)iPosX,
(float)iPosY,
1.0f,
1.0f,0.0f);
Vertices[3]=TLVertex((float)iPosX,
(float)iPosY+(float)m_iTileHeight,
1.0f,
1.0f,1.0f);
//Draw the sucker
m_pDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP,2,&Vertices,sizeof(TLVertex));
}
}
//Reset our variables in prep for starting process all over again
iTileCount=0;
//Because we just got done drawing and x is incremented after this block,
//we must tell that portion that we don't want to increment on this
//iteration
bIncrement=false;
//Reset runmode - we are starting over so runmode is false
bRunMode=false;
}
else
{
//Tile id's match so set run mode to true
bRunMode=true;
//Nothing special, we just need to increment
bIncrement=true;
}
//If we are in runmode, keep track of how many tiles are identical
if (bRunMode) iTileCount++;
//If we are supposed to increment, let's do it
if (bIncrement)
{
//Increment vertex pos
iPosX+=m_iTileWidth;
//Increment current column
iCol++;
//Increment offset in map
uMapOffset++;
//If we are at edge of screen or at edge of map, we must move down
if (iPosX>m_iScreenWidth || iCol>iMapWidth)
{
//Reset posx to starting posx
iPosX=iStartX;
//Reset our column
iCol=iStartCol;
//Move down one row
iRow++;
//Move vertex pos down one row of tiles
iPosY+=m_iTileHeight;
//Move starting offset down one row
//We cannot just move our offset down one row b/c we would end up
//at the end of the next row
//This is why we 2 vars for map offset
//We increment one which always points to the start of the current row
//which makes it point to the start of the next row
//We then set our offset to the one we just computed
uMapStartOffset+=iMapWidth;
uMapOffset=uMapStartOffset;
//We are not in run mode
bRunMode=false;
//No identical tiles
iTileCount=0;
}
}
//We must repeat the process until we are bottom of screen or bottom of map
} while (iPosY<m_iScreenHeight && iRow<iMapHeight);
}
}
This thing is very fast for two reasons.