ShapeDamageHud TGEA Ver Port to T3D
by Enel · 04/23/2010 (8:32 am) · 4 comments
it is base Resource http://www.torquepowered.com/community/resources/view/13246
//-----------------------------------------------------------------------------
// gui/game/guiShapeDamageHud.cc
// by Stephen Lujan
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "gui/core/guiControl.h"
#include "gui/3D/guiTSControl.h"
#include "console/consoleTypes.h"
#include "sceneGraph/sceneGraph.h"
#include "T3D/shapeBase.h"
#include "T3D/gameConnection.h"
#include "gfx/gfxDrawUtil.h"
//----------------------------------------------------------------------------
/// Temporarily displays damage or other text above shape objects.
///
/// This GUI control must be a child of a TSControl, and a server connection
/// and control object must be present.
///
/// This is a stand-alone control and relies only on the standard base GuiControl.
class GuiShapeDamageHud : public GuiControl
{
typedef GuiControl Parent;
public:
struct damagePopup
{
SimObjectPtr<ShapeBase> mShape;
S32 mTime;
S32 mStartTime;
ColorF mTextColor;
StringTableEntry mText;
};
Vector<damagePopup> mPopups;
protected:
// field data
ColorF mFillColor;
ColorF mFrameColor;
F32 mStartVerticalOffset;
F32 mEndVerticalOffset;
F32 mDistanceFade;
bool mShowFrame;
bool mShowFill;
U32 mLastTime;
void drawDamage( Point2I offset, damagePopup *popup, F32 opacity);
public:
GuiShapeDamageHud();
// GuiControl
virtual void onRender(Point2I offset, const RectI &updateRect);
static void initPersistFields();
DECLARE_CONOBJECT( GuiShapeDamageHud );
DECLARE_CATEGORY( "Gui game" );
DECLARE_DESCRIPTION( "Display DamageHud" );
};
//-----------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(GuiShapeDamageHud);
/// Default distance for object's information to be displayed.
static const F32 cDefaultVisibleDistance = 500.0f;
GuiShapeDamageHud::GuiShapeDamageHud()
{
mFillColor.set( 0.25, 0.25, 0.25, 0.25 );
mFrameColor.set( 0, 1, 0, 1 );
mShowFrame = mShowFill = true;
mStartVerticalOffset = 1;
mEndVerticalOffset = 40;
mDistanceFade = 0.1;
mLastTime = Platform::getVirtualMilliseconds();
}
void GuiShapeDamageHud::initPersistFields()
{
Parent::initPersistFields();
addGroup("Colors");
addField( "fillColor", TypeColorF, Offset( mFillColor, GuiShapeDamageHud ) );
addField( "frameColor", TypeColorF, Offset( mFrameColor, GuiShapeDamageHud ) );
endGroup("Colors");
addGroup("Misc");
addField( "showFill", TypeBool, Offset( mShowFill, GuiShapeDamageHud ) );
addField( "showFrame", TypeBool, Offset( mShowFrame, GuiShapeDamageHud ) );
addField( "startingVerticalOffset", TypeF32, Offset( mStartVerticalOffset, GuiShapeDamageHud ) );
addField( "distanceFade", TypeF32, Offset( mDistanceFade, GuiShapeDamageHud ) );
endGroup("Misc");
}
//----------------------------------------------------------------------------
/// Core rendering method for this control.
///
///
/// Information is offset from the center of the object's bounding box,
/// unless the object is a PlayerObjectType, in which case the eye point
/// is used.
///
/// @param updateRect Extents of control.
void GuiShapeDamageHud::onRender( Point2I, const RectI &updateRect)
{
U32 time = Platform::getVirtualMilliseconds();
S32 deltaTime= time - mLastTime;
//Con::errorf("%d = %d - %d", deltaTime, time, mLastTime);
mLastTime = time;
//no impossibilities extending life of popups
if (deltaTime < 0)
deltaTime = 0;
//if something is stuck lets not delete popups all at once
if (deltaTime > 500)
deltaTime = 500;
// Background fill first
if (mShowFill)
GFX->getDrawUtil()->drawRectFill(updateRect, mFillColor);
// Must be in a TS Control
GuiTSCtrl *parent = dynamic_cast<GuiTSCtrl*>(getParent());
if (!parent) return;
// Must have a connection and control object
GameConnection* conn = GameConnection::getConnectionToServer();
if (!conn)
return;
GameBase* control = conn->getControlObject();
if (!control)
return;
// Get control camera info
MatrixF cam;
Point3F camPos;
VectorF camDir;
conn->getControlCameraTransform(0,&cam);
cam.getColumn(3, &camPos);
cam.getColumn(1, &camDir);
F32 camFov;
conn->getControlCameraFov(&camFov);
camFov = mDegToRad(camFov) / 2;
// the next line is optional just to widen the viewcone a little bit for when 40% of a player is visible
// but their center isn't. Increase the viewcone by 5 degrees:
camFov += 0.08; //mDegToRad(5) / 2;
F32 cosCamFov = mCos(camFov);
// Visible distance info & name fading
F32 visDistance = gClientSceneGraph->getVisibleDistance();
F32 visDistanceSqr = visDistance * visDistance;
F32 fadeDistance = visDistance * mDistanceFade;
// Collision info. We're going to be running LOS tests and we
// don't want to collide with the control object.
static U32 losMask = TerrainObjectType | InteriorObjectType; //| ShapeBaseObjectType;
control->disableCollision();
Vector<damagePopup>::iterator i;
for(i = mPopups.begin(); i != mPopups.end(); i++)
{
damagePopup *current = &(*i);
if( !current )
{
//Con::errorf("Damage popup doesn't exist!");
continue;
}
if (current->mTime < 0)
{
//Con::errorf("deleting expired popup at time %d", time);
mPopups.erase(i);
i--;
continue;
}
ShapeBase* shape;
shape = static_cast<ShapeBase*> (Sim::findObject(current->mShape->getId()));
if (!shape)
{
//Con::errorf("Damage popup has a shape that doesn't exist.");
//AssertFatal(current->mShape, "this shape doesn't exist");
mPopups.erase(i);
i--;
continue;
}
if( !(shape->getType() & ShapeBaseObjectType))
{
Con::errorf("Damage popup has a shape that isn't derived from shapeBase.");
continue;
}
//Con::errorf("decreasing popup life %d - %d", current->mTime, deltaTime);
current->mTime -= deltaTime;
// Target pos to test, if it's a player run the LOS to his eye
// point, otherwise we'll grab the generic box center.
Point3F shapePos;
if (shape->getType() & PlayerObjectType)
{
MatrixF eye;
// Use the render eye transform, otherwise we'll see jittering
// Stephen: why always access violations here? grrrrrr
shape->getRenderEyeTransform(&eye);
eye.getColumn(3, &shapePos);
}
else
{
// Use the render transform instead of the box center
// otherwise it'll jitter.
MatrixF srtMat = shape->getRenderTransform();
srtMat.getColumn(3, &shapePos);
}
VectorF shapeDir = shapePos - camPos;
// test early to see if it's behind us.
// no need to normalize shapeDir for this,
// we'll normalize it later if needed.
F32 dot = mDot(shapeDir, camDir);
if (dot < 0)
{
//Con::errorf("Damage popup was behind camera.");
continue;
}
// Test to see if it's in range
F32 shapeDist = shapeDir.lenSquared();
if (shapeDist == 0 || shapeDist > visDistanceSqr)
{
//Con::errorf("Damage popup was not in range.");
continue;
}
shapeDist = mSqrt(shapeDist);
// Test to see if it's within our viewcone, this test doesn't
// actually match the viewport very well, should consider
// projection and box test.
dot /= shapeDist;
if (dot < cosCamFov)
{
//Con::errorf("Damage popup was not in viewcone.");
continue;
}
// Test to see if it's behind something, and we want to
// ignore anything it's mounted on when we run the LOS.
RayInfo info;
shape->disableCollision();
SceneObject *mount = shape->getObjectMount();
if (mount)
mount->disableCollision();
bool los = !gClientContainer.castRay(camPos, shapePos,losMask, &info);
shape->enableCollision();
if (mount)
mount->enableCollision();
if (!los)
{
//Con::errorf("Damage popup did not have line of sight.");
continue;
}
// Project the shape pos into screen space and calculate
// the distance opacity used to fade the labels into the
// distance.
Point3F projPnt;
//shapePos.z += mVerticalOffset;
//perhaps instantiating these as guimembers instead of every message every frame would be better
F32 heightMultiplier= ((F32)current->mTime / (F32)current->mStartTime);
F32 pixelHeight= ((1.0-heightMultiplier)*mEndVerticalOffset) + ((heightMultiplier)*mStartVerticalOffset);
//Con::errorf("before projPnt.y = %.2f", projPnt.y);
if (!parent->project(shapePos, &projPnt))
{
//Con::errorf("Damage popup could not project to screen coordinates.");
continue;
}
projPnt.y -= pixelHeight;
if (projPnt.y < 1)
projPnt.y = 1;
/*
projPnt.x -= 0.6*pixelHeight;
if (projPnt.x < 1)
projPnt.x = 1;
*/
//Con::errorf("heightMultiplier = %.2f pixelHeight = %.2f after projPnt.y = %.2f", heightMultiplier, pixelHeight, projPnt.y);
F32 opacity = (shapeDist < fadeDistance)? 1.0:
1.0 - (shapeDist - fadeDistance) / (visDistance - fadeDistance);
//spend last half of life fading out
F32 ageOpacity = (2.0*(F32)current->mTime / (F32)current->mStartTime);
if (ageOpacity < opacity)
opacity= ageOpacity;
// Render the text
drawDamage(Point2I((S32)projPnt.x, (S32)projPnt.y),current,opacity);
}
// Restore control object collision
control->enableCollision();
}
//----------------------------------------------------------------------------
/// Render popup text.
///
/// Helper function for GuiShapeDamageHud::onRender
///
/// @param offset Screen coordinates to render name label. (Text is centered
/// horizontally about this location, with bottom of text at
/// specified y position.)
/// @param popup the damage popup struct
/// @param opacity Opacity of name (a fraction).
void GuiShapeDamageHud::drawDamage(Point2I offset, damagePopup *popup, F32 opacity)
{
//Con::errorf("executing GuiShapeDamageHud::drawDamage() at shape %d at time %d",popup->mShape->getId(), Platform::getVirtualMilliseconds());
// Center the name
offset.x -= mProfile->mFont->getStrWidth((const UTF8 *)popup->mText) / 2;
offset.y -= mProfile->mFont->getHeight();
// Deal with opacity and draw.
popup->mTextColor.alpha = opacity;
GFX->getDrawUtil()->setBitmapModulation(popup->mTextColor);
GFX->getDrawUtil()->drawText(mProfile->mFont, offset, popup->mText);
GFX->getDrawUtil()->clearBitmapModulation();
}
//New popups are trigger by the scripts.
ConsoleMethod( GuiShapeDamageHud, addPopup, bool, 6, 6, "int time, ColorF color, int object, string text")
{
GameConnection* conn = GameConnection::getConnectionToServer();
if (!conn)
return false;
// Allocate a new popup.
GuiShapeDamageHud::damagePopup newPopup;
// PARSE SHIZZLE
newPopup.mTime = dAtoi(argv[2]);
newPopup.mStartTime = newPopup.mTime;
dSscanf(argv[3], "%f %f %f", &newPopup.mTextColor.red, &newPopup.mTextColor.green, &newPopup.mTextColor.blue);
ShapeBase* shape;
shape = static_cast<ShapeBase*> (Sim::findObject(argv[4])); //(conn->findObject(argv[4]));
if (!shape)
{
Con::errorf("New damage popup couldn't find the shape below! Check guiShapeDamageHud.cc");
Con::errorf(argv[4]);
return false;
}
newPopup.mShape = shape;
newPopup.mText = StringTable->insert(argv[5]);
// Store it in the list at the back to get rendered last
object->mPopups.push_back(newPopup);
//for now i'll assume it worked
return true;
}
Torque 3D Owner Joshua Halls (Xerves)
void GuiShapeDamageHud::pushPopups(void) { Vector<damagePopup>::iterator i; for(i = mPopups.begin(); i != mPopups.end(); i++) { damagePopup *current = &(*i); current->mTime -= 300; current->mStartTime += 300; } return; } //Modified to work with the kit. This function should work in both TGE and TGEA ConsoleMethod( GuiShapeDamageHud, addPopup, bool, 6, 6, "int time, ColorF color, int object, string text") { U32 time = Platform::getVirtualMilliseconds(); U32 diff; S32 ghostID = dAtoi(argv[4]); GameConnection* conn = GameConnection::getConnectionToServer(); if (!conn) return false; if (ghostID == -1) return false; NetObject* shape = conn->resolveGhost(ghostID); // Allocate a new popup.s GuiShapeDamageHud::damagePopup newPopup; // PARSE SHIZZLE newPopup.mTime = dAtoi(argv[2]); newPopup.mStartTime = newPopup.mTime; dSscanf(argv[3], "%f %f %f", &newPopup.mTextColor.red, &newPopup.mTextColor.green, &newPopup.mTextColor.blue); newPopup.mShape = static_cast<ShapeBase*> (shape); //(conn->findObject(argv[4])); if (!newPopup.mShape) { Con::errorf("New damage popup couldn't find the shape below! Check guiShapeDamageHud.cc"); Con::errorf(argv[4]); return false; } newPopup.mText= StringTable->insert(argv[5]); //Checking for overlap here...if they are push all the other popups ahead if (newPopup.mShape->getPopupTime() && time - newPopup.mShape->getPopupTime() < 300) object->pushPopups(); newPopup.mShape->setPopupTime(time); // Store it in the list at the back to get rendered last object->mPopups.push_back(newPopup); //for now i'll assume it worked return true; }Shapebase
void ShapeBase::setPopupTime(U32 time) { mLastPopUPTime = time; } U32 ShapeBase::getPopupTime() { return mLastPopUPTime; }