Game Development Community

dev|Pro Game Development Curriculum

Persistent GuiMapHUD, saved to a file

by Andy Schatz · 10/24/2005 (8:01 am) · 5 comments

This resource will generate a jpg for the background texture of your map and save it with the same name as the terrain file in your level. If a jpg exists with that name already, it will load it from disk instead of regenerating it (similar to how lightmaps work). It does not perform a CRC check, however, you will manually need to trigger the map generation if you want to re-generate it.

1) Remove all references to
mRenderBitmap
from the map files.

In guiMapHUD.h:

2) Change
TextureHandle mRenderTexture;
to
TextureHandle* mRenderTexture;

3) Add to the public portion of the class:
void LoadMapTexture();

4) Change
bool rebuildMapOld();
to
bool rebuildMapOld(GBitmap* bitmap);

In guiMapHUDRender.cc:

5) Change
dglDrawBitmap(mRenderTexture, offset, GFlip_Y);
to
dglDrawBitmap(*mRenderTexture, offset, GFlip_Y);

In guiMapHUD.cc:

6) Add
void GuiMapHud::LoadMapTexture()
{
   char fileNameBuffer[512];
   dStrcpy(fileNameBuffer, mTerrainBlock->mTerrFileName);   
   *(fileNameBuffer+dStrlen(fileNameBuffer)-4) = NULL;
   mRenderTexture = new TextureHandle(fileNameBuffer, BitmapTexture);

   if (mRenderTexture && !(*mRenderTexture))
   {
	   delete mRenderTexture;
	   mRenderTexture = NULL;
	    rebuildMap();
   }

}

7) Add the following code to the onWake call:
mConnection = GameConnection::getServerConnection();
   if(!mConnection)
      return false;

   TerrainBlock* newTerrain = gClientSceneGraph->getCurrentTerrain();
   AssertWarn(newTerrain, "No terrain block!");
   if (!newTerrain)
      return false;

   //ok, we've got everything we need - now do some calculations
   mTerrainBlock = newTerrain;
   mTerrainSize = TerrainBlock::BlockSize * newTerrain->getSquareSize();

   LoadMapTexture();

In GuiMapHUDGen.cc:

8) Change
bool GuiMapHud::rebuildMapOld()
to
bool GuiMapHud::rebuildMapOld(GBitmap* bitmap)

9) In rebuildMapOld, change
glBindTexture(GL_TEXTURE_2D, mRenderTexture.getGLName());
         glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
            texelSquareSize*u, texelSquareSize*v,
            0, 0,
            texelSquareSize, texelSquareSize);
to
for (S32 i=0; i<texelSquareSize; i++)
			glReadPixels(0, i, texelSquareSize, 1, GL_RGB, GL_UNSIGNED_BYTE, (void*)(bitmap->getBits(0)+3*(texelSquareSize*u+mTextureSize*(i+texelSquareSize*v))));

10) Repalce rebuildMap with:
bool GuiMapHud::rebuildMap(bool force)
{
   //make sure we're just above the highest object
   mMaxHeight = 0;
   mMinHeight = 1000;
   for (U32 v = 0; v < TerrainBlock::BlockSize; v++)
   {
      for (U32 u = 0; u < TerrainBlock::BlockSize; u++)
      {
         GridSquare* gs = mTerrainBlock->findSquare(TerrainBlock::BlockShift, u, v);
         if (gs->maxHeight * 0.03125f > mMaxHeight)
            mMaxHeight = gs->maxHeight * 0.03125f;
         if (gs->minHeight * 0.03125f < mMinHeight)
            mMinHeight = gs->minHeight * 0.03125f;
      }
   }

   mMaxHeight += 1;

   FileStream fStream;
   char fileNameBuffer[512];
   dStrcpy(fileNameBuffer, mTerrainBlock->mTerrFileName);
   dStrcpy(fileNameBuffer+dStrlen(fileNameBuffer)-4,".jpg");
   
   if(!fStream.open(fileNameBuffer, FileStream::Write))
   {   
      Con::printf("Failed to open file '%s'.", fileNameBuffer);
      return false;
   }

   //allocate bitmap, and backup old data
   //DON'T NEED TO DELETE BITMAP! TEXTURE MANAGER DOES THIS
   GBitmap* renderBitmap = new GBitmap(mTextureSize, mTextureSize);

   rebuildMapOld(renderBitmap);
   renderBitmap->writeJPEG(fStream);

   fStream.close();
   *(fileNameBuffer+dStrlen(fileNameBuffer)-4) = NULL;
	mRenderTexture = new TextureHandle(fileNameBuffer, renderBitmap);


   return true;
}

#1
10/24/2005 (10:56 am)
You can also modify this to work off of the mission file rather than the terrain file, which is a bit more accurate since the area that is snapshotted is based upon the mission area and a single terrain can be used across several missions that contain different areas.
#2
10/24/2005 (11:36 pm)
Andy, how would you do that?
#3
10/31/2005 (10:20 pm)
In RebuildMap, change the file name selection to be based on the current mission file (I don't have the code in front of me, it's really easy to do though)/ Same in LoadMapTexture.
#4
11/06/2005 (1:31 am)
Interesting, thanks
#5
06/24/2006 (7:57 am)
Added this to my RTS 1.4 build. Only change that needs to be made is...

In guiMapHud.cc

change
mConnection = GameConnection::getServerConnection();

to
mConnection = GameConnection::getConnectionToServer();