diff options
author | David Walter Seikel | 2016-03-28 22:28:34 +1000 |
---|---|---|
committer | David Walter Seikel | 2016-03-28 22:28:34 +1000 |
commit | 7028cbe09c688437910a25623098762bf0fa592d (patch) | |
tree | 10b5af58277d9880380c2251f109325542c4e6eb /src/others/irrlicht-1.8.1/examples/07.Collision/main.cpp | |
parent | Move lemon to the src/others directory. (diff) | |
download | SledjHamr-7028cbe09c688437910a25623098762bf0fa592d.zip SledjHamr-7028cbe09c688437910a25623098762bf0fa592d.tar.gz SledjHamr-7028cbe09c688437910a25623098762bf0fa592d.tar.bz2 SledjHamr-7028cbe09c688437910a25623098762bf0fa592d.tar.xz |
Move Irrlicht to src/others.
Diffstat (limited to 'src/others/irrlicht-1.8.1/examples/07.Collision/main.cpp')
-rw-r--r-- | src/others/irrlicht-1.8.1/examples/07.Collision/main.cpp | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/src/others/irrlicht-1.8.1/examples/07.Collision/main.cpp b/src/others/irrlicht-1.8.1/examples/07.Collision/main.cpp new file mode 100644 index 0000000..8387c49 --- /dev/null +++ b/src/others/irrlicht-1.8.1/examples/07.Collision/main.cpp | |||
@@ -0,0 +1,330 @@ | |||
1 | /** Example 007 Collision | ||
2 | |||
3 | We will describe 2 methods: Automatic collision detection for moving through | ||
4 | 3d worlds with stair climbing and sliding, and manual scene node and triangle | ||
5 | picking using a ray. In this case, we will use a ray coming out from the | ||
6 | camera, but you can use any ray. | ||
7 | |||
8 | To start, we take the program from tutorial 2, which loads and displays a | ||
9 | quake 3 level. We will use the level to walk in it and to pick triangles from. | ||
10 | In addition we'll place 3 animated models into it for triangle picking. The | ||
11 | following code starts up the engine and loads the level, as per tutorial 2. | ||
12 | */ | ||
13 | #include <irrlicht.h> | ||
14 | #include "driverChoice.h" | ||
15 | |||
16 | using namespace irr; | ||
17 | |||
18 | #ifdef _MSC_VER | ||
19 | #pragma comment(lib, "Irrlicht.lib") | ||
20 | #endif | ||
21 | |||
22 | enum | ||
23 | { | ||
24 | // I use this ISceneNode ID to indicate a scene node that is | ||
25 | // not pickable by getSceneNodeAndCollisionPointFromRay() | ||
26 | ID_IsNotPickable = 0, | ||
27 | |||
28 | // I use this flag in ISceneNode IDs to indicate that the | ||
29 | // scene node can be picked by ray selection. | ||
30 | IDFlag_IsPickable = 1 << 0, | ||
31 | |||
32 | // I use this flag in ISceneNode IDs to indicate that the | ||
33 | // scene node can be highlighted. In this example, the | ||
34 | // homonids can be highlighted, but the level mesh can't. | ||
35 | IDFlag_IsHighlightable = 1 << 1 | ||
36 | }; | ||
37 | |||
38 | int main() | ||
39 | { | ||
40 | // ask user for driver | ||
41 | video::E_DRIVER_TYPE driverType=driverChoiceConsole(); | ||
42 | if (driverType==video::EDT_COUNT) | ||
43 | return 1; | ||
44 | |||
45 | // create device | ||
46 | |||
47 | IrrlichtDevice *device = | ||
48 | createDevice(driverType, core::dimension2d<u32>(640, 480), 16, false); | ||
49 | |||
50 | if (device == 0) | ||
51 | return 1; // could not create selected driver. | ||
52 | |||
53 | video::IVideoDriver* driver = device->getVideoDriver(); | ||
54 | scene::ISceneManager* smgr = device->getSceneManager(); | ||
55 | |||
56 | device->getFileSystem()->addFileArchive("../../media/map-20kdm2.pk3"); | ||
57 | |||
58 | scene::IAnimatedMesh* q3levelmesh = smgr->getMesh("20kdm2.bsp"); | ||
59 | scene::IMeshSceneNode* q3node = 0; | ||
60 | |||
61 | // The Quake mesh is pickable, but doesn't get highlighted. | ||
62 | if (q3levelmesh) | ||
63 | q3node = smgr->addOctreeSceneNode(q3levelmesh->getMesh(0), 0, IDFlag_IsPickable); | ||
64 | |||
65 | /* | ||
66 | So far so good, we've loaded the quake 3 level like in tutorial 2. Now, | ||
67 | here comes something different: We create a triangle selector. A | ||
68 | triangle selector is a class which can fetch the triangles from scene | ||
69 | nodes for doing different things with them, for example collision | ||
70 | detection. There are different triangle selectors, and all can be | ||
71 | created with the ISceneManager. In this example, we create an | ||
72 | OctreeTriangleSelector, which optimizes the triangle output a little | ||
73 | bit by reducing it like an octree. This is very useful for huge meshes | ||
74 | like quake 3 levels. After we created the triangle selector, we attach | ||
75 | it to the q3node. This is not necessary, but in this way, we do not | ||
76 | need to care for the selector, for example dropping it after we do not | ||
77 | need it anymore. | ||
78 | */ | ||
79 | |||
80 | scene::ITriangleSelector* selector = 0; | ||
81 | |||
82 | if (q3node) | ||
83 | { | ||
84 | q3node->setPosition(core::vector3df(-1350,-130,-1400)); | ||
85 | |||
86 | selector = smgr->createOctreeTriangleSelector( | ||
87 | q3node->getMesh(), q3node, 128); | ||
88 | q3node->setTriangleSelector(selector); | ||
89 | // We're not done with this selector yet, so don't drop it. | ||
90 | } | ||
91 | |||
92 | |||
93 | /* | ||
94 | We add a first person shooter camera to the scene so that we can see and | ||
95 | move in the quake 3 level like in tutorial 2. But this, time, we add a | ||
96 | special animator to the camera: A Collision Response animator. This | ||
97 | animator modifies the scene node to which it is attached to in order to | ||
98 | prevent it moving through walls, and to add gravity to it. The | ||
99 | only thing we have to tell the animator is how the world looks like, | ||
100 | how big the scene node is, how much gravity to apply and so on. After the | ||
101 | collision response animator is attached to the camera, we do not have to do | ||
102 | anything more for collision detection, anything is done automatically. | ||
103 | The rest of the collision detection code below is for picking. And please | ||
104 | note another cool feature: The collision response animator can be | ||
105 | attached also to all other scene nodes, not only to cameras. And it can | ||
106 | be mixed with other scene node animators. In this way, collision | ||
107 | detection and response in the Irrlicht engine is really easy. | ||
108 | |||
109 | Now we'll take a closer look on the parameters of | ||
110 | createCollisionResponseAnimator(). The first parameter is the | ||
111 | TriangleSelector, which specifies how the world, against collision | ||
112 | detection is done looks like. The second parameter is the scene node, | ||
113 | which is the object, which is affected by collision detection, in our | ||
114 | case it is the camera. The third defines how big the object is, it is | ||
115 | the radius of an ellipsoid. Try it out and change the radius to smaller | ||
116 | values, the camera will be able to move closer to walls after this. The | ||
117 | next parameter is the direction and speed of gravity. We'll set it to | ||
118 | (0, -10, 0), which approximates to realistic gravity, assuming that our | ||
119 | units are metres. You could set it to (0,0,0) to disable gravity. And the | ||
120 | last value is just a translation: Without this, the ellipsoid with which | ||
121 | collision detection is done would be around the camera, and the camera would | ||
122 | be in the middle of the ellipsoid. But as human beings, we are used to have our | ||
123 | eyes on top of the body, with which we collide with our world, not in | ||
124 | the middle of it. So we place the scene node 50 units over the center | ||
125 | of the ellipsoid with this parameter. And that's it, collision | ||
126 | detection works now. | ||
127 | */ | ||
128 | |||
129 | // Set a jump speed of 3 units per second, which gives a fairly realistic jump | ||
130 | // when used with the gravity of (0, -10, 0) in the collision response animator. | ||
131 | scene::ICameraSceneNode* camera = | ||
132 | smgr->addCameraSceneNodeFPS(0, 100.0f, .3f, ID_IsNotPickable, 0, 0, true, 3.f); | ||
133 | camera->setPosition(core::vector3df(50,50,-60)); | ||
134 | camera->setTarget(core::vector3df(-70,30,-60)); | ||
135 | |||
136 | if (selector) | ||
137 | { | ||
138 | scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator( | ||
139 | selector, camera, core::vector3df(30,50,30), | ||
140 | core::vector3df(0,-10,0), core::vector3df(0,30,0)); | ||
141 | selector->drop(); // As soon as we're done with the selector, drop it. | ||
142 | camera->addAnimator(anim); | ||
143 | anim->drop(); // And likewise, drop the animator when we're done referring to it. | ||
144 | } | ||
145 | |||
146 | // Now I create three animated characters which we can pick, a dynamic light for | ||
147 | // lighting them, and a billboard for drawing where we found an intersection. | ||
148 | |||
149 | // First, let's get rid of the mouse cursor. We'll use a billboard to show | ||
150 | // what we're looking at. | ||
151 | device->getCursorControl()->setVisible(false); | ||
152 | |||
153 | // Add the billboard. | ||
154 | scene::IBillboardSceneNode * bill = smgr->addBillboardSceneNode(); | ||
155 | bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR ); | ||
156 | bill->setMaterialTexture(0, driver->getTexture("../../media/particle.bmp")); | ||
157 | bill->setMaterialFlag(video::EMF_LIGHTING, false); | ||
158 | bill->setMaterialFlag(video::EMF_ZBUFFER, false); | ||
159 | bill->setSize(core::dimension2d<f32>(20.0f, 20.0f)); | ||
160 | bill->setID(ID_IsNotPickable); // This ensures that we don't accidentally ray-pick it | ||
161 | |||
162 | /* Add 3 animated hominids, which we can pick using a ray-triangle intersection. | ||
163 | They all animate quite slowly, to make it easier to see that accurate triangle | ||
164 | selection is being performed. */ | ||
165 | scene::IAnimatedMeshSceneNode* node = 0; | ||
166 | |||
167 | video::SMaterial material; | ||
168 | |||
169 | // Add an MD2 node, which uses vertex-based animation. | ||
170 | node = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/faerie.md2"), | ||
171 | 0, IDFlag_IsPickable | IDFlag_IsHighlightable); | ||
172 | node->setPosition(core::vector3df(-90,-15,-140)); // Put its feet on the floor. | ||
173 | node->setScale(core::vector3df(1.6f)); // Make it appear realistically scaled | ||
174 | node->setMD2Animation(scene::EMAT_POINT); | ||
175 | node->setAnimationSpeed(20.f); | ||
176 | material.setTexture(0, driver->getTexture("../../media/faerie2.bmp")); | ||
177 | material.Lighting = true; | ||
178 | material.NormalizeNormals = true; | ||
179 | node->getMaterial(0) = material; | ||
180 | |||
181 | // Now create a triangle selector for it. The selector will know that it | ||
182 | // is associated with an animated node, and will update itself as necessary. | ||
183 | selector = smgr->createTriangleSelector(node); | ||
184 | node->setTriangleSelector(selector); | ||
185 | selector->drop(); // We're done with this selector, so drop it now. | ||
186 | |||
187 | // And this B3D file uses skinned skeletal animation. | ||
188 | node = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/ninja.b3d"), | ||
189 | 0, IDFlag_IsPickable | IDFlag_IsHighlightable); | ||
190 | node->setScale(core::vector3df(10)); | ||
191 | node->setPosition(core::vector3df(-75,-66,-80)); | ||
192 | node->setRotation(core::vector3df(0,90,0)); | ||
193 | node->setAnimationSpeed(8.f); | ||
194 | node->getMaterial(0).NormalizeNormals = true; | ||
195 | node->getMaterial(0).Lighting = true; | ||
196 | // Just do the same as we did above. | ||
197 | selector = smgr->createTriangleSelector(node); | ||
198 | node->setTriangleSelector(selector); | ||
199 | selector->drop(); | ||
200 | |||
201 | // This X files uses skeletal animation, but without skinning. | ||
202 | node = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/dwarf.x"), | ||
203 | 0, IDFlag_IsPickable | IDFlag_IsHighlightable); | ||
204 | node->setPosition(core::vector3df(-70,-66,-30)); // Put its feet on the floor. | ||
205 | node->setRotation(core::vector3df(0,-90,0)); // And turn it towards the camera. | ||
206 | node->setAnimationSpeed(20.f); | ||
207 | node->getMaterial(0).Lighting = true; | ||
208 | selector = smgr->createTriangleSelector(node); | ||
209 | node->setTriangleSelector(selector); | ||
210 | selector->drop(); | ||
211 | |||
212 | |||
213 | // And this mdl file uses skinned skeletal animation. | ||
214 | node = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/yodan.mdl"), | ||
215 | 0, IDFlag_IsPickable | IDFlag_IsHighlightable); | ||
216 | node->setPosition(core::vector3df(-90,-25,20)); | ||
217 | node->setScale(core::vector3df(0.8f)); | ||
218 | node->getMaterial(0).Lighting = true; | ||
219 | node->setAnimationSpeed(20.f); | ||
220 | |||
221 | // Just do the same as we did above. | ||
222 | selector = smgr->createTriangleSelector(node); | ||
223 | node->setTriangleSelector(selector); | ||
224 | selector->drop(); | ||
225 | |||
226 | material.setTexture(0, 0); | ||
227 | material.Lighting = false; | ||
228 | |||
229 | // Add a light, so that the unselected nodes aren't completely dark. | ||
230 | scene::ILightSceneNode * light = smgr->addLightSceneNode(0, core::vector3df(-60,100,400), | ||
231 | video::SColorf(1.0f,1.0f,1.0f,1.0f), 600.0f); | ||
232 | light->setID(ID_IsNotPickable); // Make it an invalid target for selection. | ||
233 | |||
234 | // Remember which scene node is highlighted | ||
235 | scene::ISceneNode* highlightedSceneNode = 0; | ||
236 | scene::ISceneCollisionManager* collMan = smgr->getSceneCollisionManager(); | ||
237 | int lastFPS = -1; | ||
238 | |||
239 | // draw the selection triangle only as wireframe | ||
240 | material.Wireframe=true; | ||
241 | |||
242 | while(device->run()) | ||
243 | if (device->isWindowActive()) | ||
244 | { | ||
245 | driver->beginScene(true, true, 0); | ||
246 | smgr->drawAll(); | ||
247 | |||
248 | // Unlight any currently highlighted scene node | ||
249 | if (highlightedSceneNode) | ||
250 | { | ||
251 | highlightedSceneNode->setMaterialFlag(video::EMF_LIGHTING, true); | ||
252 | highlightedSceneNode = 0; | ||
253 | } | ||
254 | |||
255 | // All intersections in this example are done with a ray cast out from the camera to | ||
256 | // a distance of 1000. You can easily modify this to check (e.g.) a bullet | ||
257 | // trajectory or a sword's position, or create a ray from a mouse click position using | ||
258 | // ISceneCollisionManager::getRayFromScreenCoordinates() | ||
259 | core::line3d<f32> ray; | ||
260 | ray.start = camera->getPosition(); | ||
261 | ray.end = ray.start + (camera->getTarget() - ray.start).normalize() * 1000.0f; | ||
262 | |||
263 | // Tracks the current intersection point with the level or a mesh | ||
264 | core::vector3df intersection; | ||
265 | // Used to show with triangle has been hit | ||
266 | core::triangle3df hitTriangle; | ||
267 | |||
268 | // This call is all you need to perform ray/triangle collision on every scene node | ||
269 | // that has a triangle selector, including the Quake level mesh. It finds the nearest | ||
270 | // collision point/triangle, and returns the scene node containing that point. | ||
271 | // Irrlicht provides other types of selection, including ray/triangle selector, | ||
272 | // ray/box and ellipse/triangle selector, plus associated helpers. | ||
273 | // See the methods of ISceneCollisionManager | ||
274 | scene::ISceneNode * selectedSceneNode = | ||
275 | collMan->getSceneNodeAndCollisionPointFromRay( | ||
276 | ray, | ||
277 | intersection, // This will be the position of the collision | ||
278 | hitTriangle, // This will be the triangle hit in the collision | ||
279 | IDFlag_IsPickable, // This ensures that only nodes that we have | ||
280 | // set up to be pickable are considered | ||
281 | 0); // Check the entire scene (this is actually the implicit default) | ||
282 | |||
283 | // If the ray hit anything, move the billboard to the collision position | ||
284 | // and draw the triangle that was hit. | ||
285 | if(selectedSceneNode) | ||
286 | { | ||
287 | bill->setPosition(intersection); | ||
288 | |||
289 | // We need to reset the transform before doing our own rendering. | ||
290 | driver->setTransform(video::ETS_WORLD, core::matrix4()); | ||
291 | driver->setMaterial(material); | ||
292 | driver->draw3DTriangle(hitTriangle, video::SColor(0,255,0,0)); | ||
293 | |||
294 | // We can check the flags for the scene node that was hit to see if it should be | ||
295 | // highlighted. The animated nodes can be highlighted, but not the Quake level mesh | ||
296 | if((selectedSceneNode->getID() & IDFlag_IsHighlightable) == IDFlag_IsHighlightable) | ||
297 | { | ||
298 | highlightedSceneNode = selectedSceneNode; | ||
299 | |||
300 | // Highlighting in this case means turning lighting OFF for this node, | ||
301 | // which means that it will be drawn with full brightness. | ||
302 | highlightedSceneNode->setMaterialFlag(video::EMF_LIGHTING, false); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | // We're all done drawing, so end the scene. | ||
307 | driver->endScene(); | ||
308 | |||
309 | int fps = driver->getFPS(); | ||
310 | |||
311 | if (lastFPS != fps) | ||
312 | { | ||
313 | core::stringw str = L"Collision detection example - Irrlicht Engine ["; | ||
314 | str += driver->getName(); | ||
315 | str += "] FPS:"; | ||
316 | str += fps; | ||
317 | |||
318 | device->setWindowCaption(str.c_str()); | ||
319 | lastFPS = fps; | ||
320 | } | ||
321 | } | ||
322 | |||
323 | device->drop(); | ||
324 | |||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | /* | ||
329 | **/ | ||
330 | |||