From 4ffe6d2bb7eb2d063dcaeb6e7b25879c509d3fac Mon Sep 17 00:00:00 2001 From: Areloch Date: Mon, 17 Aug 2020 16:41:59 -0500 Subject: [PATCH] Adds a notes object that only displays in the editor, useful for when working on maps. --- Engine/source/T3D/notesObject.cpp | 163 ++++++++++++++++++ Engine/source/T3D/notesObject.h | 103 +++++++++++ Engine/source/gui/worldEditor/worldEditor.cpp | 32 ++++ .../worldEditor/gui/objectBuilderGui.ed.gui | 5 + .../worldEditor/scripts/editors/creator.ed.cs | 1 + 5 files changed, 304 insertions(+) create mode 100644 Engine/source/T3D/notesObject.cpp create mode 100644 Engine/source/T3D/notesObject.h diff --git a/Engine/source/T3D/notesObject.cpp b/Engine/source/T3D/notesObject.cpp new file mode 100644 index 000000000..5490929de --- /dev/null +++ b/Engine/source/T3D/notesObject.cpp @@ -0,0 +1,163 @@ +#include "T3D/notesObject.h" + +#include "math/mathIO.h" +#include "scene/sceneRenderState.h" +#include "core/stream/bitStream.h" +#include "materials/sceneData.h" +#include "gfx/gfxDebugEvent.h" +#include "gfx/gfxTransformSaver.h" +#include "renderInstance/renderPassManager.h" +#include "math\mathUtils.h" +#include "gfx/gfxDrawUtil.h" + +IMPLEMENT_CO_NETOBJECT_V1(NotesObject); + +extern bool gEditingMission; + +//----------------------------------------------------------------------------- +// Object setup and teardown +//----------------------------------------------------------------------------- +NotesObject::NotesObject() +{ + // Flag this object so that it will always + // be sent across the network to clients + mNetFlags.set(Ghostable | ScopeAlways); + + // Set it as a "static" object + mTypeMask |= StaticObjectType | StaticShapeObjectType; + + mShowArrow = true; + mArrowLength = 5; + mArrowRadius = 0.25; +} + +NotesObject::~NotesObject() +{ +} + +//----------------------------------------------------------------------------- +// Object Editing +//----------------------------------------------------------------------------- +void NotesObject::initPersistFields() +{ + Parent::initPersistFields(); + + addField("Note", TypeCommand, Offset(mNote, NotesObject), ""); + + addField("showArrow", TypeBool, Offset(mShowArrow, NotesObject), ""); + + addField("arrowColor", TypeColorF, Offset(mArrowColor, NotesObject), ""); +} + +void NotesObject::inspectPostApply() +{ + // Apply any transformations set in the editor + Parent::inspectPostApply(); + + if (isServerObject()) + { + setMaskBits(-1); + } +} + +bool NotesObject::onAdd() +{ + if (!Parent::onAdd()) + return false; + + // Set up a 1x1x1 bounding box + mObjBox.set(Point3F(-0.5f, -0.5f, -0.5f), + Point3F(0.5f, 0.5f, 0.5f)); + + resetWorldBox(); + + // Add this object to the scene + addToScene(); + + return true; +} + +void NotesObject::onRemove() +{ + // Remove this object from the scene + removeFromScene(); + + Parent::onRemove(); +} + +void NotesObject::setTransform(const MatrixF& mat) +{ + // Let SceneObject handle all of the matrix manipulation + Parent::setTransform(mat); + + // Dirty our network mask so that the new transform gets + // transmitted to the client object + setMaskBits(TransformMask); +} + +U32 NotesObject::packUpdate(NetConnection* conn, U32 mask, BitStream* stream) +{ + // Allow the Parent to get a crack at writing its info + U32 retMask = Parent::packUpdate(conn, mask, stream); + + // Write our transform information + //if (stream->writeFlag(mask & TransformMask)) + { + mathWrite(*stream, getTransform()); + mathWrite(*stream, getScale()); + stream->write(mShowArrow); + + stream->write(mArrowColor); + } + + return retMask; +} + +void NotesObject::unpackUpdate(NetConnection* conn, BitStream* stream) +{ + // Let the Parent read any info it sent + Parent::unpackUpdate(conn, stream); + + //if (stream->readFlag()) // TransformMask + { + mathRead(*stream, &mObjToWorld); + mathRead(*stream, &mObjScale); + + setTransform(mObjToWorld); + + stream->read(&mShowArrow); + stream->read(&mArrowColor); + } +} + +void NotesObject::prepRenderImage(SceneRenderState* state) +{ + if (!gEditingMission) + return; + + ObjectRenderInst* ri = state->getRenderPass()->allocInst(); + ri->renderDelegate.bind(this, &NotesObject::_render); + ri->type = RenderPassManager::RIT_Editor; + state->getRenderPass()->addInst(ri); +} + +void NotesObject::_render(ObjectRenderInst* ri, SceneRenderState* state, BaseMatInstance* overrideMat) +{ + if (showArrow()) + { + GFXStateBlockDesc desc; + desc.setBlend(true); + desc.setZReadWrite(true, false); + + VectorF forwardVec = getTransform().getForwardVector(); + forwardVec.normalize(); + + Point3F startPos = forwardVec * -(mArrowLength * 0.5) + getPosition(); + Point3F endPos = forwardVec * (mArrowLength * 0.5) + getPosition(); + + ColorI arrowColor = mArrowColor.toColorI(); + arrowColor.alpha = 128; + + GFX->getDrawUtil()->drawArrow(desc, startPos, endPos, arrowColor, mArrowRadius); + } +} diff --git a/Engine/source/T3D/notesObject.h b/Engine/source/T3D/notesObject.h new file mode 100644 index 000000000..80d16cd69 --- /dev/null +++ b/Engine/source/T3D/notesObject.h @@ -0,0 +1,103 @@ +#pragma once + +#ifndef _SCENEOBJECT_H_ +#include "scene/sceneObject.h" +#endif +#ifndef _GFXSTATEBLOCK_H_ +#include "gfx/gfxStateBlock.h" +#endif +#ifndef _GFXVERTEXBUFFER_H_ +#include "gfx/gfxVertexBuffer.h" +#endif +#ifndef _GFXPRIMITIVEBUFFER_H_ +#include "gfx/gfxPrimitiveBuffer.h" +#endif + +//----------------------------------------------------------------------------- +// This class implements a basic SceneObject that can exist in the world at a +// 3D position and render itself. Note that NotesObject handles its own +// rendering by submitting itself as an ObjectRenderInst (see +// renderInstance\renderPassmanager.h) along with a delegate for its render() +// function. However, the preffered rendering method in the engine is to submit +// a MeshRenderInst along with a Material, vertex buffer, primitive buffer, and +// transform and allow the RenderMeshMgr handle the actual rendering. You can +// see this implemented in RenderMeshExample. +//----------------------------------------------------------------------------- + +class NotesObject : public SceneObject +{ + typedef SceneObject Parent; + + String mNote; + bool mShowArrow; + F32 mArrowLength; + F32 mArrowRadius; + + LinearColorF mArrowColor; + + // Networking masks + // We need to implement at least one of these to allow + // the client version of the object to receive updates + // from the server version (like if it has been moved + // or edited) + enum MaskBits + { + TransformMask = Parent::NextFreeMask << 0, + NextFreeMask = Parent::NextFreeMask << 1 + }; + + //-------------------------------------------------------------------------- + // Rendering variables + //-------------------------------------------------------------------------- + // Define our vertex format here so we don't have to + // change it in multiple spots later + typedef GFXVertexPCN VertexType; + + // The handles for our StateBlocks + GFXStateBlockRef mNormalSB; + GFXStateBlockRef mReflectSB; + + // The GFX vertex and primitive buffers + GFXVertexBufferHandle< VertexType > mVertexBuffer; + +public: + NotesObject(); + virtual ~NotesObject(); + + // Declare this object as a ConsoleObject so that we can + // instantiate it into the world and network it + DECLARE_CONOBJECT(NotesObject); + + //-------------------------------------------------------------------------- + // Object Editing + // Since there is always a server and a client object in Torque and we + // actually edit the server object we need to implement some basic + // networking functions + //-------------------------------------------------------------------------- + // Set up any fields that we want to be editable (like position) + static void initPersistFields(); + + void inspectPostApply(); + + // Handle when we are added to the scene and removed from the scene + bool onAdd(); + void onRemove(); + + // Override this so that we can dirty the network flag when it is called + void setTransform(const MatrixF& mat); + + // This function handles sending the relevant data from the server + // object to the client object + U32 packUpdate(NetConnection* conn, U32 mask, BitStream* stream); + // This function handles receiving relevant data from the server + // object and applying it to the client object + void unpackUpdate(NetConnection* conn, BitStream* stream); + + // This is the function that allows this object to submit itself for rendering + void prepRenderImage(SceneRenderState* state); + + void _render(ObjectRenderInst* ri, SceneRenderState* state, BaseMatInstance* overrideMat); + + String getNote() { return mNote; } + bool showArrow() { return mShowArrow; } +}; diff --git a/Engine/source/gui/worldEditor/worldEditor.cpp b/Engine/source/gui/worldEditor/worldEditor.cpp index e7ecfe3c6..60b67f5da 100644 --- a/Engine/source/gui/worldEditor/worldEditor.cpp +++ b/Engine/source/gui/worldEditor/worldEditor.cpp @@ -52,6 +52,7 @@ #include "tools/editorTool.h" #include "T3D/Scene.h" +#include IMPLEMENT_CONOBJECT( WorldEditor ); @@ -1709,6 +1710,37 @@ void WorldEditor::renderScreenObj( SceneObject *obj, const Point3F& projPos, con drawer->drawText(mProfile->mFont, pos, str); }; } + + NotesObject* noteObj = dynamic_cast(obj); + if (noteObj) + { + Point2I pos(sPos); + + MatrixF cameraMat = mLastCameraQuery.cameraMatrix; + + Point3F camPos = cameraMat.getPosition(); + Point3F notePos = noteObj->getPosition(); + + VectorF distVec = notePos - camPos; + F32 dist = distVec.len(); + + F32 maxNoteDistance = 100; + F32 noteFadeStartDist = 50; + + F32 fade = 1; + + if(dist >= noteFadeStartDist) + fade = -((dist - noteFadeStartDist) / (maxNoteDistance - noteFadeStartDist)); + + if (dist >= maxNoteDistance) + return; + + ColorI noteTextColor = mObjectTextColor; + noteTextColor.alpha = 255 * fade; + + drawer->setBitmapModulation(noteTextColor); + drawer->drawText(mProfile->mFont, pos, noteObj->getNote().c_str()); + } } //------------------------------------------------------------------------------ diff --git a/Templates/BaseGame/game/tools/worldEditor/gui/objectBuilderGui.ed.gui b/Templates/BaseGame/game/tools/worldEditor/gui/objectBuilderGui.ed.gui index ced9031b0..7b532067c 100644 --- a/Templates/BaseGame/game/tools/worldEditor/gui/objectBuilderGui.ed.gui +++ b/Templates/BaseGame/game/tools/worldEditor/gui/objectBuilderGui.ed.gui @@ -1070,6 +1070,11 @@ function ObjectBuilderGui::buildObserverDropPoint(%this) %this.process(); } +function ObjectBuilderGui::buildNotesObject(%this) +{ + %this.objectClassName = "NotesObject"; + %this.process(); +} //------------------------------------------------------------------------------ // System //------------------------------------------------------------------------------ diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/editors/creator.ed.cs b/Templates/BaseGame/game/tools/worldEditor/scripts/editors/creator.ed.cs index ff1aba119..8b5e706da 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/editors/creator.ed.cs +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/editors/creator.ed.cs @@ -93,6 +93,7 @@ function EWCreatorWindow::init( %this ) %this.registerMissionObject("NavMesh", "Navigation mesh"); %this.registerMissionObject("NavPath", "Path"); %this.registerMissionObject( "Entity", "Entity" ); + %this.registerMissionObject( "NotesObject", "Note" ); %this.endGroup();