diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/irrlicht-1.8/source/Irrlicht/CSceneManager.cpp | 2516 |
1 files changed, 2516 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CSceneManager.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CSceneManager.cpp new file mode 100644 index 0000000..6ec6e88 --- /dev/null +++ b/libraries/irrlicht-1.8/source/Irrlicht/CSceneManager.cpp | |||
@@ -0,0 +1,2516 @@ | |||
1 | // Copyright (C) 2002-2012 Nikolaus Gebhardt | ||
2 | // This file is part of the "Irrlicht Engine". | ||
3 | // For conditions of distribution and use, see copyright notice in irrlicht.h | ||
4 | |||
5 | #include "IrrCompileConfig.h" | ||
6 | #include "CSceneManager.h" | ||
7 | #include "IVideoDriver.h" | ||
8 | #include "IFileSystem.h" | ||
9 | #include "SAnimatedMesh.h" | ||
10 | #include "CMeshCache.h" | ||
11 | #include "IXMLWriter.h" | ||
12 | #include "ISceneUserDataSerializer.h" | ||
13 | #include "IGUIEnvironment.h" | ||
14 | #include "IMaterialRenderer.h" | ||
15 | #include "IReadFile.h" | ||
16 | #include "IWriteFile.h" | ||
17 | #include "ISceneLoader.h" | ||
18 | |||
19 | #include "os.h" | ||
20 | |||
21 | // We need this include for the case of skinned mesh support without | ||
22 | // any such loader | ||
23 | #ifdef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ | ||
24 | #include "CSkinnedMesh.h" | ||
25 | #endif | ||
26 | |||
27 | #ifdef _IRR_COMPILE_WITH_IRR_MESH_LOADER_ | ||
28 | #include "CIrrMeshFileLoader.h" | ||
29 | #endif | ||
30 | |||
31 | #ifdef _IRR_COMPILE_WITH_BSP_LOADER_ | ||
32 | #include "CBSPMeshFileLoader.h" | ||
33 | #endif | ||
34 | |||
35 | #ifdef _IRR_COMPILE_WITH_MD2_LOADER_ | ||
36 | #include "CMD2MeshFileLoader.h" | ||
37 | #endif | ||
38 | |||
39 | #ifdef _IRR_COMPILE_WITH_HALFLIFE_LOADER_ | ||
40 | #include "CAnimatedMeshHalfLife.h" | ||
41 | #endif | ||
42 | |||
43 | #ifdef _IRR_COMPILE_WITH_MS3D_LOADER_ | ||
44 | #include "CMS3DMeshFileLoader.h" | ||
45 | #endif | ||
46 | |||
47 | #ifdef _IRR_COMPILE_WITH_3DS_LOADER_ | ||
48 | #include "C3DSMeshFileLoader.h" | ||
49 | #endif | ||
50 | |||
51 | #ifdef _IRR_COMPILE_WITH_X_LOADER_ | ||
52 | #include "CXMeshFileLoader.h" | ||
53 | #endif | ||
54 | |||
55 | #ifdef _IRR_COMPILE_WITH_OCT_LOADER_ | ||
56 | #include "COCTLoader.h" | ||
57 | #endif | ||
58 | |||
59 | #ifdef _IRR_COMPILE_WITH_CSM_LOADER_ | ||
60 | #include "CCSMLoader.h" | ||
61 | #endif | ||
62 | |||
63 | #ifdef _IRR_COMPILE_WITH_LMTS_LOADER_ | ||
64 | #include "CLMTSMeshFileLoader.h" | ||
65 | #endif | ||
66 | |||
67 | #ifdef _IRR_COMPILE_WITH_MY3D_LOADER_ | ||
68 | #include "CMY3DMeshFileLoader.h" | ||
69 | #endif | ||
70 | |||
71 | #ifdef _IRR_COMPILE_WITH_COLLADA_LOADER_ | ||
72 | #include "CColladaFileLoader.h" | ||
73 | #endif | ||
74 | |||
75 | #ifdef _IRR_COMPILE_WITH_DMF_LOADER_ | ||
76 | #include "CDMFLoader.h" | ||
77 | #endif | ||
78 | |||
79 | #ifdef _IRR_COMPILE_WITH_OGRE_LOADER_ | ||
80 | #include "COgreMeshFileLoader.h" | ||
81 | #endif | ||
82 | |||
83 | #ifdef _IRR_COMPILE_WITH_OBJ_LOADER_ | ||
84 | #include "COBJMeshFileLoader.h" | ||
85 | #endif | ||
86 | |||
87 | #ifdef _IRR_COMPILE_WITH_MD3_LOADER_ | ||
88 | #include "CMD3MeshFileLoader.h" | ||
89 | #endif | ||
90 | |||
91 | #ifdef _IRR_COMPILE_WITH_B3D_LOADER_ | ||
92 | #include "CB3DMeshFileLoader.h" | ||
93 | #endif | ||
94 | |||
95 | #ifdef _IRR_COMPILE_WITH_LWO_LOADER_ | ||
96 | #include "CLWOMeshFileLoader.h" | ||
97 | #endif | ||
98 | |||
99 | #ifdef _IRR_COMPILE_WITH_STL_LOADER_ | ||
100 | #include "CSTLMeshFileLoader.h" | ||
101 | #endif | ||
102 | |||
103 | #ifdef _IRR_COMPILE_WITH_PLY_LOADER_ | ||
104 | #include "CPLYMeshFileLoader.h" | ||
105 | #endif | ||
106 | |||
107 | #ifdef _IRR_COMPILE_WITH_SMF_LOADER_ | ||
108 | #include "CSMFMeshFileLoader.h" | ||
109 | #endif | ||
110 | |||
111 | #ifdef _IRR_COMPILE_WITH_IRR_SCENE_LOADER_ | ||
112 | #include "CSceneLoaderIrr.h" | ||
113 | #endif | ||
114 | |||
115 | #ifdef _IRR_COMPILE_WITH_COLLADA_WRITER_ | ||
116 | #include "CColladaMeshWriter.h" | ||
117 | #endif | ||
118 | |||
119 | #ifdef _IRR_COMPILE_WITH_IRR_WRITER_ | ||
120 | #include "CIrrMeshWriter.h" | ||
121 | #endif | ||
122 | |||
123 | #ifdef _IRR_COMPILE_WITH_STL_WRITER_ | ||
124 | #include "CSTLMeshWriter.h" | ||
125 | #endif | ||
126 | |||
127 | #ifdef _IRR_COMPILE_WITH_OBJ_WRITER_ | ||
128 | #include "COBJMeshWriter.h" | ||
129 | #endif | ||
130 | |||
131 | #ifdef _IRR_COMPILE_WITH_PLY_WRITER_ | ||
132 | #include "CPLYMeshWriter.h" | ||
133 | #endif | ||
134 | |||
135 | #include "CCubeSceneNode.h" | ||
136 | #include "CSphereSceneNode.h" | ||
137 | #include "CAnimatedMeshSceneNode.h" | ||
138 | #include "COctreeSceneNode.h" | ||
139 | #include "CCameraSceneNode.h" | ||
140 | #include "CLightSceneNode.h" | ||
141 | #include "CBillboardSceneNode.h" | ||
142 | #include "CMeshSceneNode.h" | ||
143 | #include "CSkyBoxSceneNode.h" | ||
144 | #include "CSkyDomeSceneNode.h" | ||
145 | #include "CParticleSystemSceneNode.h" | ||
146 | #include "CDummyTransformationSceneNode.h" | ||
147 | #include "CWaterSurfaceSceneNode.h" | ||
148 | #include "CTerrainSceneNode.h" | ||
149 | #include "CEmptySceneNode.h" | ||
150 | #include "CTextSceneNode.h" | ||
151 | #include "CQuake3ShaderSceneNode.h" | ||
152 | #include "CVolumeLightSceneNode.h" | ||
153 | |||
154 | #include "CDefaultSceneNodeFactory.h" | ||
155 | |||
156 | #include "CSceneCollisionManager.h" | ||
157 | #include "CTriangleSelector.h" | ||
158 | #include "COctreeTriangleSelector.h" | ||
159 | #include "CTriangleBBSelector.h" | ||
160 | #include "CMetaTriangleSelector.h" | ||
161 | #include "CTerrainTriangleSelector.h" | ||
162 | |||
163 | #include "CSceneNodeAnimatorRotation.h" | ||
164 | #include "CSceneNodeAnimatorFlyCircle.h" | ||
165 | #include "CSceneNodeAnimatorFlyStraight.h" | ||
166 | #include "CSceneNodeAnimatorTexture.h" | ||
167 | #include "CSceneNodeAnimatorCollisionResponse.h" | ||
168 | #include "CSceneNodeAnimatorDelete.h" | ||
169 | #include "CSceneNodeAnimatorFollowSpline.h" | ||
170 | #include "CSceneNodeAnimatorCameraFPS.h" | ||
171 | #include "CSceneNodeAnimatorCameraMaya.h" | ||
172 | #include "CDefaultSceneNodeAnimatorFactory.h" | ||
173 | |||
174 | #include "CGeometryCreator.h" | ||
175 | |||
176 | //! Enable debug features | ||
177 | #define SCENEMANAGER_DEBUG | ||
178 | |||
179 | namespace irr | ||
180 | { | ||
181 | namespace scene | ||
182 | { | ||
183 | |||
184 | //! constructor | ||
185 | CSceneManager::CSceneManager(video::IVideoDriver* driver, io::IFileSystem* fs, | ||
186 | gui::ICursorControl* cursorControl, IMeshCache* cache, | ||
187 | gui::IGUIEnvironment* gui) | ||
188 | : ISceneNode(0, 0), Driver(driver), FileSystem(fs), GUIEnvironment(gui), | ||
189 | CursorControl(cursorControl), CollisionManager(0), | ||
190 | ActiveCamera(0), ShadowColor(150,0,0,0), AmbientLight(0,0,0,0), | ||
191 | MeshCache(cache), CurrentRendertime(ESNRP_NONE), LightManager(0), | ||
192 | IRR_XML_FORMAT_SCENE(L"irr_scene"), IRR_XML_FORMAT_NODE(L"node"), IRR_XML_FORMAT_NODE_ATTR_TYPE(L"type") | ||
193 | { | ||
194 | #ifdef _DEBUG | ||
195 | ISceneManager::setDebugName("CSceneManager ISceneManager"); | ||
196 | ISceneNode::setDebugName("CSceneManager ISceneNode"); | ||
197 | #endif | ||
198 | |||
199 | // root node's scene manager | ||
200 | SceneManager = this; | ||
201 | |||
202 | // set scene parameters | ||
203 | Parameters.setAttribute( DEBUG_NORMAL_LENGTH, 1.f ); | ||
204 | Parameters.setAttribute( DEBUG_NORMAL_COLOR, video::SColor(255, 34, 221, 221)); | ||
205 | |||
206 | if (Driver) | ||
207 | Driver->grab(); | ||
208 | |||
209 | if (FileSystem) | ||
210 | FileSystem->grab(); | ||
211 | |||
212 | if (CursorControl) | ||
213 | CursorControl->grab(); | ||
214 | |||
215 | if (GUIEnvironment) | ||
216 | GUIEnvironment->grab(); | ||
217 | |||
218 | // create mesh cache if not there already | ||
219 | if (!MeshCache) | ||
220 | MeshCache = new CMeshCache(); | ||
221 | else | ||
222 | MeshCache->grab(); | ||
223 | |||
224 | // create collision manager | ||
225 | CollisionManager = new CSceneCollisionManager(this, Driver); | ||
226 | |||
227 | // create geometry creator | ||
228 | GeometryCreator = new CGeometryCreator(); | ||
229 | |||
230 | // add file format loaders. add the least commonly used ones first, | ||
231 | // as these are checked last | ||
232 | |||
233 | // TODO: now that we have multiple scene managers, these should be | ||
234 | // shallow copies from the previous manager if there is one. | ||
235 | |||
236 | #ifdef _IRR_COMPILE_WITH_STL_LOADER_ | ||
237 | MeshLoaderList.push_back(new CSTLMeshFileLoader()); | ||
238 | #endif | ||
239 | #ifdef _IRR_COMPILE_WITH_PLY_LOADER_ | ||
240 | MeshLoaderList.push_back(new CPLYMeshFileLoader(this)); | ||
241 | #endif | ||
242 | #ifdef _IRR_COMPILE_WITH_SMF_LOADER_ | ||
243 | MeshLoaderList.push_back(new CSMFMeshFileLoader(Driver)); | ||
244 | #endif | ||
245 | #ifdef _IRR_COMPILE_WITH_OCT_LOADER_ | ||
246 | MeshLoaderList.push_back(new COCTLoader(this, FileSystem)); | ||
247 | #endif | ||
248 | #ifdef _IRR_COMPILE_WITH_CSM_LOADER_ | ||
249 | MeshLoaderList.push_back(new CCSMLoader(this, FileSystem)); | ||
250 | #endif | ||
251 | #ifdef _IRR_COMPILE_WITH_LMTS_LOADER_ | ||
252 | MeshLoaderList.push_back(new CLMTSMeshFileLoader(FileSystem, Driver, &Parameters)); | ||
253 | #endif | ||
254 | #ifdef _IRR_COMPILE_WITH_MY3D_LOADER_ | ||
255 | MeshLoaderList.push_back(new CMY3DMeshFileLoader(this, FileSystem)); | ||
256 | #endif | ||
257 | #ifdef _IRR_COMPILE_WITH_DMF_LOADER_ | ||
258 | MeshLoaderList.push_back(new CDMFLoader(this, FileSystem)); | ||
259 | #endif | ||
260 | #ifdef _IRR_COMPILE_WITH_OGRE_LOADER_ | ||
261 | MeshLoaderList.push_back(new COgreMeshFileLoader(FileSystem, Driver)); | ||
262 | #endif | ||
263 | #ifdef _IRR_COMPILE_WITH_HALFLIFE_LOADER_ | ||
264 | MeshLoaderList.push_back(new CHalflifeMDLMeshFileLoader( this )); | ||
265 | #endif | ||
266 | #ifdef _IRR_COMPILE_WITH_MD3_LOADER_ | ||
267 | MeshLoaderList.push_back(new CMD3MeshFileLoader( this)); | ||
268 | #endif | ||
269 | #ifdef _IRR_COMPILE_WITH_LWO_LOADER_ | ||
270 | MeshLoaderList.push_back(new CLWOMeshFileLoader(this, FileSystem)); | ||
271 | #endif | ||
272 | #ifdef _IRR_COMPILE_WITH_MD2_LOADER_ | ||
273 | MeshLoaderList.push_back(new CMD2MeshFileLoader()); | ||
274 | #endif | ||
275 | #ifdef _IRR_COMPILE_WITH_IRR_MESH_LOADER_ | ||
276 | MeshLoaderList.push_back(new CIrrMeshFileLoader(this, FileSystem)); | ||
277 | #endif | ||
278 | #ifdef _IRR_COMPILE_WITH_BSP_LOADER_ | ||
279 | MeshLoaderList.push_back(new CBSPMeshFileLoader(this, FileSystem)); | ||
280 | #endif | ||
281 | #ifdef _IRR_COMPILE_WITH_COLLADA_LOADER_ | ||
282 | MeshLoaderList.push_back(new CColladaFileLoader(this, FileSystem)); | ||
283 | #endif | ||
284 | #ifdef _IRR_COMPILE_WITH_3DS_LOADER_ | ||
285 | MeshLoaderList.push_back(new C3DSMeshFileLoader(this, FileSystem)); | ||
286 | #endif | ||
287 | #ifdef _IRR_COMPILE_WITH_X_LOADER_ | ||
288 | MeshLoaderList.push_back(new CXMeshFileLoader(this, FileSystem)); | ||
289 | #endif | ||
290 | #ifdef _IRR_COMPILE_WITH_MS3D_LOADER_ | ||
291 | MeshLoaderList.push_back(new CMS3DMeshFileLoader(Driver)); | ||
292 | #endif | ||
293 | #ifdef _IRR_COMPILE_WITH_OBJ_LOADER_ | ||
294 | MeshLoaderList.push_back(new COBJMeshFileLoader(this, FileSystem)); | ||
295 | #endif | ||
296 | #ifdef _IRR_COMPILE_WITH_B3D_LOADER_ | ||
297 | MeshLoaderList.push_back(new CB3DMeshFileLoader(this)); | ||
298 | #endif | ||
299 | |||
300 | // scene loaders | ||
301 | #ifdef _IRR_COMPILE_WITH_IRR_SCENE_LOADER_ | ||
302 | SceneLoaderList.push_back(new CSceneLoaderIrr(this, FileSystem)); | ||
303 | #endif | ||
304 | |||
305 | |||
306 | // factories | ||
307 | ISceneNodeFactory* factory = new CDefaultSceneNodeFactory(this); | ||
308 | registerSceneNodeFactory(factory); | ||
309 | factory->drop(); | ||
310 | |||
311 | ISceneNodeAnimatorFactory* animatorFactory = new CDefaultSceneNodeAnimatorFactory(this, CursorControl); | ||
312 | registerSceneNodeAnimatorFactory(animatorFactory); | ||
313 | animatorFactory->drop(); | ||
314 | } | ||
315 | |||
316 | |||
317 | //! destructor | ||
318 | CSceneManager::~CSceneManager() | ||
319 | { | ||
320 | clearDeletionList(); | ||
321 | |||
322 | //! force to remove hardwareTextures from the driver | ||
323 | //! because Scenes may hold internally data bounded to sceneNodes | ||
324 | //! which may be destroyed twice | ||
325 | if (Driver) | ||
326 | Driver->removeAllHardwareBuffers(); | ||
327 | |||
328 | if (FileSystem) | ||
329 | FileSystem->drop(); | ||
330 | |||
331 | if (CursorControl) | ||
332 | CursorControl->drop(); | ||
333 | |||
334 | if (CollisionManager) | ||
335 | CollisionManager->drop(); | ||
336 | |||
337 | if (GeometryCreator) | ||
338 | GeometryCreator->drop(); | ||
339 | |||
340 | if (GUIEnvironment) | ||
341 | GUIEnvironment->drop(); | ||
342 | |||
343 | u32 i; | ||
344 | for (i=0; i<MeshLoaderList.size(); ++i) | ||
345 | MeshLoaderList[i]->drop(); | ||
346 | |||
347 | for (i=0; i<SceneLoaderList.size(); ++i) | ||
348 | SceneLoaderList[i]->drop(); | ||
349 | |||
350 | if (ActiveCamera) | ||
351 | ActiveCamera->drop(); | ||
352 | ActiveCamera = 0; | ||
353 | |||
354 | if (MeshCache) | ||
355 | MeshCache->drop(); | ||
356 | |||
357 | for (i=0; i<SceneNodeFactoryList.size(); ++i) | ||
358 | SceneNodeFactoryList[i]->drop(); | ||
359 | |||
360 | for (i=0; i<SceneNodeAnimatorFactoryList.size(); ++i) | ||
361 | SceneNodeAnimatorFactoryList[i]->drop(); | ||
362 | |||
363 | if (LightManager) | ||
364 | LightManager->drop(); | ||
365 | |||
366 | // remove all nodes and animators before dropping the driver | ||
367 | // as render targets may be destroyed twice | ||
368 | |||
369 | removeAll(); | ||
370 | removeAnimators(); | ||
371 | |||
372 | if (Driver) | ||
373 | Driver->drop(); | ||
374 | } | ||
375 | |||
376 | |||
377 | //! gets an animateable mesh. loads it if needed. returned pointer must not be dropped. | ||
378 | IAnimatedMesh* CSceneManager::getMesh(const io::path& filename) | ||
379 | { | ||
380 | IAnimatedMesh* msh = MeshCache->getMeshByName(filename); | ||
381 | if (msh) | ||
382 | return msh; | ||
383 | |||
384 | io::IReadFile* file = FileSystem->createAndOpenFile(filename); | ||
385 | if (!file) | ||
386 | { | ||
387 | os::Printer::log("Could not load mesh, because file could not be opened: ", filename, ELL_ERROR); | ||
388 | return 0; | ||
389 | } | ||
390 | |||
391 | // iterate the list in reverse order so user-added loaders can override the built-in ones | ||
392 | s32 count = MeshLoaderList.size(); | ||
393 | for (s32 i=count-1; i>=0; --i) | ||
394 | { | ||
395 | if (MeshLoaderList[i]->isALoadableFileExtension(filename)) | ||
396 | { | ||
397 | // reset file to avoid side effects of previous calls to createMesh | ||
398 | file->seek(0); | ||
399 | msh = MeshLoaderList[i]->createMesh(file); | ||
400 | if (msh) | ||
401 | { | ||
402 | MeshCache->addMesh(filename, msh); | ||
403 | msh->drop(); | ||
404 | break; | ||
405 | } | ||
406 | } | ||
407 | } | ||
408 | |||
409 | file->drop(); | ||
410 | |||
411 | if (!msh) | ||
412 | os::Printer::log("Could not load mesh, file format seems to be unsupported", filename, ELL_ERROR); | ||
413 | else | ||
414 | os::Printer::log("Loaded mesh", filename, ELL_INFORMATION); | ||
415 | |||
416 | return msh; | ||
417 | } | ||
418 | |||
419 | |||
420 | //! gets an animateable mesh. loads it if needed. returned pointer must not be dropped. | ||
421 | IAnimatedMesh* CSceneManager::getMesh(io::IReadFile* file) | ||
422 | { | ||
423 | if (!file) | ||
424 | return 0; | ||
425 | |||
426 | io::path name = file->getFileName(); | ||
427 | IAnimatedMesh* msh = MeshCache->getMeshByName(file->getFileName()); | ||
428 | if (msh) | ||
429 | return msh; | ||
430 | |||
431 | // iterate the list in reverse order so user-added loaders can override the built-in ones | ||
432 | s32 count = MeshLoaderList.size(); | ||
433 | for (s32 i=count-1; i>=0; --i) | ||
434 | { | ||
435 | if (MeshLoaderList[i]->isALoadableFileExtension(name)) | ||
436 | { | ||
437 | // reset file to avoid side effects of previous calls to createMesh | ||
438 | file->seek(0); | ||
439 | msh = MeshLoaderList[i]->createMesh(file); | ||
440 | if (msh) | ||
441 | { | ||
442 | MeshCache->addMesh(file->getFileName(), msh); | ||
443 | msh->drop(); | ||
444 | break; | ||
445 | } | ||
446 | } | ||
447 | } | ||
448 | |||
449 | if (!msh) | ||
450 | os::Printer::log("Could not load mesh, file format seems to be unsupported", file->getFileName(), ELL_ERROR); | ||
451 | else | ||
452 | os::Printer::log("Loaded mesh", file->getFileName(), ELL_INFORMATION); | ||
453 | |||
454 | return msh; | ||
455 | } | ||
456 | |||
457 | |||
458 | //! returns the video driver | ||
459 | video::IVideoDriver* CSceneManager::getVideoDriver() | ||
460 | { | ||
461 | return Driver; | ||
462 | } | ||
463 | |||
464 | |||
465 | //! returns the GUI Environment | ||
466 | gui::IGUIEnvironment* CSceneManager::getGUIEnvironment() | ||
467 | { | ||
468 | return GUIEnvironment; | ||
469 | } | ||
470 | |||
471 | //! Get the active FileSystem | ||
472 | /** \return Pointer to the FileSystem | ||
473 | This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ | ||
474 | io::IFileSystem* CSceneManager::getFileSystem() | ||
475 | { | ||
476 | return FileSystem; | ||
477 | } | ||
478 | |||
479 | //! Adds a text scene node, which is able to display | ||
480 | //! 2d text at a position in three dimensional space | ||
481 | ITextSceneNode* CSceneManager::addTextSceneNode(gui::IGUIFont* font, | ||
482 | const wchar_t* text, video::SColor color, ISceneNode* parent, | ||
483 | const core::vector3df& position, s32 id) | ||
484 | { | ||
485 | if (!font) | ||
486 | return 0; | ||
487 | |||
488 | if (!parent) | ||
489 | parent = this; | ||
490 | |||
491 | ITextSceneNode* t = new CTextSceneNode(parent, this, id, font, | ||
492 | getSceneCollisionManager(), position, text, color); | ||
493 | t->drop(); | ||
494 | |||
495 | return t; | ||
496 | } | ||
497 | |||
498 | |||
499 | //! Adds a text scene node, which uses billboards | ||
500 | IBillboardTextSceneNode* CSceneManager::addBillboardTextSceneNode(gui::IGUIFont* font, | ||
501 | const wchar_t* text, ISceneNode* parent, | ||
502 | const core::dimension2d<f32>& size, | ||
503 | const core::vector3df& position, s32 id, | ||
504 | video::SColor colorTop, video::SColor colorBottom) | ||
505 | { | ||
506 | if (!font && GUIEnvironment) | ||
507 | font = GUIEnvironment->getBuiltInFont(); | ||
508 | |||
509 | if (!font) | ||
510 | return 0; | ||
511 | |||
512 | if (!parent) | ||
513 | parent = this; | ||
514 | |||
515 | IBillboardTextSceneNode* node = new CBillboardTextSceneNode(parent, this, id, font, text, position, size, | ||
516 | colorTop, colorBottom); | ||
517 | node->drop(); | ||
518 | |||
519 | return node; | ||
520 | |||
521 | } | ||
522 | |||
523 | |||
524 | //! Adds a scene node, which can render a quake3 shader | ||
525 | IMeshSceneNode* CSceneManager::addQuake3SceneNode(const IMeshBuffer* meshBuffer, | ||
526 | const quake3::IShader * shader, | ||
527 | ISceneNode* parent, s32 id ) | ||
528 | { | ||
529 | #ifdef _IRR_COMPILE_WITH_BSP_LOADER_ | ||
530 | if (!shader) | ||
531 | return 0; | ||
532 | |||
533 | if (!parent) | ||
534 | parent = this; | ||
535 | |||
536 | CQuake3ShaderSceneNode* node = new CQuake3ShaderSceneNode( parent, | ||
537 | this, id, FileSystem, | ||
538 | meshBuffer, shader ); | ||
539 | node->drop(); | ||
540 | |||
541 | return node; | ||
542 | #else | ||
543 | return 0; | ||
544 | #endif | ||
545 | } | ||
546 | |||
547 | |||
548 | //! adds Volume Lighting Scene Node. | ||
549 | //! the returned pointer must not be dropped. | ||
550 | IVolumeLightSceneNode* CSceneManager::addVolumeLightSceneNode( | ||
551 | ISceneNode* parent, s32 id, | ||
552 | const u32 subdivU, const u32 subdivV, | ||
553 | const video::SColor foot, const video::SColor tail, | ||
554 | const core::vector3df& position, const core::vector3df& rotation, const core::vector3df& scale) | ||
555 | { | ||
556 | if (!parent) | ||
557 | parent = this; | ||
558 | |||
559 | IVolumeLightSceneNode* node = new CVolumeLightSceneNode(parent, this, id, subdivU, subdivV, foot, tail, position, rotation, scale); | ||
560 | node->drop(); | ||
561 | |||
562 | return node; | ||
563 | } | ||
564 | |||
565 | |||
566 | //! adds a test scene node for test purposes to the scene. It is a simple cube of (1,1,1) size. | ||
567 | //! the returned pointer must not be dropped. | ||
568 | IMeshSceneNode* CSceneManager::addCubeSceneNode(f32 size, ISceneNode* parent, | ||
569 | s32 id, const core::vector3df& position, | ||
570 | const core::vector3df& rotation, const core::vector3df& scale) | ||
571 | { | ||
572 | if (!parent) | ||
573 | parent = this; | ||
574 | |||
575 | IMeshSceneNode* node = new CCubeSceneNode(size, parent, this, id, position, rotation, scale); | ||
576 | node->drop(); | ||
577 | |||
578 | return node; | ||
579 | } | ||
580 | |||
581 | |||
582 | //! Adds a sphere scene node for test purposes to the scene. | ||
583 | IMeshSceneNode* CSceneManager::addSphereSceneNode(f32 radius, s32 polyCount, | ||
584 | ISceneNode* parent, s32 id, const core::vector3df& position, | ||
585 | const core::vector3df& rotation, const core::vector3df& scale) | ||
586 | { | ||
587 | if (!parent) | ||
588 | parent = this; | ||
589 | |||
590 | IMeshSceneNode* node = new CSphereSceneNode(radius, polyCount, polyCount, parent, this, id, position, rotation, scale); | ||
591 | node->drop(); | ||
592 | |||
593 | return node; | ||
594 | } | ||
595 | |||
596 | |||
597 | //! adds a scene node for rendering a static mesh | ||
598 | //! the returned pointer must not be dropped. | ||
599 | IMeshSceneNode* CSceneManager::addMeshSceneNode(IMesh* mesh, ISceneNode* parent, s32 id, | ||
600 | const core::vector3df& position, const core::vector3df& rotation, | ||
601 | const core::vector3df& scale, bool alsoAddIfMeshPointerZero) | ||
602 | { | ||
603 | if (!alsoAddIfMeshPointerZero && !mesh) | ||
604 | return 0; | ||
605 | |||
606 | if (!parent) | ||
607 | parent = this; | ||
608 | |||
609 | IMeshSceneNode* node = new CMeshSceneNode(mesh, parent, this, id, position, rotation, scale); | ||
610 | node->drop(); | ||
611 | |||
612 | return node; | ||
613 | } | ||
614 | |||
615 | |||
616 | //! Adds a scene node for rendering a animated water surface mesh. | ||
617 | ISceneNode* CSceneManager::addWaterSurfaceSceneNode(IMesh* mesh, f32 waveHeight, f32 waveSpeed, f32 waveLength, | ||
618 | ISceneNode* parent, s32 id, const core::vector3df& position, | ||
619 | const core::vector3df& rotation, const core::vector3df& scale) | ||
620 | { | ||
621 | if (!parent) | ||
622 | parent = this; | ||
623 | |||
624 | ISceneNode* node = new CWaterSurfaceSceneNode(waveHeight, waveSpeed, waveLength, | ||
625 | mesh, parent, this, id, position, rotation, scale); | ||
626 | |||
627 | node->drop(); | ||
628 | |||
629 | return node; | ||
630 | } | ||
631 | |||
632 | |||
633 | //! adds a scene node for rendering an animated mesh model | ||
634 | IAnimatedMeshSceneNode* CSceneManager::addAnimatedMeshSceneNode(IAnimatedMesh* mesh, ISceneNode* parent, s32 id, | ||
635 | const core::vector3df& position, const core::vector3df& rotation, | ||
636 | const core::vector3df& scale, bool alsoAddIfMeshPointerZero) | ||
637 | { | ||
638 | if (!alsoAddIfMeshPointerZero && !mesh) | ||
639 | return 0; | ||
640 | |||
641 | if (!parent) | ||
642 | parent = this; | ||
643 | |||
644 | IAnimatedMeshSceneNode* node = | ||
645 | new CAnimatedMeshSceneNode(mesh, parent, this, id, position, rotation, scale); | ||
646 | node->drop(); | ||
647 | |||
648 | return node; | ||
649 | } | ||
650 | |||
651 | |||
652 | //! Adds a scene node for rendering using a octree to the scene graph. This a good method for rendering | ||
653 | //! scenes with lots of geometry. The Octree is built on the fly from the mesh, much | ||
654 | //! faster then a bsp tree. | ||
655 | IMeshSceneNode* CSceneManager::addOctreeSceneNode(IAnimatedMesh* mesh, ISceneNode* parent, | ||
656 | s32 id, s32 minimalPolysPerNode, bool alsoAddIfMeshPointerZero) | ||
657 | { | ||
658 | if (!alsoAddIfMeshPointerZero && (!mesh || !mesh->getFrameCount())) | ||
659 | return 0; | ||
660 | |||
661 | return addOctreeSceneNode(mesh ? mesh->getMesh(0) : 0, | ||
662 | parent, id, minimalPolysPerNode, | ||
663 | alsoAddIfMeshPointerZero); | ||
664 | } | ||
665 | |||
666 | |||
667 | //! Adds a scene node for rendering using a octree. This a good method for rendering | ||
668 | //! scenes with lots of geometry. The Octree is built on the fly from the mesh, much | ||
669 | //! faster then a bsp tree. | ||
670 | IMeshSceneNode* CSceneManager::addOctreeSceneNode(IMesh* mesh, ISceneNode* parent, | ||
671 | s32 id, s32 minimalPolysPerNode, bool alsoAddIfMeshPointerZero) | ||
672 | { | ||
673 | if (!alsoAddIfMeshPointerZero && !mesh) | ||
674 | return 0; | ||
675 | |||
676 | if (!parent) | ||
677 | parent = this; | ||
678 | |||
679 | COctreeSceneNode* node = new COctreeSceneNode(parent, this, id, minimalPolysPerNode); | ||
680 | |||
681 | if (node) | ||
682 | { | ||
683 | node->setMesh(mesh); | ||
684 | node->drop(); | ||
685 | } | ||
686 | |||
687 | return node; | ||
688 | } | ||
689 | |||
690 | |||
691 | //! Adds a camera scene node to the tree and sets it as active camera. | ||
692 | //! \param position: Position of the space relative to its parent where the camera will be placed. | ||
693 | //! \param lookat: Position where the camera will look at. Also known as target. | ||
694 | //! \param parent: Parent scene node of the camera. Can be null. If the parent moves, | ||
695 | //! the camera will move too. | ||
696 | //! \return Returns pointer to interface to camera | ||
697 | ICameraSceneNode* CSceneManager::addCameraSceneNode(ISceneNode* parent, | ||
698 | const core::vector3df& position, const core::vector3df& lookat, s32 id, | ||
699 | bool makeActive) | ||
700 | { | ||
701 | if (!parent) | ||
702 | parent = this; | ||
703 | |||
704 | ICameraSceneNode* node = new CCameraSceneNode(parent, this, id, position, lookat); | ||
705 | |||
706 | if (makeActive) | ||
707 | setActiveCamera(node); | ||
708 | node->drop(); | ||
709 | |||
710 | return node; | ||
711 | } | ||
712 | |||
713 | |||
714 | //! Adds a camera scene node which is able to be controlled with the mouse similar | ||
715 | //! to in the 3D Software Maya by Alias Wavefront. | ||
716 | //! The returned pointer must not be dropped. | ||
717 | ICameraSceneNode* CSceneManager::addCameraSceneNodeMaya(ISceneNode* parent, | ||
718 | f32 rotateSpeed, f32 zoomSpeed, f32 translationSpeed, s32 id, f32 distance, | ||
719 | bool makeActive) | ||
720 | { | ||
721 | ICameraSceneNode* node = addCameraSceneNode(parent, core::vector3df(), | ||
722 | core::vector3df(0,0,100), id, makeActive); | ||
723 | if (node) | ||
724 | { | ||
725 | ISceneNodeAnimator* anm = new CSceneNodeAnimatorCameraMaya(CursorControl, | ||
726 | rotateSpeed, zoomSpeed, translationSpeed, distance); | ||
727 | |||
728 | node->addAnimator(anm); | ||
729 | anm->drop(); | ||
730 | } | ||
731 | |||
732 | return node; | ||
733 | } | ||
734 | |||
735 | |||
736 | //! Adds a camera scene node which is able to be controlled with the mouse and keys | ||
737 | //! like in most first person shooters (FPS): | ||
738 | ICameraSceneNode* CSceneManager::addCameraSceneNodeFPS(ISceneNode* parent, | ||
739 | f32 rotateSpeed, f32 moveSpeed, s32 id, SKeyMap* keyMapArray, | ||
740 | s32 keyMapSize, bool noVerticalMovement, f32 jumpSpeed, | ||
741 | bool invertMouseY, bool makeActive) | ||
742 | { | ||
743 | ICameraSceneNode* node = addCameraSceneNode(parent, core::vector3df(), | ||
744 | core::vector3df(0,0,100), id, makeActive); | ||
745 | if (node) | ||
746 | { | ||
747 | ISceneNodeAnimator* anm = new CSceneNodeAnimatorCameraFPS(CursorControl, | ||
748 | rotateSpeed, moveSpeed, jumpSpeed, | ||
749 | keyMapArray, keyMapSize, noVerticalMovement, invertMouseY); | ||
750 | |||
751 | // Bind the node's rotation to its target. This is consistent with 1.4.2 and below. | ||
752 | node->bindTargetAndRotation(true); | ||
753 | node->addAnimator(anm); | ||
754 | anm->drop(); | ||
755 | } | ||
756 | |||
757 | return node; | ||
758 | } | ||
759 | |||
760 | |||
761 | //! Adds a dynamic light scene node. The light will cast dynamic light on all | ||
762 | //! other scene nodes in the scene, which have the material flag video::MTF_LIGHTING | ||
763 | //! turned on. (This is the default setting in most scene nodes). | ||
764 | ILightSceneNode* CSceneManager::addLightSceneNode(ISceneNode* parent, | ||
765 | const core::vector3df& position, video::SColorf color, f32 range, s32 id) | ||
766 | { | ||
767 | if (!parent) | ||
768 | parent = this; | ||
769 | |||
770 | ILightSceneNode* node = new CLightSceneNode(parent, this, id, position, color, range); | ||
771 | node->drop(); | ||
772 | |||
773 | return node; | ||
774 | } | ||
775 | |||
776 | |||
777 | //! Adds a billboard scene node to the scene. A billboard is like a 3d sprite: A 2d element, | ||
778 | //! which always looks to the camera. It is usually used for things like explosions, fire, | ||
779 | //! lensflares and things like that. | ||
780 | IBillboardSceneNode* CSceneManager::addBillboardSceneNode(ISceneNode* parent, | ||
781 | const core::dimension2d<f32>& size, const core::vector3df& position, s32 id, | ||
782 | video::SColor colorTop, video::SColor colorBottom | ||
783 | ) | ||
784 | { | ||
785 | if (!parent) | ||
786 | parent = this; | ||
787 | |||
788 | IBillboardSceneNode* node = new CBillboardSceneNode(parent, this, id, position, size, | ||
789 | colorTop, colorBottom); | ||
790 | node->drop(); | ||
791 | |||
792 | return node; | ||
793 | } | ||
794 | |||
795 | |||
796 | //! Adds a skybox scene node. A skybox is a big cube with 6 textures on it and | ||
797 | //! is drawn around the camera position. | ||
798 | ISceneNode* CSceneManager::addSkyBoxSceneNode(video::ITexture* top, video::ITexture* bottom, | ||
799 | video::ITexture* left, video::ITexture* right, video::ITexture* front, | ||
800 | video::ITexture* back, ISceneNode* parent, s32 id) | ||
801 | { | ||
802 | if (!parent) | ||
803 | parent = this; | ||
804 | |||
805 | ISceneNode* node = new CSkyBoxSceneNode(top, bottom, left, right, | ||
806 | front, back, parent, this, id); | ||
807 | |||
808 | node->drop(); | ||
809 | return node; | ||
810 | } | ||
811 | |||
812 | |||
813 | //! Adds a skydome scene node. A skydome is a large (half-) sphere with a | ||
814 | //! panoramic texture on it and is drawn around the camera position. | ||
815 | ISceneNode* CSceneManager::addSkyDomeSceneNode(video::ITexture* texture, | ||
816 | u32 horiRes, u32 vertRes, f32 texturePercentage,f32 spherePercentage, f32 radius, | ||
817 | ISceneNode* parent, s32 id) | ||
818 | { | ||
819 | if (!parent) | ||
820 | parent = this; | ||
821 | |||
822 | ISceneNode* node = new CSkyDomeSceneNode(texture, horiRes, vertRes, | ||
823 | texturePercentage, spherePercentage, radius, parent, this, id); | ||
824 | |||
825 | node->drop(); | ||
826 | return node; | ||
827 | } | ||
828 | |||
829 | |||
830 | //! Adds a particle system scene node. | ||
831 | IParticleSystemSceneNode* CSceneManager::addParticleSystemSceneNode( | ||
832 | bool withDefaultEmitter, ISceneNode* parent, s32 id, | ||
833 | const core::vector3df& position, const core::vector3df& rotation, | ||
834 | const core::vector3df& scale) | ||
835 | { | ||
836 | if (!parent) | ||
837 | parent = this; | ||
838 | |||
839 | IParticleSystemSceneNode* node = new CParticleSystemSceneNode(withDefaultEmitter, | ||
840 | parent, this, id, position, rotation, scale); | ||
841 | node->drop(); | ||
842 | |||
843 | return node; | ||
844 | } | ||
845 | |||
846 | |||
847 | //! Adds a terrain scene node to the scene graph. | ||
848 | ITerrainSceneNode* CSceneManager::addTerrainSceneNode( | ||
849 | const io::path& heightMapFileName, | ||
850 | ISceneNode* parent, s32 id, | ||
851 | const core::vector3df& position, | ||
852 | const core::vector3df& rotation, | ||
853 | const core::vector3df& scale, | ||
854 | video::SColor vertexColor, | ||
855 | s32 maxLOD, E_TERRAIN_PATCH_SIZE patchSize, s32 smoothFactor, | ||
856 | bool addAlsoIfHeightmapEmpty) | ||
857 | { | ||
858 | io::IReadFile* file = FileSystem->createAndOpenFile(heightMapFileName); | ||
859 | |||
860 | if (!file && !addAlsoIfHeightmapEmpty) | ||
861 | { | ||
862 | os::Printer::log("Could not load terrain, because file could not be opened.", | ||
863 | heightMapFileName, ELL_ERROR); | ||
864 | return 0; | ||
865 | } | ||
866 | |||
867 | ITerrainSceneNode* terrain = addTerrainSceneNode(file, parent, id, | ||
868 | position, rotation, scale, vertexColor, maxLOD, patchSize, | ||
869 | smoothFactor, addAlsoIfHeightmapEmpty); | ||
870 | |||
871 | if (file) | ||
872 | file->drop(); | ||
873 | |||
874 | return terrain; | ||
875 | } | ||
876 | |||
877 | //! Adds a terrain scene node to the scene graph. | ||
878 | ITerrainSceneNode* CSceneManager::addTerrainSceneNode( | ||
879 | io::IReadFile* heightMapFile, | ||
880 | ISceneNode* parent, s32 id, | ||
881 | const core::vector3df& position, | ||
882 | const core::vector3df& rotation, | ||
883 | const core::vector3df& scale, | ||
884 | video::SColor vertexColor, | ||
885 | s32 maxLOD, E_TERRAIN_PATCH_SIZE patchSize, | ||
886 | s32 smoothFactor, | ||
887 | bool addAlsoIfHeightmapEmpty) | ||
888 | { | ||
889 | if (!parent) | ||
890 | parent = this; | ||
891 | |||
892 | if (!heightMapFile && !addAlsoIfHeightmapEmpty) | ||
893 | { | ||
894 | os::Printer::log("Could not load terrain, because file could not be opened.", ELL_ERROR); | ||
895 | return 0; | ||
896 | } | ||
897 | |||
898 | CTerrainSceneNode* node = new CTerrainSceneNode(parent, this, FileSystem, id, | ||
899 | maxLOD, patchSize, position, rotation, scale); | ||
900 | |||
901 | if (!node->loadHeightMap(heightMapFile, vertexColor, smoothFactor)) | ||
902 | { | ||
903 | if (!addAlsoIfHeightmapEmpty) | ||
904 | { | ||
905 | node->remove(); | ||
906 | node->drop(); | ||
907 | return 0; | ||
908 | } | ||
909 | } | ||
910 | |||
911 | node->drop(); | ||
912 | return node; | ||
913 | } | ||
914 | |||
915 | |||
916 | //! Adds an empty scene node. | ||
917 | ISceneNode* CSceneManager::addEmptySceneNode(ISceneNode* parent, s32 id) | ||
918 | { | ||
919 | if (!parent) | ||
920 | parent = this; | ||
921 | |||
922 | ISceneNode* node = new CEmptySceneNode(parent, this, id); | ||
923 | node->drop(); | ||
924 | |||
925 | return node; | ||
926 | } | ||
927 | |||
928 | |||
929 | //! Adds a dummy transformation scene node to the scene graph. | ||
930 | IDummyTransformationSceneNode* CSceneManager::addDummyTransformationSceneNode( | ||
931 | ISceneNode* parent, s32 id) | ||
932 | { | ||
933 | if (!parent) | ||
934 | parent = this; | ||
935 | |||
936 | IDummyTransformationSceneNode* node = new CDummyTransformationSceneNode( | ||
937 | parent, this, id); | ||
938 | node->drop(); | ||
939 | |||
940 | return node; | ||
941 | } | ||
942 | |||
943 | //! Adds a Hill Plane mesh to the mesh pool. The mesh is generated on the fly | ||
944 | //! and looks like a plane with some hills on it. You can specify how many hills | ||
945 | //! there should be on the plane and how high they should be. Also you must | ||
946 | //! specify a name for the mesh, because the mesh is added to the mesh pool, | ||
947 | //! and can be retrieved again using ISceneManager::getMesh with the name as | ||
948 | //! parameter. | ||
949 | IAnimatedMesh* CSceneManager::addHillPlaneMesh(const io::path& name, | ||
950 | const core::dimension2d<f32>& tileSize, | ||
951 | const core::dimension2d<u32>& tileCount, | ||
952 | video::SMaterial* material, f32 hillHeight, | ||
953 | const core::dimension2d<f32>& countHills, | ||
954 | const core::dimension2d<f32>& textureRepeatCount) | ||
955 | { | ||
956 | if (MeshCache->isMeshLoaded(name)) | ||
957 | return MeshCache->getMeshByName(name); | ||
958 | |||
959 | IMesh* mesh = GeometryCreator->createHillPlaneMesh(tileSize, | ||
960 | tileCount, material, hillHeight, countHills, | ||
961 | textureRepeatCount); | ||
962 | if (!mesh) | ||
963 | return 0; | ||
964 | |||
965 | SAnimatedMesh* animatedMesh = new SAnimatedMesh(); | ||
966 | if (!animatedMesh) | ||
967 | { | ||
968 | mesh->drop(); | ||
969 | return 0; | ||
970 | } | ||
971 | |||
972 | animatedMesh->addMesh(mesh); | ||
973 | mesh->drop(); | ||
974 | animatedMesh->recalculateBoundingBox(); | ||
975 | |||
976 | MeshCache->addMesh(name, animatedMesh); | ||
977 | animatedMesh->drop(); | ||
978 | |||
979 | return animatedMesh; | ||
980 | } | ||
981 | |||
982 | |||
983 | //! Adds a terrain mesh to the mesh pool. | ||
984 | IAnimatedMesh* CSceneManager::addTerrainMesh(const io::path& name, | ||
985 | video::IImage* texture, video::IImage* heightmap, | ||
986 | const core::dimension2d<f32>& stretchSize, | ||
987 | f32 maxHeight, | ||
988 | const core::dimension2d<u32>& defaultVertexBlockSize) | ||
989 | { | ||
990 | if (MeshCache->isMeshLoaded(name)) | ||
991 | return MeshCache->getMeshByName(name); | ||
992 | |||
993 | const bool debugBorders=false; | ||
994 | IMesh* mesh = GeometryCreator->createTerrainMesh(texture, heightmap, | ||
995 | stretchSize, maxHeight, Driver, | ||
996 | defaultVertexBlockSize, debugBorders); | ||
997 | if (!mesh) | ||
998 | return 0; | ||
999 | |||
1000 | SAnimatedMesh* animatedMesh = new SAnimatedMesh(); | ||
1001 | if (!animatedMesh) | ||
1002 | { | ||
1003 | mesh->drop(); | ||
1004 | return 0; | ||
1005 | } | ||
1006 | |||
1007 | animatedMesh->addMesh(mesh); | ||
1008 | mesh->drop(); | ||
1009 | animatedMesh->recalculateBoundingBox(); | ||
1010 | |||
1011 | MeshCache->addMesh(name, animatedMesh); | ||
1012 | animatedMesh->drop(); | ||
1013 | |||
1014 | return animatedMesh; | ||
1015 | } | ||
1016 | |||
1017 | |||
1018 | //! Adds an arrow mesh to the mesh pool. | ||
1019 | IAnimatedMesh* CSceneManager::addArrowMesh(const io::path& name, | ||
1020 | video::SColor vtxColor0, video::SColor vtxColor1, | ||
1021 | u32 tesselationCylinder, u32 tesselationCone, f32 height, | ||
1022 | f32 cylinderHeight, f32 width0,f32 width1) | ||
1023 | { | ||
1024 | if (MeshCache->isMeshLoaded(name)) | ||
1025 | return MeshCache->getMeshByName(name); | ||
1026 | |||
1027 | IMesh* mesh = GeometryCreator->createArrowMesh( tesselationCylinder, | ||
1028 | tesselationCone, height, cylinderHeight, width0,width1, | ||
1029 | vtxColor0, vtxColor1); | ||
1030 | if (!mesh) | ||
1031 | return 0; | ||
1032 | |||
1033 | SAnimatedMesh* animatedMesh = new SAnimatedMesh(); | ||
1034 | if (!animatedMesh) | ||
1035 | { | ||
1036 | mesh->drop(); | ||
1037 | return 0; | ||
1038 | } | ||
1039 | |||
1040 | animatedMesh->addMesh(mesh); | ||
1041 | mesh->drop(); | ||
1042 | animatedMesh->recalculateBoundingBox(); | ||
1043 | |||
1044 | MeshCache->addMesh(name, animatedMesh); | ||
1045 | animatedMesh->drop(); | ||
1046 | |||
1047 | return animatedMesh; | ||
1048 | } | ||
1049 | |||
1050 | |||
1051 | //! Adds a static sphere mesh to the mesh pool. | ||
1052 | IAnimatedMesh* CSceneManager::addSphereMesh(const io::path& name, | ||
1053 | f32 radius, u32 polyCountX, u32 polyCountY) | ||
1054 | { | ||
1055 | if (MeshCache->isMeshLoaded(name)) | ||
1056 | return MeshCache->getMeshByName(name); | ||
1057 | |||
1058 | IMesh* mesh = GeometryCreator->createSphereMesh(radius, polyCountX, polyCountY); | ||
1059 | if (!mesh) | ||
1060 | return 0; | ||
1061 | |||
1062 | SAnimatedMesh* animatedMesh = new SAnimatedMesh(); | ||
1063 | if (!animatedMesh) | ||
1064 | { | ||
1065 | mesh->drop(); | ||
1066 | return 0; | ||
1067 | } | ||
1068 | |||
1069 | animatedMesh->addMesh(mesh); | ||
1070 | mesh->drop(); | ||
1071 | animatedMesh->recalculateBoundingBox(); | ||
1072 | |||
1073 | MeshCache->addMesh(name, animatedMesh); | ||
1074 | animatedMesh->drop(); | ||
1075 | |||
1076 | return animatedMesh; | ||
1077 | } | ||
1078 | |||
1079 | |||
1080 | |||
1081 | //! Adds a static volume light mesh to the mesh pool. | ||
1082 | IAnimatedMesh* CSceneManager::addVolumeLightMesh(const io::path& name, | ||
1083 | const u32 SubdivideU, const u32 SubdivideV, | ||
1084 | const video::SColor FootColor, const video::SColor TailColor) | ||
1085 | { | ||
1086 | if (MeshCache->isMeshLoaded(name)) | ||
1087 | return MeshCache->getMeshByName(name); | ||
1088 | |||
1089 | IMesh* mesh = GeometryCreator->createVolumeLightMesh(SubdivideU, SubdivideV, FootColor, TailColor); | ||
1090 | if (!mesh) | ||
1091 | return 0; | ||
1092 | |||
1093 | SAnimatedMesh* animatedMesh = new SAnimatedMesh(); | ||
1094 | if (!animatedMesh) | ||
1095 | { | ||
1096 | mesh->drop(); | ||
1097 | return 0; | ||
1098 | } | ||
1099 | |||
1100 | animatedMesh->addMesh(mesh); | ||
1101 | mesh->drop(); | ||
1102 | animatedMesh->recalculateBoundingBox(); | ||
1103 | |||
1104 | MeshCache->addMesh(name, animatedMesh); | ||
1105 | animatedMesh->drop(); | ||
1106 | |||
1107 | return animatedMesh; | ||
1108 | } | ||
1109 | |||
1110 | |||
1111 | //! Returns the root scene node. This is the scene node wich is parent | ||
1112 | //! of all scene nodes. The root scene node is a special scene node which | ||
1113 | //! only exists to manage all scene nodes. It is not rendered and cannot | ||
1114 | //! be removed from the scene. | ||
1115 | //! \return Returns a pointer to the root scene node. | ||
1116 | ISceneNode* CSceneManager::getRootSceneNode() | ||
1117 | { | ||
1118 | return this; | ||
1119 | } | ||
1120 | |||
1121 | |||
1122 | //! Returns the current active camera. | ||
1123 | //! \return The active camera is returned. Note that this can be NULL, if there | ||
1124 | //! was no camera created yet. | ||
1125 | ICameraSceneNode* CSceneManager::getActiveCamera() const | ||
1126 | { | ||
1127 | return ActiveCamera; | ||
1128 | } | ||
1129 | |||
1130 | |||
1131 | //! Sets the active camera. The previous active camera will be deactivated. | ||
1132 | //! \param camera: The new camera which should be active. | ||
1133 | void CSceneManager::setActiveCamera(ICameraSceneNode* camera) | ||
1134 | { | ||
1135 | if (camera) | ||
1136 | camera->grab(); | ||
1137 | if (ActiveCamera) | ||
1138 | ActiveCamera->drop(); | ||
1139 | |||
1140 | ActiveCamera = camera; | ||
1141 | } | ||
1142 | |||
1143 | |||
1144 | //! renders the node. | ||
1145 | void CSceneManager::render() | ||
1146 | { | ||
1147 | } | ||
1148 | |||
1149 | |||
1150 | //! returns the axis aligned bounding box of this node | ||
1151 | const core::aabbox3d<f32>& CSceneManager::getBoundingBox() const | ||
1152 | { | ||
1153 | _IRR_DEBUG_BREAK_IF(true) // Bounding Box of Scene Manager wanted. | ||
1154 | |||
1155 | // should never be used. | ||
1156 | return *((core::aabbox3d<f32>*)0); | ||
1157 | } | ||
1158 | |||
1159 | |||
1160 | //! returns if node is culled | ||
1161 | bool CSceneManager::isCulled(const ISceneNode* node) const | ||
1162 | { | ||
1163 | const ICameraSceneNode* cam = getActiveCamera(); | ||
1164 | if (!cam) | ||
1165 | { | ||
1166 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
1167 | return false; | ||
1168 | } | ||
1169 | bool result = false; | ||
1170 | |||
1171 | // has occlusion query information | ||
1172 | if (node->getAutomaticCulling() & scene::EAC_OCC_QUERY) | ||
1173 | { | ||
1174 | result = (Driver->getOcclusionQueryResult(const_cast<ISceneNode*>(node))==0); | ||
1175 | } | ||
1176 | |||
1177 | // can be seen by a bounding box ? | ||
1178 | if (!result && (node->getAutomaticCulling() & scene::EAC_BOX)) | ||
1179 | { | ||
1180 | core::aabbox3d<f32> tbox = node->getBoundingBox(); | ||
1181 | node->getAbsoluteTransformation().transformBoxEx(tbox); | ||
1182 | result = !(tbox.intersectsWithBox(cam->getViewFrustum()->getBoundingBox() )); | ||
1183 | } | ||
1184 | |||
1185 | // can be seen by a bounding sphere | ||
1186 | if (!result && (node->getAutomaticCulling() & scene::EAC_FRUSTUM_SPHERE)) | ||
1187 | { // requires bbox diameter | ||
1188 | } | ||
1189 | |||
1190 | // can be seen by cam pyramid planes ? | ||
1191 | if (!result && (node->getAutomaticCulling() & scene::EAC_FRUSTUM_BOX)) | ||
1192 | { | ||
1193 | SViewFrustum frust = *cam->getViewFrustum(); | ||
1194 | |||
1195 | //transform the frustum to the node's current absolute transformation | ||
1196 | core::matrix4 invTrans(node->getAbsoluteTransformation(), core::matrix4::EM4CONST_INVERSE); | ||
1197 | //invTrans.makeInverse(); | ||
1198 | frust.transform(invTrans); | ||
1199 | |||
1200 | core::vector3df edges[8]; | ||
1201 | node->getBoundingBox().getEdges(edges); | ||
1202 | |||
1203 | for (s32 i=0; i<scene::SViewFrustum::VF_PLANE_COUNT; ++i) | ||
1204 | { | ||
1205 | bool boxInFrustum=false; | ||
1206 | for (u32 j=0; j<8; ++j) | ||
1207 | { | ||
1208 | if (frust.planes[i].classifyPointRelation(edges[j]) != core::ISREL3D_FRONT) | ||
1209 | { | ||
1210 | boxInFrustum=true; | ||
1211 | break; | ||
1212 | } | ||
1213 | } | ||
1214 | |||
1215 | if (!boxInFrustum) | ||
1216 | { | ||
1217 | result = true; | ||
1218 | break; | ||
1219 | } | ||
1220 | } | ||
1221 | } | ||
1222 | |||
1223 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
1224 | return result; | ||
1225 | } | ||
1226 | |||
1227 | |||
1228 | //! registers a node for rendering it at a specific time. | ||
1229 | u32 CSceneManager::registerNodeForRendering(ISceneNode* node, E_SCENE_NODE_RENDER_PASS pass) | ||
1230 | { | ||
1231 | u32 taken = 0; | ||
1232 | |||
1233 | switch(pass) | ||
1234 | { | ||
1235 | // take camera if it is not already registered | ||
1236 | case ESNRP_CAMERA: | ||
1237 | { | ||
1238 | taken = 1; | ||
1239 | for (u32 i = 0; i != CameraList.size(); ++i) | ||
1240 | { | ||
1241 | if (CameraList[i] == node) | ||
1242 | { | ||
1243 | taken = 0; | ||
1244 | break; | ||
1245 | } | ||
1246 | } | ||
1247 | if (taken) | ||
1248 | { | ||
1249 | CameraList.push_back(node); | ||
1250 | } | ||
1251 | } | ||
1252 | break; | ||
1253 | |||
1254 | case ESNRP_LIGHT: | ||
1255 | // TODO: Point Light culling.. | ||
1256 | // Lighting model in irrlicht has to be redone.. | ||
1257 | //if (!isCulled(node)) | ||
1258 | { | ||
1259 | LightList.push_back(node); | ||
1260 | taken = 1; | ||
1261 | } | ||
1262 | break; | ||
1263 | |||
1264 | case ESNRP_SKY_BOX: | ||
1265 | SkyBoxList.push_back(node); | ||
1266 | taken = 1; | ||
1267 | break; | ||
1268 | case ESNRP_SOLID: | ||
1269 | if (!isCulled(node)) | ||
1270 | { | ||
1271 | SolidNodeList.push_back(node); | ||
1272 | taken = 1; | ||
1273 | } | ||
1274 | break; | ||
1275 | case ESNRP_TRANSPARENT: | ||
1276 | if (!isCulled(node)) | ||
1277 | { | ||
1278 | TransparentNodeList.push_back(TransparentNodeEntry(node, camWorldPos)); | ||
1279 | taken = 1; | ||
1280 | } | ||
1281 | break; | ||
1282 | case ESNRP_TRANSPARENT_EFFECT: | ||
1283 | if (!isCulled(node)) | ||
1284 | { | ||
1285 | TransparentEffectNodeList.push_back(TransparentNodeEntry(node, camWorldPos)); | ||
1286 | taken = 1; | ||
1287 | } | ||
1288 | break; | ||
1289 | case ESNRP_AUTOMATIC: | ||
1290 | if (!isCulled(node)) | ||
1291 | { | ||
1292 | const u32 count = node->getMaterialCount(); | ||
1293 | |||
1294 | taken = 0; | ||
1295 | for (u32 i=0; i<count; ++i) | ||
1296 | { | ||
1297 | video::IMaterialRenderer* rnd = | ||
1298 | Driver->getMaterialRenderer(node->getMaterial(i).MaterialType); | ||
1299 | if (rnd && rnd->isTransparent()) | ||
1300 | { | ||
1301 | // register as transparent node | ||
1302 | TransparentNodeEntry e(node, camWorldPos); | ||
1303 | TransparentNodeList.push_back(e); | ||
1304 | taken = 1; | ||
1305 | break; | ||
1306 | } | ||
1307 | } | ||
1308 | |||
1309 | // not transparent, register as solid | ||
1310 | if (!taken) | ||
1311 | { | ||
1312 | SolidNodeList.push_back(node); | ||
1313 | taken = 1; | ||
1314 | } | ||
1315 | } | ||
1316 | break; | ||
1317 | case ESNRP_SHADOW: | ||
1318 | if (!isCulled(node)) | ||
1319 | { | ||
1320 | ShadowNodeList.push_back(node); | ||
1321 | taken = 1; | ||
1322 | } | ||
1323 | break; | ||
1324 | |||
1325 | case ESNRP_NONE: // ignore this one | ||
1326 | break; | ||
1327 | } | ||
1328 | |||
1329 | #ifdef SCENEMANAGER_DEBUG | ||
1330 | s32 index = Parameters.findAttribute ( "calls" ); | ||
1331 | Parameters.setAttribute ( index, Parameters.getAttributeAsInt ( index ) + 1 ); | ||
1332 | |||
1333 | if (!taken) | ||
1334 | { | ||
1335 | index = Parameters.findAttribute ( "culled" ); | ||
1336 | Parameters.setAttribute ( index, Parameters.getAttributeAsInt ( index ) + 1 ); | ||
1337 | } | ||
1338 | #endif | ||
1339 | |||
1340 | return taken; | ||
1341 | } | ||
1342 | |||
1343 | |||
1344 | //! This method is called just before the rendering process of the whole scene. | ||
1345 | //! draws all scene nodes | ||
1346 | void CSceneManager::drawAll() | ||
1347 | { | ||
1348 | if (!Driver) | ||
1349 | return; | ||
1350 | |||
1351 | // reset attributes | ||
1352 | Parameters.setAttribute ( "culled", 0 ); | ||
1353 | Parameters.setAttribute ( "calls", 0 ); | ||
1354 | Parameters.setAttribute ( "drawn_solid", 0 ); | ||
1355 | Parameters.setAttribute ( "drawn_transparent", 0 ); | ||
1356 | Parameters.setAttribute ( "drawn_transparent_effect", 0 ); | ||
1357 | |||
1358 | u32 i; // new ISO for scoping problem in some compilers | ||
1359 | |||
1360 | // reset all transforms | ||
1361 | Driver->setMaterial(video::SMaterial()); | ||
1362 | Driver->setTransform ( video::ETS_PROJECTION, core::IdentityMatrix ); | ||
1363 | Driver->setTransform ( video::ETS_VIEW, core::IdentityMatrix ); | ||
1364 | Driver->setTransform ( video::ETS_WORLD, core::IdentityMatrix ); | ||
1365 | for (i=video::ETS_COUNT-1; i>=video::ETS_TEXTURE_0; --i) | ||
1366 | Driver->setTransform ( (video::E_TRANSFORMATION_STATE)i, core::IdentityMatrix ); | ||
1367 | Driver->setAllowZWriteOnTransparent(Parameters.getAttributeAsBool( ALLOW_ZWRITE_ON_TRANSPARENT) ); | ||
1368 | |||
1369 | // do animations and other stuff. | ||
1370 | OnAnimate(os::Timer::getTime()); | ||
1371 | |||
1372 | /*! | ||
1373 | First Scene Node for prerendering should be the active camera | ||
1374 | consistent Camera is needed for culling | ||
1375 | */ | ||
1376 | camWorldPos.set(0,0,0); | ||
1377 | if (ActiveCamera) | ||
1378 | { | ||
1379 | ActiveCamera->render(); | ||
1380 | camWorldPos = ActiveCamera->getAbsolutePosition(); | ||
1381 | } | ||
1382 | |||
1383 | // let all nodes register themselves | ||
1384 | OnRegisterSceneNode(); | ||
1385 | |||
1386 | if (LightManager) | ||
1387 | LightManager->OnPreRender(LightList); | ||
1388 | |||
1389 | //render camera scenes | ||
1390 | { | ||
1391 | CurrentRendertime = ESNRP_CAMERA; | ||
1392 | Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRendertime) != 0); | ||
1393 | |||
1394 | if (LightManager) | ||
1395 | LightManager->OnRenderPassPreRender(CurrentRendertime); | ||
1396 | |||
1397 | for (i=0; i<CameraList.size(); ++i) | ||
1398 | CameraList[i]->render(); | ||
1399 | |||
1400 | CameraList.set_used(0); | ||
1401 | |||
1402 | if (LightManager) | ||
1403 | LightManager->OnRenderPassPostRender(CurrentRendertime); | ||
1404 | } | ||
1405 | |||
1406 | //render lights scenes | ||
1407 | { | ||
1408 | CurrentRendertime = ESNRP_LIGHT; | ||
1409 | Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRendertime) != 0); | ||
1410 | |||
1411 | if (LightManager) | ||
1412 | { | ||
1413 | LightManager->OnRenderPassPreRender(CurrentRendertime); | ||
1414 | } | ||
1415 | else | ||
1416 | { | ||
1417 | // Sort the lights by distance from the camera | ||
1418 | core::vector3df camWorldPos(0, 0, 0); | ||
1419 | if (ActiveCamera) | ||
1420 | camWorldPos = ActiveCamera->getAbsolutePosition(); | ||
1421 | |||
1422 | core::array<DistanceNodeEntry> SortedLights; | ||
1423 | SortedLights.set_used(LightList.size()); | ||
1424 | for (s32 light = (s32)LightList.size() - 1; light >= 0; --light) | ||
1425 | SortedLights[light].setNodeAndDistanceFromPosition(LightList[light], camWorldPos); | ||
1426 | |||
1427 | SortedLights.set_sorted(false); | ||
1428 | SortedLights.sort(); | ||
1429 | |||
1430 | for(s32 light = (s32)LightList.size() - 1; light >= 0; --light) | ||
1431 | LightList[light] = SortedLights[light].Node; | ||
1432 | } | ||
1433 | |||
1434 | Driver->deleteAllDynamicLights(); | ||
1435 | |||
1436 | Driver->setAmbientLight(AmbientLight); | ||
1437 | |||
1438 | u32 maxLights = LightList.size(); | ||
1439 | |||
1440 | if (!LightManager) | ||
1441 | maxLights = core::min_ ( Driver->getMaximalDynamicLightAmount(), maxLights); | ||
1442 | |||
1443 | for (i=0; i< maxLights; ++i) | ||
1444 | LightList[i]->render(); | ||
1445 | |||
1446 | if (LightManager) | ||
1447 | LightManager->OnRenderPassPostRender(CurrentRendertime); | ||
1448 | } | ||
1449 | |||
1450 | // render skyboxes | ||
1451 | { | ||
1452 | CurrentRendertime = ESNRP_SKY_BOX; | ||
1453 | Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRendertime) != 0); | ||
1454 | |||
1455 | if (LightManager) | ||
1456 | { | ||
1457 | LightManager->OnRenderPassPreRender(CurrentRendertime); | ||
1458 | for (i=0; i<SkyBoxList.size(); ++i) | ||
1459 | { | ||
1460 | ISceneNode* node = SkyBoxList[i]; | ||
1461 | LightManager->OnNodePreRender(node); | ||
1462 | node->render(); | ||
1463 | LightManager->OnNodePostRender(node); | ||
1464 | } | ||
1465 | } | ||
1466 | else | ||
1467 | { | ||
1468 | for (i=0; i<SkyBoxList.size(); ++i) | ||
1469 | SkyBoxList[i]->render(); | ||
1470 | } | ||
1471 | |||
1472 | SkyBoxList.set_used(0); | ||
1473 | |||
1474 | if (LightManager) | ||
1475 | LightManager->OnRenderPassPostRender(CurrentRendertime); | ||
1476 | } | ||
1477 | |||
1478 | |||
1479 | // render default objects | ||
1480 | { | ||
1481 | CurrentRendertime = ESNRP_SOLID; | ||
1482 | Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRendertime) != 0); | ||
1483 | |||
1484 | SolidNodeList.sort(); // sort by textures | ||
1485 | |||
1486 | if (LightManager) | ||
1487 | { | ||
1488 | LightManager->OnRenderPassPreRender(CurrentRendertime); | ||
1489 | for (i=0; i<SolidNodeList.size(); ++i) | ||
1490 | { | ||
1491 | ISceneNode* node = SolidNodeList[i].Node; | ||
1492 | LightManager->OnNodePreRender(node); | ||
1493 | node->render(); | ||
1494 | LightManager->OnNodePostRender(node); | ||
1495 | } | ||
1496 | } | ||
1497 | else | ||
1498 | { | ||
1499 | for (i=0; i<SolidNodeList.size(); ++i) | ||
1500 | SolidNodeList[i].Node->render(); | ||
1501 | } | ||
1502 | |||
1503 | Parameters.setAttribute("drawn_solid", (s32) SolidNodeList.size() ); | ||
1504 | SolidNodeList.set_used(0); | ||
1505 | |||
1506 | if (LightManager) | ||
1507 | LightManager->OnRenderPassPostRender(CurrentRendertime); | ||
1508 | } | ||
1509 | |||
1510 | // render shadows | ||
1511 | { | ||
1512 | CurrentRendertime = ESNRP_SHADOW; | ||
1513 | Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRendertime) != 0); | ||
1514 | |||
1515 | if (LightManager) | ||
1516 | { | ||
1517 | LightManager->OnRenderPassPreRender(CurrentRendertime); | ||
1518 | for (i=0; i<ShadowNodeList.size(); ++i) | ||
1519 | { | ||
1520 | ISceneNode* node = ShadowNodeList[i]; | ||
1521 | LightManager->OnNodePreRender(node); | ||
1522 | node->render(); | ||
1523 | LightManager->OnNodePostRender(node); | ||
1524 | } | ||
1525 | } | ||
1526 | else | ||
1527 | { | ||
1528 | for (i=0; i<ShadowNodeList.size(); ++i) | ||
1529 | ShadowNodeList[i]->render(); | ||
1530 | } | ||
1531 | |||
1532 | if (!ShadowNodeList.empty()) | ||
1533 | Driver->drawStencilShadow(true,ShadowColor, ShadowColor, | ||
1534 | ShadowColor, ShadowColor); | ||
1535 | |||
1536 | ShadowNodeList.set_used(0); | ||
1537 | |||
1538 | if (LightManager) | ||
1539 | LightManager->OnRenderPassPostRender(CurrentRendertime); | ||
1540 | } | ||
1541 | |||
1542 | // render transparent objects. | ||
1543 | { | ||
1544 | CurrentRendertime = ESNRP_TRANSPARENT; | ||
1545 | Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRendertime) != 0); | ||
1546 | |||
1547 | TransparentNodeList.sort(); // sort by distance from camera | ||
1548 | if (LightManager) | ||
1549 | { | ||
1550 | LightManager->OnRenderPassPreRender(CurrentRendertime); | ||
1551 | |||
1552 | for (i=0; i<TransparentNodeList.size(); ++i) | ||
1553 | { | ||
1554 | ISceneNode* node = TransparentNodeList[i].Node; | ||
1555 | LightManager->OnNodePreRender(node); | ||
1556 | node->render(); | ||
1557 | LightManager->OnNodePostRender(node); | ||
1558 | } | ||
1559 | } | ||
1560 | else | ||
1561 | { | ||
1562 | for (i=0; i<TransparentNodeList.size(); ++i) | ||
1563 | TransparentNodeList[i].Node->render(); | ||
1564 | } | ||
1565 | |||
1566 | Parameters.setAttribute ( "drawn_transparent", (s32) TransparentNodeList.size() ); | ||
1567 | TransparentNodeList.set_used(0); | ||
1568 | |||
1569 | if (LightManager) | ||
1570 | LightManager->OnRenderPassPostRender(CurrentRendertime); | ||
1571 | } | ||
1572 | |||
1573 | // render transparent effect objects. | ||
1574 | { | ||
1575 | CurrentRendertime = ESNRP_TRANSPARENT_EFFECT; | ||
1576 | Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRendertime) != 0); | ||
1577 | |||
1578 | TransparentEffectNodeList.sort(); // sort by distance from camera | ||
1579 | |||
1580 | if (LightManager) | ||
1581 | { | ||
1582 | LightManager->OnRenderPassPreRender(CurrentRendertime); | ||
1583 | |||
1584 | for (i=0; i<TransparentEffectNodeList.size(); ++i) | ||
1585 | { | ||
1586 | ISceneNode* node = TransparentEffectNodeList[i].Node; | ||
1587 | LightManager->OnNodePreRender(node); | ||
1588 | node->render(); | ||
1589 | LightManager->OnNodePostRender(node); | ||
1590 | } | ||
1591 | } | ||
1592 | else | ||
1593 | { | ||
1594 | for (i=0; i<TransparentEffectNodeList.size(); ++i) | ||
1595 | TransparentEffectNodeList[i].Node->render(); | ||
1596 | } | ||
1597 | |||
1598 | Parameters.setAttribute ( "drawn_transparent_effect", (s32) TransparentEffectNodeList.size() ); | ||
1599 | TransparentEffectNodeList.set_used(0); | ||
1600 | } | ||
1601 | |||
1602 | if (LightManager) | ||
1603 | LightManager->OnPostRender(); | ||
1604 | |||
1605 | LightList.set_used(0); | ||
1606 | clearDeletionList(); | ||
1607 | |||
1608 | CurrentRendertime = ESNRP_NONE; | ||
1609 | } | ||
1610 | |||
1611 | void CSceneManager::setLightManager(ILightManager* lightManager) | ||
1612 | { | ||
1613 | if (lightManager) | ||
1614 | lightManager->grab(); | ||
1615 | if (LightManager) | ||
1616 | LightManager->drop(); | ||
1617 | |||
1618 | LightManager = lightManager; | ||
1619 | } | ||
1620 | |||
1621 | |||
1622 | //! Sets the color of stencil buffers shadows drawn by the scene manager. | ||
1623 | void CSceneManager::setShadowColor(video::SColor color) | ||
1624 | { | ||
1625 | ShadowColor = color; | ||
1626 | } | ||
1627 | |||
1628 | |||
1629 | //! Returns the current color of shadows. | ||
1630 | video::SColor CSceneManager::getShadowColor() const | ||
1631 | { | ||
1632 | return ShadowColor; | ||
1633 | } | ||
1634 | |||
1635 | |||
1636 | //! creates a rotation animator, which rotates the attached scene node around itself. | ||
1637 | ISceneNodeAnimator* CSceneManager::createRotationAnimator(const core::vector3df& rotationPerSecond) | ||
1638 | { | ||
1639 | ISceneNodeAnimator* anim = new CSceneNodeAnimatorRotation(os::Timer::getTime(), | ||
1640 | rotationPerSecond); | ||
1641 | |||
1642 | return anim; | ||
1643 | } | ||
1644 | |||
1645 | |||
1646 | //! creates a fly circle animator, which lets the attached scene node fly around a center. | ||
1647 | ISceneNodeAnimator* CSceneManager::createFlyCircleAnimator( | ||
1648 | const core::vector3df& center, f32 radius, f32 speed, | ||
1649 | const core::vector3df& direction, | ||
1650 | f32 startPosition, | ||
1651 | f32 radiusEllipsoid) | ||
1652 | { | ||
1653 | const f32 orbitDurationMs = (core::DEGTORAD * 360.f) / speed; | ||
1654 | const u32 effectiveTime = os::Timer::getTime() + (u32)(orbitDurationMs * startPosition); | ||
1655 | |||
1656 | ISceneNodeAnimator* anim = new CSceneNodeAnimatorFlyCircle( | ||
1657 | effectiveTime, center, | ||
1658 | radius, speed, direction,radiusEllipsoid); | ||
1659 | return anim; | ||
1660 | } | ||
1661 | |||
1662 | |||
1663 | //! Creates a fly straight animator, which lets the attached scene node | ||
1664 | //! fly or move along a line between two points. | ||
1665 | ISceneNodeAnimator* CSceneManager::createFlyStraightAnimator(const core::vector3df& startPoint, | ||
1666 | const core::vector3df& endPoint, u32 timeForWay, bool loop,bool pingpong) | ||
1667 | { | ||
1668 | ISceneNodeAnimator* anim = new CSceneNodeAnimatorFlyStraight(startPoint, | ||
1669 | endPoint, timeForWay, loop, os::Timer::getTime(), pingpong); | ||
1670 | |||
1671 | return anim; | ||
1672 | } | ||
1673 | |||
1674 | |||
1675 | //! Creates a texture animator, which switches the textures of the target scene | ||
1676 | //! node based on a list of textures. | ||
1677 | ISceneNodeAnimator* CSceneManager::createTextureAnimator(const core::array<video::ITexture*>& textures, | ||
1678 | s32 timePerFrame, bool loop) | ||
1679 | { | ||
1680 | ISceneNodeAnimator* anim = new CSceneNodeAnimatorTexture(textures, | ||
1681 | timePerFrame, loop, os::Timer::getTime()); | ||
1682 | |||
1683 | return anim; | ||
1684 | } | ||
1685 | |||
1686 | |||
1687 | //! Creates a scene node animator, which deletes the scene node after | ||
1688 | //! some time automaticly. | ||
1689 | ISceneNodeAnimator* CSceneManager::createDeleteAnimator(u32 when) | ||
1690 | { | ||
1691 | return new CSceneNodeAnimatorDelete(this, os::Timer::getTime() + when); | ||
1692 | } | ||
1693 | |||
1694 | |||
1695 | //! Creates a special scene node animator for doing automatic collision detection | ||
1696 | //! and response. | ||
1697 | ISceneNodeAnimatorCollisionResponse* CSceneManager::createCollisionResponseAnimator( | ||
1698 | ITriangleSelector* world, ISceneNode* sceneNode, const core::vector3df& ellipsoidRadius, | ||
1699 | const core::vector3df& gravityPerSecond, | ||
1700 | const core::vector3df& ellipsoidTranslation, f32 slidingValue) | ||
1701 | { | ||
1702 | ISceneNodeAnimatorCollisionResponse* anim = new | ||
1703 | CSceneNodeAnimatorCollisionResponse(this, world, sceneNode, | ||
1704 | ellipsoidRadius, gravityPerSecond, | ||
1705 | ellipsoidTranslation, slidingValue); | ||
1706 | |||
1707 | return anim; | ||
1708 | } | ||
1709 | |||
1710 | |||
1711 | //! Creates a follow spline animator. | ||
1712 | ISceneNodeAnimator* CSceneManager::createFollowSplineAnimator(s32 startTime, | ||
1713 | const core::array< core::vector3df >& points, | ||
1714 | f32 speed, f32 tightness, bool loop, bool pingpong) | ||
1715 | { | ||
1716 | ISceneNodeAnimator* a = new CSceneNodeAnimatorFollowSpline(startTime, points, | ||
1717 | speed, tightness, loop, pingpong); | ||
1718 | return a; | ||
1719 | } | ||
1720 | |||
1721 | |||
1722 | //! Adds an external mesh loader. | ||
1723 | void CSceneManager::addExternalMeshLoader(IMeshLoader* externalLoader) | ||
1724 | { | ||
1725 | if (!externalLoader) | ||
1726 | return; | ||
1727 | |||
1728 | externalLoader->grab(); | ||
1729 | MeshLoaderList.push_back(externalLoader); | ||
1730 | } | ||
1731 | |||
1732 | |||
1733 | //! Returns the number of mesh loaders supported by Irrlicht at this time | ||
1734 | u32 CSceneManager::getMeshLoaderCount() const | ||
1735 | { | ||
1736 | return MeshLoaderList.size(); | ||
1737 | } | ||
1738 | |||
1739 | |||
1740 | //! Retrieve the given mesh loader | ||
1741 | IMeshLoader* CSceneManager::getMeshLoader(u32 index) const | ||
1742 | { | ||
1743 | if (index < MeshLoaderList.size()) | ||
1744 | return MeshLoaderList[index]; | ||
1745 | else | ||
1746 | return 0; | ||
1747 | } | ||
1748 | |||
1749 | |||
1750 | //! Adds an external scene loader. | ||
1751 | void CSceneManager::addExternalSceneLoader(ISceneLoader* externalLoader) | ||
1752 | { | ||
1753 | if (!externalLoader) | ||
1754 | return; | ||
1755 | |||
1756 | externalLoader->grab(); | ||
1757 | SceneLoaderList.push_back(externalLoader); | ||
1758 | } | ||
1759 | |||
1760 | |||
1761 | //! Returns the number of scene loaders | ||
1762 | u32 CSceneManager::getSceneLoaderCount() const | ||
1763 | { | ||
1764 | return SceneLoaderList.size(); | ||
1765 | } | ||
1766 | |||
1767 | |||
1768 | //! Retrieve the given scene loader | ||
1769 | ISceneLoader* CSceneManager::getSceneLoader(u32 index) const | ||
1770 | { | ||
1771 | if (index < SceneLoaderList.size()) | ||
1772 | return SceneLoaderList[index]; | ||
1773 | else | ||
1774 | return 0; | ||
1775 | } | ||
1776 | |||
1777 | |||
1778 | //! Returns a pointer to the scene collision manager. | ||
1779 | ISceneCollisionManager* CSceneManager::getSceneCollisionManager() | ||
1780 | { | ||
1781 | return CollisionManager; | ||
1782 | } | ||
1783 | |||
1784 | |||
1785 | //! Returns a pointer to the mesh manipulator. | ||
1786 | IMeshManipulator* CSceneManager::getMeshManipulator() | ||
1787 | { | ||
1788 | return Driver->getMeshManipulator(); | ||
1789 | } | ||
1790 | |||
1791 | |||
1792 | //! Creates a simple ITriangleSelector, based on a mesh. | ||
1793 | ITriangleSelector* CSceneManager::createTriangleSelector(IMesh* mesh, ISceneNode* node) | ||
1794 | { | ||
1795 | if (!mesh) | ||
1796 | return 0; | ||
1797 | |||
1798 | return new CTriangleSelector(mesh, node); | ||
1799 | } | ||
1800 | |||
1801 | |||
1802 | //! Creates a simple and updatable ITriangleSelector, based on a the mesh owned by an | ||
1803 | //! animated scene node | ||
1804 | ITriangleSelector* CSceneManager::createTriangleSelector(IAnimatedMeshSceneNode* node) | ||
1805 | { | ||
1806 | if (!node || !node->getMesh()) | ||
1807 | return 0; | ||
1808 | |||
1809 | return new CTriangleSelector(node); | ||
1810 | } | ||
1811 | |||
1812 | |||
1813 | //! Creates a simple dynamic ITriangleSelector, based on a axis aligned bounding box. | ||
1814 | ITriangleSelector* CSceneManager::createTriangleSelectorFromBoundingBox(ISceneNode* node) | ||
1815 | { | ||
1816 | if (!node) | ||
1817 | return 0; | ||
1818 | |||
1819 | return new CTriangleBBSelector(node); | ||
1820 | } | ||
1821 | |||
1822 | |||
1823 | //! Creates a simple ITriangleSelector, based on a mesh. | ||
1824 | ITriangleSelector* CSceneManager::createOctreeTriangleSelector(IMesh* mesh, | ||
1825 | ISceneNode* node, s32 minimalPolysPerNode) | ||
1826 | { | ||
1827 | if (!mesh) | ||
1828 | return 0; | ||
1829 | |||
1830 | return new COctreeTriangleSelector(mesh, node, minimalPolysPerNode); | ||
1831 | } | ||
1832 | |||
1833 | |||
1834 | //! Creates a meta triangle selector. | ||
1835 | IMetaTriangleSelector* CSceneManager::createMetaTriangleSelector() | ||
1836 | { | ||
1837 | return new CMetaTriangleSelector(); | ||
1838 | } | ||
1839 | |||
1840 | |||
1841 | //! Creates a triangle selector which can select triangles from a terrain scene node | ||
1842 | ITriangleSelector* CSceneManager::createTerrainTriangleSelector( | ||
1843 | ITerrainSceneNode* node, s32 LOD) | ||
1844 | { | ||
1845 | return new CTerrainTriangleSelector(node, LOD); | ||
1846 | } | ||
1847 | |||
1848 | |||
1849 | |||
1850 | //! Adds a scene node to the deletion queue. | ||
1851 | void CSceneManager::addToDeletionQueue(ISceneNode* node) | ||
1852 | { | ||
1853 | if (!node) | ||
1854 | return; | ||
1855 | |||
1856 | node->grab(); | ||
1857 | DeletionList.push_back(node); | ||
1858 | } | ||
1859 | |||
1860 | |||
1861 | //! clears the deletion list | ||
1862 | void CSceneManager::clearDeletionList() | ||
1863 | { | ||
1864 | if (DeletionList.empty()) | ||
1865 | return; | ||
1866 | |||
1867 | for (u32 i=0; i<DeletionList.size(); ++i) | ||
1868 | { | ||
1869 | DeletionList[i]->remove(); | ||
1870 | DeletionList[i]->drop(); | ||
1871 | } | ||
1872 | |||
1873 | DeletionList.clear(); | ||
1874 | } | ||
1875 | |||
1876 | |||
1877 | //! Returns the first scene node with the specified name. | ||
1878 | ISceneNode* CSceneManager::getSceneNodeFromName(const char* name, ISceneNode* start) | ||
1879 | { | ||
1880 | if (start == 0) | ||
1881 | start = getRootSceneNode(); | ||
1882 | |||
1883 | if (!strcmp(start->getName(),name)) | ||
1884 | return start; | ||
1885 | |||
1886 | ISceneNode* node = 0; | ||
1887 | |||
1888 | const ISceneNodeList& list = start->getChildren(); | ||
1889 | ISceneNodeList::ConstIterator it = list.begin(); | ||
1890 | for (; it!=list.end(); ++it) | ||
1891 | { | ||
1892 | node = getSceneNodeFromName(name, *it); | ||
1893 | if (node) | ||
1894 | return node; | ||
1895 | } | ||
1896 | |||
1897 | return 0; | ||
1898 | } | ||
1899 | |||
1900 | |||
1901 | //! Returns the first scene node with the specified id. | ||
1902 | ISceneNode* CSceneManager::getSceneNodeFromId(s32 id, ISceneNode* start) | ||
1903 | { | ||
1904 | if (start == 0) | ||
1905 | start = getRootSceneNode(); | ||
1906 | |||
1907 | if (start->getID() == id) | ||
1908 | return start; | ||
1909 | |||
1910 | ISceneNode* node = 0; | ||
1911 | |||
1912 | const ISceneNodeList& list = start->getChildren(); | ||
1913 | ISceneNodeList::ConstIterator it = list.begin(); | ||
1914 | for (; it!=list.end(); ++it) | ||
1915 | { | ||
1916 | node = getSceneNodeFromId(id, *it); | ||
1917 | if (node) | ||
1918 | return node; | ||
1919 | } | ||
1920 | |||
1921 | return 0; | ||
1922 | } | ||
1923 | |||
1924 | |||
1925 | //! Returns the first scene node with the specified type. | ||
1926 | ISceneNode* CSceneManager::getSceneNodeFromType(scene::ESCENE_NODE_TYPE type, ISceneNode* start) | ||
1927 | { | ||
1928 | if (start == 0) | ||
1929 | start = getRootSceneNode(); | ||
1930 | |||
1931 | if (start->getType() == type || ESNT_ANY == type) | ||
1932 | return start; | ||
1933 | |||
1934 | ISceneNode* node = 0; | ||
1935 | |||
1936 | const ISceneNodeList& list = start->getChildren(); | ||
1937 | ISceneNodeList::ConstIterator it = list.begin(); | ||
1938 | for (; it!=list.end(); ++it) | ||
1939 | { | ||
1940 | node = getSceneNodeFromType(type, *it); | ||
1941 | if (node) | ||
1942 | return node; | ||
1943 | } | ||
1944 | |||
1945 | return 0; | ||
1946 | } | ||
1947 | |||
1948 | |||
1949 | //! returns scene nodes by type. | ||
1950 | void CSceneManager::getSceneNodesFromType(ESCENE_NODE_TYPE type, core::array<scene::ISceneNode*>& outNodes, ISceneNode* start) | ||
1951 | { | ||
1952 | if (start == 0) | ||
1953 | start = getRootSceneNode(); | ||
1954 | |||
1955 | if (start->getType() == type || ESNT_ANY == type) | ||
1956 | outNodes.push_back(start); | ||
1957 | |||
1958 | const ISceneNodeList& list = start->getChildren(); | ||
1959 | ISceneNodeList::ConstIterator it = list.begin(); | ||
1960 | |||
1961 | for (; it!=list.end(); ++it) | ||
1962 | { | ||
1963 | getSceneNodesFromType(type, outNodes, *it); | ||
1964 | } | ||
1965 | } | ||
1966 | |||
1967 | |||
1968 | //! Posts an input event to the environment. Usually you do not have to | ||
1969 | //! use this method, it is used by the internal engine. | ||
1970 | bool CSceneManager::postEventFromUser(const SEvent& event) | ||
1971 | { | ||
1972 | bool ret = false; | ||
1973 | ICameraSceneNode* cam = getActiveCamera(); | ||
1974 | if (cam) | ||
1975 | ret = cam->OnEvent(event); | ||
1976 | |||
1977 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
1978 | return ret; | ||
1979 | } | ||
1980 | |||
1981 | |||
1982 | //! Removes all children of this scene node | ||
1983 | void CSceneManager::removeAll() | ||
1984 | { | ||
1985 | ISceneNode::removeAll(); | ||
1986 | setActiveCamera(0); | ||
1987 | // Make sure the driver is reset, might need a more complex method at some point | ||
1988 | if (Driver) | ||
1989 | Driver->setMaterial(video::SMaterial()); | ||
1990 | } | ||
1991 | |||
1992 | |||
1993 | //! Clears the whole scene. All scene nodes are removed. | ||
1994 | void CSceneManager::clear() | ||
1995 | { | ||
1996 | removeAll(); | ||
1997 | } | ||
1998 | |||
1999 | |||
2000 | //! Returns interface to the parameters set in this scene. | ||
2001 | io::IAttributes* CSceneManager::getParameters() | ||
2002 | { | ||
2003 | return &Parameters; | ||
2004 | } | ||
2005 | |||
2006 | |||
2007 | //! Returns current render pass. | ||
2008 | E_SCENE_NODE_RENDER_PASS CSceneManager::getSceneNodeRenderPass() const | ||
2009 | { | ||
2010 | return CurrentRendertime; | ||
2011 | } | ||
2012 | |||
2013 | |||
2014 | //! Returns an interface to the mesh cache which is shared beween all existing scene managers. | ||
2015 | IMeshCache* CSceneManager::getMeshCache() | ||
2016 | { | ||
2017 | return MeshCache; | ||
2018 | } | ||
2019 | |||
2020 | |||
2021 | //! Creates a new scene manager. | ||
2022 | ISceneManager* CSceneManager::createNewSceneManager(bool cloneContent) | ||
2023 | { | ||
2024 | CSceneManager* manager = new CSceneManager(Driver, FileSystem, CursorControl, MeshCache, GUIEnvironment); | ||
2025 | |||
2026 | if (cloneContent) | ||
2027 | manager->cloneMembers(this, manager); | ||
2028 | |||
2029 | return manager; | ||
2030 | } | ||
2031 | |||
2032 | |||
2033 | //! Returns the default scene node factory which can create all built in scene nodes | ||
2034 | ISceneNodeFactory* CSceneManager::getDefaultSceneNodeFactory() | ||
2035 | { | ||
2036 | return getSceneNodeFactory(0); | ||
2037 | } | ||
2038 | |||
2039 | |||
2040 | //! Adds a scene node factory to the scene manager. | ||
2041 | void CSceneManager::registerSceneNodeFactory(ISceneNodeFactory* factoryToAdd) | ||
2042 | { | ||
2043 | if (factoryToAdd) | ||
2044 | { | ||
2045 | factoryToAdd->grab(); | ||
2046 | SceneNodeFactoryList.push_back(factoryToAdd); | ||
2047 | } | ||
2048 | } | ||
2049 | |||
2050 | |||
2051 | //! Returns amount of registered scene node factories. | ||
2052 | u32 CSceneManager::getRegisteredSceneNodeFactoryCount() const | ||
2053 | { | ||
2054 | return SceneNodeFactoryList.size(); | ||
2055 | } | ||
2056 | |||
2057 | |||
2058 | //! Returns a scene node factory by index | ||
2059 | ISceneNodeFactory* CSceneManager::getSceneNodeFactory(u32 index) | ||
2060 | { | ||
2061 | if (index < SceneNodeFactoryList.size()) | ||
2062 | return SceneNodeFactoryList[index]; | ||
2063 | |||
2064 | return 0; | ||
2065 | } | ||
2066 | |||
2067 | |||
2068 | //! Returns the default scene node animator factory which can create all built-in scene node animators | ||
2069 | ISceneNodeAnimatorFactory* CSceneManager::getDefaultSceneNodeAnimatorFactory() | ||
2070 | { | ||
2071 | return getSceneNodeAnimatorFactory(0); | ||
2072 | } | ||
2073 | |||
2074 | //! Adds a scene node animator factory to the scene manager. | ||
2075 | void CSceneManager::registerSceneNodeAnimatorFactory(ISceneNodeAnimatorFactory* factoryToAdd) | ||
2076 | { | ||
2077 | if (factoryToAdd) | ||
2078 | { | ||
2079 | factoryToAdd->grab(); | ||
2080 | SceneNodeAnimatorFactoryList.push_back(factoryToAdd); | ||
2081 | } | ||
2082 | } | ||
2083 | |||
2084 | |||
2085 | //! Returns amount of registered scene node animator factories. | ||
2086 | u32 CSceneManager::getRegisteredSceneNodeAnimatorFactoryCount() const | ||
2087 | { | ||
2088 | return SceneNodeAnimatorFactoryList.size(); | ||
2089 | } | ||
2090 | |||
2091 | |||
2092 | //! Returns a scene node animator factory by index | ||
2093 | ISceneNodeAnimatorFactory* CSceneManager::getSceneNodeAnimatorFactory(u32 index) | ||
2094 | { | ||
2095 | if (index < SceneNodeAnimatorFactoryList.size()) | ||
2096 | return SceneNodeAnimatorFactoryList[index]; | ||
2097 | |||
2098 | return 0; | ||
2099 | } | ||
2100 | |||
2101 | |||
2102 | //! Saves the current scene into a file. | ||
2103 | //! \param filename: Name of the file . | ||
2104 | bool CSceneManager::saveScene(const io::path& filename, ISceneUserDataSerializer* userDataSerializer, ISceneNode* node) | ||
2105 | { | ||
2106 | bool ret = false; | ||
2107 | io::IWriteFile* file = FileSystem->createAndWriteFile(filename); | ||
2108 | if (file) | ||
2109 | { | ||
2110 | ret = saveScene(file, userDataSerializer, node); | ||
2111 | file->drop(); | ||
2112 | } | ||
2113 | else | ||
2114 | os::Printer::log("Unable to open file", filename, ELL_ERROR); | ||
2115 | |||
2116 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
2117 | return ret; | ||
2118 | } | ||
2119 | |||
2120 | |||
2121 | //! Saves the current scene into a file. | ||
2122 | bool CSceneManager::saveScene(io::IWriteFile* file, ISceneUserDataSerializer* userDataSerializer, ISceneNode* node) | ||
2123 | { | ||
2124 | if (!file) | ||
2125 | { | ||
2126 | return false; | ||
2127 | } | ||
2128 | |||
2129 | bool result=false; | ||
2130 | io::IXMLWriter* writer = FileSystem->createXMLWriter(file); | ||
2131 | if (!writer) | ||
2132 | { | ||
2133 | os::Printer::log("Unable to create XML writer", file->getFileName(), ELL_ERROR); | ||
2134 | } | ||
2135 | else | ||
2136 | { | ||
2137 | result = saveScene(writer, FileSystem->getFileDir(FileSystem->getAbsolutePath(file->getFileName())), userDataSerializer, node); | ||
2138 | writer->drop(); | ||
2139 | } | ||
2140 | return result; | ||
2141 | } | ||
2142 | |||
2143 | |||
2144 | //! Saves the current scene into a file. | ||
2145 | bool CSceneManager::saveScene(io::IXMLWriter* writer, const io::path& currentPath, ISceneUserDataSerializer* userDataSerializer, ISceneNode* node) | ||
2146 | { | ||
2147 | if (!writer) | ||
2148 | return false; | ||
2149 | |||
2150 | if (!node) | ||
2151 | node=this; | ||
2152 | |||
2153 | writer->writeXMLHeader(); | ||
2154 | writeSceneNode(writer, node, userDataSerializer, currentPath.c_str(), true); | ||
2155 | |||
2156 | return true; | ||
2157 | } | ||
2158 | |||
2159 | |||
2160 | //! Loads a scene. | ||
2161 | bool CSceneManager::loadScene(const io::path& filename, ISceneUserDataSerializer* userDataSerializer, ISceneNode* rootNode) | ||
2162 | { | ||
2163 | io::IReadFile* file = FileSystem->createAndOpenFile(filename); | ||
2164 | if (!file) | ||
2165 | { | ||
2166 | os::Printer::log("Unable to open scene file", filename.c_str(), ELL_ERROR); | ||
2167 | return false; | ||
2168 | } | ||
2169 | |||
2170 | const bool ret = loadScene(file, userDataSerializer, rootNode); | ||
2171 | file->drop(); | ||
2172 | |||
2173 | return ret; | ||
2174 | } | ||
2175 | |||
2176 | |||
2177 | //! Loads a scene. Note that the current scene is not cleared before. | ||
2178 | bool CSceneManager::loadScene(io::IReadFile* file, ISceneUserDataSerializer* userDataSerializer, ISceneNode* rootNode) | ||
2179 | { | ||
2180 | if (!file) | ||
2181 | { | ||
2182 | os::Printer::log("Unable to open scene file", ELL_ERROR); | ||
2183 | return false; | ||
2184 | } | ||
2185 | |||
2186 | bool ret = false; | ||
2187 | |||
2188 | // try scene loaders in reverse order | ||
2189 | s32 i = SceneLoaderList.size()-1; | ||
2190 | for (; i >= 0 && !ret; --i) | ||
2191 | if (SceneLoaderList[i]->isALoadableFileFormat(file)) | ||
2192 | ret = SceneLoaderList[i]->loadScene(file, userDataSerializer, rootNode); | ||
2193 | |||
2194 | if (!ret) | ||
2195 | os::Printer::log("Could not load scene file, perhaps the format is unsupported: ", file->getFileName().c_str(), ELL_ERROR); | ||
2196 | |||
2197 | return ret; | ||
2198 | } | ||
2199 | |||
2200 | |||
2201 | //! writes a scene node | ||
2202 | void CSceneManager::writeSceneNode(io::IXMLWriter* writer, ISceneNode* node, ISceneUserDataSerializer* userDataSerializer, | ||
2203 | const fschar_t* currentPath, bool init) | ||
2204 | { | ||
2205 | if (!writer || !node || node->isDebugObject()) | ||
2206 | return; | ||
2207 | |||
2208 | const wchar_t* name; | ||
2209 | ISceneNode* tmpNode=node; | ||
2210 | |||
2211 | if (init) | ||
2212 | { | ||
2213 | name = IRR_XML_FORMAT_SCENE.c_str(); | ||
2214 | writer->writeElement(name, false); | ||
2215 | node=this; | ||
2216 | } | ||
2217 | else | ||
2218 | { | ||
2219 | name = IRR_XML_FORMAT_NODE.c_str(); | ||
2220 | writer->writeElement(name, false, IRR_XML_FORMAT_NODE_ATTR_TYPE.c_str(), | ||
2221 | core::stringw(getSceneNodeTypeName(node->getType())).c_str()); | ||
2222 | } | ||
2223 | |||
2224 | writer->writeLineBreak(); | ||
2225 | |||
2226 | // write properties | ||
2227 | |||
2228 | io::IAttributes* attr = FileSystem->createEmptyAttributes(Driver); | ||
2229 | io::SAttributeReadWriteOptions options; | ||
2230 | if (currentPath) | ||
2231 | { | ||
2232 | options.Filename=currentPath; | ||
2233 | options.Flags|=io::EARWF_USE_RELATIVE_PATHS; | ||
2234 | } | ||
2235 | node->serializeAttributes(attr, &options); | ||
2236 | |||
2237 | if (attr->getAttributeCount() != 0) | ||
2238 | { | ||
2239 | attr->write(writer); | ||
2240 | writer->writeLineBreak(); | ||
2241 | } | ||
2242 | |||
2243 | // write materials | ||
2244 | |||
2245 | if (node->getMaterialCount() && Driver) | ||
2246 | { | ||
2247 | const wchar_t* materialElement = L"materials"; | ||
2248 | |||
2249 | writer->writeElement(materialElement); | ||
2250 | writer->writeLineBreak(); | ||
2251 | |||
2252 | for (u32 i=0; i < node->getMaterialCount(); ++i) | ||
2253 | { | ||
2254 | io::IAttributes* tmp_attr = | ||
2255 | Driver->createAttributesFromMaterial(node->getMaterial(i), &options); | ||
2256 | tmp_attr->write(writer); | ||
2257 | tmp_attr->drop(); | ||
2258 | } | ||
2259 | |||
2260 | writer->writeClosingTag(materialElement); | ||
2261 | writer->writeLineBreak(); | ||
2262 | } | ||
2263 | |||
2264 | // write animators | ||
2265 | |||
2266 | if (!node->getAnimators().empty()) | ||
2267 | { | ||
2268 | const wchar_t* animatorElement = L"animators"; | ||
2269 | writer->writeElement(animatorElement); | ||
2270 | writer->writeLineBreak(); | ||
2271 | |||
2272 | ISceneNodeAnimatorList::ConstIterator it = node->getAnimators().begin(); | ||
2273 | for (; it != node->getAnimators().end(); ++it) | ||
2274 | { | ||
2275 | attr->clear(); | ||
2276 | attr->addString("Type", getAnimatorTypeName((*it)->getType())); | ||
2277 | |||
2278 | (*it)->serializeAttributes(attr); | ||
2279 | |||
2280 | attr->write(writer); | ||
2281 | } | ||
2282 | |||
2283 | writer->writeClosingTag(animatorElement); | ||
2284 | writer->writeLineBreak(); | ||
2285 | } | ||
2286 | |||
2287 | // write possible user data | ||
2288 | |||
2289 | if (userDataSerializer) | ||
2290 | { | ||
2291 | io::IAttributes* userData = userDataSerializer->createUserData(node); | ||
2292 | if (userData) | ||
2293 | { | ||
2294 | const wchar_t* userDataElement = L"userData"; | ||
2295 | |||
2296 | writer->writeLineBreak(); | ||
2297 | writer->writeElement(userDataElement); | ||
2298 | writer->writeLineBreak(); | ||
2299 | |||
2300 | userData->write(writer); | ||
2301 | |||
2302 | writer->writeClosingTag(userDataElement); | ||
2303 | writer->writeLineBreak(); | ||
2304 | writer->writeLineBreak(); | ||
2305 | |||
2306 | userData->drop(); | ||
2307 | } | ||
2308 | } | ||
2309 | // reset to actual root node | ||
2310 | if (init) | ||
2311 | node=tmpNode; | ||
2312 | |||
2313 | // write children once root node is written | ||
2314 | // if parent is not scene manager, we need to write out node first | ||
2315 | if (init && (node != this)) | ||
2316 | { | ||
2317 | writeSceneNode(writer, node, userDataSerializer, currentPath); | ||
2318 | } | ||
2319 | else | ||
2320 | { | ||
2321 | ISceneNodeList::ConstIterator it = node->getChildren().begin(); | ||
2322 | for (; it != node->getChildren().end(); ++it) | ||
2323 | writeSceneNode(writer, (*it), userDataSerializer, currentPath); | ||
2324 | } | ||
2325 | |||
2326 | attr->drop(); | ||
2327 | |||
2328 | writer->writeClosingTag(name); | ||
2329 | writer->writeLineBreak(); | ||
2330 | writer->writeLineBreak(); | ||
2331 | } | ||
2332 | |||
2333 | |||
2334 | //! Returns a typename from a scene node type or null if not found | ||
2335 | const c8* CSceneManager::getSceneNodeTypeName(ESCENE_NODE_TYPE type) | ||
2336 | { | ||
2337 | const char* name = 0; | ||
2338 | |||
2339 | for (s32 i=(s32)SceneNodeFactoryList.size()-1; !name && i>=0; --i) | ||
2340 | name = SceneNodeFactoryList[i]->getCreateableSceneNodeTypeName(type); | ||
2341 | |||
2342 | return name; | ||
2343 | } | ||
2344 | |||
2345 | //! Adds a scene node to the scene by name | ||
2346 | ISceneNode* CSceneManager::addSceneNode(const char* sceneNodeTypeName, ISceneNode* parent) | ||
2347 | { | ||
2348 | ISceneNode* node = 0; | ||
2349 | |||
2350 | for (s32 i=(s32)SceneNodeFactoryList.size()-1; i>=0 && !node; --i) | ||
2351 | node = SceneNodeFactoryList[i]->addSceneNode(sceneNodeTypeName, parent); | ||
2352 | |||
2353 | return node; | ||
2354 | } | ||
2355 | |||
2356 | ISceneNodeAnimator* CSceneManager::createSceneNodeAnimator(const char* typeName, ISceneNode* target) | ||
2357 | { | ||
2358 | ISceneNodeAnimator *animator = 0; | ||
2359 | |||
2360 | for (s32 i=(s32)SceneNodeAnimatorFactoryList.size()-1; i>=0 && !animator; --i) | ||
2361 | animator = SceneNodeAnimatorFactoryList[i]->createSceneNodeAnimator(typeName, target); | ||
2362 | |||
2363 | return animator; | ||
2364 | } | ||
2365 | |||
2366 | |||
2367 | //! Returns a typename from a scene node animator type or null if not found | ||
2368 | const c8* CSceneManager::getAnimatorTypeName(ESCENE_NODE_ANIMATOR_TYPE type) | ||
2369 | { | ||
2370 | const char* name = 0; | ||
2371 | |||
2372 | for (s32 i=SceneNodeAnimatorFactoryList.size()-1; !name && i >= 0; --i) | ||
2373 | name = SceneNodeAnimatorFactoryList[i]->getCreateableSceneNodeAnimatorTypeName(type); | ||
2374 | |||
2375 | return name; | ||
2376 | } | ||
2377 | |||
2378 | |||
2379 | //! Writes attributes of the scene node. | ||
2380 | void CSceneManager::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const | ||
2381 | { | ||
2382 | out->addString ("Name", Name.c_str()); | ||
2383 | out->addInt ("Id", ID ); | ||
2384 | out->addColorf ("AmbientLight", AmbientLight); | ||
2385 | |||
2386 | // fog attributes from video driver | ||
2387 | video::SColor color; | ||
2388 | video::E_FOG_TYPE fogType; | ||
2389 | f32 start, end, density; | ||
2390 | bool pixelFog, rangeFog; | ||
2391 | |||
2392 | Driver->getFog(color, fogType, start, end, density, pixelFog, rangeFog); | ||
2393 | |||
2394 | out->addEnum("FogType", fogType, video::FogTypeNames); | ||
2395 | out->addColorf("FogColor", color); | ||
2396 | out->addFloat("FogStart", start); | ||
2397 | out->addFloat("FogEnd", end); | ||
2398 | out->addFloat("FogDensity", density); | ||
2399 | out->addBool("FogPixel", pixelFog); | ||
2400 | out->addBool("FogRange", rangeFog); | ||
2401 | } | ||
2402 | |||
2403 | //! Reads attributes of the scene node. | ||
2404 | void CSceneManager::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) | ||
2405 | { | ||
2406 | Name = in->getAttributeAsString("Name"); | ||
2407 | ID = in->getAttributeAsInt("Id"); | ||
2408 | AmbientLight = in->getAttributeAsColorf("AmbientLight"); | ||
2409 | |||
2410 | // fog attributes | ||
2411 | video::SColor color; | ||
2412 | video::E_FOG_TYPE fogType; | ||
2413 | f32 start, end, density; | ||
2414 | bool pixelFog, rangeFog; | ||
2415 | if (in->existsAttribute("FogType")) | ||
2416 | { | ||
2417 | fogType = (video::E_FOG_TYPE) in->getAttributeAsEnumeration("FogType", video::FogTypeNames); | ||
2418 | color = in->getAttributeAsColorf("FogColor").toSColor(); | ||
2419 | start = in->getAttributeAsFloat("FogStart"); | ||
2420 | end = in->getAttributeAsFloat("FogEnd"); | ||
2421 | density = in->getAttributeAsFloat("FogDensity"); | ||
2422 | pixelFog = in->getAttributeAsBool("FogPixel"); | ||
2423 | rangeFog = in->getAttributeAsBool("FogRange"); | ||
2424 | Driver->setFog(color, fogType, start, end, density, pixelFog, rangeFog); | ||
2425 | } | ||
2426 | |||
2427 | RelativeTranslation.set(0,0,0); | ||
2428 | RelativeRotation.set(0,0,0); | ||
2429 | RelativeScale.set(1,1,1); | ||
2430 | IsVisible = true; | ||
2431 | AutomaticCullingState = scene::EAC_BOX; | ||
2432 | DebugDataVisible = scene::EDS_OFF; | ||
2433 | IsDebugObject = false; | ||
2434 | |||
2435 | updateAbsolutePosition(); | ||
2436 | } | ||
2437 | |||
2438 | |||
2439 | //! Sets ambient color of the scene | ||
2440 | void CSceneManager::setAmbientLight(const video::SColorf &ambientColor) | ||
2441 | { | ||
2442 | AmbientLight = ambientColor; | ||
2443 | } | ||
2444 | |||
2445 | |||
2446 | //! Returns ambient color of the scene | ||
2447 | const video::SColorf& CSceneManager::getAmbientLight() const | ||
2448 | { | ||
2449 | return AmbientLight; | ||
2450 | } | ||
2451 | |||
2452 | |||
2453 | //! Get a skinned mesh, which is not available as header-only code | ||
2454 | ISkinnedMesh* CSceneManager::createSkinnedMesh() | ||
2455 | { | ||
2456 | #ifdef _IRR_COMPILE_WITH_SKINNED_MESH_SUPPORT_ | ||
2457 | return new CSkinnedMesh(); | ||
2458 | #else | ||
2459 | return 0; | ||
2460 | #endif | ||
2461 | } | ||
2462 | |||
2463 | //! Returns a mesh writer implementation if available | ||
2464 | IMeshWriter* CSceneManager::createMeshWriter(EMESH_WRITER_TYPE type) | ||
2465 | { | ||
2466 | switch(type) | ||
2467 | { | ||
2468 | case EMWT_IRR_MESH: | ||
2469 | #ifdef _IRR_COMPILE_WITH_IRR_WRITER_ | ||
2470 | return new CIrrMeshWriter(Driver, FileSystem); | ||
2471 | #else | ||
2472 | return 0; | ||
2473 | #endif | ||
2474 | case EMWT_COLLADA: | ||
2475 | #ifdef _IRR_COMPILE_WITH_COLLADA_WRITER_ | ||
2476 | return new CColladaMeshWriter(this, Driver, FileSystem); | ||
2477 | #else | ||
2478 | return 0; | ||
2479 | #endif | ||
2480 | case EMWT_STL: | ||
2481 | #ifdef _IRR_COMPILE_WITH_STL_WRITER_ | ||
2482 | return new CSTLMeshWriter(this); | ||
2483 | #else | ||
2484 | return 0; | ||
2485 | #endif | ||
2486 | case EMWT_OBJ: | ||
2487 | #ifdef _IRR_COMPILE_WITH_OBJ_WRITER_ | ||
2488 | return new COBJMeshWriter(this, FileSystem); | ||
2489 | #else | ||
2490 | return 0; | ||
2491 | #endif | ||
2492 | |||
2493 | case EMWT_PLY: | ||
2494 | #ifdef _IRR_COMPILE_WITH_PLY_WRITER_ | ||
2495 | return new CPLYMeshWriter(); | ||
2496 | #else | ||
2497 | return 0; | ||
2498 | #endif | ||
2499 | } | ||
2500 | |||
2501 | return 0; | ||
2502 | } | ||
2503 | |||
2504 | |||
2505 | // creates a scenemanager | ||
2506 | ISceneManager* createSceneManager(video::IVideoDriver* driver, | ||
2507 | io::IFileSystem* fs, gui::ICursorControl* cursorcontrol, | ||
2508 | gui::IGUIEnvironment *guiEnvironment) | ||
2509 | { | ||
2510 | return new CSceneManager(driver, fs, cursorcontrol, 0, guiEnvironment ); | ||
2511 | } | ||
2512 | |||
2513 | |||
2514 | } // end namespace scene | ||
2515 | } // end namespace irr | ||
2516 | |||