Game Development Community

dev|Pro Game Development Curriculum

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.

commHud.zoomTo(0.02);
function panPlayer() { commHud.panTo(getWord(1494.getPosition(), 0), getWord(1494.getPosition(), 1)); schedule(100, 0, panPlayer); }
panPlayer();
Page«First 2 3 4 5 6 7 8 Next»
#141
12/27/2007 (2:35 pm)
I am using AFX 1.02 with TGE 1.5.2, this control compiles but crashes the program upon execution or request of the class. Any ideas????
Thanks ahead of time.
#142
01/12/2008 (11:05 pm)
Interesting! :-)

Thank you for your efforts.
#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
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
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
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"
#151
08/31/2010 (8:44 pm)
Yes, I get a "NULL primary render target" as well.
What does this mean?
#152
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
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
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~
Page«First 2 3 4 5 6 7 8 Next»