//----------------------------------------------------------------------------- // guiObjectSelectionHud.cpp // // Description: Action-RPG object selection gui element. // // Author: Matt Huston (matthuston@gmail.com) // Date: June 28th, 2007 // // TGE Porting by // bank // Date: July 11th, 2007 // //----------------------------------------------------------------------------- #include "gui/core/guiControl.h" #include "gui/core/guiTSControl.h" #include "console/consoleTypes.h" #include "sceneGraph/sceneGraph.h" #include "game/shapeBase.h" #include "game/gameConnection.h" class GuiObjectSelectionHud : public GuiControl { typedef GuiControl Parent; S32 mOffset; ColorF mTextColor; ColorF mTextOutlineColor; ColorF mTextFillColor; ColorF mOutlineColor; protected: void drawTargetingRect( const Point2I &a, const Point2I &b, F32 offset, const ColorI &color ); void drawName( Point2I offset, const char *buf, F32 opacity); public: DECLARE_CONOBJECT( GuiObjectSelectionHud ); GuiObjectSelectionHud(); static void initPersistFields(); void onRender( Point2I, const RectI &); }; // Objects we want the castRay to detect static const U32 ObjectMask = PlayerObjectType | VehicleObjectType; IMPLEMENT_CONOBJECT( GuiObjectSelectionHud ); GuiObjectSelectionHud::GuiObjectSelectionHud() { mOffset = 10.0f; mTextColor.set(0.2f, 0.2f, 0.2f, 1.0f); mTextOutlineColor.set(0.0f, 1.0f, 0.0f, 1.0f); mTextFillColor.set(0.8f, 0.8f, 0.8f, 0.8f); mOutlineColor.set(0.0f, 1.0f, 0.0f, 1.0f); } void GuiObjectSelectionHud::initPersistFields() { Parent::initPersistFields(); addField( "Offset", TypeS32, Offset( mOffset, GuiObjectSelectionHud ) ); addField( "TextColor", TypeColorF, Offset( mTextColor, GuiObjectSelectionHud ) ); addField( "TextOutlineColor", TypeColorF, Offset( mTextOutlineColor, GuiObjectSelectionHud ) ); addField( "TextFillColor", TypeColorF, Offset( mTextFillColor, GuiObjectSelectionHud ) ); addField( "OutlineColor", TypeColorF, Offset( mOutlineColor, GuiObjectSelectionHud ) ); } void GuiObjectSelectionHud::onRender(Point2I offset, const RectI &updateRect) { // Must be in a TS Control GuiTSCtrl *parent = dynamic_cast(getParent()); if (!parent) return; // Must have a connection and player control object GameConnection* conn = GameConnection::getConnectionToServer(); if (!conn) return; ShapeBase* control = conn->getControlObject(); if (!control || !(control->getType() & ObjectMask))// || !conn->isFirstPerson()) return; // Parent render. Parent::onRender(offset, updateRect); // Get control camera info MatrixF cam; Point3F camPos; control->getEyeTransform(&cam); cam.getColumn(3, &camPos); // Extend the camera vector to create an endpoint for our ray Point3F endPos; cam.getColumn(1, &endPos); endPos *= 10.0f; endPos += camPos; // Collision info. We're going to be running LOS tests and we don't // want to collide with the control object, terrain or interiors. static U32 losMask = TerrainObjectType | InteriorObjectType | ShapeBaseObjectType; control->disableCollision(); RayInfo info; if (gClientContainer.castRay(camPos, endPos, losMask, &info)) { if (ShapeBase* obj = dynamic_cast(info.object)) { // If the object has a name, we will allow it to be selected if (obj->getShapeName()) { Box3F bounds = obj->getRenderWorldBox(); // Generate the 8 bounding points of the box. Point3F pts[8]; U32 i = 0; pts[i].x = bounds.min.x; pts[i].y = bounds.min.y; pts[i].z = bounds.min.z; i++; pts[i].x = bounds.min.x; pts[i].y = bounds.min.y; pts[i].z = bounds.max.z; i++; pts[i].x = bounds.min.x; pts[i].y = bounds.max.y; pts[i].z = bounds.min.z; i++; pts[i].x = bounds.min.x; pts[i].y = bounds.max.y; pts[i].z = bounds.max.z; i++; pts[i].x = bounds.max.x; pts[i].y = bounds.min.y; pts[i].z = bounds.min.z; i++; pts[i].x = bounds.max.x; pts[i].y = bounds.min.y; pts[i].z = bounds.max.z; i++; pts[i].x = bounds.max.x; pts[i].y = bounds.max.y; pts[i].z = bounds.min.z; i++; pts[i].x = bounds.max.x; pts[i].y = bounds.max.y; pts[i].z = bounds.max.z; i++; Point3F boxCenter; bounds.getCenter(&boxCenter); Point3F rectCenter; parent->project(boxCenter, &rectCenter); RectI rect(rectCenter.x, rectCenter.y, 1, 1); Point3F pt; for(S32 i = 0 ; i < 8; i++) { parent->project(pts[i], &pt); if (pt.x < rect.point.x) { rect.point.x = pt.x; } if (pt.y < rect.point.y) { rect.point.y = pt.y; } } for(S32 i = 0 ; i < 8 ; i++) { parent->project(pts[i], &pt); if (pt.x > rect.point.x + rect.extent.x) { rect.extent.x = pt.x - rect.point.x; } if (pt.y > rect.point.y + rect.extent.y) { rect.extent.y = pt.y - rect.point.y; } } Point2I topleft(rect.point.x, rect.point.y); Point2I botright(rect.point.x + rect.extent.x - 1, rect.point.y + rect.extent.y - 1); if (topleft.x < 5) topleft.x = 5; if (topleft.y < 5) topleft.y = 5; if (topleft.x > getWidth() - 105) topleft.x = getWidth() - 105; if (topleft.y > getHeight() - 105) topleft.y = getHeight() - 105; if (botright.x < 105) botright.x = 105; if (botright.y < 105) botright.y = 105; if (botright.x > getWidth() - 5) botright.x = getWidth() - 5; if (botright.y > getHeight() - 5) botright.y = getHeight() - 5; // Draw!! drawTargetingRect(topleft, botright, 20.0f, mOutlineColor); drawName(topleft, obj->getShapeName(), 1.0f); } } } // Restore control object collision control->enableCollision(); } void GuiObjectSelectionHud::drawName(Point2I offset, const char *name, F32 opacity) { offset.x += 5; offset.y += 5; // Text outline rectangle dglDrawRect(Point2I(offset.x, offset.y), Point2I(offset.x + mProfile->mFont->getStrWidth((const UTF8 *)name) + mOffset, offset.y + mProfile->mFont->getHeight()), mTextOutlineColor); // Text outline fill rectangle dglDrawRectFill(Point2I(offset.x + 1, offset.y + 1), Point2I(offset.x + mProfile->mFont->getStrWidth((const UTF8 *)name) + mOffset - 1, offset.y + mProfile->mFont->getHeight() - 1), mTextFillColor); // Position text in the rectangle and draw offset.x = offset.x + (mOffset / 2); dglSetBitmapModulation(mTextColor); dglDrawText(mProfile->mFont, offset, name); dglClearBitmapModulation(); } void GuiObjectSelectionHud::drawTargetingRect( const Point2I &tl, const Point2I &br, F32 offset, const ColorI &color ) { // Top Left dglDrawLine(tl.x, tl.y, tl.x + offset, tl.y, color); dglDrawLine(tl.x, tl.y, tl.x, tl.y + offset, color); // Top Right dglDrawLine(br.x, tl.y, br.x - offset, tl.y, color); dglDrawLine(br.x, tl.y, br.x, tl.y + offset, color); // Bottom Left dglDrawLine(tl.x, br.y, tl.x + offset, br.y, color); dglDrawLine(tl.x, br.y, tl.x, br.y - offset, color); // Bottom Right dglDrawLine(br.x, br.y, br.x - offset, br.y, color); dglDrawLine(br.x, br.y, br.x, br.y - offset, color); }