From 24989c4487f4a322d164aca107b5f749baabcc70 Mon Sep 17 00:00:00 2001 From: teella Date: Sun, 6 Jan 2008 13:13:24 +0000 Subject: [PATCH] Volumetric lighting for Irrlicht Example useage added to 08.Special FX demo git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@1160 dfc29bdd-3216-0410-991c-e03cc46cb475 --- examples/08.SpecialFX/main.cpp | 15 + include/ISceneManager.h | 2475 ++++----- media/lightFalloff.png | Bin 0 -> 43385 bytes source/Irrlicht/CSceneManager.cpp | 4439 +++++++++-------- source/Irrlicht/CSceneManager.h | 8 + source/Irrlicht/CVolumeLightSceneNode.cpp | 301 ++ source/Irrlicht/CVolumeLightSceneNode.h | 98 + .../MacOSX/MacOSX.xcodeproj/project.pbxproj | 86 +- 8 files changed, 3947 insertions(+), 3475 deletions(-) create mode 100644 media/lightFalloff.png create mode 100644 source/Irrlicht/CVolumeLightSceneNode.cpp create mode 100644 source/Irrlicht/CVolumeLightSceneNode.h diff --git a/examples/08.SpecialFX/main.cpp b/examples/08.SpecialFX/main.cpp index 5ac743e9..dcfc1645 100644 --- a/examples/08.SpecialFX/main.cpp +++ b/examples/08.SpecialFX/main.cpp @@ -214,6 +214,21 @@ int main() anode->setPosition(core::vector3df(-50,20,-60)); anode->setAnimationSpeed(15); + //volumetric lighting + scene::ISceneNode * n = smgr->addVolumeLightSceneNode(NULL, -1, + 32, //Sub Divid U + 32, //Sub Divid V + video::SColor(0, 180, 180, 180), //foot colour + video::SColor(0, 0, 0, 0) //tail colour + ); + + if (n) { + n->setScale(core::vector3df(56.0f, 56.0f, 56.0f)); + n->setPosition(core::vector3df(-120,60,40)); + video::SMaterial& mat = n->getMaterial(0); + mat.setTexture(0, smgr->getVideoDriver()->getTexture("../../media/lightFalloff.png")); + } + // add shadow anode->addShadowVolumeSceneNode(); smgr->setShadowColor(video::SColor(150,0,0,0)); diff --git a/include/ISceneManager.h b/include/ISceneManager.h index d17b32cf..d5790824 100644 --- a/include/ISceneManager.h +++ b/include/ISceneManager.h @@ -1,1225 +1,1250 @@ -// Copyright (C) 2002-2007 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#ifndef __I_SCENE_MANAGER_H_INCLUDED__ -#define __I_SCENE_MANAGER_H_INCLUDED__ - -#include "IReferenceCounted.h" -#include "irrArray.h" -#include "vector3d.h" -#include "dimension2d.h" -#include "SColor.h" -#include "ETerrainElements.h" -#include "ESceneNodeTypes.h" -#include "EMeshWriterEnums.h" -#include "SceneParameters.h" - -namespace irr -{ - struct SKeyMap; - struct SEvent; - -namespace io -{ - class IReadFile; - class IAttributes; - class IWriteFile; -} // end namespace io - -namespace gui -{ - class IGUIFont; - class IGUIEnvironment; -} // end namespace gui - -namespace video -{ - class IVideoDriver; - class SMaterial; - class IImage; - class ITexture; -} // end namespace video - -namespace scene -{ - class IMeshWriter; - - //! Enumeration for render passes. - /** A parameter passed to the registerNodeForRendering() method of the ISceneManager, - specifying when the mode wants to be drawn in relation to the other nodes. */ - enum E_SCENE_NODE_RENDER_PASS - { - //! Camera pass. The active view is set up here. - //! The very first pass. - ESNRP_CAMERA, - - //! In this pass, lights are transformed into camera space and added to the driver - ESNRP_LIGHT, - - //! This is used for sky boxes. - ESNRP_SKY_BOX, - - //! All normal objects can use this for registering themselves. - //! This value will never be returned by ISceneManager::getSceneNodeRenderPass(). - //! The scene manager will determine by itself if an object is - //! transparent or solid and register the object as SNRT_TRANSPARENT or - //! SNRT_SOLD automatically if you call registerNodeForRendering with this - //! value (which is default). Note that it will register the node only as ONE type. - //! If your scene node has both solid and transparent material types register - //! it twice (one time as SNRT_SOLID, the other time as SNRT_TRANSPARENT) and - //! in the render() method call getSceneNodeRenderPass() to find out the current - //! render pass and render only the corresponding parts of the node. - ESNRP_AUTOMATIC, - - //! Solid scene nodes or special scene nodes without materials. - ESNRP_SOLID, - - //! Drawn after the transparent nodes, the time for drawing shadow volumes - ESNRP_SHADOW, - - //! Transparent scene nodes, drawn after shadow nodes. They are sorted from back - //! to front and drawn in that order. - ESNRP_TRANSPARENT, - - //! Never used, value specifing how much parameters there are. - ESNRP_COUNT - }; - - class IMesh; - class IMeshBuffer; - class IAnimatedMesh; - class IMeshCache; - class ISceneNode; - class ICameraSceneNode; - class IAnimatedMeshSceneNode; - class ISceneNodeAnimator; - class ISceneNodeAnimatorCollisionResponse; - class ILightSceneNode; - class IBillboardSceneNode; - class ITerrainSceneNode; - class IMeshSceneNode; - class IMeshLoader; - class ISceneCollisionManager; - class IParticleSystemSceneNode; - class IDummyTransformationSceneNode; - class ITriangleSelector; - class IMetaTriangleSelector; - class IMeshManipulator; - class ITextSceneNode; - class ISceneNodeFactory; - class ISceneNodeAnimatorFactory; - class ISceneUserDataSerializer; - - namespace quake3 - { - class SShader; - } // end namespace quake3 - - //! The Scene Manager manages scene nodes, mesh recources, cameras and all the other stuff. - /** All Scene nodes can be created only here. There is a always growing list of scene - nodes for lots of purposes: Indoor rendering scene nodes like the Octree - (addOctTreeSceneNode()) or the terrain renderer (addTerrainSceneNode()), - different Camera scene nodes (addCameraSceneNode(), addCameraSceneNodeMaya()), - scene nodes for Light (addLightSceneNode()), Billboards (addBillboardSceneNode()) - and so on. - A scene node is a node in the hierachical scene graph. Every scene node may have children, - which are other scene nodes. Children move relative the their parents position. If the parent of a node is not - visible, its children won't be visible, too. In this way, it is for example easily possible - to attach a light to a moving car or to place a walking character on a moving platform - on a moving ship. - The SceneManager is also able to load 3d mesh files of different formats. Take a look - at getMesh() to find out what formats are supported. And if these formats are not enough - use addExternalMeshLoader() to add new formats to the engine. - */ - class ISceneManager : public virtual IReferenceCounted - { - public: - - //! destructor - virtual ~ISceneManager() {} - - //! Returns pointer to an animateable mesh. Loads the file if not loaded already. - /** - * If you want to remove a loaded mesh from the cache again, use removeMesh(). - * Currently there are the following mesh formats supported: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
FormatDescription
3D Studio (.3ds)Loader for 3D-Studio files which lots of 3D packages are able to export. - * Only static meshes are currently supported by this importer.
Bliz Basic B3D (.b3d)Loader for blitz basic files, developed by Mark Sibly, also supports animations.
Cartography shop 4 (.csm)Cartography Shop is a modeling program for creating architecture and calculating - * lighting. Irrlicht can directly import .csm files thanks to the IrrCSM library - * created by Saurav Mohapatra which is now integrated directly in Irrlicht. - * If you are using this loader, please note that you'll have to set the path - * of the textures before loading .csm files. You can do this using SceneManager->getParameters()->setParameter(scene::CSM_TEXTURE_PATH, - * "path/to/your/textures");
COLLADA (.dae, .xml)COLLADA is an open Digital Asset Exchange Schema for the interactive 3D industry. There are - * exporters and importers for this format available for most of the big 3d packages - * at http://collada.org. Irrlicht can import COLLADA files by using the - * ISceneManager::getMesh() method. COLLADA files need not contain only one single mesh - * but multiple meshes and a whole scene setup with lights, cameras and mesh instances, - * this loader can set up a scene as described by the COLLADA file instead of loading - * and returning one single mesh. By default, this loader behaves like the other loaders - * and does not create instances, but it can be switched into this mode by using - * SceneManager->getParameters()->setParameter(COLLADA_CREATE_SCENE_INSTANCES, true); - * Created scene nodes will be named as the names of the nodes in the - * COLLADA file. The returned mesh is just a dummy object in this mode. Meshes included in - * the scene will be added into the scene manager with the following naming scheme: - * path/to/file/file.dea#meshname. The loading of such meshes is logged. - * Currently, this loader is able to create meshes (made of only polygons), lights, - * and cameras. Materials and animations are currently not supported but this will - * change with future releases. - *
Delgine DeleD (.dmf)DeleD (delgine.com) is a 3D editor and level-editor combined into one and is specifically - * designed for 3D game-development. With this loader, it is possible to directly load - * all geometry is as well as textures and lightmaps from .dmf files. To set texture and - * material paths, see scene::DMF_USE_MATERIALS_DIRS and scene::DMF_TEXTURE_PATH. It is also - * possible to flip the alpha texture by setting scene::DMF_FLIP_ALPHA_TEXTURES to true and - * to set the material transparent reference value by setting scene::DMF_ALPHA_CHANNEL_REF to - * a float between 0 and 1. The loader is - * based on Salvatore Russo's .dmf loader, I just changed some parts of it. Thanks to - * Salvatore for his work and for allowing me to use his code in Irrlicht and put it under Irrlicht's - * license. For newer and more enchanced versions of the loader, take a look at delgine.com. - *
DirectX (.x)Platform independent importer (so not D3D-only) for .x files. Most 3D - * packages can export these natively and there are several tools for them - * available. (e.g. the Maya exporter included in the DX SDK) .x files can - * include skeletal animations and Irrlicht is able to play and display them. - * Currently, Irrlicht only supports uncompressed .x files.
Maya (.obj)Most 3D software can create .obj files which contain static geometry without - * material data. The material files .mtl are also supported. This importer - * for Irrlicht can load them directly.
Milkshape (.ms3d).MS3D files contain models and sometimes skeletal animations from the - * Milkshape 3D modeling and animation software. This importer for Irrlicht - * can display and/or animate these files.
My3D (.my3d).my3D is a flexible 3D file format. The My3DTools contains plug-ins to - * export .my3D files from several 3D packages. With this built-in importer, - * Irrlicht can read and display those files directly. This loader was written - * by Zhuck Dimitry who also created the whole My3DTools package. If you are using this loader, please - * note that you can set the path of the textures before loading .my3d files. - * You can do this using SceneManager->getParameters()->setParameter(scene::MY3D_TEXTURE_PATH, - * "path/to/your/textures");
OCT (.oct)The oct file format contains 3D geometry and lightmaps and can be loaded - * directly by Irrlicht. OCT files
- * can be created by FSRad, Paul Nette's radiosity processor or exported from - * Blender using OCTTools which can be found in the exporters/OCTTools directory - * of the SDK. Thanks to Murphy McCauley for creating all this.
OGRE Meshes (.mesh)Ogre .mesh files contain 3D data for the OGRE 3D engine. Irrlicht can read and - * display them directly with this importer. To define materials for the mesh, - * copy a .material file named like the corresponding .mesh file where the .mesh - * file is. (For example ogrehead.material for ogrehead.mesh). Thanks to Christian Stehno - * who wrote and contributed this loader.
Pulsar LMTools (.lmts)LMTools is a set of tools (Windows & Linux) for creating lightmaps. - * Irrlicht can directly read .lmts files thanks to
- * the importer created by Jonas Petersen. If you are using this loader, please - * note that you can set the path of the textures before loading .lmts files. - * You can do this using SceneManager->getParameters()->setParameter(scene::LMTS_TEXTURE_PATH, - * "path/to/your/textures"); Notes for
- * this version of the loader:
- * - It does not recognice/support user data in the *.lmts files.
- * - The TGAs generated by LMTools don't work in Irrlicht for some reason (the - * textures are upside down). Opening and resaving them in a graphics app will - * solve the problem.
Quake 3 levels (.bsp)Quake 3 is a popular game by IDSoftware, and .pk3 files contain .bsp files - * and textures/lightmaps describing huge
- * prelighted levels. Irrlicht can read .pk3 and .bsp files directly and thus - * render Quake 3 levels directly. Written by Nikolaus Gebhardt enhanced by - * Dean P. Macri with the curved surfaces feature.
Quake 2 models (.md2)Quake 2 models are characters with morph target animation. Irrlicht can - * read, display and animate them directly with this importer.
- * - * To load and display a mesh quickly, just do this: - * \code - * SceneManager->addAnimatedMeshSceneNode( - * SceneManager->getMesh("yourmesh.3ds")); - * \endcode - * If you would like to implement and add your own file format loader to Irrlicht, - * see addExternalMeshLoader(). - * \param filename: Filename of the mesh to load. - * \return Returns NULL if failed and the pointer to the mesh if - * successful. - * This pointer should not be dropped. See IReferenceCounted::drop() for more information. - **/ - virtual IAnimatedMesh* getMesh(const c8* filename) = 0; - - //! Returns an interface to the mesh cache which is shared beween all existing scene managers. - /** With this interface, it is possible to manually add new loaded - meshes (if ISceneManager::getMesh() is not sufficient), to remove them and to iterate - through already loaded meshes. */ - virtual IMeshCache* getMeshCache() = 0; - - //! Returns the video driver. - /** \return Returns pointer to the video Driver. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual video::IVideoDriver* getVideoDriver() = 0; - - //! Returns the active GUIEnvironment - /** \return Returns pointer to the GUIEnvironment - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual gui::IGUIEnvironment* getGUIEnvironment() = 0; - - //! Adds a test scene node for test purposes to the scene. - /** It is a simple cube of (1,1,1) size. - \param size: Size of the cube. - \param parent: Parent of the scene node. Can be NULL if no parent. - \param id: Id of the node. This id can be used to identify the scene node. - \param position: Position of the space relative to its parent where the - scene node will be placed. - \param rotation: Initital rotation of the scene node. - \param scale: Initial scale of the scene node. - \return Returns pointer to the created test scene node. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual ISceneNode* addCubeSceneNode(f32 size=10.0f, ISceneNode* parent=0, s32 id=-1, - const core::vector3df& position = core::vector3df(0,0,0), - const core::vector3df& rotation = core::vector3df(0,0,0), - const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) = 0; - - //! Adds a sphere scene node for test purposes to the scene. - /** It is a simple sphere. - \param radius: Radius of the sphere. - \param polyCount: Polycount of the sphere. - \param parent: Parent of the scene node. Can be NULL if no parent. - \param id: Id of the node. This id can be used to identify the scene node. - \param position: Position of the space relative to its parent where the - scene node will be placed. - \param rotation: Initital rotation of the scene node. - \param scale: Initial scale of the scene node. - \return Returns pointer to the created test scene node. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual ISceneNode* addSphereSceneNode(f32 radius=5.0f, s32 polyCount=16, ISceneNode* parent=0, s32 id=-1, - const core::vector3df& position = core::vector3df(0,0,0), - const core::vector3df& rotation = core::vector3df(0,0,0), - const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) = 0; - - //! Adds a scene node for rendering an animated mesh model. - /** \param mesh: Pointer to the loaded animated mesh to be displayed. - \param parent: Parent of the scene node. Can be NULL if no parent. - \param id: Id of the node. This id can be used to identify the scene node. - \param position: Position of the space relative to its parent where the - scene node will be placed. - \param rotation: Initital rotation of the scene node. - \param scale: Initial scale of the scene node. - \param alsoAddIfMeshPointerZero: Add the scene node even if a 0 pointer is passed. - \return Returns pointer to the created scene node. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual IAnimatedMeshSceneNode* addAnimatedMeshSceneNode(IAnimatedMesh* mesh, ISceneNode* parent=0, s32 id=-1, - const core::vector3df& position = core::vector3df(0,0,0), - const core::vector3df& rotation = core::vector3df(0,0,0), - const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f), - bool alsoAddIfMeshPointerZero=false) = 0; - - //! Adds a scene node for rendering a static mesh. - /** \param mesh: Pointer to the loaded static mesh to be displayed. - \param parent: Parent of the scene node. Can be NULL if no parent. - \param id: Id of the node. This id can be used to identify the scene node. - \param position: Position of the space relative to its parent where the - scene node will be placed. - \param rotation: Initital rotation of the scene node. - \param scale: Initial scale of the scene node. - \param alsoAddIfMeshPointerZero: Add the scene node even if a 0 pointer is passed. - \return Returns pointer to the created scene node. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual IMeshSceneNode* addMeshSceneNode(IMesh* mesh, ISceneNode* parent=0, s32 id=-1, - const core::vector3df& position = core::vector3df(0,0,0), - const core::vector3df& rotation = core::vector3df(0,0,0), - const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f), - bool alsoAddIfMeshPointerZero=false) = 0; - - //! Adds a scene node for rendering a animated water surface mesh. - /** Looks really good when the Material type EMT_TRANSPARENT_REFLECTION - is used. - \param waveHeight: Height of the water waves. - \param waveSpeed: Speed of the water waves. - \param waveLength: Lenght of a water wave. - \param mesh: Pointer to the loaded static mesh to be displayed with water waves on it. - \param parent: Parent of the scene node. Can be NULL if no parent. - \param id: Id of the node. This id can be used to identify the scene node. - \param position: Position of the space relative to its parent where the - scene node will be placed. - \param rotation: Initital rotation of the scene node. - \param scale: Initial scale of the scene node. - \return Returns pointer to the created scene node. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual ISceneNode* addWaterSurfaceSceneNode(IMesh* mesh, - f32 waveHeight=2.0f, f32 waveSpeed=300.0f, f32 waveLength=10.0f, - ISceneNode* parent=0, s32 id=-1, - const core::vector3df& position = core::vector3df(0,0,0), - const core::vector3df& rotation = core::vector3df(0,0,0), - const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) = 0; - - - //! Adds a scene node for rendering using a octtree to the scene graph. - /** This a good method for rendering - scenes with lots of geometry. The Octree is built on the fly from the mesh. - \param mesh: The mesh containing all geometry from which the octtree will be build. - If this animated mesh has more than one frames in it, the first frame is taken. - \param parent: Parent node of the octtree node. - \param id: id of the node. This id can be used to identify the node. - \param minimalPolysPerNode: Specifies the minimal polygons contained a octree node. - If a node gets less polys than this value it will not be split into - smaller nodes. - \param alsoAddIfMeshPointerZero: Add the scene node even if a 0 pointer is passed. - \return Returns the pointer to the OctTree if successful, otherwise 0. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual ISceneNode* addOctTreeSceneNode(IAnimatedMesh* mesh, ISceneNode* parent=0, - s32 id=-1, s32 minimalPolysPerNode=256, bool alsoAddIfMeshPointerZero=false) = 0; - - //! Adds a scene node for rendering using a octtree to the scene graph. - /** This a good method for rendering - scenes with lots of geometry. The Octree is built on the fly from the mesh, much - faster then a bsp tree. - \param mesh: The mesh containing all geometry from which the octtree will be build. - \param parent: Parent node of the octtree node. - \param id: id of the node. This id can be used to identify the node. - \param minimalPolysPerNode: Specifies the minimal polygons contained a octree node. - If a node gets less polys than this value it will not be split into - smaller nodes. - \param alsoAddIfMeshPointerZero: Add the scene node even if a 0 pointer is passed. - \return Returns the pointer to the octtree if successful, otherwise 0. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual ISceneNode* addOctTreeSceneNode(IMesh* mesh, ISceneNode* parent=0, - s32 id=-1, s32 minimalPolysPerNode=256, bool alsoAddIfMeshPointerZero=false) = 0; - - //! Adds a camera scene node to the scene graph and sets it as active camera. - /** This camera does not react on user input like for example the one created with - addCameraSceneNodeFPS(). If you want to move or animate it, use animators or the - ISceneNode::setPosition(), ICameraSceneNode::setTarget() etc methods. - \param position: Position of the space relative to its parent where the camera will be placed. - \param lookat: Position where the camera will look at. Also known as target. - \param parent: Parent scene node of the camera. Can be null. If the parent moves, - the camera will move too. - \param id: id of the camera. This id can be used to identify the camera. - \return Returns pointer to interface to camera if successful, otherwise 0. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual ICameraSceneNode* addCameraSceneNode(ISceneNode* parent = 0, - const core::vector3df& position = core::vector3df(0,0,0), - const core::vector3df& lookat = core::vector3df(0,0,100), s32 id=-1) = 0; - - //! Adds a maya style user controlled camera scene node to the scene graph. - /** The maya camera is able to be controlled with the mouse similar - like in the 3D Software Maya by Alias Wavefront. - \param parent: Parent scene node of the camera. Can be null. - \param rotateSpeed: Rotation speed of the camera. - \param zoomSpeed: Zoom speed of the camera. - \param translationSpeed: TranslationSpeed of the camera. - \param id: id of the camera. This id can be used to identify the camera. - \return Returns a pointer to the interface of the camera if successful, otherwise 0. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual ICameraSceneNode* addCameraSceneNodeMaya(ISceneNode* parent = 0, - f32 rotateSpeed = -1500.0f, f32 zoomSpeed = 200.0f, f32 translationSpeed = 1500.0f, s32 id=-1) = 0; - - //! Adds a camera scene node which is able to be controlled with the mouse and keys like in most first person shooters (FPS). - /** Look with the mouse, move with cursor keys. If you do not like the default - key layout, you may want to specify your own. For example to make the camera - be controlled by the cursor keys AND the keys W,A,S, and D, do something - like this: - \code - SKeyMap keyMap[8]; - keyMap[0].Action = EKA_MOVE_FORWARD; - keyMap[0].KeyCode = KEY_UP; - keyMap[1].Action = EKA_MOVE_FORWARD; - keyMap[1].KeyCode = KEY_KEY_W; - - keyMap[2].Action = EKA_MOVE_BACKWARD; - keyMap[2].KeyCode = KEY_DOWN; - keyMap[3].Action = EKA_MOVE_BACKWARD; - keyMap[3].KeyCode = KEY_KEY_S; - - keyMap[4].Action = EKA_STRAFE_LEFT; - keyMap[4].KeyCode = KEY_LEFT; - keyMap[5].Action = EKA_STRAFE_LEFT; - keyMap[5].KeyCode = KEY_KEY_A; - - keyMap[6].Action = EKA_STRAFE_RIGHT; - keyMap[6].KeyCode = KEY_RIGHT; - keyMap[7].Action = EKA_STRAFE_RIGHT; - keyMap[7].KeyCode = KEY_KEY_D; - - camera = sceneManager->addCameraSceneNodeFPS(0, 100, 500, -1, keyMap, 8); - \endcode - \param parent: Parent scene node of the camera. Can be null. - \param rotateSpeed: Speed with which the camera is rotated. This can be done - only with the mouse. - \param moveSpeed: Speed with which the camera is moved. Movement is done with - the cursor keys. - \param id: id of the camera. This id can be used to identify the camera. - \param keyMapArray: Optional pointer to an array of a keymap, specifying what - keys should be used to move the camera. If this is null, the default keymap - is used. You can define actions more then one time in the array, to bind - multiple keys to the same action. - \param keyMapSize: Amount of items in the keymap array. - \param noVerticalMovement: Setting this to true makes the camera only move within a - horizontal plane, and disables vertical movement as known from most ego shooters. Default - is 'false', with which it is possible to fly around in space, if no gravity is there. - \param jumpSpeed: Speed with which the camera is moved when jumping. - \return Returns a pointer to the interface of the camera if successful, otherwise 0. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual ICameraSceneNode* addCameraSceneNodeFPS(ISceneNode* parent = 0, - f32 rotateSpeed = 100.0f, f32 moveSpeed = 500.0f, s32 id=-1, - SKeyMap* keyMapArray=0, s32 keyMapSize=0, bool noVerticalMovement=false, - f32 jumpSpeed = 0.f) = 0; - - //! Adds a dynamic light scene node to the scene graph. - /** The light will cast dynamic light on all - other scene nodes in the scene, which have the material flag video::MTF_LIGHTING - turned on. (This is the default setting in most scene nodes). - \param parent: Parent scene node of the light. Can be null. If the parent moves, - the light will move too. - \param position: Position of the space relative to its parent where the light will be placed. - \param color: Diffuse color of the light. Ambient or Specular colors can be set manually with - the ILightSceneNode::getLightData() method. - \param radius: Radius of the light. - \param id: id of the node. This id can be used to identify the node. - \return Returns pointer to the interface of the light if successful, otherwise NULL. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual ILightSceneNode* addLightSceneNode(ISceneNode* parent = 0, - const core::vector3df& position = core::vector3df(0,0,0), - video::SColorf color = video::SColorf(1.0f, 1.0f, 1.0f), - f32 radius=100.0f, s32 id=-1) = 0; - - //! Adds a billboard scene node to the scene graph. - /** A billboard is like a 3d sprite: A 2d element, - which always looks to the camera. It is usually used for things like explosions, fire, - lensflares and things like that. - \param parent: Parent scene node of the billboard. Can be null. If the parent moves, - the billboard will move too. - \param position: Position of the space relative to its parent where the billboard will be placed. - \param size: Size of the billboard. This size is 2 dimensional because a billboard only has - width and height. - \param id: An id of the node. This id can be used to identify the node. - \param shade_top: vertex color top - \param shade_down: vertex color down - \return Returns pointer to the billboard if successful, otherwise NULL. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual IBillboardSceneNode* addBillboardSceneNode(ISceneNode* parent = 0, - const core::dimension2d& size = core::dimension2d(10.0f, 10.0f), - const core::vector3df& position = core::vector3df(0,0,0), s32 id=-1, - video::SColor shade_top = 0xFFFFFFFF, video::SColor shade_down = 0xFFFFFFFF) = 0; - - //! Adds a skybox scene node to the scene graph. - /** A skybox is a big cube with 6 textures on it and - is drawn around the camera position. - \param top: Texture for the top plane of the box. - \param bottom: Texture for the bottom plane of the box. - \param left: Texture for the left plane of the box. - \param right: Texture for the right plane of the box. - \param front: Texture for the front plane of the box. - \param back: Texture for the back plane of the box. - \param parent: Parent scene node of the skybox. A skybox usually has no parent, - so this should be null. Note: If a parent is set to the skybox, the box will not - change how it is drawn. - \param id: An id of the node. This id can be used to identify the node. - \return Returns a pointer to the sky box if successful, otherwise NULL. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual ISceneNode* addSkyBoxSceneNode(video::ITexture* top, video::ITexture* bottom, - video::ITexture* left, video::ITexture* right, video::ITexture* front, - video::ITexture* back, ISceneNode* parent = 0, s32 id=-1) = 0; - - //! Adds a skydome scene node to the scene graph. - /** A skydome is a large (half-) sphere with a panoramic texture - on the inside and is drawn around the camera position. - \param texture: Texture for the dome. - \param horiRes: Number of vertices of a horizontal layer of the sphere. - \param vertRes: Number of vertices of a vertical layer of the sphere. - \param texturePercentage: How much of the height of the texture is used. Should be between 0 and 1. - \param spherePercentage: How much of the sphere is drawn. Value should be between 0 and 2, where 1 is an exact half-sphere and 2 is a full sphere. - \param parent: Parent scene node of the dome. A dome usually has no parent, - so this should be null. Note: If a parent is set, the dome will not - change how it is drawn. - \param id: An id of the node. This id can be used to identify the node. - \return Returns a pointer to the sky dome if successful, otherwise NULL. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual ISceneNode* addSkyDomeSceneNode(video::ITexture* texture, - u32 horiRes, u32 vertRes, f64 texturePercentage, f64 spherePercentage, - ISceneNode* parent = 0, s32 id=-1) = 0; - - //! Adds a particle system scene node to the scene graph. - /** \param withDefaultEmitter: Creates a default working point emitter - which emitts some particles. Set this to true to see a particle system - in action. If set to false, you'll have to set the emitter you want by - calling IParticleSystemSceneNode::setEmitter(). - \param parent: Parent of the scene node. Can be NULL if no parent. - \param id: Id of the node. This id can be used to identify the scene node. - \param position: Position of the space relative to its parent where the - scene node will be placed. - \param rotation: Initital rotation of the scene node. - \param scale: Initial scale of the scene node. - \return Returns pointer to the created scene node. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual IParticleSystemSceneNode* addParticleSystemSceneNode( - bool withDefaultEmitter=true, ISceneNode* parent=0, s32 id=-1, - const core::vector3df& position = core::vector3df(0,0,0), - const core::vector3df& rotation = core::vector3df(0,0,0), - const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) = 0; - - //! Adds a terrain scene node to the scene graph. - /** This node implements is a simple terrain renderer which uses - a technique known as geo mip mapping - for reducing the detail of triangle blocks which are far away. - The code for the TerrainSceneNode is based on the terrain - renderer by Soconne and the GeoMipMapSceneNode developed by - Spintz. They made their code available for Irrlicht and allowed - it to be distributed under this licence. I only modified some - parts. A lot of thanks go to them. - - This scene node is capable of loading terrains and updating - the indices at runtime to enable viewing very large terrains - very quickly. It uses a CLOD (Continuous Level of Detail) - algorithm which updates the indices for each patch based on - a LOD (Level of Detail) which is determined based on a patch's - distance from the camera. - - The patch size of the terrain must always be a size of ( 2^N+1, i.e. 8+1(9), 16+1(17), etc. ). - The MaxLOD available is directly dependent on the patch size of the terrain. LOD 0 contains all - of the indices to draw all the triangles at the max detail for a patch. As each LOD goes up by 1 - the step taken, in generating indices increases by - 2^LOD, so for LOD 1, the step taken is 2, for - LOD 2, the step taken is 4, LOD 3 - 8, etc. The step can be no larger than the size of the patch, - so having a LOD of 8, with a patch size of 17, is asking the algoritm to generate indices every - 2^8 ( 256 ) vertices, which is not possible with a patch size of 17. The maximum LOD for a patch - size of 17 is 2^4 ( 16 ). So, with a MaxLOD of 5, you'll have LOD 0 ( full detail ), LOD 1 ( every - 2 vertices ), LOD 2 ( every 4 vertices ), LOD 3 ( every 8 vertices ) and LOD 4 ( every 16 vertices ). - \param heightMapFileName: The name of the file on disk, to read vertex data from. This should - be a gray scale bitmap. - \param parent: Parent of the scene node. Can be 0 if no parent. - \param id: Id of the node. This id can be used to identify the scene node. - \param position: The absolute position of this node. - \param rotation: The absolute rotation of this node. ( NOT YET IMPLEMENTED ) - \param scale: The scale factor for the terrain. If you're using a heightmap of size 129x129 and would like - your terrain to be 12900x12900 in game units, then use a scale factor of ( core::vector ( 100.0f, 100.0f, 100.0f ). - If you use a Y scaling factor of 0.0f, then your terrain will be flat. - \param vertexColor: The default color of all the vertices. If no texture is associated - with the scene node, then all vertices will be this color. Defaults to white. - \param maxLOD: The maximum LOD (level of detail) for the node. Only change if you - know what you are doing, this might lead to strange behaviour. - \param patchSize: patch size of the terrain. Only change if you - know what you are doing, this might lead to strange behaviour. - \param smoothFactor: The number of times the vertices are smoothed. - \param addAlsoIfHeightmapEmpty: Add terrain node even with empty heightmap. - \return Returns pointer to the created scene node. Can be null if the - terrain could not be created, for example because the heightmap could not be loaded. - The returned pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual ITerrainSceneNode* addTerrainSceneNode( - const c8* heightMapFileName, - ISceneNode* parent=0, s32 id=-1, - const core::vector3df& position = core::vector3df(0.0f,0.0f,0.0f), - const core::vector3df& rotation = core::vector3df(0.0f,0.0f,0.0f), - const core::vector3df& scale = core::vector3df(1.0f,1.0f,1.0f), - video::SColor vertexColor = video::SColor(255,255,255,255), - s32 maxLOD=5, E_TERRAIN_PATCH_SIZE patchSize=ETPS_17, s32 smoothFactor=0, - bool addAlsoIfHeightmapEmpty = false) = 0; - - //! Adds a terrain scene node to the scene graph. - /** Just like the other addTerrainSceneNode() method, but takes an IReadFile - pointer as parameter for the heightmap. For more informations take a look - at the other function. - \param heightMapFile: The file handle to read vertex data from. This should - be a gray scale bitmap. - \param parent: Parent of the scene node. Can be 0 if no parent. - \param id: Id of the node. This id can be used to identify the scene node. - \param position: The absolute position of this node. - \param rotation: The absolute rotation of this node. ( NOT YET IMPLEMENTED ) - \param scale: The scale factor for the terrain. If you're using a heightmap of size 129x129 and would like - your terrain to be 12900x12900 in game units, then use a scale factor of ( core::vector ( 100.0f, 100.0f, 100.0f ). - If you use a Y scaling factor of 0.0f, then your terrain will be flat. - \param vertexColor: The default color of all the vertices. If no texture is associated - with the scene node, then all vertices will be this color. Defaults to white. - \param maxLOD: The maximum LOD (level of detail) for the node. Only change if you - know what you are doing, this might lead to strange behaviour. - \param patchSize: patch size of the terrain. Only change if you - know what you are doing, this might lead to strange behaviour. - \param smoothFactor: The number of times the vertices are smoothed. - \param addAlsoIfHeightmapEmpty: Add terrain node even with empty heightmap. - \return Returns pointer to the created scene node. Can be null if the - terrain could not be created, for example because the heightmap could not be loaded. - The returned pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual ITerrainSceneNode* addTerrainSceneNode( - io::IReadFile* heightMapFile, - ISceneNode* parent=0, s32 id=-1, - const core::vector3df& position = core::vector3df(0.0f,0.0f,0.0f), - const core::vector3df& rotation = core::vector3df(0.0f,0.0f,0.0f), - const core::vector3df& scale = core::vector3df(1.0f,1.0f,1.0f), - video::SColor vertexColor = video::SColor(255,255,255,255), - s32 maxLOD=5, E_TERRAIN_PATCH_SIZE patchSize=ETPS_17, s32 smoothFactor=0, - bool addAlsoIfHeightmapEmpty = false) = 0; - - //! Adds a quake3 scene node to the scene graph. - /** A Quake3 Scene renders multiple meshes for a specific HighLanguage Shader (Quake3 Style ) - \return Returns a pointer to the quake3 scene node if successful, otherwise NULL. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual ISceneNode* addQuake3SceneNode(IMeshBuffer* meshBuffer, const quake3::SShader * shader, - ISceneNode* parent=0, s32 id=-1 - ) = 0; - - - //! Adds an empty scene node to the scene graph. - /** Can be used for doing advanced transformations - or structuring the scene graph. - \return Returns pointer to the created scene node. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual ISceneNode* addEmptySceneNode(ISceneNode* parent=0, s32 id=-1) = 0; - - //! Adds a dummy transformation scene node to the scene graph. - /** This scene node does not render itself, and does not respond to set/getPosition, - set/getRotation and set/getScale. Its just a simple scene node that takes a - matrix as relative transformation, making it possible to insert any transformation - anywhere into the scene graph. - \return Returns pointer to the created scene node. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual IDummyTransformationSceneNode* addDummyTransformationSceneNode( - ISceneNode* parent=0, s32 id=-1) = 0; - - //! Adds a text scene node, which is able to display 2d text at a position in three dimensional space - virtual ITextSceneNode* addTextSceneNode(gui::IGUIFont* font, const wchar_t* text, - video::SColor color=video::SColor(100,255,255,255), - ISceneNode* parent = 0, const core::vector3df& position = core::vector3df(0,0,0), - s32 id=-1) = 0; - - //! Adds a text scene node, which uses billboards - virtual ITextSceneNode* addBillboardTextSceneNode( gui::IGUIFont* font, const wchar_t* text, - ISceneNode* parent = 0, - const core::dimension2d& size = core::dimension2d(10.0f, 10.0f), - const core::vector3df& position = core::vector3df(0,0,0), s32 id=-1, - video::SColor shade_top = 0xFFFFFFFF, video::SColor shade_down = 0xFFFFFFFF) = 0; - - //! Adds a Hill Plane mesh to the mesh pool. - /** The mesh is generated on the fly - and looks like a plane with some hills on it. It is uses mostly for quick - tests of the engine only. You can specify how many hills there should be - on the plane and how high they should be. Also you must specify a name for - the mesh, because the mesh is added to the mesh pool, and can be retrieved - again using ISceneManager::getMesh() with the name as parameter. - \param name: The name of this mesh which must be specified in order - to be able to retrieve the mesh later with ISceneManager::getMesh(). - \param tileSize: Size of a tile of the mesh. (10.0f, 10.0f) would be a - good value to start, for example. - \param tileCount: Specifies how much tiles there will be. If you specifiy - for example that a tile has the size (10.0f, 10.0f) and the tileCount is - (10,10), than you get a field of 100 tiles which has the dimension 100.0fx100.0f. - \param material: Material of the hill mesh. - \param hillHeight: Height of the hills. If you specify a negative value - you will get holes instead of hills. If the height is 0, no hills will be - created. - \param countHills: Amount of hills on the plane. There will be countHills.X - hills along the X axis and countHills.Y along the Y axis. So in total there - will be countHills.X * countHills.Y hills. - \param textureRepeatCount: Defines how often the texture will be repeated in - x and y direction. - \return Returns null if the creation failed. The reason could be that you - specified some invalid parameters or that a mesh with that name already - exists. If successful, a pointer to the mesh is returned. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual IAnimatedMesh* addHillPlaneMesh(const c8* name, - const core::dimension2d& tileSize, const core::dimension2d& tileCount, - video::SMaterial* material = 0, f32 hillHeight = 0.0f, - const core::dimension2d& countHills = core::dimension2d(0.0f, 0.0f), - const core::dimension2d& textureRepeatCount = core::dimension2d(1.0f, 1.0f)) = 0; - - //! Adds a static terrain mesh to the mesh pool. - /** The mesh is generated on the fly - from a texture file and a height map file. Both files may be huge - (8000x8000 pixels would be no problem) because the generator splits the - files into smaller textures if necessary. - You must specify a name for the mesh, because the mesh is added to the mesh pool, - and can be retrieved again using ISceneManager::getMesh() with the name as parameter. - \param meshname: The name of this mesh which must be specified in order - to be able to retrieve the mesh later with ISceneManager::getMesh(). - \param texture: Texture for the terrain. Please note that this is not a - hardware texture as usual (ITexture), but an IImage software texture. - You can load this texture with IVideoDriver::createImageFromFile(). - \param heightmap: A grayscaled heightmap image. Like the texture, - it can be created with IVideoDriver::createImageFromFile(). The amount - of triangles created depends on the size of this texture, so use a small - heightmap to increase rendering speed. - \param stretchSize: Parameter defining how big a is pixel on the heightmap. - \param maxHeight: Defines how height a white pixel on the heighmap is. - \param defaultVertexBlockSize: Defines the initial dimension between vertices. - \return Returns null if the creation failed. The reason could be that you - specified some invalid parameters, that a mesh with that name already - exists, or that a texture could not be found. If successful, a pointer to the mesh is returned. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual IAnimatedMesh* addTerrainMesh(const c8* meshname, - video::IImage* texture, video::IImage* heightmap, - const core::dimension2d& stretchSize = core::dimension2d(10.0f,10.0f), - f32 maxHeight=200.0f, - const core::dimension2d& defaultVertexBlockSize = core::dimension2d(64,64)) = 0; - - //! add a static arrow mesh to the meshpool - virtual IAnimatedMesh* addArrowMesh(const c8* name, - video::SColor vtxColor0=0xFFFFFFFF, - video::SColor vtxColor1=0xFFFFFFFF, - u32 tesselationCylinder=4, u32 tesselationCone=8, - f32 height=1.f, f32 cylinderHeight=0.6f, - f32 width0=0.05f, f32 width1=0.3f) = 0; - - //! add a static sphere mesh to the meshpool - virtual IAnimatedMesh* addSphereMesh(const c8* name, - f32 radius=5.f, u32 polyCountX = 16, - u32 polyCountY = 16) = 0; - - //! Returns the root scene node. - /** This is the scene node which is parent - of all scene nodes. The root scene node is a special scene node which - only exists to manage all scene nodes. It will not be rendered and cannot - be removed from the scene. - \return Returns a pointer to the root scene node. */ - virtual ISceneNode* getRootSceneNode() = 0; - - //! Returns the first scene node with the specified id. - /** \param id: The id to search for - \param start: Scene node to start from. All children of this scene - node are searched. If null is specified, the root scene node is - taken. - \return Returns pointer to the first scene node with this id, - and null if no scene node could be found. */ - virtual ISceneNode* getSceneNodeFromId(s32 id, ISceneNode* start=0) = 0; - - //! Returns the first scene node with the specified name. - /** \param name: The name to search for - \param start: Scene node to start from. All children of this scene - node are searched. If null is specified, the root scene node is - taken. - \return Returns pointer to the first scene node with this id, - and null if no scene node could be found. */ - virtual ISceneNode* getSceneNodeFromName(const c8* name, ISceneNode* start=0) = 0; - - //! Returns the first scene node with the specified type. - /** \param type: The type to search for - \param start: Scene node to start from. All children of this scene - node are searched. If null is specified, the root scene node is - taken. - \return Returns pointer to the first scene node with this type, - and null if no scene node could be found. */ - virtual ISceneNode* getSceneNodeFromType(scene::ESCENE_NODE_TYPE type, ISceneNode* start=0) = 0; - - //! returns scene nodes by type. - /** \param type: Type of scene node to find. - \param outNodes: array to be filled with results. - \param start: Scene node to start from. All children of this scene - node are searched. If null is specified, the root scene node is - taken. */ - virtual void getSceneNodesFromType(ESCENE_NODE_TYPE type, core::array& outNodes, ISceneNode* start=0) = 0; - - //! Returns the current active camera. - /** \return The active camera is returned. Note that this can be NULL, if there - was no camera created yet. */ - virtual ICameraSceneNode* getActiveCamera() = 0; - - //! Sets the currently active camera. - /** The previous active camera will be deactivated. - \param camera: The new camera which should be active. */ - virtual void setActiveCamera(ICameraSceneNode* camera) = 0; - - //! Sets the color of stencil buffers shadows drawn by the scene manager. - virtual void setShadowColor(video::SColor color = video::SColor(150,0,0,0)) = 0; - - //! Returns the current color of shadows. - virtual video::SColor getShadowColor() const = 0; - - //! Registers a node for rendering it at a specific time. - /** This method should only be used by SceneNodes when they get a - ISceneNode::OnRegisterSceneNode() call. - \param node: Node to register for drawing. Usually scene nodes would set 'this' - as parameter here because they want to be drawn. - \param pass: Specifies when the mode wants to be drawn in relation to the other nodes. - For example, if the node is a shadow, it usually wants to be drawn after all other nodes - and will use ESNRP_SHADOW for this. See E_SCENE_NODE_RENDER_PASS for details. - \return scene will be rendered ( passed culling ) */ - virtual u32 registerNodeForRendering(ISceneNode* node, - E_SCENE_NODE_RENDER_PASS pass = ESNRP_AUTOMATIC) = 0; - - //! Draws all the scene nodes. - /** This can only be invoked between - IVideoDriver::beginScene() and IVideoDriver::endScene(). Please note that - the scene is not only drawn when calling this, but also animated - by existing scene node animators, culling of scene nodes is done, etc. */ - virtual void drawAll() = 0; - - //! Creates a rotation animator, which rotates the attached scene node around itself. - /** \param rotationPerSecond: Specifies the speed of the animation - \return Returns the animator. Attach it to a scene node with ISceneNode::addAnimator() - and the animator will animate it. - If you no longer need the animator, you should call ISceneNodeAnimator::drop(). - See IReferenceCounted::drop() for more information. */ - virtual ISceneNodeAnimator* createRotationAnimator(const core::vector3df& rotationPerSecond) = 0; - - //! Creates a fly circle animator, which lets the attached scene node fly around a center. - /** \param center: Center of the circle. - \param radius: Radius of the circle. - \param speed: Specifies the speed of the flight. - \param direction: Specifies the upvector used for alignment of the mesh. - \return Returns the animator. Attach it to a scene node with ISceneNode::addAnimator() - and the animator will animate it. - If you no longer need the animator, you should call ISceneNodeAnimator::drop(). - See IReferenceCounted::drop() for more information. */ - virtual ISceneNodeAnimator* createFlyCircleAnimator(const core::vector3df& center, - f32 radius, f32 speed=0.001f, const core::vector3df& direction= core::vector3df ( 0.f, 1.f, 0.f ) ) = 0; - - //! Creates a fly straight animator, which lets the attached scene node fly or move along a line between two points. - /** \param startPoint: Start point of the line. - \param endPoint: End point of the line. - \param timeForWay: Time in milli seconds how long the node should need to - move from the start point to the end point. - \param loop: If set to false, the node stops when the end point is reached. - If loop is true, the node begins again at the start. - \return Returns the animator. Attach it to a scene node with ISceneNode::addAnimator() - and the animator will animate it. - If you no longer need the animator, you should call ISceneNodeAnimator::drop(). - See IReferenceCounted::drop() for more information. */ - virtual ISceneNodeAnimator* createFlyStraightAnimator(const core::vector3df& startPoint, - const core::vector3df& endPoint, u32 timeForWay, bool loop=false) = 0; - - //! Creates a texture animator, which switches the textures of the target scene node based on a list of textures. - /** \param textures: List of textures to use. - \param timePerFrame: Time in milliseconds, how long any texture in the list - should be visible. - \param loop: If set to to false, the last texture remains set, and the animation - stops. If set to true, the animation restarts with the first texture. - \return Returns the animator. Attach it to a scene node with ISceneNode::addAnimator() - and the animator will animate it. - If you no longer need the animator, you should call ISceneNodeAnimator::drop(). - See IReferenceCounted::drop() for more information. */ - virtual ISceneNodeAnimator* createTextureAnimator(const core::array& textures, - s32 timePerFrame, bool loop=true) = 0; - - //! Creates a scene node animator, which deletes the scene node after some time automatically. - /** \param timeMs: Time in milliseconds, after when the node will be deleted. - \return Returns the animator. Attach it to a scene node with ISceneNode::addAnimator() - and the animator will animate it. - If you no longer need the animator, you should call ISceneNodeAnimator::drop(). - See IReferenceCounted::drop() for more information. */ - virtual ISceneNodeAnimator* createDeleteAnimator(u32 timeMs) = 0; - - //! Creates a special scene node animator for doing automatic collision detection and response. - /** See ISceneNodeAnimatorCollisionResponse for details. - \param world: Triangle selector holding all triangles of the world with which - the scene node may collide. You can create a triangle selector with - ISceneManager::createTriangleSelector(); - \param sceneNode: SceneNode which should be manipulated. After you added this animator - to the scene node, the scene node will not be able to move through walls and is - affected by gravity. - \param ellipsoidRadius: Radius of the ellipsoid with which collision detection and - response is done. If you have got a scene node, and you are unsure about - how big the radius should be, you could use the following code to determine - it: - \code - const core::aabbox& box = yourSceneNode->getBoundingBox(); - core::vector3df radius = box.MaxEdge - box.getCenter(); - \endcode - \param gravityPerSecond: Sets the gravity of the environment. A good example value would be - core::vector3df(0,-100.0f,0) for letting gravity affect all object to - fall down. For bigger gravity, make increase the length of the vector. - You can disable gravity by setting it to core::vector3df(0,0,0). - \param ellipsoidTranslation: By default, the ellipsoid for collision detection is created around - the center of the scene node, which means that the ellipsoid surrounds - it completely. If this is not what you want, you may specify a translation - for the ellipsoid. - \param slidingValue: DOCUMENTATION NEEDED. - \return Returns the animator. Attach it to a scene node with ISceneNode::addAnimator() - and the animator will cause it to do collision detection and response. - If you no longer need the animator, you should call ISceneNodeAnimator::drop(). - See IReferenceCounted::drop() for more information. */ - virtual ISceneNodeAnimatorCollisionResponse* createCollisionResponseAnimator( - ITriangleSelector* world, ISceneNode* sceneNode, - const core::vector3df& ellipsoidRadius = core::vector3df(30,60,30), - const core::vector3df& gravityPerSecond = core::vector3df(0,-100.0f,0), - const core::vector3df& ellipsoidTranslation = core::vector3df(0,0,0), - f32 slidingValue = 0.0005f) = 0; - - //! Creates a follow spline animator. - /** The animator modifies the position of - the attached scene node to make it follow a hermite spline. - The code of the is based on a scene node - Matthias Gall sent in. Thanks! I adapted the code just a little bit. Matthias - wrote: - Uses a subset of hermite splines: either cardinal splines (tightness != 0.5) or catmull-rom-splines (tightness == 0.5) - but this is just my understanding of this stuff, I'm not a mathematician, so this might be wrong ;) */ - virtual ISceneNodeAnimator* createFollowSplineAnimator(s32 startTime, - const core::array< core::vector3df >& points, - f32 speed = 1.0f, f32 tightness = 0.5f) = 0; - - //! Creates a simple ITriangleSelector, based on a mesh. - /** Triangle selectors - can be used for doing collision detection. Don't use this selector - for a huge amount of triangles like in Quake3 maps. - Instead, use for example ISceneManager::createOctTreeTriangleSelector(). - Please note that the created triangle selector is not automaticly attached - to the scene node. You will have to call ISceneNode::setTriangleSelector() - for this. To create and attach a triangle selector is done like this: - \code - ITriangleSelector* s = sceneManager->createTriangleSelector(yourMesh, - yourSceneNode); - yourSceneNode->setTriangleSelector(s); - s->drop(); - \endcode - \param mesh: Mesh of which the triangles are taken. - \param node: Scene node of which visibility and transformation is used. - \return Returns the selector, or null if not successful. - If you no longer need the selector, you should call ITriangleSelector::drop(). - See IReferenceCounted::drop() for more information. */ - virtual ITriangleSelector* createTriangleSelector(IMesh* mesh, ISceneNode* node) = 0; - - //! Creates a simple dynamic ITriangleSelector, based on a axis aligned bounding box. - /** Triangle selectors - can be used for doing collision detection. Every time when triangles are - queried, the triangle selector gets the bounding box of the scene node, - an creates new triangles. In this way, it works good with animated scene nodes. - \param node: Scene node of which the bounding box, visibility and transformation is used. - \return Returns the selector, or null if not successful. - If you no longer need the selector, you should call ITriangleSelector::drop(). - See IReferenceCounted::drop() for more information. */ - virtual ITriangleSelector* createTriangleSelectorFromBoundingBox(ISceneNode* node) = 0; - - //! Creates a Triangle Selector, optimized by an octtree. - /** Triangle selectors - can be used for doing collision detection. This triangle selector is - optimized for huge amounts of triangle, it organizes them in an octtree. - Please note that the created triangle selector is not automaticly attached - to the scene node. You will have to call ISceneNode::setTriangleSelector() - for this. To create and attach a triangle selector is done like this: - \code - ITriangleSelector* s = sceneManager->createOctTreeTriangleSelector(yourMesh, - yourSceneNode); - yourSceneNode->setTriangleSelector(s); - s->drop(); - \endcode - For more informations and examples on this, take a look at the collision - tutorial in the SDK. - \param mesh: Mesh of which the triangles are taken. - \param node: Scene node of which visibility and transformation is used. - \param minimalPolysPerNode: Specifies the minimal polygons contained a octree node. - If a node gets less polys the this value, it will not be splitted into - smaller nodes. - \return Returns the selector, or null if not successful. - If you no longer need the selector, you should call ITriangleSelector::drop(). - See IReferenceCounted::drop() for more information. */ - virtual ITriangleSelector* createOctTreeTriangleSelector(IMesh* mesh, - ISceneNode* node, s32 minimalPolysPerNode=32) = 0; - - //! Creates a meta triangle selector. - /** A meta triangle selector is nothing more than a - collection of one or more triangle selectors providing together - the interface of one triangle selector. In this way, - collision tests can be done with different triangle soups in one pass. - \return Returns the selector, or null if not successful. - If you no longer need the selector, you should call ITriangleSelector::drop(). - See IReferenceCounted::drop() for more information. */ - virtual IMetaTriangleSelector* createMetaTriangleSelector() = 0; - - //! Creates a triangle selector which can select triangles from a terrain scene node. - /** \param node: Pointer to the created terrain scene node - \param LOD: Level of detail, 0 for highest detail. */ - virtual ITriangleSelector* createTerrainTriangleSelector( - ITerrainSceneNode* node, s32 LOD=0) = 0; - - //! Adds an external mesh loader for extending the engine with new file formats. - /** If you want the engine to be extended with - file formats it currently is not able to load (e.g. .cob), just implement - the IMeshLoader interface in your loading class and add it with this method. - Using this method it is also possible to override built-in mesh loaders with - newer or updated versions without the need of recompiling the engine. - \param externalLoader: Implementation of a new mesh loader. */ - virtual void addExternalMeshLoader(IMeshLoader* externalLoader) = 0; - - //! Returns a pointer to the scene collision manager. - virtual ISceneCollisionManager* getSceneCollisionManager() = 0; - - //! Returns a pointer to the mesh manipulator. - virtual IMeshManipulator* getMeshManipulator() = 0; - - //! Adds a scene node to the deletion queue. - /** The scene node is immediatly - deleted when it's secure. Which means when the scene node does not - execute animators and things like that. This method is for example - used for deleting scene nodes by their scene node animators. In - most other cases, a ISceneNode::remove() call is enough, using this - deletion queue is not necessary. - See ISceneManager::createDeleteAnimator() for details. - \param node: Node to detete. */ - virtual void addToDeletionQueue(ISceneNode* node) = 0; - - //! Posts an input event to the environment. - /** Usually you do not have to - use this method, it is used by the internal engine. */ - virtual bool postEventFromUser(const SEvent& event) = 0; - - //! Clears the whole scene. - /** All scene nodes are removed. */ - virtual void clear() = 0; - - //! Returns interface to the parameters set in this scene. - /** String parameters can be used by plugins and mesh loaders. - For example the CMS and LMTS loader want a parameter named 'CSM_TexturePath' - and 'LMTS_TexturePath' set to the path were attached textures can be found. See - CSM_TEXTURE_PATH, LMTS_TEXTURE_PATH, MY3D_TEXTURE_PATH, - COLLADA_CREATE_SCENE_INSTANCES, DMF_TEXTURE_PATH and DMF_USE_MATERIALS_DIRS*/ - virtual io::IAttributes* getParameters() = 0; - - //! Returns current render pass. - /** All scene nodes are being rendered in a specific order. - First lights, cameras, sky boxes, solid geometry, and then transparent - stuff. During the rendering process, scene nodes may want to know what the scene - manager is rendering currently, because for example they registered for rendering - twice, once for transparent geometry and once for solid. When knowing what rendering - pass currently is active they can render the correct part of their geometry. */ - virtual E_SCENE_NODE_RENDER_PASS getSceneNodeRenderPass() const = 0; - - //! Returns the default scene node factory which can create all built in scene nodes - virtual ISceneNodeFactory* getDefaultSceneNodeFactory() = 0; - - //! Adds a scene node factory to the scene manager. - /** Use this to extend the scene manager with new scene node types which it should be - able to create automaticly, for example when loading data from xml files. */ - virtual void registerSceneNodeFactory(ISceneNodeFactory* factoryToAdd) = 0; - - //! Returns amount of registered scene node factories. - virtual u32 getRegisteredSceneNodeFactoryCount() const = 0; - - //! Returns a scene node factory by index - virtual ISceneNodeFactory* getSceneNodeFactory(u32 index) = 0; - - //! Returns the default scene node animator factory which can create all built-in scene node animators - virtual ISceneNodeAnimatorFactory* getDefaultSceneNodeAnimatorFactory() = 0; - - //! Adds a scene node animator factory to the scene manager. - /** Use this to extend the scene manager with new scene node animator types which it should be - able to create automaticly, for example when loading data from xml files. */ - virtual void registerSceneNodeAnimatorFactory(ISceneNodeAnimatorFactory* factoryToAdd) = 0; - - //! Returns amount of registered scene node animator factories. - virtual u32 getRegisteredSceneNodeAnimatorFactoryCount() const = 0; - - //! Returns a scene node animator factory by index - virtual ISceneNodeAnimatorFactory* getSceneNodeAnimatorFactory(u32 index) = 0; - - //! Returns a typename from a scene node type or null if not found - virtual const c8* getSceneNodeTypeName(ESCENE_NODE_TYPE type) = 0; - - //! Adds a scene node to the scene by name - virtual ISceneNode* addSceneNode(const char* sceneNodeTypeName, ISceneNode* parent) = 0; - - //! Creates a new scene manager. - /** This can be used to easily draw and/or store two independent scenes at the same time. - The mesh cache will be shared between all existing scene managers, which means if you load - a mesh in the original scene manager using for example getMesh(), the mesh will be available - in all other scene managers too, without loading. - The original/main scene manager will still be there and accessible via IrrlichtDevice::getSceneManager(). - If you need input event in this new scene manager, for example for FPS cameras, you'll need - to forward input to this manually: Just implement an IEventReceiver and call - yourNewSceneManager->postEventFromUser(), and return true so that the original scene manager - doesn't get the event. Otherwise, all input will go automaticly to the main scene manager. - If you no longer need the new scene manager, you should call ISceneManager::drop(). - See IReferenceCounted::drop() for more information. */ - virtual ISceneManager* createNewSceneManager(bool cloneContent=false) = 0; - - //! Saves the current scene into a file. - /** Scene nodes with the option isDebugObject set to true are not being saved. - The scene is usually written to an .irr file, an xml based format. .irr files can - Be edited with the Irrlicht Engine Editor, irrEdit (http://irredit.irrlicht3d.org). - To load .irr files again, see ISceneManager::loadScene(). - \param filename: Name of the file. - \param userDataSerializer: If you want to save some user data for every scene node into the - file, implement the ISceneUserDataSerializer interface and provide it as parameter here. - Otherwise, simply specify 0 as this parameter. - \return Returns true if successful. */ - virtual bool saveScene(const c8* filename, ISceneUserDataSerializer* userDataSerializer=0) = 0; - - //! Saves the current scene into a file. - /** Scene nodes with the option isDebugObject set to true are not being saved. - The scene is usually written to an .irr file, an xml based format. .irr files can - Be edited with the Irrlicht Engine Editor, irrEdit (http://irredit.irrlicht3d.org). - To load .irr files again, see ISceneManager::loadScene(). - \param file: File where the scene is saved into. - \param userDataSerializer: If you want to save some user data for every scene node into the - file, implement the ISceneUserDataSerializer interface and provide it as parameter here. - Otherwise, simply specify 0 as this parameter. - \return Returns true if successful. */ - virtual bool saveScene(io::IWriteFile* file, ISceneUserDataSerializer* userDataSerializer=0) = 0; - - //! Loads a scene. Note that the current scene is not cleared before. - /** The scene is usually load from an .irr file, an xml based format. .irr files can - Be edited with the Irrlicht Engine Editor, irrEdit (http://irredit.irrlicht3d.org) or - saved directly by the engine using ISceneManager::saveScene(). - \param filename: Name of the file. - \param userDataSerializer: If you want to load user data possibily saved in that file for - some scene nodes in the file, implement the ISceneUserDataSerializer interface and provide it as parameter here. - Otherwise, simply specify 0 as this parameter. - \return Returns true if successful. */ - virtual bool loadScene(const c8* filename, ISceneUserDataSerializer* userDataSerializer=0) = 0; - - //! Loads a scene. Note that the current scene is not cleared before. - /** The scene is usually load from an .irr file, an xml based format. .irr files can - Be edited with the Irrlicht Engine Editor, irrEdit (http://irredit.irrlicht3d.org) or - saved directly by the engine using ISceneManager::saveScene(). - \param file: File where the scene is going to be saved into. - \param userDataSerializer: If you want to load user data possibily saved in that file for - some scene nodes in the file, implement the ISceneUserDataSerializer interface and provide it as parameter here. - Otherwise, simply specify 0 as this parameter. - \return Returns true if successful. */ - virtual bool loadScene(io::IReadFile* file, ISceneUserDataSerializer* userDataSerializer=0) = 0; - - //! Returns a mesh writer implementation if available - /** Note: You need to drop() the pointer after use again, see IReferenceCounted::drop() - for details. */ - virtual IMeshWriter* createMeshWriter(EMESH_WRITER_TYPE type) = 0; - - //! Sets ambient color of the scene - virtual void setAmbientLight(const video::SColorf &ambientColor) = 0; - - //! Returns ambient color of the scene - virtual const video::SColorf& getAmbientLight() const = 0; - - }; - - -} // end namespace scene -} // end namespace irr - -#endif - +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_SCENE_MANAGER_H_INCLUDED__ +#define __I_SCENE_MANAGER_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "irrArray.h" +#include "vector3d.h" +#include "dimension2d.h" +#include "SColor.h" +#include "ETerrainElements.h" +#include "ESceneNodeTypes.h" +#include "EMeshWriterEnums.h" +#include "SceneParameters.h" + +namespace irr +{ + struct SKeyMap; + struct SEvent; + +namespace io +{ + class IReadFile; + class IAttributes; + class IWriteFile; +} // end namespace io + +namespace gui +{ + class IGUIFont; + class IGUIEnvironment; +} // end namespace gui + +namespace video +{ + class IVideoDriver; + class SMaterial; + class IImage; + class ITexture; +} // end namespace video + +namespace scene +{ + class IMeshWriter; + + //! Enumeration for render passes. + /** A parameter passed to the registerNodeForRendering() method of the ISceneManager, + specifying when the mode wants to be drawn in relation to the other nodes. */ + enum E_SCENE_NODE_RENDER_PASS + { + //! Camera pass. The active view is set up here. + //! The very first pass. + ESNRP_CAMERA, + + //! In this pass, lights are transformed into camera space and added to the driver + ESNRP_LIGHT, + + //! This is used for sky boxes. + ESNRP_SKY_BOX, + + //! All normal objects can use this for registering themselves. + //! This value will never be returned by ISceneManager::getSceneNodeRenderPass(). + //! The scene manager will determine by itself if an object is + //! transparent or solid and register the object as SNRT_TRANSPARENT or + //! SNRT_SOLD automatically if you call registerNodeForRendering with this + //! value (which is default). Note that it will register the node only as ONE type. + //! If your scene node has both solid and transparent material types register + //! it twice (one time as SNRT_SOLID, the other time as SNRT_TRANSPARENT) and + //! in the render() method call getSceneNodeRenderPass() to find out the current + //! render pass and render only the corresponding parts of the node. + ESNRP_AUTOMATIC, + + //! Solid scene nodes or special scene nodes without materials. + ESNRP_SOLID, + + //! Drawn after the transparent nodes, the time for drawing shadow volumes + ESNRP_SHADOW, + + //! Transparent scene nodes, drawn after shadow nodes. They are sorted from back + //! to front and drawn in that order. + ESNRP_TRANSPARENT, + + //! Never used, value specifing how much parameters there are. + ESNRP_COUNT + }; + + class IMesh; + class IMeshBuffer; + class IAnimatedMesh; + class IMeshCache; + class ISceneNode; + class ICameraSceneNode; + class IAnimatedMeshSceneNode; + class ISceneNodeAnimator; + class ISceneNodeAnimatorCollisionResponse; + class ILightSceneNode; + class IBillboardSceneNode; + class ITerrainSceneNode; + class IMeshSceneNode; + class IMeshLoader; + class ISceneCollisionManager; + class IParticleSystemSceneNode; + class IDummyTransformationSceneNode; + class ITriangleSelector; + class IMetaTriangleSelector; + class IMeshManipulator; + class ITextSceneNode; + class ISceneNodeFactory; + class ISceneNodeAnimatorFactory; + class ISceneUserDataSerializer; + + namespace quake3 + { + class SShader; + } // end namespace quake3 + + //! The Scene Manager manages scene nodes, mesh recources, cameras and all the other stuff. + /** All Scene nodes can be created only here. There is a always growing list of scene + nodes for lots of purposes: Indoor rendering scene nodes like the Octree + (addOctTreeSceneNode()) or the terrain renderer (addTerrainSceneNode()), + different Camera scene nodes (addCameraSceneNode(), addCameraSceneNodeMaya()), + scene nodes for Light (addLightSceneNode()), Billboards (addBillboardSceneNode()) + and so on. + A scene node is a node in the hierachical scene graph. Every scene node may have children, + which are other scene nodes. Children move relative the their parents position. If the parent of a node is not + visible, its children won't be visible, too. In this way, it is for example easily possible + to attach a light to a moving car or to place a walking character on a moving platform + on a moving ship. + The SceneManager is also able to load 3d mesh files of different formats. Take a look + at getMesh() to find out what formats are supported. And if these formats are not enough + use addExternalMeshLoader() to add new formats to the engine. + */ + class ISceneManager : public virtual IReferenceCounted + { + public: + + //! destructor + virtual ~ISceneManager() {} + + //! Returns pointer to an animateable mesh. Loads the file if not loaded already. + /** + * If you want to remove a loaded mesh from the cache again, use removeMesh(). + * Currently there are the following mesh formats supported: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
FormatDescription
3D Studio (.3ds)Loader for 3D-Studio files which lots of 3D packages are able to export. + * Only static meshes are currently supported by this importer.
Bliz Basic B3D (.b3d)Loader for blitz basic files, developed by Mark Sibly, also supports animations.
Cartography shop 4 (.csm)Cartography Shop is a modeling program for creating architecture and calculating + * lighting. Irrlicht can directly import .csm files thanks to the IrrCSM library + * created by Saurav Mohapatra which is now integrated directly in Irrlicht. + * If you are using this loader, please note that you'll have to set the path + * of the textures before loading .csm files. You can do this using SceneManager->getParameters()->setParameter(scene::CSM_TEXTURE_PATH, + * "path/to/your/textures");
COLLADA (.dae, .xml)COLLADA is an open Digital Asset Exchange Schema for the interactive 3D industry. There are + * exporters and importers for this format available for most of the big 3d packages + * at http://collada.org. Irrlicht can import COLLADA files by using the + * ISceneManager::getMesh() method. COLLADA files need not contain only one single mesh + * but multiple meshes and a whole scene setup with lights, cameras and mesh instances, + * this loader can set up a scene as described by the COLLADA file instead of loading + * and returning one single mesh. By default, this loader behaves like the other loaders + * and does not create instances, but it can be switched into this mode by using + * SceneManager->getParameters()->setParameter(COLLADA_CREATE_SCENE_INSTANCES, true); + * Created scene nodes will be named as the names of the nodes in the + * COLLADA file. The returned mesh is just a dummy object in this mode. Meshes included in + * the scene will be added into the scene manager with the following naming scheme: + * path/to/file/file.dea#meshname. The loading of such meshes is logged. + * Currently, this loader is able to create meshes (made of only polygons), lights, + * and cameras. Materials and animations are currently not supported but this will + * change with future releases. + *
Delgine DeleD (.dmf)DeleD (delgine.com) is a 3D editor and level-editor combined into one and is specifically + * designed for 3D game-development. With this loader, it is possible to directly load + * all geometry is as well as textures and lightmaps from .dmf files. To set texture and + * material paths, see scene::DMF_USE_MATERIALS_DIRS and scene::DMF_TEXTURE_PATH. It is also + * possible to flip the alpha texture by setting scene::DMF_FLIP_ALPHA_TEXTURES to true and + * to set the material transparent reference value by setting scene::DMF_ALPHA_CHANNEL_REF to + * a float between 0 and 1. The loader is + * based on Salvatore Russo's .dmf loader, I just changed some parts of it. Thanks to + * Salvatore for his work and for allowing me to use his code in Irrlicht and put it under Irrlicht's + * license. For newer and more enchanced versions of the loader, take a look at delgine.com. + *
DirectX (.x)Platform independent importer (so not D3D-only) for .x files. Most 3D + * packages can export these natively and there are several tools for them + * available. (e.g. the Maya exporter included in the DX SDK) .x files can + * include skeletal animations and Irrlicht is able to play and display them. + * Currently, Irrlicht only supports uncompressed .x files.
Maya (.obj)Most 3D software can create .obj files which contain static geometry without + * material data. The material files .mtl are also supported. This importer + * for Irrlicht can load them directly.
Milkshape (.ms3d).MS3D files contain models and sometimes skeletal animations from the + * Milkshape 3D modeling and animation software. This importer for Irrlicht + * can display and/or animate these files.
My3D (.my3d).my3D is a flexible 3D file format. The My3DTools contains plug-ins to + * export .my3D files from several 3D packages. With this built-in importer, + * Irrlicht can read and display those files directly. This loader was written + * by Zhuck Dimitry who also created the whole My3DTools package. If you are using this loader, please + * note that you can set the path of the textures before loading .my3d files. + * You can do this using SceneManager->getParameters()->setParameter(scene::MY3D_TEXTURE_PATH, + * "path/to/your/textures");
OCT (.oct)The oct file format contains 3D geometry and lightmaps and can be loaded + * directly by Irrlicht. OCT files
+ * can be created by FSRad, Paul Nette's radiosity processor or exported from + * Blender using OCTTools which can be found in the exporters/OCTTools directory + * of the SDK. Thanks to Murphy McCauley for creating all this.
OGRE Meshes (.mesh)Ogre .mesh files contain 3D data for the OGRE 3D engine. Irrlicht can read and + * display them directly with this importer. To define materials for the mesh, + * copy a .material file named like the corresponding .mesh file where the .mesh + * file is. (For example ogrehead.material for ogrehead.mesh). Thanks to Christian Stehno + * who wrote and contributed this loader.
Pulsar LMTools (.lmts)LMTools is a set of tools (Windows & Linux) for creating lightmaps. + * Irrlicht can directly read .lmts files thanks to
+ * the importer created by Jonas Petersen. If you are using this loader, please + * note that you can set the path of the textures before loading .lmts files. + * You can do this using SceneManager->getParameters()->setParameter(scene::LMTS_TEXTURE_PATH, + * "path/to/your/textures"); Notes for
+ * this version of the loader:
+ * - It does not recognice/support user data in the *.lmts files.
+ * - The TGAs generated by LMTools don't work in Irrlicht for some reason (the + * textures are upside down). Opening and resaving them in a graphics app will + * solve the problem.
Quake 3 levels (.bsp)Quake 3 is a popular game by IDSoftware, and .pk3 files contain .bsp files + * and textures/lightmaps describing huge
+ * prelighted levels. Irrlicht can read .pk3 and .bsp files directly and thus + * render Quake 3 levels directly. Written by Nikolaus Gebhardt enhanced by + * Dean P. Macri with the curved surfaces feature.
Quake 2 models (.md2)Quake 2 models are characters with morph target animation. Irrlicht can + * read, display and animate them directly with this importer.
+ * + * To load and display a mesh quickly, just do this: + * \code + * SceneManager->addAnimatedMeshSceneNode( + * SceneManager->getMesh("yourmesh.3ds")); + * \endcode + * If you would like to implement and add your own file format loader to Irrlicht, + * see addExternalMeshLoader(). + * \param filename: Filename of the mesh to load. + * \return Returns NULL if failed and the pointer to the mesh if + * successful. + * This pointer should not be dropped. See IReferenceCounted::drop() for more information. + **/ + virtual IAnimatedMesh* getMesh(const c8* filename) = 0; + + //! Returns an interface to the mesh cache which is shared beween all existing scene managers. + /** With this interface, it is possible to manually add new loaded + meshes (if ISceneManager::getMesh() is not sufficient), to remove them and to iterate + through already loaded meshes. */ + virtual IMeshCache* getMeshCache() = 0; + + //! Returns the video driver. + /** \return Returns pointer to the video Driver. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual video::IVideoDriver* getVideoDriver() = 0; + + //! Returns the active GUIEnvironment + /** \return Returns pointer to the GUIEnvironment + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual gui::IGUIEnvironment* getGUIEnvironment() = 0; + + //! adds Volume Lighting Scene Node. + //! the returned pointer must not be dropped. + // Example Useage: + // scene::ISceneNode * n = smgr->addVolumeLightSceneNode(NULL, -1, + // 32, //Sub Divid U + // 32, //Sub Divid V + // video::SColor(0, 180, 180, 180), //foot colour + // video::SColor(0, 0, 0, 0) //tail colour + // ); + // if (n) { + // n->setScale(core::vector3df(46.0f, 45.0f, 46.0f)); + // n->setPosition(core::vector3df(0,0,0)); + // video::SMaterial& mat = n->getMaterial(0); + // mat.setTexture(0, smgr->getVideoDriver()->getTexture("lightFalloff.png")); + // } + // + virtual ISceneNode* addVolumeLightSceneNode(ISceneNode* parent=0, s32 id=-1, + const s32 subdivU = 32, const s32 subdivV = 32, + const video::SColor foot = video::SColor(51, 0, 230, 180), + const video::SColor tail = video::SColor(0, 0, 0, 0), + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) = 0; + + + //! Adds a test scene node for test purposes to the scene. + /** It is a simple cube of (1,1,1) size. + \param size: Size of the cube. + \param parent: Parent of the scene node. Can be NULL if no parent. + \param id: Id of the node. This id can be used to identify the scene node. + \param position: Position of the space relative to its parent where the + scene node will be placed. + \param rotation: Initital rotation of the scene node. + \param scale: Initial scale of the scene node. + \return Returns pointer to the created test scene node. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual ISceneNode* addCubeSceneNode(f32 size=10.0f, ISceneNode* parent=0, s32 id=-1, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) = 0; + + //! Adds a sphere scene node for test purposes to the scene. + /** It is a simple sphere. + \param radius: Radius of the sphere. + \param polyCount: Polycount of the sphere. + \param parent: Parent of the scene node. Can be NULL if no parent. + \param id: Id of the node. This id can be used to identify the scene node. + \param position: Position of the space relative to its parent where the + scene node will be placed. + \param rotation: Initital rotation of the scene node. + \param scale: Initial scale of the scene node. + \return Returns pointer to the created test scene node. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual ISceneNode* addSphereSceneNode(f32 radius=5.0f, s32 polyCount=16, ISceneNode* parent=0, s32 id=-1, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) = 0; + + //! Adds a scene node for rendering an animated mesh model. + /** \param mesh: Pointer to the loaded animated mesh to be displayed. + \param parent: Parent of the scene node. Can be NULL if no parent. + \param id: Id of the node. This id can be used to identify the scene node. + \param position: Position of the space relative to its parent where the + scene node will be placed. + \param rotation: Initital rotation of the scene node. + \param scale: Initial scale of the scene node. + \param alsoAddIfMeshPointerZero: Add the scene node even if a 0 pointer is passed. + \return Returns pointer to the created scene node. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual IAnimatedMeshSceneNode* addAnimatedMeshSceneNode(IAnimatedMesh* mesh, ISceneNode* parent=0, s32 id=-1, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f), + bool alsoAddIfMeshPointerZero=false) = 0; + + //! Adds a scene node for rendering a static mesh. + /** \param mesh: Pointer to the loaded static mesh to be displayed. + \param parent: Parent of the scene node. Can be NULL if no parent. + \param id: Id of the node. This id can be used to identify the scene node. + \param position: Position of the space relative to its parent where the + scene node will be placed. + \param rotation: Initital rotation of the scene node. + \param scale: Initial scale of the scene node. + \param alsoAddIfMeshPointerZero: Add the scene node even if a 0 pointer is passed. + \return Returns pointer to the created scene node. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual IMeshSceneNode* addMeshSceneNode(IMesh* mesh, ISceneNode* parent=0, s32 id=-1, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f), + bool alsoAddIfMeshPointerZero=false) = 0; + + //! Adds a scene node for rendering a animated water surface mesh. + /** Looks really good when the Material type EMT_TRANSPARENT_REFLECTION + is used. + \param waveHeight: Height of the water waves. + \param waveSpeed: Speed of the water waves. + \param waveLength: Lenght of a water wave. + \param mesh: Pointer to the loaded static mesh to be displayed with water waves on it. + \param parent: Parent of the scene node. Can be NULL if no parent. + \param id: Id of the node. This id can be used to identify the scene node. + \param position: Position of the space relative to its parent where the + scene node will be placed. + \param rotation: Initital rotation of the scene node. + \param scale: Initial scale of the scene node. + \return Returns pointer to the created scene node. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual ISceneNode* addWaterSurfaceSceneNode(IMesh* mesh, + f32 waveHeight=2.0f, f32 waveSpeed=300.0f, f32 waveLength=10.0f, + ISceneNode* parent=0, s32 id=-1, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) = 0; + + + //! Adds a scene node for rendering using a octtree to the scene graph. + /** This a good method for rendering + scenes with lots of geometry. The Octree is built on the fly from the mesh. + \param mesh: The mesh containing all geometry from which the octtree will be build. + If this animated mesh has more than one frames in it, the first frame is taken. + \param parent: Parent node of the octtree node. + \param id: id of the node. This id can be used to identify the node. + \param minimalPolysPerNode: Specifies the minimal polygons contained a octree node. + If a node gets less polys than this value it will not be split into + smaller nodes. + \param alsoAddIfMeshPointerZero: Add the scene node even if a 0 pointer is passed. + \return Returns the pointer to the OctTree if successful, otherwise 0. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual ISceneNode* addOctTreeSceneNode(IAnimatedMesh* mesh, ISceneNode* parent=0, + s32 id=-1, s32 minimalPolysPerNode=256, bool alsoAddIfMeshPointerZero=false) = 0; + + //! Adds a scene node for rendering using a octtree to the scene graph. + /** This a good method for rendering + scenes with lots of geometry. The Octree is built on the fly from the mesh, much + faster then a bsp tree. + \param mesh: The mesh containing all geometry from which the octtree will be build. + \param parent: Parent node of the octtree node. + \param id: id of the node. This id can be used to identify the node. + \param minimalPolysPerNode: Specifies the minimal polygons contained a octree node. + If a node gets less polys than this value it will not be split into + smaller nodes. + \param alsoAddIfMeshPointerZero: Add the scene node even if a 0 pointer is passed. + \return Returns the pointer to the octtree if successful, otherwise 0. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual ISceneNode* addOctTreeSceneNode(IMesh* mesh, ISceneNode* parent=0, + s32 id=-1, s32 minimalPolysPerNode=256, bool alsoAddIfMeshPointerZero=false) = 0; + + //! Adds a camera scene node to the scene graph and sets it as active camera. + /** This camera does not react on user input like for example the one created with + addCameraSceneNodeFPS(). If you want to move or animate it, use animators or the + ISceneNode::setPosition(), ICameraSceneNode::setTarget() etc methods. + \param position: Position of the space relative to its parent where the camera will be placed. + \param lookat: Position where the camera will look at. Also known as target. + \param parent: Parent scene node of the camera. Can be null. If the parent moves, + the camera will move too. + \param id: id of the camera. This id can be used to identify the camera. + \return Returns pointer to interface to camera if successful, otherwise 0. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual ICameraSceneNode* addCameraSceneNode(ISceneNode* parent = 0, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& lookat = core::vector3df(0,0,100), s32 id=-1) = 0; + + //! Adds a maya style user controlled camera scene node to the scene graph. + /** The maya camera is able to be controlled with the mouse similar + like in the 3D Software Maya by Alias Wavefront. + \param parent: Parent scene node of the camera. Can be null. + \param rotateSpeed: Rotation speed of the camera. + \param zoomSpeed: Zoom speed of the camera. + \param translationSpeed: TranslationSpeed of the camera. + \param id: id of the camera. This id can be used to identify the camera. + \return Returns a pointer to the interface of the camera if successful, otherwise 0. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual ICameraSceneNode* addCameraSceneNodeMaya(ISceneNode* parent = 0, + f32 rotateSpeed = -1500.0f, f32 zoomSpeed = 200.0f, f32 translationSpeed = 1500.0f, s32 id=-1) = 0; + + //! Adds a camera scene node which is able to be controlled with the mouse and keys like in most first person shooters (FPS). + /** Look with the mouse, move with cursor keys. If you do not like the default + key layout, you may want to specify your own. For example to make the camera + be controlled by the cursor keys AND the keys W,A,S, and D, do something + like this: + \code + SKeyMap keyMap[8]; + keyMap[0].Action = EKA_MOVE_FORWARD; + keyMap[0].KeyCode = KEY_UP; + keyMap[1].Action = EKA_MOVE_FORWARD; + keyMap[1].KeyCode = KEY_KEY_W; + + keyMap[2].Action = EKA_MOVE_BACKWARD; + keyMap[2].KeyCode = KEY_DOWN; + keyMap[3].Action = EKA_MOVE_BACKWARD; + keyMap[3].KeyCode = KEY_KEY_S; + + keyMap[4].Action = EKA_STRAFE_LEFT; + keyMap[4].KeyCode = KEY_LEFT; + keyMap[5].Action = EKA_STRAFE_LEFT; + keyMap[5].KeyCode = KEY_KEY_A; + + keyMap[6].Action = EKA_STRAFE_RIGHT; + keyMap[6].KeyCode = KEY_RIGHT; + keyMap[7].Action = EKA_STRAFE_RIGHT; + keyMap[7].KeyCode = KEY_KEY_D; + + camera = sceneManager->addCameraSceneNodeFPS(0, 100, 500, -1, keyMap, 8); + \endcode + \param parent: Parent scene node of the camera. Can be null. + \param rotateSpeed: Speed with which the camera is rotated. This can be done + only with the mouse. + \param moveSpeed: Speed with which the camera is moved. Movement is done with + the cursor keys. + \param id: id of the camera. This id can be used to identify the camera. + \param keyMapArray: Optional pointer to an array of a keymap, specifying what + keys should be used to move the camera. If this is null, the default keymap + is used. You can define actions more then one time in the array, to bind + multiple keys to the same action. + \param keyMapSize: Amount of items in the keymap array. + \param noVerticalMovement: Setting this to true makes the camera only move within a + horizontal plane, and disables vertical movement as known from most ego shooters. Default + is 'false', with which it is possible to fly around in space, if no gravity is there. + \param jumpSpeed: Speed with which the camera is moved when jumping. + \return Returns a pointer to the interface of the camera if successful, otherwise 0. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual ICameraSceneNode* addCameraSceneNodeFPS(ISceneNode* parent = 0, + f32 rotateSpeed = 100.0f, f32 moveSpeed = 500.0f, s32 id=-1, + SKeyMap* keyMapArray=0, s32 keyMapSize=0, bool noVerticalMovement=false, + f32 jumpSpeed = 0.f) = 0; + + //! Adds a dynamic light scene node to the scene graph. + /** The light will cast dynamic light on all + other scene nodes in the scene, which have the material flag video::MTF_LIGHTING + turned on. (This is the default setting in most scene nodes). + \param parent: Parent scene node of the light. Can be null. If the parent moves, + the light will move too. + \param position: Position of the space relative to its parent where the light will be placed. + \param color: Diffuse color of the light. Ambient or Specular colors can be set manually with + the ILightSceneNode::getLightData() method. + \param radius: Radius of the light. + \param id: id of the node. This id can be used to identify the node. + \return Returns pointer to the interface of the light if successful, otherwise NULL. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual ILightSceneNode* addLightSceneNode(ISceneNode* parent = 0, + const core::vector3df& position = core::vector3df(0,0,0), + video::SColorf color = video::SColorf(1.0f, 1.0f, 1.0f), + f32 radius=100.0f, s32 id=-1) = 0; + + //! Adds a billboard scene node to the scene graph. + /** A billboard is like a 3d sprite: A 2d element, + which always looks to the camera. It is usually used for things like explosions, fire, + lensflares and things like that. + \param parent: Parent scene node of the billboard. Can be null. If the parent moves, + the billboard will move too. + \param position: Position of the space relative to its parent where the billboard will be placed. + \param size: Size of the billboard. This size is 2 dimensional because a billboard only has + width and height. + \param id: An id of the node. This id can be used to identify the node. + \param shade_top: vertex color top + \param shade_down: vertex color down + \return Returns pointer to the billboard if successful, otherwise NULL. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual IBillboardSceneNode* addBillboardSceneNode(ISceneNode* parent = 0, + const core::dimension2d& size = core::dimension2d(10.0f, 10.0f), + const core::vector3df& position = core::vector3df(0,0,0), s32 id=-1, + video::SColor shade_top = 0xFFFFFFFF, video::SColor shade_down = 0xFFFFFFFF) = 0; + + //! Adds a skybox scene node to the scene graph. + /** A skybox is a big cube with 6 textures on it and + is drawn around the camera position. + \param top: Texture for the top plane of the box. + \param bottom: Texture for the bottom plane of the box. + \param left: Texture for the left plane of the box. + \param right: Texture for the right plane of the box. + \param front: Texture for the front plane of the box. + \param back: Texture for the back plane of the box. + \param parent: Parent scene node of the skybox. A skybox usually has no parent, + so this should be null. Note: If a parent is set to the skybox, the box will not + change how it is drawn. + \param id: An id of the node. This id can be used to identify the node. + \return Returns a pointer to the sky box if successful, otherwise NULL. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual ISceneNode* addSkyBoxSceneNode(video::ITexture* top, video::ITexture* bottom, + video::ITexture* left, video::ITexture* right, video::ITexture* front, + video::ITexture* back, ISceneNode* parent = 0, s32 id=-1) = 0; + + //! Adds a skydome scene node to the scene graph. + /** A skydome is a large (half-) sphere with a panoramic texture + on the inside and is drawn around the camera position. + \param texture: Texture for the dome. + \param horiRes: Number of vertices of a horizontal layer of the sphere. + \param vertRes: Number of vertices of a vertical layer of the sphere. + \param texturePercentage: How much of the height of the texture is used. Should be between 0 and 1. + \param spherePercentage: How much of the sphere is drawn. Value should be between 0 and 2, where 1 is an exact half-sphere and 2 is a full sphere. + \param parent: Parent scene node of the dome. A dome usually has no parent, + so this should be null. Note: If a parent is set, the dome will not + change how it is drawn. + \param id: An id of the node. This id can be used to identify the node. + \return Returns a pointer to the sky dome if successful, otherwise NULL. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual ISceneNode* addSkyDomeSceneNode(video::ITexture* texture, + u32 horiRes, u32 vertRes, f64 texturePercentage, f64 spherePercentage, + ISceneNode* parent = 0, s32 id=-1) = 0; + + //! Adds a particle system scene node to the scene graph. + /** \param withDefaultEmitter: Creates a default working point emitter + which emitts some particles. Set this to true to see a particle system + in action. If set to false, you'll have to set the emitter you want by + calling IParticleSystemSceneNode::setEmitter(). + \param parent: Parent of the scene node. Can be NULL if no parent. + \param id: Id of the node. This id can be used to identify the scene node. + \param position: Position of the space relative to its parent where the + scene node will be placed. + \param rotation: Initital rotation of the scene node. + \param scale: Initial scale of the scene node. + \return Returns pointer to the created scene node. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual IParticleSystemSceneNode* addParticleSystemSceneNode( + bool withDefaultEmitter=true, ISceneNode* parent=0, s32 id=-1, + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) = 0; + + //! Adds a terrain scene node to the scene graph. + /** This node implements is a simple terrain renderer which uses + a technique known as geo mip mapping + for reducing the detail of triangle blocks which are far away. + The code for the TerrainSceneNode is based on the terrain + renderer by Soconne and the GeoMipMapSceneNode developed by + Spintz. They made their code available for Irrlicht and allowed + it to be distributed under this licence. I only modified some + parts. A lot of thanks go to them. + + This scene node is capable of loading terrains and updating + the indices at runtime to enable viewing very large terrains + very quickly. It uses a CLOD (Continuous Level of Detail) + algorithm which updates the indices for each patch based on + a LOD (Level of Detail) which is determined based on a patch's + distance from the camera. + + The patch size of the terrain must always be a size of ( 2^N+1, i.e. 8+1(9), 16+1(17), etc. ). + The MaxLOD available is directly dependent on the patch size of the terrain. LOD 0 contains all + of the indices to draw all the triangles at the max detail for a patch. As each LOD goes up by 1 + the step taken, in generating indices increases by - 2^LOD, so for LOD 1, the step taken is 2, for + LOD 2, the step taken is 4, LOD 3 - 8, etc. The step can be no larger than the size of the patch, + so having a LOD of 8, with a patch size of 17, is asking the algoritm to generate indices every + 2^8 ( 256 ) vertices, which is not possible with a patch size of 17. The maximum LOD for a patch + size of 17 is 2^4 ( 16 ). So, with a MaxLOD of 5, you'll have LOD 0 ( full detail ), LOD 1 ( every + 2 vertices ), LOD 2 ( every 4 vertices ), LOD 3 ( every 8 vertices ) and LOD 4 ( every 16 vertices ). + \param heightMapFileName: The name of the file on disk, to read vertex data from. This should + be a gray scale bitmap. + \param parent: Parent of the scene node. Can be 0 if no parent. + \param id: Id of the node. This id can be used to identify the scene node. + \param position: The absolute position of this node. + \param rotation: The absolute rotation of this node. ( NOT YET IMPLEMENTED ) + \param scale: The scale factor for the terrain. If you're using a heightmap of size 129x129 and would like + your terrain to be 12900x12900 in game units, then use a scale factor of ( core::vector ( 100.0f, 100.0f, 100.0f ). + If you use a Y scaling factor of 0.0f, then your terrain will be flat. + \param vertexColor: The default color of all the vertices. If no texture is associated + with the scene node, then all vertices will be this color. Defaults to white. + \param maxLOD: The maximum LOD (level of detail) for the node. Only change if you + know what you are doing, this might lead to strange behaviour. + \param patchSize: patch size of the terrain. Only change if you + know what you are doing, this might lead to strange behaviour. + \param smoothFactor: The number of times the vertices are smoothed. + \param addAlsoIfHeightmapEmpty: Add terrain node even with empty heightmap. + \return Returns pointer to the created scene node. Can be null if the + terrain could not be created, for example because the heightmap could not be loaded. + The returned pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual ITerrainSceneNode* addTerrainSceneNode( + const c8* heightMapFileName, + ISceneNode* parent=0, s32 id=-1, + const core::vector3df& position = core::vector3df(0.0f,0.0f,0.0f), + const core::vector3df& rotation = core::vector3df(0.0f,0.0f,0.0f), + const core::vector3df& scale = core::vector3df(1.0f,1.0f,1.0f), + video::SColor vertexColor = video::SColor(255,255,255,255), + s32 maxLOD=5, E_TERRAIN_PATCH_SIZE patchSize=ETPS_17, s32 smoothFactor=0, + bool addAlsoIfHeightmapEmpty = false) = 0; + + //! Adds a terrain scene node to the scene graph. + /** Just like the other addTerrainSceneNode() method, but takes an IReadFile + pointer as parameter for the heightmap. For more informations take a look + at the other function. + \param heightMapFile: The file handle to read vertex data from. This should + be a gray scale bitmap. + \param parent: Parent of the scene node. Can be 0 if no parent. + \param id: Id of the node. This id can be used to identify the scene node. + \param position: The absolute position of this node. + \param rotation: The absolute rotation of this node. ( NOT YET IMPLEMENTED ) + \param scale: The scale factor for the terrain. If you're using a heightmap of size 129x129 and would like + your terrain to be 12900x12900 in game units, then use a scale factor of ( core::vector ( 100.0f, 100.0f, 100.0f ). + If you use a Y scaling factor of 0.0f, then your terrain will be flat. + \param vertexColor: The default color of all the vertices. If no texture is associated + with the scene node, then all vertices will be this color. Defaults to white. + \param maxLOD: The maximum LOD (level of detail) for the node. Only change if you + know what you are doing, this might lead to strange behaviour. + \param patchSize: patch size of the terrain. Only change if you + know what you are doing, this might lead to strange behaviour. + \param smoothFactor: The number of times the vertices are smoothed. + \param addAlsoIfHeightmapEmpty: Add terrain node even with empty heightmap. + \return Returns pointer to the created scene node. Can be null if the + terrain could not be created, for example because the heightmap could not be loaded. + The returned pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual ITerrainSceneNode* addTerrainSceneNode( + io::IReadFile* heightMapFile, + ISceneNode* parent=0, s32 id=-1, + const core::vector3df& position = core::vector3df(0.0f,0.0f,0.0f), + const core::vector3df& rotation = core::vector3df(0.0f,0.0f,0.0f), + const core::vector3df& scale = core::vector3df(1.0f,1.0f,1.0f), + video::SColor vertexColor = video::SColor(255,255,255,255), + s32 maxLOD=5, E_TERRAIN_PATCH_SIZE patchSize=ETPS_17, s32 smoothFactor=0, + bool addAlsoIfHeightmapEmpty = false) = 0; + + //! Adds a quake3 scene node to the scene graph. + /** A Quake3 Scene renders multiple meshes for a specific HighLanguage Shader (Quake3 Style ) + \return Returns a pointer to the quake3 scene node if successful, otherwise NULL. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual ISceneNode* addQuake3SceneNode(IMeshBuffer* meshBuffer, const quake3::SShader * shader, + ISceneNode* parent=0, s32 id=-1 + ) = 0; + + + //! Adds an empty scene node to the scene graph. + /** Can be used for doing advanced transformations + or structuring the scene graph. + \return Returns pointer to the created scene node. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual ISceneNode* addEmptySceneNode(ISceneNode* parent=0, s32 id=-1) = 0; + + //! Adds a dummy transformation scene node to the scene graph. + /** This scene node does not render itself, and does not respond to set/getPosition, + set/getRotation and set/getScale. Its just a simple scene node that takes a + matrix as relative transformation, making it possible to insert any transformation + anywhere into the scene graph. + \return Returns pointer to the created scene node. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual IDummyTransformationSceneNode* addDummyTransformationSceneNode( + ISceneNode* parent=0, s32 id=-1) = 0; + + //! Adds a text scene node, which is able to display 2d text at a position in three dimensional space + virtual ITextSceneNode* addTextSceneNode(gui::IGUIFont* font, const wchar_t* text, + video::SColor color=video::SColor(100,255,255,255), + ISceneNode* parent = 0, const core::vector3df& position = core::vector3df(0,0,0), + s32 id=-1) = 0; + + //! Adds a text scene node, which uses billboards + virtual ITextSceneNode* addBillboardTextSceneNode( gui::IGUIFont* font, const wchar_t* text, + ISceneNode* parent = 0, + const core::dimension2d& size = core::dimension2d(10.0f, 10.0f), + const core::vector3df& position = core::vector3df(0,0,0), s32 id=-1, + video::SColor shade_top = 0xFFFFFFFF, video::SColor shade_down = 0xFFFFFFFF) = 0; + + //! Adds a Hill Plane mesh to the mesh pool. + /** The mesh is generated on the fly + and looks like a plane with some hills on it. It is uses mostly for quick + tests of the engine only. You can specify how many hills there should be + on the plane and how high they should be. Also you must specify a name for + the mesh, because the mesh is added to the mesh pool, and can be retrieved + again using ISceneManager::getMesh() with the name as parameter. + \param name: The name of this mesh which must be specified in order + to be able to retrieve the mesh later with ISceneManager::getMesh(). + \param tileSize: Size of a tile of the mesh. (10.0f, 10.0f) would be a + good value to start, for example. + \param tileCount: Specifies how much tiles there will be. If you specifiy + for example that a tile has the size (10.0f, 10.0f) and the tileCount is + (10,10), than you get a field of 100 tiles which has the dimension 100.0fx100.0f. + \param material: Material of the hill mesh. + \param hillHeight: Height of the hills. If you specify a negative value + you will get holes instead of hills. If the height is 0, no hills will be + created. + \param countHills: Amount of hills on the plane. There will be countHills.X + hills along the X axis and countHills.Y along the Y axis. So in total there + will be countHills.X * countHills.Y hills. + \param textureRepeatCount: Defines how often the texture will be repeated in + x and y direction. + \return Returns null if the creation failed. The reason could be that you + specified some invalid parameters or that a mesh with that name already + exists. If successful, a pointer to the mesh is returned. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual IAnimatedMesh* addHillPlaneMesh(const c8* name, + const core::dimension2d& tileSize, const core::dimension2d& tileCount, + video::SMaterial* material = 0, f32 hillHeight = 0.0f, + const core::dimension2d& countHills = core::dimension2d(0.0f, 0.0f), + const core::dimension2d& textureRepeatCount = core::dimension2d(1.0f, 1.0f)) = 0; + + //! Adds a static terrain mesh to the mesh pool. + /** The mesh is generated on the fly + from a texture file and a height map file. Both files may be huge + (8000x8000 pixels would be no problem) because the generator splits the + files into smaller textures if necessary. + You must specify a name for the mesh, because the mesh is added to the mesh pool, + and can be retrieved again using ISceneManager::getMesh() with the name as parameter. + \param meshname: The name of this mesh which must be specified in order + to be able to retrieve the mesh later with ISceneManager::getMesh(). + \param texture: Texture for the terrain. Please note that this is not a + hardware texture as usual (ITexture), but an IImage software texture. + You can load this texture with IVideoDriver::createImageFromFile(). + \param heightmap: A grayscaled heightmap image. Like the texture, + it can be created with IVideoDriver::createImageFromFile(). The amount + of triangles created depends on the size of this texture, so use a small + heightmap to increase rendering speed. + \param stretchSize: Parameter defining how big a is pixel on the heightmap. + \param maxHeight: Defines how height a white pixel on the heighmap is. + \param defaultVertexBlockSize: Defines the initial dimension between vertices. + \return Returns null if the creation failed. The reason could be that you + specified some invalid parameters, that a mesh with that name already + exists, or that a texture could not be found. If successful, a pointer to the mesh is returned. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + virtual IAnimatedMesh* addTerrainMesh(const c8* meshname, + video::IImage* texture, video::IImage* heightmap, + const core::dimension2d& stretchSize = core::dimension2d(10.0f,10.0f), + f32 maxHeight=200.0f, + const core::dimension2d& defaultVertexBlockSize = core::dimension2d(64,64)) = 0; + + //! add a static arrow mesh to the meshpool + virtual IAnimatedMesh* addArrowMesh(const c8* name, + video::SColor vtxColor0=0xFFFFFFFF, + video::SColor vtxColor1=0xFFFFFFFF, + u32 tesselationCylinder=4, u32 tesselationCone=8, + f32 height=1.f, f32 cylinderHeight=0.6f, + f32 width0=0.05f, f32 width1=0.3f) = 0; + + //! add a static sphere mesh to the meshpool + virtual IAnimatedMesh* addSphereMesh(const c8* name, + f32 radius=5.f, u32 polyCountX = 16, + u32 polyCountY = 16) = 0; + + //! Returns the root scene node. + /** This is the scene node which is parent + of all scene nodes. The root scene node is a special scene node which + only exists to manage all scene nodes. It will not be rendered and cannot + be removed from the scene. + \return Returns a pointer to the root scene node. */ + virtual ISceneNode* getRootSceneNode() = 0; + + //! Returns the first scene node with the specified id. + /** \param id: The id to search for + \param start: Scene node to start from. All children of this scene + node are searched. If null is specified, the root scene node is + taken. + \return Returns pointer to the first scene node with this id, + and null if no scene node could be found. */ + virtual ISceneNode* getSceneNodeFromId(s32 id, ISceneNode* start=0) = 0; + + //! Returns the first scene node with the specified name. + /** \param name: The name to search for + \param start: Scene node to start from. All children of this scene + node are searched. If null is specified, the root scene node is + taken. + \return Returns pointer to the first scene node with this id, + and null if no scene node could be found. */ + virtual ISceneNode* getSceneNodeFromName(const c8* name, ISceneNode* start=0) = 0; + + //! Returns the first scene node with the specified type. + /** \param type: The type to search for + \param start: Scene node to start from. All children of this scene + node are searched. If null is specified, the root scene node is + taken. + \return Returns pointer to the first scene node with this type, + and null if no scene node could be found. */ + virtual ISceneNode* getSceneNodeFromType(scene::ESCENE_NODE_TYPE type, ISceneNode* start=0) = 0; + + //! returns scene nodes by type. + /** \param type: Type of scene node to find. + \param outNodes: array to be filled with results. + \param start: Scene node to start from. All children of this scene + node are searched. If null is specified, the root scene node is + taken. */ + virtual void getSceneNodesFromType(ESCENE_NODE_TYPE type, core::array& outNodes, ISceneNode* start=0) = 0; + + //! Returns the current active camera. + /** \return The active camera is returned. Note that this can be NULL, if there + was no camera created yet. */ + virtual ICameraSceneNode* getActiveCamera() = 0; + + //! Sets the currently active camera. + /** The previous active camera will be deactivated. + \param camera: The new camera which should be active. */ + virtual void setActiveCamera(ICameraSceneNode* camera) = 0; + + //! Sets the color of stencil buffers shadows drawn by the scene manager. + virtual void setShadowColor(video::SColor color = video::SColor(150,0,0,0)) = 0; + + //! Returns the current color of shadows. + virtual video::SColor getShadowColor() const = 0; + + //! Registers a node for rendering it at a specific time. + /** This method should only be used by SceneNodes when they get a + ISceneNode::OnRegisterSceneNode() call. + \param node: Node to register for drawing. Usually scene nodes would set 'this' + as parameter here because they want to be drawn. + \param pass: Specifies when the mode wants to be drawn in relation to the other nodes. + For example, if the node is a shadow, it usually wants to be drawn after all other nodes + and will use ESNRP_SHADOW for this. See E_SCENE_NODE_RENDER_PASS for details. + \return scene will be rendered ( passed culling ) */ + virtual u32 registerNodeForRendering(ISceneNode* node, + E_SCENE_NODE_RENDER_PASS pass = ESNRP_AUTOMATIC) = 0; + + //! Draws all the scene nodes. + /** This can only be invoked between + IVideoDriver::beginScene() and IVideoDriver::endScene(). Please note that + the scene is not only drawn when calling this, but also animated + by existing scene node animators, culling of scene nodes is done, etc. */ + virtual void drawAll() = 0; + + //! Creates a rotation animator, which rotates the attached scene node around itself. + /** \param rotationPerSecond: Specifies the speed of the animation + \return Returns the animator. Attach it to a scene node with ISceneNode::addAnimator() + and the animator will animate it. + If you no longer need the animator, you should call ISceneNodeAnimator::drop(). + See IReferenceCounted::drop() for more information. */ + virtual ISceneNodeAnimator* createRotationAnimator(const core::vector3df& rotationPerSecond) = 0; + + //! Creates a fly circle animator, which lets the attached scene node fly around a center. + /** \param center: Center of the circle. + \param radius: Radius of the circle. + \param speed: Specifies the speed of the flight. + \param direction: Specifies the upvector used for alignment of the mesh. + \return Returns the animator. Attach it to a scene node with ISceneNode::addAnimator() + and the animator will animate it. + If you no longer need the animator, you should call ISceneNodeAnimator::drop(). + See IReferenceCounted::drop() for more information. */ + virtual ISceneNodeAnimator* createFlyCircleAnimator(const core::vector3df& center, + f32 radius, f32 speed=0.001f, const core::vector3df& direction= core::vector3df ( 0.f, 1.f, 0.f ) ) = 0; + + //! Creates a fly straight animator, which lets the attached scene node fly or move along a line between two points. + /** \param startPoint: Start point of the line. + \param endPoint: End point of the line. + \param timeForWay: Time in milli seconds how long the node should need to + move from the start point to the end point. + \param loop: If set to false, the node stops when the end point is reached. + If loop is true, the node begins again at the start. + \return Returns the animator. Attach it to a scene node with ISceneNode::addAnimator() + and the animator will animate it. + If you no longer need the animator, you should call ISceneNodeAnimator::drop(). + See IReferenceCounted::drop() for more information. */ + virtual ISceneNodeAnimator* createFlyStraightAnimator(const core::vector3df& startPoint, + const core::vector3df& endPoint, u32 timeForWay, bool loop=false) = 0; + + //! Creates a texture animator, which switches the textures of the target scene node based on a list of textures. + /** \param textures: List of textures to use. + \param timePerFrame: Time in milliseconds, how long any texture in the list + should be visible. + \param loop: If set to to false, the last texture remains set, and the animation + stops. If set to true, the animation restarts with the first texture. + \return Returns the animator. Attach it to a scene node with ISceneNode::addAnimator() + and the animator will animate it. + If you no longer need the animator, you should call ISceneNodeAnimator::drop(). + See IReferenceCounted::drop() for more information. */ + virtual ISceneNodeAnimator* createTextureAnimator(const core::array& textures, + s32 timePerFrame, bool loop=true) = 0; + + //! Creates a scene node animator, which deletes the scene node after some time automatically. + /** \param timeMs: Time in milliseconds, after when the node will be deleted. + \return Returns the animator. Attach it to a scene node with ISceneNode::addAnimator() + and the animator will animate it. + If you no longer need the animator, you should call ISceneNodeAnimator::drop(). + See IReferenceCounted::drop() for more information. */ + virtual ISceneNodeAnimator* createDeleteAnimator(u32 timeMs) = 0; + + //! Creates a special scene node animator for doing automatic collision detection and response. + /** See ISceneNodeAnimatorCollisionResponse for details. + \param world: Triangle selector holding all triangles of the world with which + the scene node may collide. You can create a triangle selector with + ISceneManager::createTriangleSelector(); + \param sceneNode: SceneNode which should be manipulated. After you added this animator + to the scene node, the scene node will not be able to move through walls and is + affected by gravity. + \param ellipsoidRadius: Radius of the ellipsoid with which collision detection and + response is done. If you have got a scene node, and you are unsure about + how big the radius should be, you could use the following code to determine + it: + \code + const core::aabbox& box = yourSceneNode->getBoundingBox(); + core::vector3df radius = box.MaxEdge - box.getCenter(); + \endcode + \param gravityPerSecond: Sets the gravity of the environment. A good example value would be + core::vector3df(0,-100.0f,0) for letting gravity affect all object to + fall down. For bigger gravity, make increase the length of the vector. + You can disable gravity by setting it to core::vector3df(0,0,0). + \param ellipsoidTranslation: By default, the ellipsoid for collision detection is created around + the center of the scene node, which means that the ellipsoid surrounds + it completely. If this is not what you want, you may specify a translation + for the ellipsoid. + \param slidingValue: DOCUMENTATION NEEDED. + \return Returns the animator. Attach it to a scene node with ISceneNode::addAnimator() + and the animator will cause it to do collision detection and response. + If you no longer need the animator, you should call ISceneNodeAnimator::drop(). + See IReferenceCounted::drop() for more information. */ + virtual ISceneNodeAnimatorCollisionResponse* createCollisionResponseAnimator( + ITriangleSelector* world, ISceneNode* sceneNode, + const core::vector3df& ellipsoidRadius = core::vector3df(30,60,30), + const core::vector3df& gravityPerSecond = core::vector3df(0,-100.0f,0), + const core::vector3df& ellipsoidTranslation = core::vector3df(0,0,0), + f32 slidingValue = 0.0005f) = 0; + + //! Creates a follow spline animator. + /** The animator modifies the position of + the attached scene node to make it follow a hermite spline. + The code of the is based on a scene node + Matthias Gall sent in. Thanks! I adapted the code just a little bit. Matthias + wrote: + Uses a subset of hermite splines: either cardinal splines (tightness != 0.5) or catmull-rom-splines (tightness == 0.5) + but this is just my understanding of this stuff, I'm not a mathematician, so this might be wrong ;) */ + virtual ISceneNodeAnimator* createFollowSplineAnimator(s32 startTime, + const core::array< core::vector3df >& points, + f32 speed = 1.0f, f32 tightness = 0.5f) = 0; + + //! Creates a simple ITriangleSelector, based on a mesh. + /** Triangle selectors + can be used for doing collision detection. Don't use this selector + for a huge amount of triangles like in Quake3 maps. + Instead, use for example ISceneManager::createOctTreeTriangleSelector(). + Please note that the created triangle selector is not automaticly attached + to the scene node. You will have to call ISceneNode::setTriangleSelector() + for this. To create and attach a triangle selector is done like this: + \code + ITriangleSelector* s = sceneManager->createTriangleSelector(yourMesh, + yourSceneNode); + yourSceneNode->setTriangleSelector(s); + s->drop(); + \endcode + \param mesh: Mesh of which the triangles are taken. + \param node: Scene node of which visibility and transformation is used. + \return Returns the selector, or null if not successful. + If you no longer need the selector, you should call ITriangleSelector::drop(). + See IReferenceCounted::drop() for more information. */ + virtual ITriangleSelector* createTriangleSelector(IMesh* mesh, ISceneNode* node) = 0; + + //! Creates a simple dynamic ITriangleSelector, based on a axis aligned bounding box. + /** Triangle selectors + can be used for doing collision detection. Every time when triangles are + queried, the triangle selector gets the bounding box of the scene node, + an creates new triangles. In this way, it works good with animated scene nodes. + \param node: Scene node of which the bounding box, visibility and transformation is used. + \return Returns the selector, or null if not successful. + If you no longer need the selector, you should call ITriangleSelector::drop(). + See IReferenceCounted::drop() for more information. */ + virtual ITriangleSelector* createTriangleSelectorFromBoundingBox(ISceneNode* node) = 0; + + //! Creates a Triangle Selector, optimized by an octtree. + /** Triangle selectors + can be used for doing collision detection. This triangle selector is + optimized for huge amounts of triangle, it organizes them in an octtree. + Please note that the created triangle selector is not automaticly attached + to the scene node. You will have to call ISceneNode::setTriangleSelector() + for this. To create and attach a triangle selector is done like this: + \code + ITriangleSelector* s = sceneManager->createOctTreeTriangleSelector(yourMesh, + yourSceneNode); + yourSceneNode->setTriangleSelector(s); + s->drop(); + \endcode + For more informations and examples on this, take a look at the collision + tutorial in the SDK. + \param mesh: Mesh of which the triangles are taken. + \param node: Scene node of which visibility and transformation is used. + \param minimalPolysPerNode: Specifies the minimal polygons contained a octree node. + If a node gets less polys the this value, it will not be splitted into + smaller nodes. + \return Returns the selector, or null if not successful. + If you no longer need the selector, you should call ITriangleSelector::drop(). + See IReferenceCounted::drop() for more information. */ + virtual ITriangleSelector* createOctTreeTriangleSelector(IMesh* mesh, + ISceneNode* node, s32 minimalPolysPerNode=32) = 0; + + //! Creates a meta triangle selector. + /** A meta triangle selector is nothing more than a + collection of one or more triangle selectors providing together + the interface of one triangle selector. In this way, + collision tests can be done with different triangle soups in one pass. + \return Returns the selector, or null if not successful. + If you no longer need the selector, you should call ITriangleSelector::drop(). + See IReferenceCounted::drop() for more information. */ + virtual IMetaTriangleSelector* createMetaTriangleSelector() = 0; + + //! Creates a triangle selector which can select triangles from a terrain scene node. + /** \param node: Pointer to the created terrain scene node + \param LOD: Level of detail, 0 for highest detail. */ + virtual ITriangleSelector* createTerrainTriangleSelector( + ITerrainSceneNode* node, s32 LOD=0) = 0; + + //! Adds an external mesh loader for extending the engine with new file formats. + /** If you want the engine to be extended with + file formats it currently is not able to load (e.g. .cob), just implement + the IMeshLoader interface in your loading class and add it with this method. + Using this method it is also possible to override built-in mesh loaders with + newer or updated versions without the need of recompiling the engine. + \param externalLoader: Implementation of a new mesh loader. */ + virtual void addExternalMeshLoader(IMeshLoader* externalLoader) = 0; + + //! Returns a pointer to the scene collision manager. + virtual ISceneCollisionManager* getSceneCollisionManager() = 0; + + //! Returns a pointer to the mesh manipulator. + virtual IMeshManipulator* getMeshManipulator() = 0; + + //! Adds a scene node to the deletion queue. + /** The scene node is immediatly + deleted when it's secure. Which means when the scene node does not + execute animators and things like that. This method is for example + used for deleting scene nodes by their scene node animators. In + most other cases, a ISceneNode::remove() call is enough, using this + deletion queue is not necessary. + See ISceneManager::createDeleteAnimator() for details. + \param node: Node to detete. */ + virtual void addToDeletionQueue(ISceneNode* node) = 0; + + //! Posts an input event to the environment. + /** Usually you do not have to + use this method, it is used by the internal engine. */ + virtual bool postEventFromUser(const SEvent& event) = 0; + + //! Clears the whole scene. + /** All scene nodes are removed. */ + virtual void clear() = 0; + + //! Returns interface to the parameters set in this scene. + /** String parameters can be used by plugins and mesh loaders. + For example the CMS and LMTS loader want a parameter named 'CSM_TexturePath' + and 'LMTS_TexturePath' set to the path were attached textures can be found. See + CSM_TEXTURE_PATH, LMTS_TEXTURE_PATH, MY3D_TEXTURE_PATH, + COLLADA_CREATE_SCENE_INSTANCES, DMF_TEXTURE_PATH and DMF_USE_MATERIALS_DIRS*/ + virtual io::IAttributes* getParameters() = 0; + + //! Returns current render pass. + /** All scene nodes are being rendered in a specific order. + First lights, cameras, sky boxes, solid geometry, and then transparent + stuff. During the rendering process, scene nodes may want to know what the scene + manager is rendering currently, because for example they registered for rendering + twice, once for transparent geometry and once for solid. When knowing what rendering + pass currently is active they can render the correct part of their geometry. */ + virtual E_SCENE_NODE_RENDER_PASS getSceneNodeRenderPass() const = 0; + + //! Returns the default scene node factory which can create all built in scene nodes + virtual ISceneNodeFactory* getDefaultSceneNodeFactory() = 0; + + //! Adds a scene node factory to the scene manager. + /** Use this to extend the scene manager with new scene node types which it should be + able to create automaticly, for example when loading data from xml files. */ + virtual void registerSceneNodeFactory(ISceneNodeFactory* factoryToAdd) = 0; + + //! Returns amount of registered scene node factories. + virtual u32 getRegisteredSceneNodeFactoryCount() const = 0; + + //! Returns a scene node factory by index + virtual ISceneNodeFactory* getSceneNodeFactory(u32 index) = 0; + + //! Returns the default scene node animator factory which can create all built-in scene node animators + virtual ISceneNodeAnimatorFactory* getDefaultSceneNodeAnimatorFactory() = 0; + + //! Adds a scene node animator factory to the scene manager. + /** Use this to extend the scene manager with new scene node animator types which it should be + able to create automaticly, for example when loading data from xml files. */ + virtual void registerSceneNodeAnimatorFactory(ISceneNodeAnimatorFactory* factoryToAdd) = 0; + + //! Returns amount of registered scene node animator factories. + virtual u32 getRegisteredSceneNodeAnimatorFactoryCount() const = 0; + + //! Returns a scene node animator factory by index + virtual ISceneNodeAnimatorFactory* getSceneNodeAnimatorFactory(u32 index) = 0; + + //! Returns a typename from a scene node type or null if not found + virtual const c8* getSceneNodeTypeName(ESCENE_NODE_TYPE type) = 0; + + //! Adds a scene node to the scene by name + virtual ISceneNode* addSceneNode(const char* sceneNodeTypeName, ISceneNode* parent) = 0; + + //! Creates a new scene manager. + /** This can be used to easily draw and/or store two independent scenes at the same time. + The mesh cache will be shared between all existing scene managers, which means if you load + a mesh in the original scene manager using for example getMesh(), the mesh will be available + in all other scene managers too, without loading. + The original/main scene manager will still be there and accessible via IrrlichtDevice::getSceneManager(). + If you need input event in this new scene manager, for example for FPS cameras, you'll need + to forward input to this manually: Just implement an IEventReceiver and call + yourNewSceneManager->postEventFromUser(), and return true so that the original scene manager + doesn't get the event. Otherwise, all input will go automaticly to the main scene manager. + If you no longer need the new scene manager, you should call ISceneManager::drop(). + See IReferenceCounted::drop() for more information. */ + virtual ISceneManager* createNewSceneManager(bool cloneContent=false) = 0; + + //! Saves the current scene into a file. + /** Scene nodes with the option isDebugObject set to true are not being saved. + The scene is usually written to an .irr file, an xml based format. .irr files can + Be edited with the Irrlicht Engine Editor, irrEdit (http://irredit.irrlicht3d.org). + To load .irr files again, see ISceneManager::loadScene(). + \param filename: Name of the file. + \param userDataSerializer: If you want to save some user data for every scene node into the + file, implement the ISceneUserDataSerializer interface and provide it as parameter here. + Otherwise, simply specify 0 as this parameter. + \return Returns true if successful. */ + virtual bool saveScene(const c8* filename, ISceneUserDataSerializer* userDataSerializer=0) = 0; + + //! Saves the current scene into a file. + /** Scene nodes with the option isDebugObject set to true are not being saved. + The scene is usually written to an .irr file, an xml based format. .irr files can + Be edited with the Irrlicht Engine Editor, irrEdit (http://irredit.irrlicht3d.org). + To load .irr files again, see ISceneManager::loadScene(). + \param file: File where the scene is saved into. + \param userDataSerializer: If you want to save some user data for every scene node into the + file, implement the ISceneUserDataSerializer interface and provide it as parameter here. + Otherwise, simply specify 0 as this parameter. + \return Returns true if successful. */ + virtual bool saveScene(io::IWriteFile* file, ISceneUserDataSerializer* userDataSerializer=0) = 0; + + //! Loads a scene. Note that the current scene is not cleared before. + /** The scene is usually load from an .irr file, an xml based format. .irr files can + Be edited with the Irrlicht Engine Editor, irrEdit (http://irredit.irrlicht3d.org) or + saved directly by the engine using ISceneManager::saveScene(). + \param filename: Name of the file. + \param userDataSerializer: If you want to load user data possibily saved in that file for + some scene nodes in the file, implement the ISceneUserDataSerializer interface and provide it as parameter here. + Otherwise, simply specify 0 as this parameter. + \return Returns true if successful. */ + virtual bool loadScene(const c8* filename, ISceneUserDataSerializer* userDataSerializer=0) = 0; + + //! Loads a scene. Note that the current scene is not cleared before. + /** The scene is usually load from an .irr file, an xml based format. .irr files can + Be edited with the Irrlicht Engine Editor, irrEdit (http://irredit.irrlicht3d.org) or + saved directly by the engine using ISceneManager::saveScene(). + \param file: File where the scene is going to be saved into. + \param userDataSerializer: If you want to load user data possibily saved in that file for + some scene nodes in the file, implement the ISceneUserDataSerializer interface and provide it as parameter here. + Otherwise, simply specify 0 as this parameter. + \return Returns true if successful. */ + virtual bool loadScene(io::IReadFile* file, ISceneUserDataSerializer* userDataSerializer=0) = 0; + + //! Returns a mesh writer implementation if available + /** Note: You need to drop() the pointer after use again, see IReferenceCounted::drop() + for details. */ + virtual IMeshWriter* createMeshWriter(EMESH_WRITER_TYPE type) = 0; + + //! Sets ambient color of the scene + virtual void setAmbientLight(const video::SColorf &ambientColor) = 0; + + //! Returns ambient color of the scene + virtual const video::SColorf& getAmbientLight() const = 0; + + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/media/lightFalloff.png b/media/lightFalloff.png new file mode 100644 index 0000000000000000000000000000000000000000..21b2142aa9fb969838713c82126efe7f8cb60868 GIT binary patch literal 43385 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 - - if (FileSystem) - FileSystem->grab(); - - if (CursorControl) - CursorControl->grab(); - - if ( GUIEnvironment ) - GUIEnvironment->grab(); - - // create mesh cache if not there already - if (!MeshCache) - MeshCache = new CMeshCache(); - else - MeshCache->grab(); - - // create collision manager - CollisionManager = new CSceneCollisionManager(this, Driver); - - // create manipulator - MeshManipulator = new CMeshManipulator(); - - // add file format loaders - - #ifdef _IRR_COMPILE_WITH_IRR_MESH_LOADER_ - MeshLoaderList.push_back(new CIrrMeshFileLoader(Driver, this, FileSystem)); - #endif - #ifdef _IRR_COMPILE_WITH_BSP_LOADER_ - MeshLoaderList.push_back(new CBSPMeshFileLoader(FileSystem, Driver, this)); - #endif - #ifdef _IRR_COMPILE_WITH_MD2_LOADER_ - MeshLoaderList.push_back(new CMD2MeshFileLoader()); - #endif - #ifdef _IRR_COMPILE_WITH_MS3D_LOADER_ - MeshLoaderList.push_back(new CMS3DMeshFileLoader(Driver)); - #endif - #ifdef _IRR_COMPILE_WITH_3DS_LOADER_ - MeshLoaderList.push_back(new C3DSMeshFileLoader(MeshManipulator,FileSystem, Driver)); - #endif - #ifdef _IRR_COMPILE_WITH_X_LOADER_ - MeshLoaderList.push_back(new CXMeshFileLoader(this)); - #endif - #ifdef _IRR_COMPILE_WITH_OCT_LOADER_ - MeshLoaderList.push_back(new COCTLoader(Driver)); - #endif - #ifdef _IRR_COMPILE_WITH_CSM_LOADER_ - MeshLoaderList.push_back(new CCSMLoader(this, FileSystem)); - #endif - #ifdef _IRR_COMPILE_WITH_LMTS_LOADER_ - MeshLoaderList.push_back(new CLMTSMeshFileLoader(FileSystem, Driver, &Parameters)); - #endif - #ifdef _IRR_COMPILE_WITH_MY3D_LOADER_ - MeshLoaderList.push_back(new CMY3DMeshFileLoader(FileSystem, Driver, this)); - #endif - #ifdef _IRR_COMPILE_WITH_COLLADA_LOADER_ - MeshLoaderList.push_back(new CColladaFileLoader(Driver, this, FileSystem)); - #endif - #ifdef _IRR_COMPILE_WITH_DMF_LOADER_ - MeshLoaderList.push_back(new CDMFLoader(Driver, this)); - #endif - #ifdef _IRR_COMPILE_WITH_OGRE_LOADER_ - MeshLoaderList.push_back(new COgreMeshFileLoader(MeshManipulator, FileSystem, Driver)); - #endif - #ifdef _IRR_COMPILE_WITH_OBJ_LOADER_ - MeshLoaderList.push_back(new COBJMeshFileLoader(FileSystem, Driver)); - #endif - #ifdef _IRR_COMPILE_WITH_MD3_LOADER_ - MeshLoaderList.push_back(new CMD3MeshFileLoader(FileSystem, Driver)); - #endif - #ifdef _IRR_COMPILE_WITH_B3D_LOADER_ - MeshLoaderList.push_back(new CB3DMeshFileLoader(this)); - #endif - #ifdef _IRR_COMPILE_WITH_STL_LOADER_ - MeshLoaderList.push_back(new CSTLMeshFileLoader()); - #endif - - // factories - ISceneNodeFactory* factory = new CDefaultSceneNodeFactory(this); - registerSceneNodeFactory(factory); - factory->drop(); - - ISceneNodeAnimatorFactory* animatorFactory = new CDefaultSceneNodeAnimatorFactory(this); - registerSceneNodeAnimatorFactory(animatorFactory); - animatorFactory->drop(); -} - - - -//! destructor -CSceneManager::~CSceneManager() -{ - clearDeletionList(); - - if (Driver) - Driver->drop(); - - if (FileSystem) - FileSystem->drop(); - - if (CursorControl) - CursorControl->drop(); - - if (CollisionManager) - CollisionManager->drop(); - - if (MeshManipulator) - MeshManipulator->drop(); - - if ( GUIEnvironment ) - GUIEnvironment->drop (); - - u32 i; - - for (i=0; idrop(); - - if (ActiveCamera) - ActiveCamera->drop(); - - if (MeshCache) - MeshCache->drop(); - - for (i=0; idrop(); - - for (i=0; idrop(); -} - - -//! gets an animateable mesh. loads it if needed. returned pointer must not be dropped. -IAnimatedMesh* CSceneManager::getMesh(const c8* filename) -{ - IAnimatedMesh* msh = MeshCache->getMeshByFilename(filename); - if (msh) - return msh; - - io::IReadFile* file = FileSystem->createAndOpenFile(filename); - if (!file) - { - os::Printer::log("Could not load mesh, because file could not be opened.", filename, ELL_ERROR); - return 0; - } - - core::stringc name = filename; - name.make_lower(); - s32 count = MeshLoaderList.size(); - for (s32 i=count-1; i>=0; --i) - { - if (MeshLoaderList[i]->isALoadableFileExtension(name.c_str())) - { - // reset file to avoid side effects of previous calls to createMesh - file->seek(0); - msh = MeshLoaderList[i]->createMesh(file); - if (msh) - { - MeshCache->addMesh(filename, msh); - msh->drop(); - break; - } - } - } - - file->drop(); - - if (!msh) - os::Printer::log("Could not load mesh, file format seems to be unsupported", filename, ELL_ERROR); - else - os::Printer::log("Loaded mesh", filename, ELL_INFORMATION); - - return msh; -} - - -//! returns the video driver -video::IVideoDriver* CSceneManager::getVideoDriver() -{ - return Driver; -} - -//! returns the GUI Environment -gui::IGUIEnvironment* CSceneManager::getGUIEnvironment () -{ - return GUIEnvironment; -} - - -//! Adds a text scene node, which is able to display -//! 2d text at a position in three dimensional space -ITextSceneNode* CSceneManager::addTextSceneNode(gui::IGUIFont* font, - const wchar_t* text, video::SColor color, ISceneNode* parent, - const core::vector3df& position, s32 id) -{ - if (!font) - return 0; - - if (!parent) - parent = this; - - ITextSceneNode* t = new CTextSceneNode(parent, this, id, font, - getSceneCollisionManager(), position, text, color); - t->drop(); - - return t; -} - -//! Adds a text scene node, which uses billboards -ITextSceneNode* CSceneManager::addBillboardTextSceneNode(gui::IGUIFont* font, - const wchar_t* text, ISceneNode* parent, - const core::dimension2d& size, - const core::vector3df& position, s32 id, - video::SColor shade_top, video::SColor shade_down) -{ - if (!font) - return 0; - - if (!parent) - parent = this; - - ITextSceneNode* node = new CBillboardTextSceneNode(parent, this, id, font, text, position, size, - shade_top, shade_down); - node->drop(); - - return node; - -} - - -//! Adds a scene node, which can render a quake3 shader -ISceneNode* CSceneManager::addQuake3SceneNode( IMeshBuffer* meshBuffer, - const quake3::SShader * shader, - ISceneNode* parent, - s32 id - ) - -{ - if ( 0 == shader ) - return 0; - - if (!parent) - parent = this; - - CQuake3ShaderSceneNode* node = new CQuake3ShaderSceneNode ( parent, this, id, FileSystem, meshBuffer, shader ); - node->drop(); - - return node; - -} - - -//! adds a test scene node for test purposes to the scene. It is a simple cube of (1,1,1) size. -//! the returned pointer must not be dropped. -ISceneNode* CSceneManager::addCubeSceneNode(f32 size, ISceneNode* parent, s32 id, - const core::vector3df& position, const core::vector3df& rotation, const core::vector3df& scale) -{ - if (!parent) - parent = this; - - ISceneNode* node = new CCubeSceneNode(size, parent, this, id, position, rotation, scale); - node->drop(); - - return node; -} - -//! Adds a sphere scene node for test purposes to the scene. -ISceneNode* CSceneManager::addSphereSceneNode(f32 radius, s32 polyCount, ISceneNode* parent, s32 id, - const core::vector3df& position, - const core::vector3df& rotation, - const core::vector3df& scale) -{ - if (!parent) - parent = this; - - ISceneNode* node = new CSphereSceneNode(radius, polyCount, polyCount, parent, this, id, position, rotation, scale); - node->drop(); - - return node; -} - - -//! adds a scene node for rendering a static mesh -//! the returned pointer must not be dropped. -IMeshSceneNode* CSceneManager::addMeshSceneNode(IMesh* mesh, ISceneNode* parent, s32 id, - const core::vector3df& position, const core::vector3df& rotation, - const core::vector3df& scale, bool alsoAddIfMeshPointerZero) -{ - if (!alsoAddIfMeshPointerZero && !mesh) - return 0; - - if (!parent) - parent = this; - - IMeshSceneNode* node = new CMeshSceneNode(mesh, parent, this, id, position, rotation, scale); - node->drop(); - - return node; -} - - -//! Adds a scene node for rendering a animated water surface mesh. -ISceneNode* CSceneManager::addWaterSurfaceSceneNode(IMesh* mesh, f32 waveHeight, f32 waveSpeed, f32 waveLength, - ISceneNode* parent, s32 id, const core::vector3df& position, - const core::vector3df& rotation, const core::vector3df& scale) -{ - if (!mesh) - return 0; - - if (!parent) - parent = this; - - ISceneNode* node = new CWaterSurfaceSceneNode(waveHeight, waveSpeed, waveLength, - mesh, parent, this, id, position, rotation, scale); - - node->drop(); - - return node; -} - - - -//! adds a scene node for rendering an animated mesh model -IAnimatedMeshSceneNode* CSceneManager::addAnimatedMeshSceneNode(IAnimatedMesh* mesh, ISceneNode* parent, s32 id, - const core::vector3df& position, const core::vector3df& rotation, - const core::vector3df& scale, bool alsoAddIfMeshPointerZero) -{ - if (!alsoAddIfMeshPointerZero && !mesh) - return 0; - - if (!parent) - parent = this; - - IAnimatedMeshSceneNode* node = - new CAnimatedMeshSceneNode(mesh, parent, this, id, position, rotation, scale); - node->drop(); - - return node; -} - - -//! Adds a scene node for rendering using a octtree to the scene graph. This a good method for rendering -//! scenes with lots of geometry. The Octree is built on the fly from the mesh, much -//! faster then a bsp tree. -ISceneNode* CSceneManager::addOctTreeSceneNode(IAnimatedMesh* mesh, ISceneNode* parent, - s32 id, s32 minimalPolysPerNode, bool alsoAddIfMeshPointerZero) -{ - if (!alsoAddIfMeshPointerZero && (!mesh || !mesh->getFrameCount())) - return 0; - - return addOctTreeSceneNode(mesh ? mesh->getMesh(0) : 0, - parent, id, minimalPolysPerNode, - alsoAddIfMeshPointerZero); -} - - - -//! Adss a scene node for rendering using a octtree. This a good method for rendering -//! scenes with lots of geometry. The Octree is built on the fly from the mesh, much -//! faster then a bsp tree. -ISceneNode* CSceneManager::addOctTreeSceneNode(IMesh* mesh, ISceneNode* parent, - s32 id, s32 minimalPolysPerNode, bool alsoAddIfMeshPointerZero) -{ - if (!alsoAddIfMeshPointerZero && !mesh) - return 0; - - if (!parent) - parent = this; - - COctTreeSceneNode* node = new COctTreeSceneNode(parent, this, id, minimalPolysPerNode); - - if (mesh) - node->createTree(mesh); - - node->drop(); - - return node; -} - - -//! Adds a camera scene node to the tree and sets it as active camera. -//! \param position: Position of the space relative to its parent where the camera will be placed. -//! \param lookat: Position where the camera will look at. Also known as target. -//! \param parent: Parent scene node of the camera. Can be null. If the parent moves, -//! the camera will move too. -//! \return Returns pointer to interface to camera -ICameraSceneNode* CSceneManager::addCameraSceneNode(ISceneNode* parent, - const core::vector3df& position, const core::vector3df& lookat, s32 id) -{ - if (!parent) - parent = this; - - ICameraSceneNode* node = new CCameraSceneNode(parent, this, id, position, lookat); - node->drop(); - - setActiveCamera(node); - - return node; -} - - - -//! Adds a camera scene node which is able to be controlle with the mouse similar -//! like in the 3D Software Maya by Alias Wavefront. -//! The returned pointer must not be dropped. -ICameraSceneNode* CSceneManager::addCameraSceneNodeMaya(ISceneNode* parent, - f32 rotateSpeed, f32 zoomSpeed, f32 translationSpeed, s32 id) -{ - if (!parent) - parent = this; - - ICameraSceneNode* node = new CCameraMayaSceneNode(parent, this, id, rotateSpeed, - zoomSpeed, translationSpeed); - node->drop(); - - setActiveCamera(node); - - return node; -} - - - -//! Adds a camera scene node which is able to be controled with the mouse and keys -//! like in most first person shooters (FPS): -ICameraSceneNode* CSceneManager::addCameraSceneNodeFPS(ISceneNode* parent, - f32 rotateSpeed, f32 moveSpeed, s32 id, - SKeyMap* keyMapArray, s32 keyMapSize, bool noVerticalMovement,f32 jumpSpeed) -{ - if (!parent) - parent = this; - - ICameraSceneNode* node = new CCameraFPSSceneNode(parent, this, CursorControl, - id, rotateSpeed, moveSpeed, jumpSpeed, keyMapArray, keyMapSize, noVerticalMovement); - node->drop(); - - setActiveCamera(node); - - return node; -} - - - -//! Adds a dynamic light scene node. The light will cast dynamic light on all -//! other scene nodes in the scene, which have the material flag video::MTF_LIGHTING -//! turned on. (This is the default setting in most scene nodes). -ILightSceneNode* CSceneManager::addLightSceneNode(ISceneNode* parent, - const core::vector3df& position, video::SColorf color, f32 range, s32 id) -{ - if (!parent) - parent = this; - - ILightSceneNode* node = new CLightSceneNode(parent, this, id, position, color, range); - node->drop(); - - return node; -} - - - -//! Adds a billboard scene node to the scene. A billboard is like a 3d sprite: A 2d element, -//! which always looks to the camera. It is usually used for things like explosions, fire, -//! lensflares and things like that. -IBillboardSceneNode* CSceneManager::addBillboardSceneNode(ISceneNode* parent, - const core::dimension2d& size, const core::vector3df& position, s32 id, - video::SColor shade_top, video::SColor shade_down - ) -{ - if (!parent) - parent = this; - - IBillboardSceneNode* node = new CBillboardSceneNode(parent, this, id, position, size, - shade_top, shade_down); - node->drop(); - - return node; -} - - - -//! Adds a skybox scene node. A skybox is a big cube with 6 textures on it and -//! is drawn around the camera position. -ISceneNode* CSceneManager::addSkyBoxSceneNode(video::ITexture* top, video::ITexture* bottom, - video::ITexture* left, video::ITexture* right, video::ITexture* front, - video::ITexture* back, ISceneNode* parent, s32 id) -{ - if (!parent) - parent = this; - - ISceneNode* node = new CSkyBoxSceneNode(top, bottom, left, right, - front, back, parent, this, id); - - node->drop(); - return node; -} - - -//! Adds a skydome scene node. A skydome is a large (half-) sphere with a -//! panoramic texture on it and is drawn around the camera position. -ISceneNode* CSceneManager::addSkyDomeSceneNode(video::ITexture* texture, - u32 horiRes, u32 vertRes, f64 texturePercentage, - f64 spherePercentage, ISceneNode* parent, s32 id) -{ - if (!parent) - parent = this; - - ISceneNode* node = new CSkyDomeSceneNode(texture, horiRes, vertRes, - texturePercentage, spherePercentage, parent, this, id); - - node->drop(); - return node; -} - - -//! Adds a particle system scene node. -IParticleSystemSceneNode* CSceneManager::addParticleSystemSceneNode( - bool withDefaultEmitter, ISceneNode* parent, s32 id, - const core::vector3df& position, const core::vector3df& rotation, - const core::vector3df& scale) -{ - if (!parent) - parent = this; - - IParticleSystemSceneNode* node = new CParticleSystemSceneNode(withDefaultEmitter, - parent, this, id, position, rotation, scale); - node->drop(); - - return node; -} - - -//! Adds a terrain scene node to the scene graph. -ITerrainSceneNode* CSceneManager::addTerrainSceneNode( - const char* heightMapFileName, - ISceneNode* parent, s32 id, - const core::vector3df& position, - const core::vector3df& rotation, - const core::vector3df& scale, - video::SColor vertexColor, - s32 maxLOD, E_TERRAIN_PATCH_SIZE patchSize, s32 smoothFactor, - bool addAlsoIfHeightmapEmpty) -{ - io::IReadFile* file = FileSystem->createAndOpenFile(heightMapFileName); - - if(!file && !addAlsoIfHeightmapEmpty) - { - os::Printer::log("Could not load terrain, because file could not be opened.", - heightMapFileName, ELL_ERROR); - return 0; - } - - ITerrainSceneNode* terrain = addTerrainSceneNode(file, parent, id, - position, rotation, scale, vertexColor, maxLOD, patchSize, - smoothFactor, addAlsoIfHeightmapEmpty); - - if (file) - file->drop(); - - return terrain; -} - -//! Adds a terrain scene node to the scene graph. -ITerrainSceneNode* CSceneManager::addTerrainSceneNode( - io::IReadFile* heightMapFile, - ISceneNode* parent, s32 id, - const core::vector3df& position, - const core::vector3df& rotation, - const core::vector3df& scale, - video::SColor vertexColor, - s32 maxLOD, E_TERRAIN_PATCH_SIZE patchSize, - s32 smoothFactor, - bool addAlsoIfHeightmapEmpty) -{ - if (!parent) - parent = this; - - if (!heightMapFile && !addAlsoIfHeightmapEmpty) - { - os::Printer::log("Could not load terrain, because file could not be opened.", ELL_ERROR); - return 0; - } - - CTerrainSceneNode* node = new CTerrainSceneNode(parent, this, FileSystem, id, - maxLOD, patchSize, position, rotation, scale); - - if (!node->loadHeightMap(heightMapFile, vertexColor, smoothFactor)) - { - if (!addAlsoIfHeightmapEmpty) - { - node->remove(); - node->drop(); - return 0; - } - } - - node->drop(); - return node; -} - - -//! Adds an empty scene node. -ISceneNode* CSceneManager::addEmptySceneNode(ISceneNode* parent, s32 id) -{ - if (!parent) - parent = this; - - ISceneNode* node = new CEmptySceneNode(parent, this, id); - node->drop(); - - return node; -} - - -//! Adds a dummy transformation scene node to the scene graph. -IDummyTransformationSceneNode* CSceneManager::addDummyTransformationSceneNode( - ISceneNode* parent, s32 id) -{ - if (!parent) - parent = this; - - IDummyTransformationSceneNode* node = new CDummyTransformationSceneNode( - parent, this, id); - node->drop(); - - return node; -} - -//! Adds a Hill Plane mesh to the mesh pool. The mesh is generated on the fly -//! and looks like a plane with some hills on it. It is uses mostly for quick -//! tests of the engine only. You can specify how many hills there should be -//! on the plane and how high they should be. Also you must specify a name for -//! the mesh, because the mesh is added to the mesh pool, and can be retrieved -//! again using ISceneManager::getMesh with the name as parameter. -IAnimatedMesh* CSceneManager::addHillPlaneMesh(const c8* name, - const core::dimension2d& tileSize, - const core::dimension2d& tileCount, - video::SMaterial* material, f32 hillHeight, - const core::dimension2d& countHills, - const core::dimension2d& textureRepeatCount) -{ - if (!name || MeshCache->isMeshLoaded(name)) - return 0; - - IMesh* mesh = CGeometryCreator::createHillPlaneMesh(tileSize, - tileCount, material, hillHeight, countHills, - textureRepeatCount); - if (!mesh) - return 0; - - SAnimatedMesh* animatedMesh = new SAnimatedMesh(); - if (!animatedMesh) - return 0; - - animatedMesh->addMesh(mesh); - animatedMesh->recalculateBoundingBox(); - mesh->drop(); - - MeshCache->addMesh(name, animatedMesh); - animatedMesh->drop(); - - return animatedMesh; -} - - -//! Adds a terrain mesh to the mesh pool. -IAnimatedMesh* CSceneManager::addTerrainMesh(const c8* name, - video::IImage* texture, video::IImage* heightmap, - const core::dimension2d& stretchSize, - f32 maxHeight, - const core::dimension2d& defaultVertexBlockSize) -{ - if (!name || MeshCache->isMeshLoaded(name)) - return 0; - - IMesh* mesh = CGeometryCreator::createTerrainMesh(texture, heightmap, - stretchSize, maxHeight, getVideoDriver(), - defaultVertexBlockSize); - if (!mesh) - return 0; - - SAnimatedMesh* animatedMesh = new SAnimatedMesh(); - if (!animatedMesh) - return 0; - - animatedMesh->addMesh(mesh); - animatedMesh->recalculateBoundingBox(); - mesh->drop(); - - MeshCache->addMesh(name, animatedMesh); - animatedMesh->drop(); - - return animatedMesh; -} - -//! Adds an arrow mesh to the mesh pool. -IAnimatedMesh* CSceneManager::addArrowMesh(const c8* name, - video::SColor vtxColor0, video::SColor vtxColor1, - u32 tesselationCylinder, u32 tesselationCone, f32 height, - f32 cylinderHeight, f32 width0,f32 width1) -{ - if (!name || MeshCache->isMeshLoaded(name)) - return 0; - - IMesh* mesh = CGeometryCreator::createArrowMesh( tesselationCylinder, - tesselationCone, height, cylinderHeight, width0,width1, - vtxColor0, vtxColor1); - if (!mesh) - return 0; - - SAnimatedMesh* animatedMesh = new SAnimatedMesh(); - if (!animatedMesh) - return 0; - - animatedMesh->addMesh(mesh); - animatedMesh->recalculateBoundingBox(); - mesh->drop(); - - MeshCache->addMesh(name, animatedMesh); - animatedMesh->drop(); - - return animatedMesh; -} - - - -//! Adds a static sphere mesh to the mesh pool. -IAnimatedMesh* CSceneManager::addSphereMesh(const c8* name, - f32 radius, u32 polyCountX, u32 polyCountY) -{ - if (!name || MeshCache->isMeshLoaded(name)) - return 0; - - IMesh* mesh = CGeometryCreator::createSphereMesh( radius, polyCountX, polyCountY); - if (!mesh) - return 0; - - SAnimatedMesh* animatedMesh = new SAnimatedMesh(); - if (!animatedMesh) - return 0; - - animatedMesh->addMesh(mesh); - animatedMesh->recalculateBoundingBox(); - mesh->drop(); - - MeshCache->addMesh(name, animatedMesh); - animatedMesh->drop(); - - return animatedMesh; -} - - - -//! Returns the root scene node. This is the scene node wich is parent -//! of all scene nodes. The root scene node is a special scene node which -//! only exists to manage all scene nodes. It is not rendered and cannot -//! be removed from the scene. -//! \return Returns a pointer to the root scene node. -ISceneNode* CSceneManager::getRootSceneNode() -{ - return this; -} - - - -//! Returns the current active camera. -//! \return The active camera is returned. Note that this can be NULL, if there -//! was no camera created yet. -ICameraSceneNode* CSceneManager::getActiveCamera() -{ - return ActiveCamera; -} - - - -//! Sets the active camera. The previous active camera will be deactivated. -//! \param camera: The new camera which should be active. -void CSceneManager::setActiveCamera(ICameraSceneNode* camera) -{ - if (ActiveCamera) - ActiveCamera->drop(); - - ActiveCamera = camera; - - if (ActiveCamera) - ActiveCamera->grab(); -} - - - - -//! renders the node. -void CSceneManager::render() -{ -} - - -//! returns the axis aligned bounding box of this node -const core::aabbox3d& CSceneManager::getBoundingBox() const -{ - _IRR_DEBUG_BREAK_IF(true) // Bounding Box of Scene Manager wanted. - - // should never be used. - return *((core::aabbox3d*)0); -} - - - -//! returns if node is culled -bool CSceneManager::isCulled(const ISceneNode* node) -{ - const ICameraSceneNode* cam = getActiveCamera(); - if (!cam) - return false; - - switch ( node->getAutomaticCulling() ) - { - // can be seen by a bounding box ? - case scene::EAC_BOX: - { - core::aabbox3d tbox = node->getBoundingBox(); - node->getAbsoluteTransformation().transformBox(tbox); - return !(tbox.intersectsWithBox(cam->getViewFrustum()->getBoundingBox() )); - } - - // can be seen by a bounding sphere - case scene::EAC_FRUSTUM_SPHERE: - { // requires bbox diameter - } - break; - - // can be seen by cam pyramid planes ? - case scene::EAC_FRUSTUM_BOX: - { - SViewFrustum frust = *cam->getViewFrustum(); - - //transform the frustum to the node's current absolute transformation - core::matrix4 invTrans(node->getAbsoluteTransformation()); - invTrans.makeInverse(); - frust.transform(invTrans); - - core::vector3df edges[8]; - node->getBoundingBox().getEdges(edges); - - for (s32 i=0; igetMaterialCount(); - - taken = 0; - for (u32 i=0; igetMaterialRenderer(node->getMaterial(i).MaterialType); - if (rnd && rnd->isTransparent()) - { - // register as transparent node - TransparentNodeEntry e(node, camWorldPos); - TransparentNodeList.push_back(e); - taken = 1; - break; - } - } - - // not transparent, register as solid - if ( 0 == taken ) - { - SolidNodeList.push_back( node ); - taken = 1; - } - } - break; - case ESNRP_SHADOW: - if (!isCulled(node)) - { - ShadowNodeList.push_back(node); - taken = 1; - } - break; - - case ESNRP_COUNT: // ignore this one - break; - } - -#ifdef SCENEMANAGER_DEBUG - s32 index = Parameters.findAttribute ( "calls" ); - Parameters.setAttribute ( index, Parameters.getAttributeAsInt ( index ) + 1 ); - - if ( 0 == taken ) - { - index = Parameters.findAttribute ( "culled" ); - Parameters.setAttribute ( index, Parameters.getAttributeAsInt ( index ) + 1 ); - } -#endif - - return taken; -} - -//! This method is called just before the rendering process of the whole scene. -//! draws all scene nodes -void CSceneManager::drawAll() -{ - if (!Driver) - return; - - // reset attributes - Parameters.setAttribute ( "culled", 0 ); - Parameters.setAttribute ( "calls", 0 ); - Parameters.setAttribute ( "drawn", 0 ); - - // reset all transforms - video::IVideoDriver* driver = getVideoDriver(); - if ( driver ) - { - driver->setTransform ( video::ETS_PROJECTION, core::IdentityMatrix ); - driver->setTransform ( video::ETS_VIEW, core::IdentityMatrix ); - driver->setTransform ( video::ETS_WORLD, core::IdentityMatrix ); - driver->setTransform ( video::ETS_TEXTURE_0, core::IdentityMatrix ); - driver->setTransform ( video::ETS_TEXTURE_1, core::IdentityMatrix ); - driver->setTransform ( video::ETS_TEXTURE_2, core::IdentityMatrix ); - driver->setTransform ( video::ETS_TEXTURE_3, core::IdentityMatrix ); - } - - // do animations and other stuff. - OnAnimate(os::Timer::getTime()); - - /*! - First Scene Node for prerendering should be the active camera - consistent Camera is needed for culling - */ - camWorldPos.set(0,0,0); - if ( ActiveCamera ) - { - ActiveCamera->OnRegisterSceneNode(); - camWorldPos = ActiveCamera->getAbsolutePosition(); - } - - // let all nodes register themselves - OnRegisterSceneNode(); - - u32 i; // new ISO for scoping problem in some compilers - - //render camera scenes - { - CurrentRendertime = ESNRP_CAMERA; - for (i=0; irender(); - - CameraList.set_used(0); - } - - //render lights scenes - { - CurrentRendertime = ESNRP_LIGHT; - - Driver->deleteAllDynamicLights(); - - Driver->setAmbientLight(AmbientLight); - - LightList.sort (); // on distance to camera - - u32 maxLights = core::min_ ( Driver->getMaximalDynamicLightAmount (), LightList.size () ); - for (i=0; i< maxLights; ++i) - LightList[i].node->render(); - - LightList.set_used(0); - } - - // render skyboxes - { - CurrentRendertime = ESNRP_SKY_BOX; - - for (i=0; irender(); - - SkyBoxList.set_used(0); - } - - - // render default objects - { - CurrentRendertime = ESNRP_SOLID; - SolidNodeList.sort(); // sort by textures - - for (i=0; irender(); - - Parameters.setAttribute ( "drawn", (s32) SolidNodeList.size () ); - - SolidNodeList.set_used(0); - } - - // render shadows - { - CurrentRendertime = ESNRP_SHADOW; - for (i=0; irender(); - - if (!ShadowNodeList.empty()) - Driver->drawStencilShadow(true,ShadowColor, ShadowColor, - ShadowColor, ShadowColor); - - ShadowNodeList.set_used(0); - } - - // render transparent objects. - { - CurrentRendertime = ESNRP_TRANSPARENT; - TransparentNodeList.sort(); // sort by distance from camera - - for (i=0; irender(); - - TransparentNodeList.set_used(0); - } - - - clearDeletionList(); - - CurrentRendertime = ESNRP_COUNT; -} - - -//! Sets the color of stencil buffers shadows drawn by the scene manager. -void CSceneManager::setShadowColor(video::SColor color) -{ - ShadowColor = color; -} - - -//! Returns the current color of shadows. -video::SColor CSceneManager::getShadowColor() const -{ - return ShadowColor; -} - - - -//! creates a rotation animator, which rotates the attached scene node around itself. -ISceneNodeAnimator* CSceneManager::createRotationAnimator(const core::vector3df& rotationPerSecond) -{ - ISceneNodeAnimator* anim = new CSceneNodeAnimatorRotation(os::Timer::getTime(), - rotationPerSecond); - - return anim; -} - - - -//! creates a fly circle animator, which lets the attached scene node fly around a center. -ISceneNodeAnimator* CSceneManager::createFlyCircleAnimator( - const core::vector3df& normal, f32 radius, f32 speed, - const core::vector3df& direction) -{ - ISceneNodeAnimator* anim = new CSceneNodeAnimatorFlyCircle(os::Timer::getTime(), normal, - radius, speed, direction); - return anim; -} - - -//! Creates a fly straight animator, which lets the attached scene node -//! fly or move along a line between two points. -ISceneNodeAnimator* CSceneManager::createFlyStraightAnimator(const core::vector3df& startPoint, - const core::vector3df& endPoint, u32 timeForWay, bool loop) -{ - ISceneNodeAnimator* anim = new CSceneNodeAnimatorFlyStraight(startPoint, - endPoint, timeForWay, loop, os::Timer::getTime()); - - return anim; -} - - -//! Creates a texture animator, which switches the textures of the target scene -//! node based on a list of textures. -ISceneNodeAnimator* CSceneManager::createTextureAnimator(const core::array& textures, - s32 timePerFrame, bool loop) -{ - ISceneNodeAnimator* anim = new CSceneNodeAnimatorTexture(textures, - timePerFrame, loop, os::Timer::getTime()); - - return anim; -} - - -//! Creates a scene node animator, which deletes the scene node after -//! some time automaticly. -ISceneNodeAnimator* CSceneManager::createDeleteAnimator(u32 when) -{ - return new CSceneNodeAnimatorDelete(this, os::Timer::getTime() + when); -} - - - - -//! Creates a special scene node animator for doing automatic collision detection -//! and response. -ISceneNodeAnimatorCollisionResponse* CSceneManager::createCollisionResponseAnimator( - ITriangleSelector* world, ISceneNode* sceneNode, const core::vector3df& ellipsoidRadius, - const core::vector3df& gravityPerSecond, - const core::vector3df& ellipsoidTranslation, f32 slidingValue) -{ - ISceneNodeAnimatorCollisionResponse* anim = new - CSceneNodeAnimatorCollisionResponse(this, world, sceneNode, - ellipsoidRadius, gravityPerSecond, - ellipsoidTranslation, slidingValue); - - return anim; -} - - -//! Creates a follow spline animator. -ISceneNodeAnimator* CSceneManager::createFollowSplineAnimator(s32 startTime, - const core::array< core::vector3df >& points, - f32 speed, f32 tightness) -{ - ISceneNodeAnimator* a = new CSceneNodeAnimatorFollowSpline(startTime, points, - speed, tightness); - return a; -} - - - -//! Adds an external mesh loader. -void CSceneManager::addExternalMeshLoader(IMeshLoader* externalLoader) -{ - if (!externalLoader) - return; - - externalLoader->grab(); - MeshLoaderList.push_back(externalLoader); -} - - - -//! Returns a pointer to the scene collision manager. -ISceneCollisionManager* CSceneManager::getSceneCollisionManager() -{ - return CollisionManager; -} - - -//! Returns a pointer to the mesh manipulator. -IMeshManipulator* CSceneManager::getMeshManipulator() -{ - return MeshManipulator; -} - - -//! Creates a simple ITriangleSelector, based on a mesh. -ITriangleSelector* CSceneManager::createTriangleSelector(IMesh* mesh, ISceneNode* node) -{ - if (!mesh || !node) - return 0; - - return new CTriangleSelector(mesh, node); -} - - -//! Creates a simple dynamic ITriangleSelector, based on a axis aligned bounding box. -ITriangleSelector* CSceneManager::createTriangleSelectorFromBoundingBox(ISceneNode* node) -{ - if (!node) - return 0; - - return new CTriangleBBSelector(node); -} - - -//! Creates a simple ITriangleSelector, based on a mesh. -ITriangleSelector* CSceneManager::createOctTreeTriangleSelector(IMesh* mesh, - ISceneNode* node, - s32 minimalPolysPerNode) -{ - if (!mesh || !node) - return 0; - - return new COctTreeTriangleSelector(mesh, node, minimalPolysPerNode); -} - - - -//! Creates a meta triangle selector. -IMetaTriangleSelector* CSceneManager::createMetaTriangleSelector() -{ - return new CMetaTriangleSelector(); -} - - - -//! Creates a triangle selector which can select triangles from a terrain scene node -ITriangleSelector* CSceneManager::createTerrainTriangleSelector( - ITerrainSceneNode* node, s32 LOD) -{ - return new CTerrainTriangleSelector(node, LOD); -} - - - -//! Adds a scene node to the deletion queue. -void CSceneManager::addToDeletionQueue(ISceneNode* node) -{ - if (!node) - return; - - node->grab(); - DeletionList.push_back(node); -} - - -//! clears the deletion list -void CSceneManager::clearDeletionList() -{ - if (DeletionList.empty()) - return; - - for (s32 i=0; i<(s32)DeletionList.size(); ++i) - { - DeletionList[i]->remove(); - DeletionList[i]->drop(); - } - - DeletionList.clear(); -} - - -//! Returns the first scene node with the specified name. -ISceneNode* CSceneManager::getSceneNodeFromName(const char* name, ISceneNode* start) -{ - if (start == 0) - start = getRootSceneNode(); - - if (!strcmp(start->getName(),name)) - return start; - - ISceneNode* node = 0; - - const core::list& list = start->getChildren(); - core::list::ConstIterator it = list.begin(); - for (; it!=list.end(); ++it) - { - node = getSceneNodeFromName(name, *it); - if (node) - return node; - } - - return 0; -} - - -//! Returns the first scene node with the specified id. -ISceneNode* CSceneManager::getSceneNodeFromId(s32 id, ISceneNode* start) -{ - if (start == 0) - start = getRootSceneNode(); - - if (start->getID() == id) - return start; - - ISceneNode* node = 0; - - const core::list& list = start->getChildren(); - core::list::ConstIterator it = list.begin(); - for (; it!=list.end(); ++it) - { - node = getSceneNodeFromId(id, *it); - if (node) - return node; - } - - return 0; -} - - -//! Returns the first scene node with the specified type. -ISceneNode* CSceneManager::getSceneNodeFromType(scene::ESCENE_NODE_TYPE type, ISceneNode* start) -{ - if (start == 0) - start = getRootSceneNode(); - - if (start->getType() == type) - return start; - - ISceneNode* node = 0; - - const core::list& list = start->getChildren(); - core::list::ConstIterator it = list.begin(); - for (; it!=list.end(); ++it) - { - node = getSceneNodeFromType(type, *it); - if (node) - return node; - } - - return 0; -} - -//! returns scene nodes by type. -void CSceneManager::getSceneNodesFromType(ESCENE_NODE_TYPE type, core::array& outNodes, ISceneNode* start) -{ - if (start == 0) - start = getRootSceneNode(); - - if (start->getType() == type) - outNodes.push_back(start); - - const core::list& list = start->getChildren(); - core::list::ConstIterator it = list.begin(); - - for (; it!=list.end(); ++it) - { - getSceneNodesFromType(type, outNodes, *it); - } -} - - -//! Posts an input event to the environment. Usually you do not have to -//! use this method, it is used by the internal engine. -bool CSceneManager::postEventFromUser(const SEvent& event) -{ - bool ret = false; - ICameraSceneNode* cam = getActiveCamera(); - if (cam) - ret = cam->OnEvent(event); - - _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; - return ret; -} - - -//! Removes all children of this scene node -void CSceneManager::removeAll() -{ - ISceneNode::removeAll(); - setActiveCamera(0); -} - - -//! Clears the whole scene. All scene nodes are removed. -void CSceneManager::clear() -{ - removeAll(); -} - - -//! Returns interface to the parameters set in this scene. -io::IAttributes* CSceneManager::getParameters() -{ - return &Parameters; -} - - -//! Returns current render pass. -E_SCENE_NODE_RENDER_PASS CSceneManager::getSceneNodeRenderPass() const -{ - return CurrentRendertime; -} - - - -//! Returns an interface to the mesh cache which is shared beween all existing scene managers. -IMeshCache* CSceneManager::getMeshCache() -{ - return MeshCache; -} - - -//! Creates a new scene manager. -ISceneManager* CSceneManager::createNewSceneManager(bool cloneContent) -{ - CSceneManager* manager = new CSceneManager(Driver, FileSystem, CursorControl, MeshCache); - - if (cloneContent) - manager->cloneMembers(this, manager); - - return manager; -} - - -//! Returns the default scene node factory which can create all built in scene nodes -ISceneNodeFactory* CSceneManager::getDefaultSceneNodeFactory() -{ - return getSceneNodeFactory(0); -} - - -//! Adds a scene node factory to the scene manager. -void CSceneManager::registerSceneNodeFactory(ISceneNodeFactory* factoryToAdd) -{ - if (factoryToAdd) - { - factoryToAdd->grab(); - SceneNodeFactoryList.push_back(factoryToAdd); - } -} - - -//! Returns amount of registered scene node factories. -u32 CSceneManager::getRegisteredSceneNodeFactoryCount() const -{ - return SceneNodeFactoryList.size(); -} - - -//! Returns a scene node factory by index -ISceneNodeFactory* CSceneManager::getSceneNodeFactory(u32 index) -{ - if (indexgrab(); - SceneNodeAnimatorFactoryList.push_back(factoryToAdd); - } -} - - -//! Returns amount of registered scene node animator factories. -u32 CSceneManager::getRegisteredSceneNodeAnimatorFactoryCount() const -{ - return SceneNodeAnimatorFactoryList.size(); -} - - -//! Returns a scene node animator factory by index -ISceneNodeAnimatorFactory* CSceneManager::getSceneNodeAnimatorFactory(u32 index) -{ - if (indexcreateAndWriteFile(filename); - if (!file) - return false; - - bool ret = saveScene(file, userDataSerializer); - file->drop(); - return ret; -} - - -//! Saves the current scene into a file. -bool CSceneManager::saveScene(io::IWriteFile* file, ISceneUserDataSerializer* userDataSerializer) -{ - if (!file) - return false; - - io::IXMLWriter* writer = FileSystem->createXMLWriter(file); - if (!writer) - return false; - - writer->writeXMLHeader(); - writeSceneNode(writer, this, userDataSerializer); - writer->drop(); - - return true; -} - - -//! Loads a scene. Note that the current scene is not cleared before. -//! \param filename: Name of the file . -bool CSceneManager::loadScene(const c8* filename, ISceneUserDataSerializer* userDataSerializer) -{ - io::IReadFile* read = FileSystem->createAndOpenFile(filename); - if (!read) - { - os::Printer::log("Unable to open scene file", filename, ELL_ERROR); - return false; - } - - bool ret = loadScene(read, userDataSerializer); - read->drop(); - - return ret; -} - - -//! Loads a scene. Note that the current scene is not cleared before. -bool CSceneManager::loadScene(io::IReadFile* file, ISceneUserDataSerializer* userDataSerializer) -{ - if (!file) - { - os::Printer::log("Unable to open scene file", ELL_ERROR); - return false; - } - - io::IXMLReader* reader = FileSystem->createXMLReader(file); - if (!reader) - { - os::Printer::log("Scene is not a valid XML file", file->getFileName(), ELL_ERROR); - return false; - } - - // for mesh loading, set collada loading attributes - - bool oldColladaSingleMesh = getParameters()->getAttributeAsBool(COLLADA_CREATE_SCENE_INSTANCES); - getParameters()->setAttribute(COLLADA_CREATE_SCENE_INSTANCES, false); - - // read file - - while(reader->read()) - { - readSceneNode(reader, 0, userDataSerializer); - } - - // restore old collada parameters - - getParameters()->setAttribute(COLLADA_CREATE_SCENE_INSTANCES, oldColladaSingleMesh); - - // finish up - - reader->drop(); - return true; - -} - - -//! reads a scene node -void CSceneManager::readSceneNode(io::IXMLReader* reader, ISceneNode* parent, ISceneUserDataSerializer* userDataSerializer) -{ - if (!reader) - return; - - scene::ISceneNode* node = 0; - - if ((!parent && IRR_XML_FORMAT_SCENE==reader->getNodeName()) || - ( parent && IRR_XML_FORMAT_NODE==reader->getNodeName())) - { - if (parent) - { - // find node type and create it - core::stringc attrName = reader->getAttributeValue(IRR_XML_FORMAT_NODE_ATTR_TYPE.c_str()); - - for (int i=(int)SceneNodeFactoryList.size()-1; i>=0 && !node; --i) - node = SceneNodeFactoryList[i]->addSceneNode(attrName.c_str(), parent); - - if (!node) - os::Printer::log("Could not create scene node of unknown type", attrName.c_str()); - } - else - node = this; // root - } - - // read attributes - while(reader->read()) - { - bool endreached = false; - - switch (reader->getNodeType()) - { - case io::EXN_ELEMENT_END: - if ((IRR_XML_FORMAT_NODE==reader->getNodeName()) || - (IRR_XML_FORMAT_SCENE==reader->getNodeName())) - { - endreached = true; - } - break; - case io::EXN_ELEMENT: - if (core::stringw(L"attributes")==reader->getNodeName()) - { - // read attributes - io::IAttributes* attr = FileSystem->createEmptyAttributes(Driver); - attr->read(reader, true); - - if (node) - node->deserializeAttributes(attr); - - attr->drop(); - } - else - if (core::stringw(L"materials")==reader->getNodeName()) - readMaterials(reader, node); - else - if (core::stringw(L"animators")==reader->getNodeName()) - readAnimators(reader, node); - else - if (core::stringw(L"userData")==reader->getNodeName()) - readUserData(reader, node, userDataSerializer); - else - if ((IRR_XML_FORMAT_NODE==reader->getNodeName()) || - (IRR_XML_FORMAT_SCENE==reader->getNodeName())) - { - readSceneNode(reader, node, userDataSerializer); - } - else - { - os::Printer::log("Found unknown element in irrlicht scene file", - core::stringc(reader->getNodeName()).c_str()); - } - break; - default: - break; - } - - if (endreached) - break; - } -} - - -//! reads materials of a node -void CSceneManager::readMaterials(io::IXMLReader* reader, ISceneNode* node) -{ - u32 nr = 0; - - while(reader->read()) - { - const wchar_t* name = reader->getNodeName(); - - switch(reader->getNodeType()) - { - case io::EXN_ELEMENT_END: - if (core::stringw(L"materials")==name) - return; - break; - case io::EXN_ELEMENT: - if (core::stringw(L"attributes")==name) - { - // read materials from attribute list - io::IAttributes* attr = FileSystem->createEmptyAttributes(Driver); - attr->read(reader); - - if (node && node->getMaterialCount() > nr) - { - getVideoDriver()->fillMaterialStructureFromAttributes( - node->getMaterial(nr), attr); - } - - attr->drop(); - ++nr; - } - break; - default: - break; - } - } -} - - -//! reads animators of a node -void CSceneManager::readAnimators(io::IXMLReader* reader, ISceneNode* node) -{ - while(reader->read()) - { - const wchar_t* name = reader->getNodeName(); - - switch(reader->getNodeType()) - { - case io::EXN_ELEMENT_END: - if (core::stringw(L"animators")==name) - return; - break; - case io::EXN_ELEMENT: - if (core::stringw(L"attributes")==name) - { - // read animator data from attribute list - io::IAttributes* attr = FileSystem->createEmptyAttributes(Driver); - attr->read(reader); - - if (node) - { - core::stringc typeName = attr->getAttributeAsString("Type"); - ISceneNodeAnimator* anim = 0; - - for (int i=0; i<(int)SceneNodeAnimatorFactoryList.size() && !anim; ++i) - anim = SceneNodeAnimatorFactoryList[i]->createSceneNodeAnimator(typeName.c_str(), node); - - if (anim) - { - anim->deserializeAttributes(attr); - anim->drop(); - } - } - - attr->drop(); - } - break; - default: - break; - } - } -} - - -//! reads user data of a node -void CSceneManager::readUserData(io::IXMLReader* reader, ISceneNode* node, ISceneUserDataSerializer* userDataSerializer) -{ - while(reader->read()) - { - const wchar_t* name = reader->getNodeName(); - - switch(reader->getNodeType()) - { - case io::EXN_ELEMENT_END: - if (core::stringw(L"userData")==name) - return; - break; - case io::EXN_ELEMENT: - if (core::stringw(L"attributes")==name) - { - // read user data from attribute list - io::IAttributes* attr = FileSystem->createEmptyAttributes(Driver); - attr->read(reader); - - if (node && userDataSerializer) - { - userDataSerializer->OnReadUserData(node, attr); - } - - attr->drop(); - } - break; - default: - break; - } - } -} - - -//! writes a scene node -void CSceneManager::writeSceneNode(io::IXMLWriter* writer, ISceneNode* node, ISceneUserDataSerializer* userDataSerializer) -{ - if (!writer || !node || node->isDebugObject()) - return; - - const wchar_t* name; - - if (node == this) - { - name = IRR_XML_FORMAT_SCENE.c_str(); - writer->writeElement(name, false); - } - else - { - name = IRR_XML_FORMAT_NODE.c_str(); - writer->writeElement(name, false, IRR_XML_FORMAT_NODE_ATTR_TYPE.c_str(), - core::stringw(getSceneNodeTypeName(node->getType())).c_str()); - } - - writer->writeLineBreak(); - writer->writeLineBreak(); - - // write properties - - io::IAttributes* attr = FileSystem->createEmptyAttributes(Driver); - node->serializeAttributes(attr); - - if (attr->getAttributeCount() != 0) - { - attr->write(writer); - writer->writeLineBreak(); - } - - // write materials - - if (node->getMaterialCount() && getVideoDriver()) - { - const wchar_t* materialElement = L"materials"; - - writer->writeElement(materialElement); - writer->writeLineBreak(); - - for (u32 i=0; i < node->getMaterialCount(); ++i) - { - io::IAttributes* tmp_attr = - getVideoDriver()->createAttributesFromMaterial(node->getMaterial(i)); - tmp_attr->write(writer); - tmp_attr->drop(); - } - - writer->writeClosingTag(materialElement); - writer->writeLineBreak(); - } - - // write animators - - if (!node->getAnimators().empty()) - { - const wchar_t* animatorElement = L"animators"; - writer->writeElement(animatorElement); - writer->writeLineBreak(); - - core::list::ConstIterator it = node->getAnimators().begin(); - for (; it != node->getAnimators().end(); ++it) - { - attr->clear(); - attr->addString("Type", getAnimatorTypeName((*it)->getType())); - - (*it)->serializeAttributes(attr); - - attr->write(writer); - } - - writer->writeClosingTag(animatorElement); - writer->writeLineBreak(); - } - - // write possible user data - - if ( userDataSerializer ) - { - io::IAttributes* userData = userDataSerializer->createUserData(node); - if (userData) - { - const wchar_t* userDataElement = L"userData"; - - writer->writeLineBreak(); - writer->writeElement(userDataElement); - writer->writeLineBreak(); - - userData->write(writer); - - writer->writeClosingTag(userDataElement); - writer->writeLineBreak(); - writer->writeLineBreak(); - - userData->drop(); - } - } - - // write children - - core::list::ConstIterator it = node->getChildren().begin(); - for (; it != node->getChildren().end(); ++it) - writeSceneNode(writer, (*it), userDataSerializer); - - attr->drop(); - - writer->writeClosingTag(name); - writer->writeLineBreak(); - writer->writeLineBreak(); -} - - -//! Returns a typename from a scene node type or null if not found -const c8* CSceneManager::getSceneNodeTypeName(ESCENE_NODE_TYPE type) -{ - const char* name = 0; - - for (int i=(int)SceneNodeFactoryList.size()-1; !name && i>=0; --i) - name = SceneNodeFactoryList[i]->getCreateableSceneNodeTypeName(type); - - return name; -} - -//! Adds a scene node to the scene by name -ISceneNode* CSceneManager::addSceneNode(const char* sceneNodeTypeName, ISceneNode* parent) -{ - ISceneNode* node = 0; - - for (int i=(int)SceneNodeFactoryList.size()-1; i>=0 && !node; --i) - node = SceneNodeFactoryList[i]->addSceneNode(sceneNodeTypeName, parent); - - return node; -} - - -//! Returns a typename from a scene node animator type or null if not found -const c8* CSceneManager::getAnimatorTypeName(ESCENE_NODE_ANIMATOR_TYPE type) const -{ - const char* name = 0; - - for (u32 i=0; !name && igetCreateableSceneNodeAnimatorTypeName(type); - - return name; -} - - -//! Writes attributes of the scene node. -void CSceneManager::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const -{ - out->addString ("Name", Name.c_str()); - out->addInt ("Id", ID ); - out->addColorf ("AmbientLight", AmbientLight); -} - -//! Reads attributes of the scene node. -void CSceneManager::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) -{ - Name = in->getAttributeAsString("Name"); - ID = in->getAttributeAsInt("Id"); - AmbientLight = in->getAttributeAsColorf("AmbientLight"); - - RelativeTranslation.set(0,0,0); - RelativeRotation.set(0,0,0); - RelativeScale.set(1,1,1); - IsVisible = true; - AutomaticCullingState = scene::EAC_BOX; - DebugDataVisible = scene::EDS_OFF; - IsDebugObject = false; - - updateAbsolutePosition(); -} - - -//! Sets ambient color of the scene -void CSceneManager::setAmbientLight(const video::SColorf &ambientColor) -{ - AmbientLight = ambientColor; -} - - -//! Returns ambient color of the scene -const video::SColorf& CSceneManager::getAmbientLight() const -{ - return AmbientLight; -} - - -//! Returns a mesh writer implementation if available -IMeshWriter* CSceneManager::createMeshWriter(EMESH_WRITER_TYPE type) -{ - switch(type) - { - case EMWT_IRR_MESH: -#ifdef _IRR_COMPILE_WITH_IRR_WRITER_ - return new CIrrMeshWriter(Driver, FileSystem); -#else - return 0; -#endif - case EMWT_COLLADA: -#ifdef _IRR_COMPILE_WITH_COLLADA_WRITER_ - return new CColladaMeshWriter(Driver, FileSystem); -#else - return 0; -#endif - case EMWT_STL: -#ifdef _IRR_COMPILE_WITH_STL_WRITER_ - return new CSTLMeshWriter(this); -#else - return 0; -#endif - } - - return 0; -} - - -// creates a scenemanager -ISceneManager* createSceneManager(video::IVideoDriver* driver, - io::IFileSystem* fs, gui::ICursorControl* cursorcontrol, - gui::IGUIEnvironment *guiEnvironment) -{ - return new CSceneManager(driver, fs, cursorcontrol, 0, guiEnvironment ); -} - - -} // end namespace scene -} // end namespace irr - +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "IrrCompileConfig.h" +#include "CSceneManager.h" +#include "IVideoDriver.h" +#include "IFileSystem.h" +#include "SAnimatedMesh.h" +#include "CMeshCache.h" +#include "IWriteFile.h" +#include "IXMLWriter.h" +#include "ISceneUserDataSerializer.h" +#include "IGUIEnvironment.h" +#include "IMaterialRenderer.h" + +#include "os.h" + +#include "CGeometryCreator.h" + +#ifdef _IRR_COMPILE_WITH_IRR_MESH_LOADER_ +#include "CIrrMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_BSP_LOADER_ +#include "CBSPMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_MD2_LOADER_ +#include "CMD2MeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_MS3D_LOADER_ +#include "CMS3DMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_3DS_LOADER_ +#include "C3DSMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_X_LOADER_ +#include "CXMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_OCT_LOADER_ +#include "COCTLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_CSM_LOADER_ +#include "CCSMLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_LMTS_LOADER_ +#include "CLMTSMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_MY3D_LOADER_ +#include "CMY3DMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_COLLADA_LOADER_ +#include "CColladaFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_DMF_LOADER_ +#include "CDMFLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_OGRE_LOADER_ +#include "COgreMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_OBJ_LOADER_ +#include "COBJMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_MD3_LOADER_ +#include "CMD3MeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_B3D_LOADER_ +#include "CB3DMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_STL_LOADER_ +#include "CSTLMeshFileLoader.h" +#endif + +#ifdef _IRR_COMPILE_WITH_COLLADA_WRITER_ +#include "CColladaMeshWriter.h" +#endif + +#ifdef _IRR_COMPILE_WITH_IRR_WRITER_ +#include "CIrrMeshWriter.h" +#endif + +#ifdef _IRR_COMPILE_WITH_STL_WRITER_ +#include "CSTLMeshWriter.h" +#endif + +#include "CCubeSceneNode.h" +#include "CSphereSceneNode.h" +#include "CAnimatedMeshSceneNode.h" +#include "COctTreeSceneNode.h" +#include "CCameraSceneNode.h" +#include "CCameraMayaSceneNode.h" +#include "CCameraFPSSceneNode.h" +#include "CLightSceneNode.h" +#include "CBillboardSceneNode.h" +#include "CMeshSceneNode.h" +#include "CSkyBoxSceneNode.h" +#include "CSkyDomeSceneNode.h" +#include "CParticleSystemSceneNode.h" +#include "CDummyTransformationSceneNode.h" +#include "CWaterSurfaceSceneNode.h" +#include "CTerrainSceneNode.h" +#include "CEmptySceneNode.h" +#include "CTextSceneNode.h" +#include "CDefaultSceneNodeFactory.h" + +#include "CSceneCollisionManager.h" +#include "CMeshManipulator.h" +#include "CTriangleSelector.h" +#include "COctTreeTriangleSelector.h" +#include "CTriangleBBSelector.h" +#include "CMetaTriangleSelector.h" +#include "CTerrainTriangleSelector.h" + +#include "CSceneNodeAnimatorRotation.h" +#include "CSceneNodeAnimatorFlyCircle.h" +#include "CSceneNodeAnimatorFlyStraight.h" +#include "CSceneNodeAnimatorTexture.h" +#include "CSceneNodeAnimatorCollisionResponse.h" +#include "CSceneNodeAnimatorDelete.h" +#include "CSceneNodeAnimatorFollowSpline.h" +#include "CDefaultSceneNodeAnimatorFactory.h" + +#include "CQuake3ShaderSceneNode.h" +#include "CVolumeLightSceneNode.h" + +//! Enable debug features +#define SCENEMANAGER_DEBUG + +namespace irr +{ +namespace scene +{ + +//! constructor +CSceneManager::CSceneManager(video::IVideoDriver* driver, io::IFileSystem* fs, + gui::ICursorControl* cursorControl, IMeshCache* cache, + gui::IGUIEnvironment* gui) +: ISceneNode(0, 0), Driver(driver), FileSystem(fs), GUIEnvironment(gui), + CursorControl(cursorControl), CollisionManager(0), MeshManipulator(0), + ActiveCamera(0), ShadowColor(150,0,0,0), AmbientLight(0,0,0,0), + MeshCache(cache), CurrentRendertime(ESNRP_COUNT), + IRR_XML_FORMAT_SCENE(L"irr_scene"), IRR_XML_FORMAT_NODE(L"node"), IRR_XML_FORMAT_NODE_ATTR_TYPE(L"type") +{ + #ifdef _DEBUG + ISceneManager::setDebugName("CSceneManager ISceneManager"); + ISceneNode::setDebugName("CSceneManager ISceneNode"); + #endif + + if (Driver) + Driver->grab(); + + if (FileSystem) + FileSystem->grab(); + + if (CursorControl) + CursorControl->grab(); + + if ( GUIEnvironment ) + GUIEnvironment->grab(); + + // create mesh cache if not there already + if (!MeshCache) + MeshCache = new CMeshCache(); + else + MeshCache->grab(); + + // create collision manager + CollisionManager = new CSceneCollisionManager(this, Driver); + + // create manipulator + MeshManipulator = new CMeshManipulator(); + + // add file format loaders + + #ifdef _IRR_COMPILE_WITH_IRR_MESH_LOADER_ + MeshLoaderList.push_back(new CIrrMeshFileLoader(Driver, this, FileSystem)); + #endif + #ifdef _IRR_COMPILE_WITH_BSP_LOADER_ + MeshLoaderList.push_back(new CBSPMeshFileLoader(FileSystem, Driver, this)); + #endif + #ifdef _IRR_COMPILE_WITH_MD2_LOADER_ + MeshLoaderList.push_back(new CMD2MeshFileLoader()); + #endif + #ifdef _IRR_COMPILE_WITH_MS3D_LOADER_ + MeshLoaderList.push_back(new CMS3DMeshFileLoader(Driver)); + #endif + #ifdef _IRR_COMPILE_WITH_3DS_LOADER_ + MeshLoaderList.push_back(new C3DSMeshFileLoader(MeshManipulator,FileSystem, Driver)); + #endif + #ifdef _IRR_COMPILE_WITH_X_LOADER_ + MeshLoaderList.push_back(new CXMeshFileLoader(this)); + #endif + #ifdef _IRR_COMPILE_WITH_OCT_LOADER_ + MeshLoaderList.push_back(new COCTLoader(Driver)); + #endif + #ifdef _IRR_COMPILE_WITH_CSM_LOADER_ + MeshLoaderList.push_back(new CCSMLoader(this, FileSystem)); + #endif + #ifdef _IRR_COMPILE_WITH_LMTS_LOADER_ + MeshLoaderList.push_back(new CLMTSMeshFileLoader(FileSystem, Driver, &Parameters)); + #endif + #ifdef _IRR_COMPILE_WITH_MY3D_LOADER_ + MeshLoaderList.push_back(new CMY3DMeshFileLoader(FileSystem, Driver, this)); + #endif + #ifdef _IRR_COMPILE_WITH_COLLADA_LOADER_ + MeshLoaderList.push_back(new CColladaFileLoader(Driver, this, FileSystem)); + #endif + #ifdef _IRR_COMPILE_WITH_DMF_LOADER_ + MeshLoaderList.push_back(new CDMFLoader(Driver, this)); + #endif + #ifdef _IRR_COMPILE_WITH_OGRE_LOADER_ + MeshLoaderList.push_back(new COgreMeshFileLoader(MeshManipulator, FileSystem, Driver)); + #endif + #ifdef _IRR_COMPILE_WITH_OBJ_LOADER_ + MeshLoaderList.push_back(new COBJMeshFileLoader(FileSystem, Driver)); + #endif + #ifdef _IRR_COMPILE_WITH_MD3_LOADER_ + MeshLoaderList.push_back(new CMD3MeshFileLoader(FileSystem, Driver)); + #endif + #ifdef _IRR_COMPILE_WITH_B3D_LOADER_ + MeshLoaderList.push_back(new CB3DMeshFileLoader(this)); + #endif + #ifdef _IRR_COMPILE_WITH_STL_LOADER_ + MeshLoaderList.push_back(new CSTLMeshFileLoader()); + #endif + + // factories + ISceneNodeFactory* factory = new CDefaultSceneNodeFactory(this); + registerSceneNodeFactory(factory); + factory->drop(); + + ISceneNodeAnimatorFactory* animatorFactory = new CDefaultSceneNodeAnimatorFactory(this); + registerSceneNodeAnimatorFactory(animatorFactory); + animatorFactory->drop(); +} + + + +//! destructor +CSceneManager::~CSceneManager() +{ + clearDeletionList(); + + if (Driver) + Driver->drop(); + + if (FileSystem) + FileSystem->drop(); + + if (CursorControl) + CursorControl->drop(); + + if (CollisionManager) + CollisionManager->drop(); + + if (MeshManipulator) + MeshManipulator->drop(); + + if ( GUIEnvironment ) + GUIEnvironment->drop (); + + u32 i; + + for (i=0; idrop(); + + if (ActiveCamera) + ActiveCamera->drop(); + + if (MeshCache) + MeshCache->drop(); + + for (i=0; idrop(); + + for (i=0; idrop(); +} + + +//! gets an animateable mesh. loads it if needed. returned pointer must not be dropped. +IAnimatedMesh* CSceneManager::getMesh(const c8* filename) +{ + IAnimatedMesh* msh = MeshCache->getMeshByFilename(filename); + if (msh) + return msh; + + io::IReadFile* file = FileSystem->createAndOpenFile(filename); + if (!file) + { + os::Printer::log("Could not load mesh, because file could not be opened.", filename, ELL_ERROR); + return 0; + } + + core::stringc name = filename; + name.make_lower(); + s32 count = MeshLoaderList.size(); + for (s32 i=count-1; i>=0; --i) + { + if (MeshLoaderList[i]->isALoadableFileExtension(name.c_str())) + { + // reset file to avoid side effects of previous calls to createMesh + file->seek(0); + msh = MeshLoaderList[i]->createMesh(file); + if (msh) + { + MeshCache->addMesh(filename, msh); + msh->drop(); + break; + } + } + } + + file->drop(); + + if (!msh) + os::Printer::log("Could not load mesh, file format seems to be unsupported", filename, ELL_ERROR); + else + os::Printer::log("Loaded mesh", filename, ELL_INFORMATION); + + return msh; +} + + +//! returns the video driver +video::IVideoDriver* CSceneManager::getVideoDriver() +{ + return Driver; +} + +//! returns the GUI Environment +gui::IGUIEnvironment* CSceneManager::getGUIEnvironment () +{ + return GUIEnvironment; +} + + +//! Adds a text scene node, which is able to display +//! 2d text at a position in three dimensional space +ITextSceneNode* CSceneManager::addTextSceneNode(gui::IGUIFont* font, + const wchar_t* text, video::SColor color, ISceneNode* parent, + const core::vector3df& position, s32 id) +{ + if (!font) + return 0; + + if (!parent) + parent = this; + + ITextSceneNode* t = new CTextSceneNode(parent, this, id, font, + getSceneCollisionManager(), position, text, color); + t->drop(); + + return t; +} + +//! Adds a text scene node, which uses billboards +ITextSceneNode* CSceneManager::addBillboardTextSceneNode(gui::IGUIFont* font, + const wchar_t* text, ISceneNode* parent, + const core::dimension2d& size, + const core::vector3df& position, s32 id, + video::SColor shade_top, video::SColor shade_down) +{ + if (!font) + return 0; + + if (!parent) + parent = this; + + ITextSceneNode* node = new CBillboardTextSceneNode(parent, this, id, font, text, position, size, + shade_top, shade_down); + node->drop(); + + return node; + +} + + +//! Adds a scene node, which can render a quake3 shader +ISceneNode* CSceneManager::addQuake3SceneNode( IMeshBuffer* meshBuffer, + const quake3::SShader * shader, + ISceneNode* parent, + s32 id + ) + +{ + if ( 0 == shader ) + return 0; + + if (!parent) + parent = this; + + CQuake3ShaderSceneNode* node = new CQuake3ShaderSceneNode ( parent, this, id, FileSystem, meshBuffer, shader ); + node->drop(); + + return node; + +} + +//! adds Volume Lighting Scene Node. +//! the returned pointer must not be dropped. +ISceneNode* CSceneManager::addVolumeLightSceneNode(ISceneNode* parent, s32 id, + const s32 subdivU, const s32 subdivV, + const video::SColor foot, + const video::SColor tail, + const core::vector3df& position, const core::vector3df& rotation, const core::vector3df& scale) +{ + if (!parent) + parent = this; + + ISceneNode* node = new CVolumeLightSceneNode(parent, this, id, subdivU, subdivV, foot, tail, position, rotation, scale); + node->drop(); + + return node; +} + +//! adds a test scene node for test purposes to the scene. It is a simple cube of (1,1,1) size. +//! the returned pointer must not be dropped. +ISceneNode* CSceneManager::addCubeSceneNode(f32 size, ISceneNode* parent, s32 id, + const core::vector3df& position, const core::vector3df& rotation, const core::vector3df& scale) +{ + if (!parent) + parent = this; + + ISceneNode* node = new CCubeSceneNode(size, parent, this, id, position, rotation, scale); + node->drop(); + + return node; +} + +//! Adds a sphere scene node for test purposes to the scene. +ISceneNode* CSceneManager::addSphereSceneNode(f32 radius, s32 polyCount, ISceneNode* parent, s32 id, + const core::vector3df& position, + const core::vector3df& rotation, + const core::vector3df& scale) +{ + if (!parent) + parent = this; + + ISceneNode* node = new CSphereSceneNode(radius, polyCount, polyCount, parent, this, id, position, rotation, scale); + node->drop(); + + return node; +} + + +//! adds a scene node for rendering a static mesh +//! the returned pointer must not be dropped. +IMeshSceneNode* CSceneManager::addMeshSceneNode(IMesh* mesh, ISceneNode* parent, s32 id, + const core::vector3df& position, const core::vector3df& rotation, + const core::vector3df& scale, bool alsoAddIfMeshPointerZero) +{ + if (!alsoAddIfMeshPointerZero && !mesh) + return 0; + + if (!parent) + parent = this; + + IMeshSceneNode* node = new CMeshSceneNode(mesh, parent, this, id, position, rotation, scale); + node->drop(); + + return node; +} + + +//! Adds a scene node for rendering a animated water surface mesh. +ISceneNode* CSceneManager::addWaterSurfaceSceneNode(IMesh* mesh, f32 waveHeight, f32 waveSpeed, f32 waveLength, + ISceneNode* parent, s32 id, const core::vector3df& position, + const core::vector3df& rotation, const core::vector3df& scale) +{ + if (!mesh) + return 0; + + if (!parent) + parent = this; + + ISceneNode* node = new CWaterSurfaceSceneNode(waveHeight, waveSpeed, waveLength, + mesh, parent, this, id, position, rotation, scale); + + node->drop(); + + return node; +} + + + +//! adds a scene node for rendering an animated mesh model +IAnimatedMeshSceneNode* CSceneManager::addAnimatedMeshSceneNode(IAnimatedMesh* mesh, ISceneNode* parent, s32 id, + const core::vector3df& position, const core::vector3df& rotation, + const core::vector3df& scale, bool alsoAddIfMeshPointerZero) +{ + if (!alsoAddIfMeshPointerZero && !mesh) + return 0; + + if (!parent) + parent = this; + + IAnimatedMeshSceneNode* node = + new CAnimatedMeshSceneNode(mesh, parent, this, id, position, rotation, scale); + node->drop(); + + return node; +} + + +//! Adds a scene node for rendering using a octtree to the scene graph. This a good method for rendering +//! scenes with lots of geometry. The Octree is built on the fly from the mesh, much +//! faster then a bsp tree. +ISceneNode* CSceneManager::addOctTreeSceneNode(IAnimatedMesh* mesh, ISceneNode* parent, + s32 id, s32 minimalPolysPerNode, bool alsoAddIfMeshPointerZero) +{ + if (!alsoAddIfMeshPointerZero && (!mesh || !mesh->getFrameCount())) + return 0; + + return addOctTreeSceneNode(mesh ? mesh->getMesh(0) : 0, + parent, id, minimalPolysPerNode, + alsoAddIfMeshPointerZero); +} + + + +//! Adss a scene node for rendering using a octtree. This a good method for rendering +//! scenes with lots of geometry. The Octree is built on the fly from the mesh, much +//! faster then a bsp tree. +ISceneNode* CSceneManager::addOctTreeSceneNode(IMesh* mesh, ISceneNode* parent, + s32 id, s32 minimalPolysPerNode, bool alsoAddIfMeshPointerZero) +{ + if (!alsoAddIfMeshPointerZero && !mesh) + return 0; + + if (!parent) + parent = this; + + COctTreeSceneNode* node = new COctTreeSceneNode(parent, this, id, minimalPolysPerNode); + + if (mesh) + node->createTree(mesh); + + node->drop(); + + return node; +} + + +//! Adds a camera scene node to the tree and sets it as active camera. +//! \param position: Position of the space relative to its parent where the camera will be placed. +//! \param lookat: Position where the camera will look at. Also known as target. +//! \param parent: Parent scene node of the camera. Can be null. If the parent moves, +//! the camera will move too. +//! \return Returns pointer to interface to camera +ICameraSceneNode* CSceneManager::addCameraSceneNode(ISceneNode* parent, + const core::vector3df& position, const core::vector3df& lookat, s32 id) +{ + if (!parent) + parent = this; + + ICameraSceneNode* node = new CCameraSceneNode(parent, this, id, position, lookat); + node->drop(); + + setActiveCamera(node); + + return node; +} + + + +//! Adds a camera scene node which is able to be controlle with the mouse similar +//! like in the 3D Software Maya by Alias Wavefront. +//! The returned pointer must not be dropped. +ICameraSceneNode* CSceneManager::addCameraSceneNodeMaya(ISceneNode* parent, + f32 rotateSpeed, f32 zoomSpeed, f32 translationSpeed, s32 id) +{ + if (!parent) + parent = this; + + ICameraSceneNode* node = new CCameraMayaSceneNode(parent, this, id, rotateSpeed, + zoomSpeed, translationSpeed); + node->drop(); + + setActiveCamera(node); + + return node; +} + + + +//! Adds a camera scene node which is able to be controled with the mouse and keys +//! like in most first person shooters (FPS): +ICameraSceneNode* CSceneManager::addCameraSceneNodeFPS(ISceneNode* parent, + f32 rotateSpeed, f32 moveSpeed, s32 id, + SKeyMap* keyMapArray, s32 keyMapSize, bool noVerticalMovement,f32 jumpSpeed) +{ + if (!parent) + parent = this; + + ICameraSceneNode* node = new CCameraFPSSceneNode(parent, this, CursorControl, + id, rotateSpeed, moveSpeed, jumpSpeed, keyMapArray, keyMapSize, noVerticalMovement); + node->drop(); + + setActiveCamera(node); + + return node; +} + + + +//! Adds a dynamic light scene node. The light will cast dynamic light on all +//! other scene nodes in the scene, which have the material flag video::MTF_LIGHTING +//! turned on. (This is the default setting in most scene nodes). +ILightSceneNode* CSceneManager::addLightSceneNode(ISceneNode* parent, + const core::vector3df& position, video::SColorf color, f32 range, s32 id) +{ + if (!parent) + parent = this; + + ILightSceneNode* node = new CLightSceneNode(parent, this, id, position, color, range); + node->drop(); + + return node; +} + + + +//! Adds a billboard scene node to the scene. A billboard is like a 3d sprite: A 2d element, +//! which always looks to the camera. It is usually used for things like explosions, fire, +//! lensflares and things like that. +IBillboardSceneNode* CSceneManager::addBillboardSceneNode(ISceneNode* parent, + const core::dimension2d& size, const core::vector3df& position, s32 id, + video::SColor shade_top, video::SColor shade_down + ) +{ + if (!parent) + parent = this; + + IBillboardSceneNode* node = new CBillboardSceneNode(parent, this, id, position, size, + shade_top, shade_down); + node->drop(); + + return node; +} + + + +//! Adds a skybox scene node. A skybox is a big cube with 6 textures on it and +//! is drawn around the camera position. +ISceneNode* CSceneManager::addSkyBoxSceneNode(video::ITexture* top, video::ITexture* bottom, + video::ITexture* left, video::ITexture* right, video::ITexture* front, + video::ITexture* back, ISceneNode* parent, s32 id) +{ + if (!parent) + parent = this; + + ISceneNode* node = new CSkyBoxSceneNode(top, bottom, left, right, + front, back, parent, this, id); + + node->drop(); + return node; +} + + +//! Adds a skydome scene node. A skydome is a large (half-) sphere with a +//! panoramic texture on it and is drawn around the camera position. +ISceneNode* CSceneManager::addSkyDomeSceneNode(video::ITexture* texture, + u32 horiRes, u32 vertRes, f64 texturePercentage, + f64 spherePercentage, ISceneNode* parent, s32 id) +{ + if (!parent) + parent = this; + + ISceneNode* node = new CSkyDomeSceneNode(texture, horiRes, vertRes, + texturePercentage, spherePercentage, parent, this, id); + + node->drop(); + return node; +} + + +//! Adds a particle system scene node. +IParticleSystemSceneNode* CSceneManager::addParticleSystemSceneNode( + bool withDefaultEmitter, ISceneNode* parent, s32 id, + const core::vector3df& position, const core::vector3df& rotation, + const core::vector3df& scale) +{ + if (!parent) + parent = this; + + IParticleSystemSceneNode* node = new CParticleSystemSceneNode(withDefaultEmitter, + parent, this, id, position, rotation, scale); + node->drop(); + + return node; +} + + +//! Adds a terrain scene node to the scene graph. +ITerrainSceneNode* CSceneManager::addTerrainSceneNode( + const char* heightMapFileName, + ISceneNode* parent, s32 id, + const core::vector3df& position, + const core::vector3df& rotation, + const core::vector3df& scale, + video::SColor vertexColor, + s32 maxLOD, E_TERRAIN_PATCH_SIZE patchSize, s32 smoothFactor, + bool addAlsoIfHeightmapEmpty) +{ + io::IReadFile* file = FileSystem->createAndOpenFile(heightMapFileName); + + if(!file && !addAlsoIfHeightmapEmpty) + { + os::Printer::log("Could not load terrain, because file could not be opened.", + heightMapFileName, ELL_ERROR); + return 0; + } + + ITerrainSceneNode* terrain = addTerrainSceneNode(file, parent, id, + position, rotation, scale, vertexColor, maxLOD, patchSize, + smoothFactor, addAlsoIfHeightmapEmpty); + + if (file) + file->drop(); + + return terrain; +} + +//! Adds a terrain scene node to the scene graph. +ITerrainSceneNode* CSceneManager::addTerrainSceneNode( + io::IReadFile* heightMapFile, + ISceneNode* parent, s32 id, + const core::vector3df& position, + const core::vector3df& rotation, + const core::vector3df& scale, + video::SColor vertexColor, + s32 maxLOD, E_TERRAIN_PATCH_SIZE patchSize, + s32 smoothFactor, + bool addAlsoIfHeightmapEmpty) +{ + if (!parent) + parent = this; + + if (!heightMapFile && !addAlsoIfHeightmapEmpty) + { + os::Printer::log("Could not load terrain, because file could not be opened.", ELL_ERROR); + return 0; + } + + CTerrainSceneNode* node = new CTerrainSceneNode(parent, this, FileSystem, id, + maxLOD, patchSize, position, rotation, scale); + + if (!node->loadHeightMap(heightMapFile, vertexColor, smoothFactor)) + { + if (!addAlsoIfHeightmapEmpty) + { + node->remove(); + node->drop(); + return 0; + } + } + + node->drop(); + return node; +} + + +//! Adds an empty scene node. +ISceneNode* CSceneManager::addEmptySceneNode(ISceneNode* parent, s32 id) +{ + if (!parent) + parent = this; + + ISceneNode* node = new CEmptySceneNode(parent, this, id); + node->drop(); + + return node; +} + + +//! Adds a dummy transformation scene node to the scene graph. +IDummyTransformationSceneNode* CSceneManager::addDummyTransformationSceneNode( + ISceneNode* parent, s32 id) +{ + if (!parent) + parent = this; + + IDummyTransformationSceneNode* node = new CDummyTransformationSceneNode( + parent, this, id); + node->drop(); + + return node; +} + +//! Adds a Hill Plane mesh to the mesh pool. The mesh is generated on the fly +//! and looks like a plane with some hills on it. It is uses mostly for quick +//! tests of the engine only. You can specify how many hills there should be +//! on the plane and how high they should be. Also you must specify a name for +//! the mesh, because the mesh is added to the mesh pool, and can be retrieved +//! again using ISceneManager::getMesh with the name as parameter. +IAnimatedMesh* CSceneManager::addHillPlaneMesh(const c8* name, + const core::dimension2d& tileSize, + const core::dimension2d& tileCount, + video::SMaterial* material, f32 hillHeight, + const core::dimension2d& countHills, + const core::dimension2d& textureRepeatCount) +{ + if (!name || MeshCache->isMeshLoaded(name)) + return 0; + + IMesh* mesh = CGeometryCreator::createHillPlaneMesh(tileSize, + tileCount, material, hillHeight, countHills, + textureRepeatCount); + if (!mesh) + return 0; + + SAnimatedMesh* animatedMesh = new SAnimatedMesh(); + if (!animatedMesh) + return 0; + + animatedMesh->addMesh(mesh); + animatedMesh->recalculateBoundingBox(); + mesh->drop(); + + MeshCache->addMesh(name, animatedMesh); + animatedMesh->drop(); + + return animatedMesh; +} + + +//! Adds a terrain mesh to the mesh pool. +IAnimatedMesh* CSceneManager::addTerrainMesh(const c8* name, + video::IImage* texture, video::IImage* heightmap, + const core::dimension2d& stretchSize, + f32 maxHeight, + const core::dimension2d& defaultVertexBlockSize) +{ + if (!name || MeshCache->isMeshLoaded(name)) + return 0; + + IMesh* mesh = CGeometryCreator::createTerrainMesh(texture, heightmap, + stretchSize, maxHeight, getVideoDriver(), + defaultVertexBlockSize); + if (!mesh) + return 0; + + SAnimatedMesh* animatedMesh = new SAnimatedMesh(); + if (!animatedMesh) + return 0; + + animatedMesh->addMesh(mesh); + animatedMesh->recalculateBoundingBox(); + mesh->drop(); + + MeshCache->addMesh(name, animatedMesh); + animatedMesh->drop(); + + return animatedMesh; +} + +//! Adds an arrow mesh to the mesh pool. +IAnimatedMesh* CSceneManager::addArrowMesh(const c8* name, + video::SColor vtxColor0, video::SColor vtxColor1, + u32 tesselationCylinder, u32 tesselationCone, f32 height, + f32 cylinderHeight, f32 width0,f32 width1) +{ + if (!name || MeshCache->isMeshLoaded(name)) + return 0; + + IMesh* mesh = CGeometryCreator::createArrowMesh( tesselationCylinder, + tesselationCone, height, cylinderHeight, width0,width1, + vtxColor0, vtxColor1); + if (!mesh) + return 0; + + SAnimatedMesh* animatedMesh = new SAnimatedMesh(); + if (!animatedMesh) + return 0; + + animatedMesh->addMesh(mesh); + animatedMesh->recalculateBoundingBox(); + mesh->drop(); + + MeshCache->addMesh(name, animatedMesh); + animatedMesh->drop(); + + return animatedMesh; +} + + + +//! Adds a static sphere mesh to the mesh pool. +IAnimatedMesh* CSceneManager::addSphereMesh(const c8* name, + f32 radius, u32 polyCountX, u32 polyCountY) +{ + if (!name || MeshCache->isMeshLoaded(name)) + return 0; + + IMesh* mesh = CGeometryCreator::createSphereMesh( radius, polyCountX, polyCountY); + if (!mesh) + return 0; + + SAnimatedMesh* animatedMesh = new SAnimatedMesh(); + if (!animatedMesh) + return 0; + + animatedMesh->addMesh(mesh); + animatedMesh->recalculateBoundingBox(); + mesh->drop(); + + MeshCache->addMesh(name, animatedMesh); + animatedMesh->drop(); + + return animatedMesh; +} + + + +//! Returns the root scene node. This is the scene node wich is parent +//! of all scene nodes. The root scene node is a special scene node which +//! only exists to manage all scene nodes. It is not rendered and cannot +//! be removed from the scene. +//! \return Returns a pointer to the root scene node. +ISceneNode* CSceneManager::getRootSceneNode() +{ + return this; +} + + + +//! Returns the current active camera. +//! \return The active camera is returned. Note that this can be NULL, if there +//! was no camera created yet. +ICameraSceneNode* CSceneManager::getActiveCamera() +{ + return ActiveCamera; +} + + + +//! Sets the active camera. The previous active camera will be deactivated. +//! \param camera: The new camera which should be active. +void CSceneManager::setActiveCamera(ICameraSceneNode* camera) +{ + if (ActiveCamera) + ActiveCamera->drop(); + + ActiveCamera = camera; + + if (ActiveCamera) + ActiveCamera->grab(); +} + + + + +//! renders the node. +void CSceneManager::render() +{ +} + + +//! returns the axis aligned bounding box of this node +const core::aabbox3d& CSceneManager::getBoundingBox() const +{ + _IRR_DEBUG_BREAK_IF(true) // Bounding Box of Scene Manager wanted. + + // should never be used. + return *((core::aabbox3d*)0); +} + + + +//! returns if node is culled +bool CSceneManager::isCulled(const ISceneNode* node) +{ + const ICameraSceneNode* cam = getActiveCamera(); + if (!cam) + return false; + + switch ( node->getAutomaticCulling() ) + { + // can be seen by a bounding box ? + case scene::EAC_BOX: + { + core::aabbox3d tbox = node->getBoundingBox(); + node->getAbsoluteTransformation().transformBox(tbox); + return !(tbox.intersectsWithBox(cam->getViewFrustum()->getBoundingBox() )); + } + + // can be seen by a bounding sphere + case scene::EAC_FRUSTUM_SPHERE: + { // requires bbox diameter + } + break; + + // can be seen by cam pyramid planes ? + case scene::EAC_FRUSTUM_BOX: + { + SViewFrustum frust = *cam->getViewFrustum(); + + //transform the frustum to the node's current absolute transformation + core::matrix4 invTrans(node->getAbsoluteTransformation()); + invTrans.makeInverse(); + frust.transform(invTrans); + + core::vector3df edges[8]; + node->getBoundingBox().getEdges(edges); + + for (s32 i=0; igetMaterialCount(); + + taken = 0; + for (u32 i=0; igetMaterialRenderer(node->getMaterial(i).MaterialType); + if (rnd && rnd->isTransparent()) + { + // register as transparent node + TransparentNodeEntry e(node, camWorldPos); + TransparentNodeList.push_back(e); + taken = 1; + break; + } + } + + // not transparent, register as solid + if ( 0 == taken ) + { + SolidNodeList.push_back( node ); + taken = 1; + } + } + break; + case ESNRP_SHADOW: + if (!isCulled(node)) + { + ShadowNodeList.push_back(node); + taken = 1; + } + break; + + case ESNRP_COUNT: // ignore this one + break; + } + +#ifdef SCENEMANAGER_DEBUG + s32 index = Parameters.findAttribute ( "calls" ); + Parameters.setAttribute ( index, Parameters.getAttributeAsInt ( index ) + 1 ); + + if ( 0 == taken ) + { + index = Parameters.findAttribute ( "culled" ); + Parameters.setAttribute ( index, Parameters.getAttributeAsInt ( index ) + 1 ); + } +#endif + + return taken; +} + +//! This method is called just before the rendering process of the whole scene. +//! draws all scene nodes +void CSceneManager::drawAll() +{ + if (!Driver) + return; + + // reset attributes + Parameters.setAttribute ( "culled", 0 ); + Parameters.setAttribute ( "calls", 0 ); + Parameters.setAttribute ( "drawn", 0 ); + + // reset all transforms + video::IVideoDriver* driver = getVideoDriver(); + if ( driver ) + { + driver->setTransform ( video::ETS_PROJECTION, core::IdentityMatrix ); + driver->setTransform ( video::ETS_VIEW, core::IdentityMatrix ); + driver->setTransform ( video::ETS_WORLD, core::IdentityMatrix ); + driver->setTransform ( video::ETS_TEXTURE_0, core::IdentityMatrix ); + driver->setTransform ( video::ETS_TEXTURE_1, core::IdentityMatrix ); + driver->setTransform ( video::ETS_TEXTURE_2, core::IdentityMatrix ); + driver->setTransform ( video::ETS_TEXTURE_3, core::IdentityMatrix ); + } + + // do animations and other stuff. + OnAnimate(os::Timer::getTime()); + + /*! + First Scene Node for prerendering should be the active camera + consistent Camera is needed for culling + */ + camWorldPos.set(0,0,0); + if ( ActiveCamera ) + { + ActiveCamera->OnRegisterSceneNode(); + camWorldPos = ActiveCamera->getAbsolutePosition(); + } + + // let all nodes register themselves + OnRegisterSceneNode(); + + u32 i; // new ISO for scoping problem in some compilers + + //render camera scenes + { + CurrentRendertime = ESNRP_CAMERA; + for (i=0; irender(); + + CameraList.set_used(0); + } + + //render lights scenes + { + CurrentRendertime = ESNRP_LIGHT; + + Driver->deleteAllDynamicLights(); + + Driver->setAmbientLight(AmbientLight); + + LightList.sort (); // on distance to camera + + u32 maxLights = core::min_ ( Driver->getMaximalDynamicLightAmount (), LightList.size () ); + for (i=0; i< maxLights; ++i) + LightList[i].node->render(); + + LightList.set_used(0); + } + + // render skyboxes + { + CurrentRendertime = ESNRP_SKY_BOX; + + for (i=0; irender(); + + SkyBoxList.set_used(0); + } + + + // render default objects + { + CurrentRendertime = ESNRP_SOLID; + SolidNodeList.sort(); // sort by textures + + for (i=0; irender(); + + Parameters.setAttribute ( "drawn", (s32) SolidNodeList.size () ); + + SolidNodeList.set_used(0); + } + + // render shadows + { + CurrentRendertime = ESNRP_SHADOW; + for (i=0; irender(); + + if (!ShadowNodeList.empty()) + Driver->drawStencilShadow(true,ShadowColor, ShadowColor, + ShadowColor, ShadowColor); + + ShadowNodeList.set_used(0); + } + + // render transparent objects. + { + CurrentRendertime = ESNRP_TRANSPARENT; + TransparentNodeList.sort(); // sort by distance from camera + + for (i=0; irender(); + + TransparentNodeList.set_used(0); + } + + + clearDeletionList(); + + CurrentRendertime = ESNRP_COUNT; +} + + +//! Sets the color of stencil buffers shadows drawn by the scene manager. +void CSceneManager::setShadowColor(video::SColor color) +{ + ShadowColor = color; +} + + +//! Returns the current color of shadows. +video::SColor CSceneManager::getShadowColor() const +{ + return ShadowColor; +} + + + +//! creates a rotation animator, which rotates the attached scene node around itself. +ISceneNodeAnimator* CSceneManager::createRotationAnimator(const core::vector3df& rotationPerSecond) +{ + ISceneNodeAnimator* anim = new CSceneNodeAnimatorRotation(os::Timer::getTime(), + rotationPerSecond); + + return anim; +} + + + +//! creates a fly circle animator, which lets the attached scene node fly around a center. +ISceneNodeAnimator* CSceneManager::createFlyCircleAnimator( + const core::vector3df& normal, f32 radius, f32 speed, + const core::vector3df& direction) +{ + ISceneNodeAnimator* anim = new CSceneNodeAnimatorFlyCircle(os::Timer::getTime(), normal, + radius, speed, direction); + return anim; +} + + +//! Creates a fly straight animator, which lets the attached scene node +//! fly or move along a line between two points. +ISceneNodeAnimator* CSceneManager::createFlyStraightAnimator(const core::vector3df& startPoint, + const core::vector3df& endPoint, u32 timeForWay, bool loop) +{ + ISceneNodeAnimator* anim = new CSceneNodeAnimatorFlyStraight(startPoint, + endPoint, timeForWay, loop, os::Timer::getTime()); + + return anim; +} + + +//! Creates a texture animator, which switches the textures of the target scene +//! node based on a list of textures. +ISceneNodeAnimator* CSceneManager::createTextureAnimator(const core::array& textures, + s32 timePerFrame, bool loop) +{ + ISceneNodeAnimator* anim = new CSceneNodeAnimatorTexture(textures, + timePerFrame, loop, os::Timer::getTime()); + + return anim; +} + + +//! Creates a scene node animator, which deletes the scene node after +//! some time automaticly. +ISceneNodeAnimator* CSceneManager::createDeleteAnimator(u32 when) +{ + return new CSceneNodeAnimatorDelete(this, os::Timer::getTime() + when); +} + + + + +//! Creates a special scene node animator for doing automatic collision detection +//! and response. +ISceneNodeAnimatorCollisionResponse* CSceneManager::createCollisionResponseAnimator( + ITriangleSelector* world, ISceneNode* sceneNode, const core::vector3df& ellipsoidRadius, + const core::vector3df& gravityPerSecond, + const core::vector3df& ellipsoidTranslation, f32 slidingValue) +{ + ISceneNodeAnimatorCollisionResponse* anim = new + CSceneNodeAnimatorCollisionResponse(this, world, sceneNode, + ellipsoidRadius, gravityPerSecond, + ellipsoidTranslation, slidingValue); + + return anim; +} + + +//! Creates a follow spline animator. +ISceneNodeAnimator* CSceneManager::createFollowSplineAnimator(s32 startTime, + const core::array< core::vector3df >& points, + f32 speed, f32 tightness) +{ + ISceneNodeAnimator* a = new CSceneNodeAnimatorFollowSpline(startTime, points, + speed, tightness); + return a; +} + + + +//! Adds an external mesh loader. +void CSceneManager::addExternalMeshLoader(IMeshLoader* externalLoader) +{ + if (!externalLoader) + return; + + externalLoader->grab(); + MeshLoaderList.push_back(externalLoader); +} + + + +//! Returns a pointer to the scene collision manager. +ISceneCollisionManager* CSceneManager::getSceneCollisionManager() +{ + return CollisionManager; +} + + +//! Returns a pointer to the mesh manipulator. +IMeshManipulator* CSceneManager::getMeshManipulator() +{ + return MeshManipulator; +} + + +//! Creates a simple ITriangleSelector, based on a mesh. +ITriangleSelector* CSceneManager::createTriangleSelector(IMesh* mesh, ISceneNode* node) +{ + if (!mesh || !node) + return 0; + + return new CTriangleSelector(mesh, node); +} + + +//! Creates a simple dynamic ITriangleSelector, based on a axis aligned bounding box. +ITriangleSelector* CSceneManager::createTriangleSelectorFromBoundingBox(ISceneNode* node) +{ + if (!node) + return 0; + + return new CTriangleBBSelector(node); +} + + +//! Creates a simple ITriangleSelector, based on a mesh. +ITriangleSelector* CSceneManager::createOctTreeTriangleSelector(IMesh* mesh, + ISceneNode* node, + s32 minimalPolysPerNode) +{ + if (!mesh || !node) + return 0; + + return new COctTreeTriangleSelector(mesh, node, minimalPolysPerNode); +} + + + +//! Creates a meta triangle selector. +IMetaTriangleSelector* CSceneManager::createMetaTriangleSelector() +{ + return new CMetaTriangleSelector(); +} + + + +//! Creates a triangle selector which can select triangles from a terrain scene node +ITriangleSelector* CSceneManager::createTerrainTriangleSelector( + ITerrainSceneNode* node, s32 LOD) +{ + return new CTerrainTriangleSelector(node, LOD); +} + + + +//! Adds a scene node to the deletion queue. +void CSceneManager::addToDeletionQueue(ISceneNode* node) +{ + if (!node) + return; + + node->grab(); + DeletionList.push_back(node); +} + + +//! clears the deletion list +void CSceneManager::clearDeletionList() +{ + if (DeletionList.empty()) + return; + + for (s32 i=0; i<(s32)DeletionList.size(); ++i) + { + DeletionList[i]->remove(); + DeletionList[i]->drop(); + } + + DeletionList.clear(); +} + + +//! Returns the first scene node with the specified name. +ISceneNode* CSceneManager::getSceneNodeFromName(const char* name, ISceneNode* start) +{ + if (start == 0) + start = getRootSceneNode(); + + if (!strcmp(start->getName(),name)) + return start; + + ISceneNode* node = 0; + + const core::list& list = start->getChildren(); + core::list::ConstIterator it = list.begin(); + for (; it!=list.end(); ++it) + { + node = getSceneNodeFromName(name, *it); + if (node) + return node; + } + + return 0; +} + + +//! Returns the first scene node with the specified id. +ISceneNode* CSceneManager::getSceneNodeFromId(s32 id, ISceneNode* start) +{ + if (start == 0) + start = getRootSceneNode(); + + if (start->getID() == id) + return start; + + ISceneNode* node = 0; + + const core::list& list = start->getChildren(); + core::list::ConstIterator it = list.begin(); + for (; it!=list.end(); ++it) + { + node = getSceneNodeFromId(id, *it); + if (node) + return node; + } + + return 0; +} + + +//! Returns the first scene node with the specified type. +ISceneNode* CSceneManager::getSceneNodeFromType(scene::ESCENE_NODE_TYPE type, ISceneNode* start) +{ + if (start == 0) + start = getRootSceneNode(); + + if (start->getType() == type) + return start; + + ISceneNode* node = 0; + + const core::list& list = start->getChildren(); + core::list::ConstIterator it = list.begin(); + for (; it!=list.end(); ++it) + { + node = getSceneNodeFromType(type, *it); + if (node) + return node; + } + + return 0; +} + +//! returns scene nodes by type. +void CSceneManager::getSceneNodesFromType(ESCENE_NODE_TYPE type, core::array& outNodes, ISceneNode* start) +{ + if (start == 0) + start = getRootSceneNode(); + + if (start->getType() == type) + outNodes.push_back(start); + + const core::list& list = start->getChildren(); + core::list::ConstIterator it = list.begin(); + + for (; it!=list.end(); ++it) + { + getSceneNodesFromType(type, outNodes, *it); + } +} + + +//! Posts an input event to the environment. Usually you do not have to +//! use this method, it is used by the internal engine. +bool CSceneManager::postEventFromUser(const SEvent& event) +{ + bool ret = false; + ICameraSceneNode* cam = getActiveCamera(); + if (cam) + ret = cam->OnEvent(event); + + _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; + return ret; +} + + +//! Removes all children of this scene node +void CSceneManager::removeAll() +{ + ISceneNode::removeAll(); + setActiveCamera(0); +} + + +//! Clears the whole scene. All scene nodes are removed. +void CSceneManager::clear() +{ + removeAll(); +} + + +//! Returns interface to the parameters set in this scene. +io::IAttributes* CSceneManager::getParameters() +{ + return &Parameters; +} + + +//! Returns current render pass. +E_SCENE_NODE_RENDER_PASS CSceneManager::getSceneNodeRenderPass() const +{ + return CurrentRendertime; +} + + + +//! Returns an interface to the mesh cache which is shared beween all existing scene managers. +IMeshCache* CSceneManager::getMeshCache() +{ + return MeshCache; +} + + +//! Creates a new scene manager. +ISceneManager* CSceneManager::createNewSceneManager(bool cloneContent) +{ + CSceneManager* manager = new CSceneManager(Driver, FileSystem, CursorControl, MeshCache); + + if (cloneContent) + manager->cloneMembers(this, manager); + + return manager; +} + + +//! Returns the default scene node factory which can create all built in scene nodes +ISceneNodeFactory* CSceneManager::getDefaultSceneNodeFactory() +{ + return getSceneNodeFactory(0); +} + + +//! Adds a scene node factory to the scene manager. +void CSceneManager::registerSceneNodeFactory(ISceneNodeFactory* factoryToAdd) +{ + if (factoryToAdd) + { + factoryToAdd->grab(); + SceneNodeFactoryList.push_back(factoryToAdd); + } +} + + +//! Returns amount of registered scene node factories. +u32 CSceneManager::getRegisteredSceneNodeFactoryCount() const +{ + return SceneNodeFactoryList.size(); +} + + +//! Returns a scene node factory by index +ISceneNodeFactory* CSceneManager::getSceneNodeFactory(u32 index) +{ + if (indexgrab(); + SceneNodeAnimatorFactoryList.push_back(factoryToAdd); + } +} + + +//! Returns amount of registered scene node animator factories. +u32 CSceneManager::getRegisteredSceneNodeAnimatorFactoryCount() const +{ + return SceneNodeAnimatorFactoryList.size(); +} + + +//! Returns a scene node animator factory by index +ISceneNodeAnimatorFactory* CSceneManager::getSceneNodeAnimatorFactory(u32 index) +{ + if (indexcreateAndWriteFile(filename); + if (!file) + return false; + + bool ret = saveScene(file, userDataSerializer); + file->drop(); + return ret; +} + + +//! Saves the current scene into a file. +bool CSceneManager::saveScene(io::IWriteFile* file, ISceneUserDataSerializer* userDataSerializer) +{ + if (!file) + return false; + + io::IXMLWriter* writer = FileSystem->createXMLWriter(file); + if (!writer) + return false; + + writer->writeXMLHeader(); + writeSceneNode(writer, this, userDataSerializer); + writer->drop(); + + return true; +} + + +//! Loads a scene. Note that the current scene is not cleared before. +//! \param filename: Name of the file . +bool CSceneManager::loadScene(const c8* filename, ISceneUserDataSerializer* userDataSerializer) +{ + io::IReadFile* read = FileSystem->createAndOpenFile(filename); + if (!read) + { + os::Printer::log("Unable to open scene file", filename, ELL_ERROR); + return false; + } + + bool ret = loadScene(read, userDataSerializer); + read->drop(); + + return ret; +} + + +//! Loads a scene. Note that the current scene is not cleared before. +bool CSceneManager::loadScene(io::IReadFile* file, ISceneUserDataSerializer* userDataSerializer) +{ + if (!file) + { + os::Printer::log("Unable to open scene file", ELL_ERROR); + return false; + } + + io::IXMLReader* reader = FileSystem->createXMLReader(file); + if (!reader) + { + os::Printer::log("Scene is not a valid XML file", file->getFileName(), ELL_ERROR); + return false; + } + + // for mesh loading, set collada loading attributes + + bool oldColladaSingleMesh = getParameters()->getAttributeAsBool(COLLADA_CREATE_SCENE_INSTANCES); + getParameters()->setAttribute(COLLADA_CREATE_SCENE_INSTANCES, false); + + // read file + + while(reader->read()) + { + readSceneNode(reader, 0, userDataSerializer); + } + + // restore old collada parameters + + getParameters()->setAttribute(COLLADA_CREATE_SCENE_INSTANCES, oldColladaSingleMesh); + + // finish up + + reader->drop(); + return true; + +} + + +//! reads a scene node +void CSceneManager::readSceneNode(io::IXMLReader* reader, ISceneNode* parent, ISceneUserDataSerializer* userDataSerializer) +{ + if (!reader) + return; + + scene::ISceneNode* node = 0; + + if ((!parent && IRR_XML_FORMAT_SCENE==reader->getNodeName()) || + ( parent && IRR_XML_FORMAT_NODE==reader->getNodeName())) + { + if (parent) + { + // find node type and create it + core::stringc attrName = reader->getAttributeValue(IRR_XML_FORMAT_NODE_ATTR_TYPE.c_str()); + + for (int i=(int)SceneNodeFactoryList.size()-1; i>=0 && !node; --i) + node = SceneNodeFactoryList[i]->addSceneNode(attrName.c_str(), parent); + + if (!node) + os::Printer::log("Could not create scene node of unknown type", attrName.c_str()); + } + else + node = this; // root + } + + // read attributes + while(reader->read()) + { + bool endreached = false; + + switch (reader->getNodeType()) + { + case io::EXN_ELEMENT_END: + if ((IRR_XML_FORMAT_NODE==reader->getNodeName()) || + (IRR_XML_FORMAT_SCENE==reader->getNodeName())) + { + endreached = true; + } + break; + case io::EXN_ELEMENT: + if (core::stringw(L"attributes")==reader->getNodeName()) + { + // read attributes + io::IAttributes* attr = FileSystem->createEmptyAttributes(Driver); + attr->read(reader, true); + + if (node) + node->deserializeAttributes(attr); + + attr->drop(); + } + else + if (core::stringw(L"materials")==reader->getNodeName()) + readMaterials(reader, node); + else + if (core::stringw(L"animators")==reader->getNodeName()) + readAnimators(reader, node); + else + if (core::stringw(L"userData")==reader->getNodeName()) + readUserData(reader, node, userDataSerializer); + else + if ((IRR_XML_FORMAT_NODE==reader->getNodeName()) || + (IRR_XML_FORMAT_SCENE==reader->getNodeName())) + { + readSceneNode(reader, node, userDataSerializer); + } + else + { + os::Printer::log("Found unknown element in irrlicht scene file", + core::stringc(reader->getNodeName()).c_str()); + } + break; + default: + break; + } + + if (endreached) + break; + } +} + + +//! reads materials of a node +void CSceneManager::readMaterials(io::IXMLReader* reader, ISceneNode* node) +{ + u32 nr = 0; + + while(reader->read()) + { + const wchar_t* name = reader->getNodeName(); + + switch(reader->getNodeType()) + { + case io::EXN_ELEMENT_END: + if (core::stringw(L"materials")==name) + return; + break; + case io::EXN_ELEMENT: + if (core::stringw(L"attributes")==name) + { + // read materials from attribute list + io::IAttributes* attr = FileSystem->createEmptyAttributes(Driver); + attr->read(reader); + + if (node && node->getMaterialCount() > nr) + { + getVideoDriver()->fillMaterialStructureFromAttributes( + node->getMaterial(nr), attr); + } + + attr->drop(); + ++nr; + } + break; + default: + break; + } + } +} + + +//! reads animators of a node +void CSceneManager::readAnimators(io::IXMLReader* reader, ISceneNode* node) +{ + while(reader->read()) + { + const wchar_t* name = reader->getNodeName(); + + switch(reader->getNodeType()) + { + case io::EXN_ELEMENT_END: + if (core::stringw(L"animators")==name) + return; + break; + case io::EXN_ELEMENT: + if (core::stringw(L"attributes")==name) + { + // read animator data from attribute list + io::IAttributes* attr = FileSystem->createEmptyAttributes(Driver); + attr->read(reader); + + if (node) + { + core::stringc typeName = attr->getAttributeAsString("Type"); + ISceneNodeAnimator* anim = 0; + + for (int i=0; i<(int)SceneNodeAnimatorFactoryList.size() && !anim; ++i) + anim = SceneNodeAnimatorFactoryList[i]->createSceneNodeAnimator(typeName.c_str(), node); + + if (anim) + { + anim->deserializeAttributes(attr); + anim->drop(); + } + } + + attr->drop(); + } + break; + default: + break; + } + } +} + + +//! reads user data of a node +void CSceneManager::readUserData(io::IXMLReader* reader, ISceneNode* node, ISceneUserDataSerializer* userDataSerializer) +{ + while(reader->read()) + { + const wchar_t* name = reader->getNodeName(); + + switch(reader->getNodeType()) + { + case io::EXN_ELEMENT_END: + if (core::stringw(L"userData")==name) + return; + break; + case io::EXN_ELEMENT: + if (core::stringw(L"attributes")==name) + { + // read user data from attribute list + io::IAttributes* attr = FileSystem->createEmptyAttributes(Driver); + attr->read(reader); + + if (node && userDataSerializer) + { + userDataSerializer->OnReadUserData(node, attr); + } + + attr->drop(); + } + break; + default: + break; + } + } +} + + +//! writes a scene node +void CSceneManager::writeSceneNode(io::IXMLWriter* writer, ISceneNode* node, ISceneUserDataSerializer* userDataSerializer) +{ + if (!writer || !node || node->isDebugObject()) + return; + + const wchar_t* name; + + if (node == this) + { + name = IRR_XML_FORMAT_SCENE.c_str(); + writer->writeElement(name, false); + } + else + { + name = IRR_XML_FORMAT_NODE.c_str(); + writer->writeElement(name, false, IRR_XML_FORMAT_NODE_ATTR_TYPE.c_str(), + core::stringw(getSceneNodeTypeName(node->getType())).c_str()); + } + + writer->writeLineBreak(); + writer->writeLineBreak(); + + // write properties + + io::IAttributes* attr = FileSystem->createEmptyAttributes(Driver); + node->serializeAttributes(attr); + + if (attr->getAttributeCount() != 0) + { + attr->write(writer); + writer->writeLineBreak(); + } + + // write materials + + if (node->getMaterialCount() && getVideoDriver()) + { + const wchar_t* materialElement = L"materials"; + + writer->writeElement(materialElement); + writer->writeLineBreak(); + + for (u32 i=0; i < node->getMaterialCount(); ++i) + { + io::IAttributes* tmp_attr = + getVideoDriver()->createAttributesFromMaterial(node->getMaterial(i)); + tmp_attr->write(writer); + tmp_attr->drop(); + } + + writer->writeClosingTag(materialElement); + writer->writeLineBreak(); + } + + // write animators + + if (!node->getAnimators().empty()) + { + const wchar_t* animatorElement = L"animators"; + writer->writeElement(animatorElement); + writer->writeLineBreak(); + + core::list::ConstIterator it = node->getAnimators().begin(); + for (; it != node->getAnimators().end(); ++it) + { + attr->clear(); + attr->addString("Type", getAnimatorTypeName((*it)->getType())); + + (*it)->serializeAttributes(attr); + + attr->write(writer); + } + + writer->writeClosingTag(animatorElement); + writer->writeLineBreak(); + } + + // write possible user data + + if ( userDataSerializer ) + { + io::IAttributes* userData = userDataSerializer->createUserData(node); + if (userData) + { + const wchar_t* userDataElement = L"userData"; + + writer->writeLineBreak(); + writer->writeElement(userDataElement); + writer->writeLineBreak(); + + userData->write(writer); + + writer->writeClosingTag(userDataElement); + writer->writeLineBreak(); + writer->writeLineBreak(); + + userData->drop(); + } + } + + // write children + + core::list::ConstIterator it = node->getChildren().begin(); + for (; it != node->getChildren().end(); ++it) + writeSceneNode(writer, (*it), userDataSerializer); + + attr->drop(); + + writer->writeClosingTag(name); + writer->writeLineBreak(); + writer->writeLineBreak(); +} + + +//! Returns a typename from a scene node type or null if not found +const c8* CSceneManager::getSceneNodeTypeName(ESCENE_NODE_TYPE type) +{ + const char* name = 0; + + for (int i=(int)SceneNodeFactoryList.size()-1; !name && i>=0; --i) + name = SceneNodeFactoryList[i]->getCreateableSceneNodeTypeName(type); + + return name; +} + +//! Adds a scene node to the scene by name +ISceneNode* CSceneManager::addSceneNode(const char* sceneNodeTypeName, ISceneNode* parent) +{ + ISceneNode* node = 0; + + for (int i=(int)SceneNodeFactoryList.size()-1; i>=0 && !node; --i) + node = SceneNodeFactoryList[i]->addSceneNode(sceneNodeTypeName, parent); + + return node; +} + + +//! Returns a typename from a scene node animator type or null if not found +const c8* CSceneManager::getAnimatorTypeName(ESCENE_NODE_ANIMATOR_TYPE type) const +{ + const char* name = 0; + + for (u32 i=0; !name && igetCreateableSceneNodeAnimatorTypeName(type); + + return name; +} + + +//! Writes attributes of the scene node. +void CSceneManager::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + out->addString ("Name", Name.c_str()); + out->addInt ("Id", ID ); + out->addColorf ("AmbientLight", AmbientLight); +} + +//! Reads attributes of the scene node. +void CSceneManager::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + Name = in->getAttributeAsString("Name"); + ID = in->getAttributeAsInt("Id"); + AmbientLight = in->getAttributeAsColorf("AmbientLight"); + + RelativeTranslation.set(0,0,0); + RelativeRotation.set(0,0,0); + RelativeScale.set(1,1,1); + IsVisible = true; + AutomaticCullingState = scene::EAC_BOX; + DebugDataVisible = scene::EDS_OFF; + IsDebugObject = false; + + updateAbsolutePosition(); +} + + +//! Sets ambient color of the scene +void CSceneManager::setAmbientLight(const video::SColorf &ambientColor) +{ + AmbientLight = ambientColor; +} + + +//! Returns ambient color of the scene +const video::SColorf& CSceneManager::getAmbientLight() const +{ + return AmbientLight; +} + + +//! Returns a mesh writer implementation if available +IMeshWriter* CSceneManager::createMeshWriter(EMESH_WRITER_TYPE type) +{ + switch(type) + { + case EMWT_IRR_MESH: +#ifdef _IRR_COMPILE_WITH_IRR_WRITER_ + return new CIrrMeshWriter(Driver, FileSystem); +#else + return 0; +#endif + case EMWT_COLLADA: +#ifdef _IRR_COMPILE_WITH_COLLADA_WRITER_ + return new CColladaMeshWriter(Driver, FileSystem); +#else + return 0; +#endif + case EMWT_STL: +#ifdef _IRR_COMPILE_WITH_STL_WRITER_ + return new CSTLMeshWriter(this); +#else + return 0; +#endif + } + + return 0; +} + + +// creates a scenemanager +ISceneManager* createSceneManager(video::IVideoDriver* driver, + io::IFileSystem* fs, gui::ICursorControl* cursorcontrol, + gui::IGUIEnvironment *guiEnvironment) +{ + return new CSceneManager(driver, fs, cursorcontrol, 0, guiEnvironment ); +} + + +} // end namespace scene +} // end namespace irr + diff --git a/source/Irrlicht/CSceneManager.h b/source/Irrlicht/CSceneManager.h index 3449e91d..79741072 100644 --- a/source/Irrlicht/CSceneManager.h +++ b/source/Irrlicht/CSceneManager.h @@ -50,6 +50,14 @@ namespace scene virtual gui::IGUIEnvironment* getGUIEnvironment(); + //! adds Volume Lighting Scene Node. + //! the returned pointer must not be dropped. + virtual ISceneNode* addVolumeLightSceneNode(ISceneNode* parent=0, s32 id=-1, + const s32 subdivU = 32, const s32 subdivV = 32, + const video::SColor foot = video::SColor(51, 0, 230, 180), + const video::SColor tail = video::SColor(0, 0, 0, 0), + const core::vector3df& position = core::vector3df(0,0,0), const core::vector3df& rotation = core::vector3df(0,0,0), const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)); + //! adds a cube scene node to the scene. It is a simple cube of (1,1,1) size. //! the returned pointer must not be dropped. virtual ISceneNode* addCubeSceneNode(f32 size=10.0f, ISceneNode* parent=0, s32 id=-1, diff --git a/source/Irrlicht/CVolumeLightSceneNode.cpp b/source/Irrlicht/CVolumeLightSceneNode.cpp new file mode 100644 index 00000000..2dc7a29d --- /dev/null +++ b/source/Irrlicht/CVolumeLightSceneNode.cpp @@ -0,0 +1,301 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h +// +// created by Dean Wadsworth aka Varmint Dec 31 2007 + +#include "CVolumeLightSceneNode.h" +#include "IVideoDriver.h" +#include "ISceneManager.h" +#include "S3DVertex.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CVolumeLightSceneNode::CVolumeLightSceneNode(ISceneNode* parent, ISceneManager* mgr, + s32 id, const s32 subdivU, const s32 subdivV, + const video::SColor foot, + const video::SColor tail, + const core::vector3df& position, + const core::vector3df& rotation, const core::vector3df& scale) + : ISceneNode(parent, mgr, id, position, rotation, scale) +{ + #ifdef _DEBUG + setDebugName("CVolumeLightSceneNode"); + #endif + + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + + lightDimensions = core::vector3df(1.0f, 1.2f, 1.0f); + + mlpDistance = 8.0f; + + mSubdivideU = subdivU; + mSubdivideV = subdivV; + + //test light + mfootColour = foot; + mtailColour = tail; + + Buffer = NULL; + + constructLight(); +} + + +//! destructor +CVolumeLightSceneNode::~CVolumeLightSceneNode() +{ + if (Buffer) + Buffer->drop(); +} + +void CVolumeLightSceneNode::addToBuffer(video::S3DVertex v) +{ + s32 tnidx = Buffer->Vertices.linear_reverse_search(v); + bool alreadyIn = (tnidx != -1); + u16 nidx = (u16)tnidx; + if (!alreadyIn) { + nidx = Buffer->Vertices.size(); + Buffer->Indices.push_back(nidx); + Buffer->Vertices.push_back(v); + } else + Buffer->Indices.push_back(nidx); + +} + +void CVolumeLightSceneNode::constructLight() +{ + core::vector3df lightPoint = core::vector3df(0, -(mlpDistance*lightDimensions.Y), 0); + f32 ax = lightDimensions.X / 2.0f; // X Axis + f32 az = lightDimensions.Z / 2.0f; // Z Axis + + if (Buffer) + Buffer->drop(); + Buffer = new SMeshBuffer(); + + //draw the bottom foot.. the glowing region + addToBuffer(video::S3DVertex(-ax, 0, az, 0,0,0, mfootColour, 0, 1)); + addToBuffer(video::S3DVertex(ax , 0, az, 0,0,0, mfootColour, 1, 1)); + addToBuffer(video::S3DVertex(ax , 0,-az, 0,0,0, mfootColour, 1, 0)); + + addToBuffer(video::S3DVertex(ax , 0,-az, 0,0,0, mfootColour, 1, 0)); + addToBuffer(video::S3DVertex(-ax, 0,-az, 0,0,0, mfootColour, 0, 0)); + addToBuffer(video::S3DVertex(-ax, 0, az, 0,0,0, mfootColour, 0, 1)); + + // Slices in X/U space + for(s32 i = 0; i <= mSubdivideU; i++) { + f32 k = ((f32)i) / mSubdivideU; // use for the texture coord + f32 bx = ((lightDimensions.X / (f32)mSubdivideU) * i) - ax; + //printf("bx: %f\n", bx); + + // These are the two endpoints for a slice at the foot + core::vector3df end1(bx, 0.0f, -az); + core::vector3df end2(bx, 0.0f, az); + + end1 -= lightPoint; // get a vector from point to lightsource + end1.normalize(); // normalize vector + end1 *= lightDimensions.Y; // multiply it out by shootlength + + end1.X += bx; // Add the original point location to the vector + end1.Z -= az; + + // Do it again for the other point. + end2 -= lightPoint; + end2.normalize(); + end2 *= lightDimensions.Y; + + end2.X += bx; + end2.Z += az; + + + addToBuffer(video::S3DVertex(bx , 0, az, 0,0,0, mfootColour, k, 1)); + addToBuffer(video::S3DVertex(bx , 0, -az, 0,0,0, mfootColour, k, 0)); + addToBuffer(video::S3DVertex(end2.X , end2.Y, end2.Z, 0,0,0, mtailColour, k, 1)); + + addToBuffer(video::S3DVertex(bx , 0, -az, 0,0,0, mfootColour, k, 0)); + addToBuffer(video::S3DVertex(end1.X , end1.Y, end1.Z, 0,0,0, mtailColour, k, 0)); + addToBuffer(video::S3DVertex(end2.X , end2.Y, end2.Z, 0,0,0, mtailColour, k, 1)); + + //back side + addToBuffer(video::S3DVertex(-end2.X , end2.Y, -end2.Z, 0,0,0, mtailColour, k, 1)); + addToBuffer(video::S3DVertex(-bx , 0, -az, 0,0,0, mfootColour, k, 1)); + addToBuffer(video::S3DVertex(-bx , 0, az, 0,0,0, mfootColour, k, 0)); + + addToBuffer(video::S3DVertex(-bx , 0, az, 0,0,0, mfootColour, k, 0)); + addToBuffer(video::S3DVertex(-end1.X , end1.Y, -end1.Z, 0,0,0, mtailColour, k, 0)); + addToBuffer(video::S3DVertex(-end2.X , end2.Y, -end2.Z, 0,0,0, mtailColour, k, 1)); + + } + + // Slices in Z/V space + for(s32 i = 0; i <= mSubdivideV; i++) { + f32 k = ((f32)i) / mSubdivideV; // use for the texture coord + f32 bz = ((lightDimensions.Z / (f32)mSubdivideV) * i) - az; + + // These are the two endpoints for a slice at the foot + core::vector3df end1(-ax, 0.0f, bz); + core::vector3df end2(ax, 0.0f, bz); + + end1 -= lightPoint; // get a vector from point to lightsource + end1.normalize(); // normalize vector + end1 *= lightDimensions.Y; // multiply it out by shootlength + + end1.X -= ax; // Add the original point location to the vector + end1.Z += bz; + + // Do it again for the other point. + end2 -= lightPoint; + end2.normalize(); + end2 *= lightDimensions.Y; + + end2.X += ax; + end2.Z += bz; + + addToBuffer(video::S3DVertex(-ax , 0, bz, 0,0,0, mfootColour, 0, k)); + addToBuffer(video::S3DVertex(ax , 0, bz, 0,0,0, mfootColour, 1, k)); + addToBuffer(video::S3DVertex(end2.X , end2.Y, end2.Z, 0,0,0, mtailColour, 1, k)); + + addToBuffer(video::S3DVertex(end2.X , end2.Y, end2.Z, 0,0,0, mtailColour, 1, k)); + addToBuffer(video::S3DVertex(end1.X , end1.Y, end1.Z, 0,0,0, mtailColour, 0, k)); + addToBuffer(video::S3DVertex(-ax , 0, bz, 0,0,0, mfootColour, 0, k)); + + //back side + addToBuffer(video::S3DVertex(ax , 0, -bz, 0,0,0, mfootColour, 0, k)); + addToBuffer(video::S3DVertex(-ax , 0, -bz, 0,0,0, mfootColour, 1, k)); + addToBuffer(video::S3DVertex(-end2.X , end2.Y, -end2.Z, 0,0,0, mtailColour, 1, k)); + + addToBuffer(video::S3DVertex(-end2.X , end2.Y, -end2.Z, 0,0,0, mtailColour, 1, k)); + addToBuffer(video::S3DVertex(-end1.X , end1.Y, -end1.Z, 0,0,0, mtailColour, 0, k)); + addToBuffer(video::S3DVertex(ax , 0, -bz, 0,0,0, mfootColour, 0, k)); + + } + + Buffer->BoundingBox.reset(0,0,0); + + Buffer->recalculateBoundingBox(); + + Buffer->Material.MaterialType = video::EMT_ONETEXTURE_BLEND; + Buffer->Material.MaterialTypeParam = pack_texureBlendFunc( video::EBF_SRC_COLOR, video::EBF_SRC_ALPHA, video::EMFN_MODULATE_1X ); + + Buffer->Material.Lighting = false; + Buffer->Material.ZWriteEnable = false; +} + +//! renders the node. +void CVolumeLightSceneNode::render() +{ + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); + + driver->setMaterial(Buffer->Material); + driver->drawVertexPrimitiveList( + Buffer->getVertices(), Buffer->getVertexCount(), + Buffer->getIndices(), Buffer->getIndexCount() / 3 , + Buffer->getVertexType(), EPT_TRIANGLES); +} + + +//! returns the axis aligned bounding box of this node +const core::aabbox3d& CVolumeLightSceneNode::getBoundingBox() const +{ + return Buffer->BoundingBox; +} + + +void CVolumeLightSceneNode::OnRegisterSceneNode() +{ + if (IsVisible) { + //lie to sceneManager + Buffer->Material.MaterialType = video::EMT_TRANSPARENT_ADD_COLOR; + Buffer->Material.MaterialTypeParam = 0.01f; + SceneManager->registerNodeForRendering(this, ESNRP_AUTOMATIC); + + //restore state + Buffer->Material.MaterialType = video::EMT_ONETEXTURE_BLEND; + Buffer->Material.MaterialTypeParam = pack_texureBlendFunc( video::EBF_SRC_COLOR, video::EBF_SRC_ALPHA, video::EMFN_MODULATE_1X ); + } + ISceneNode::OnRegisterSceneNode(); +} + + +//! returns the material based on the zero based index i. To get the amount +//! of materials used by this scene node, use getMaterialCount(). +//! This function is needed for inserting the node into the scene hirachy on a +//! optimal position for minimizing renderstate changes, but can also be used +//! to directly modify the material of a scene node. +video::SMaterial& CVolumeLightSceneNode::getMaterial(u32 i) +{ + return Buffer->Material; +} + + +//! returns amount of materials used by this scene node. +u32 CVolumeLightSceneNode::getMaterialCount() const +{ + return 1; +} + + +//! Writes attributes of the scene node. +void CVolumeLightSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + ISceneNode::serializeAttributes(out, options); + + out->addFloat("lpDistance", mlpDistance); + out->addInt("subDivideU", mSubdivideU); + out->addInt("subDivideV", mSubdivideV); + + out->addColor("footColour", mfootColour); + out->addColor("tailColour", mtailColour); + + out->addVector3d("lightDimension", lightDimensions); +} + + +//! Reads attributes of the scene node. +void CVolumeLightSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + mlpDistance = in->getAttributeAsFloat("lpDistance"); + mlpDistance = core::max_(mlpDistance, 8.0f); + + mSubdivideU = in->getAttributeAsInt("subDivideU"); + mSubdivideU = core::max_(mSubdivideU, 1); + + mSubdivideV = in->getAttributeAsInt("subDivideV"); + mSubdivideV = core::max_(mSubdivideV, 1); + + mfootColour = in->getAttributeAsColor("footColour"); + mtailColour = in->getAttributeAsColor("tailColour"); + + lightDimensions = in->getAttributeAsVector3d("lightDimension"); + + constructLight(); + + ISceneNode::deserializeAttributes(in, options); +} + + +//! Creates a clone of this scene node and its children. +ISceneNode* CVolumeLightSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager) +{ + if (!newParent) newParent = Parent; + if (!newManager) newManager = SceneManager; + + CVolumeLightSceneNode* nb = new CVolumeLightSceneNode(newParent, + newManager, ID, mSubdivideU, mSubdivideV, mfootColour, mtailColour, RelativeTranslation); + + nb->cloneMembers(this, newManager); + nb->Buffer->Material = Buffer->Material; + + nb->drop(); + return nb; +} + + +} // end namespace scene +} // end namespace irr diff --git a/source/Irrlicht/CVolumeLightSceneNode.h b/source/Irrlicht/CVolumeLightSceneNode.h new file mode 100644 index 00000000..e8da5d0b --- /dev/null +++ b/source/Irrlicht/CVolumeLightSceneNode.h @@ -0,0 +1,98 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h +// +// created by Dean Wadsworth aka Varmint Dec 31 2007 + +#ifndef __VOLUME_LIGHT_SCENE_NODE_H_INCLUDED__ +#define __VOLUME_LIGHT_SCENE_NODE_H_INCLUDED__ + +#include "ISceneNode.h" +#include "SMeshBuffer.h" + +namespace irr +{ +namespace scene +{ + class CVolumeLightSceneNode : public ISceneNode + { + public: + + //! constructor + CVolumeLightSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, + const s32 subdivU = 32, const s32 subdivV = 32, + const video::SColor foot = video::SColor(51, 0, 230, 180), + const video::SColor tail = video::SColor(0, 0, 0, 0), + const core::vector3df& position = core::vector3df(0,0,0), + const core::vector3df& rotation = core::vector3df(0,0,0), + const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)); + + //! destructor + virtual ~CVolumeLightSceneNode(); + + virtual void OnRegisterSceneNode(); + + //! renders the node. + virtual void render(); + + //! returns the axis aligned bounding box of this node + virtual const core::aabbox3d& getBoundingBox() const; + + //! returns the material based on the zero based index i. To get the amount + //! of materials used by this scene node, use getMaterialCount(). + //! This function is needed for inserting the node into the scene hirachy on a + //! optimal position for minimizing renderstate changes, but can also be used + //! to directly modify the material of a scene node. + virtual video::SMaterial& getMaterial(u32 i); + + //! returns amount of materials used by this scene node. + virtual u32 getMaterialCount() const; + + //! Returns type of the scene node + virtual ESCENE_NODE_TYPE getType() const { return ESNT_CUBE; } + + //! Writes attributes of the scene node. + virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const; + + //! Reads attributes of the scene node. + virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0); + + //! Creates a clone of this scene node and its children. + virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0); + + void setSubDivideU (const s32 inU) { mSubdivideU = inU; } + void setSubDivideV (const s32 inV) { mSubdivideV = inV; } + + s32 getSubDivideU () const { return mSubdivideU; } + s32 getSubDivideV () const { return mSubdivideV; } + + void setFootColour(const video::SColor inColouf) { mfootColour = inColouf; } + void setTailColour(const video::SColor inColouf) { mtailColour = inColouf; } + + video::SColor getFootColour () const { return mfootColour; } + video::SColor getTailColour () const { return mtailColour; } + + private: + void addToBuffer(video::S3DVertex v); + void constructLight(); + + SMeshBuffer * Buffer; + + f32 mlpDistance; // Distance to hypothetical lightsource point -- affects fov angle + + s32 mSubdivideU; // Number of subdivisions in U and V space. + s32 mSubdivideV; // Controls the number of "slices" in the volume. + // NOTE : Total number of polygons = 2 + ((mSubdiveU + 1) + (mSubdivideV + 1)) * 2 + // Each slice being a quad plus the rectangular plane at the bottom. + + video::SColor mfootColour; // Color at the source + video::SColor mtailColour; // Color at the end. + + core::vector3df lightDimensions; // lightDimensions.Y Distance of shooting -- Length of beams + // lightDimensions.X and lightDimensions.Z determine the size/dimension of the plane + }; + +} // end namespace scene +} // end namespace irr + +#endif diff --git a/source/Irrlicht/MacOSX/MacOSX.xcodeproj/project.pbxproj b/source/Irrlicht/MacOSX/MacOSX.xcodeproj/project.pbxproj index 545b3eb0..a319dcb3 100644 --- a/source/Irrlicht/MacOSX/MacOSX.xcodeproj/project.pbxproj +++ b/source/Irrlicht/MacOSX/MacOSX.xcodeproj/project.pbxproj @@ -36,6 +36,8 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 090FBC820D31085E0076D847 /* CVolumeLightSceneNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 090FBC800D31085E0076D847 /* CVolumeLightSceneNode.cpp */; }; + 090FBC830D31085E0076D847 /* CVolumeLightSceneNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 090FBC810D31085E0076D847 /* CVolumeLightSceneNode.h */; }; 0910B9DE0D1F5D4100D46B04 /* CBurningShader_Raster_Reference.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0910B9D90D1F5D4100D46B04 /* CBurningShader_Raster_Reference.cpp */; }; 0910B9DF0D1F5D4100D46B04 /* CGUITable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0910B9DA0D1F5D4100D46B04 /* CGUITable.cpp */; }; 0910B9E00D1F5D4100D46B04 /* CGUITable.h in Headers */ = {isa = PBXBuildFile; fileRef = 0910B9DB0D1F5D4100D46B04 /* CGUITable.h */; }; @@ -721,6 +723,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 090FBC800D31085E0076D847 /* CVolumeLightSceneNode.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CVolumeLightSceneNode.cpp; sourceTree = ""; }; + 090FBC810D31085E0076D847 /* CVolumeLightSceneNode.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CVolumeLightSceneNode.h; sourceTree = ""; }; 0910B9D90D1F5D4100D46B04 /* CBurningShader_Raster_Reference.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CBurningShader_Raster_Reference.cpp; sourceTree = ""; }; 0910B9DA0D1F5D4100D46B04 /* CGUITable.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CGUITable.cpp; sourceTree = ""; }; 0910B9DB0D1F5D4100D46B04 /* CGUITable.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CGUITable.h; sourceTree = ""; }; @@ -1155,7 +1159,7 @@ 4C53E18D0A484C2C0014E966 /* uncompr.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = uncompr.c; sourceTree = ""; }; 4C53E1920A484C2C0014E966 /* zutil.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = zutil.c; sourceTree = ""; }; 4C53E24D0A4850120014E966 /* libIrrlicht.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libIrrlicht.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 4C53E2520A4850550014E966 /* Quake3Map_dbg.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Quake3Map_dbg.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 4C53E2520A4850550014E966 /* Quake3Map.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Quake3Map.app; sourceTree = BUILT_PRODUCTS_DIR; }; 4C53E26D0A4850D60014E966 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 4C53E26E0A4850D60014E966 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = ""; }; 4C53E38E0A4855BA0014E966 /* DemoApp-Info.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xml; path = "DemoApp-Info.plist"; sourceTree = ""; }; @@ -1219,18 +1223,18 @@ 4C53E76F0A485CD90014E966 /* wrrle.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = wrrle.c; sourceTree = ""; }; 4C53E7700A485CD90014E966 /* wrtarga.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = wrtarga.c; sourceTree = ""; }; 4C6DC9B60A48715A0017A6E5 /* inflate.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = inflate.c; sourceTree = ""; }; - 4CA25B980A485D9800B4E469 /* CustomSceneNode_dbg.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CustomSceneNode_dbg.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 4CA25B9A0A485D9800B4E469 /* MeshViewer_dbg.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MeshViewer_dbg.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 4CA25B9C0A485D9800B4E469 /* RenderToTexture_dbg.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RenderToTexture_dbg.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 4CA25B9E0A485D9800B4E469 /* UserInterface_dbg.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = UserInterface_dbg.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 4CA25BA00A485D9800B4E469 /* PerPixelLighting_dbg.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = PerPixelLighting_dbg.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 4CA25BA20A485D9800B4E469 /* Demo_dbg.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demo_dbg.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 4CA25BA40A485D9800B4E469 /* Movement_dbg.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Movement_dbg.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 4CA25BA60A485D9800B4E469 /* Shaders_dbg.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = Shaders_dbg.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 4CA25BA80A485D9800B4E469 /* SpecialFx_dbg.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SpecialFx_dbg.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 4CA25BAA0A485D9800B4E469 /* TerrainRendering_dbg.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TerrainRendering_dbg.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 4CA25BAC0A485D9800B4E469 /* 2DGraphics_dbg.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 2DGraphics_dbg.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 4CA25BAE0A485D9800B4E469 /* Collision_dbg.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Collision_dbg.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 4CA25B980A485D9800B4E469 /* CustomSceneNode.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CustomSceneNode.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 4CA25B9A0A485D9800B4E469 /* MeshViewer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MeshViewer.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 4CA25B9C0A485D9800B4E469 /* RenderToTexture.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RenderToTexture.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 4CA25B9E0A485D9800B4E469 /* UserInterface.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = UserInterface.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 4CA25BA00A485D9800B4E469 /* PerPixelLighting.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PerPixelLighting.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 4CA25BA20A485D9800B4E469 /* Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demo.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 4CA25BA40A485D9800B4E469 /* Movement.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Movement.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 4CA25BA60A485D9800B4E469 /* Shaders.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Shaders.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 4CA25BA80A485D9800B4E469 /* SpecialFx.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SpecialFx.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 4CA25BAA0A485D9800B4E469 /* TerrainRendering.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TerrainRendering.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 4CA25BAC0A485D9800B4E469 /* 2DGraphics.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 2DGraphics.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 4CA25BAE0A485D9800B4E469 /* Collision.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Collision.app; sourceTree = BUILT_PRODUCTS_DIR; }; 4CC36B0D0A6B61DB0076C4B2 /* CSphereSceneNode.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CSphereSceneNode.cpp; sourceTree = ""; }; 4CC36B0E0A6B61DB0076C4B2 /* CSphereSceneNode.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CSphereSceneNode.h; sourceTree = ""; }; 4CFA7BDC0A88735900B03626 /* CImageLoaderBMP.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 2; path = CImageLoaderBMP.cpp; sourceTree = ""; }; @@ -2042,6 +2046,8 @@ 4C53DFCB0A484C240014E966 /* CTerrainSceneNode.h */, 4C53DFCE0A484C240014E966 /* CTextSceneNode.cpp */, 4C53DFCF0A484C240014E966 /* CTextSceneNode.h */, + 090FBC800D31085E0076D847 /* CVolumeLightSceneNode.cpp */, + 090FBC810D31085E0076D847 /* CVolumeLightSceneNode.h */, 4C53DFF00A484C250014E966 /* CWaterSurfaceSceneNode.cpp */, 4C53DFF10A484C250014E966 /* CWaterSurfaceSceneNode.h */, ); @@ -2588,19 +2594,19 @@ isa = PBXGroup; children = ( 4C53E24D0A4850120014E966 /* libIrrlicht.a */, - 4C53E2520A4850550014E966 /* Quake3Map_dbg.app */, - 4CA25B980A485D9800B4E469 /* CustomSceneNode_dbg.app */, - 4CA25BA40A485D9800B4E469 /* Movement_dbg.app */, - 4CA25B9E0A485D9800B4E469 /* UserInterface_dbg.app */, - 4CA25BAC0A485D9800B4E469 /* 2DGraphics_dbg.app */, - 4CA25BAE0A485D9800B4E469 /* Collision_dbg.app */, - 4CA25BA80A485D9800B4E469 /* SpecialFx_dbg.app */, - 4CA25B9A0A485D9800B4E469 /* MeshViewer_dbg.app */, - 4CA25BA60A485D9800B4E469 /* Shaders_dbg.app */, - 4CA25BA00A485D9800B4E469 /* PerPixelLighting_dbg.app */, - 4CA25B9C0A485D9800B4E469 /* RenderToTexture_dbg.app */, - 4CA25BAA0A485D9800B4E469 /* TerrainRendering_dbg.app */, - 4CA25BA20A485D9800B4E469 /* Demo_dbg.app */, + 4C53E2520A4850550014E966 /* Quake3Map.app */, + 4CA25B980A485D9800B4E469 /* CustomSceneNode.app */, + 4CA25BA40A485D9800B4E469 /* Movement.app */, + 4CA25B9E0A485D9800B4E469 /* UserInterface.app */, + 4CA25BAC0A485D9800B4E469 /* 2DGraphics.app */, + 4CA25BAE0A485D9800B4E469 /* Collision.app */, + 4CA25BA80A485D9800B4E469 /* SpecialFx.app */, + 4CA25B9A0A485D9800B4E469 /* MeshViewer.app */, + 4CA25BA60A485D9800B4E469 /* Shaders.app */, + 4CA25BA00A485D9800B4E469 /* PerPixelLighting.app */, + 4CA25B9C0A485D9800B4E469 /* RenderToTexture.app */, + 4CA25BAA0A485D9800B4E469 /* TerrainRendering.app */, + 4CA25BA20A485D9800B4E469 /* Demo.app */, 09F6493E0D2CE03E001E0599 /* LoadIrrFile.app */, 09F649650D2CE206001E0599 /* Quake3Shader.app */, 09F649030D2CDED9001E0599 /* HelloWorld.app */, @@ -2753,6 +2759,7 @@ 0910BA480D1F64B300D46B04 /* SSharedMeshBuffer.h in Headers */, 0910BA490D1F64B300D46B04 /* SSkinMeshBuffer.h in Headers */, 0910BA4A0D1F64B300D46B04 /* SViewFrustum.h in Headers */, + 090FBC830D31085E0076D847 /* CVolumeLightSceneNode.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2828,7 +2835,7 @@ ); name = 2DGraphics; productName = DemoApp; - productReference = 4CA25BAC0A485D9800B4E469 /* 2DGraphics_dbg.app */; + productReference = 4CA25BAC0A485D9800B4E469 /* 2DGraphics.app */; productType = "com.apple.product-type.application"; }; B81CFE82097FDDE20057C06F /* Collision */ = { @@ -2846,7 +2853,7 @@ ); name = Collision; productName = DemoApp; - productReference = 4CA25BAE0A485D9800B4E469 /* Collision_dbg.app */; + productReference = 4CA25BAE0A485D9800B4E469 /* Collision.app */; productType = "com.apple.product-type.application"; }; B81CFEA4097FDE900057C06F /* PerPixelLightning */ = { @@ -2864,7 +2871,7 @@ ); name = PerPixelLightning; productName = DemoApp; - productReference = 4CA25BA00A485D9800B4E469 /* PerPixelLighting_dbg.app */; + productReference = 4CA25BA00A485D9800B4E469 /* PerPixelLighting.app */; productType = "com.apple.product-type.application"; }; B81CFEC2097FDF020057C06F /* TerrainRendering */ = { @@ -2882,7 +2889,7 @@ ); name = TerrainRendering; productName = DemoApp; - productReference = 4CA25BAA0A485D9800B4E469 /* TerrainRendering_dbg.app */; + productReference = 4CA25BAA0A485D9800B4E469 /* TerrainRendering.app */; productType = "com.apple.product-type.application"; }; B81CFEE8097FE05F0057C06F /* SpecialFx */ = { @@ -2900,7 +2907,7 @@ ); name = SpecialFx; productName = DemoApp; - productReference = 4CA25BA80A485D9800B4E469 /* SpecialFx_dbg.app */; + productReference = 4CA25BA80A485D9800B4E469 /* SpecialFx.app */; productType = "com.apple.product-type.application"; }; B81CFF07097FE13E0057C06F /* UserInterface */ = { @@ -2918,7 +2925,7 @@ ); name = UserInterface; productName = DemoApp; - productReference = 4CA25B9E0A485D9800B4E469 /* UserInterface_dbg.app */; + productReference = 4CA25B9E0A485D9800B4E469 /* UserInterface.app */; productType = "com.apple.product-type.application"; }; B81CFF1E097FE1E00057C06F /* CustomSceneNode */ = { @@ -2936,7 +2943,7 @@ ); name = CustomSceneNode; productName = DemoApp; - productReference = 4CA25B980A485D9800B4E469 /* CustomSceneNode_dbg.app */; + productReference = 4CA25B980A485D9800B4E469 /* CustomSceneNode.app */; productType = "com.apple.product-type.application"; }; B81CFF33097FE25F0057C06F /* Quake3Map */ = { @@ -2954,7 +2961,7 @@ ); name = Quake3Map; productName = DemoApp; - productReference = 4C53E2520A4850550014E966 /* Quake3Map_dbg.app */; + productReference = 4C53E2520A4850550014E966 /* Quake3Map.app */; productType = "com.apple.product-type.application"; }; B81CFF4A097FE3050057C06F /* Shaders */ = { @@ -2972,7 +2979,7 @@ ); name = Shaders; productName = DemoApp; - productReference = 4CA25BA60A485D9800B4E469 /* Shaders_dbg.app */; + productReference = 4CA25BA60A485D9800B4E469 /* Shaders.app */; productType = "com.apple.product-type.application"; }; B81CFF78097FE3DC0057C06F /* Movement */ = { @@ -2990,7 +2997,7 @@ ); name = Movement; productName = DemoApp; - productReference = 4CA25BA40A485D9800B4E469 /* Movement_dbg.app */; + productReference = 4CA25BA40A485D9800B4E469 /* Movement.app */; productType = "com.apple.product-type.application"; }; B81CFF91097FE45E0057C06F /* MeshViewer */ = { @@ -3008,7 +3015,7 @@ ); name = MeshViewer; productName = DemoApp; - productReference = 4CA25B9A0A485D9800B4E469 /* MeshViewer_dbg.app */; + productReference = 4CA25B9A0A485D9800B4E469 /* MeshViewer.app */; productType = "com.apple.product-type.application"; }; B81CFFAF097FE5F80057C06F /* RenderToTexture */ = { @@ -3026,7 +3033,7 @@ ); name = RenderToTexture; productName = DemoApp; - productReference = 4CA25B9C0A485D9800B4E469 /* RenderToTexture_dbg.app */; + productReference = 4CA25B9C0A485D9800B4E469 /* RenderToTexture.app */; productType = "com.apple.product-type.application"; }; B8DEF35C0950229200FDEA7E /* Demo */ = { @@ -3044,7 +3051,7 @@ ); name = Demo; productName = DemoApp; - productReference = 4CA25BA20A485D9800B4E469 /* Demo_dbg.app */; + productReference = 4CA25BA20A485D9800B4E469 /* Demo.app */; productType = "com.apple.product-type.application"; }; D2AAC07D0554694100DB518D /* libIrrlicht.a */ = { @@ -3663,6 +3670,7 @@ 0910B9DE0D1F5D4100D46B04 /* CBurningShader_Raster_Reference.cpp in Sources */, 0910B9DF0D1F5D4100D46B04 /* CGUITable.cpp in Sources */, 0910B9E10D1F5D4100D46B04 /* CImageLoaderWAL.cpp in Sources */, + 090FBC820D31085E0076D847 /* CVolumeLightSceneNode.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; };