Game Development Community

Mini Map for TGEA 1.7.1 and 1.8.1

by Dennis Trevillyan · 03/28/2009 (5:48 pm) · 32 comments

This MiniMap is based on two existing resources, both of which were posted before TGEA 1.7.x. Code updates to the 1.7.1 are included and the intended function is slightly different. See further down in the comments for changes to make this code work with TGEA 1.8.1. These are:

Ultimate Compass by Xavier "eXoDus": www.garagegames.com/community/resource/view/2779/2#comments

Trying to Implement drawBitmapRotated in TGEA by Jorge Luis Gandulfo: www.garagegames.com/community/forums/viewthread/75414

Screenshot:

i40.photobucket.com/albums/e216/zedd10/minimap.jpg

Download Source Code:

Script files are not included since you will create that in the dialog editor and add one line to map a key stroke.
TGEA v1.7.1:www.2shared.com/file/5413830/e8aad6b3/mini_Map_TGEA_171.html
TGEA v1.8.1:www.2shared.com/file/5413800/c3878570/Minimap_TGEA_181.html


Terrain Graphic: You will need a jpeg or png graphic of your terrain. This can be anything you wish but needs to be to scale. (Edit: see first and second comments)

Pointer: a jpeg or png graphic of an arrow shaped pointer. Used to show the players position and direction.

Script Code:


Add the C code listed below (yes, it's out of order. Sorry) and compile it. Then in the dialog editor create a new dialog with the types shown below:
//--- OBJECT WRITE BEGIN ---
new GuiControl(MiniMap) {
   profile = "GuiModelessDialogProfile";
   horizSizing = "right";
   vertSizing = "bottom";
   position = "0 0";
   extent = "640 480";
   minExtent = "8 8";
   visible = "1";
   helpTag = "0";
   noCursor = "1";

   new GuiMiniMap() {
      profile = "HudScrollProfile";
      canSaveDynamicFields = "0";
      Enabled = "1";
      isContainer = "1";
      HorizSizing = "right";
      VertSizing = "bottom";
      Position = "0 0";
      Extent = "130 130";
      MinExtent = "8 8";
      canSave = "0";
      Visible = "1";
      hovertime = "1000";
      wrap = "0";
      };
};
//--- OBJECT WRITE END ---
function MiniMap::toggle(%this)
{
   if (%this.isAwake())
      Canvas.popDialog(%this);
   else
      Canvas.pushDialog(%this);
}

Add a line to the default.bind.cs in scriptsAndAssets/client/scripts to bind the dialog to a key as follows:
moveMap.bindcmd(keyboard, "Q", "", "MiniMap.toggle();");

C++ Code:

Add the following code to guiMiniMap.cc:
#include "console/console.h"
#include "console/consoleTypes.h"
#include "app/game.h"
#include "T3D/gameconnection.h"
#include "T3D/gameFunctions.h"
#include "gfx/gfxTextureHandle.h"
#include "gfx/gfxDrawUtil.h"
#include "gui/guiCompass/guiMiniMap.h"
#include "atlas/runtime/atlasInstance2.h"

IMPLEMENT_CONOBJECT(GuiMiniMap);

GuiMiniMap::GuiMiniMap(void)
{
	terrain_size = 4096;		//terrain size in pixels
	mpp = (F32)3.66;			//grid spacing in meters  --> overall terrain size in meters is terrain_size * mpp
}

void GuiMiniMap::initPersistFields()
{
   Parent::initPersistFields();
   removeField("wrap");
   removeField("autosize");
   removeField("command");
   removeField("altcommand");
}

bool GuiMiniMap::onWake()
{
   if (! Parent::onWake())
      return false;
   setActive(true);
   mOuterTextureHandle  = GFXTexHandle("scriptsAndAssets/client/ui/Adsquare1", &GFXDefaultGUIProfile);
   mTextureHandle = GFXTexHandle("scriptsAndAssets/client/ui/Arrow", &GFXDefaultGUIProfile);
   return true;
}

void GuiMiniMap::onSleep()
{
   mTextureHandle = NULL;
   mOuterTextureHandle = NULL;
   Parent::onSleep();
}

float Vector2dToDegree(Point3F vector)
{
    float angle;
	if (vector.x == 0.0F)
    {
        if (vector.y > 0.0F)
            return 0.0F;
        else if (vector.y == 0.0F)
            return -1.0F;		//oops!  shouldn't happen!
        else
            return 180.0F;
    }
    if (vector.y == 0.0F)
    {
        if (vector.x < 0.0F)
            return 270.0F;
        else
            return 90.0F;
    }
    angle = atanf((1.0F * vector.x) / (-1.0F * vector.y)) * (180.0F / M_PI);
    if ((-1.0F * vector.y) < 0.0F)		// y is positive
        return angle + 180.0F;		
    else								// y is negative
    {
        if (vector.x > 0.0F)
            return angle;
        else
            return angle + 360.0F;
    }
}

void GuiMiniMap::onRender(Point2I offset, const RectI &updateRect)
{
   if(mOuterTextureHandle)		//terrain map
   {
	   GFXTextureObject* texture = (GFXTextureObject*) mOuterTextureHandle;
	   setExtent(texture->getWidth(), texture->getHeight());
	   terrain_tex_size.x = texture->getWidth();
	   terrain_tex_size.y = texture->getHeight();
	   
	   RectI outerRect(offset, getExtent());
	   GFX->getDrawUtil()->drawBitmapStretch(mOuterTextureHandle, outerRect, GFXBitmapFlip_None);
	   
   }

   if (mTextureHandle)		//pointer
   {
      GFX->getDrawUtil()->clearBitmapModulation();
	  GFXTextureObject* texture = (GFXTextureObject*) mTextureHandle;

	  CameraQuery query;
	  GameProcessCameraQuery(&query);

  	  MatrixF cameraMatrix = query.cameraMatrix;
	  Point3F cameraRot;
	  cameraMatrix.getColumn(1, &cameraRot); // get camera rotation
      cameraMatrix.getColumn(3, &mMyCoords); // get camera position
	  cameraRot.neg();						// change the sign of the rotation vector, makes it easier to interpret
	  cameraRot.z = 0;						// not really needed since z isn't used here

	  RectI srcRect(0, 0, texture->getBitmapWidth(), texture->getBitmapHeight());
	  RectI dstRect(0, 0, texture->getBitmapWidth(), texture->getBitmapHeight());

	  Point3F coords = AtlasInstance::startCoords;		//get the terrain offset from the mission file

	  //Map the terrain coordinates to the dialog window
	  F32 x = ((mMyCoords.x-coords.x)*terrain_tex_size.x)/(mpp*terrain_size);
	  F32 y = ((mMyCoords.y-coords.y)*terrain_tex_size.y)/(mpp*terrain_size);
	
	  mAngle = Vector2dToDegree(cameraRot)+(F32)90;		//get the pointer angle.  Zero degres is our typical "-X" direction.

	  GFX->getDrawUtil()->drawBitmapRotCtr(texture,
											dstRect,
											srcRect,
											GFXBitmapFlip_None,
											mAngle, 
											Point2F(0,0),
											y,
											x);
   }

   if (mProfile->mBorder || !mTextureHandle && !mOuterTextureHandle )   
   {
      RectI rect(offset.x, offset.y, getExtent().x, getExtent().y);
      GFX->getDrawUtil()->drawRect( rect, mProfile->mBorderColor );
   }

   renderChildControls(offset, updateRect);
}
bool GuiMiniMap::onAdd()
{
if (!Parent::onAdd())
return false;

mOuterTextureHandle  = GFXTexHandle("scriptsAndAssets/client/ui/Adsquare1", &GFXDefaultGUIProfile);
mTextureHandle = GFXTexHandle("scriptsAndAssets/client/ui/Arrow", &GFXDefaultGUIProfile);

return true;
}

Add the following code to guiMiniMap.h:
#ifndef _GUICOMPASSCTRL_H_
#define _GUICOMPASSCTRL_H_

#ifndef _GUIBITMAPCTRL_H_
#include "gui/controls/guiBitmapCtrl.h"
#endif

struct CameraQuery
{
   SimObject*  object;
   F32         nearPlane;
   F32         farPlane;
   F32         fov;
   bool        ortho;
   MatrixF     cameraMatrix;
};

class GuiMiniMap : public GuiBitmapCtrl
{
private:
	typedef GuiBitmapCtrl Parent;
	F32 mAngle;
	GFXTexHandle mOuterBitmapName;
	GFXTexHandle mBitmapName;
	Point3F mMyCoords;
	F32 terrain_size;
	Point2F terrain_tex_size;
	F32 mpp;

protected:

   GFXTexHandle mOuterTextureHandle;
   GFXTexHandle mTextureHandle;

public:
	//creation methods
	DECLARE_CONOBJECT(GuiMiniMap);
	GuiMiniMap();
    static void initPersistFields();
   	bool onAdd(); 


   //Parental methods
   bool onWake();
   void onSleep();

   void setOuterBitmap(const char *name);
   void setOuterBitmap(const GFXTexHandle &handle);
   void setNeedleBitmap(const char *name);
   void setNeedleBitmap(const GFXTexHandle &handle);

   void onRender(Point2I offset, const RectI &updateRect);
};

#endif

Add the following line to the public section of class AtlasInstance in atlasInstance2.h. This code makes the terrain position defined in the mission file so that all is displayed correctly. There may be a better way to do this.:
static Point3F startCoords

In AtlasInstance2.cpp add:
bool AtlasInstance::smNoUpdate = false;
Point3F AtlasInstance::startCoords(0, 0, 0);  <== add this line

void AtlasInstance::consoleInit()

and further down in atlasInstance2.cpp add:
// Do general render initialization stuff.
   mObjToWorld.getColumn(3, &startCoords);     <==  add this line
   setRenderTransform(mObjToWorld);
   resetWorldBox();
   addToScene();

Add to gfxDrawUtil.cpp the following code:
void GFXDrawUtil::drawBitmapRotCtr(GFXTextureObject *texture,const RectI& dstRect,const RectI& srcRect,const GFXBitmapFlip in_flip,F32 spinAngle, const Point2F spinOffset, F32 X, F32 Y)
{
	if(!texture)
      return;

   mDevice->setBaseRenderState();

   GFXVertexBufferHandle<GFXVertexPCT> verts(mDevice, 4, GFXBufferTypeVolatile );
   verts.lock();

   F32 texLeft   = F32(srcRect.point.x)                    / F32(texture->mTextureSize.x);
   F32 texRight  = F32(srcRect.point.x + srcRect.extent.x) / F32(texture->mTextureSize.x);
   F32 texTop    = F32(srcRect.point.y)                    / F32(texture->mTextureSize.y);
   F32 texBottom = F32(srcRect.point.y + srcRect.extent.y) / F32(texture->mTextureSize.y);

   F32 screenLeft   = dstRect.point.x;
   F32 screenRight  = dstRect.point.x + dstRect.extent.x;
   F32 screenTop    = dstRect.point.y;
   F32 screenBottom = dstRect.point.y + dstRect.extent.y;

	if(in_flip & GFXBitmapFlip_X)
   {
      F32 temp = texLeft;
      texLeft = texRight;
      texRight = temp;
   }
   if(in_flip & GFXBitmapFlip_Y)
   {
      F32 temp = texTop;
      texTop = texBottom;
      texBottom = temp;
   }

   // spin angle is in degree's so convert to radians..radians = degrees * pi /180
   spinAngle = spinAngle * 3.14 / 180.0f;

   Point2F screenPoint(X,Y); 

   F32 width = dstRect.extent.x;
   width *= 0.5;

   MatrixF rotMatrix( EulerF( 0.0, 0.0, spinAngle ) );

   Point3F offset( screenPoint.x, screenPoint.y, 0.0 );

	//const F32 fillConv = mDevice->getFillConventionOffset();
   verts[0].point.set( -width + spinOffset.x, -width + spinOffset.y, 0.0 );
   verts[1].point.set( -width + spinOffset.x,  width + spinOffset.y, 0.0 );
   verts[2].point.set( width + spinOffset.x,  width + spinOffset.y, 0.0 );
   verts[3].point.set( width + spinOffset.x, -width + spinOffset.y, 0.0 );

   verts[0].color = verts[1].color = verts[2].color = verts[3].color = mBitmapModulation;

   verts[0].texCoord.set( texLeft,  texTop );
   verts[1].texCoord.set( texLeft, texBottom );
   verts[2].texCoord.set( texRight,  texBottom );
   verts[3].texCoord.set( texRight, texTop );

	for( int i=0; i<4; i++ )
   {
      rotMatrix.mulP( verts[i].point );
      verts[i].point += offset;
   }

   verts.unlock();
  
   mDevice->setVertexBuffer( verts );

   mDevice->setCullMode( GFXCullNone );
   mDevice->setLightingEnable( false );
   mDevice->setAlphaBlendEnable( true );
   mDevice->setSrcBlend( GFXBlendSrcAlpha );
   mDevice->setDestBlend( GFXBlendInvSrcAlpha );
   mDevice->setTextureStageColorOp( 0, GFXTOPModulate );
   mDevice->setTextureStageColorOp( 1, GFXTOPDisable );
   mDevice->setTexture( 0, texture );
   mDevice->setupGenericShaders( GFXDevice::GSModColorTexture );

   mDevice->drawPrimitive(GFXTriangleFan, 0, 2 );

   mDevice->setAlphaBlendEnable( false );
}

and add to gfxDrawUtil.h in the public section of class GFXDrawUtil:
void drawBitmapRotCtr( GFXTextureObject *texture, const RectI &dstRect, const RectI &srcRect, const GFXBitmapFlip in_flip, F32 spinAngle, const Point2F spinOffset, F32 X, F32 Y );

You may need to adjust the path definitions for the graphics and the orientation of your pointer to get the proper behavior.

Page«First 1 2 Next»
#21
08/27/2009 (8:29 am)
Quick Update,

Still not getting any joy, so I decided to compare my files against the ones included in the download using CodePatch and there are no differences at all. Still getting the same compilation error... The only thing I can think of is that one of my previous modifications is causing a problem.

Can anyone point me in the right direction ? :-)

[EDIT] OK, I've resolved the main compilation error by renaming "Vector2dToDegree" to "Vector2dToDegreeb", thereby avoiding the double declaration error. I'm still getting the Atlas problem though... Atlas is fully enabled, and this error has only occured since I added this resource (the project has compiled peacefully a zillion times before...)
#22
09/08/2009 (10:42 pm)
Richard, most likely you have not defined and initialized the static variable "startCoords" in AtlasInstance2.h and AtlasInstance2.cpp.

Add the following line to the public section of class AtlasInstance in atlasInstance2.h. This code makes the terrain position defined in the mission file so that all is displayed correctly. There may be a better way to do this.:
view plainprint?

   1. static Point3F startCoords  

static Point3F startCoords


In AtlasInstance2.cpp add:
view plainprint?

   1. bool AtlasInstance::smNoUpdate = false;  
   2. Point3F AtlasInstance::startCoords(0, 0, 0);  <== add this line  
   3.   
   4. void AtlasInstance::consoleInit()  

bool AtlasInstance::smNoUpdate = false;
Point3F AtlasInstance::startCoords(0, 0, 0);  <== add this line

void AtlasInstance::consoleInit()


and further down in atlasInstance2.cpp add:
view plainprint?

   1. // Do general render initialization stuff.  
   2.    mObjToWorld.getColumn(3, &startCoords);     <==  add this line  
   3.    setRenderTransform(mObjToWorld);  
   4.    resetWorldBox();  
   5.    addToScene();
#23
09/09/2009 (5:57 am)
Hi Dennis,

Thanks for your response! I'd already added the code you mentioned, but after looking at it again I relocated the initial declaration statement for the static variable.

I'm now getting this:

1>atlasInstance2.cpp
1>..........enginesourceatlasruntimeatlasInstance2.cpp(227) : error C2661: 'ClipMapBlenderCache::ClipMapBlenderCache' : no overloaded function takes 3 arguments

#24
09/16/2009 (7:31 pm)
Richard, I don't really know the answer. I can't imagine why the constructor for that class would suddenly be redefined. It isn't unusual that the compiler throws some odd errors when you have a syntax error somewhere so I'd look for that. Sorry, not sure what else to tell you.
#25
10/11/2009 (1:53 am)
thanks Dennis, good start up point for commander map, its very difficult add radar functionality?, some guidance to show enemies as points or points of interest?....
#26
11/11/2009 (3:05 am)
Hi Dennis, I successfully re-built the source code with this resource.
But somehow, my mini-map does not display the image files (both .jpg and .png. And also I don't really know where to put the Pointer image.

Please provide some basic guidance for using the minimap GUI. Thanks a lot
#27
12/19/2009 (2:05 pm)
im got wired result , pointer always rendered behind terrain in TGEA 1.8.1 but map is rendered correctly so if im place minimap on top left everything work fine until player move to some hill and terrain is behind minimap then pointer is gone.
#28
01/29/2010 (8:41 pm)
How would I remove the green border line around the map? I have an idea but wanted to make sure I didn't mess up the code :)
#29
03/22/2010 (12:04 pm)
Hey thanks, I used some of the code from here to resolve an issue with the port of the Super Crosshair www.torquepowered.com/community/resources/view/19509
#30
05/24/2010 (9:36 pm)
is anyone has ported this resource to t3d?
#31
11/06/2010 (10:42 pm)
I've got this working in TGEA 1.8.2, even got it working on non atlas maps, however I have the same problem as an above poster, the "arrow" is rendered behind the terrains for some reason, and I cannot get past this.

If anyone can figure this out, I should be able to get radar and PoI's going on it for a fully functional minimap.
#32
01/11/2012 (3:39 pm)
Can I use this resource to T3d pro 1.1?is it need to modify some codes?thanks
Page«First 1 2 Next»