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