mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-20 20:54:46 +00:00
280 lines
9.1 KiB
C++
280 lines
9.1 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 "T3D/examples/renderObjectExample.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"
|
||
|
|
|
||
|
|
|
||
|
|
IMPLEMENT_CO_NETOBJECT_V1(RenderObjectExample);
|
||
|
|
|
||
|
|
ConsoleDocClass( RenderObjectExample,
|
||
|
|
"@brief An example scene object which renders using a callback.\n\n"
|
||
|
|
"This class implements a basic SceneObject that can exist in the world at a "
|
||
|
|
"3D position and render itself. Note that RenderObjectExample 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.\n\n"
|
||
|
|
"See the C++ code for implementation details.\n\n"
|
||
|
|
"@ingroup Examples\n" );
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
// Object setup and teardown
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
RenderObjectExample::RenderObjectExample()
|
||
|
|
{
|
||
|
|
// 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;
|
||
|
|
}
|
||
|
|
|
||
|
|
RenderObjectExample::~RenderObjectExample()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
// Object Editing
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void RenderObjectExample::initPersistFields()
|
||
|
|
{
|
||
|
|
// SceneObject already handles exposing the transform
|
||
|
|
Parent::initPersistFields();
|
||
|
|
}
|
||
|
|
|
||
|
|
bool RenderObjectExample::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 RenderObjectExample::onRemove()
|
||
|
|
{
|
||
|
|
// Remove this object from the scene
|
||
|
|
removeFromScene();
|
||
|
|
|
||
|
|
Parent::onRemove();
|
||
|
|
}
|
||
|
|
|
||
|
|
void RenderObjectExample::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 RenderObjectExample::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());
|
||
|
|
}
|
||
|
|
|
||
|
|
return retMask;
|
||
|
|
}
|
||
|
|
|
||
|
|
void RenderObjectExample::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 );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
// Object Rendering
|
||
|
|
//-----------------------------------------------------------------------------
|
||
|
|
void RenderObjectExample::createGeometry()
|
||
|
|
{
|
||
|
|
static const Point3F cubePoints[8] =
|
||
|
|
{
|
||
|
|
Point3F( 1.0f, -1.0f, -1.0f), Point3F( 1.0f, -1.0f, 1.0f),
|
||
|
|
Point3F( 1.0f, 1.0f, -1.0f), Point3F( 1.0f, 1.0f, 1.0f),
|
||
|
|
Point3F(-1.0f, -1.0f, -1.0f), Point3F(-1.0f, 1.0f, -1.0f),
|
||
|
|
Point3F(-1.0f, -1.0f, 1.0f), Point3F(-1.0f, 1.0f, 1.0f)
|
||
|
|
};
|
||
|
|
|
||
|
|
static const Point3F cubeNormals[6] =
|
||
|
|
{
|
||
|
|
Point3F( 1.0f, 0.0f, 0.0f), Point3F(-1.0f, 0.0f, 0.0f),
|
||
|
|
Point3F( 0.0f, 1.0f, 0.0f), Point3F( 0.0f, -1.0f, 0.0f),
|
||
|
|
Point3F( 0.0f, 0.0f, 1.0f), Point3F( 0.0f, 0.0f, -1.0f)
|
||
|
|
};
|
||
|
|
|
||
|
|
static const ColorI cubeColors[3] =
|
||
|
|
{
|
||
|
|
ColorI( 255, 0, 0, 255 ),
|
||
|
|
ColorI( 0, 255, 0, 255 ),
|
||
|
|
ColorI( 0, 0, 255, 255 )
|
||
|
|
};
|
||
|
|
|
||
|
|
static const U32 cubeFaces[36][3] =
|
||
|
|
{
|
||
|
|
{ 3, 0, 0 }, { 0, 0, 0 }, { 1, 0, 0 },
|
||
|
|
{ 2, 0, 0 }, { 0, 0, 0 }, { 3, 0, 0 },
|
||
|
|
{ 7, 1, 0 }, { 4, 1, 0 }, { 5, 1, 0 },
|
||
|
|
{ 6, 1, 0 }, { 4, 1, 0 }, { 7, 1, 0 },
|
||
|
|
{ 3, 2, 1 }, { 5, 2, 1 }, { 2, 2, 1 },
|
||
|
|
{ 7, 2, 1 }, { 5, 2, 1 }, { 3, 2, 1 },
|
||
|
|
{ 1, 3, 1 }, { 4, 3, 1 }, { 6, 3, 1 },
|
||
|
|
{ 0, 3, 1 }, { 4, 3, 1 }, { 1, 3, 1 },
|
||
|
|
{ 3, 4, 2 }, { 6, 4, 2 }, { 7, 4, 2 },
|
||
|
|
{ 1, 4, 2 }, { 6, 4, 2 }, { 3, 4, 2 },
|
||
|
|
{ 2, 5, 2 }, { 4, 5, 2 }, { 0, 5, 2 },
|
||
|
|
{ 5, 5, 2 }, { 4, 5, 2 }, { 2, 5, 2 }
|
||
|
|
};
|
||
|
|
|
||
|
|
// 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& cdx = cubeFaces[i][2];
|
||
|
|
|
||
|
|
pVert[i].point = cubePoints[vdx] * halfSize;
|
||
|
|
pVert[i].normal = cubeNormals[ndx];
|
||
|
|
pVert[i].color = cubeColors[cdx];
|
||
|
|
}
|
||
|
|
|
||
|
|
mVertexBuffer.unlock();
|
||
|
|
|
||
|
|
// Set up our normal and reflection StateBlocks
|
||
|
|
GFXStateBlockDesc desc;
|
||
|
|
|
||
|
|
// The normal StateBlock only needs a default StateBlock
|
||
|
|
mNormalSB = GFX->createStateBlock( desc );
|
||
|
|
|
||
|
|
// The reflection needs its culling reversed
|
||
|
|
desc.cullDefined = true;
|
||
|
|
desc.cullMode = GFXCullCW;
|
||
|
|
mReflectSB = GFX->createStateBlock( desc );
|
||
|
|
}
|
||
|
|
|
||
|
|
void RenderObjectExample::prepRenderImage( SceneRenderState *state )
|
||
|
|
{
|
||
|
|
// Do a little prep work if needed
|
||
|
|
if ( mVertexBuffer.isNull() )
|
||
|
|
createGeometry();
|
||
|
|
|
||
|
|
// Allocate an ObjectRenderInst so that we can submit it to the RenderPassManager
|
||
|
|
ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
|
||
|
|
|
||
|
|
// Now bind our rendering function so that it will get called
|
||
|
|
ri->renderDelegate.bind( this, &RenderObjectExample::render );
|
||
|
|
|
||
|
|
// Set our RenderInst as a standard object render
|
||
|
|
ri->type = RenderPassManager::RIT_Object;
|
||
|
|
|
||
|
|
// Set our sorting keys to a default value
|
||
|
|
ri->defaultKey = 0;
|
||
|
|
ri->defaultKey2 = 0;
|
||
|
|
|
||
|
|
// Submit our RenderInst to the RenderPassManager
|
||
|
|
state->getRenderPass()->addInst( ri );
|
||
|
|
}
|
||
|
|
|
||
|
|
void RenderObjectExample::render( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat )
|
||
|
|
{
|
||
|
|
if ( overrideMat )
|
||
|
|
return;
|
||
|
|
|
||
|
|
if ( mVertexBuffer.isNull() )
|
||
|
|
return;
|
||
|
|
|
||
|
|
PROFILE_SCOPE(RenderObjectExample_Render);
|
||
|
|
|
||
|
|
// Set up a GFX debug event (this helps with debugging rendering events in external tools)
|
||
|
|
GFXDEBUGEVENT_SCOPE( RenderObjectExample_Render, ColorI::RED );
|
||
|
|
|
||
|
|
// GFXTransformSaver is a handy helper class that restores
|
||
|
|
// the current GFX matrices to their original values when
|
||
|
|
// it goes out of scope at the end of the function
|
||
|
|
GFXTransformSaver saver;
|
||
|
|
|
||
|
|
// Calculate our object to world transform matrix
|
||
|
|
MatrixF objectToWorld = getRenderTransform();
|
||
|
|
objectToWorld.scale( getScale() );
|
||
|
|
|
||
|
|
// Apply our object transform
|
||
|
|
GFX->multWorld( objectToWorld );
|
||
|
|
|
||
|
|
// Deal with reflect pass otherwise
|
||
|
|
// set the normal StateBlock
|
||
|
|
if ( state->isReflectPass() )
|
||
|
|
GFX->setStateBlock( mReflectSB );
|
||
|
|
else
|
||
|
|
GFX->setStateBlock( mNormalSB );
|
||
|
|
|
||
|
|
// Set up the "generic" shaders
|
||
|
|
// These handle rendering on GFX layers that don't support
|
||
|
|
// fixed function. Otherwise they disable shaders.
|
||
|
|
GFX->setupGenericShaders( GFXDevice::GSModColorTexture );
|
||
|
|
|
||
|
|
// Set the vertex buffer
|
||
|
|
GFX->setVertexBuffer( mVertexBuffer );
|
||
|
|
|
||
|
|
// Draw our triangles
|
||
|
|
GFX->drawPrimitive( GFXTriangleList, 0, 12 );
|
||
|
|
}
|