diff --git a/changes.txt b/changes.txt index be43b0ba..6ee71071 100644 --- a/changes.txt +++ b/changes.txt @@ -9,6 +9,26 @@ Changes in ogl-es (not yet released - will be merged with trunk at some point) -------------------------- Changes in 1.9 (not yet released) +- Add equals and set_data functions to core::array for easier working with blocks of data. +- SIrrlichtCreationParameters::IgnoreInput set to false works again on X11. + Thanks @ Victor Gaydov for report + patch + very good test cases! (bug #401) + This had been broken since Irrlicht 1.6 +- Add steer parameter to CSceneNodeAnimatorFollowSpline which allows rotating node toward direction of movement. + Thanks @ Bate for the patch (patch #175) +- Add a workaround for XWarpPointer bug that causes mouse to jump when users have set a Coordinate Transformation Matrix for their mouse on X11. + This was mentioned in bug #450 by vikaig. + The fix needs compiling with _IRR_LINUX_X11_XINPUT2_ enabled (so far disabled by default) +- Add IGeometryCreator::createTorusMesh to create donuts. +- Don't try loading broken image files twice with same loader anymore. +- Make CImageLoaderJPG thread safe. Thanks @ Edoardo Lolletti for report and patch (patch #324) +- Add ETCF_SUPPORT_VERTEXT_TEXTURE flag which can be used to enable vertex texture sampling support in Direct3D 9. + Note that this was enabled for a long time in 1.9 svn, but is now disabled by default. +- CGUIListBox now serializes the state of "Selected". Feature wish by chronologicaldot (http://irrlicht.sourceforge.net/forum/viewtopic.php?f=2&t=52719) +- Bugfix: Changing focus with tab-keys now also work when elements are inside a modal screen. +- COBJMeshFileLoader using a bit more exact color conversion for 0-1 to 0-255 range (same now as SColorf::toSColor uses). +- Speedup for COBJMeshWriter +- Add blinkMode parameter to IGUIEnvironment::addModalScreen, so blinking can be suppressed +- Speedup: Avoid string copy in CXMLReaderImpl::getAttributeByName - Fix bug in rect::clipAgainst that had caused rects completely outside to the left-top of the rect to be clipped against ending up with both corners outside. It still worked for UI in most cases as the resulting rectangle still had an area of 0. - Add getAlign functions to IGUIElement @@ -84,7 +104,7 @@ Changes in 1.9 (not yet released) - Drivers can now try to create textures from images in more exotic color formats (like floating point formats). It depends on the driver how much that works (so far mainly OpenGL can handle it somewhat). - Fix OpenGL to no longer switch colors red and blue in 24-bit RGB format. But warnings added to documentation to avoid 24-bit textures as they are generally just trouble. - No longer try to convert ECF_R5G6B5 to ECF_A1R5G5B5 on OpenGL (just made texture-loading seem to fail). -- Add flag SIrrlichtCreationParameters.WindowResizable. Mainly to work around troubles with SDL+OpenGL on some platforms where resizing later can be tricky/impossible. +- Add parameter SIrrlichtCreationParameters.WindowResizable. Mainly to work around troubles with SDL+OpenGL on some platforms where resizing later can be tricky/impossible. - Add operator[] to vector2d and vector3d - Bugfix: IrrlichtDevice::isWindowMinimized no longer returns true when it's maximized on Windows. - Ignore degenerated faces in obj file loader when they would generate triangles where 2 vertices use identical indices. @@ -318,6 +338,7 @@ Changes in 1.9 (not yet released) -------------------------- Changes in 1.8.5 + - Update script to generate tutorial.html's in example folders. Add missing ones. Update existing ones. Thanks @Guillian J for noticing those were outdated. - Update libpng to 1.6.37 (from 1.6.23) - Fix CIrrDeviceSDL::getVideoModeList which didn't return video modes before. Thx @kas1e for report and patch. - CIrrDeviceMacOSX now sets the SEvent.MouseInput Shift and Control values on mouse events like the other devices. Thanks @ Zero King for patch (#321) diff --git a/doc/release_checklist.txt b/doc/release_checklist.txt index 840e7728..42eae88a 100644 --- a/doc/release_checklist.txt +++ b/doc/release_checklist.txt @@ -1,12 +1,12 @@ -Checklist for Irrlicht developers for doing releases. +Checklist for Irrlicht developers doing releases. + +Note: Generally the more platforms, compilers, settings you can test the better. Ask for help for platforms which you don't own. - PRE-BUILD TESTS: - - Run tests in the tests folder -- - Compile and run all examples for testing (preferably on all platforms, -compilers, settings ... until you are certain enough stuff works sufficiently). -Ask for help for platforms which you don't own. -- - Compile the tools on all platforms you have. Note that some tools are in the buildall-examples VS project files on Windows, but on Linux -command line you have to compile them individually. +- - Compile and run examples. +- - Compile and run the tools. Note that some tools are in the buildall-examples VS project files on Windows, + but on Linux command line you have to compile them individually. - VERSION UPDATES: - - check IRRLICHT_SDK_VERSION (in IrrCompileConfig.h) @@ -15,13 +15,16 @@ command line you have to compile them individually. - - Add new release information (date+version-number) in changes.txt - - go through folders if other .txt files still make sense (things change and updating those files tends to be forgotten) +- DOCUMENTATION UPDATES: +- - run makedocumentation.sh in scripts\doc\irrlicht +- - run maketutorial.sh in scripts\doc\irrlicht (commit changed tutorial.html's) + - BUILDING THE RELEASE + (TBD - should we still release dll's? Newer and older VS builds are no longer compatible anyway) - - run a clean build for buildAllExamples in the examples folder with the -target compiler for 32-bit and for release (preferably oldest supported VS -compiler, otherwise oldest you have still installed) + target compiler for 32-bit and for release (old VS compiler - so far VS2010) - - when possible compile the dll for MinGW on Windows (in release and with -s for smaller size) - - when possible compile the dll for 64 bit (again with Visual Studio and release) -- - run makedocumentation in scripts\doc\irrlicht - - create a target directory, like irrlicht-1.8.1 for example - - svn export to the target directory - - copy the subfolders of doctemp into the doc folder of the target directory diff --git a/examples/01.HelloWorld/tutorial.html b/examples/01.HelloWorld/tutorial.html index e46c9542..916e554e 100644 --- a/examples/01.HelloWorld/tutorial.html +++ b/examples/01.HelloWorld/tutorial.html @@ -1,394 +1,231 @@ - -
-Tutorial 1.HelloWorld | - -
- This Tutorial shows how to set up the IDE for using the
- Irrlicht Engine and how to write a simple HelloWorld program
- with it. The program will show how to use the basics of
- the VideoDriver, the GUIEnvironment and the SceneManager.
|
-
-
Lets start! | -|||||||||||||||
-
-
-
-
-
-
- After we have set up the IDE, the compiler will know - where to find the Irrlicht Engine header files so - we can include it now into our code. -
In the Irrlicht Engine, everything can be found in - the namespace 'irr'. So if you want to use a class - of the engine, you'll have to type an irr:: before - the name of the class. For example, to use the IrrlichtDevice, - write: irr::IrrlichtDevice. To avoid having to put - irr:: before of the name of every class, we tell the - compiler that we use that namespace. -
There are 5 sub-namespaces in the Irrlicht Engine. - Take a look at them: you can read a detailed description - of them in the documentation by clicking on the top - menu item 'Namespace - List'. To keep this example simple, we don't want - to have to specify the name spaces, Hence: -
To be able to use the Irrlicht.DLL file, we need - to link with the Irrlicht.lib. We could set this option - in the project settings, but to make it easy we use - a pragma comment: -
Now the main method: to keep this example simple - we use int main(), which can be used on any platform. - However, on Windows platforms, we could also use the - WinMain method if we would want to get rid of the - console window which pops up when starting a program - with main(). -
The most important function of the engine is the - 'createDevice' function. The Irrlicht Device, which - is the root object for doing everything with the engine, - can be created with it. createDevice() has 7 parameters: -
Now we set the caption of the window to some nice text. - Note that there is a 'L' in front of the string: the - Irrlicht Engine uses wide character strings when displaying - text. -
Now we store a pointer to the video driver, the SceneManager, - and the graphical user interface environment so that - we do not always have to write device->getVideoDriver(), - device->getSceneManager(), and device->getGUIEnvironment(). -
We add a hello world label to the window using the - GUI environment. The text is placed at the position - (10,10) as top left corner and (200,22) as lower right - corner. -
To display something interesting, we load a Quake 2
- model and display it. We only have to get the Mesh from
- the Scene Manager with getMesh() and add a SceneNode
- to display the mesh with addAnimatedMeshSceneNode().
- Instead of loading a Quake2 file (.md2), it is also
- possible to load a Maya object file (.obj), a complete
- Quake3 map (.bsp), or a Milshape file (.ms3d).
To make the mesh look a little bit nicer, we change - its material a little bit: we disable lighting because - we do not have a dynamic light in here and the mesh - would be totally black. Then we set the frame loop so - that the animation is looped between the frames 0 and - 310. Then, at last, we apply a texture to the mesh. - Without it the mesh would be drawn using only a solid - color. -
To look at the mesh, we place a camera into 3d space - at the position (0, 10, -40). The camera looks from - there to (0,5,0). -
Ok. Now that we have set up the scene, let's draw everything: - we run the device in a while() loop until the device - does not want to run any more. This would be when the - user closes the window or presses ALT+F4 in Windows. -
Everything must be drawn between a beginScene() and - an endScene() call. The beginScene clears the screen - with a color and also the depth buffer, if desired. - Then we let the Scene Manager and the GUI environment - draw their content. With the endScene() call, everything - is presented on the screen. -
After we are finished, we have to delete the Irrlicht - Device created earlier with createDevice(). With the - Irrlicht Engine, you should delete all objects you created - with a method or function that starts with 'create'. - The object is deleted simply by calling ->drop(). - See the documentation - for more information. -
That's it. Compile and run. -- |
-
Possible Errors - or Problems | -|||||
-
-
-
-
- Visual Studio
Solution: You may have set the include directory improperly - in the Visual Studio options. See above - for information on setting it. - -
Solution: You may have set the library directory improperly.
- See above for information on
- setting it. Compiler independent problems
Solution: You may have forgotten to copy the Irrlicht.dll - file from Irrlicht\bin\VisualStudio to the directory - the tutorial's project file is in. - If the tutorial compiles and runs successfully but produces - errors in the console like:- -
Or: -
Solution: The file listed in the error message cannot
- be found. Ensure that the directory specified in the
- main.cpp exists and is where the file is located. |
-
- - + + + + + + + +
This tutorial shows how to set up the IDE for using the Irrlicht Engine and how to write a simple HelloWorld program with it. The program will show how to use the basics of the VideoDriver, the GUIEnvironment, and the SceneManager. Microsoft Visual Studio is used as an IDE, but you will also be able to understand everything if you are using a different one or even another operating system than Windows.
+You have to include the header file <irrlicht.h> in order to use the engine. The header file can be found in the Irrlicht Engine SDK directory include
. To let the compiler find this header file, the directory where it is located has to be added in your project as include path. This is different for every IDE and compiler you use. Let's explain shortly how to do this in Visual Studio 2010:
include
directory of the Irrlicht engine folder to the list of directories. Now the compiler will find the irrlicht.h header file. We also need the irrlicht.lib to be found, so select "Linker" - "General" and add the lib/Win64-visualStudio
or lib/Win32-visualStudio
directory to "Additional Library Directories". Which of the 2 Irrlicht versions you chose depends on the target platform for your application (win32 or x64). In your project properties you can see what your active solution platform is, you can use the same one for Irrlicht.To be able to use the Irrlicht.DLL file, we need to link with the Irrlicht.lib. In most IDE's you have to add irrlicht.lib (or irrlicht.a or irrlicht.so on Linux) to your Linker input files.
+For VisualStudio we can be lazy and use the pragma comment lib. We also want to get rid of the console window, which pops up when starting a program with main() (instead of WinMain). This is done by the second pragma. We could also use the WinMain method, though losing platform independence then.
That's it. With your IDE set up like this, you will now be able to develop applications with the Irrlicht Engine.
+Lets start!
+After we have set up the IDE, the compiler will know where to find the Irrlicht Engine header files so we can include it now in our code.
That header just adds the getExampleMediaPath tool-functions to help locating the media we need. More about that later below.
In the Irrlicht Engine, everything can be found in the namespace 'irr'. So if you want to use a class of the engine, you have to write irr:: before the name of the class. For example to use the IrrlichtDevice write: irr::IrrlichtDevice. To get rid of the irr:: in front of the name of every class, we tell the compiler that we use that namespace from now on, and we will not have to write irr:: anymore. Note that you never should do that in headers - otherwise you will pollute the namespace of every file including such a header. So in headers always write out the full names including all namespaces.
There are 5 sub namespaces in the Irrlicht Engine. Take a look at them, you can read a detailed description of them in the documentation by clicking on the top menu item 'Namespace List' or by using this link: http://irrlicht.sourceforge.net/docu/namespaces.html Like the irr namespace, we do not want these 5 sub namespaces now, to keep this example simple. Hence, we tell the compiler again that we do not want always to write their names.
This is the main method. We can now use main() on every platform.
The most important function of the engine is the createDevice() function. The IrrlichtDevice is created by it, which is the root object for doing anything with the engine. createDevice() has the following parameters:
+Always check the return value to cope with unsupported drivers, dimensions, etc.
Set the caption of the window to some nice text. Note that there is an 'L' in front of the string. The Irrlicht Engine uses wide character strings when displaying text.
Get a pointer to the VideoDriver, the SceneManager and the graphical user interface environment, so that we do not always have to write device->getVideoDriver(), device->getSceneManager(), or device->getGUIEnvironment().
We add a hello world label to the window, using the GUI environment. The text is placed at the position (10,10) as top left corner and (260,22) as lower right corner.
Get a media path dedicated for your platform. Finding media files for your applications can be tricky. First you have 2 options - working with relative paths or working with absolute paths.
+On Windows a common solution is that your installer will write a key into the registry with the absolute path of wherever the user installed the media. And in your application you read out that key from the registry. On Linux a common solution is to use config file which is placed in some fixed location (for example in a . file/folder in the user home).
+But you can also work with relative paths - which is what we do here. There is a slight complication with relative paths as they are relative to your current working directory. And that depends on the way your application is started and it might change inside your application. But mostly it will be set to your executable on start so you can ignore that problem while developing.
+When inside VisualStudio the current working directory is set to your project files location unless you overwrite Project properties - Debugging
Whatever you chose to find your base-folder for media - wrap it with some function and then you can improve the code to locate the media later on.
To show something interesting, we load a Quake 2 model and display it. We get the Mesh from the Scene Manager with getMesh() and add a SceneNode to display the mesh with addAnimatedMeshSceneNode(). Check the return value of getMesh() to become aware of loading problems and other errors.
+Instead of writing the filename sydney.md2, it would also be possible to load a Maya object file (.obj), a complete Quake3 map (.bsp) or any other supported file format. By the way, that cool Quake 2 model called sydney was modeled by Brian Collins.
To let the mesh look a little bit nicer, we change its material. We disable lighting because we do not have a dynamic light in here, and the mesh would be totally black otherwise. Then we set the frame loop, such that the predefined STAND animation is used. And last, we apply a texture to the mesh. Without it the mesh would be drawn using only a color.
To look at the mesh, we place a camera into 3d space at the position (0, 30, -40). The camera looks from there to (0,5,0), which is approximately the place where our md2 model is.
OK, now we have set up the scene, lets draw everything: We run the device in a while() loop, until the device does not want to run any more. This would be when the user closes the window or presses ALT+F4 (or whatever keycode closes a window on your OS).
Anything can be drawn between a beginScene() and an endScene() call. The beginScene() call clears the screen with a color and the depth buffer, if desired. Then we let the Scene Manager and the GUI Environment draw their content. With the endScene() call everything is presented on the screen.
After we are done with the render loop, we have to delete the Irrlicht Device created before with createDevice(). In the Irrlicht Engine, you have to delete all objects you created with a method or function which starts with 'create'. The object is simply deleted by calling ->drop(). See the documentation at irr::IReferenceCounted::drop() for more information.
That's it. Compile and run.
++ + diff --git a/examples/02.Quake3Map/tutorial.html b/examples/02.Quake3Map/tutorial.html index 1858b866..ddc6a5bf 100644 --- a/examples/02.Quake3Map/tutorial.html +++ b/examples/02.Quake3Map/tutorial.html @@ -1,181 +1,208 @@ - - -
- Lets start! |
- |||||||||||||
-
- Lets start like the HelloWorld example: We include the irrlicht header
- files and an additional file to be able
As already written in the HelloWorld example, in the Irrlicht Engine,
- everything can be found in the namespace 'irr'. To get rid of the irr::
- in front of the name of every class, we tell the compiler that we use
- that namespace from now on, and we will not have to write that 'irr::'.
Again, to be able to use the Irrlicht.DLL file, we need to link with - the Irrlicht.lib. We could set this option in the project settings, - but to make it easy, we use a pragma comment lib: -
Ok, lets start. Again, we use the main() method as start, not the WinMain(), - because its shorter to write. -
Like in the HelloWorld example, we create an IrrlichtDevice with createDevice(). - The difference now is that we ask the user to select which hardware accelerated - driver to use. The Software device would be too slow to draw a huge Quake - 3 map, but just for the fun of it, we make this decision possible too. -
Get a pointer to the video driver and the SceneManager so that we do - not always have to write device->getVideoDriver() and device->getSceneManager(). -
To display the Quake 3 map, we first need to load it. Quake 3 maps are - packed into .pk3 files wich are nothing other than .zip files. So we add - the .pk3 file to our FileSystem. After it was added, we are able to read - from the files in that archive as they would directly be stored on disk. -
Now we can load the mesh by calling getMesh(). We get a pointer returned
- to a IAnimatedMesh. As you know, Quake 3 maps are not really animated,
- they are only a huge chunk of static geometry with some materials attached.
- Hence the IAnimated mesh consists of only one frame,
Because the level was modelled not around the origin (0,0,0), we translate - the whole level a little bit. -
Now we only need a Camera to look at the Quake 3 map. And we want to
- create a user controlled camera. There are some different cameras available
- in the Irrlicht engine. For example the Maya Camera which can be controlled
- compareable to the camera in Maya: Rotate with left mouse button pressed,
- Zoom with both buttons pressed,
The mouse cursor needs not to be visible, so we make it invisible. -
We have done everything, so lets draw it. We also write the current frames - per second and the drawn primitives to the caption of the window. The - 'if (device->isWindowActive())' line is optional, but prevents the - engine render to set the position of the mouse cursor after task switching - when other program are active. -
In the end, delete the Irrlicht device. -
That's it. Compile and play around with the program. |
-
-
- - + + + + + + + +
This tutorial shows how to load a Quake 3 map into the engine, create a SceneNode for optimizing the speed of rendering, and how to create a user controlled camera.
+Please note that you should know the basics of the engine before starting this tutorial. Just take a short look at the first tutorial, if you haven't done this yet: http://irrlicht.sourceforge.net/docu/example001.html
+Lets start like the HelloWorld example: We include the irrlicht header files and an additional file to be able to ask the user for a driver type using the console.
As already written in the HelloWorld example, in the Irrlicht Engine everything can be found in the namespace 'irr'. To get rid of the irr:: in front of the name of every class, we tell the compiler that we use that namespace from now on, and we will not have to write that 'irr::'. There are 5 other sub namespaces 'core', 'scene', 'video', 'io' and 'gui'. Unlike in the HelloWorld example, we do not call 'using namespace' for these 5 other namespaces, because in this way you will see what can be found in which namespace. But if you like, you can also include the namespaces like in the previous example.
Again, to be able to use the Irrlicht.DLL file, we need to link with the Irrlicht.lib. We could set this option in the project settings, but to make it easy, we use a pragma comment lib:
OK, lets start. Again, we use the main() method as start, not the WinMain().
Like in the HelloWorld example, we create an IrrlichtDevice with createDevice(). The difference now is that we ask the user to select which video driver to use. The Software device might be too slow to draw a huge Quake 3 map, but just for the fun of it, we make this decision possible, too.
Get a pointer to the video driver and the SceneManager so that we do not always have to call irr::IrrlichtDevice::getVideoDriver() and irr::IrrlichtDevice::getSceneManager().
To display the Quake 3 map, we first need to load it. Quake 3 maps are packed into .pk3 files which are nothing else than .zip files. So we add the .pk3 file to our irr::io::IFileSystem. After it was added, we can read from the files in that archive as if they were stored on disk.
Now we can load the mesh by calling irr::scene::ISceneManager::getMesh(). We get a pointer returned to an irr::scene::IAnimatedMesh. Quake 3 maps are not really animated, they are only a chunk of static geometry with some materials attached. Hence the IAnimatedMesh consists of only one frame, so we get the "first frame" of the "animation", which is our quake level and create an Octree scene node with it, using irr::scene::ISceneManager::addOctreeSceneNode(). The Octree optimizes the scene a little bit, trying to draw only geometry which is currently visible. An alternative to the Octree would be a irr::scene::IMeshSceneNode, which would always draw the complete geometry of the mesh, without optimization. Try it: Use irr::scene::ISceneManager::addMeshSceneNode() instead of addOctreeSceneNode() and compare the primitives drawn by the video driver. (There is a irr::video::IVideoDriver::getPrimitiveCountDrawn() method in the irr::video::IVideoDriver class). Note that this optimization with the Octree is only useful when drawing huge meshes consisting of lots of geometry and if users can't see the whole scene at once.
Because the level was not modeled around the origin (0,0,0), we translate the whole level a little bit. This is done on irr::scene::ISceneNode level using the methods irr::scene::ISceneNode::setPosition() (in this case), irr::scene::ISceneNode::setRotation(), and irr::scene::ISceneNode::setScale().
Now we need a camera to look at the Quake 3 map. We want to create a user controlled camera. There are some cameras available in the Irrlicht engine. For example the MayaCamera which can be controlled like the camera in Maya: Rotate with left mouse button pressed, Zoom with both buttons pressed, translate with right mouse button pressed. This could be created with irr::scene::ISceneManager::addCameraSceneNodeMaya(). But for this example, we want to create a camera which behaves like the ones in first person shooter games (FPS) and hence use irr::scene::ISceneManager::addCameraSceneNodeFPS().
The mouse cursor needs not be visible, so we hide it via the irr::IrrlichtDevice::ICursorControl.
Everything is set up, so lets draw it. We also write the current frames per second and the primitives drawn into the caption of the window. The test for irr::IrrlichtDevice::isWindowActive() is optional, but prevents the engine to grab the mouse cursor after task switching when other programs are active. The call to irr::IrrlichtDevice::yield() will avoid the busy loop to eat up all CPU cycles when the window is not active.
In the end, delete the Irrlicht device.
That's it. Compile and play around with the program.
++ + diff --git a/examples/03.CustomSceneNode/tutorial.html b/examples/03.CustomSceneNode/tutorial.html index becc3d77..bfa3a7b9 100644 --- a/examples/03.CustomSceneNode/tutorial.html +++ b/examples/03.CustomSceneNode/tutorial.html @@ -1,222 +1,209 @@ - - -
- Lets start! |
- ||||||||||||
-
- To start, I include the header files, use the irr namespace, and tell - the linker to link with the .lib file. -
Here comes the most sophisticated part of this tutorial: The class
- of our very own custom scene node. To keep it simple, To let our scene node be able to be inserted into the Irrlicht Engine - scene, the class we create needs only be derived from the ISceneNode - class and has to override some methods. -
First, we declare some member variables, to hold data for our tetraeder:
- The bounding box, 4 vertices, and
The parameters of the constructor specify the parent of the scene node, - a pointer to the scene manager, and an id of the scene node. In the - constructor itself, we call the parent classes constructor, set some - properties of the material we use to draw the scene node and create - the 4 vertices of the tetraeder we will draw later. -
- The Irrlicht Engine needs to know the bounding box of your scene node. - It will use it for doing automatic culling and other things. Hence we - need to create a bounding box from the 4 vertices we use. If you do not - want the engine to use the box for automatic culling, and/or don't want - to create the box, you could also write - AutomaticCullingEnabled = false;. - -
- Before it is drawn, the OnPreRender() method of every scene node in
- the scene is called by the scene manager. If the scene node wishes to
- draw itself, it may register itself in the scene manager to be drawn.
- This is necessary to tell the scene manager when it should call the
- ::render method. For example normal scene nodes render their content
- one after another, while stencil buffer shadows would like to be drawn
- after all other scene nodes. And camera or light scene nodes need to
- be rendered before all other scene nodes (if at all).
In the render() method most of the interresting stuff happenes: The Scene - node renders itself. We override this method and draw the tetraeder. -
At least, we create three small additional methods. GetBoundingBox()
- returns the bounding box of this scene node,
That's it. The Scene node is done. Now we simply have to start the engine, - create the scene node and a camera, and look at the result. -
Create our scene node. Note that it is dropped (->drop()) instantly - after we create it. This is possible because the scene manager now takes - care of it. This is not nessecary, it would also be possible to drop it - at the end of the program. -
To animate something in this boring scene consisting only of one tetraeder, - and to show, that you now can use your scene node like any other scene - node in the engine, we add an animator to the scene node, which rotates - the node a little bit. -
Now draw everything and finish. -
That's it. Compile and play around with the program. |
-
- - + + + + + + + +
This tutorial is more advanced than the previous ones. If you are currently just playing around with the Irrlicht engine, you may want to look at other examples first. This tutorials shows how to create a custom scene node and how to use it in the engine. A custom scene node is needed if you want to implement a render technique the Irrlicht Engine currently does not support. For example, you can write an indoor portal based renderer or an advanced terrain scene node with it. By creating custom scene nodes, you can easily extend the Irrlicht Engine and adapt it to your needs.
+I will keep the tutorial simple: Keep everything very short and everything in one .cpp file. This is the style which will also be used in most of the following tutorials.
+To start, I include the header files, use the irr namespace, and tell the linker to link with the .lib file.
Here comes the more sophisticated part of this tutorial: The class of our very own custom scene node. To keep it simple, our scene node will not be an indoor portal renderer nor a terrain scene node, but a simple tetrahedron, a 3D object consisting of 4 connected vertices, which only draws itself and does nothing more. Note that this scenario does not require a custom scene node in Irrlicht. Instead one would create a mesh from the geometry and pass it to a irr::scene::IMeshSceneNode. This example just illustrates creation of a custom scene node in a simple setting.
+To allow our scene node to be inserted into the Irrlicht Engine scene, the class we create needs to be derived from the irr::scene::ISceneNode class and has to override some methods.
First, we declare some member variables: The bounding box, 4 vertices, and the material of the tetrahedron.
The parameters of the constructor specify the parent of the scene node, a pointer to the scene manager, and an id of the scene node. In the constructor we call the parent class' constructor, set some properties of the material, and create the 4 vertices of the tetrahedron.
The Irrlicht Engine needs to know the bounding box of a scene node. It will use it for automatic culling and other things. Hence, we need to create a bounding box from the 4 vertices we use. If you do not want the engine to use the box for automatic culling, and/or don't want to create the box, you could also call irr::scene::ISceneNode::setAutomaticCulling() with irr::scene::EAC_OFF.
Before it is drawn, the irr::scene::ISceneNode::OnRegisterSceneNode() method of every scene node in the scene is called by the scene manager. If the scene node wishes to draw itself, it may register itself in the scene manager to be drawn. This is necessary to tell the scene manager when it should call irr::scene::ISceneNode::render(). For example, normal scene nodes render their content one after another, while stencil buffer shadows would like to be drawn after all other scene nodes. And camera or light scene nodes need to be rendered before all other scene nodes (if at all). So here we simply register the scene node to render normally. If we would like to let it be rendered like cameras or light, we would have to call SceneManager->registerNodeForRendering(this, SNRT_LIGHT_AND_CAMERA); After this, we call the actual irr::scene::ISceneNode::OnRegisterSceneNode() method of the base class, which lets all the child scene nodes of this node register themselves.
In the render() method most of the interesting stuff happens: The Scene node renders itself. We override this method and draw the tetrahedron.
Indices into the 'Vertices' array. A triangle needs 3 vertices so you have to pass the 3 corresponding indices for each triangle to tell which of the vertices should be used for it.
And finally we create three small additional methods. irr::scene::ISceneNode::getBoundingBox() returns the bounding box of this scene node, irr::scene::ISceneNode::getMaterialCount() returns the amount of materials in this scene node (our tetrahedron only has one material), and irr::scene::ISceneNode::getMaterial() returns the material at an index. Because we have only one material, we can return that and assume that no one ever calls getMaterial() with an index greater than 0.
That's it. The Scene node is done. Now we start the engine, create the scene node and a camera, and look at the result.
Create our scene node. I don't check the result of calling new, as it should throw an exception rather than returning 0 on failure. Because the new node will create itself with a reference count of 1, and then will have another reference added by its parent scene node when it is added to the scene, I need to drop my reference to it. Best practice is to drop it only after I have finished using it, regardless of what the reference count of the object is after creation.
To animate something in this boring scene consisting only of one tetrahedron, and to show that you now can use your scene node like any other scene node in the engine, we add an animator to the scene node, which rotates the node a little bit. irr::scene::ISceneManager::createRotationAnimator() could return 0, so should be checked.
I'm done referring to anim, so must irr::IReferenceCounted::drop() this reference now because it was produced by a createFoo() function. As I shouldn't refer to it again, ensure that I can't by setting to 0.
I'm done with my CSampleSceneNode object, and so must drop my reference. This won't delete the object, yet, because it is still attached to the scene graph, which prevents the deletion until the graph is deleted or the custom scene node is removed from it.
Now draw everything and finish.
That's it. Compile and play around with the program.
++ + diff --git a/examples/04.Movement/tutorial.html b/examples/04.Movement/tutorial.html index 28b207dc..cb793b21 100644 --- a/examples/04.Movement/tutorial.html +++ b/examples/04.Movement/tutorial.html @@ -1,188 +1,208 @@ - - -
- Lets start! |
- |||||||||||
-
- As always, I include the header files, use the irr namespace, and tell - the linker to link with the .lib file. -
In this tutorial, one of our goals is to move a scene node using some
- keys on the keyboard. We store a pointer to the scene node we want to
- move with the keys here.
To get events like mouse and keyboard input, or GUI events like "the - OK button has been clicked", we need an object wich is derived - from the IEventReceiver object. There is only one method to override: - OnEvent. This method will be called by the engine when an event happened. - We will use this input to move the scene node with the keys W and S. -
If the key 'W' or 'S' was left up, we get the position of the scene - node, and modify the Y coordinate a little bit. So if you press 'W', - the node moves up, and if you press 'S' it moves down. -
The event receiver for moving a scene node is ready. So lets just create - an Irrlicht Device and the scene node we want to move. We also create - some other additional scene nodes, to show that there are also some different - possibilities to move and animate scene nodes. -
Create the node for moving it with the 'W' and 'S' key. We create a - sphere node, which is a built in geometric primitive scene node. - We place the node at (0,0,30) and assign a texture to it to let it look - a little bit more interesting. -
Now we create another node, moving using a scene node animator. Scene
- node animators modify scene nodes and can be attached to any scene node
- like
The last scene node we add to show possibilities of scene node animators - is a md2 model, which uses a 'fly straight' animator to run between to - points. -
To make to model look right we set the frames between which
- the animation should loop, rotate the model around 180 degrees, and adjust
- the animation speed and the texture.
To be able to look at and move around in this scene, we create a first - person shooter style camera and make the mouse cursor invisible. -
We have done everything, so lets draw it. We also write the current frames - per second and the name of the driver to the caption of the window. -
That's it. Compile and play around with the program. -
|
-
- - + + + + + + + +
This tutorial shows how to move and animate SceneNodes. The basic concept of SceneNodeAnimators is shown as well as manual movement of nodes using the keyboard. We'll demonstrate framerate independent movement, which means moving by an amount dependent on the duration of the last run of the Irrlicht loop.
+Example 19.MouseAndJoystick shows how to handle other input than keyboard.
+As always, include the header files, use the irr namespace, and tell the linker to link with the .lib file.
To receive events like mouse and keyboard input, or GUI events like "button has been clicked", we need an object which is derived from the irr::IEventReceiver object. There is only one method to override: irr::IEventReceiver::OnEvent(). This method will be called by the engine once when an event happens. What we really want to know is whether a key is being held down, and so we will remember the current state of each key.
Always return false by default. If you return true you tell the engine that you handled this event completely and the Irrlicht should not process it any further. So for example if you return true for all EET_KEY_INPUT_EVENT events then Irrlicht would not pass on key-events to it's GUI system.
The event receiver for keeping the pressed keys is ready, the actual responses will be made inside the render loop, right before drawing the scene. So lets create an irr::IrrlichtDevice and the scene node we want to move. We also create some additional scene nodes to show different possibilities to move and animate scene nodes.
Create the event receiver. Take care that the pointer to it has to stay valid as long as the IrrlichtDevice uses it. Event receivers are not reference counted.
Create the node which will be moved with the WSAD keys. We create a sphere node, which is a built-in geometry primitive. We place the node at (0,0,30) and assign a texture to it to let it look a little bit more interesting. Because we have no dynamic lights in this scene we disable lighting for each model (otherwise the models would be black).
Now we create another node, movable using a scene node animator. Scene node animators modify scene nodes and can be attached to any scene node like mesh scene nodes, billboards, lights and even camera scene nodes. Scene node animators are not only able to modify the position of a scene node, they can also animate the textures of an object for example. We create a cube scene node and attach a 'fly circle' scene node animator to it, letting this node fly around our sphere scene node.
The last scene node we add is a b3d model of a walking ninja. Is shows the use of a 'fly straight' animator to move the node between two points.
To make the model look right we disable lighting, set the frames between which the animation should loop, rotate the model around 180 degrees, and adjust the animation speed and the texture. To set the correct animation (frames and speed), we would also be able to just call "ninjaNode->setMD2Animation(scene::EMAT_RUN)" for the 'run' animation instead of "setFrameLoop" and "setAnimationSpeed", But that only works with MD2 animations, while this can be used to start other animations. For MD2 it's usually good advice not to use hardcoded frame-numbers...
To be able to look at and move around in this scene, we create a first person shooter style camera and make the mouse cursor invisible.
Add a colorful irrlicht logo
Lets draw the scene and also write the current frames per second and the name of the driver to the caption of the window.
Check if keys W, S, A or D are being held down, and move the sphere node around respectively.
In the end, delete the Irrlicht device.
That's it. Compile and play around with the program.
++ + diff --git a/examples/05.UserInterface/tutorial.html b/examples/05.UserInterface/tutorial.html index 3f3614fa..5b048a17 100644 --- a/examples/05.UserInterface/tutorial.html +++ b/examples/05.UserInterface/tutorial.html @@ -1,225 +1,206 @@ - - -
- Lets start! |
- ||||||||||
-
- As always, we include the header files (conio and curses for getting - user input from the console), and use the irrlicht namespaces. We also - store a pointer to the Irrlicht device, a counter variable for changing - the creation position of a window, and a pointer to a listbox. -
The Event Receiver is not only capable of getting keyboard and mouse
- input events, but also events of the graphical user interface (gui).
- There are events for almost everything: Button click, Listbox selection
- change, events that say that a element was hovered and so on. To be
- able to react to some of these events, we create
If a scrollbar changed its scroll position, and it is 'our' scrollbar
- (the one with id 104), then we change the
If a button was clicked, it could be one of 'our' three buttons. If
- it is the first, we shut down the engine.
Ok, now for the more interesting part. First, create the Irrlicht device. - As in some examples before, we ask the user which driver he wants to - use for this example: -
The creation was successful, now we set the event receiver and store - pointers to the driver and to the gui environment. -
We add three buttons. The first one closes the engine. The second creates - a window and the third opens a file open dialog. The third parameter is - the id of the button, with which we can easily identify the button in - the event receiver. -
Now, we add a static text and a scrollbar, which modifies the transparency
- of all gui elements. We set the maximum value of the scrollbar to 255,
- because that's the maximal value for a color value.
- To make the font a little bit nicer, we load an external font and set it - as new font in the skin. An at last, we create a nice Irrlicht Engine logo - in the top left corner. - -
That's all, we only have to draw everything. -
|
-
- - + + + + + + + +
This tutorial shows how to use the built in User Interface of the Irrlicht Engine. It will give a brief overview and show how to create and use windows, buttons, scroll bars, static texts, and list boxes.
+As always, we include the header files, and use the irrlicht namespaces. We also store a pointer to the Irrlicht device, a counter variable for changing the creation position of a window, and a pointer to a listbox.
Set the skin transparency by changing the alpha values of all skin-colors
The Event Receiver is not only capable of getting keyboard and mouse input events, but also events of the graphical user interface (gui). There are events for almost everything: button click, listbox selection change, events that say that a element was hovered and so on. To be able to react to some of these events, we create an event receiver. We only react to gui events, and if it's such an event, we get the id of the caller (the gui element which caused the event) and get the pointer to the gui environment.
If a scrollbar changed its scroll position, and it is 'our' scrollbar (the one with id GUI_ID_TRANSPARENCY_SCROLL_BAR), then we change the transparency of all gui elements. This is an easy task: There is a skin object, in which all color settings are stored. We simply go through all colors stored in the skin and change their alpha value.
If a button was clicked, it could be one of 'our' three buttons. If it is the first, we shut down the engine. If it is the second, we create a little window with some text on it. We also add a string to the list box to log what happened. And if it is the third button, we create a file open dialog, and add also this as string to the list box. That's all for the event receiver.
OK, now for the more interesting part. First, create the Irrlicht device. As in some examples before, we ask the user which driver he wants to use for this example.
The creation was successful, now we set the event receiver and store pointers to the driver and to the gui environment.
To make the font a little bit nicer, we load an external font and set it as the new default font in the skin. To keep the standard font for tool tip text, we set it to the built-in font.
We add three buttons. The first one closes the engine. The second creates a window and the third opens a file open dialog. The third parameter is the id of the button, with which we can easily identify the button in the event receiver.
Now, we add a static text and a scrollbar, which modifies the transparency of all gui elements. We set the maximum value of the scrollbar to 255, because that's the maximal value for a color value. Then we create an other static text and a list box.
And at last, we create a nice Irrlicht Engine logo in the top left corner.
That's all, we only have to draw everything.
+ + diff --git a/examples/06.2DGraphics/tutorial.html b/examples/06.2DGraphics/tutorial.html index ea6291af..423c9c25 100644 --- a/examples/06.2DGraphics/tutorial.html +++ b/examples/06.2DGraphics/tutorial.html @@ -1,163 +1,208 @@ - - -
- Lets start! |
- |||||||||
-
- As always, I include the header files, use the irr namespace, and tell - the linker to link with the .lib file. -
At first, we let the user select the driver type, then start up the - engine, set a caption, and get a pointer to the video driver. -
All 2d graphics in this example are put together into one texture, - 2ddemo.bmp. Because we want to draw colorkey based sprites, we need - to load this texture and tell the engine, which part of it should be - transparent based on a colorkey. In this example, we don't tell it the - color directly, we just say "Hey Irrlicht Engine, you'll find the - color I want at position (0,0) on the texture.". Instead, it would - be also possible to call driver->makeColorKeyTexture(images, - video::SColor(0,0,0,0)), to make e.g. all black pixels transparent. - Please note, that makeColorKeyTexture just creates an alpha channel - based on the color. -
To be able to draw some text with two different fonts, we load them.
- Ok, we load just one, as first font we just use the default font which
- is built into the engine.
Everything is prepared, now we can draw everything in the draw loop, - between the begin scene and end scene calls. In this example, we are - just doing 2d graphics, but it would be no problem to mix them with - 3d graphics. Just try it out, and draw some 3d vertices or set up a - scene with the scene manager and draw it. -
First, we draw 3 sprites, using the alpha channel we created with makeColorKeyTexture. - The last parameter specifiys that the drawing method should use thiw alpha - channel. The parameter before the last one specifies a color, with wich - the sprite should be colored. (255,255,255,255) is full white, so the - sprite will look like the original. The third sprite is drawed colored - based on the time. -
Drawing text is really simple. The code should be self explanatory. -
At last, we draw the Irrlicht Engine logo (without using a color or an - alpha channel) and a transparent 2d Rectangle at the position of the mouse - cursor. -
That's all, it was not really difficult, I hope. -
|
-
- - + + + + + + + +
This tutorial shows how to do 2d graphics with the Irrlicht Engine. It shows how to draw images, keycolor based sprites, transparent rectangles, and different fonts. You may consider this useful if you want to make a 2d game with the engine, or if you want to draw a cool interface or head up display for your 3d game.
+As always, I include the header files, use the irr namespace, and tell the linker to link with the .lib file.
At first, we let the user select the driver type, then start up the engine, set a caption, and get a pointer to the video driver.
All 2d graphics in this example are put together into one texture, 2ddemo.png. Because we want to draw colorkey based sprites, we need to load this texture and tell the engine, which part of it should be transparent based on a colorkey.
+In this example, we don't tell it the color directly, we just say "Hey Irrlicht Engine, you'll find the color I want at position (0,0) on the texture.". Instead, it would be also possible to call driver->makeColorKeyTexture(images, video::SColor(0,0,0,0)), to make e.g. all black pixels transparent. Please note that makeColorKeyTexture just creates an alpha channel based on the color.
To be able to draw some text with two different fonts, we first load them. OK, we load just one. As the first font we just use the default font which is built into the engine. Also, we define two rectangles which specify the position of the images of the red imps (little flying creatures) in the texture.
Prepare a nicely filtering 2d render mode for special cases.
Everything is prepared, now we can draw everything in the draw loop, between the begin scene and end scene calls. In this example, we are just doing 2d graphics, but it would be no problem to mix them with 3d graphics. Just try it out, and draw some 3d vertices or set up a scene with the scene manager and draw it.
First, we draw 3 sprites, using the alpha channel we created with makeColorKeyTexture. The last parameter specifies that the drawing method should use this alpha channel. The last-but-one parameter specifies a color, with which the sprite should be colored. (255,255,255,255) is full white, so the sprite will look like the original. The third sprite is drawn with the red channel modulated based on the time.
Drawing text is really simple. The code should be self explanatory.
Next, we draw the Irrlicht Engine logo (without using a color or an alpha channel). Since we slightly scale the image we use the prepared filter mode.
Finally draw a half-transparent rect under the mouse cursor.
That's all. I hope it was not too difficult.
++ + diff --git a/examples/07.Collision/tutorial.html b/examples/07.Collision/tutorial.html index c04fce99..03fa80af 100644 --- a/examples/07.Collision/tutorial.html +++ b/examples/07.Collision/tutorial.html @@ -1,308 +1,207 @@ - - -
- Lets start! |
- ||||||||
-
-
-
- To start, we take the program from tutorial 2, which loaded and displayed - a quake 3 level. We will use the level to walk in it and to pick triangles - from it. In addition we'll place 3 animated models into it for scene - node picking. The following code starts up the engine and loads a - quake 3 level. I will not explain it, because it should already be - known from tutorial 2. -
So far so good, we've loaded the quake 3 level like in tutorial
- 2. Now, here comes something different: We create a triangle selector.
- A triangle selector is a class which can fetch the triangles from
- scene nodes for doing different things with them, for example collision
- detection. There are different triangle selectors, and all can be
- created with the ISceneManager. In this example, we create an OctTreeTriangleSelector,
- which optimizes the triangle output a little bit by reducing it like
- an octree. This is very useful for huge meshes like quake 3 levels.
We add a first person shooter camera to the scene for being able
- to move in the quake 3 level like in tutorial 2. But this, time, we
- add a special animator to the camera: A Collision Response animator.
- This thing modifies the scene node to which it is attached to in that
- way, that it may no more move through walls and is affected by gravity.
- The only thing we have to tell the animator is how the world looks
- like, how big the scene node is, how gravity and so on. After the
- collision response animator is attached to the camera, we do not have
- to do anything more for collision detection, anything is done automaticly,
- all other collision detection code below is for picking. And please
- note another cool feature: The collsion response animator can be attached
- also to all other scene nodes, not only to cameras. And it can be
- mixed with other scene node animators. In this way, collision detection
- and response in the Irrlicht
Because collision detection is no big deal in irrlicht, I'll describe
- how to do two different types of picking in the next section. But
- before this, I'll prepare the scene a little. I need three animated
- characters which we
For not making it to complicated, I'm doing picking inside the drawing - loop. We take two pointers for storing the current and the last selected - scene node and start the loop. -
After we've drawn the whole scene whit smgr->drawAll(), we'll do - the first picking: We want to know which triangle of the world we are - looking at. In addition, we want the exact point of the quake 3 level - we are looking at. For this, we create a 3d line starting at the position - of the camera and going through the lookAt-target of it. Then we ask - the collision manager if this line collides with a triangle of the world - stored in the triangle selector. If yes, we draw the 3d triangle and - set the position of the billboard to the intersection point. -
Another type of picking supported by the Irrlicht Engine is scene
- node picking based on bouding boxes. Every scene node has got a bounding
- box, and because of that, it's very fast for example to get the scene
- node which the camera looks
That's it, we just have to finish drawing. -
- - |
-
- - + + + + + + + +
We will describe 2 methods: Automatic collision detection for moving through 3d worlds with stair climbing and sliding, and manual scene node and triangle picking using a ray. In this case, we will use a ray coming out from the camera, but you can use any ray.
+To start, we take the program from tutorial 2, which loads and displays a quake 3 level. We will use the level to walk in it and to pick triangles from. In addition we'll place 3 animated models into it for triangle picking. The following code starts up the engine and loads the level, as per tutorial 2.
If we want to receive information about the material of a hit triangle we have to get collisions per meshbuffer. The only disadvantage of this is that getting them per meshbuffer can be a little bit slower than per mesh, but usually that's not noticeable. If you set this to false you will no longer get material names in the title bar.
So far so good, we've loaded the quake 3 level like in tutorial 2. Now, here comes something different: We create a triangle selector. A triangle selector is a class which can fetch the triangles from scene nodes for doing different things with them, for example collision detection. There are different triangle selectors, and all can be created with the ISceneManager. In this example, we create an OctreeTriangleSelector, which optimizes the triangle output a little bit by reducing it like an octree. This is very useful for huge meshes like quake 3 levels. After we created the triangle selector, we attach it to the q3node. This is not necessary, but in this way, we do not need to care for the selector, for example dropping it after we do not need it anymore.
There is currently no way to split an octree by material. So if we need material infos we have to create one octree per meshbuffer and put them together in a MetaTriangleSelector.
We add a first person shooter camera to the scene so that we can see and move in the quake 3 level like in tutorial 2. But this, time, we add a special animator to the camera: A collision response animator. This animator modifies the scene node to which it is attached in order to prevent it from moving through walls and to add gravity to the node. The only things we have to tell the animator is how the world looks like, how big the scene node is, how much gravity to apply and so on. After the collision response animator is attached to the camera, we do not have to do anything else for collision detection, it's all done automatically. The rest of the collision detection code below is for picking. And please note another cool feature: The collision response animator can be attached also to all other scene nodes, not only to cameras. And it can be mixed with other scene node animators. In this way, collision detection and response in the Irrlicht engine is really easy.
+Now we'll take a closer look on the parameters of createCollisionResponseAnimator(). The first parameter is the TriangleSelector, which specifies how the world, against which collision detection is done, looks like. The second parameter is the scene node, which is the object which is affected by collision detection - in our case it is the camera. The third defines how big the object is, it is the radius of an ellipsoid. Try it out and change the radius to smaller values, the camera will be able to move closer to walls after this. The next parameter is the direction and speed of gravity. We'll set it to (0, -1000, 0), which approximates realistic gravity (depends on the units which are used in the scene model). You could set it to (0,0,0) to disable gravity. And the last value is just an offset: Without it the ellipsoid with which collision detection is done would be around the camera and the camera would be in the middle of the ellipsoid. But as human beings, we are used to have our eyes on top of the body, not in the middle of it. So we place the scene node 50 units over the center of the ellipsoid with this parameter. And that's it, collision detection works now.
Add 3 animated hominids, which we can pick using a ray-triangle intersection. They all animate quite slowly, to make it easier to see that accurate triangle selection is being performed.
+ + diff --git a/examples/08.SpecialFX/tutorial.html b/examples/08.SpecialFX/tutorial.html index 8c1fc51a..1c77ef6a 100644 --- a/examples/08.SpecialFX/tutorial.html +++ b/examples/08.SpecialFX/tutorial.html @@ -1,278 +1,210 @@ - - -
Lets start! | -|||||||
-
-
-
- We start like in some tutorials before. Please note that this time, - the 'shadows' flag in createDevice() is set to true, for we want to - have a dynamic shadow casted from an animated character. If your this - example runs to slow, set it to false. The Irrlicht Engine checks - if your hardware doesn't support the stencil buffer, and disables - shadows by itself, but just in case the demo runs slow on your hardware. -
For our environment, we load a .3ds file. It is a small room I modelled
- with Anim8or and exported it into the 3ds format because the Irrlicht
- Engine did not support the .an8 format when I wrote this tutorial.
- I am a very bad 3d graphic artist, and so the texture mapping is not
- very nice in this model. Luckily I am a better programmer than artist,
- and so the Irrlicht Engine is able to create a cool texture mapping
- for me: Just use the mesh manipulator and create a planar texture
- mapping for the mesh. If you want to see the mapping I made with Anim8or,
- uncomment this line. I also did not figure out how to
Now, for the first special effect: Animated water. It works like - this: The WaterSurfaceSceneNode takes a mesh as input and makes it - wave like a water surface. And if we let this scene node use a nice - material like the MT_REFLECTION_2_LAYER, it looks really cool. We - are doing this with the next few lines of code. As input mesh, we - create a hill plane mesh, without hills. But any other mesh could - be used for this, you could even use the room.3ds (which would look - really strange) if you wanted to. -
The second special effect is very basic, I bet you saw it already - in some Irrlicht Engine demos: A transparent billboard combined with - a dynamic light. We simply create a light scene node, let it fly around, - an to make it look more cool, we attach a billboard scene node to - it. -
The next special effect is a lot more interesting: A particle system.
- The particle system in the Irrlicht Engine is quit modular and extensible
- and yet easy to use. There is a particle system scene node into which
- you can put particle emitters, which make particles come out of nothing.
- These emitters are quite flexible and usually have lots of parameters
- like direction, amount and color of the particles they should create. Because only with emitters particle system would be a little bit
- boring, there are particle affectors, which modify particles during
- they fly around. They can be added to the particle system, simulating
- additional effects like gravity or wind. The particle affector we
- use in this example is an affector, which modifies the color of the
- particles: It lets them fade out. Like the particle emitters, additional
- particle affectors can also be implemented by you, simply derive a
- class from IParticleAffector and add it with addAffector(). After
- we set a nice material to the particle system, we have a cool looking
- camp fire. By adjusting material, texture, particle emitter and affector
- parameters, it is also easily possible to create smoke, rain, explosions,
- snow, and so on.
As our last special effect, we want a dynamic shadow be casted from
- an animated character. For this we load a DirectX .x model and place
- it into our world. For creating the shadow, we simply need to call addShadowVolumeSceneNode().
- The color of shadows is only adjustable globally for all shadows, by
- calling ISceneManager::setShadowColor(). Voila, here is our dynamic
- shadow.
Finally we simply have to draw everything, that's all. -
- - - |
-
- - + + + + + + + +
This tutorial describes how to do special effects. It shows how to use stencil buffer shadows, the particle system, billboards, dynamic light, and the water surface scene node.
+We start like in some tutorials before. Please note that this time, the 'shadows' flag in createDevice() is set to true, for we want to have a dynamic shadow cast from an animated character. If this example runs too slow, set it to false. The Irrlicht Engine also checks if your hardware doesn't support the stencil buffer, and then disables shadows by itself.
Create device and exit if creation failed. We make the stencil flag optional to avoid slow screen modes for runs without shadows.
For our environment, we load a .3ds file. It is a small room I modeled with Anim8or and exported into the 3ds format because the Irrlicht Engine does not support the .an8 format. I am a very bad 3d graphic artist, and so the texture mapping is not very nice in this model. Luckily I am a better programmer than artist, and so the Irrlicht Engine is able to create a cool texture mapping for me: Just use the mesh manipulator and create a planar texture mapping for the mesh. If you want to see the mapping I made with Anim8or, uncomment this line. I also did not figure out how to set the material right in Anim8or, it has a specular light color which I don't really like. I'll switch it off too with this code.
Now, for the first special effect: Animated water. It works like this: The WaterSurfaceSceneNode takes a mesh as input and makes it wave like a water surface. And if we let this scene node use a nice material like the EMT_REFLECTION_2_LAYER, it looks really cool. We are doing this with the next few lines of code. As input mesh, we create a hill plane mesh, without hills. But any other mesh could be used for this, you could even use the room.3ds (which would look really strange) if you want to.
The second special effect is very basic, I bet you saw it already in some Irrlicht Engine demos: A transparent billboard combined with a dynamic light. We simply create a light scene node, let it fly around, and to make it look more cool, we attach a billboard scene node to it.
The next special effect is a lot more interesting: A particle system. The particle system in the Irrlicht Engine is quite modular and extensible, but yet easy to use. There is a particle system scene node into which you can put a particle emitter, which makes particles come out of nothing. These emitters are quite flexible and usually have lots of parameters like direction, amount, and color of the particles they create.
+There are different emitters, for example a point emitter which lets particles pop out at a fixed point. If the particle emitters available in the engine are not enough for you, you can easily create your own ones, you'll simply have to create a class derived from the IParticleEmitter interface and attach it to the particle system using setEmitter(). In this example we create a box particle emitter, which creates particles randomly inside a box. The parameters define the box, direction of the particles, minimal and maximal new particles per second, color, and minimal and maximal lifetime of the particles.
+Because only with emitters particle system would be a little bit boring, there are particle affectors which modify particles while they fly around. Affectors can be added to a particle system for simulating additional effects like gravity or wind. The particle affector we use in this example is an affector which modifies the color of the particles: It lets them fade out. Like the particle emitters, additional particle affectors can also be implemented by you, simply derive a class from IParticleAffector and add it with addAffector().
+After we set a nice material to the particle system, we have a cool looking camp fire. By adjusting material, texture, particle emitter, and affector parameters, it is also easily possible to create smoke, rain, explosions, snow, and so on.
Next we add a volumetric light node, which adds a glowing fake area light to the scene. Like with the billboards and particle systems we also assign a texture for the desired effect, though this time we'll use a texture animator to create the illusion of a magical glowing area effect.
As our last special effect, we want a dynamic shadow be cast from an animated character. For this we load a DirectX .x model and place it into our world. For creating the shadow, we simply need to call addShadowVolumeSceneNode(). The color of shadows is only adjustable globally for all shadows, by calling ISceneManager::setShadowColor(). Voila, here is our dynamic shadow.
+Because the character is a little bit too small for this scene, we make it bigger using setScale(). And because the character is lighted by a dynamic light, we need to normalize the normals to make the lighting on it correct. This is always necessary if the scale of a dynamic lighted model is not (1,1,1). Otherwise it would get too dark or too bright because the normals will be scaled too.
Shadows still have to be drawn even then the node causing them is not visible itself. We have to disable culling if the node is animated or it's transformations change as otherwise the shadow is not updated correctly. If you have many objects and this becomes a speed problem you will have to figure out some manual culling (for exampling hiding all objects beyond a certain distance).
Finally we simply have to draw everything, that's all.
+ + diff --git a/examples/09.Meshviewer/tutorial.html b/examples/09.Meshviewer/tutorial.html index d296b6ca..50d0d1be 100644 --- a/examples/09.Meshviewer/tutorial.html +++ b/examples/09.Meshviewer/tutorial.html @@ -1,182 +1,213 @@ - - -
Lets start! | -|||||||||||
-
-
-
- We start like in most other tutorials: Include all nesessary header - files, add a comment to let the engine be linked with the right .lib - file in Visual Studio, and deklare some global variables. We also - add two 'using namespece' statements, so we do not need to write the - whole names of all classes. In this tutorial, we use a lot stuff from - the gui namespace. -
The three following functions do several stuff used by the mesh - viewer. The first function showAboutText() simply displays a messagebox - with a caption and a message text. The texts will be stored in the - MessageText and Caption variables at startup. -
The second function loadModel() loads a model and displays it using - an addAnimatedMeshSceneNode and the scene manager. Nothing difficult. - It also displays a short message box, if the model could not be loaded. - -
Finally, the third function creates a toolbox window. In this simple - mesh viewer, this toolbox only contains a tab control with three edit - boxes for changing the scale of the displayed model. -
To get all the events sent by the GUI Elements, we need to create - an event receiver. This one is really simple. If an event occurs, - it checks the id of the caller and the event type, and starts an action - based on these values. For example, if a menu item with id 100 was - selected, if opens a file-open-dialog. -
Most of the hard work is done. We only need to create the Irrlicht - Engine device and all the buttons, menus and toolbars. We start up the - engine as usual, using createDevice(). To make our application catch - events, we set our eventreceiver as parameter. The #ifdef WIN32 preprocessor - commands are not necesarry, but I included them to make the tutorial - use DirectX on Windows and OpenGL on all other platforms like Linux. - As you can see, there is also a unusual call to IrrlichtDevice::setResizeAble(). - This makes the render window resizeable, which is quite useful for a - mesh viewer. -
The next step is to read the configuration file. It is stored in the
- xml format and looks a little bit like this:
That wasn't difficult. Now we'll set a nicer font and create the Menu. - It is possible to create submenus for every menu item. The call menu->addItem(L"File", - -1, true, true); for example adds a new menu Item with the name "File" - and the id -1. The following parameter says that the menu item should - be enabled, and the last one says, that there should be a submenu. The - submenu can now be accessed with menu->getSubMenu(0), because the - "File" entry is the menu item with index 0. -
- We want a toolbar, onto which we can place colored buttons and important - looking stuff like a senseless combobox. - -
- To make the editor look a little bit better, we disable transparent gui - elements, and add a Irrlicht Engine logo. In addition, a text, which will - show the current frame per second value is created, and the window caption - changed. - -
- That's nearly the whole application. We simply show the about message - box at start up, and load the first model. To make everything look better, - a skybox is created and a user controled camera, to make the application - a little bit more interactive. Finally, everything is drawed in a standard - drawing loop. - -
- Compile and run this, and you have a fully functional 3d Mesh viewer. - |
-
- - + + + + + + + +
This tutorial show how to create a more complex application with the engine. We construct a simple mesh viewer using the user interface API and the scene management of Irrlicht. The tutorial show how to create and use Buttons, Windows, Toolbars, Menus, ComboBoxes, Tabcontrols, Editboxes, Images, MessageBoxes, SkyBoxes, and how to parse XML files with the integrated XML reader of the engine.
+We start like in most other tutorials: Include all necessary header files, add a comment to let the engine be linked with the correct .lib file in Visual Studio, and declare some global variables. We also add two 'using namespace' statements, so we do not need to write the whole names of all classes. In this tutorial, we use a lot of stuff from the gui namespace.
Some global variables used later on
Toggle between various cameras
Set the skin transparency by changing the alpha values of all skin-colors
Update the display of the model scaling
Function showAboutText() displays a messagebox with a caption and a message text. The texts will be stored in the MessageText and Caption variables at startup.
Function loadModel() loads a model and displays it using an addAnimatedMeshSceneNode and the scene manager. Nothing difficult. It also displays a short message box, if the model could not be loaded.
Function createToolBox() creates a toolbox window. In this simple mesh viewer, this toolbox only contains a controls to change the scale and animation speed of the model and a control to set the transparency of the GUI-elements.
Function updateToolBox() is called each frame to update dynamic information in the toolbox.
Function hasModalDialog() checks if we currently have a modal dialog open.
To get all the events sent by the GUI Elements, we need to create an event receiver. This one is really simple. If an event occurs, it checks the id of the caller and the event type, and starts an action based on these values. For example, if a menu item with id GUI_ID_OPEN_MODEL was selected, it opens a file-open-dialog.
Handle key-up events
Handle "menu item clicked" events.
Handle the event that one of the texture-filters was selected in the corresponding combobox.
Most of the hard work is done. We only need to create the Irrlicht Engine device and all the buttons, menus and toolbars. We start up the engine as usual, using createDevice(). To make our application catch events, we set our eventreceiver as parameter. As you can see, there is also a call to IrrlichtDevice::setResizeable(). This makes the render window resizeable, which is quite useful for a mesh viewer.
The next step is to read the configuration file. It is stored in the xml format and looks a little bit like this:
+<?xml version="1.0"?> + <config> + <startUpModel file="some filename" /> + <messageText caption="Irrlicht Engine Mesh Viewer"> + Hello! + </messageText> + </config>
We need the data stored in there to be written into the global variables StartUpModelFile, MessageText and Caption. This is now done using the Irrlicht Engine integrated XML parser:
Now create the Menu. It is possible to create submenus for every menu item. The call menu->addItem(L"File", -1, true, true); for example adds a new menu Item with the name "File" and the id -1. The following parameter says that the menu item should be enabled, and the last one says, that there should be a submenu. The submenu can now be accessed with menu->getSubMenu(0), because the "File" entry is the menu item with index 0.
Below the menu we want a toolbar, onto which we can place colored buttons and important looking stuff like a senseless combobox.
To make the editor look a little bit better, we disable transparent gui elements, and add an Irrlicht Engine logo. In addition, a text showing the current frames per second value is created and the window caption is changed.
Now we show the about message box at start up, and load the first model. To make everything look better a skybox is created. We also add a user controlled camera, to make the application more interactive. Finally, everything is drawn in a standard drawing loop.
+ + diff --git a/examples/10.Shaders/tutorial.html b/examples/10.Shaders/tutorial.html index 05c4f08a..7b63cea5 100644 --- a/examples/10.Shaders/tutorial.html +++ b/examples/10.Shaders/tutorial.html @@ -1,566 +1,210 @@ - - -
Lets start! | -|||||||||||
-
-
-
- At first, we need to include all headers and do the stuff we always - do, like in nearly all other tutorials: -
Because we want to use some interesting shaders in this tutorials,
- we need to set some data for them to make them able to compute nice
- colors. In this example, we'll use a simple vertex shader which will
- calculate the color of the vertex based on the position of the camera.
- For this, the shader needs the following data: The inverted world
- matrix for transforming the normal, the clip matrix for transforming
- the position, the camera position and the world position of the object
- for the calculation of the angle of light, and the color of the light.
- To be able to tell the shader all this data every frame, we have to
- derive a class from the IShaderConstantSetCallBack interface and override
- its only method, namely OnSetConstants(). This method will be called
- every time the material is set.
The next few lines start up the engine. Just like in most other - tutorials before. But in addition, we ask the user if he wants this - example to use high level shaders if he selected a driver which is - capable of doing so. -
Now for the more interesting parts. If we are using Direct3D, we
- want to load vertex and pixel shader programs, if we have
In addition, we check if the hardware and the selected renderer
- is capable of executing the shaders we want. If not, we simply set
- the filename string to 0. This is not necessary, but useful in this
- example: For example, if the hardware is able to execute vertex shaders
- but not pixel shaders, we create a new material which only uses the
- vertex shader, and no pixel shader. Otherwise, if we would tell the
- engine to create this material and the engine sees that the hardware
- wouldn't be able to fullfill the request completely,
Now lets create the new materials.
Now its time for testing out the materials. We create a test cube - and set the material we created. In addition, we add a text scene node - to the cube and a rotatation animator, to make it look more interesting - and important. -
Same for the second cube, but with the second material we created. -
- Then we add a third cube without a shader on it, to be able to compare - the cubes. - -
- And last, we add a skybox and a user controlled camera to the scene. For - the skybox textures, we disable mipmap generation, because we don't need - mipmaps on it. - -
- Now draw everything. That's all. - -
- Compile and run this, and I hope you have fun with your new little shader - writing tool :). - |
-
Shader files | -||||||||||||||
-
-
- The files containing the shaders can be found in the media directory - of the SDK. However, they look like this: -
-
-
-
-
-
-
- |
-
-
- - + + + + + + + +
This tutorial shows how to use shaders for D3D9, and OpenGL with the engine and how to create new material types with them. It also shows how to disable the generation of mipmaps at texture loading, and how to use text scene nodes.
+This tutorial does not explain how shaders work. I would recommend to read the D3D or OpenGL, documentation, to search a tutorial, or to read a book about this.
+At first, we need to include all headers and do the stuff we always do, like in nearly all other tutorials:
Because we want to use some interesting shaders in this tutorials, we need to set some data for them to make them able to compute nice colors. In this example, we'll use a simple vertex shader which will calculate the color of the vertex based on the position of the camera. For this, the shader needs the following data: The inverted world matrix for transforming the normal, the clip matrix for transforming the position, the camera position and the world position of the object for the calculation of the angle of light, and the color of the light. To be able to tell the shader all this data every frame, we have to derive a class from the IShaderConstantSetCallBack interface and override its only method, namely OnSetConstants(). This method will be called every time the material is set. The method setVertexShaderConstant() of the IMaterialRendererServices interface is used to set the data the shader needs. If the user chose to use a High Level shader language like HLSL instead of Assembler in this example, you have to set the variable name as parameter instead of the register index.
The next few lines start up the engine just like in most other tutorials before. But in addition, we ask the user if he wants to use high level shaders in this example, if he selected a driver which is capable of doing so.
Now for the more interesting parts. If we are using Direct3D, we want to load vertex and pixel shader programs, if we have OpenGL, we want to use ARB fragment and vertex programs. I wrote the corresponding programs down into the files d3d9.ps, d3d9.vs, opengl.ps and opengl.vs. We only need the right filenames now. This is done in the following switch. Note, that it is not necessary to write the shaders into text files, like in this example. You can even write the shaders directly as strings into the cpp source file, and use later addShaderMaterial() instead of addShaderMaterialFromFiles().
In addition, we check if the hardware and the selected renderer is capable of executing the shaders we want. If not, we simply set the filename string to 0. This is not necessary, but useful in this example: For example, if the hardware is able to execute vertex shaders but not pixel shaders, we create a new material which only uses the vertex shader, and no pixel shader. Otherwise, if we would tell the engine to create this material and the engine sees that the hardware wouldn't be able to fulfill the request completely, it would not create any new material at all. So in this example you would see at least the vertex shader in action, without the pixel shader.
Now lets create the new materials. As you maybe know from previous examples, a material type in the Irrlicht engine is set by simply changing the MaterialType value in the SMaterial struct. And this value is just a simple 32 bit value, like video::EMT_SOLID. So we only need the engine to create a new value for us which we can set there. To do this, we get a pointer to the IGPUProgrammingServices and call addShaderMaterialFromFiles(), which returns such a new 32 bit value. That's all.
+The parameters to this method are the following: First, the names of the files containing the code of the vertex and the pixel shader. If you would use addShaderMaterial() instead, you would not need file names, then you could write the code of the shader directly as string. The following parameter is a pointer to the IShaderConstantSetCallBack class we wrote at the beginning of this tutorial. If you don't want to set constants, set this to 0. The last parameter tells the engine which material it should use as base material.
+To demonstrate this, we create two materials with a different base material, one with EMT_SOLID and one with EMT_TRANSPARENT_ADD_COLOR.
Create one callback instance for each shader material you add. Reason is that the getVertexShaderConstantID returns ID's which are only valid per added material (The ID's tend to be identical as long as the shader code is exactly identical, but it's not good style to depend on that).
Now it's time for testing the materials. We create a test cube and set the material we created. In addition, we add a text scene node to the cube and a rotation animator to make it look more interesting and important.
Same for the second cube, but with the second material we created.
Then we add a third cube without a shader on it, to be able to compare the cubes.
And last, we add a skybox and a user controlled camera to the scene. For the skybox textures, we disable mipmap generation, because we don't need mipmaps on it.
Now draw everything. That's all.
Compile and run this, and I hope you have fun with your new little shader writing tool :).
++ + diff --git a/examples/11.PerPixelLighting/tutorial.html b/examples/11.PerPixelLighting/tutorial.html index 89e87bd8..fe1cda11 100644 --- a/examples/11.PerPixelLighting/tutorial.html +++ b/examples/11.PerPixelLighting/tutorial.html @@ -1,502 +1,206 @@ - - -
Lets start! | -|||||||||||||
-
-
-
- At first, we need to include all headers and do the stuff we always - do, like in nearly all other tutorials. -
For this example, we need an event receiver, to make it possible - for the user to switch between the three available material types. - In addition, the event receiver will create some small GUI window - which displays what material is currently being used. There is nothing - special done in this class, so maybe you want to skip reading it. -
We need to add a warning if the materials will not be able to be
- displayed 100% correctly. This is no problem, they will be renderered
- using fall back materials, but at least the user should know that
- it would look better on better hardware. We simply check if the material
- renderer is able to draw at full quality on the current hardware.
- The IMaterialRenderer::getRenderCapability() returns 0 if this is
- the case.
- Before we start with the interesting stuff, we do some simple things: - Store pointers to the most important parts of the engine (video driver, - scene manager, gui environment) to safe us from typing too much, add - an irrlicht engine logo to the window and a user controlled first person - shooter style camera. Also, we let the engine now that it should store - all textures in 32 bit. This necessary because for parallax mapping, - we need 32 bit textures. - -
- Because we want the whole scene to look a little bit scarier, we add - some fog to it. This is done by a call to IVideoDriver::setFog(). There - you can set - various fog settings. In this example, we use pixel fog, because it - will work well with the materials we'll use in this example. Please - note that you will have to set the material flag EMF_FOG_ENABLE to 'true' - in every scene node which should be affected by this fog. - -
- To be able to display something interesting, we load a mesh from a .3ds - file which is a room I modeled with anim8or. It is the same room as - - from the specialFX example. Maybe you remember from that tutorial, I - am no good modeler at all and so I totally messed up the texture mapping - in this model, but we can simply repair it with the IMeshManipulator::makePlanarTextureMapping() - method. - -
- Now for the first exciting thing: If we successfully loaded the mesh - we need to apply textures to it. Because we want this room to be displayed - with a very cool material, we have to do a little bit more than just - set the textures. Instead of only loading a color map as usual, we also - load a height map which is simply a grayscale texture. From this height - map, we create a normal map which we will set as second texture of the - room. If you already have a normal map, you could directly set it, but - I simply didn´t find a nice normal map for this texture. The normal - map texture is being generated by the makeNormalMapTexture method - of the VideoDriver. The second parameter specifies the height of the - heightmap. If you set it to a bigger value, the map will look more rocky. - -
- But just setting color and normal map is not everything. The material - we want to use needs some additional informations per vertex like tangents - and binormals. - Because we are too lazy to calculate that information now, we let Irrlicht - do this for us. That's why we call IMeshManipulator::createMeshWithTangents(). - It - creates a mesh copy with tangents and binormals from any other mesh. - After we've done that, we simply create a standard mesh scene node with - this - mesh copy, set color and normal map and adjust some other material settings. - Note that we set EMF_FOG_ENABLE to true to enable fog in the room. - -
- After we've created a room shaded by per pixel lighting, we add a sphere - into it with the same material, but we'll make it transparent. In addition, - because the sphere looks somehow like a familiar planet, we make it - rotate. The procedure is similar as before. The difference is that we - are loading - the mesh from an .x file which already contains a color map so we do - not need to load it manually. But the sphere is a little bit too small - for our needs, so we scale it by the factor 50. - -
- Per pixel lighted materials only look cool when there are moving lights. - So we add some. And because moving lights alone are so boring, we add - billboards - to them, and a whole particle system to one of them. We start with the - first light which is red and has only the billboard attached. - -
- Now the same again, with the second light. The difference is that we - add a particle system to it too. And because the light moves, the particles - of the particlesystem will follow. If you want to know more about how - particle systems are created in Irrlicht, take a look at the specialFx - example. - Maybe you will have noticed that we only add 2 lights, this has a simple - reason: The low end version of this material was written in ps1.1 and - vs1.1, which doesn't allow more lights. You could add a third light - to the scene, but it won't be used to shade the walls. But of course, - this will change in future versions of Irrlicht were higher versions - of pixel/vertex shaders will be implemented too. - -
- Finally, draw everything. That's it. - -
- |
-
- - + + + + + + + +
This tutorial shows how to use one of the built in more complex materials in irrlicht: Per pixel lighted surfaces using normal maps and parallax mapping. It will also show how to use fog and moving particle systems. And don't panic: You do not need any experience with shaders to use these materials in Irrlicht.
+At first, we need to include all headers and do the stuff we always do, like in nearly all other tutorials.
For this example, we need an event receiver, to make it possible for the user to switch between the three available material types. In addition, the event receiver will create some small GUI window which displays what material is currently being used. There is nothing special done in this class, so maybe you want to skip reading it.
We need to add a warning if the materials will not be able to be displayed 100% correctly. This is no problem, they will be rendered using fall back materials, but at least the user should know that it would look better on better hardware. We simply check if the material renderer is able to draw at full quality on the current hardware. The IMaterialRenderer::getRenderCapability() returns 0 if this is the case.
Now for the real fun. We create an Irrlicht Device and start to setup the scene.
Before we start with the interesting stuff, we do some simple things: Store pointers to the most important parts of the engine (video driver, scene manager, gui environment) to safe us from typing too much, add an irrlicht engine logo to the window and a user controlled first person shooter style camera. Also, we let the engine know that it should store all textures in 32 bit. This necessary because for parallax mapping, we need 32 bit textures.
Because we want the whole scene to look a little bit scarier, we add some fog to it. This is done by a call to IVideoDriver::setFog(). There you can set various fog settings. In this example, we use pixel fog, because it will work well with the materials we'll use in this example. Please note that you will have to set the material flag EMF_FOG_ENABLE to 'true' in every scene node which should be affected by this fog.
To be able to display something interesting, we load a mesh from a .3ds file which is a room I modeled with anim8or. It is the same room as from the specialFX example. Maybe you remember from that tutorial, I am no good modeler at all and so I totally messed up the texture mapping in this model, but we can simply repair it with the IMeshManipulator::makePlanarTextureMapping() method.
Now for the first exciting thing: If we successfully loaded the mesh we need to apply textures to it. Because we want this room to be displayed with a very cool material, we have to do a little bit more than just set the textures. Instead of only loading a color map as usual, we also load a height map which is simply a grayscale texture. From this height map, we create a normal map which we will set as second texture of the room. If you already have a normal map, you could directly set it, but I simply didn't find a nice normal map for this texture. The normal map texture is being generated by the makeNormalMapTexture method of the VideoDriver. The second parameter specifies the height of the heightmap. If you set it to a bigger value, the map will look more rocky.
But just setting color and normal map is not everything. The material we want to use needs some additional information per vertex like tangents and binormals. Because we are too lazy to calculate that information now, we let Irrlicht do this for us. That's why we call IMeshManipulator::createMeshWithTangents(). It creates a mesh copy with tangents and binormals from another mesh. After we've done that, we simply create a standard mesh scene node with this mesh copy, set color and normal map and adjust some other material settings. Note that we set EMF_FOG_ENABLE to true to enable fog in the room.
After we've created a room shaded by per pixel lighting, we add a sphere into it with the same material, but we'll make it transparent. In addition, because the sphere looks somehow like a familiar planet, we make it rotate. The procedure is similar as before. The difference is that we are loading the mesh from an .x file which already contains a color map so we do not need to load it manually. But the sphere is a little bit too small for our needs, so we scale it by the factor 50.
Per pixel lighted materials only look cool when there are moving lights. So we add some. And because moving lights alone are so boring, we add billboards to them, and a whole particle system to one of them. We start with the first light which is red and has only the billboard attached.
Now the same again, with the second light. The difference is that we add a particle system to it too. And because the light moves, the particles of the particle system will follow. If you want to know more about how particle systems are created in Irrlicht, take a look at the SpecialFX example. Maybe you will have noticed that we only add 2 lights, this has a simple reason: The low end version of this material was written in ps1.1 and vs1.1, which doesn't allow more lights. You could add a third light to the scene, but it won't be used to shade the walls. But of course, this will change in future versions of Irrlicht where higher versions of pixel/vertex shaders will be implemented too.
Finally, draw everything. That's it.
+ + diff --git a/examples/12.TerrainRendering/tutorial.html b/examples/12.TerrainRendering/tutorial.html index f3d765f9..079e7cc4 100644 --- a/examples/12.TerrainRendering/tutorial.html +++ b/examples/12.TerrainRendering/tutorial.html @@ -1,122 +1,209 @@ - - -
Lets start! | -|||||||
-
-
-
- In the beginning there is nothing special. We include the needed - header files and create an event listener to listen if the user presses - the 'W' key so we can switch to wireframe mode and if he presses 'D' - we toggle to material between solid and detail mapped. -
The start of the main function starts like in most other example. - We ask the user for the desired renderer and start it up. -
First, we add standard stuff to the scene: A nice irrlicht engine - logo, a small help text, a user controlled camera, and we disable - the mouse cursor. -
Here comes the terrain renderer scene node: We add it just like
- any other scene node to the scene using ISceneManager::addTerrainSceneNode().
- The only parameter we use is a file name to the heightmap we use.
- A heightmap is simply a gray scale texture. The terrain renderer loads
- it and creates the 3D terrain from it.
To be able to do collision with the terrain, we create a triangle - selector. If you want to know what triangle selectors do, just take - a look into the collision tutorial. The terrain triangle selector - works together with the terrain. To demonstrate this, we create a - collision response animator and attach it to the camera, so that the - camera will not be able to fly through the terrain. -
To make the user be able to switch between normal and wireframe mode, - we create an instance of the event reciever from above and let Irrlicht - know about it. In addition, we add the skybox which we already used - in lots of Irrlicht examples. -
That's it, draw everything. Now you know how to use terrain in Irrlicht. -
- |
-
- - + + + + + + + +
This tutorial will briefly show how to use the terrain renderer of Irrlicht. It will also show the terrain renderer triangle selector to be able to do collision detection with terrain.
+Note that the Terrain Renderer in Irrlicht is based on Spintz' GeoMipMapSceneNode, lots of thanks go to him. DeusXL provided a new elegant simple solution for building larger area on small heightmaps -> terrain smoothing.
+In the beginning there is nothing special. We include the needed header files and create an event listener to listen if the user presses certain keys.
The start of the main function starts like in most other example. We ask the user for the desired renderer and start it up. This time with the advanced parameter handling.
First, we add standard stuff to the scene: A nice irrlicht engine logo, a small help text, a user controlled camera, and we disable the mouse cursor.
Here comes the terrain renderer scene node: We add it just like any other scene node to the scene using ISceneManager::addTerrainSceneNode(). The first parameter is a file name to the heightmap we use. A heightmap is simply a gray scale texture. The terrain renderer loads it and creates the 3D terrain from it.
+To make the terrain look bigger, we change it's scale factor to (40, 4.4, 40). Because we don't have any dynamic lights in the scene, we switch off the lighting, and we set the file terrain-texture.jpg as texture for the terrain and detailmap3.jpg as second texture, called detail map. At last, we set the scale values for the texture: The first texture will be repeated only one time over the whole terrain, and the second one (detail map) 20 times.
To be able to do collision with the terrain, we create a triangle selector. If you want to know what triangle selectors do, just take a look into the collision tutorial. The terrain triangle selector works together with the terrain. To demonstrate this, we create a collision response animator and attach it to the camera, so that the camera will not be able to fly through the terrain.
If you need access to the terrain data you can also do this directly via the following code fragment.
To make the user be able to switch between normal and wireframe mode, we create an instance of the event receiver from above and let Irrlicht know about it. In addition, we add the skybox which we already used in lots of Irrlicht examples and a skydome, which is shown mutually exclusive with the skybox by pressing 'S'.
That's it, draw everything.
Now you know how to use terrain in Irrlicht.
++ + diff --git a/examples/13.RenderToTexture/tutorial.html b/examples/13.RenderToTexture/tutorial.html index 26340a3e..0b4c4351 100644 --- a/examples/13.RenderToTexture/tutorial.html +++ b/examples/13.RenderToTexture/tutorial.html @@ -1,244 +1,209 @@ - - -
Lets start! | -||||||
-
-
-
- In the beginning, everything as usual. Include the needed headers, - ask the user for the rendering driver, create the Irrlicht Device: -
Now, we load an animated mesh to be displayed. As in most examples,
- we'll take the fairy md2 model. The difference here: We set the shininess
To make specular highlights appear on the model, we need a dynamic - light in the scene. We add one directly in vicinity of the model. - In addition, to make the model not that dark, we set the ambient light - to gray. -
The next is just some standard stuff: Add a user controlled camera - to the scene, disable mouse cursor, and add a test cube and let it - rotate to make the scene more interesting. -
To test out the render to texture feature, we need a render target - texture. These are not like standard textures, but need to be created - first. To create one, we call IVideoDriver::createRenderTargetTexture() - and specify the size of the texture. Please don't use sizes bigger - than the frame buffer for this, because the render target shares the - zbuffer with the frame buffer. And because we want to render the scene - not from the user camera into the texture, we add another, fixed camera - to the scene. But before we do all this, we check if the current running - driver is able to render to textures. If it is not, we simply display - a warning text. -
Nearly finished. Now we need to draw everything. Every frame, we
- draw the scene twice. Once from the fixed camera into the render target
- texture and once as usual. When rendering into the render target,
- we need to disable the visibilty of the test cube, because it has
- the render target texture applied to it.
|
-
- - + + + + + + + +
This tutorial shows how to render to a texture using Irrlicht. Render to texture is a feature where everything which would usually be rendered to the screen is instead written to a (special) texture. This can be used to create nice special effects. In addition, this tutorial shows how to enable specular highlights.
+In the beginning, everything as usual. Include the needed headers, ask the user for the rendering driver, create the Irrlicht device:
Now, we load an animated mesh to be displayed. As in most examples, we'll take the fairy md2 model. The difference here: We set the shininess of the model to a value other than 0 which is the default value. This enables specular highlights on the model if dynamic lighting is on. The value influences the size of the highlights.
To make specular highlights appear on the model, we need a dynamic light in the scene. We add one directly in vicinity of the model. In addition, to make the model not that dark, we set the ambient light to gray.
The next is just some standard stuff: Add a test cube and let it rotate to make the scene more interesting. The user defined camera and cursor setup is made later on, right before the render loop.
To test out the render to texture feature, we need to define our new rendertarget. The rendertarget will need one texture to receive the result you would otherwise see on screen and one texture which is used as depth-buffer.
+(Note: If you worked with older Irrlicht versions (before 1.9) you might be used to only create a rendertarget texture and no explicit rendertarget. While that's still possible, it's no longer recommended.)
+The rendertarget textures are not like standard textures, but need to be created first. To create them, we call IVideoDriver::addRenderTargetTexture() and specify the size of the texture and the type. For depth-maps you can use types ECF_D16, ECF_D32 or ECF_D24S8. When ECF_D24S8 you can also use a stencil-buffer.
+Because we want to render the scene not from the user camera into the texture, we add another fixed camera to the scene. But before we do all this, we check if the current running driver is able to render to textures. If it is not, we simply display a warning text.
Nearly finished. Now we need to draw everything. Every frame, we draw the scene twice. Once from the fixed camera into the render target texture and once as usual. When rendering into the render target, we need to disable the visibility of the test cube, because it has the render target texture applied to it. That's it, wasn't too complicated I hope. :)
+ + diff --git a/examples/14.Win32Window/tutorial.html b/examples/14.Win32Window/tutorial.html index 6c5d5baa..849c474f 100644 --- a/examples/14.Win32Window/tutorial.html +++ b/examples/14.Win32Window/tutorial.html @@ -1,247 +1,210 @@ - - -
Lets start! | -|||
-
-
-
- In the begining, we create a windows window using the windows API. - I'm not going to explain this code, because it is windows specific. - See the MSDN or a windows book for details. -
So now that we have some window, we can create an Irrlicht device - inside of it. We use Irrlicht createEx() function for this. We only - need the handle (HWND) to that window, set it as windowsID parameter - and start up the engine as usual. That's it. -
Now the only thing missing is the drawing loop using IrrlichtDevice::run().
- We do this as usual. But instead of this, there is another possibility:
- You can also simply use your own message loop using GetMessage, DispatchMessage
- and whatever. Calling
That's it, Irrlicht now runs in your own windows window. - |
-
- - + + + + + + + +
This example only runs under MS Windows and demonstrates that Irrlicht can render inside a win32 window. MFC and .NET Windows.Forms windows are possible, too.
+In the beginning, we create a windows window using the windows API. I'm not going to explain this code, because it is windows specific. See the MSDN or a windows book for details.
Now ask for the driver and create the Windows specific window.
So now that we have some window, we can create an Irrlicht device inside of it. We use Irrlicht createEx() function for this. We only need the handle (HWND) to that window, set it as windowsID parameter and start up the engine as usual. That's it.
Now the only thing missing is the drawing loop using IrrlichtDevice::run(). We do this as usual. But instead of this, there is another possibility: You can also simply use your own message loop using GetMessage, DispatchMessage and whatever. Calling Device->run() will cause Irrlicht to dispatch messages internally too. You need not call Device->run() if you want to do your own message dispatching loop, but Irrlicht will not be able to fetch user input then and you have to do it on your own using the window messages, DirectInput, or whatever.
The alternative, own message dispatching loop without Device->run() would look like this:
MSG msg; while (true) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg);
+if (msg.message == WM_QUIT) break; }
+advance virtual time device->getTimer()->tick();
+draw engine picture driver->beginScene(true, true, 0, (key=='c')?hIrrlichtWindow:0); smgr->drawAll(); driver->endScene(); }
That's it, Irrlicht now runs in your own windows window.
++ + diff --git a/examples/15.LoadIrrFile/tutorial.html b/examples/15.LoadIrrFile/tutorial.html index e3e4a6b2..3416c8f2 100644 --- a/examples/15.LoadIrrFile/tutorial.html +++ b/examples/15.LoadIrrFile/tutorial.html @@ -1,129 +1,210 @@ - - -
- |
- Tutorial 15. Load .irr File |
-
- Since version 1.1, Irrlicht is able to save and load the full scene - graph into an .irr file, an xml based format. There is also an editor - available to edit those files, named irrEdit on http://www.ambiera.com/irredit, - which can also be used as world and particle editor. This tutorial shows - how to use .irr files. -
|
-
- Lets start! |
- |||
-
- Lets start: Create an Irrlicht device and setup the window. -
Now load our .irr file. .irr files can store the whole scene graph - including animators, materials and particle systems. And there is also - the possibility to store arbitrary user data for every scene node in - that file. To keep this example simple, we are simply loading the scene - here. See the documentation at ISceneManager::loadScene and ISceneManager::saveScene - for more information. So to load and display a complicated huge scene, - we only need a single call to loadScene(). -
That was it already. Now add a camera and draw the scene. -
- |
-
-
- - + + + + + + + +
Since version 1.1, Irrlicht is able to save and load the full scene graph into an .irr file, an xml based format. There is an editor available to edit those files, named irrEdit (http://www.ambiera.com/irredit) which can also be used as world and particle editor. This tutorial shows how to use .irr files.
+Lets start: Create an Irrlicht device and setup the window.
Now load our .irr file. .irr files can store the whole scene graph including animators, materials and particle systems. And there is also the possibility to store arbitrary user data for every scene node in that file. To keep this example simple, we are simply loading the scene here. See the documentation at ISceneManager::loadScene and ISceneManager::saveScene for more information. So to load and display a complicated huge scene, we only need a single call to loadScene().
You might have to work around some minor problems in current .irr loader:
+ + diff --git a/examples/16.Quake3MapShader/tutorial.html b/examples/16.Quake3MapShader/tutorial.html new file mode 100644 index 00000000..6397cdf5 --- /dev/null +++ b/examples/16.Quake3MapShader/tutorial.html @@ -0,0 +1,206 @@ + + + + + + + +
This tutorial shows how to load a Quake 3 map into the engine, create a SceneNode for optimizing the speed of rendering and how to create a user controlled camera.
+Lets start like the HelloWorld example: We include the irrlicht header files and an additional file to be able to ask the user for a driver type using the console.
define which Quake3 Level should be loaded
Again, to be able to use the Irrlicht.DLL file, we need to link with the Irrlicht.lib. We could set this option in the project settings, but to make it easy, we use a pragma comment lib:
A class to produce a series of screenshots
Ok, lets start.
Like in the HelloWorld example, we create an IrrlichtDevice with createDevice(). The difference now is that we ask the user to select which hardware accelerated driver to use. The Software device would be too slow to draw a huge Quake 3 map, but just for the fun of it, we make this decision possible too.
Get a pointer to the video driver and the SceneManager so that we do not always have to write device->getVideoDriver() and device->getSceneManager().
To display the Quake 3 map, we first need to load it. Quake 3 maps are packed into .pk3 files, which are nothing other than .zip files. So we add the .pk3 file to our FileSystem. After it was added, we are able to read from the files in that archive as they would directly be stored on disk.
Now we can load the mesh by calling getMesh(). We get a pointer returned to a IAnimatedMesh. As you know, Quake 3 maps are not really animated, they are only a huge chunk of static geometry with some materials attached. Hence the IAnimated mesh consists of only one frame, so we get the "first frame" of the "animation", which is our quake level and create an Octree scene node with it, using addOctreeSceneNode(). The Octree optimizes the scene a little bit, trying to draw only geometry which is currently visible. An alternative to the Octree would be a AnimatedMeshSceneNode, which would draw always the complete geometry of the mesh, without optimization. Try it out: Write addAnimatedMeshSceneNode instead of addOctreeSceneNode and compare the primitives drawn by the video driver. (There is a getPrimitiveCountDrawed() method in the IVideoDriver class). Note that this optimization with the Octree is only useful when drawing huge meshes consisting of lots of geometry.
add the geometry mesh to the Scene ( polygon & patches ) The Geometry mesh is optimised for faster drawing
now construct SceneNodes for each Shader The Objects are stored in the quake mesh scene::E_Q3_MESH_ITEMS and the Shader ID is stored in the MaterialParameters mostly dark looking skulls and moving lava.. or green flashing tubes?
Now we only need a Camera to look at the Quake 3 map. And we want to create a user controlled camera. There are some different cameras available in the Irrlicht engine. For example the Maya Camera which can be controlled comparable to the camera in Maya: Rotate with left mouse button pressed, Zoom with both buttons pressed, translate with right mouse button pressed. This could be created with addCameraSceneNodeMaya(). But for this example, we want to create a camera which behaves like the ones in first person shooter games (FPS).
so we need a good starting Position in the level. we can ask the Quake3 Loader for all entities with class_name "info_player_deathmatch" we choose a random launch
notEndList = ( index < (s32) entityList.size () && entityList[index].name == search.name && (device->getTimer()->getRealTime() >> 3 ) & 1 );
The mouse cursor needs not to be visible, so we make it invisible.
We have done everything, so lets draw it. We also write the current frames per second and the drawn primitives to the caption of the window. The 'if (device->isWindowActive())' line is optional, but prevents the engine render to set the position of the mouse cursor after task switching when other program are active.
In the end, delete the Irrlicht device.
+ + diff --git a/examples/17.HelloWorld_Mobile/main.cpp b/examples/17.HelloWorld_Mobile/main.cpp index 9db5806f..69374c26 100644 --- a/examples/17.HelloWorld_Mobile/main.cpp +++ b/examples/17.HelloWorld_Mobile/main.cpp @@ -1,8 +1,9 @@ -/** Deprecated. This was Example 017 Helloworld mobile for WinCE 6. - But WinCE6 support has been removed for Irrlicht 1.9. +/** Example 017 Helloworld mobile for WinCE 6. DEPRECATED + This was Example 017 Helloworld mobile for WinCE 6. + But WinCE6 support has been removed for Irrlicht 1.9. If you still need that please use Irrlicht 1.8 or svn revision 5045 which was the last one to include it. - Sources still kept for now as it compiles on other platform too. And we might use this example again + Sources still kept for now as it compiles on other platform too. And we might use this example again once we support Windows RT. */ @@ -101,7 +102,7 @@ public: virtual SMaterial& getMaterial(u32 i) { return Material; - } + } }; /*! @@ -186,7 +187,7 @@ int example_customscenenode() // create engine and camera EventReceiver_basic receiver(device); device->setEventReceiver(&receiver); - + IVideoDriver* driver = device->getVideoDriver(); ISceneManager* smgr = device->getSceneManager(); IGUIEnvironment* guienv = device->getGUIEnvironment(); @@ -194,10 +195,10 @@ int example_customscenenode() smgr->addCameraSceneNode(0, vector3df(0,-40,0), vector3df(0,0,0)); - CSampleSceneNode *myNode = + CSampleSceneNode *myNode = new CSampleSceneNode(smgr->getRootSceneNode(), smgr, 666); - ISceneNodeAnimator* anim = + ISceneNodeAnimator* anim = smgr->createRotationAnimator(vector3df(0.8f, 0, 0.8f)); if(anim) @@ -293,7 +294,7 @@ int example_terrain() IrrlichtDevice *device = startup(); if (device == 0) return 1; // could not create selected driver. - + /* First, we add standard stuff to the scene: A nice irrlicht engine logo, a small help text, a user controlled camera, and we disable @@ -363,7 +364,7 @@ int example_terrain() driver->getTexture("../../media/terrain-texture.jpg")); terrain->setMaterialTexture(1, driver->getTexture("../../media/detailmap3.jpg")); - + terrain->setMaterialType(video::EMT_DETAIL_MAP); terrain->scaleTexture(1.0f, 20.0f); @@ -378,7 +379,7 @@ int example_terrain() through the terrain. */ - // create triangle selector for the terrain + // create triangle selector for the terrain scene::ITriangleSelector* selector = smgr->createTerrainTriangleSelector(terrain, 0); terrain->setTriangleSelector(selector); diff --git a/examples/17.HelloWorld_Mobile/tutorial.html b/examples/17.HelloWorld_Mobile/tutorial.html new file mode 100644 index 00000000..e0e6d3c3 --- /dev/null +++ b/examples/17.HelloWorld_Mobile/tutorial.html @@ -0,0 +1,207 @@ + + + + + + + +
Sources still kept for now as it compiles on other platform too. And we might use this example again once we support Windows RT.
! Startup a Windows Mobile Device
!
!
The start of the main function starts like in most other example. We ask the user for the desired renderer and start it up. This time with the advanced parameter handling.
First, we add standard stuff to the scene: A nice irrlicht engine logo, a small help text, a user controlled camera, and we disable the mouse cursor.
Here comes the terrain renderer scene node: We add it just like any other scene node to the scene using ISceneManager::addTerrainSceneNode(). The only parameter we use is a file name to the heightmap we use. A heightmap is simply a gray scale texture. The terrain renderer loads it and creates the 3D terrain from it.
+To make the terrain look more big, we change the scale factor of it to (40, 4.4, 40). Because we don't have any dynamic lights in the scene, we switch off the lighting, and we set the file terrain-texture.jpg as texture for the terrain and detailmap3.jpg as second texture, called detail map. At last, we set the scale values for the texture: The first texture will be repeated only one time over the whole terrain, and the second one (detail map) 20 times.
To be able to do collision with the terrain, we create a triangle selector. If you want to know what triangle selectors do, just take a look into the collision tutorial. The terrain triangle selector works together with the terrain. To demonstrate this, we create a collision response animator and attach it to the camera, so that the camera will not be able to fly through the terrain.
If you need access to the terrain data you can also do this directly via the following code fragment.
To make the user be able to switch between normal and wireframe mode, we create an instance of the event receiver from above and let Irrlicht know about it. In addition, we add the skybox which we already used in lots of Irrlicht examples and a skydome, which is shown mutually exclusive with the skybox by pressing 'S'.
To let the mesh look a little bit nicer, we change its material. We disable lighting because we do not have a dynamic light in here, and the mesh would be totally black otherwise. Then we set the frame loop, such that the predefined STAND animation is used. And last, we apply a texture to the mesh. Without it the mesh would be drawn using only a color.
To look at the mesh, we place a camera into 3d space at the position (0, 30, -40). The camera looks from there to (0,5,0), which is approximately the place where our md2 model is.
+ + diff --git a/examples/18.SplitScreen/main.cpp b/examples/18.SplitScreen/main.cpp index 600b7bf8..85aa403d 100644 --- a/examples/18.SplitScreen/main.cpp +++ b/examples/18.SplitScreen/main.cpp @@ -170,6 +170,9 @@ Sounds a little complicated, but you'll see it isn't: while(device->run()) { + // Don't reset mouse cursor when window is not active + camera[3]->setInputReceiverEnabled(device->isWindowActive()); + //Set the viewpoint to the whole screen and begin scene driver->setViewPort(rect
A tutorial by Max Winkel.
+In this tutorial we'll learn how to use splitscreen (e.g. for racing-games) with Irrlicht. We'll create a viewport divided into 4 parts, with 3 fixed cameras and one user-controlled.
+Ok, let's start with the headers (I think there's nothing to say about it)
Now we'll define the resolution in a constant for use in initializing the device and setting up the viewport. In addition we set up a global variable saying splitscreen is active or not.
Now we need four pointers to our cameras which are created later:
In our event-receiver we switch the SplitScreen-variable, whenever the user press the S-key. All other events are sent to the FPS camera.
Ok, now the main-function: First, we initialize the device, get the SourceManager and VideoDriver, load an animated mesh from .md2 and a map from .pk3. Because that's old stuff, I won't explain every step. Just take care of the maps position.
Now we create our four cameras. One is looking at the model from the front, one from the top and one from the side. In addition there's a FPS-camera which can be controlled by the user.
Create a variable for counting the fps and hide the mouse:
There wasn't much new stuff - till now! Only by defining four cameras, the game won't be splitscreen. To do this you need several steps:
Sounds a little complicated, but you'll see it isn't:
As you can probably see, the image is rendered for every viewport separately. That means, that you'll loose much performance. Ok, if you're asking "How do I have to set the viewport + to get this or that screen?", don't panic. It's really easy: In the rect-function you define 4 coordinates:
That means, if you want to split the screen into 2 viewports you would give the following coordinates:
If you didn't fully understand, just play around with the example to check out what happens.
+Now we just view the current fps and shut down the engine, when the user wants to:
That's it! Just compile and play around with the program. Note: With the S-Key you can switch between using splitscreen and not.
++ + diff --git a/examples/19.MouseAndJoystick/tutorial.html b/examples/19.MouseAndJoystick/tutorial.html new file mode 100644 index 00000000..f96a47a1 --- /dev/null +++ b/examples/19.MouseAndJoystick/tutorial.html @@ -0,0 +1,205 @@ + + + + + + + +
This tutorial builds on example 04.Movement which showed how to handle keyboard events in Irrlicht. Here we'll handle mouse events and joystick events, if you have a joystick connected and a device that supports joysticks. These are currently Windows, Linux and SDL devices.
Just as we did in example 04.Movement, we'll store the latest state of the mouse and the first joystick, updating them as we receive events.
The event receiver for keeping the pressed keys is ready, the actual responses will be made inside the render loop, right before drawing the scene. So lets just create an irr::IrrlichtDevice and the scene node we want to move. We also create some other additional scene nodes, to show that there are also some different possibilities to move and animate scene nodes.
We'll create an arrow mesh and move it around either with the joystick axis/hat, or make it follow the mouse pointer.
In the end, delete the Irrlicht device.
+ + diff --git a/examples/20.ManagedLights/tutorial.html b/examples/20.ManagedLights/tutorial.html new file mode 100644 index 00000000..4bf4b290 --- /dev/null +++ b/examples/20.ManagedLights/tutorial.html @@ -0,0 +1,210 @@ + + + + + + + +
Written by Colin MacDonald. This tutorial explains the use of the Light Manager of Irrlicht. It enables the use of more dynamic light sources than the actual hardware supports. Further applications of the Light Manager, such as per scene node callbacks, are left out for simplicity of the example.
Normally, you are limited to 8 dynamic lights per scene: this is a hardware limit. If you want to use more dynamic lights in your scene, then you can register an optional light manager that allows you to to turn lights on and off at specific point during rendering. You are still limited to 8 lights, but the limit is per scene node.
+This is completely optional: if you do not register a light manager, then a default distance-based scheme will be used to prioritise hardware lights based on their distance from the active camera.
+NO_MANAGEMENT disables the light manager and shows Irrlicht's default light behaviour. The 8 lights nearest to the camera will be turned on, and other lights will be turned off. In this example, this produces a funky looking but incoherent light display.
+LIGHTS_NEAREST_NODE shows an implementation that turns on a limited number of lights per mesh scene node. If finds the 3 lights that are nearest to the node being rendered, and turns them on, turning all other lights off. This works, but as it operates on every light for every node, it does not scale well with many lights. The flickering you can see in this demo is due to the lights swapping their relative positions from the cubes (a deliberate demonstration of the limitations of this technique).
+LIGHTS_IN_ZONE shows a technique for turning on lights based on a 'zone'. Each empty scene node is considered to be the parent of a zone. When nodes are rendered, they turn off all lights, then find their parent 'zone' and turn on all lights that are inside that zone, i.e. are descendents of it in the scene graph. This produces true 'local' lighting for each cube in this example. You could use a similar technique to locally light all meshes in (e.g.) a room, without the lights spilling out to other rooms.
+This light manager is also an event receiver; this is purely for simplicity in this example, it's neither necessary nor recommended for a real application.
Add several "zones". You could use this technique to light individual rooms, for example.
+ + diff --git a/examples/21.Quake3Explorer/tutorial.html b/examples/21.Quake3Explorer/tutorial.html new file mode 100644 index 00000000..e798b49a --- /dev/null +++ b/examples/21.Quake3Explorer/tutorial.html @@ -0,0 +1,218 @@ + + + + + + + +
This tutorial shows how to load different Quake 3 maps.
+Features:
You can download the Quake III Arena demo ( copyright id software ) at the following location: ftp://ftp.idsoftware.com/idstuff/quake3/win32/q3ademo.exe
+Copyright 2006-2011 Burningwater, Thomas Alten
Game Data is used to hold Data which is needed to drive the game
set default settings
Load the current game State from a typical quake3 cfg file
Store the current game State in a quake3 configuration file
Representing a player
End player
create a new player
so we need a good starting Position in the level. we can ask the Quake3 Loader for all entities with class_name "info_player_deathmatch"
set Player position from saved coordinates
set the Animation of the player and weapon
GUI Elements
CQuake3EventHandler controls the game
Constructor
create the GUI
Add an Archive to the FileSystems and updates the GUI
clears the Map in Memory
Load new map
add the geometry mesh to the Scene ( polygon & patches ) The Geometry mesh is optimised for faster drawing
now construct SceneNodes for each Shader The Objects are stored in the quake mesh E_Q3_MESH_ITEMS and the Shader ID is stored in the MaterialParameters mostly dark looking skulls and moving lava.. or green flashing tubes?
Now construct Models from Entity List
Adds a SceneNode with an icon to the Scene Tree
Handle game input
set debug map data on/off debugState = debugState == EDS_OFF ? EDS_NORMALS | EDS_MESH_WIRE_OVERLAY | EDS_BBOX_ALL: EDS_OFF;
useItem
if (irrKlang) { audio::ISound* sound = irrKlang->play3D(impactSound, Impacts[i].pos, false, false, true);
+if (sound) { adjust max value a bit to make to sound of an impact louder sound->setMinDistance(400); sound->drop(); } }
render
update the generic scene node
The main game states
The main routine, doing all setup
+ + diff --git a/examples/22.MaterialViewer/tutorial.html b/examples/22.MaterialViewer/tutorial.html new file mode 100644 index 00000000..20bc5d38 --- /dev/null +++ b/examples/22.MaterialViewer/tutorial.html @@ -0,0 +1,206 @@ + + + + + + + +
This example can be used to play around with material settings and watch the results. Only the default non-shader materials are used in here.
+You have a node with a mesh, one dynamic light and global ambient light to play around with. You can move the light with cursor-keys and +/-. You can move the camera while left-mouse button is clicked.
Variables within the empty namespace are globals which are restricted to this file.
Returns a new unique number on each call.
Find out which vertex-type is needed for the given material type.
Custom GUI-control to edit colorvalues.
Custom GUI-control for to edit all colors typically used in materials and lights
GUI-Control to offer a selection of available textures.
Control which allows setting some of the material values for a meshscenenode
Control to allow setting the color values of a lightscenenode.
Main application class
Event handler
Update one frame
Short main as most is done in classes.
main application loop
+ + diff --git a/examples/23.SMeshHandling/tutorial.html b/examples/23.SMeshHandling/tutorial.html new file mode 100644 index 00000000..ebb196ee --- /dev/null +++ b/examples/23.SMeshHandling/tutorial.html @@ -0,0 +1,209 @@ + + + + + + + +
A tutorial by geoff.
+In this tutorial we'll learn how to create custom meshes and deal with them with Irrlicht. We'll create an interesting heightmap with some lighting effects. With keys 1,2,3 you can choose a different mesh layout, which is put into the mesh buffers as desired. All positions, normals, etc. are updated accordingly.
+Ok, let's start with the headers (I think there's nothing to say about it)
This is the type of the functions which work out the colour.
Here comes a set of functions which can be used for coloring the nodes while creating the mesh.
The type of the functions which generate the heightmap. x and y range between -0.5 and 0.5, and s is the scale of the heightmap.
A simple class for representing heightmaps. Most of this should be obvious.
The only difficult part. This considers the normal at (x, y) to be the cross product of the vectors between the adjacent points in the horizontal and vertical directions.
+s is a scaling factor, which is necessary if the height units are different from the coordinate units; for example, if your map has heights in meters and the coordinates are in units of a kilometer.
A class which generates a mesh from a heightmap.
Our event receiver implementation, taken from tutorial 4.
Much of this is code taken from some of the examples. We merely set up a mesh from a heightmap, light it with a moving light, and allow the user to navigate around it.
Create the custom mesh and initialize with a heightmap
Just a usual render loop with event handling. The custom mesh is a usual part of the scene graph which gets rendered by drawAll.
That's it! Just compile and play around with the program.
++ + diff --git a/examples/24.CursorControl/tutorial.html b/examples/24.CursorControl/tutorial.html new file mode 100644 index 00000000..c374ea19 --- /dev/null +++ b/examples/24.CursorControl/tutorial.html @@ -0,0 +1,205 @@ + + + + + + + +
Show how to modify cursors and offer some useful tool-functions for creating cursors. It can also be used for experiments with the mouse in general.
Structure to allow delayed execution of some actions.
Add another icon which the user can click and select as cursor later on.
Here we create a hardware cursor from a sprite
Helper function to print mouse event names into a stringw
Helper function to print all the state information which get from a mouse-event into a stringw
A typical event receiver.
Replace an existing cursor icon by another icon. The user has to select both - the icon which should be replaced and the icon which will replace it.
This does replace the icon.
Do also show the new icon.
Find out which cursor the user selected
Here we set the new cursor icon which will now be used within our window.
Use several imagefiles as animation frames for a sprite which can be used as cursor icon. The images in those files all need to have the same size. Return sprite index on success or -1 on failure
Use several images within one imagefile as animation frames for a sprite which can be used as cursor icon The sizes of the icons within that file all need to have the same size Return sprite index on success or -1 on failure
Create a non-animated icon from the given file and position and put it into the spritebank. We can use this icon later on in a cursor.
Create sprites which then can be used as cursor icons.
+ + diff --git a/examples/25.XmlHandling/main.cpp b/examples/25.XmlHandling/main.cpp index d022e5c2..c12afe2e 100644 --- a/examples/25.XmlHandling/main.cpp +++ b/examples/25.XmlHandling/main.cpp @@ -76,7 +76,8 @@ public: /* Load xml from disk, overwrite default settings The xml we are trying to load has the following structure - settings nested in sections nested in the root node, like so + settings nested in sections nested in the root node, like: + \verbatim
+ \endverbatim */ bool load() { diff --git a/examples/25.XmlHandling/tutorial.html b/examples/25.XmlHandling/tutorial.html new file mode 100644 index 00000000..7fd4c938 --- /dev/null +++ b/examples/25.XmlHandling/tutorial.html @@ -0,0 +1,219 @@ + + + + + + + +@@ -87,6 +88,7 @@ public:
Demonstrates loading and saving of configurations via XML
+ +This demo features a fully usable system for configuration handling. The code can easily be integrated into own apps.
+SettingManager class.
+This class loads and writes the settings and manages the options.
+The class makes use of irrMap which is a an associative arrays using a red-black tree it allows easy mapping of a key to a value, along the way there is some information on how to use it.
Load xml from disk, overwrite default settings The xml we are trying to load has the following structure settings nested in sections nested in the root node, like:
<pre> + <?xml version="1.0"?> + <mygame> + <video> + <setting name="driver" value="Direct3D9" /> + <setting name="fullscreen" value="0" /> + <setting name="resolution" value="1024x768" /> + </video> + </mygame> + </pre>
Application context for global variables
A typical event receiver.
Function to create a video settings dialog This dialog shows the current settings from the configuration xml and allows them to be changed
The main function. Creates all objects and does the XML handling.
+ + diff --git a/examples/26.OcclusionQuery/tutorial.html b/examples/26.OcclusionQuery/tutorial.html new file mode 100644 index 00000000..f9ec97c7 --- /dev/null +++ b/examples/26.OcclusionQuery/tutorial.html @@ -0,0 +1,207 @@ + + + + + + + +
This tutorial shows how to speed up rendering by use of the OcclusionQuery feature. The usual rendering tries to avoid rendering of scene nodes by culling those nodes which are outside the visible area, the view frustum. However, this technique does not cope with occluded objects which are still in the line of sight, but occluded by some larger object between the object and the eye (camera). Occlusion queries check exactly that. The queries basically measure the number of pixels that a previous render left on the screen. Since those pixels cannot be recognized at the end of a rendering anymore, the pixel count is measured directly when rendering. Thus, one needs to render the occluder (the object in front) first. This object needs to write to the z-buffer in order to become a real occluder. Then the node is rendered and in case a z-pass happens, i.e. the pixel is written to the framebuffer, the pixel is counted in the query. The result of a query is the number of pixels which got through. One can, based on this number, judge if the scene node is visible enough to be rendered, or if the node should be removed in the next round. Also note that the number of pixels is a safe over approximation in general. The pixels might be overdrawn later on, and the GPU tries to avoid inaccuracies which could lead to false negatives in the queries.
+As you might have recognized already, we had to render the node to get the numbers. So where's the benefit, you might say. There are several ways where occlusion queries can help. It is often a good idea to just render the bbox of the node instead of the actual mesh. This is really fast and is a safe over approximation. If you need a more exact render with the actual geometry, it's a good idea to render with just basic solid material. Avoid complex shaders and state changes through textures. There's no need while just doing the occlusion query. At least if the render is not used for the actual scene. This is the third way to optimize occlusion queries. Just check the queries every 5th or 10th frame, or even less frequent. This depends on the movement speed of the objects and camera.
We need keyboard input events to switch some parameters
We create an irr::IrrlichtDevice and the scene nodes. One occluder, one occluded. The latter is a complex sphere, which has many triangles.
Create the node to be occluded. We create a sphere node with high poly count.
Now we create another node, the occluder. It's a simple plane.
Here we create the occlusion query. Because we don't have a plain mesh scene node (ESNT_MESH or ESNT_ANIMATED_MESH), we pass the base geometry as well. Instead, we could also pass a simpler mesh or the bounding box. But we will use a time based method, where the occlusion query renders to the frame buffer and in case of success (occlusion), the mesh is not drawn for several frames.
We have done everything, just a camera and draw it. We also write the current frames per second and the name of the driver to the caption of the window to examine the render speedup. We also store the time for measuring the time since the last occlusion query ran and store whether the node should be visible in the next frames.
First, we draw the scene, possibly without the occluded element. This is necessary because we need the occluder to be drawn first. You can also use several scene managers to collect a number of possible occluders in a separately rendered scene.
Once in a while, here every 100 ms, we check the visibility. We run the queries, update the pixel value, and query the result. Since we already rendered the node we render the query invisible. The update is made blocking, as we need the result immediately. If you don't need the result immediately, e.g. because you have other things to render, you can call the update non-blocking. This gives the GPU more time to pass back the results without flushing the render pipeline. If the update was called non-blocking, the result from getOcclusionQueryResult is either the previous value, or 0xffffffff if no value has been generated at all, yet. The result is taken immediately as visibility flag for the node.
In the end, delete the Irrlicht device.
That's it. Compile and play around with the program.
++ + diff --git a/examples/27.PostProcessing/tutorial.html b/examples/27.PostProcessing/tutorial.html new file mode 100644 index 00000000..505c3841 --- /dev/null +++ b/examples/27.PostProcessing/tutorial.html @@ -0,0 +1,209 @@ + + + + + + + +
This tutorial shows how to implement post processing for D3D9 and OpenGL with the engine. In order to do post processing, scene objects are firstly rendered to render target. With the help of screen quad, the render target texture is then drawn on the quad with shader-defined effects applied.
+This tutorial shows how to create a screen quad. It also shows how to create a render target texture and associate it with the quad. Effects are defined as shaders which are applied during rendering the quad with the render target texture attached to it.
+A simple color inverse example is presented in this tutorial. The effect is written in HLSL and GLSL.
+ +We include all headers and define necessary variables as we have done before.
We write a class derived from IShaderConstantSetCallBack class and implement OnSetConstants callback interface. In this callback, we will set constants used by the shader. In this example, our HLSL shader needs texture size as input in its vertex shader. Therefore, we set texture size in OnSetConstants callback using setVertexShaderConstant function.
A screen quad is composed of two adjacent triangles with 4 vertices. Vertex [0], [1] and [2] create the first triangle and Vertex [0], [2] and [3] create the second one. To map texture on the quad, UV coordinates are assigned to the vertices. The origin of UV coordinate locates on the top-left corner. And the value of UVs range from 0 to 1.
We start up the engine just like before. Then shader programs are selected according to the driver type.
In this example, high level post processing shaders are loaded for both Direct3D and OpenGL drivers. File pp_d3d9.hlsl is for Direct3D 9, and pp_opengl.frag/pp_opengl.vert are for OpenGL.
Check for hardware capability of executing the corresponding shaders on selected renderer. This is not necessary though.
An animated mesh is loaded to be displayed. As in most examples, we'll take the fairy md2 model.
We create a render target texture (RTT) with the same size as frame buffer. Instead of rendering the scene directly to the frame buffer, we firstly render it to this RTT. Post processing is then applied based on this RTT. RTT size needs not to be the same with frame buffer though. However in this example, we expect the result of rendering to RTT to be consistent with the result of rendering directly to the frame buffer. Therefore, the size of RTT keeps the same with frame buffer.
Post processing is achieved by rendering a screen quad with this RTT (with previously rendered result) as a texture on the quad. A screen quad is geometry of flat plane composed of two adjacent triangles covering the entire area of viewport. In this pass of rendering, RTT works just like a normal texture and is drawn on the quad during rendering. We can then take control of this rendering process by applying various shader-defined materials to the quad. In other words, we can achieve different effect by writing different shaders. This process is called post processing because it normally does not rely on scene geometry. The inputs of this process are just textures, or in other words, just images. With the help of screen quad, we can draw these images on the screen with different effects. For example, we can adjust contrast, make grayscale, add noise, do more fancy effect such as blur, bloom, ghost, or just like in this example, we invert the color to produce negative image. Note that post processing is not limited to use only one texture. It can take multiple textures as shader inputs to provide desired result. In addition, post processing can also be chained to produce compound result.
Let's create material for the quad. Like in other example, we create material using IGPUProgrammingServices and call addShaderMaterialFromFiles, which returns a material type identifier.
Now draw everything. That's all.
+ + diff --git a/examples/28.CubeMapping/tutorial.html b/examples/28.CubeMapping/tutorial.html new file mode 100644 index 00000000..30a5dd1b --- /dev/null +++ b/examples/28.CubeMapping/tutorial.html @@ -0,0 +1,213 @@ + + + + + + + +
Shows usage of cubemap textures and how to do some simple environment mapping. Cubemap textures have images for all 6 directions of a cube in a single texture. Environment is used to reflect the environment around an object onto the object. Cubemaps only work with shader materials which are written to support cube mapping.
+ +Start with the usual includes.
A callback class for our cubemap shader. We need a shader material which maps the cubemap texture to the polygon vertices of objects.
Setting the style to map vertex UV-coordinates to the cubemap textures.
So... the following 2 defines are two different workarounds I found. Both are ugly, which one is better in reality depends probably on the scene. Only use one of those: CUBEMAP_UPSIDE_DOWN_GL_PROJECTION is relatively fast as it just changes the project matrix. The problem is that changing the projection matrix means changing front/backside culling. So every node rendered has to flip the material flags for those.
+CUBEMAP_USPIDE_DOWN_RTT will change the texture memory itself and flip the image upside-down. While easier to do, this involves texture-locking and is very slow.
Render the environment around a node into a cubemap texture.
We want to see everything around the center node, so hide the node itself, otherwise it would be in the way. Then set the camera to that node's position.
Render all 6 directions. Which means simple setting the camera target/up vector to all 6 directions and then render the full scene each time. So yeah - updating an environment cube-map means 6 full renders for each object which needs an environment map. In other words - you generally only want to do that in pre-processing, not in realtime.
Typical setup at the main start.
Create a shader material for cube mapping
Get 6 images forming a cubemap. The coordinate system used in those images seemed to be different than the one in Irrlicht. I decided to leave it like that because it's pretty common that way. If you get cubemap textures which seem to have x/y/z axis named different you'll just have to experiment until you figured out the correct order.
Create a cubemap texture from those images. Note that 6 images become a single texture now.
Create a render target, cubemap render-target-textures and a camera with settings for cube mapping
Add sphere-nodes which will be using the cubemaps as materials. You may also want to experiment with other node-types here!
Add some background which will show up in the environment maps. For first one we use the same textures as used in the spheres. Note the difference between a skybox and a cubemap is that the skybox really uses 6 different textures. While the cubemap uses a single texture created from 6 images.
Another background for comparison and to make it more obvious when the spheres reflect the environment and when they use static cubemaps.
Add some moving node to show the difference between static/dynamic environment maps
Add some UI
Main loop
Check if we want to update the environment maps. Usually not something you'll do every frame, but either once at the star or maybe updating an environment map once in a while.
Flipping projection matrix flips front/backface culling. We only have a skybox so in this case this still would be fast, with more objects it's getting more ugly.
If rendered just once then this node has still a white (or even undefined) texture at this point Just hiding it and render the background when rendering the cubemap for the other node is less noticable than having a big white dot in the environment texture. Render order can matter if you want several environment maps in your scene.
Our rtt's unfortunately don't have mipmaps (sorry, not sure if we can get that somehow...) So if we want mipmaps in the dynamic cubemap we have to copy it to a non-rtt texture. Warning: Very, very slow. Far slower than just creating an environment map as this will copy the texture from GPU to main memory - copy it to a new texture, create mip-maps and upload the result back to the GPU.
+ + diff --git a/examples/30.Profiling/tutorial.html b/examples/30.Profiling/tutorial.html new file mode 100644 index 00000000..eb5e8ec9 --- /dev/null +++ b/examples/30.Profiling/tutorial.html @@ -0,0 +1,209 @@ + + + + + + + +
Profiling is used to get runtime information about code code.
+There exist several independent profiling tools. Examples for free profilers are "gprof" for the GNU toolchain and "very sleepy" from codersnotes for Windows. Proprietary tools are for example "VTune" from Intel or "AMD APP Profiler". Those tools work by sampling the running application regularly to get statistic information about the called functions. The way to use them is to compile your application with special flags to include profiling information (some also work with debug information). They also might allow to profile only certain parts of the code, although most can't do that. The sampling is usually rather time-consuming which means the application will be very slow when collecting the profiling data. It's often useful to start with one of those tools to get an overview over the bottlenecks in your application. Those tools have the advantage that they don't need any modifications inside the code.
+Once you need to dig deeper the Irrlicht profiler can help you. It works nearly like a stopwatch. You add start/stop blocks into the parts of your code which you need to check and the Irrlicht profiler will give you then the exact times of execution for those parts. And unlike general profiler tools you don't just get average information about the run-time but also worst-cases. Which tends to be information you really for a stable framerate. Also the Irrlicht profiler has a low overhead and affects only the areas which you want to time. So you can profile applications with nearly original speed.
+Irrlicht itself has such profiling information, which is useful to figure out where the runtime inside the engine is spend. To get that profiling data you need to recompile Irrlicht with IRR_COMPILE_WITH_PROFILING enabled as collecting profiling information is disabled by default for speed reasons.
It's usually a good idea to wrap all your profile code with a define. That way you don't have to worry too much about the runtime profiling itself takes. You can remove the profiling code completely when you release the software by removing a single define.Or sometimes you might want to have several such defines for different areas of your application code.
We have the choice between working with fixed and with automatic profiling id's. Here are some fixed ID's we will be using.
Controlling the profiling display is application specific behavior. We use function keys in our case and play around with all the parameters. In real applications you will likely only need something to make the profiling-display visible/invisible and switch pages while the parameters can be set to fixed values.
Catching keys to control the profiling display and the profiler itself
You can set more filters. This one filters out profile data which was never called.
Some example scenes so we have something to profile
Simple scene with cube and light.
Our typical Irrlicht example quake map.
Stress-test Irrlicht a little bit by creating many objects.
You can never have too many dwarves. So let's make some.
As the profiler uses internally counters for start stop and only takes profile data when that counter is zero we count all recursions as a single call. If you want to profile each call on it's own you have to use explicit start/stop calls and stop the profile id right before the recursive call.
Setup, nothing special here.
Profiler is independent of the device - so we can time the device setup
When working with start/stop you should add a stop to all exit paths. Although in this case it wouldn't matter as we don't do anything with it when we quit here.
A map we use for one of our test-scenes.
Show some info about the controls used in this example
IGUIProfiler is can be used to show active profiling data at runtime.
Get a monospaced font - it's nicer when working with rows of numbers.
Adding ID's has to be done before the start/stop calls. This allows start/stop to be really fast and we still have nice information like names and groups. Groups are created automatically each time an ID with a new group-name is added. Groups exist to sort the display data in a nicer way.
Two timers which run the whole time. One will be continuously updated the other won't.
For comparison show the FPS in the title bar
Times are only updated on stop() calls. So if we want a long-running timer to update we have to stop() and start() it in between. Note that this will also update the call-counter and is rarely needed.
The following CProfileScope's will all do the same thing: they measure the time this loop takes. They call start() when the object is created and call stop() when it is destroyed.
+The first one creates an ID on it's first call and will do constant string-comparisons for the name. It's the slowest, but most comfortable solution. Use it when you just need to run a quick check without the hassle of setting up id's.
Second CProfileScope solution will create a data block on first call. So it's a little bit slower on the first run. But usually that's hardly noticeable.
Last CProfileScope solution is the fastest one. But you must add the id before you can use it like that.
Call a recursive function to show how profiler only counts it once.
If you want to profile only some lines and not a complete scope then you have to work with start() and stop() calls.
If it doesn't matter if the profiler takes some time you can also be lazy and create id's automatically on the spot:
Shutdown.
The profiler is independent of an device - so we can still work with it.
Print a complete overview of the profiling data to the console.
+ + diff --git a/include/EGUIAlignment.h b/include/EGUIAlignment.h index 85f81b46..4876503b 100644 --- a/include/EGUIAlignment.h +++ b/include/EGUIAlignment.h @@ -5,6 +5,8 @@ #ifndef __E_GUI_ALIGNMENT_H_INCLUDED__ #define __E_GUI_ALIGNMENT_H_INCLUDED__ +#include "irrTypes.h" + namespace irr { namespace gui @@ -35,4 +37,3 @@ const c8* const GUIAlignmentNames[] = } // namespace irr #endif // __E_GUI_ALIGNMENT_H_INCLUDED__ - diff --git a/include/IBoneSceneNode.h b/include/IBoneSceneNode.h index 4032bb0a..a96a28be 100644 --- a/include/IBoneSceneNode.h +++ b/include/IBoneSceneNode.h @@ -74,13 +74,13 @@ namespace scene virtual E_BONE_ANIMATION_MODE getAnimationMode() const = 0; //! Get the axis aligned bounding box of this node - virtual const core::aabbox3d