1 //-----------------------------------------------------------------------------
2 // Copyright (c) 2012 GarageGames, LLC
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to
6 // deal in the Software without restriction, including without limitation the
7 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 // sell copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 //-----------------------------------------------------------------------------
23 #include "platform/platform.h"
24 #include "renderInstance/renderMeshMgr.h"
26 #include "console/consoleTypes.h"
27 #include "gfx/gfxTransformSaver.h"
28 #include "gfx/gfxPrimitiveBuffer.h"
29 #include "materials/sceneData.h"
30 #include "materials/processedMaterial.h"
31 #include "materials/materialManager.h"
32 #include "scene/sceneRenderState.h"
33 #include "gfx/gfxDebugEvent.h"
34 #include "math/util/matrixSet.h"
37 IMPLEMENT_CONOBJECT(RenderMeshMgr
);
39 ConsoleDocClass( RenderMeshMgr
,
40 "@brief A render bin for mesh rendering.\n\n"
41 "This is the primary render bin in Torque which does most of the "
42 "work of rendering DTS shapes and arbitrary mesh geometry. It knows "
43 "how to render mesh instances using materials and supports hardware mesh "
45 "@ingroup RenderBin\n" );
48 RenderMeshMgr::RenderMeshMgr()
49 : RenderBinManager(RenderPassManager::RIT_Mesh
, 1.0f
, 1.0f
)
53 RenderMeshMgr::RenderMeshMgr(RenderInstType riType
, F32 renderOrder
, F32 processAddOrder
)
54 : RenderBinManager(riType
, renderOrder
, processAddOrder
)
58 void RenderMeshMgr::init()
63 d
.cullMode
= GFXCullCCW
;
64 d
.samplersDefined
= true;
65 d
.samplers
[0] = GFXSamplerStateDesc::getWrapLinear();
67 mNormalSB
= GFX
->createStateBlock(d
);
69 d
.cullMode
= GFXCullCW
;
70 mReflectSB
= GFX
->createStateBlock(d
);
73 void RenderMeshMgr::initPersistFields()
75 Parent::initPersistFields();
78 //-----------------------------------------------------------------------------
80 //-----------------------------------------------------------------------------
81 void RenderMeshMgr::addElement( RenderInst
*inst
)
83 // If this instance is translucent handle it in RenderTranslucentMgr
84 if (inst
->translucentSort
)
87 AssertFatal( inst
->defaultKey
!= 0, "RenderMeshMgr::addElement() - Got null sort key... did you forget to set it?" );
89 internalAddElement(inst
);
92 //-----------------------------------------------------------------------------
94 //-----------------------------------------------------------------------------
95 void RenderMeshMgr::render(SceneRenderState
* state
)
97 PROFILE_SCOPE(RenderMeshMgr_render
);
99 // Early out if nothing to draw.
100 if(!mElementList
.size())
104 GFXDEBUGEVENT_SCOPE( RenderMeshMgr_Render
, ColorI::GREEN
);
106 // Automagically save & restore our viewport and transforms.
107 GFXTransformSaver saver
;
109 // Restore transforms
110 MatrixSet
&matrixSet
= getRenderPass()->getMatrixSet();
111 matrixSet
.restoreSceneViewProjection();
114 GFXTextureObject
*lastLM
= NULL
;
115 GFXCubemap
*lastCubemap
= NULL
;
116 GFXTextureObject
*lastReflectTex
= NULL
;
117 GFXTextureObject
*lastMiscTex
= NULL
;
118 GFXTextureObject
*lastAccuTex
= NULL
;
121 sgData
.init( state
);
123 U32 binSize
= mElementList
.size();
125 for( U32 j
=0; j
<binSize
; )
127 MeshRenderInst
*ri
= static_cast<MeshRenderInst
*>(mElementList
[j
].inst
);
129 setupSGData( ri
, sgData
);
130 BaseMatInstance
*mat
= ri
->matInst
;
132 // If we have an override delegate then give it a
133 // chance to swap the material with another.
134 if ( mMatOverrideDelegate
)
136 mat
= mMatOverrideDelegate( mat
);
145 mat
= MATMGR
->getWarningMatInstance();
147 // Check if bin is disabled in advanced lighting.
148 // Allow forward rendering pass on custom materials.
150 if ( ( MATMGR
->getPrePassEnabled() && mBasicOnly
&& !mat
->isCustomMaterial() ) )
157 lastMiscTex
= sgData
.miscTex
;
160 while( mat
&& mat
->setupPass(state
, sgData
) )
162 for( a
=j
; a
<binSize
; a
++ )
164 MeshRenderInst
*passRI
= static_cast<MeshRenderInst
*>(mElementList
[a
].inst
);
166 // Check to see if we need to break this batch.
167 if ( newPassNeeded( ri
, passRI
) ||
168 lastMiscTex
!= passRI
->miscTex
)
174 matrixSet
.setWorld(*passRI
->objectToWorld
);
175 matrixSet
.setView(*passRI
->worldToCamera
);
176 matrixSet
.setProjection(*passRI
->projection
);
177 mat
->setTransforms(matrixSet
, state
);
179 // Setup HW skinning transforms if applicable
180 if (mat
->usesHardwareSkinning())
182 mat
->setNodeTransforms(passRI
->mNodeTransforms
, passRI
->mNodeTransformCount
);
185 setupSGData( passRI
, sgData
);
186 mat
->setSceneInfo( state
, sgData
);
188 // If we're instanced then don't render yet.
189 if ( mat
->isInstanced() )
191 // Let the material increment the instance buffer, but
192 // break the batch if it runs out of room for more.
193 if ( !mat
->stepInstance() )
202 // TODO: This could proably be done in a cleaner way.
204 // This section of code is dangerous, it overwrites the
205 // lightmap values in sgData. This could be a problem when multiple
206 // render instances use the same multi-pass material. When
207 // the first pass is done, setupPass() is called again on
208 // the material, but the lightmap data has been changed in
209 // sgData to the lightmaps in the last renderInstance rendered.
211 // This section sets the lightmap data for the current batch.
212 // For the first iteration, it sets the same lightmap data,
213 // however the redundancy will be caught by GFXDevice and not
214 // actually sent to the card. This is done for simplicity given
215 // the possible condition mentioned above. Better to set always
216 // than to get bogged down into special case detection.
217 //-------------------------------------
220 // set the lightmaps if different
221 if( passRI
->lightmap
&& passRI
->lightmap
!= lastLM
)
223 sgData
.lightmap
= passRI
->lightmap
;
224 lastLM
= passRI
->lightmap
;
228 // set the cubemap if different.
229 if ( passRI
->cubemap
!= lastCubemap
)
231 sgData
.cubemap
= passRI
->cubemap
;
232 lastCubemap
= passRI
->cubemap
;
236 if ( passRI
->reflectTex
!= lastReflectTex
)
238 sgData
.reflectTex
= passRI
->reflectTex
;
239 lastReflectTex
= passRI
->reflectTex
;
243 // Update accumulation texture if it changed.
244 // Note: accumulation texture can be NULL, and must be updated.
245 if ( passRI
->accuTex
!= lastAccuTex
)
247 sgData
.accuTex
= passRI
->accuTex
;
248 lastAccuTex
= passRI
->accuTex
;
253 mat
->setTextureStages( state
, sgData
);
255 // Setup the vertex and index buffers.
256 mat
->setBuffers( passRI
->vertBuff
, passRI
->primBuff
);
258 // Render this sucker.
260 GFX
->drawPrimitive( *passRI
->prim
);
262 GFX
->drawPrimitive( passRI
->primBuffIndex
);
265 // Draw the instanced batch.
266 if ( mat
->isInstanced() )
268 // Sets the buffers including the instancing stream.
269 mat
->setBuffers( ri
->vertBuff
, ri
->primBuff
);
271 // Render the instanced stream.
273 GFX
->drawPrimitive( *ri
->prim
);
275 GFX
->drawPrimitive( ri
->primBuffIndex
);
281 // force increment if none happened, otherwise go to end of batch
282 j
= ( j
== matListEnd
) ? j
+1 : matListEnd
;