Now I've coded up a method to render the entire city to a 512x512 texture, and then I use that texture upsampled for the minimap. It looks like it'll work out quite well. From my previous test sessions with my publisher I've noticed that the lack of a decent mini map was a problem...hopefully that's a thing of the past.
Instead of having the author of each map distribute a .bmp image with each .map city file, I've decided to generate the city mini maps at the start of the game. The most obvious solution would be to use a RenderToTexture function to render the map to a texture...but there are a lot of cards out there that don't support that functionality, or multiple render targets.
So what I decided to do....is at the loading of the particular map, I render the entire map onto the center of the screen and then grab that part of the screen and then load it into a texture file (much like taking a screenshot). Using D3DDevice->GetFrontBufferData(). This seems like it will work on any system. If it turns out that this doesn't work on some systems...I suppose I could just embed each city's mini-map into the .map file format I use. Though it would increase the map size by about 1MB, and make downloading maps from a server less efficient.
Hopefully this method will work out. There is one issue though, because I'm using the front buffer as my render target the user can see the map being displayed...I need to find a work around using multiple swap chains, or something like that. Until then this produces the results I'm going for, and will work on pretty much any system out there...if anybody has some ideas about how to generate these mini maps without them being displayed...I'd like to hear it :-)
Here's the code to do what I'm talking about...I'm really not worried about efficiency since this only gets executed once.
I know a few of these functions are pretty slow, and I'm using the hard disk as a intermediary instead of just going from the copied front buffer surface -> a renderable texture...this is mostly for debugging purposes.
void CCity::GenerateCityMap(LPDIRECT3DTEXTURE9 pMapTexture){ //Temporary variables D3DVIEWPORT9 oldViewport; D3DXMATRIX OldView, OldProj, OldWorld, TempMatrix; int OldTimeOfDay[2] = { GameWorld.m_WorldTime.tm_hour, GameWorld.m_WorldTime.tm_min }; int MapOffset[2] = { (ValidResolutions[GameEngine.GetCurrentResolution()][0]/2)-256, (ValidResolutions[GameEngine.GetCurrentResolution()][1]/2)-256 }; // Save old device info D3DDEVICE->GetViewport(&oldViewport); D3DDEVICE->GetTransform(D3DTS_VIEW, &OldView); D3DDEVICE->GetTransform(D3DTS_PROJECTION, &OldProj); D3DDEVICE->GetTransform(D3DTS_WORLD, &OldWorld); // Setup city map viewport D3DVIEWPORT9 CityMapViewport; CityMapViewport.X = MapOffset[0]; CityMapViewport.Y = MapOffset[1]; CityMapViewport.Width = 512; CityMapViewport.Height = 512; CityMapViewport.MinZ = 0.0f; CityMapViewport.MaxZ = 1.0f; D3DDEVICE->SetViewport(&CityMapViewport); //Make the entire city visible for(int i = 0; i < MAP_SIZE; i++) for(int j = 0; j < MAP_SIZE; j++) { m_VisibilityTable[j] = true; } //end of for loop //Set the lighting conditions //Always render the map at Noon. GameWorld.m_WorldTime.tm_hour = 12; GameWorld.m_WorldTime.tm_min = 0; GameEngine.SetWeatherCondition(); //Generate all of the render groups using the new visibility data. GameEngine.UpdateRenderGroups(true); //Set view/world/projection matrices for the city map render D3DDEVICE->SetTransform(D3DTS_VIEW, D3DXMatrixLookAtLH(&TempMatrix, &D3DXVECTOR3(-10.5,100,-10.5), &D3DXVECTOR3(-10.5,0.1,-10.001), &D3DXVECTOR3(0,1,0))); D3DDEVICE->SetTransform(D3DTS_PROJECTION, D3DXMatrixOrthoLH(&TempMatrix, (MAP_SIZE*TILE_SCALE), (MAP_SIZE*TILE_SCALE), 0.01, 1000.0)); D3DDEVICE->SetTransform(D3DTS_WORLD, D3DXMatrixIdentity(&TempMatrix)); D3DDEVICE->BeginScene(); { //Update shadow map transforms GameEngine.UpdateShadowTransform(); if(GameVariableValues[38] >= 2) { //Global shadow map GameEngine.GenerateShadowMapTexture(0); //Generate local shadow map every frame GameEngine.GenerateShadowMapTexture(1); } //end of if //Clear the area of the screen the map will be rendered to D3DDEVICE->Clear(0, NULL, D3DCLEAR_ZBUFFER|D3DCLEAR_TARGET, 0x00000000, 1.0f, 0L); //Render city GameEngine.RenderScene(false, false); } D3DDEVICE->EndScene(); //Show the map so it can be captured with a screenshot D3DDEVICE->Present(NULL, NULL, NULL, NULL);// Sleep(2000); //Restore old device info D3DDEVICE->SetViewport(&oldViewport); D3DDEVICE->SetTransform(D3DTS_VIEW, &OldView); D3DDEVICE->SetTransform(D3DTS_PROJECTION, &OldProj); D3DDEVICE->SetTransform(D3DTS_WORLD, &OldWorld); GameWorld.m_WorldTime.tm_hour = OldTimeOfDay[0]; GameWorld.m_WorldTime.tm_min = OldTimeOfDay[1]; //Create scratch surface to receive the front buffer copy LPDIRECT3DSURFACE9 pFrontBufferCopy; if(GameEngine.GetWindowed() == true) D3DDEVICE->CreateOffscreenPlainSurface(GameEngine.Direct3D.GetDesktopResolution().x, GameEngine.Direct3D.GetDesktopResolution().y, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &pFrontBufferCopy, NULL); else D3DDEVICE->CreateOffscreenPlainSurface(ValidResolutions[GameEngine.GetCurrentResolution()][0], ValidResolutions[GameEngine.GetCurrentResolution()][1], D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &pFrontBufferCopy, NULL); //Get back buffer surface D3DDEVICE->GetFrontBufferData(0, pFrontBufferCopy); //Specify city map rect, needs to be modified slightly if running in windowed mode. //Only grab the part of the front buffer that contains the 512x512 map! RECT CityMapRect; if(GameEngine.GetWindowed() == false) { CityMapRect.top = MapOffset[1]; CityMapRect.left = MapOffset[0]; CityMapRect.right = CityMapRect.left+512; CityMapRect.bottom = CityMapRect.top+512; } //end of if else { CityMapRect.top = MapOffset[1]+24; CityMapRect.left = MapOffset[0]+3; CityMapRect.right = CityMapRect.left+512; CityMapRect.bottom = CityMapRect.top+512; } //end of else //Save city map image to hard drive //Only save the 512x512 area that contains the map, the region is specified in CityMapRect D3DXSaveSurfaceToFile("CityMap.bmp", D3DXIFF_BMP, pFrontBufferCopy, NULL, &CityMapRect); //Load city map texture from hard drive. SAFE_RELEASE(pMapTexture); D3DXCreateTextureFromFile(D3DDEVICE, "CityMap.bmp", &pMapTexture); //Clean up SAFE_RELEASE(pFrontBufferCopy); DeleteFile("CityMap.bmp");} //end of GenerateCityMap function
But yea...if anybody can follow what I'm doing there, and knows of a widely supported way of doing this other than multiple render targets, lemme know. The only real issue is getting the map to render without displaying it to the user.
I threw together a quick test map...here's how it looks in the map editor.
![](http://www.radioactive-software.com/gangwar/cityeditor/CityEditor_Map1.jpg)
Aaaand here's what the mini map looks like...
![](http://www.radioactive-software.com/gangwar/cityeditor/Map1.jpg)
I think that it came out pretty clean. That's why I like this method so much...it'll generate these on any system that can run the game, regardless of hardware.
Alright back to work...I've fixed many bugs today, but I've still got a lot of work to do, and I'm going to have to create a lot more artwork for the city...I think there isn't enough variety.
Ugh...so much to do, I was hoping to have the game done tommorow...but that's not going to happen. Oh well, my only concern is getting the game up to MY standards, and I'm going to keep working until that happens.
- Dan
*****************************************************
Update....I've scratched the idea of generating the minimaps at load time, and I'll just save them as a .bmp file. The simpler things are the less that can go wrong. This is a much more sound approach. Also now I can guarantee that everyone will see the same mini map, and I can bake shadows into them and do some other cool effects, that not all computers would support.
Yea...this is def. the way to go. Though players will have to download at least 1.5MB worth of data with each custom map.
*****************************************************