A simple radar UI control
by Harry Chow · 07/03/2006 (11:27 am) · 2 comments
Following is the engine code.
guiRadarCtrl.h
guiRadarCtrl.cc
Following is the script code.
In PlayGui.gui
guiRadarCtrl.h
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUIRADARCTRL_H_
#define _GUIRADARCTRL_H_
#ifndef _GUITYPES_H_
#include "gui/core/guiTypes.h"
#endif
#ifndef _DGL_H_
#include "dgl/dgl.h"
#endif
#ifndef _GAME_H_
#include "game/game.h"
#endif
#ifndef _GUITSCONTROL_H_
#include "gui/core/guiTSControl.h"
#endif
#ifndef _GUICONTROL_H_
#include "gui/core/guiControl.h"
#endif
#ifndef _GTEXMANAGER_H_
#include "dgl/gTexManager.h"
#endif
#ifndef _SCENEOBJECT_H_
#include "sim/sceneObject.h"
#endif
#define MIN(a, b) ((a < b) ? a:b)
#define MAX(a, b) ((a > b) ? a:b)
inline int Fast_Distance_2D(int x, int y)
{
// this function computes the distance from 0,0 to x,y with 3.5% error
// first compute the absolute value of x,y
x = abs(x);
y = abs(y);
// compute the minimum of x,y
int mn = MIN(x,y);
// return the distance
return(x+y-(mn>>1)-(mn>>2)+(mn>>4));
} // end Fast_Distance_2D
class GuiRadarCtrl : public GuiControl
{
private:
typedef GuiControl Parent;
protected:
StringTableEntry mBitmapName;
TextureHandle mTextureHandle;
Point2I startPoint;
bool mWrap;
Vector<SceneObject*> ObjectsToDraw;
void onUpdate();
// --------------------------------------------------
// conversion
VectorF mScale;
Point2F mCenterPos;
Point2F worldToScreen(const Point2F &);
Point2F screenToWorld(const Point2F &);
S32 mDistFromCenterX;
S32 mDistFromCenterY;
public:
void CalCenterDist( Point2F * );
void TransToCenter( Point2F * );
void MirrorCenterX( Point2F * );
void MirrorCenterY( Point2F * );
GuiRadarCtrl();
//
const RectI & getArea();
// GuiControl
void parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent);
void onRender(Point2I offset, const RectI &updateRect);
bool onWake();
void onSleep();
void inspectPostApply();
void setBitmap(const char *name,bool resize = false);
void setBitmap(const TextureHandle &handle,bool resize = false);
S32 getWidth() const { return(mTextureHandle.getWidth()); }
S32 getHeight() const { return(mTextureHandle.getHeight()); }
void setValue(S32 x, S32 y);
// field data..
bool mRenderCamera;
ColorI mHandleFrameColor;
ColorI mHandleFillColor;
ColorI mDefaultObjectColor;
ColorI mBuildingObjectColor;
ColorI mMissionBoundsColor;
ColorI mCameraColor;
bool mEnableMirroring;
S32 mMirrorIndex;
ColorI mMirrorLineColor;
ColorI mMirrorArrowColor;
static void initPersistFields();
DECLARE_CONOBJECT(GuiRadarCtrl);
};
#endif // _GUIRADARCTRL_H_guiRadarCtrl.cc
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "gui/utility/guiRadarCtrl.h"
#include "console/console.h"
#include "console/consoleTypes.h"
#include "gui/core/guiCanvas.h"
#include "game/game.h"
#include "game/objectTypes.h"
#include "game/shapeBase.h"
#include "game/gameConnection.h"
#include "core/bitMatrix.h"
IMPLEMENT_CONOBJECT(GuiRadarCtrl);
// unnamed namespace for static data
namespace {
static const Point3F BoxNormals[] =
{
Point3F( 1, 0, 0),
Point3F(-1, 0, 0),
Point3F( 0, 1, 0),
Point3F( 0,-1, 0),
Point3F( 0, 0, 1),
Point3F( 0, 0,-1)
};
static U32 BoxVerts[][4] = {
{7,6,4,5}, // +x
{0,2,3,1}, // -x
{7,3,2,6}, // +y
{0,1,5,4}, // -y
{7,5,1,3}, // +z
{0,4,6,2} // -z
};
static Point3F BoxPnts[] = {
Point3F(0,0,0),
Point3F(0,0,1),
Point3F(0,1,0),
Point3F(0,1,1),
Point3F(1,0,0),
Point3F(1,0,1),
Point3F(1,1,0),
Point3F(1,1,1)
};
F32 round_local(F32 val)
{
if(val >= 0.f)
{
F32 floor = mFloor(val);
if((val - floor) >= 0.5f)
return(floor + 1.f);
return(floor);
}
else
{
F32 ceil = mCeil(val);
if((val - ceil) <= -0.5f)
return(ceil - 1.f);
return(ceil);
}
}
S32 clamp(S32 val, S32 resolution)
{
return(S32(round_local(F32(val) / F32(resolution))) * resolution);
}
}
//------------------------------------------------------------------------------
GuiRadarCtrl::GuiRadarCtrl()
{
mRenderCamera = true;
mHandleFrameColor.set(255,255,255);
mHandleFillColor.set(0,0,0);
mDefaultObjectColor.set(0,255,0,100);
mBuildingObjectColor.set( 255, 255, 255, 255 );
mMissionBoundsColor.set(255,0,0);
mCameraColor.set(255,0,0);
mEnableMirroring = false;
mMirrorIndex = 0;
mMirrorLineColor.set(255,0,255,128);
mMirrorArrowColor.set(255,0,255,128);
mBitmapName = StringTable->insert("");
startPoint.set(0, 0);
mWrap = false;
mScale.set(1.f, 1.f, 0.f);
mDistFromCenterX = 0;
mDistFromCenterY = 0;
}
//------------------------------------------------------------------------------
bool GuiRadarCtrl::onWake()
{
if(!Parent::onWake())
return(false);
onUpdate();
setActive(true);
setBitmap(mBitmapName);
mCenterPos.set( getPosition().x + (getExtent().x >> 1), getPosition().y + (getExtent().y >> 1) );
mScale.set(0.125f, 0.125f, 0.f);
return(true);
}
void GuiRadarCtrl::onSleep()
{
mTextureHandle = NULL;
Parent::onSleep();
}
//------------------------------------------------------------------------------
void GuiRadarCtrl::onUpdate()
{
Con::executef(this, 1, "onUpdate");
}
void GuiRadarCtrl::parentResized(const Point2I & oldParentExtent, const Point2I & newParentExtent)
{
static Point2I offset = (oldParentExtent - getPosition()) - getExtent();
resize(getPosition(), newParentExtent - getPosition() - offset);
}
void GuiRadarCtrl::CalCenterDist( Point2F * point )
{
mDistFromCenterX = - (point->x - mCenterPos.x);
mDistFromCenterY = - (point->y - mCenterPos.y);
}
void GuiRadarCtrl::TransToCenter( Point2F * point )
{
point->x += mDistFromCenterX;
point->y += mDistFromCenterY;
}
void GuiRadarCtrl::MirrorCenterX( Point2F * point )
{
F32 dis = point->x - mCenterPos.x;
if( dis > 0.f )
{
point->x -= 2*dis;
}
else
{
point->x += 2*fabs(dis);
}
}
void GuiRadarCtrl::MirrorCenterY( Point2F * point )
{
F32 dis = point->y - mCenterPos.y;
if( dis > 0.f )
{
point->y -= 2*dis;
}
else
{
point->y += 2*fabs(dis);
}
}
//------------------------------------------------------------------------------
Point2F GuiRadarCtrl::worldToScreen(const Point2F & pos)
{
return(Point2F( mCenterPos.x + (pos.x * mScale.x), mCenterPos.y + (pos.y * mScale.y) ));
}
Point2F GuiRadarCtrl::screenToWorld(const Point2F & pos)
{
return(Point2F((pos.x - mCenterPos.x) / mScale.x, (pos.y - mCenterPos.y) / mScale.y));
}
//------------------------------------------------------------------------------
static void findObjectsCallback(SceneObject* obj, void * val)
{
Vector<SceneObject*> * list = (Vector<SceneObject*>*)val;
list->push_back(obj);
}
void GuiRadarCtrl::setValue(S32 x, S32 y)
{
if (mTextureHandle)
{
TextureObject* texture = (TextureObject *) mTextureHandle;
x+=texture->bitmapWidth/2;
y+=texture->bitmapHeight/2;
}
while (x < 0)
x += 256;
startPoint.x = x % 256;
while (y < 0)
y += 256;
startPoint.y = y % 256;
}
void GuiRadarCtrl::inspectPostApply()
{
// if the extent is set to (0,0) in the gui editor and appy hit, this control will
// set it's extent to be exactly the size of the bitmap (if present)
Parent::inspectPostApply();
if (!mWrap && (mBounds.extent.x == 0) && (mBounds.extent.y == 0) && mTextureHandle)
{
TextureObject *texture = (TextureObject *) mTextureHandle;
mBounds.extent.x = texture->bitmapWidth;
mBounds.extent.y = texture->bitmapHeight;
}
}
void GuiRadarCtrl::setBitmap(const char *name, bool resize)
{
mBitmapName = StringTable->insert(name);
if (*mBitmapName) {
mTextureHandle = TextureHandle(mBitmapName, BitmapTexture, true);
// Resize the control to fit the bitmap
if (resize) {
TextureObject* texture = (TextureObject *) mTextureHandle;
mBounds.extent.x = texture->bitmapWidth;
mBounds.extent.y = texture->bitmapHeight;
Point2I extent = getParent()->getExtent();
parentResized(extent,extent);
}
}
else
mTextureHandle = NULL;
setUpdate();
}
void GuiRadarCtrl::setBitmap(const TextureHandle &handle, bool resize)
{
mTextureHandle = handle;
// Resize the control to fit the bitmap
if (resize) {
TextureObject* texture = (TextureObject *) mTextureHandle;
mBounds.extent.x = texture->bitmapWidth;
mBounds.extent.y = texture->bitmapHeight;
Point2I extent = getParent()->getExtent();
parentResized(extent,extent);
}
}
void GuiRadarCtrl::onRender(Point2I offset, const RectI & updateRect)
{
RectI rect = updateRect;
setUpdate();
if( !mTextureHandle )
return ;
dglClearBitmapModulation();
if(mWrap)
{
TextureObject* texture = (TextureObject *) mTextureHandle;
RectI srcRegion;
RectI dstRegion;
float xdone = ((float)mBounds.extent.x/(float)texture->bitmapWidth)+1;
float ydone = ((float)mBounds.extent.y/(float)texture->bitmapHeight)+1;
int xshift = startPoint.x%texture->bitmapWidth;
int yshift = startPoint.y%texture->bitmapHeight;
for(int y = 0; y < ydone; ++y)
for(int x = 0; x < xdone; ++x)
{
srcRegion.set(0,0,texture->bitmapWidth,texture->bitmapHeight);
dstRegion.set( ((texture->bitmapWidth*x)+offset.x)-xshift,
((texture->bitmapHeight*y)+offset.y)-yshift,
texture->bitmapWidth,
texture->bitmapHeight);
dglDrawBitmapStretchSR(texture,dstRegion, srcRegion, false);
}
}
else
{
RectI rect(offset, mBounds.extent);
dglDrawBitmapStretch(mTextureHandle, rect);
}
CameraQuery camera;
GameProcessCameraQuery(&camera);
// farplane too far, 90' looks wrong...
camera.fov = mDegToRad(60.f);
camera.farPlane = 500.f;
//
F32 rot = camera.fov / 2;
//
VectorF ray;
VectorF projRayA;
Point3F camPos;
camera.cameraMatrix.getColumn(3, &camPos);
glColor4ub(mCameraColor.red, mCameraColor.green, mCameraColor.blue, mCameraColor.alpha);
glBegin(GL_LINES);
glVertex2f(mCenterPos.x, mCenterPos.y);
glVertex2f(mCenterPos.x, 0);
glEnd();
// draw all the objects
Vector<SceneObject*> objects;
U32 mask = PlayerObjectType | VehicleObjectType | StaticShapeObjectType | StaticTSObjectType ;
gClientContainer.findObjects( mask, findObjectsCallback, &objects );
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBegin(GL_QUADS);
// project 'em
for(U32 i = 0; i < objects.size(); i++)
{
// get the color
glColor4ub(mDefaultObjectColor.red,
mDefaultObjectColor.green,
mDefaultObjectColor.blue,
mDefaultObjectColor.alpha);
const Box3F & objBox = objects[i]->getObjBox();
const MatrixF & objTransform = objects[i]->getTransform();
const VectorF & objScale = objects[i]->getScale();
U32 numPlanes = 0;
PlaneF testPlanes[3];
U32 planeIndices[3];
U32 j;
for(j = 0; (j < 6) && (numPlanes < 3); j++)
{
PlaneF plane;
plane.x = BoxNormals[j].x;
plane.y = BoxNormals[j].y;
plane.z = BoxNormals[j].z;
if(j&1)
plane.d = (((const F32 *)objBox.min)[(j-1)>>1]);
else
plane.d = -(((const F32 *)objBox.max)[j>>1]);
//
mTransformPlane(objTransform, objScale, plane, &testPlanes[numPlanes]);
planeIndices[numPlanes] = j;
if(mDot(testPlanes[numPlanes], Point3F(0,0,1)) > 0.f)
numPlanes++;
}
for(j = 0; j < numPlanes; j++)
{
for(U32 k = 0; k < 4; k++)
{
U32 vertIndex = BoxVerts[planeIndices[j]][k];
Point3F pnt;
pnt.set(BoxPnts[vertIndex].x ? objBox.max.x : objBox.min.x,
BoxPnts[vertIndex].y ? objBox.max.y : objBox.min.y,
BoxPnts[vertIndex].z ? objBox.max.z : objBox.min.z);
// scale it
//pnt.convolve(objScale);
VectorF newScale(5.f, 5.f, 0.f);
pnt.convolve(newScale);
Point3F proj;
objTransform.mulP(pnt, &proj);
Point2F pos;
ray.set( (camPos.x - proj.x), -(camPos.y - proj.y), 0 );
camera.cameraMatrix.mulV(ray, &projRayA);
pos = worldToScreen( Point2F( projRayA.x, projRayA.y ) );
glColor4ub(255,
255,
0,
255);
MirrorCenterY(&pos);
MirrorCenterX(&pos);
glVertex2f(pos.x, pos.y);
}
}
}
glEnd();
glDisable(GL_BLEND);
renderChildControls(offset, updateRect);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// the following globals allocations needed for cCenterWorld are allocated when first refd.
void GuiRadarCtrl::initPersistFields()
{
Parent::initPersistFields();
addGroup("Mirror");
addField("enableMirroring", TypeBool, Offset(mEnableMirroring, GuiRadarCtrl));
addField("mirrorIndex", TypeS32, Offset(mMirrorIndex, GuiRadarCtrl));
addField("mirrorLineColor", TypeColorI, Offset(mMirrorLineColor, GuiRadarCtrl));
addField("mirrorArrowColor", TypeColorI, Offset(mMirrorArrowColor, GuiRadarCtrl));
endGroup("Mirror");
addGroup("Misc");
addField("bitmap", TypeFilename, Offset(mBitmapName, GuiRadarCtrl));
addField("wrap", TypeBool, Offset(mWrap, GuiRadarCtrl));
addField("handleFrameColor", TypeColorI, Offset(mHandleFrameColor, GuiRadarCtrl));
addField("handleFillColor", TypeColorI, Offset(mHandleFillColor, GuiRadarCtrl));
addField("defaultObjectColor", TypeColorI, Offset(mDefaultObjectColor, GuiRadarCtrl));
addField("buildingObjectColor", TypeColorI, Offset(mBuildingObjectColor, GuiRadarCtrl));
addField("missionBoundsColor", TypeColorI, Offset(mMissionBoundsColor, GuiRadarCtrl));
addField("cameraColor", TypeColorI, Offset(mCameraColor, GuiRadarCtrl));
addField("renderCamera", TypeBool, Offset(mRenderCamera, GuiRadarCtrl));
endGroup("Misc");
}Following is the script code.
In PlayGui.gui
new GuiRadarCtrl(TestRd) {
Profile = "GuiDefaultProfile";
HorizSizing = "relative";
VertSizing = "relative";
position = "102 18";
Extent = "191 190";
MinExtent = "8 2";
Visible = "1";
enableMirroring = "0";
mirrorIndex = "0";
mirrorLineColor = "255 0 255 128";
mirrorArrowColor = "255 0 255 128";
bitmap = "./black.png";
wrap = "0";
handleFrameColor = "255 255 255 255";
handleFillColor = "0 0 0 255";
defaultObjectColor = "0 255 0 100";
buildingObjectColor = "255 255 255 255";
missionBoundsColor = "255 0 0 255";
cameraColor = "255 0 0 255";
renderCamera = "1";
};
#2
what could be wrong?
edit: it works on stock missions, but not in my game.. probably something that I've added..
thanks for resource!
07/07/2006 (6:44 am)
Harry, I've put it in, but I see only yellow square.. (i'm on TLK1.4)what could be wrong?
edit: it works on stock missions, but not in my game.. probably something that I've added..
thanks for resource!

Torque Owner Harry Chow
Alish Game Studio