renderMeshExample.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  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:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  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
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "T3D/examples/renderMeshExample.h"
  24. #include "math/mathIO.h"
  25. #include "scene/sceneRenderState.h"
  26. #include "console/consoleTypes.h"
  27. #include "core/stream/bitStream.h"
  28. #include "materials/materialManager.h"
  29. #include "materials/baseMatInstance.h"
  30. #include "renderInstance/renderPassManager.h"
  31. #include "lighting/lightQuery.h"
  32. #include "console/engineAPI.h"
  33. IMPLEMENT_CO_NETOBJECT_V1(RenderMeshExample);
  34. ConsoleDocClass( RenderMeshExample,
  35. "@brief An example scene object which renders a mesh.\n\n"
  36. "This class implements a basic SceneObject that can exist in the world at a "
  37. "3D position and render itself. There are several valid ways to render an "
  38. "object in Torque. This class implements the preferred rendering method which "
  39. "is to submit a MeshRenderInst along with a Material, vertex buffer, "
  40. "primitive buffer, and transform and allow the RenderMeshMgr handle the "
  41. "actual setup and rendering for you.\n\n"
  42. "See the C++ code for implementation details.\n\n"
  43. "@ingroup Examples\n" );
  44. //-----------------------------------------------------------------------------
  45. // Object setup and teardown
  46. //-----------------------------------------------------------------------------
  47. RenderMeshExample::RenderMeshExample()
  48. {
  49. // Flag this object so that it will always
  50. // be sent across the network to clients
  51. mNetFlags.set( Ghostable | ScopeAlways );
  52. // Set it as a "static" object that casts shadows
  53. mTypeMask |= StaticObjectType | StaticShapeObjectType;
  54. // Make sure we the Material instance to NULL
  55. // so we don't try to access it incorrectly
  56. mMaterialInst = NULL;
  57. initMaterialAsset(Material);
  58. }
  59. RenderMeshExample::~RenderMeshExample()
  60. {
  61. if ( mMaterialInst )
  62. SAFE_DELETE( mMaterialInst );
  63. }
  64. //-----------------------------------------------------------------------------
  65. // Object Editing
  66. //-----------------------------------------------------------------------------
  67. void RenderMeshExample::initPersistFields()
  68. {
  69. addGroup( "Rendering" );
  70. scriptBindMaterialAsset(Material, RenderMeshExample, "The material used to render the mesh.");
  71. endGroup( "Rendering" );
  72. // SceneObject already handles exposing the transform
  73. Parent::initPersistFields();
  74. }
  75. void RenderMeshExample::inspectPostApply()
  76. {
  77. Parent::inspectPostApply();
  78. // Flag the network mask to send the updates
  79. // to the client object
  80. setMaskBits( UpdateMask );
  81. }
  82. bool RenderMeshExample::onAdd()
  83. {
  84. if ( !Parent::onAdd() )
  85. return false;
  86. // Set up a 1x1x1 bounding box
  87. mObjBox.set( Point3F( -0.5f, -0.5f, -0.5f ),
  88. Point3F( 0.5f, 0.5f, 0.5f ) );
  89. resetWorldBox();
  90. // Add this object to the scene
  91. addToScene();
  92. // Refresh this object's material (if any)
  93. updateMaterial();
  94. return true;
  95. }
  96. void RenderMeshExample::onRemove()
  97. {
  98. // Remove this object from the scene
  99. removeFromScene();
  100. Parent::onRemove();
  101. }
  102. void RenderMeshExample::setTransform(const MatrixF & mat)
  103. {
  104. // Let SceneObject handle all of the matrix manipulation
  105. Parent::setTransform( mat );
  106. // Dirty our network mask so that the new transform gets
  107. // transmitted to the client object
  108. setMaskBits( TransformMask );
  109. }
  110. U32 RenderMeshExample::packUpdate( NetConnection *conn, U32 mask, BitStream *stream )
  111. {
  112. // Allow the Parent to get a crack at writing its info
  113. U32 retMask = Parent::packUpdate( conn, mask, stream );
  114. // Write our transform information
  115. if ( stream->writeFlag( mask & TransformMask ) )
  116. {
  117. mathWrite(*stream, getTransform());
  118. mathWrite(*stream, getScale());
  119. }
  120. // Write out any of the updated editable properties
  121. if (stream->writeFlag(mask & UpdateMask))
  122. {
  123. packMaterialAsset(conn, Material);
  124. }
  125. return retMask;
  126. }
  127. void RenderMeshExample::unpackUpdate(NetConnection *conn, BitStream *stream)
  128. {
  129. // Let the Parent read any info it sent
  130. Parent::unpackUpdate(conn, stream);
  131. if ( stream->readFlag() ) // TransformMask
  132. {
  133. mathRead(*stream, &mObjToWorld);
  134. mathRead(*stream, &mObjScale);
  135. setTransform( mObjToWorld );
  136. }
  137. if ( stream->readFlag() ) // UpdateMask
  138. {
  139. unpackMaterialAsset(conn, Material);
  140. if ( isProperlyAdded() )
  141. updateMaterial();
  142. }
  143. }
  144. //-----------------------------------------------------------------------------
  145. // Object Rendering
  146. //-----------------------------------------------------------------------------
  147. void RenderMeshExample::createGeometry()
  148. {
  149. static const Point3F cubePoints[8] =
  150. {
  151. Point3F( 1, -1, -1), Point3F( 1, -1, 1), Point3F( 1, 1, -1), Point3F( 1, 1, 1),
  152. Point3F(-1, -1, -1), Point3F(-1, 1, -1), Point3F(-1, -1, 1), Point3F(-1, 1, 1)
  153. };
  154. static const Point3F cubeNormals[6] =
  155. {
  156. Point3F( 1, 0, 0), Point3F(-1, 0, 0), Point3F( 0, 1, 0),
  157. Point3F( 0, -1, 0), Point3F( 0, 0, 1), Point3F( 0, 0, -1)
  158. };
  159. static const Point2F cubeTexCoords[4] =
  160. {
  161. Point2F( 0, 0), Point2F( 0, -1),
  162. Point2F( 1, 0), Point2F( 1, -1)
  163. };
  164. static const U32 cubeFaces[36][3] =
  165. {
  166. { 3, 0, 3 }, { 0, 0, 0 }, { 1, 0, 1 },
  167. { 2, 0, 2 }, { 0, 0, 0 }, { 3, 0, 3 },
  168. { 7, 1, 1 }, { 4, 1, 2 }, { 5, 1, 0 },
  169. { 6, 1, 3 }, { 4, 1, 2 }, { 7, 1, 1 },
  170. { 3, 2, 1 }, { 5, 2, 2 }, { 2, 2, 0 },
  171. { 7, 2, 3 }, { 5, 2, 2 }, { 3, 2, 1 },
  172. { 1, 3, 3 }, { 4, 3, 0 }, { 6, 3, 1 },
  173. { 0, 3, 2 }, { 4, 3, 0 }, { 1, 3, 3 },
  174. { 3, 4, 3 }, { 6, 4, 0 }, { 7, 4, 1 },
  175. { 1, 4, 2 }, { 6, 4, 0 }, { 3, 4, 3 },
  176. { 2, 5, 1 }, { 4, 5, 2 }, { 0, 5, 0 },
  177. { 5, 5, 3 }, { 4, 5, 2 }, { 2, 5, 1 }
  178. };
  179. // Fill the vertex buffer
  180. VertexType *pVert = NULL;
  181. mVertexBuffer.set( GFX, 36, GFXBufferTypeStatic );
  182. pVert = mVertexBuffer.lock();
  183. Point3F halfSize = getObjBox().getExtents() * 0.5f;
  184. for (U32 i = 0; i < 36; i++)
  185. {
  186. const U32& vdx = cubeFaces[i][0];
  187. const U32& ndx = cubeFaces[i][1];
  188. const U32& tdx = cubeFaces[i][2];
  189. pVert[i].point = cubePoints[vdx] * halfSize;
  190. pVert[i].normal = cubeNormals[ndx];
  191. pVert[i].texCoord = cubeTexCoords[tdx];
  192. }
  193. mVertexBuffer.unlock();
  194. // Fill the primitive buffer
  195. U16 *pIdx = NULL;
  196. mPrimitiveBuffer.set( GFX, 36, 12, GFXBufferTypeStatic );
  197. mPrimitiveBuffer.lock(&pIdx);
  198. for (U16 i = 0; i < 36; i++)
  199. pIdx[i] = i;
  200. mPrimitiveBuffer.unlock();
  201. }
  202. void RenderMeshExample::updateMaterial()
  203. {
  204. if (mMaterialAsset.notNull())
  205. {
  206. if (mMaterialInst && String(mMaterialAsset->getMaterialDefinitionName()).equal(mMaterialInst->getMaterial()->getName(), String::NoCase))
  207. return;
  208. SAFE_DELETE(mMaterialInst);
  209. mMaterialInst = MATMGR->createMatInstance(mMaterialAsset->getMaterialDefinitionName(), getGFXVertexFormat< VertexType >());
  210. if (!mMaterialInst)
  211. Con::errorf("RenderMeshExample::updateMaterial - no Material called '%s'", mMaterialAsset->getMaterialDefinitionName());
  212. }
  213. }
  214. void RenderMeshExample::prepRenderImage( SceneRenderState *state )
  215. {
  216. // Do a little prep work if needed
  217. if ( mVertexBuffer.isNull() )
  218. createGeometry();
  219. // If we have no material then skip out.
  220. if ( !mMaterialInst || !state)
  221. return;
  222. // If we don't have a material instance after the override then
  223. // we can skip rendering all together.
  224. BaseMatInstance *matInst = state->getOverrideMaterial( mMaterialInst );
  225. if ( !matInst )
  226. return;
  227. // Get a handy pointer to our RenderPassmanager
  228. RenderPassManager *renderPass = state->getRenderPass();
  229. // Allocate an MeshRenderInst so that we can submit it to the RenderPassManager
  230. MeshRenderInst *ri = renderPass->allocInst<MeshRenderInst>();
  231. // Set our RenderInst as a standard mesh render
  232. ri->type = RenderPassManager::RIT_Mesh;
  233. //If our material has transparency set on this will redirect it to proper render bin
  234. if ( matInst->getMaterial()->isTranslucent() )
  235. {
  236. ri->type = RenderPassManager::RIT_Translucent;
  237. ri->translucentSort = true;
  238. }
  239. // Calculate our sorting point
  240. if ( state )
  241. {
  242. // Calculate our sort point manually.
  243. const Box3F& rBox = getRenderWorldBox();
  244. ri->sortDistSq = rBox.getSqDistanceToPoint( state->getCameraPosition() );
  245. }
  246. else
  247. ri->sortDistSq = 0.0f;
  248. // Set up our transforms
  249. MatrixF objectToWorld = getRenderTransform();
  250. objectToWorld.scale( getScale() );
  251. ri->objectToWorld = renderPass->allocUniqueXform( objectToWorld );
  252. ri->worldToCamera = renderPass->allocSharedXform(RenderPassManager::View);
  253. ri->projection = renderPass->allocSharedXform(RenderPassManager::Projection);
  254. // If our material needs lights then fill the RIs
  255. // light vector with the best lights.
  256. if ( matInst->isForwardLit() )
  257. {
  258. LightQuery query;
  259. query.init( getWorldSphere() );
  260. query.getLights( ri->lights, 8 );
  261. }
  262. // Make sure we have an up-to-date backbuffer in case
  263. // our Material would like to make use of it
  264. // NOTICE: SFXBB is removed and refraction is disabled!
  265. //ri->backBuffTex = GFX->getSfxBackBuffer();
  266. // Set our Material
  267. ri->matInst = matInst;
  268. // Set up our vertex buffer and primitive buffer
  269. ri->vertBuff = &mVertexBuffer;
  270. ri->primBuff = &mPrimitiveBuffer;
  271. ri->prim = renderPass->allocPrim();
  272. ri->prim->type = GFXTriangleList;
  273. ri->prim->minIndex = 0;
  274. ri->prim->startIndex = 0;
  275. ri->prim->numPrimitives = 12;
  276. ri->prim->startVertex = 0;
  277. ri->prim->numVertices = 36;
  278. // We sort by the material then vertex buffer
  279. ri->defaultKey = matInst->getStateHint();
  280. ri->defaultKey2 = (uintptr_t)ri->vertBuff; // Not 64bit safe!
  281. // Submit our RenderInst to the RenderPassManager
  282. state->getRenderPass()->addInst( ri );
  283. }
  284. DefineEngineMethod( RenderMeshExample, postApply, void, (),,
  285. "A utility method for forcing a network update.\n")
  286. {
  287. object->inspectPostApply();
  288. }