//----------------------------------------------------------------------------- // 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() { docsURL; // 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(); // 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 ); }