Commander Map
by Kyle Carter · 03/01/2004 (10:52 am) · 155 comments
Download Code File
To use this resource:
1. Copy guiCommanderHud.cc to your engine/gui subfolder.
2. Open your IDE of choice (or a text editor if that's what you like).
3. Add the source file to your project so it will be compiled into Torque.
4. Do a clean rebuild.
5. Go to the GUI of your choice and add a GuiCommanderHud to it. Poof, instant GUI!
Security and Scoping Issues:
The HUD is designed to prevent people from abusing it in-game. It does not change how anything is scoped, so people will only see what the net code would have previously allowed them to see. If you want to have a special "commander map" behavior that shows all active objects you will need to add it either via server side scripting or in GameConnection::doneScopingScene(). Remember, the best way to prevent cheating and improve net performance on your game is to only scope what people need to see.
If you're particularly paranoid, you may want to remove the ConsoleMethods at the end of the file and control the commander map with events; this is probably unnecessary in most cases, as the commander map reveals no more information than the player could get by opening a map in single player mode or a dedicated server and flying/walking around.
Panning and Zooming:
There are three useful actions you can do via scripting with the GuiCommanderHud. First, you can zoom. This basically consists of changing the FOV of the overhead camera that the view is being rendered from (see GuiCommanderHud::processCameraQuery()), so you want to stick to values between 0 and one half pi. Larger values can give "interesting" results though no value should crash the engine. The available script methods for this are zoom() to instantly set the zoom level and zoomTo() to smoothly interpolate to the requested zoom level.
pan() and panTo() let you set the x,y co-ordinates of the overhead camera - essentially setting where the center of the map is. If you wish to pan onto an object, get the first two words of its position and pass them to pan() or panTo().
There are also two exposed fields, panSpeed and zoomSpeed, which let you tweak how quickly panning and zooming occurs. Negative values for these will give catastrophic results!
Performance:
On a 1.8Ghz P4 with 512mb of RAM and a GeForce 4 440 Go (equivalent to a fast GeForce 2), I get 70fps in the test FPS level without the map on screen, and 40fps with it on the screen (in addition to the normal FPS view). Suggested usage is to run the GuiCommanderHud in its own GUI, so that you don't have the overhead of the PlayGUI and its view of the world.
The GuiCommanderHud only renders interior, terrain, water, and environmental objects. You can easily change the mask it uses for rendering the scene by editing GuiCommanderHud::renderWorld() - there is a comment to guide you. Re-enabling all DTS shapes will bring a significant performance hit, since you'll be rendering potentially all the objects in the game world!
Extensions:
There are three major areas in which the GuiCommanderHud could be extended for your game.
First, you may want to render an overlay or icons indicating where objectives/players are. There is a comment located where you would want to render these objects, in GuiCommanderHud::onRender(). Using standard DGL calls will give good results.
Second, you may want to have the control handle mouse input. Looking at EditTSCtrl (located in engine/editor/editTSCtrl.*) will be an excellent guide for this process. You could either inherit from EditTSCtrl, or copy its mouse handling code to the GuiCommanderHud. The project() and unproject() functions that GuiCommmanderHud inherits from GuiTSCtrl may also be useful here.
Finally, you may wish to optimize rendering speed by caching output to a texture, rendering only the texture, and updating the texture as needed when the map needs to change its view. (You could even render to a large texture and simply pan it around, though this would kill the neat parallaxing and depth buffering effects that you could gain from actually rendering the world into the GuiCommanderHud.) This would be a bit tricky, but GuiCommanderHud::onRender would be your starting point. Look at TSShapeInstance::snapshot() for guidance on how to implement this sort of functionality in OpenGL - beware that the DirectX layer may not place nice with this.
Usage Restrictions:
None. Knock yourself out! :) I would ask that you put my name in your credits somewhere and send me a free copy of your game if this resource is a major piece of functionality for your project, but you are by no means required to do so. I'd also appreciate it if, if you found bugs or made enhancements for the code, if you'd send me your change(s) so I can merge them back into this resource. Many eyes find more bugs. ;)
Addendums:
Neat bit of code to try from the console(replace 1494 with the SimObject you want to track). Notice my commander hud is named commHud.
To use this resource:
1. Copy guiCommanderHud.cc to your engine/gui subfolder.
2. Open your IDE of choice (or a text editor if that's what you like).
3. Add the source file to your project so it will be compiled into Torque.
4. Do a clean rebuild.
5. Go to the GUI of your choice and add a GuiCommanderHud to it. Poof, instant GUI!
Security and Scoping Issues:
The HUD is designed to prevent people from abusing it in-game. It does not change how anything is scoped, so people will only see what the net code would have previously allowed them to see. If you want to have a special "commander map" behavior that shows all active objects you will need to add it either via server side scripting or in GameConnection::doneScopingScene(). Remember, the best way to prevent cheating and improve net performance on your game is to only scope what people need to see.
If you're particularly paranoid, you may want to remove the ConsoleMethods at the end of the file and control the commander map with events; this is probably unnecessary in most cases, as the commander map reveals no more information than the player could get by opening a map in single player mode or a dedicated server and flying/walking around.
Panning and Zooming:
There are three useful actions you can do via scripting with the GuiCommanderHud. First, you can zoom. This basically consists of changing the FOV of the overhead camera that the view is being rendered from (see GuiCommanderHud::processCameraQuery()), so you want to stick to values between 0 and one half pi. Larger values can give "interesting" results though no value should crash the engine. The available script methods for this are zoom() to instantly set the zoom level and zoomTo() to smoothly interpolate to the requested zoom level.
pan() and panTo() let you set the x,y co-ordinates of the overhead camera - essentially setting where the center of the map is. If you wish to pan onto an object, get the first two words of its position and pass them to pan() or panTo().
There are also two exposed fields, panSpeed and zoomSpeed, which let you tweak how quickly panning and zooming occurs. Negative values for these will give catastrophic results!
Performance:
On a 1.8Ghz P4 with 512mb of RAM and a GeForce 4 440 Go (equivalent to a fast GeForce 2), I get 70fps in the test FPS level without the map on screen, and 40fps with it on the screen (in addition to the normal FPS view). Suggested usage is to run the GuiCommanderHud in its own GUI, so that you don't have the overhead of the PlayGUI and its view of the world.
The GuiCommanderHud only renders interior, terrain, water, and environmental objects. You can easily change the mask it uses for rendering the scene by editing GuiCommanderHud::renderWorld() - there is a comment to guide you. Re-enabling all DTS shapes will bring a significant performance hit, since you'll be rendering potentially all the objects in the game world!
Extensions:
There are three major areas in which the GuiCommanderHud could be extended for your game.
First, you may want to render an overlay or icons indicating where objectives/players are. There is a comment located where you would want to render these objects, in GuiCommanderHud::onRender(). Using standard DGL calls will give good results.
Second, you may want to have the control handle mouse input. Looking at EditTSCtrl (located in engine/editor/editTSCtrl.*) will be an excellent guide for this process. You could either inherit from EditTSCtrl, or copy its mouse handling code to the GuiCommanderHud. The project() and unproject() functions that GuiCommmanderHud inherits from GuiTSCtrl may also be useful here.
Finally, you may wish to optimize rendering speed by caching output to a texture, rendering only the texture, and updating the texture as needed when the map needs to change its view. (You could even render to a large texture and simply pan it around, though this would kill the neat parallaxing and depth buffering effects that you could gain from actually rendering the world into the GuiCommanderHud.) This would be a bit tricky, but GuiCommanderHud::onRender would be your starting point. Look at TSShapeInstance::snapshot() for guidance on how to implement this sort of functionality in OpenGL - beware that the DirectX layer may not place nice with this.
Usage Restrictions:
None. Knock yourself out! :) I would ask that you put my name in your credits somewhere and send me a free copy of your game if this resource is a major piece of functionality for your project, but you are by no means required to do so. I'd also appreciate it if, if you found bugs or made enhancements for the code, if you'd send me your change(s) so I can merge them back into this resource. Many eyes find more bugs. ;)
Addendums:
Neat bit of code to try from the console(replace 1494 with the SimObject you want to track). Notice my commander hud is named commHud.
commHud.zoomTo(0.02);
function panPlayer() { commHud.panTo(getWord(1494.getPosition(), 0), getWord(1494.getPosition(), 1)); schedule(100, 0, panPlayer); }
panPlayer();
#143
01/30/2008 (12:00 pm)
@Andy Hodges - hi is there any news on the tgea version yet?
#144
12/12/2008 (4:45 am)
Hello, I tried out the map hud and I get a problem I have been struggling to solve for some time now. How do I do so that I don't get the PlayGUI recreated with its view of the world? I created a new GUI, executed it in init.cs. Where and how do I add it to the canvas? Please help!
#145
12/20/2008 (2:26 pm)
I have a strange bug. When i try to view the commander map in first person it doesnt lock on to the object I set as the target. If i press alt+c and enter freecam though, the CommanderMap snaps right to the target object. Any clues?
#146
06/12/2009 (6:32 pm)
Anyone have a TGEA version they would like to share or are to busy to clean it up for a resource?? thanks!
#147
I'm new to render targets, so I'm thinking that I am bracketing either the wrong part of the code, or I'm putting the code in the right place, but I'm just doing something wrong with getting the render into the GFXTexHandle. Anyway, here's the code, and any pointers would be grand, thanks in advance!
03/22/2010 (6:16 pm)
Anyone have any input on getting this resource hooked up with render targets? I have it to the point where it displays the bitmap, which is cleared to (0,0,0), but it doesn't display what is (should be) rendering to it.I'm new to render targets, so I'm thinking that I am bracketing either the wrong part of the code, or I'm putting the code in the right place, but I'm just doing something wrong with getting the render into the GFXTexHandle. Anyway, here's the code, and any pointers would be grand, thanks in advance!
//Snipped headers...
#include "gfx/gfxDevice.h"
#include "gfx/gfxTextureManager.h"
#include "gfx/gfxDrawUtil.h"
class GuiCommanderHud : public GuiTSCtrl
{
private:
//Snipped code...
GFXTextureTargetRef mRenderTarget;
GFXTextureObject* mTexObject;
GFXTexHandle mTexHandle;
//Snipped code...
};
//More snipped code...
void GuiCommanderHud::renderWorld(const RectI &updateRect)
{
GFX->pushActiveRenderTarget();
mRenderTarget = GFX->allocRenderToTextureTarget();
GFX->pushWorldMatrix();
mTexHandle = GFX->getTextureManager()->createTexture(getExtent().x, getExtent().y, GFXFormatR8G8B8X8, &GFXDefaultRenderTargetProfile, 0, 0);
mRenderTarget->attachTexture( GFXTextureTarget::Color0, mTexHandle );
GFX->setActiveRenderTarget( mRenderTarget );
GFX->clear( GFXClearStencil | GFXClearZBuffer | GFXClearTarget, ColorI(0, 0, 0), 1.0f, 0 );
//gClientSceneGraph->setMiniMapPass(true); //<< added
// Set up state
// draw all the objects
Vector<SceneObject*> objects;
U32 mask = TerrainObjectType;
gClientContainer.findObjects(mask, findObjectsCallback, &objects);
Box3F box;
Point3F pt;
for(U32 i = 0; i < objects.size(); i++)
{
// get the color
if(objects[i]->getTypeMask() & TerrainObjectType)
{
pt = objects[i]->getBoxCenter();
box = objects[i]->getWorldBox();
break;
}
}
//TerrainBlock::mRenderingCommander = true;
//TerrainRender::mRenderingCommander = true;
F32 oldVisDist = gClientSceneGraph->getVisibleDistance();
gClientSceneGraph->setVisibleDistance(5000);//box.len_x());
//gClientSceneGraph->setFogDistance(5000);//box.len_x());
// set up the camera and viewport stuff:
// Render (stolen from GameRenderWorld)
PROFILE_START(GameRenderCommanderWorld);
FrameAllocator::setWaterMark(0);
#if defined(GATHER_METRICS) && GATHER_METRICS > 1
TextureManager::smTextureCacheMisses = 0;
#endif
//Snipped code (setting masks)...
gClientSceneGraph->renderScene(ScenePassType::SPT_Diffuse, rMask);
//GFX->setZEnable(false);
#if defined(GATHER_METRICS) && GATHER_METRICS > 1
Con::setFloatVariable("Video::texResidentPercentage",
TextureManager::getResidentFraction());
Con::setIntVariable("Video::textureCacheMisses",
TextureManager::smTextureCacheMisses);
#endif
AssertFatal(FrameAllocator::getWaterMark() == 0, "Error, someone didn't reset the water mark on the frame allocator!");
FrameAllocator::setWaterMark(0);
PROFILE_END();
// Restore state
gClientSceneGraph->setVisibleDistance(oldVisDist);
//TerrainRender::mRenderingCommander = false;
GFX->setClipRect( updateRect);
//gClientSceneGraph->setMiniMapPass(false); //<< added
mRenderTarget->resolve();//resolveTo(mTexHandle);
GFX->popActiveRenderTarget();
//mRenderTarget->attachTexture(GFXTextureTarget::Color0, NULL);
GFX->popWorldMatrix();
}
void GuiCommanderHud::onRender(Point2I offset, const RectI &updateRect)
{
// Update pan/zoom
S32 time = Platform::getVirtualMilliseconds();
S32 dt = time - mLastRenderTime;
mLastRenderTime = time;
mCurPan += (mPanGoal - mCurPan) * ((F32)(dt/1000.f) * mPanSpeed);
mCurZoom += (mZoomGoal - mCurZoom) * ((F32)(dt/1000.f) * mZoomSpeed);
// Render the world...
Parent::onRender(offset, updateRect);
// If you wanted to render custom GUI elements, like a sensor map, icons for
// players/vehicles/objectives, you would do it here by calling project()
// for all their positions and drawing bitmaps at the appropriate locations.
if(mTexHandle)
{
RectI dstRect(offset, getExtent());
RectI srcRect(0, 0, mTexHandle->getWidth(), mTexHandle->getHeight());
GFX->getDrawUtil()->drawBitmapStretchSR(mTexHandle, dstRect, srcRect, GFXBitmapFlip_None, GFXTextureFilterLinear, false);
}
}
#148
Edit: Kind of goes without saying once you look at it, but I ripped out a lot of the pan/zoom stuff. Code to taste :)
Still, it's a good way there, so here it is:
03/23/2010 (9:15 pm)
Update: Got it working for the most part, with the help of Keith Johnston's thread (for some reason I don't understand yet it didn't agree with the version I had). Some issues with this currently are that it is kind of dim, the map zooms in and out when you aim your player camera up and down, and the water reflections are still there. Edit: Kind of goes without saying once you look at it, but I ripped out a lot of the pan/zoom stuff. Code to taste :)
Still, it's a good way there, so here it is:
//-----------------------------------------------------------------------------
// Commander Map HUD
//
// Portions Copyright (c) GarageGames.Com
// Copyright (c) Ben Garney
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "gui/3d/guiTSControl.h"
#include "console/console.h"
#include "console/consoleTypes.h"
#include "gfx/gfxDevice.h"
#include "gfx/gfxDrawUtil.h"
#include "gui/core/guiCanvas.h"
#include "gui/editor/guiShapeEdPreview.h"
#include "renderInstance/renderPassManager.h"
#include "lighting/lightManager.h"
#include "lighting/lightInfo.h"
#include "core/resourceManager.h"
#include "sceneGraph/sceneGraph.h"
#include "sceneGraph/sceneState.h"
#include "gfx/primBuilder.h"
#include "gfx/gfxDrawUtil.h"
#include "terrain/terrData.h"
#include "gfx/gfxTextureManager.h"
#include "T3D/gameBase/gameConnection.h"
//-----------------------------------------------------------------------------
class GuiCommanderHud : public GuiTSCtrl
{
private:
typedef GuiTSCtrl Parent;
GFXTextureTargetRef mRenderTarget;
GFXTextureObject* mTexObject;
GFXTexHandle mTexHandle;
F32 mOldVisDist;
F32 maxHi,minHi;
S32 mSizeX, mSizeY, time, dt;
MatrixF playercam, mat1, mat2;
Point3F playPos;
RectI srcRect, dstRect;
AngAxisF aa;
GameConnection* conn;
Point2F mPanSpeed;
F32 mZoomSpeed;
S32 mLastRenderTime;
public:
Point2F mPanGoal, mCurPan;
F32 mZoomGoal, mCurZoom;
GuiCommanderHud();
bool onAdd();
bool processCameraQuery(CameraQuery *query);
void renderWorld(const RectI &updateRect);
void onRender( Point2I, const RectI &);
static void initPersistFields();
DECLARE_CONOBJECT( GuiCommanderHud );
};
//-----------------------------------------------------------------------------
IMPLEMENT_CONOBJECT( GuiCommanderHud );
#149
03/23/2010 (9:16 pm)
And the rest:GuiCommanderHud::GuiCommanderHud()
: mPanSpeed(10, 10), mZoomSpeed(1), mCurPan(0,0), mCurZoom(M_PI_F/2),
mPanGoal(0,0), mZoomGoal(M_PI_F/2), mLastRenderTime(0)
{
}
void GuiCommanderHud::initPersistFields()
{
Parent::initPersistFields();
addField("panSpeed", TypePoint2F, Offset(mPanSpeed, GuiCommanderHud), "Set the speed (x/y) we pan to our goal.");
addField("zoomSpeed", TypeF32, Offset(mZoomSpeed, GuiCommanderHud), "Set the speed we zoom with to our goal.");
}
bool GuiCommanderHud::onAdd()
{
mRenderTarget = GFX->allocRenderToTextureTarget();
mSizeX = getExtent().x;
mSizeY = getExtent().y;
mTexHandle = GFX->getTextureManager()->createTexture(mSizeX, mSizeY, GFXFormatR8G8B8X8, &GFXDefaultRenderTargetProfile, 0, 0);
mRenderTarget->attachTexture( GFXTextureTarget::Color0, mTexHandle );
dstRect.set(this->getPosition(), getExtent());
srcRect.set(Point2I(0, 0), Point2I(mSizeX, mSizeY));
bool parentRet = Parent::onAdd();
return parentRet;
}
bool GuiCommanderHud::processCameraQuery(CameraQuery *q)
{
gClientSceneGraph->getCurrentTerrain()->getMinMaxHeight(&minHi,&maxHi);
q->object = NULL;
q->nearPlane = 1;
q->farPlane = mFabs(maxHi) + mFabs(minHi);
q->fov = mCurZoom/2;// / 75;
conn = GameConnection::getConnectionToServer();
if (!conn)
return false;
conn->getControlCameraTransform(0, &playercam); // store camera information
playPos = playercam.getPosition();
// Get camera angle
aa.set(playercam);
aa.axis.x = 0.0f;
aa.axis.y = 0.0f;
aa.setMatrix(&mat1);
// Create angle to look straight down
aa.axis.x = 1.0f;
aa.axis.y = 0.0f;
aa.axis.z = 0.0f;
aa.angle = 3.14/2;
aa.setMatrix(&mat2);
// Combine the camera angles
mat1.mul(mat2);
// Make sure we're high enough that we we won't clip
mat1.setColumn(3, Point3F(playPos.x, playPos.y, maxHi + 100));
q->cameraMatrix = mat1;
return true;
}
void GuiCommanderHud::renderWorld(const RectI &updateRect)
{
GFX->pushActiveRenderTarget();
GFX->pushWorldMatrix();
GFX->setActiveRenderTarget( mRenderTarget );
GFX->clear( GFXClearStencil | GFXClearZBuffer | GFXClearTarget, ColorI(0, 0, 0), 1.0f, 0 );
// Render (stolen from GameRenderWorld)
PROFILE_START(GameRenderCommanderWorld);
FrameAllocator::setWaterMark(0);
// If you want to render other things, change this mask.
gClientSceneGraph->renderScene(SPT_Diffuse, EnvironmentObjectType | TerrainObjectType | WaterObjectType | ForestObjectType | StaticObjectType);
AssertFatal(FrameAllocator::getWaterMark() == 0,
"Error, someone didn't reset the water mark on the frame allocator!");
FrameAllocator::setWaterMark(0);
PROFILE_END();
GFX->popActiveRenderTarget();
GFX->popWorldMatrix();
}
void GuiCommanderHud::onRender(Point2I offset, const RectI &updateRect)
{
// Render the world...
Parent::onRender(offset, updateRect);
// If you wanted to render custom GUI elements, like a sensor map, icons for
// players/vehicles/objectives, you would do it here by calling project()
// for all their positions and drawing bitmaps at the appropriate locations.
if(mTexHandle)
{
GFX->getDrawUtil()->drawBitmapStretchSR(mTexHandle, dstRect, srcRect, GFXBitmapFlip_None, GFXTextureFilterLinear, false);
}
}
#150
Did you run into the problem where resizing your window causes "You can never have a NULL primary render target"
05/20/2010 (11:10 am)
Ted -- Thanks for posting your work here, it has helped me solve all of my drawing issues.Did you run into the problem where resizing your window causes "You can never have a NULL primary render target"
#152
I added te ressource to my project but when i try to add it in the GUI editor Torque crash...
Did anyone have the same ?
I tried it on T3D 1.1
05/14/2011 (5:06 am)
Hi,I added te ressource to my project but when i try to add it in the GUI editor Torque crash...
Did anyone have the same ?
I tried it on T3D 1.1
#153
05/14/2011 (6:55 am)
@Abdel: How can you add it if you don't have a license?
#154
I'm studying Game development at the University(they have a license)
so i can access all resources they have including torque
Can you please help me to fix the problem ?
05/17/2011 (4:14 am)
@Ted:I'm studying Game development at the University(they have a license)
so i can access all resources they have including torque
Can you please help me to fix the problem ?
#155
#include "sceneGraph/sceneGraph.h"
#include "sceneGraph/sceneState.h"
to correspond for t3d pro 1.1
#include "scene/sceneManager.h"
#include "scene/sceneRenderState.h"
but still have 4 errors while compile,so have anyone can offer solution?thanks~
12/29/2011 (5:36 am)
Hi,Ted. Would you intro how make it work for torque3d Pro 1.1?and I try the codes that you post in 147 and 148,and change under codes#include "sceneGraph/sceneGraph.h"
#include "sceneGraph/sceneState.h"
to correspond for t3d pro 1.1
#include "scene/sceneManager.h"
#include "scene/sceneRenderState.h"
but still have 4 errors while compile,so have anyone can offer solution?thanks~

Torque Owner Shon Gale
Thanks ahead of time.