main.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /** Example 003 Custom SceneNode
  2. This tutorial is more advanced than the previous ones.
  3. If you are currently just playing around with the Irrlicht
  4. engine, you may want to look at other examples first.
  5. This tutorials shows how to create a custom scene node and
  6. how to use it in the engine. A custom scene node is needed
  7. if you want to implement a render technique the Irrlicht
  8. Engine currently does not support. For example, you can write
  9. an indoor portal based renderer or an advanced terrain scene
  10. node with it. By creating custom scene nodes, you can
  11. easily extend the Irrlicht Engine and adapt it to your needs.
  12. I will keep the tutorial simple: Keep everything very short
  13. and everything in one .cpp file. This is the style which
  14. will also be used in most of the following tutorials.
  15. To start, I include the header files, use the irr namespace,
  16. and tell the linker to link with the .lib file.
  17. */
  18. #include <irrlicht.h>
  19. #include "driverChoice.h"
  20. using namespace irr;
  21. #ifdef _MSC_VER
  22. #pragma comment(lib, "Irrlicht.lib")
  23. #endif
  24. /*
  25. Here comes the more sophisticated part of this tutorial:
  26. The class of our very own custom scene node. To keep it simple,
  27. our scene node will not be an indoor portal renderer nor a terrain
  28. scene node, but a simple tetrahedron, a 3D object consisting of 4
  29. connected vertices, which only draws itself and does nothing more.
  30. Note that this scenario does not require a custom scene node in Irrlicht.
  31. Instead one would create a mesh from the geometry and pass it to a
  32. irr::scene::IMeshSceneNode. This example just illustrates creation of a custom
  33. scene node in a simple setting.
  34. To allow our scene node to be inserted into the Irrlicht
  35. Engine scene, the class we create needs to be derived from the
  36. irr::scene::ISceneNode class and has to override some methods.
  37. */
  38. class CSampleSceneNode : public scene::ISceneNode
  39. {
  40. /*
  41. First, we declare some member variables:
  42. The bounding box, 4 vertices, and the material of the tetrahedron.
  43. */
  44. core::aabbox3d<f32> Box;
  45. video::S3DVertex Vertices[4];
  46. video::SMaterial Material;
  47. public:
  48. /*
  49. The parameters of the constructor specify the parent of the scene node,
  50. a pointer to the scene manager, and an id of the scene node.
  51. In the constructor we call the parent class' constructor,
  52. set some properties of the material, and create the 4 vertices of
  53. the tetrahedron.
  54. */
  55. CSampleSceneNode(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id)
  56. : scene::ISceneNode(parent, mgr, id)
  57. {
  58. Material.Wireframe = false;
  59. Material.Lighting = false;
  60. Vertices[0] = video::S3DVertex(0,0,10, 1,1,0,
  61. video::SColor(255,0,255,255), 0, 1);
  62. Vertices[1] = video::S3DVertex(10,0,-10, 1,0,0,
  63. video::SColor(255,255,0,255), 1, 1);
  64. Vertices[2] = video::S3DVertex(0,20,0, 0,1,1,
  65. video::SColor(255,255,255,0), 1, 0);
  66. Vertices[3] = video::S3DVertex(-10,0,-10, 0,0,1,
  67. video::SColor(255,0,255,0), 0, 0);
  68. /*
  69. The Irrlicht Engine needs to know the bounding box of a scene node.
  70. It will use it for automatic culling and other things. Hence, we
  71. need to create a bounding box from the 4 vertices we use.
  72. If you do not want the engine to use the box for automatic culling,
  73. and/or don't want to create the box, you could also call
  74. irr::scene::ISceneNode::setAutomaticCulling() with irr::scene::EAC_OFF.
  75. */
  76. Box.reset(Vertices[0].Pos);
  77. for (s32 i=1; i<4; ++i)
  78. Box.addInternalPoint(Vertices[i].Pos);
  79. }
  80. /*
  81. Before it is drawn, the irr::scene::ISceneNode::OnRegisterSceneNode()
  82. method of every scene node in the scene is called by the scene manager.
  83. If the scene node wishes to draw itself, it may register itself in the
  84. scene manager to be drawn. This is necessary to tell the scene manager
  85. when it should call irr::scene::ISceneNode::render(). For
  86. example, normal scene nodes render their content one after another,
  87. while stencil buffer shadows would like to be drawn after all other
  88. scene nodes. And camera or light scene nodes need to be rendered before
  89. all other scene nodes (if at all). So here we simply register the
  90. scene node to render normally. If we would like to let it be rendered
  91. like cameras or light, we would have to call
  92. SceneManager->registerNodeForRendering(this, SNRT_LIGHT_AND_CAMERA);
  93. After this, we call the actual irr::scene::ISceneNode::OnRegisterSceneNode()
  94. method of the base class, which lets all the child scene nodes of this node
  95. register themselves.
  96. */
  97. virtual void OnRegisterSceneNode()
  98. {
  99. if (IsVisible)
  100. SceneManager->registerNodeForRendering(this);
  101. ISceneNode::OnRegisterSceneNode();
  102. }
  103. /*
  104. In the render() method most of the interesting stuff happens: The
  105. Scene node renders itself. We override this method and draw the
  106. tetrahedron.
  107. */
  108. virtual void render()
  109. {
  110. /* Indices into the 'Vertices' array. A triangle needs 3 vertices
  111. so you have to pass the 3 corresponding indices for each triangle to
  112. tell which of the vertices should be used for it. */
  113. u16 indices[] = { 0,2,3, 2,1,3, 1,0,3, 2,0,1 };
  114. video::IVideoDriver* driver = SceneManager->getVideoDriver();
  115. driver->setMaterial(Material);
  116. driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
  117. driver->drawVertexPrimitiveList(&Vertices[0], 4, &indices[0], 4, video::EVT_STANDARD, scene::EPT_TRIANGLES, video::EIT_16BIT);
  118. }
  119. /*
  120. And finally we create three small additional methods.
  121. irr::scene::ISceneNode::getBoundingBox() returns the bounding box of
  122. this scene node, irr::scene::ISceneNode::getMaterialCount() returns the
  123. amount of materials in this scene node (our tetrahedron only has one
  124. material), and irr::scene::ISceneNode::getMaterial() returns the
  125. material at an index. Because we have only one material, we can
  126. return that and assume that no one ever calls getMaterial() with an index
  127. greater than 0.
  128. */
  129. virtual const core::aabbox3d<f32>& getBoundingBox() const
  130. {
  131. return Box;
  132. }
  133. virtual u32 getMaterialCount() const
  134. {
  135. return 1;
  136. }
  137. virtual video::SMaterial& getMaterial(u32 i)
  138. {
  139. return Material;
  140. }
  141. };
  142. /*
  143. That's it. The Scene node is done. Now we start the engine,
  144. create the scene node and a camera, and look at the result.
  145. */
  146. int main()
  147. {
  148. // ask user for driver
  149. video::E_DRIVER_TYPE driverType=driverChoiceConsole();
  150. if (driverType==video::EDT_COUNT)
  151. return 1;
  152. // create device
  153. IrrlichtDevice *device = createDevice(driverType,
  154. core::dimension2d<u32>(640, 480), 16, false);
  155. if (device == 0)
  156. return 1; // could not create selected driver.
  157. // set window caption, get some pointers, create a camera
  158. device->setWindowCaption(L"Custom Scene Node - Irrlicht Engine Demo");
  159. video::IVideoDriver* driver = device->getVideoDriver();
  160. scene::ISceneManager* smgr = device->getSceneManager();
  161. smgr->addCameraSceneNode(0, core::vector3df(0,-40,0), core::vector3df(0,0,0));
  162. /*
  163. Create our scene node. I don't check the result of calling new, as it
  164. should throw an exception rather than returning 0 on failure. Because
  165. the new node will create itself with a reference count of 1, and then
  166. will have another reference added by its parent scene node when it is
  167. added to the scene, I need to drop my reference to it. Best practice is
  168. to drop it only *after* I have finished using it, regardless of what
  169. the reference count of the object is after creation.
  170. */
  171. CSampleSceneNode *myNode =
  172. new CSampleSceneNode(smgr->getRootSceneNode(), smgr, 666);
  173. /*
  174. To animate something in this boring scene consisting only of one
  175. tetrahedron, and to show that you now can use your scene node like any
  176. other scene node in the engine, we add an animator to the scene node,
  177. which rotates the node a little bit.
  178. irr::scene::ISceneManager::createRotationAnimator() could return 0, so
  179. should be checked.
  180. */
  181. scene::ISceneNodeAnimator* anim =
  182. smgr->createRotationAnimator(core::vector3df(0.8f, 0, 0.8f));
  183. if(anim)
  184. {
  185. myNode->addAnimator(anim);
  186. /*
  187. I'm done referring to anim, so must
  188. irr::IReferenceCounted::drop() this reference now because it
  189. was produced by a createFoo() function. As I shouldn't refer to
  190. it again, ensure that I can't by setting to 0.
  191. */
  192. anim->drop();
  193. anim = 0;
  194. }
  195. /*
  196. I'm done with my CSampleSceneNode object, and so must drop my reference.
  197. This won't delete the object, yet, because it is still attached to the
  198. scene graph, which prevents the deletion until the graph is deleted or the
  199. custom scene node is removed from it.
  200. */
  201. myNode->drop();
  202. myNode = 0; // As I shouldn't refer to it again, ensure that I can't
  203. /*
  204. Now draw everything and finish.
  205. */
  206. u32 frames=0;
  207. while(device->run())
  208. {
  209. driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0,100,100,100));
  210. smgr->drawAll();
  211. driver->endScene();
  212. if (++frames==100) // don't update more often, setWindowCaption can be expensive
  213. {
  214. core::stringw str = L"Irrlicht Engine [";
  215. str += driver->getName();
  216. str += L"] FPS: ";
  217. str += (s32)driver->getFPS();
  218. device->setWindowCaption(str.c_str());
  219. frames=0;
  220. }
  221. }
  222. device->drop();
  223. return 0;
  224. }
  225. /*
  226. That's it. Compile and play around with the program.
  227. **/