mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-20 04:34:48 +00:00
Added utility method to prefab to be able to get the internal simGroup that contains it's children Adjusted logic for mounting items in GuiShapeEdPreview to utilize assetIds for the shapes Moved the Asset and AssetBrowser editor settings populate functions to the AssetBrowser script to better organize things Fixed command usage for General, Player and Observer spawn point creator entries to use the correct callback commands Fixed logic for creator callback commands that don't just route through the class name based structure Added RMB context menu actions for opening asset file or folder locations in OS file explorer Fixed lookup of animation assets when editing a shape's animations in the shape editor so it provides the assetId of the anim if it exists Fixes handling of mounting in the shape editor so it utilizes assets and the asset browser like everything else
356 lines
11 KiB
C++
356 lines
11 KiB
C++
//-----------------------------------------------------------------------------
|
|
// Copyright (c) 2012 GarageGames, LLC
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to
|
|
// deal in the Software without restriction, including without limitation the
|
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
// sell copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
// IN THE SOFTWARE.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "platform/platform.h"
|
|
#include "T3D/examples/renderMeshExample.h"
|
|
|
|
#include "math/mathIO.h"
|
|
#include "scene/sceneRenderState.h"
|
|
#include "console/consoleTypes.h"
|
|
#include "core/stream/bitStream.h"
|
|
#include "materials/materialManager.h"
|
|
#include "materials/baseMatInstance.h"
|
|
#include "renderInstance/renderPassManager.h"
|
|
#include "lighting/lightQuery.h"
|
|
#include "console/engineAPI.h"
|
|
|
|
IMPLEMENT_CO_NETOBJECT_V1(RenderMeshExample);
|
|
|
|
ConsoleDocClass( RenderMeshExample,
|
|
"@brief An example scene object which renders a mesh.\n\n"
|
|
"This class implements a basic SceneObject that can exist in the world at a "
|
|
"3D position and render itself. There are several valid ways to render an "
|
|
"object in Torque. This class implements the preferred rendering method which "
|
|
"is to submit a MeshRenderInst along with a Material, vertex buffer, "
|
|
"primitive buffer, and transform and allow the RenderMeshMgr handle the "
|
|
"actual setup and rendering for you.\n\n"
|
|
"See the C++ code for implementation details.\n\n"
|
|
"@ingroup Examples\n" );
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object setup and teardown
|
|
//-----------------------------------------------------------------------------
|
|
RenderMeshExample::RenderMeshExample()
|
|
{
|
|
// 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 that casts shadows
|
|
mTypeMask |= StaticObjectType | StaticShapeObjectType;
|
|
|
|
INIT_ASSET(Material);
|
|
mMaterialInst = NULL;
|
|
}
|
|
|
|
RenderMeshExample::~RenderMeshExample()
|
|
{
|
|
if ( mMaterialInst )
|
|
SAFE_DELETE( mMaterialInst );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object Editing
|
|
//-----------------------------------------------------------------------------
|
|
void RenderMeshExample::initPersistFields()
|
|
{
|
|
addGroup( "Rendering" );
|
|
INITPERSISTFIELD_MATERIALASSET(Material, RenderMeshExample, "The material used to render the mesh.");
|
|
endGroup( "Rendering" );
|
|
|
|
// SceneObject already handles exposing the transform
|
|
Parent::initPersistFields();
|
|
}
|
|
|
|
void RenderMeshExample::inspectPostApply()
|
|
{
|
|
Parent::inspectPostApply();
|
|
|
|
// Flag the network mask to send the updates
|
|
// to the client object
|
|
setMaskBits( UpdateMask );
|
|
}
|
|
|
|
bool RenderMeshExample::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();
|
|
|
|
// Refresh this object's material (if any)
|
|
updateMaterial();
|
|
|
|
return true;
|
|
}
|
|
|
|
void RenderMeshExample::onRemove()
|
|
{
|
|
// Remove this object from the scene
|
|
removeFromScene();
|
|
|
|
Parent::onRemove();
|
|
}
|
|
|
|
void RenderMeshExample::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 RenderMeshExample::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());
|
|
}
|
|
|
|
// Write out any of the updated editable properties
|
|
if (stream->writeFlag(mask & UpdateMask))
|
|
{
|
|
PACK_ASSET(conn, Material);
|
|
}
|
|
|
|
return retMask;
|
|
}
|
|
|
|
void RenderMeshExample::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 );
|
|
}
|
|
|
|
if ( stream->readFlag() ) // UpdateMask
|
|
{
|
|
UNPACK_ASSET(conn, Material);
|
|
|
|
if ( isProperlyAdded() )
|
|
updateMaterial();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Object Rendering
|
|
//-----------------------------------------------------------------------------
|
|
void RenderMeshExample::createGeometry()
|
|
{
|
|
static const Point3F cubePoints[8] =
|
|
{
|
|
Point3F( 1, -1, -1), Point3F( 1, -1, 1), Point3F( 1, 1, -1), Point3F( 1, 1, 1),
|
|
Point3F(-1, -1, -1), Point3F(-1, 1, -1), Point3F(-1, -1, 1), Point3F(-1, 1, 1)
|
|
};
|
|
|
|
static const Point3F cubeNormals[6] =
|
|
{
|
|
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 const Point2F cubeTexCoords[4] =
|
|
{
|
|
Point2F( 0, 0), Point2F( 0, -1),
|
|
Point2F( 1, 0), Point2F( 1, -1)
|
|
};
|
|
|
|
static const U32 cubeFaces[36][3] =
|
|
{
|
|
{ 3, 0, 3 }, { 0, 0, 0 }, { 1, 0, 1 },
|
|
{ 2, 0, 2 }, { 0, 0, 0 }, { 3, 0, 3 },
|
|
{ 7, 1, 1 }, { 4, 1, 2 }, { 5, 1, 0 },
|
|
{ 6, 1, 3 }, { 4, 1, 2 }, { 7, 1, 1 },
|
|
{ 3, 2, 1 }, { 5, 2, 2 }, { 2, 2, 0 },
|
|
{ 7, 2, 3 }, { 5, 2, 2 }, { 3, 2, 1 },
|
|
{ 1, 3, 3 }, { 4, 3, 0 }, { 6, 3, 1 },
|
|
{ 0, 3, 2 }, { 4, 3, 0 }, { 1, 3, 3 },
|
|
{ 3, 4, 3 }, { 6, 4, 0 }, { 7, 4, 1 },
|
|
{ 1, 4, 2 }, { 6, 4, 0 }, { 3, 4, 3 },
|
|
{ 2, 5, 1 }, { 4, 5, 2 }, { 0, 5, 0 },
|
|
{ 5, 5, 3 }, { 4, 5, 2 }, { 2, 5, 1 }
|
|
};
|
|
|
|
// Fill the vertex buffer
|
|
VertexType *pVert = NULL;
|
|
|
|
mVertexBuffer.set( GFX, 36, GFXBufferTypeStatic );
|
|
pVert = mVertexBuffer.lock();
|
|
|
|
Point3F halfSize = getObjBox().getExtents() * 0.5f;
|
|
|
|
for (U32 i = 0; i < 36; i++)
|
|
{
|
|
const U32& vdx = cubeFaces[i][0];
|
|
const U32& ndx = cubeFaces[i][1];
|
|
const U32& tdx = cubeFaces[i][2];
|
|
|
|
pVert[i].point = cubePoints[vdx] * halfSize;
|
|
pVert[i].normal = cubeNormals[ndx];
|
|
pVert[i].texCoord = cubeTexCoords[tdx];
|
|
}
|
|
|
|
mVertexBuffer.unlock();
|
|
|
|
// Fill the primitive buffer
|
|
U16 *pIdx = NULL;
|
|
|
|
mPrimitiveBuffer.set( GFX, 36, 12, GFXBufferTypeStatic );
|
|
|
|
mPrimitiveBuffer.lock(&pIdx);
|
|
|
|
for (U16 i = 0; i < 36; i++)
|
|
pIdx[i] = i;
|
|
|
|
mPrimitiveBuffer.unlock();
|
|
}
|
|
|
|
void RenderMeshExample::updateMaterial()
|
|
{
|
|
if (mMaterialAsset.notNull())
|
|
{
|
|
if (mMaterialInst && String(mMaterialAsset->getMaterialDefinitionName()).equal(mMaterialInst->getMaterial()->getName(), String::NoCase))
|
|
return;
|
|
|
|
SAFE_DELETE(mMaterialInst);
|
|
|
|
mMaterialInst = MATMGR->createMatInstance(mMaterialAsset->getMaterialDefinitionName(), getGFXVertexFormat< VertexType >());
|
|
|
|
if (!mMaterialInst)
|
|
Con::errorf("RenderMeshExample::updateMaterial - no Material called '%s'", mMaterialAsset->getMaterialDefinitionName());
|
|
}
|
|
}
|
|
|
|
void RenderMeshExample::prepRenderImage( SceneRenderState *state )
|
|
{
|
|
// Do a little prep work if needed
|
|
if ( mVertexBuffer.isNull() )
|
|
createGeometry();
|
|
|
|
// If we have no material then skip out.
|
|
if ( !mMaterialInst || !state)
|
|
return;
|
|
|
|
// If we don't have a material instance after the override then
|
|
// we can skip rendering all together.
|
|
BaseMatInstance *matInst = state->getOverrideMaterial( mMaterialInst );
|
|
if ( !matInst )
|
|
return;
|
|
|
|
// Get a handy pointer to our RenderPassmanager
|
|
RenderPassManager *renderPass = state->getRenderPass();
|
|
|
|
// Allocate an MeshRenderInst so that we can submit it to the RenderPassManager
|
|
MeshRenderInst *ri = renderPass->allocInst<MeshRenderInst>();
|
|
|
|
// Set our RenderInst as a standard mesh render
|
|
ri->type = RenderPassManager::RIT_Mesh;
|
|
|
|
//If our material has transparency set on this will redirect it to proper render bin
|
|
if ( matInst->getMaterial()->isTranslucent() )
|
|
{
|
|
ri->type = RenderPassManager::RIT_Translucent;
|
|
ri->translucentSort = true;
|
|
}
|
|
|
|
// Calculate our sorting point
|
|
if ( state )
|
|
{
|
|
// Calculate our sort point manually.
|
|
const Box3F& rBox = getRenderWorldBox();
|
|
ri->sortDistSq = rBox.getSqDistanceToPoint( state->getCameraPosition() );
|
|
}
|
|
else
|
|
ri->sortDistSq = 0.0f;
|
|
|
|
// Set up our transforms
|
|
MatrixF objectToWorld = getRenderTransform();
|
|
objectToWorld.scale( getScale() );
|
|
|
|
ri->objectToWorld = renderPass->allocUniqueXform( objectToWorld );
|
|
ri->worldToCamera = renderPass->allocSharedXform(RenderPassManager::View);
|
|
ri->projection = renderPass->allocSharedXform(RenderPassManager::Projection);
|
|
|
|
// If our material needs lights then fill the RIs
|
|
// light vector with the best lights.
|
|
if ( matInst->isForwardLit() )
|
|
{
|
|
LightQuery query;
|
|
query.init( getWorldSphere() );
|
|
query.getLights( ri->lights, 8 );
|
|
}
|
|
|
|
// Make sure we have an up-to-date backbuffer in case
|
|
// our Material would like to make use of it
|
|
// NOTICE: SFXBB is removed and refraction is disabled!
|
|
//ri->backBuffTex = GFX->getSfxBackBuffer();
|
|
|
|
// Set our Material
|
|
ri->matInst = matInst;
|
|
|
|
// Set up our vertex buffer and primitive buffer
|
|
ri->vertBuff = &mVertexBuffer;
|
|
ri->primBuff = &mPrimitiveBuffer;
|
|
|
|
ri->prim = renderPass->allocPrim();
|
|
ri->prim->type = GFXTriangleList;
|
|
ri->prim->minIndex = 0;
|
|
ri->prim->startIndex = 0;
|
|
ri->prim->numPrimitives = 12;
|
|
ri->prim->startVertex = 0;
|
|
ri->prim->numVertices = 36;
|
|
|
|
// We sort by the material then vertex buffer
|
|
ri->defaultKey = matInst->getStateHint();
|
|
ri->defaultKey2 = (uintptr_t)ri->vertBuff; // Not 64bit safe!
|
|
|
|
// Submit our RenderInst to the RenderPassManager
|
|
state->getRenderPass()->addInst( ri );
|
|
}
|
|
|
|
DefineEngineMethod( RenderMeshExample, postApply, void, (),,
|
|
"A utility method for forcing a network update.\n")
|
|
{
|
|
object->inspectPostApply();
|
|
}
|