Torque3D/Engine/source/T3D/examples/renderMeshExample.cpp
Areloch 5525f8ecdd Converts all game, gui editor, and system classes to utilize assets
Processed core, tools and default modules to utilize assets
Converted all console types that were string based, such as TypeImageFilename to utilize const char*/the string table, which avoids a lot of type swapping shenanigans and avoids string corruption
Removed unneeded MainEditor mockup module
Removed some unused/duplicate image assets from the tools
2021-07-19 01:07:08 -05:00

355 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_MATERIALASSET(Material);
}
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_MATERIALASSET(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_MATERIALASSET(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();
}