Commit 8db1da30 authored by hybrid's avatar hybrid

Merge revisions 1572:1596 from 1.4 branch: Some late bugfixes of the 1.4.2...

Merge revisions 1572:1596 from 1.4 branch: Some late bugfixes of the 1.4.2 release. Tutorial generation mechanism.

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@1598 dfc29bdd-3216-0410-991c-e03cc46cb475
parent 9d3b46ab
Changes in version 1.5 (... 2008) Changes in version 1.5 (... 2008)
- WindowsCE-Bugfix - WindowsCE-Bugfix
...@@ -209,7 +208,7 @@ Changes in version 1.5 (... 2008) ...@@ -209,7 +208,7 @@ Changes in version 1.5 (... 2008)
- Finally added StarSonata patch with table element and TabControl additions. Table is based on MultiColor listbox by Acki, and has loads of changes by CuteAlien. - Finally added StarSonata patch with table element and TabControl additions. Table is based on MultiColor listbox by Acki, and has loads of changes by CuteAlien.
------------------------------------------- -------------------------------------------
Changes in version 1.4.2 (x.x.2008) Changes in version 1.4.2 (22.9.2008)
- Unified the handling of zwrite enable with transparent materials on all hw accelerated drivers. This means that all transparent materials will now disable ZWrite, ignoring the material flag. - Unified the handling of zwrite enable with transparent materials on all hw accelerated drivers. This means that all transparent materials will now disable ZWrite, ignoring the material flag.
There is a scene manager attribute, though, which will revert this behavior to the usual SMaterial driven way. Simply call There is a scene manager attribute, though, which will revert this behavior to the usual SMaterial driven way. Simply call
......
...@@ -1277,3 +1277,40 @@ New overload/missing method (completing the findLast... and find...Char methods) ...@@ -1277,3 +1277,40 @@ New overload/missing method (completing the findLast... and find...Char methods)
Changed signature (Added return value) Changed signature (Added return value)
string<T>& trim() string<T>& trim()
Changes for Version 1.4.2
-------------------------
This is once more a bugfix release of the 1.4 branch, and hence pretty API-consistent and backward compatible. The major reason to publish this release is the OpenGL bug, which made several OpenGL 2.x drivers run in SW emulation.
However, we also introduced some driver consistency fixes, which might affect your application's behavior. So read through the next points thoroughly.
SceneParameters.h (and general video driver behavior)
The way Irrlicht handles zbuffer writing with transparent materials has changed. This was an issue ever since, because the default behavior in Irrlicht is to disable writing to the z-buffer for all really transparent, i.e. blending materials. This avoids problems with intersecting faces, but can also break renderings. And this is now consistent for both OpenGL and Direct3D.
If transparent materials should use the SMaterial flag for ZWriteEnable just as other material types use the newly introduced attribute scene::ALLOW_ZWRITE_ON_TRANSPARENT like this:
SceneManager->getParameters()->setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true);
All transparent materials will henceforth work as specified by the material flag, until the scenemanager attribute is set to false.
SMaterialLayer.h
The texture matrix now uses irrAllocator for memory handling. This shouldn't be noticeable from the user application (besides fixed heap corruptions on Windows machines), but is still mentioned for completeness.
ISceneNode.h
Documentation error. The docs said that children of a scene node are not visible if the node itself is set to visible. This is of course wrong, children inherit non-visibility of the parent and are hence invisible if the parent is. If the parent is visible, the visibility flag of the child determines its status.
SColor.h
Removed methods (use the unsigned versions and cast in your app if necessary)
inline s32 getRedSigned(u16 color)
inline s32 getGreenSigned(u16 color)
inline s32 getBlueSigned(u16 color)
IParticleSystemSceneNode.h
Changed default values (the old direction default was no real direction)
virtual IParticleAnimatedMeshSceneNodeEmitter* createAnimatedMeshSceneNodeEmitter(...)
virtual IParticleCylinderEmitter* createCylinderEmitter(...)
virtual IParticleMeshEmitter* createMeshEmitter(...)
IBoneSceneNode.h
Changed signature (Made const)
virtual E_BONE_SKINNING_SPACE getSkinningSpace() const=0;
IrrlichtDevice.h
Changed signature (Return value bool instead of void). Returns whether the event has been handled somewhere.
virtual bool postEventFromUser(const SEvent& event) = 0;
/** Example 001 HelloWorld
/*
This Tutorial shows how to set up the IDE for using the This Tutorial shows how to set up the IDE for using the Irrlicht Engine and how
Irrlicht Engine and how to write a simple HelloWorld to write a simple HelloWorld program with it. The program will show how to use
program with it. The program will show how to use the the basics of the VideoDriver, the GUIEnvironment, and the SceneManager.
basics of the VideoDriver, the GUIEnvironment and the Microsoft Visual Studio is used as an IDE, but you will also be able to
SceneManager. understand everything if you are using a different one or even another
Microsoft Visual C++ 6.0 and .NET is used as operating system than windows.
example IDE, but you will also be able to understand everything
if you are using a different one or even another operating You have to include the header file <irrlicht.h> in order to use the engine. The
system than windows. header file can be found in the Irrlicht Engine SDK directory \c include. To let
the compiler find this header file, the directory where it is located has to be
To use the engine, we will have to include the header file specified. This is different for every IDE and compiler you use. Let's explain
irrlicht.h, which can be found in the Irrlicht Engine SDK shortly how to do this in Microsoft Visual Studio:
directory \include.
To let the compiler find this header file, the directory where - If you use Version 6.0, select the Menu Extras -> Options.
it is located should be specified somewhere. This is different
for every IDE and compiler you use. I explain shortly how to
do this in Microsift Visual Studio C++ 6.0 and .NET:
- If you use Version 6.0, select the Menu Extras -> Options.
Select the directories tab, and select the 'Include' Item in the combo box. Select the directories tab, and select the 'Include' Item in the combo box.
Add the \include directory of the irrlicht engine folder to the list of directories. Add the \c include directory of the irrlicht engine folder to the list of
Now the compiler will find the Irrlicht.h header file. We also directories. Now the compiler will find the Irrlicht.h header file. We also
need the irrlicht.lib to be found, so stay need the irrlicht.lib to be found, so stay in that dialog, select 'Libraries'
in that dialog, select 'Libraries' in the combo box and add the in the combo box and add the \c lib/VisualStudio directory.
\lib\VisualStudio directory. \image html "vc6optionsdir.jpg"
\image latex "vc6optionsdir.jpg"
\image html "vc6include.jpg"
\image latex "vc6include.jpg"
- If your IDE is Visual Studio .NET, select Tools -> Options. - If your IDE is Visual Studio .NET, select Tools -> Options.
Select the projects entry and then select VC++ directories. Select the projects entry and then select VC++ directories. Select 'show
Select 'show directories for include files' in the combo box, and directories for include files' in the combo box, and add the \c include
add the \include directory of the irrlicht engine folder to the list of directories. directory of the irrlicht engine folder to the list of directories. Now the
Now the compiler will find the Irrlicht.h header file. We also compiler will find the Irrlicht.h header file. We also need the irrlicht.lib
need the irrlicht.lib to be found, so stay to be found, so stay in that dialog, select 'show directories for Library
in that dialog, select 'show directories for Library files' and add the files' and add the \c lib/VisualStudio directory.
\lib\VisualStudio directory. \image html "vcnetinclude.jpg"
\image latex "vcnetinclude.jpg"
That's it, with your IDE set up like this, you will now be able to
develop applications with the Irrlicht Engine. 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.
*/ */
#include <irrlicht.h> #include <irrlicht.h>
/* /*
In the Irrlicht Engine, everything can be found in the namespace In the Irrlicht Engine, everything can be found in the namespace 'irr'. So if
'irr'. So if you want to use a class of the engine, you have to you want to use a class of the engine, you have to write irr:: before the name
write an irr:: before the name of the class. For example to use of the class. For example to use the IrrlichtDevice write: irr::IrrlichtDevice.
the IrrlichtDevice write: irr::IrrlichtDevice. To get rid of the To get rid of the irr:: in front of the name of every class, we tell the
irr:: in front of the name of every class, we tell the compiler compiler that we use that namespace from now on, and we will not have to write
that we use that namespace from now on, and we will not have to irr:: anymore.
write that 'irr::'.
*/ */
using namespace irr; using namespace irr;
/* /*
There are 5 sub namespaces in the Irrlicht Engine. Take a look There are 5 sub namespaces in the Irrlicht Engine. Take a look at them, you can
at them, you can read a detailed description of them in the read a detailed description of them in the documentation by clicking on the top
documentation by clicking on the top menu item 'Namespace List' menu item 'Namespace List' or by using this link:
or using this link: http://irrlicht.sourceforge.net/docu/namespaces.html. http://irrlicht.sourceforge.net/docu/namespaces.html
Like the irr Namespace, we do not want these 5 sub namespaces now, Like the irr namespace, we do not want these 5 sub namespaces now, to keep this
to keep this example simple. Hence we tell the compiler again example simple. Hence, we tell the compiler again that we do not want always to
that we do not want always to write their names: write their names.
*/ */
using namespace core; using namespace core;
using namespace scene; using namespace scene;
...@@ -68,46 +70,57 @@ using namespace io; ...@@ -68,46 +70,57 @@ using namespace io;
using namespace gui; using namespace gui;
/* /*
To be able to use the Irrlicht.DLL file, we need to link with the To be able to use the Irrlicht.DLL file, we need to link with the Irrlicht.lib.
Irrlicht.lib. We could set this option in the project settings, but We could set this option in the project settings, but to make it easy, we use a
to make it easy, we use a pragma comment lib: pragma comment lib for VisualStudio. On Windows platforms, we have to get rid
of the console window, which pops up when starting a program with main(). This
is done by the second pragma. We could also use the WinMain method, though
losing platform independence then.
*/ */
#ifdef _IRR_WINDOWS_ #ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib") #pragma comment(lib, "Irrlicht.lib")
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif #endif
/* /*
This is the main method. We can use int main() on every platform. This is the main method. We can now use main() on every platform.
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(), but to keep this example simple,
we use main().
*/ */
int main() int main()
{ {
/* /*
The most important function of the engine is the 'createDevice' The most important function of the engine is the createDevice()
function. The Irrlicht Device can be created with it, which is the function. The IrrlichtDevice is created by it, which is the root
root object for doing everything with the engine. object for doing anything with the engine. createDevice() has 7
createDevice() has 7 paramters: parameters:
deviceType: Type of the device. This can currently be the Null-device,
the Software device, the second software renderer, D3D8, D3D9, or OpenGL. - deviceType: Type of the device. This can currently be the Null-device,
In this example we use EDT_SOFTWARE, but to try out, you might want to change it to one of the two software renderers, D3D8, D3D9, or OpenGL. In this
EDT_BURNINGSVIDEO, EDT_NULL, EDT_DIRECT3D8 , EDT_DIRECT3D9, or EDT_OPENGL. example we use EDT_SOFTWARE, but to try out, you might want to
windowSize: Size of the Window or FullscreenMode to be created. In this change it to EDT_BURNINGSVIDEO, EDT_NULL, EDT_DIRECT3D8,
example we use 640x480. EDT_DIRECT3D9, or EDT_OPENGL.
bits: Amount of bits per pixel when in fullscreen mode. This should
be 16 or 32. This parameter is ignored when running in windowed mode. - windowSize: Size of the Window or screen in FullScreenMode to be
fullscreen: Specifies if we want the device to run in fullscreen mode created. In this example we use 640x480.
- bits: Amount of color bits per pixel. This should be 16 or 32. The
parameter is often ignored when running in windowed mode.
- fullscreen: Specifies if we want the device to run in fullscreen mode
or not. or not.
stencilbuffer: Specifies if we want to use the stencil buffer for drawing shadows.
vsync: Specifies if we want to have vsync enabled, this is only useful in fullscreen - stencilbuffer: Specifies if we want to use the stencil buffer (for
mode. drawing shadows).
eventReceiver: An object to receive events. We do not want to use this
- vsync: Specifies if we want to have vsync enabled, this is only useful
in fullscreen mode.
- eventReceiver: An object to receive events. We do not want to use this
parameter here, and set it to 0. parameter here, and set it to 0.
*/
Always check the return value to cope with unsupported drivers,
dimensions, etc.
*/
IrrlichtDevice *device = IrrlichtDevice *device =
#ifdef _IRR_OSX_PLATFORM_ #ifdef _IRR_OSX_PLATFORM_
createDevice( video::EDT_OPENGL, dimension2d<s32>(640, 480), 16, createDevice( video::EDT_OPENGL, dimension2d<s32>(640, 480), 16,
...@@ -116,19 +129,21 @@ int main() ...@@ -116,19 +129,21 @@ int main()
createDevice( video::EDT_SOFTWARE, dimension2d<s32>(640, 480), 16, createDevice( video::EDT_SOFTWARE, dimension2d<s32>(640, 480), 16,
false, false, false, 0); false, false, false, 0);
#endif #endif
if (!device)
return 1;
/* /*
Set the caption of the window to some nice text. Note that there is Set the caption of the window to some nice text. Note that there is an
a 'L' in front of the string. The Irrlicht Engine uses wide character 'L' in front of the string. The Irrlicht Engine uses wide character
strings when displaying text. strings when displaying text.
*/ */
device->setWindowCaption(L"Hello World! - Irrlicht Engine Demo"); device->setWindowCaption(L"Hello World! - Irrlicht Engine Demo");
/* /*
Get a pointer to the video driver, the SceneManager and the Get a pointer to the VideoDriver, the SceneManager and the graphical
graphical user interface environment, so that user interface environment, so that we do not always have to write
we do not always have to write device->getVideoDriver(), device->getVideoDriver(), device->getSceneManager(), or
device->getSceneManager() and device->getGUIEnvironment(). device->getGUIEnvironment().
*/ */
IVideoDriver* driver = device->getVideoDriver(); IVideoDriver* driver = device->getVideoDriver();
ISceneManager* smgr = device->getSceneManager(); ISceneManager* smgr = device->getSceneManager();
...@@ -136,58 +151,65 @@ int main() ...@@ -136,58 +151,65 @@ int main()
/* /*
We add a hello world label to the window, using the GUI environment. 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.
*/ */
guienv->addStaticText(L"Hello World! This is the Irrlicht Software renderer!", guienv->addStaticText(L"Hello World! This is the Irrlicht Software renderer!",
rect<s32>(10,10,260,22), true); rect<s32>(10,10,260,22), true);
/* /*
To display something interesting, we load a Quake 2 model To show something interesting, we load a Quake 2 model and display it.
and display it. We only have to get the Mesh from the Scene We only have to get the Mesh from the Scene Manager with getMesh() and add
Manager (getMesh()) and add a SceneNode to display the mesh. a SceneNode to display the mesh with addAnimatedMeshSceneNode(). We
(addAnimatedMeshSceneNode()). Instead of writing the filename check the return value of getMesh() to become aware of loading problems
sydney.md2, it would also be possible to load a Maya object file and other errors.
(.obj), a complete Quake3 map (.bsp) or a Milshape file (.ms3d).
By the way, that cool Quake 2 model called sydney was modelled Instead of writing the filename sydney.md2, it would also be possible
by Brian Collins. 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 modelled by Brian Collins.
*/ */
IAnimatedMesh* mesh = smgr->getMesh("../../media/sydney.md2"); IAnimatedMesh* mesh = smgr->getMesh("../../media/sydney.md2");
if (!mesh)
return 1;
IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh ); IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh );
/* /*
To let the mesh look a little bit nicer, we change its material a To let the mesh look a little bit nicer, we change its material. We
little bit: We disable lighting because we do not have a dynamic light disable lighting because we do not have a dynamic light in here, and
in here, and the mesh would be totally black. Then we set the frame the mesh would be totally black otherwise. Then we set the frame loop,
loop, so that the animation is looped between the frames 0 and 310. such that the predefined STAND animation is used. And last, we apply a
And at last, we apply a texture to the mesh. Without it the mesh texture to the mesh. Without it the mesh would be drawn using only a
would be drawn using only a color. color.
*/ */
if (node) if (node)
{ {
node->setMaterialFlag(EMF_LIGHTING, false); node->setMaterialFlag(EMF_LIGHTING, false);
node->setMD2Animation ( scene::EMAT_STAND ); node->setMD2Animation(scene::EMAT_STAND);
node->setMaterialTexture( 0, driver->getTexture("../../media/sydney.bmp") ); node->setMaterialTexture( 0, driver->getTexture("../../media/sydney.bmp") );
} }
/* /*
To look at the mesh, we place a camera into 3d space at the position 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). (0, 30, -40). The camera looks from there to (0,5,0), which is
approximately the place where our md2 model is.
*/ */
smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0)); smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0));
/* /*
Ok, now we have set up the scene, lets draw everything: Ok, now we have set up the scene, lets draw everything: We run the
We run the device in a while() loop, until the device does not device in a while() loop, until the device does not want to run any
want to run any more. This would be when the user closed the window more. This would be when the user closes the window or presses ALT+F4
or pressed ALT+F4 in windows. (or whatever keycode closes a window).
*/ */
while(device->run()) while(device->run())
{ {
/* /*
Anything can be drawn between a beginScene() and an endScene() Anything can be drawn between a beginScene() and an endScene()
call. The beginScene clears the screen with a color and also the call. The beginScene() call clears the screen with a color and
depth buffer if wanted. Then we let the Scene Manager and the the depth buffer, if desired. Then we let the Scene Manager and
GUI Environment draw their content. With the endScene() call the GUI Environment draw their content. With the endScene()
everything is presented on the screen. call everything is presented on the screen.
*/ */
driver->beginScene(true, true, SColor(255,100,101,140)); driver->beginScene(true, true, SColor(255,100,101,140));
...@@ -198,17 +220,18 @@ int main() ...@@ -198,17 +220,18 @@ int main()
} }
/* /*
After we are finished, we have to delete the Irrlicht Device After we are done with the render loop, we have to delete the Irrlicht
created before with createDevice(). In the Irrlicht Engine, Device created before with createDevice(). In the Irrlicht Engine, you
you will have to delete all objects you created with a method or have to delete all objects you created with a method or function which
function which starts with 'create'. The object is simply deleted starts with 'create'. The object is simply deleted by calling ->drop().
by calling ->drop(). See the documentation at irr::IReferenceCounted::drop() for more
See the documentation at information.
http://irrlicht.sourceforge.net//docu/classirr_1_1IUnknown.html#a3
for more information.
*/ */
device->drop(); device->drop();
return 0; return 0;
} }
/*
That's it. Compile and run.
**/
/* /** Example 002 Quake3Map
This Tutorial shows how to load a Quake 3 map into the
engine, create a SceneNode for optimizing the speed of This Tutorial shows how to load a Quake 3 map into the engine, create a
rendering and how to create a user controlled camera. 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/tut001.html
Lets start like the HelloWorld example: We include Lets start like the HelloWorld example: We include the irrlicht header files
the irrlicht header files and an additional file to be able and an additional file to be able to ask the user for a driver type using the
to ask the user for a driver type using the console. console.
*/ */
#include <irrlicht.h> #include <irrlicht.h>
#include <iostream> #include <iostream>
/* /*
As already written in the HelloWorld example, in the Irrlicht As already written in the HelloWorld example, in the Irrlicht Engine everything
Engine, everything can be found in the namespace 'irr'. can be found in the namespace 'irr'. To get rid of the irr:: in front of the
To get rid of the irr:: in front of the name of every class, name of every class, we tell the compiler that we use that namespace from now
we tell the compiler that we use that namespace from now on, on, and we will not have to write that 'irr::'. There are 5 other sub
and we will not have to write that 'irr::'. namespaces 'core', 'scene', 'video', 'io' and 'gui'. Unlike in the HelloWorld
There are 5 other sub namespaces 'core', 'scene', 'video', example, we do not call 'using namespace' for these 5 other namespaces, because
'io' and 'gui'. Unlike in the HelloWorld example, in this way you will see what can be found in which namespace. But if you like,
we do not a 'using namespace' for these 5 other namespaces you can also include the namespaces like in the previous example.
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. Code just like you want to.
*/ */
using namespace irr; using namespace irr;
/* /*
Again, to be able to use the Irrlicht.DLL file, we need to link with the 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 Irrlicht.lib. We could set this option in the project settings, but to make it
to make it easy, we use a pragma comment lib: easy, we use a pragma comment lib:
*/ */
#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib") #pragma comment(lib, "Irrlicht.lib")
#endif
/* /*
Ok, lets start. Again, we use the main() method as start, not the Ok, lets start. Again, we use the main() method as start, not the WinMain().
WinMain(), because its shorter to write.
*/ */
int main() int main()
{ {
/* /*
Like in the HelloWorld example, we create an IrrlichtDevice with Like in the HelloWorld example, we create an IrrlichtDevice with
createDevice(). The difference now is that we ask the user to select createDevice(). The difference now is that we ask the user to select
which hardware accelerated driver to use. The Software device would be 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 too slow to draw a huge Quake 3 map, but just for the fun of it, we make
this decision possible too. this decision possible, too.
*/ */
// ask user for driver // ask user for driver
...@@ -79,36 +82,40 @@ int main() ...@@ -79,36 +82,40 @@ int main()
/* /*
Get a pointer to the video driver and the SceneManager so that Get a pointer to the video driver and the SceneManager so that
we do not always have to write device->getVideoDriver() and we do not always have to call irr::IrrlichtDevice::getVideoDriver() and
device->getSceneManager(). irr::IrrlichtDevice::getSceneManager().
*/ */
video::IVideoDriver* driver = device->getVideoDriver(); video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager(); scene::ISceneManager* smgr = device->getSceneManager();
/* /*
To display the Quake 3 map, we first need to load it. Quake 3 maps 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. are packed into .pk3 files which are nothing else than .zip files.
So we add the .pk3 file to our FileSystem. After it was added, So we add the .pk3 file to our irr::io::IFileSystem. After it was added,
we are able to read from the files in that archive as they would we are able to read from the files in that archive as if they are
directly be stored on disk. directly stored on the disk.
*/ */
device->getFileSystem()->addZipFileArchive("../../media/map-20kdm2.pk3"); device->getFileSystem()->addZipFileArchive("../../media/map-20kdm2.pk3");
/* /*
Now we can load the mesh by calling getMesh(). We get a pointer returned Now we can load the mesh by calling
to a IAnimatedMesh. As you know, Quake 3 maps are not really animated, irr::scene::ISceneManager::getMesh(). We get a pointer returned to an
they are only a huge chunk of static geometry with some materials irr::scene::IAnimatedMesh. As you might know, Quake 3 maps are not
attached. Hence the IAnimated mesh consists of only one frame, really animated, they are only a huge chunk of static geometry with
so we get the "first frame" of the "animation", which is our quake level some materials attached. Hence the IAnimatedMesh consists of only one
and create an OctTree scene node with it, using addOctTreeSceneNode(). frame, so we get the "first frame" of the "animation", which is our
The OctTree optimizes the scene a little bit, trying to draw only quake level and create an OctTree scene node with it, using
geometry which is currently visible. An alternative to the OctTree irr::scene::ISceneManager::addOctTreeSceneNode().
would be a MeshSceneNode, which would draw always the complete geometry The OctTree optimizes the scene a little bit, trying to draw only geometry
of the mesh, without optimization. Try it out: Write addMeshSceneNode which is currently visible. An alternative to the OctTree would be a
instead of addOctTreeSceneNode and compare the primitives drawn by the irr::scene::IMeshSceneNode, which would always draw the complete
video driver. (There is a getPrimitiveCountDrawn() method in the geometry of the mesh, without optimization. Try it: Use
IVideoDriver class). Note that this optimization with the Octree is only irr::scene::ISceneManager::addMeshSceneNode() instead of
useful when drawing huge meshes consisting of lots of geometry. addOctTreeSceneNode() 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 OctTree is only useful when drawing huge meshes
consisting of lots of geometry.
*/ */
scene::IAnimatedMesh* mesh = smgr->getMesh("20kdm2.bsp"); scene::IAnimatedMesh* mesh = smgr->getMesh("20kdm2.bsp");
scene::ISceneNode* node = 0; scene::ISceneNode* node = 0;
...@@ -118,58 +125,70 @@ int main() ...@@ -118,58 +125,70 @@ int main()
// node = smgr->addMeshSceneNode(mesh->getMesh(0)); // node = smgr->addMeshSceneNode(mesh->getMesh(0));
/* /*
Because the level was modelled not around the origin (0,0,0), we translate Because the level was not modelled around the origin (0,0,0), we
the whole level a little bit. 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().
*/ */
if (node) if (node)
node->setPosition(core::vector3df(-1300,-144,-1249)); node->setPosition(core::vector3df(-1300,-144,-1249));
/* /*
Now we only need a Camera to look at the Quake 3 map. 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 We want to create a user controlled camera. There are some
different cameras available in the Irrlicht engine. For example the cameras available in the Irrlicht engine. For example the
Maya Camera which can be controlled compareable to the camera in Maya: MayaCamera which can be controlled like the camera in Maya:
Rotate with left mouse button pressed, Zoom with both buttons pressed, Rotate with left mouse button pressed, Zoom with both buttons pressed,
translate with right mouse button pressed. This could be created with translate with right mouse button pressed. This could be created with
addCameraSceneNodeMaya(). But for this example, we want to create a irr::scene::ISceneManager::addCameraSceneNodeMaya(). But for this
camera which behaves like the ones in first person shooter games (FPS). 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().
*/ */
smgr->addCameraSceneNodeFPS(); smgr->addCameraSceneNodeFPS();
/* /*
The mouse cursor needs not to be visible, so we make it invisible. The mouse cursor needs not be visible, so we hide it via the
irr::IrrlichtDevice::ICursorControl.
*/ */
device->getCursorControl()->setVisible(false); device->getCursorControl()->setVisible(false);
/* /*
We have done everything, so lets draw it. We also write the current 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 frames per second and the primitives drawn into the caption of the
window. The 'if (device->isWindowActive())' line is optional, but window. The test for irr::IrrlichtDevice::isWindowActive() is optional,
prevents the engine render to set the position of the mouse cursor but prevents the engine to grab the mouse cursor after task switching
after task switching when other program are active. 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.
*/ */
int lastFPS = -1; int lastFPS = -1;
while(device->run()) while(device->run())
if (device->isWindowActive())
{ {
driver->beginScene(true, true, video::SColor(0,200,200,200)); if (device->isWindowActive())
smgr->drawAll();
driver->endScene();
int fps = driver->getFPS();
if (lastFPS != fps)
{ {
core::stringw str = L"Irrlicht Engine - Quake 3 Map example ["; driver->beginScene(true, true, video::SColor(255,200,200,200));
str += driver->getName(); smgr->drawAll();
str += "] FPS:"; driver->endScene();
str += fps;
int fps = driver->getFPS();
device->setWindowCaption(str.c_str());
lastFPS = fps; if (lastFPS != fps)
{
core::stringw str = L"Irrlicht Engine - Quake 3 Map example [";
str += driver->getName();
str += "] FPS:";
str += fps;
device->setWindowCaption(str.c_str());
lastFPS = fps;
}
} }
else
device->yield();
} }
/* /*
...@@ -179,3 +198,6 @@ int main() ...@@ -179,3 +198,6 @@ int main()
return 0; return 0;
} }
/*
That's it. Compile and play around with the program.
**/
/* /** Example 003 Custom SceneNode
This Tutorial is a tutorial for more advanced developers.
This Tutorial is more advanced than the previous ones.
If you are currently just playing around with the Irrlicht If you are currently just playing around with the Irrlicht
engine, please look at other examples first. engine, you may want to look at other examples first.
This tutorials shows how to create a custom scene node and This tutorials shows how to create a custom scene node and
how to use it in the engine. A custom scene node is needed, how to use it in the engine. A custom scene node is needed
if you want to implement a render technique, the Irrlicht if you want to implement a render technique the Irrlicht
Engine is currently not supporting. For example you can write Engine currently does not support. For example, you can write
a indoor portal based renderer or a advanced terrain scene an indoor portal based renderer or an advanced terrain scene
node with it. With creating custom scene nodes, you can node with it. By creating custom scene nodes, you can
easily extend the Irrlicht Engine and adapt it to your easily extend the Irrlicht Engine and adapt it to your own
needs. needs.
I will keep the tutorial simple: Keep everything very I will keep the tutorial simple: Keep everything very
...@@ -16,45 +17,49 @@ short, everything in one .cpp file, and I'll use the engine ...@@ -16,45 +17,49 @@ short, everything in one .cpp file, and I'll use the engine
here as in all other tutorials. here as in all other tutorials.
To start, I include the header files, use the irr namespace, To start, I include the header files, use the irr namespace,
and tell the linker to link with the .lib file. and tell the linker to link with the .lib file.
*/ */
#include <irrlicht.h> #include <irrlicht.h>
#include <iostream> #include <iostream>
using namespace irr; using namespace irr;
#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib") #pragma comment(lib, "Irrlicht.lib")
#endif
/* /*
Here comes the most sophisticated part of this tutorial: Here comes the more sophisticated part of this tutorial:
The class of our very own custom scene node. To keep it simple, 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 our scene node will not be an indoor portal renderer nor a terrain
scene node, but a simple tetraeder, a 3d object consiting of 4 scene node, but a simple tetraeder, a 3d object consisting of 4
connected vertices, which only draws itself and does nothing more. connected vertices, which only draws itself and does nothing more.
Note that this scenario does not require a custom scene node in Irrlicht.
To let our scene node be able to be inserted into the Irrlicht Instead one would create a mesh from the geometry and pass it to a
Engine scene, the class we create needs only be derived from the irr::scene::IMeshSceneNode. This example just illustrates creation of a custom
ISceneNode class and has to override some methods. scene node in a very simple setting.
To let our scene node be able 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.
*/ */
class CSampleSceneNode : public scene::ISceneNode class CSampleSceneNode : public scene::ISceneNode
{ {
/* /*
First, we declare some member variables. Some space to First, we declare some member variables:
hold data for our tetraeder: The bounding box, 4 vertices, and The bounding box, 4 vertices, and the material of the tetraeder.
the material of the tetraeder.
*/ */
core::aabbox3d<f32> Box; core::aabbox3d<f32> Box;
video::S3DVertex Vertices[4]; video::S3DVertex Vertices[4];
video::SMaterial Material; video::SMaterial Material;
/* /*
The parameters of the constructor specify the parent of the scene node, 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. a pointer to the scene manager, and an id of the scene node.
In the constructor itself, we call the parent classes constructor, In the constructor we call the parent class' constructor,
set some properties of the material we use to draw the scene nodem and set some properties of the material, and
create the 4 vertices of the tetraeder we will draw later. create the 4 vertices of the tetraeder we will draw later.
*/ */
...@@ -72,33 +77,35 @@ public: ...@@ -72,33 +77,35 @@ public:
Vertices[3] = video::S3DVertex(-10,0,-10, 0,0,1, video::SColor(255,0,255,0), 0, 0); Vertices[3] = video::S3DVertex(-10,0,-10, 0,0,1, video::SColor(255,0,255,0), 0, 0);
/* /*
The Irrlicht Engine needs to know the bounding box of your scene node. The Irrlicht Engine needs to know the bounding box of a scene node.
It will use it for doing automatic culling and other things. Hence we It will use it for automatic culling and other things. Hence, we
need to create a bounding box from the 4 vertices we use. 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, 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 and/or don't want to create the box, you could also call
AutomaticCullingEnabled = false;. irr::scene::ISceneNode::setAutomaticCulling() with irr::scene::EAC_OFF.
*/ */
Box.reset(Vertices[0].Pos); Box.reset(Vertices[0].Pos);
for (s32 i=1; i<4; ++i) for (s32 i=1; i<4; ++i)
Box.addInternalPoint(Vertices[i].Pos); Box.addInternalPoint(Vertices[i].Pos);
} }
/* /*
Before it is drawn, the OnRegisterSceneNode() method of every scene node in the scene Before it is drawn, the irr::scene::ISceneNode::OnRegisterSceneNode()
is called by the scene manager. If the scene node wishes to draw itself, method of every scene node in the scene is called by the scene manager.
it may register itself in the scene manager to be drawn. This is necessary to If the scene node wishes to draw itself, it may register itself in the
tell the scene manager when it should call the ::render method. For example scene manager to be drawn. This is necessary to tell the scene manager
normal scene nodes render their content one after another, while when it should call irr::scene::ISceneNode::render(). For
stencil buffer shadows would like to be drawn after all other scene nodes. And example, normal scene nodes render their content one after another,
camera or light scene nodes need to be rendered before all other scene while stencil buffer shadows would like to be drawn after all other
nodes (if at all). scene nodes. And camera or light scene nodes need to be rendered before
So here we simply register the scene node to get render normally. If we would like all other scene nodes (if at all). So here we simply register the
to let it be rendered like cameras or light, we would have to call 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); SceneManager->registerNodeForRendering(this, SNRT_LIGHT_AND_CAMERA);
After this, we call the OnRegisterSceneNode-method of the base class ISceneNode, After this, we call the actual
which simply lets also all the child scene nodes of this node register themselves. irr::scene::ISceneNode::OnRegisterSceneNode() method of the base class,
which simply lets also all the child scene nodes of this node register
themselves.
*/ */
virtual void OnRegisterSceneNode() virtual void OnRegisterSceneNode()
{ {
...@@ -109,7 +116,7 @@ public: ...@@ -109,7 +116,7 @@ public:
} }
/* /*
In the render() method most of the interesting stuff happenes: The In the render() method most of the interesting stuff happens: The
Scene node renders itself. We override this method and draw the Scene node renders itself. We override this method and draw the
tetraeder. tetraeder.
*/ */
...@@ -124,13 +131,14 @@ public: ...@@ -124,13 +131,14 @@ public:
} }
/* /*
At least, we create three small additional methods. And finally we create three small additional methods.
GetBoundingBox() returns the bounding box of this scene node, irr::scene::ISceneNode::getBoundingBox() returns the bounding box of
GetMaterialCount() returns the amount of materials in this scene node this scene node, irr::scene::ISceneNode::getMaterialCount() returns the
(our tetraeder only has one material), and getMaterial() returns the amount of materials in this scene node (our tetraeder only has one
material), and irr::scene::ISceneNode::getMaterial() returns the
material at an index. Because we have only one material here, we can material at an index. Because we have only one material here, we can
return the only one meterial, assuming that no one ever calls getMaterial() return the only one material, assuming that no one ever calls
with an index greater than 0. getMaterial() with an index greater than 0.
*/ */
virtual const core::aabbox3d<f32>& getBoundingBox() const virtual const core::aabbox3d<f32>& getBoundingBox() const
{ {
...@@ -172,7 +180,7 @@ int main() ...@@ -172,7 +180,7 @@ int main()
case 'b': driverType = video::EDT_DIRECT3D8;break; case 'b': driverType = video::EDT_DIRECT3D8;break;
case 'c': driverType = video::EDT_OPENGL; break; case 'c': driverType = video::EDT_OPENGL; break;
case 'd': driverType = video::EDT_SOFTWARE; break; case 'd': driverType = video::EDT_SOFTWARE; break;
case 'e': driverType = video::EDT_BURNINGSVIDEO; break; case 'e': driverType = video::EDT_BURNINGSVIDEO;break;
case 'f': driverType = video::EDT_NULL; break; case 'f': driverType = video::EDT_NULL; break;
default: return 0; default: return 0;
} }
...@@ -194,43 +202,55 @@ int main() ...@@ -194,43 +202,55 @@ int main()
smgr->addCameraSceneNode(0, core::vector3df(0,-40,0), core::vector3df(0,0,0)); smgr->addCameraSceneNode(0, core::vector3df(0,-40,0), core::vector3df(0,0,0));
// 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. Create our scene node. I don't check the result of calling new, as it
// Because the new node will create itself with a reference count of 1, and should throw an exception rather than returning 0 on failure. Because
// then will have another reference added by its parent scene node when it is the new node will create itself with a reference count of 1, and then
// added to the scene, I need to drop my reference to it. Best practice is will have another reference added by its parent scene node when it is
// to drop it only *after* I have finished using it, regardless of what the added to the scene, I need to drop my reference to it. Best practice is
// reference count of the object is after creation. to drop it only *after* I have finished using it, regardless of what
CSampleSceneNode *myNode = the reference count of the object is after creation.
*/
CSampleSceneNode *myNode =
new CSampleSceneNode(smgr->getRootSceneNode(), smgr, 666); new CSampleSceneNode(smgr->getRootSceneNode(), smgr, 666);
// 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 To animate something in this boring scene consisting only of one
// node in the engine, we add an animator to the scene node, which rotates tetraeder, and to show that you now can use your scene node like any
// the node a little bit. other scene node in the engine, we add an animator to the scene node,
scene::ISceneNodeAnimator* anim = which rotates the node a little bit.
irr::scene::ISceneManager::createRotationAnimator() could return 0, so
should be checked.
*/
scene::ISceneNodeAnimator* anim =
smgr->createRotationAnimator(core::vector3df(0.8f, 0, 0.8f)); smgr->createRotationAnimator(core::vector3df(0.8f, 0, 0.8f));
// createRotationAnimator() could return 0, so should be checked
if(anim) if(anim)
{ {
myNode->addAnimator(anim); myNode->addAnimator(anim);
// I'm done referring to anim, so must drop this reference now because it /*
// was produced by a createFoo() function. 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.
*/
anim->drop(); anim->drop();
anim = 0; // As I shouldn't refer to it again, ensure that I can't anim = 0;
} }
// I'm done with my CSampleSceneNode object, and so must drop my reference /*
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.
*/
myNode->drop(); myNode->drop();
myNode = 0; // As I shouldn't refer to it again, ensure that I can't myNode = 0; // As I shouldn't refer to it again, ensure that I can't
/*
/*
Now draw everything and finish. Now draw everything and finish.
*/ */
u32 frames=0; u32 frames=0;
while(device->run()) while(device->run())
{ {
...@@ -256,3 +276,6 @@ int main() ...@@ -256,3 +276,6 @@ int main()
return 0; return 0;
} }
/*
That's it. Compile and play around with the program.
**/
/* /** Example 004 Movement
This Tutorial shows how to move and animate SceneNodes. The This Tutorial shows how to move and animate SceneNodes. The
basic concept of SceneNodeAnimators is shown as well as manual basic concept of SceneNodeAnimators is shown as well as manual
movement of nodes using the keyboard. movement of nodes using the keyboard.
...@@ -11,15 +12,17 @@ and tell the linker to link with the .lib file. ...@@ -11,15 +12,17 @@ and tell the linker to link with the .lib file.
using namespace irr; using namespace irr;
#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib") #pragma comment(lib, "Irrlicht.lib")
#endif
/* /*
To receive events like mouse and keyboard input, or GUI events like To receive events like mouse and keyboard input, or GUI events like "the OK
"the OK button has been clicked", we need an object which is derived from the button has been clicked", we need an object which is derived from the
IEventReceiver object. There is only one method to override: OnEvent. irr::IEventReceiver object. There is only one method to override:
This method will be called by the engine once when an event happens. irr::IEventReceiver::OnEvent(). This method will be called by the engine once
What we really want to know is whether a key is being held down, when an event happens. What we really want to know is whether a key is being
and so we will remember the current state of each key. held down, and so we will remember the current state of each key.
*/ */
class MyEventReceiver : public IEventReceiver class MyEventReceiver : public IEventReceiver
{ {
...@@ -53,10 +56,11 @@ private: ...@@ -53,10 +56,11 @@ private:
/* /*
The event receiver for moving a scene node is ready. So lets just create The event receiver for keeping the pressed keys is ready, the actual responses
an Irrlicht Device and the scene node we want to move. We also create some will be made inside the render loop, right before drawing the scene. So lets
other additional scene nodes, to show that there are also some different just create an irr::IrrlichtDevice and the scene node we want to move. We also
possibilities to move and animate scene nodes. create some other additional scene nodes, to show that there are also some
different possibilities to move and animate scene nodes.
*/ */
int main() int main()
{ {
...@@ -92,14 +96,12 @@ int main() ...@@ -92,14 +96,12 @@ int main()
if (device == 0) if (device == 0)
return 1; // could not create selected driver. return 1; // could not create selected driver.
video::IVideoDriver* driver = device->getVideoDriver(); video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager(); scene::ISceneManager* smgr = device->getSceneManager();
/* /*
Create the node for moving it with the 'W' and 'S' key. We create a Create the node which will be moved with the 'W' and 'S' key. We create a
sphere node, which is a built in geometry primitive. We place the node 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 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 interesting. Because we have no dynamic lights in this scene we disable
lighting for each model (otherwise the models would be black). lighting for each model (otherwise the models would be black).
...@@ -112,15 +114,14 @@ int main() ...@@ -112,15 +114,14 @@ int main()
node->setMaterialFlag(video::EMF_LIGHTING, false); node->setMaterialFlag(video::EMF_LIGHTING, false);
} }
/*
/* Now we create another node, movable using a scene node animator. Scene
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 node animators modify scene nodes and can be attached to any scene node
like mesh scene nodes, billboards, lights and even camera scene nodes. 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 animators are not only able to modify the position of a
scene node, they can also animate the textures of an object for 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 example. We create a cube scene node and attach a 'fly circle' scene
node to it, letting this node fly around our sphere scene node. node animator to it, letting this node fly around our sphere scene node.
*/ */
scene::ISceneNode* n = smgr->addCubeSceneNode(); scene::ISceneNode* n = smgr->addCubeSceneNode();
...@@ -138,7 +139,7 @@ int main() ...@@ -138,7 +139,7 @@ int main()
} }
/* /*
The last scene node we add to show possibilities of scene node animators is 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. a md2 model, which uses a 'fly straight' animator to run between to points.
*/ */
scene::IAnimatedMeshSceneNode* anms = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/sydney.md2")); scene::IAnimatedMeshSceneNode* anms = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/sydney.md2"));
...@@ -146,7 +147,7 @@ int main() ...@@ -146,7 +147,7 @@ int main()
if (anms) if (anms)
{ {
scene::ISceneNodeAnimator* anim = scene::ISceneNodeAnimator* anim =
smgr->createFlyStraightAnimator(core::vector3df(100,0,60), smgr->createFlyStraightAnimator(core::vector3df(100,0,60),
core::vector3df(-100,0,60), 2500, true); core::vector3df(-100,0,60), 2500, true);
if (anim) if (anim)
{ {
...@@ -155,14 +156,16 @@ int main() ...@@ -155,14 +156,16 @@ int main()
} }
/* /*
To make to model look right we set the frames between which the animation To make the model look right we disable lighting, set the
should loop, rotate the model around 180 degrees, and adjust the animation speed frames between which the animation should loop, rotate the
and the texture. model around 180 degrees, and adjust the animation speed and
To set the right animation (frames and speed), we would also be able to just the texture. To set the right animation (frames and speed), we
call "anms->setMD2Animation(scene::EMAT_RUN)" for the 'run' animation would also be able to just call
instead of "setFrameLoop" and "setAnimationSpeed", "anms->setMD2Animation(scene::EMAT_RUN)" for the 'run'
but this only works with MD2 animations, and so you know how to start other animations. animation instead of "setFrameLoop" and "setAnimationSpeed",
but it a good advice to use not hardcoded frame-numbers... but this only works with MD2 animations, and so you know how to
start other animations. But a good advice is to not use
hardcoded frame-numbers...
*/ */
anms->setMaterialFlag(video::EMF_LIGHTING, false); anms->setMaterialFlag(video::EMF_LIGHTING, false);
...@@ -228,7 +231,7 @@ int main() ...@@ -228,7 +231,7 @@ int main()
{ {
core::stringw tmp(L"Movement Example - Irrlicht Engine ["); core::stringw tmp(L"Movement Example - Irrlicht Engine [");
tmp += driver->getName(); tmp += driver->getName();
tmp += L"] fps: "; tmp += L"] fps: ";
tmp += fps; tmp += fps;
device->setWindowCaption(tmp.c_str()); device->setWindowCaption(tmp.c_str());
...@@ -244,3 +247,6 @@ int main() ...@@ -244,3 +247,6 @@ int main()
return 0; return 0;
} }
/*
That's it. Compile and play around with the program.
**/
/* /** Example 005 User Interface
This tutorial shows how to use the built in User Interface of This tutorial shows how to use the built in User Interface of
the Irrlicht Engine. It will give a brief overview and show the Irrlicht Engine. It will give a brief overview and show
how to create and use windows, buttons, scroll bars, static how to create and use windows, buttons, scroll bars, static
texts and list boxes. texts, and list boxes.
As always, we include the header files, and use the irrlicht As always, we include the header files, and use the irrlicht
namespaces. We also store a pointer to the Irrlicht device, namespaces. We also store a pointer to the Irrlicht device,
...@@ -32,13 +33,13 @@ IGUIListBox* listbox = 0; ...@@ -32,13 +33,13 @@ IGUIListBox* listbox = 0;
/* /*
The Event Receiver is not only capable of getting keyboard and The Event Receiver is not only capable of getting keyboard and
mouse input events, but also events of the graphical user interface mouse input events, but also events of the graphical user interface
(gui). There are events for almost everything: Button click, (gui). There are events for almost everything: Button click,
Listbox selection change, events that say that a element was hovered 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 and so on. To be able to react to some of these events, we create
an event receiver. an event receiver.
We only react to gui events, and if it's such an event, we get the 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 id of the caller (the gui element which caused the event) and get
the pointer to the gui environment. the pointer to the gui environment.
*/ */
class MyEventReceiver : public IEventReceiver class MyEventReceiver : public IEventReceiver
...@@ -55,12 +56,12 @@ public: ...@@ -55,12 +56,12 @@ public:
{ {
/* /*
If a scrollbar changed its scroll position, and it is 'our' If a scrollbar changed its scroll position, and it is
scrollbar (the one with id 104), then we change the 'our' scrollbar (the one with id 104), then we change
transparency of all gui elements. This is a very easy task: the transparency of all gui elements. This is a very
There is a skin object, in which all color settings are stored. easy task: There is a skin object, in which all color
We simply go through all colors stored in the skin and change settings are stored. We simply go through all colors
their alpha value. stored in the skin and change their alpha value.
*/ */
case EGET_SCROLL_BAR_CHANGED: case EGET_SCROLL_BAR_CHANGED:
if (id == 104) if (id == 104)
...@@ -80,7 +81,7 @@ public: ...@@ -80,7 +81,7 @@ public:
/* /*
If a button was clicked, it could be one of 'our' If a button was clicked, it could be one of 'our'
three buttons. If it is the first, we shut down the engine. three buttons. If it is the first, we shut down the engine.
If it is the second, we create a little window with some 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 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 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. a file open dialog, and add also this as string to the list box.
...@@ -98,15 +99,15 @@ public: ...@@ -98,15 +99,15 @@ public:
{ {
listbox->addItem(L"Window created"); listbox->addItem(L"Window created");
cnt += 30; cnt += 30;
if (cnt > 200) if (cnt > 200)
cnt = 0; cnt = 0;
IGUIWindow* window = env->addWindow( IGUIWindow* window = env->addWindow(
rect<s32>(100 + cnt, 100 + cnt, 300 + cnt, 200 + cnt), rect<s32>(100 + cnt, 100 + cnt, 300 + cnt, 200 + cnt),
false, // modal? false, // modal?
L"Test window"); L"Test window");
env->addStaticText(L"Please close me", env->addStaticText(L"Please close me",
rect<s32>(35,35,140,50), rect<s32>(35,35,140,50),
true, // border? true, // border?
false, // wordwrap? false, // wordwrap?
...@@ -134,9 +135,9 @@ public: ...@@ -134,9 +135,9 @@ public:
/* /*
Ok, now for the more interesting part. First, create the Ok, now for the more interesting part. First, create the Irrlicht device. As in
Irrlicht device. As in some examples before, we ask the user which some examples before, we ask the user which driver he wants to use for this
driver he wants to use for this example: example:
*/ */
int main() int main()
{ {
...@@ -182,7 +183,7 @@ int main() ...@@ -182,7 +183,7 @@ int main()
/* /*
To make the font a little bit nicer, we load an external font To make the font a little bit nicer, we load an external font
and set it as the new default font in the skin. and set it as the new default font in the skin.
To keep the standard font for tool tip text, we set it to To keep the standard font for tool tip text, we set it to
the built-in font. the built-in font.
*/ */
...@@ -208,7 +209,7 @@ int main() ...@@ -208,7 +209,7 @@ int main()
/* /*
Now, we add a static text and a scrollbar, which modifies the Now, we add a static text and a scrollbar, which modifies the
transparency of all gui elements. We set the maximum value of transparency of all gui elements. We set the maximum value of
the scrollbar to 255, because that's the maximal value for the scrollbar to 255, because that's the maximal value for
a color value. a color value.
Then we create an other static text and a list box. Then we create an other static text and a list box.
*/ */
...@@ -224,7 +225,9 @@ int main() ...@@ -224,7 +225,9 @@ int main()
listbox = env->addListBox(rect<s32>(50, 140, 250, 210)); listbox = env->addListBox(rect<s32>(50, 140, 250, 210));
env->addEditBox(L"Editable Text", rect<s32>(350, 80, 550, 100)); env->addEditBox(L"Editable Text", rect<s32>(350, 80, 550, 100));
// add the engine logo /*
And at last, we create a nice Irrlicht Engine logo in the top left corner.
*/
env->addImage(driver->getTexture("../../media/irrlichtlogo2.png"), env->addImage(driver->getTexture("../../media/irrlichtlogo2.png"),
position2d<int>(10,10)); position2d<int>(10,10));
...@@ -247,3 +250,6 @@ int main() ...@@ -247,3 +250,6 @@ int main()
return 0; return 0;
} }
/*
**/
/* /** Example 006 2D Graphics
This Tutorial shows how to do 2d graphics with the Irrlicht Engine.
It shows how to draw images, keycolor based sprites, This Tutorial shows how to do 2d graphics with the Irrlicht Engine.
transparent rectangles and different fonts. You will may consider It shows how to draw images, keycolor based sprites,
this useful if you want to make a 2d game with the engine, or if transparent rectangles, and different fonts. You may consider
you want to draw a cool interface or head up display for your 3d game. 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. As always, I include the header files, use the irr namespace,
*/ and tell the linker to link with the .lib file.
#include <irrlicht.h> */
#include <iostream> #include <irrlicht.h>
#include <iostream>
using namespace irr;
using namespace irr;
#pragma comment(lib, "Irrlicht.lib")
#ifdef _MSC_VER
/* #pragma comment(lib, "Irrlicht.lib")
At first, we let the user select the driver type, then #endif
start up the engine, set a caption, and get a pointer
to the video driver. /*
*/ At first, we let the user select the driver type, then start up the engine, set
int main() a caption, and get a pointer to the video driver.
{ */
// let user select driver type int main()
{
video::E_DRIVER_TYPE driverType; // let user select driver type
printf("Please select the driver you want for this example:\n"\ video::E_DRIVER_TYPE driverType;
" (a) Direct3D 9.0c\n (b) Direct3D 8.1\n (c) OpenGL 1.5\n"\
" (d) Software Renderer\n (e) Burning's Software Renderer\n"\ printf("Please select the driver you want for this example:\n"\
" (f) NullDevice\n (otherKey) exit\n\n"); " (a) Direct3D 9.0c\n (b) Direct3D 8.1\n (c) OpenGL 1.5\n"\
" (d) Software Renderer\n (e) Burning's Software Renderer\n"\
char i; " (f) NullDevice\n (otherKey) exit\n\n");
std::cin >> i;
char i;
switch(i) std::cin >> i;
{
case 'a': driverType = video::EDT_DIRECT3D9;break; switch(i)
case 'b': driverType = video::EDT_DIRECT3D8;break; {
case 'c': driverType = video::EDT_OPENGL; break; case 'a': driverType = video::EDT_DIRECT3D9;break;
case 'd': driverType = video::EDT_SOFTWARE; break; case 'b': driverType = video::EDT_DIRECT3D8;break;
case 'e': driverType = video::EDT_BURNINGSVIDEO;break; case 'c': driverType = video::EDT_OPENGL; break;
case 'f': driverType = video::EDT_NULL; break; case 'd': driverType = video::EDT_SOFTWARE; break;
default: return 0; case 'e': driverType = video::EDT_BURNINGSVIDEO;break;
} case 'f': driverType = video::EDT_NULL; break;
default: return 0;
// create device }
IrrlichtDevice *device = createDevice(driverType, // create device
core::dimension2d<s32>(512, 384));
IrrlichtDevice *device = createDevice(driverType,
if (device == 0) core::dimension2d<s32>(512, 384));
return 1; // could not create selected driver.
if (device == 0)
device->setWindowCaption(L"Irrlicht Engine - 2D Graphics Demo"); return 1; // could not create selected driver.
video::IVideoDriver* driver = device->getVideoDriver(); device->setWindowCaption(L"Irrlicht Engine - 2D Graphics Demo");
/* video::IVideoDriver* driver = device->getVideoDriver();
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 All 2d graphics in this example are put together into one texture,
part of it should be transparent based on a colorkey. In this example, 2ddemo.bmp. Because we want to draw colorkey based sprites, we need to
we don't tell it the color directly, we just say "Hey Irrlicht Engine, load this texture and tell the engine, which part of it should be
you'll find the color I want at position (0,0) on the texture.". transparent based on a colorkey.
Instead, it would be also possible to call
driver->makeColorKeyTexture(images, video::SColor(0,0,0,0)), to make In this example, we don't tell it the color directly, we just say "Hey
e.g. all black pixels transparent. Please note, that makeColorKeyTexture Irrlicht Engine, you'll find the color I want at position (0,0) on the
just creates an alpha channel based on the color. texture.". Instead, it would be also possible to call
*/ driver->makeColorKeyTexture(images, video::SColor(0,0,0,0)), to make
video::ITexture* images = driver->getTexture("../../media/2ddemo.bmp"); e.g. all black pixels transparent. Please note that
driver->makeColorKeyTexture(images, core::position2d<s32>(0,0)); makeColorKeyTexture just creates an alpha channel based on the color.
*/
video::ITexture* images = driver->getTexture("../../media/2ddemo.bmp");
/* driver->makeColorKeyTexture(images, core::position2d<s32>(0,0));
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. To be able to draw some text with two different fonts, we first load
Also, we define two rectangles, which specify the position of the them. Ok, we load just one. As the first font we just use the default
images of the red imps (little flying creatures) in the texture. 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
gui::IGUIFont* font = device->getGUIEnvironment()->getBuiltInFont(); creatures) in the texture.
gui::IGUIFont* font2 = device->getGUIEnvironment()->getFont("../../media/fonthaettenschweiler.bmp"); */
gui::IGUIFont* font = device->getGUIEnvironment()->getBuiltInFont();
core::rect<s32> imp1(349,15,385,78); gui::IGUIFont* font2 = device->getGUIEnvironment()->getFont("../../media/fonthaettenschweiler.bmp");
core::rect<s32> imp2(387,15,423,78);
core::rect<s32> imp1(349,15,385,78);
core::rect<s32> imp2(387,15,423,78);
/*
Everything is prepared, now we can draw everything in the draw loop, /*
between the begin scene and end scene calls. In this example, we Everything is prepared, now we can draw everything in the draw loop,
are just doing 2d graphics, but it would be no problem to mix them between the begin scene and end scene calls. In this example, we are
with 3d graphics. Just try it out, and draw some 3d vertices or set just doing 2d graphics, but it would be no problem to mix them with 3d
up a scene with the scene manager and draw it. graphics. Just try it out, and draw some 3d vertices or set up a scene
*/ with the scene manager and draw it.
while(device->run() && driver) */
{ while(device->run() && driver)
if (device->isWindowActive()) {
{ if (device->isWindowActive())
u32 time = device->getTimer()->getTime(); {
u32 time = device->getTimer()->getTime();
driver->beginScene(true, true, video::SColor(0,120,102,136));
driver->beginScene(true, true, video::SColor(255,120,102,136));
/*
First, we draw 3 sprites, using the alpha channel we created with /*
makeColorKeyTexture. The last parameter specifiys that the drawing First, we draw 3 sprites, using the alpha channel we
method should use thiw alpha channel. The parameter before the last created with makeColorKeyTexture. The last parameter
one specifies a color, with wich the sprite should be colored. specifies that the drawing method should use this alpha
(255,255,255,255) is full white, so the sprite will look like the channel. The last-but-one parameter specifies a
original. The third sprite is drawed colored based on the time. 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
// draw fire & dragons background world with the red channel modulated based on the time.
driver->draw2DImage(images, core::position2d<s32>(50,50), */
core::rect<s32>(0,0,342,224), 0,
video::SColor(255,255,255,255), true); // draw fire & dragons background world
driver->draw2DImage(images, core::position2d<s32>(50,50),
// draw flying imp core::rect<s32>(0,0,342,224), 0,
driver->draw2DImage(images, core::position2d<s32>(164,125), video::SColor(255,255,255,255), true);
(time/500 % 2) ? imp1 : imp2, 0,
video::SColor(255,255,255,255), true); // draw flying imp
driver->draw2DImage(images, core::position2d<s32>(164,125),
// draw second flying imp with colorcylce (time/500 % 2) ? imp1 : imp2, 0,
driver->draw2DImage(images, core::position2d<s32>(270,105), video::SColor(255,255,255,255), true);
(time/500 % 2) ? imp1 : imp2, 0,
video::SColor(255,(time) % 255,255,255), true); // draw second flying imp with colorcylce
driver->draw2DImage(images, core::position2d<s32>(270,105),
/* (time/500 % 2) ? imp1 : imp2, 0,
Drawing text is really simple. The code should be self explanatory. video::SColor(255,(time) % 255,255,255), true);
*/
/*
// draw some text Drawing text is really simple. The code should be self
if (font) explanatory.
font->draw(L"This demo shows that Irrlicht is also capable of drawing 2D graphics.", */
core::rect<s32>(130,10,300,50),
video::SColor(255,255,255,255)); // draw some text
if (font)
// draw some other text font->draw(L"This demo shows that Irrlicht is also capable of drawing 2D graphics.",
if (font2) core::rect<s32>(130,10,300,50),
font2->draw(L"Also mixing with 3d graphics is possible.", video::SColor(255,255,255,255));
core::rect<s32>(130,20,300,60),
video::SColor(255,time % 255,time % 255,255)); // draw some other text
if (font2)
/* font2->draw(L"Also mixing with 3d graphics is possible.",
At last, we draw the Irrlicht Engine logo (without using a color or core::rect<s32>(130,20,300,60),
an alpha channel) and a transparent 2d Rectangle at the position of video::SColor(255,time % 255,time % 255,255));
the mouse cursor.
*/ /*
At last, we draw the Irrlicht Engine logo (without
// draw logo using a color or an alpha channel) and a transparent 2d
driver->draw2DImage(images, core::position2d<s32>(10,10), Rectangle at the position of the mouse cursor.
core::rect<s32>(354,87,442,118)); */
// draw transparent rect under cursor // draw logo
core::position2d<s32> m = device->getCursorControl()->getPosition(); driver->draw2DImage(images, core::position2d<s32>(10,10),
driver->draw2DRectangle(video::SColor(100,255,255,255), core::rect<s32>(354,87,442,118));
core::rect<s32>(m.X-20, m.Y-20, m.X+20, m.Y+20));
// draw transparent rect under cursor
driver->endScene(); core::position2d<s32> m = device->getCursorControl()->getPosition();
} driver->draw2DRectangle(video::SColor(100,255,255,255),
} core::rect<s32>(m.X-20, m.Y-20, m.X+20, m.Y+20));
/* driver->endScene();
That's all, it was not really difficult, I hope. }
*/ }
device->drop(); device->drop();
return 0; return 0;
} }
/*
That's all. I hope it was not too difficult.
**/
/* /** Example 007 Collision
In this tutorial, I will show how to collision detection with the Irrlicht Engine.
I will describe 3 methods: Automatic collision detection for moving through 3d worlds In this tutorial, I will show how to detect collisions with the Irrlicht Engine.
with stair climbing and sliding, manual triangle picking and manual I will describe 3 methods: Automatic collision detection for moving through 3d
worlds with stair climbing and sliding, manual triangle picking, and manual
scene node picking. scene node picking.
To start, we take the program from tutorial 2, which loaded and displayed a quake 3 To start, we take the program from tutorial 2, which loads and displays a quake
level. We will use the level to walk in it and to pick triangles from it. In addition 3 level. We will use the level to walk in it and to pick triangles from it. In
we'll place 3 animated models into it for scene node picking. The following code addition we'll place 3 animated models into it for scene node picking. The
starts up the engine and loads following code starts up the engine and loads a quake 3 level. I will not
a quake 3 level. I will not explain it, because it should already be known from tutorial explain it, because it should already be known from tutorial 2.
2.
*/ */
#include <irrlicht.h> #include <irrlicht.h>
#include <iostream> #include <iostream>
...@@ -20,7 +20,6 @@ using namespace irr; ...@@ -20,7 +20,6 @@ using namespace irr;
#pragma comment(lib, "Irrlicht.lib") #pragma comment(lib, "Irrlicht.lib")
#endif #endif
int main() int main()
{ {
// let user select driver type // let user select driver type
...@@ -50,41 +49,40 @@ int main() ...@@ -50,41 +49,40 @@ int main()
IrrlichtDevice *device = IrrlichtDevice *device =
createDevice(driverType, core::dimension2d<s32>(640, 480), 16, false); createDevice(driverType, core::dimension2d<s32>(640, 480), 16, false);
if (device == 0) if (device == 0)
return 1; // could not create selected driver. return 1; // could not create selected driver.
video::IVideoDriver* driver = device->getVideoDriver(); video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager(); scene::ISceneManager* smgr = device->getSceneManager();
device->getFileSystem()->addZipFileArchive("../../media/map-20kdm2.pk3"); device->getFileSystem()->addZipFileArchive("../../media/map-20kdm2.pk3");
scene::IAnimatedMesh* q3levelmesh = smgr->getMesh("20kdm2.bsp"); scene::IAnimatedMesh* q3levelmesh = smgr->getMesh("20kdm2.bsp");
scene::ISceneNode* q3node = 0; scene::ISceneNode* q3node = 0;
if (q3levelmesh) if (q3levelmesh)
q3node = smgr->addOctTreeSceneNode(q3levelmesh->getMesh(0)); q3node = smgr->addOctTreeSceneNode(q3levelmesh->getMesh(0));
/* /*
So far so good, we've loaded the quake 3 level like in tutorial 2. Now, here So far so good, we've loaded the quake 3 level like in tutorial 2. Now,
comes something different: We create a triangle selector. A triangle selector here comes something different: We create a triangle selector. A
is a class which can fetch the triangles from scene nodes for doing different triangle selector is a class which can fetch the triangles from scene
things with them, for example collision detection. There are different triangle nodes for doing different things with them, for example collision
selectors, and all can be created with the ISceneManager. In this example, detection. There are different triangle selectors, and all can be
we create an OctTreeTriangleSelector, which optimizes the triangle output a created with the ISceneManager. In this example, we create an
little bit by reducing it like an octree. This is very useful for huge meshes OctTreeTriangleSelector, which optimizes the triangle output a little
like quake 3 levels. bit by reducing it like an octree. This is very useful for huge meshes
After we created the triangle selector, we attach it to the q3node. This is not like quake 3 levels. After we created the triangle selector, we attach
necessary, but in this way, we do not need to care for the selector, for example it to the q3node. This is not necessary, but in this way, we do not
dropping it after we do not need it anymore. need to care for the selector, for example dropping it after we do not
need it anymore.
*/ */
scene::ITriangleSelector* selector = 0; scene::ITriangleSelector* selector = 0;
if (q3node) if (q3node)
{ {
q3node->setPosition(core::vector3df(-1350,-130,-1400)); q3node->setPosition(core::vector3df(-1350,-130,-1400));
selector = smgr->createOctTreeTriangleSelector(q3levelmesh->getMesh(0), q3node, 128); selector = smgr->createOctTreeTriangleSelector(q3levelmesh->getMesh(0), q3node, 128);
...@@ -93,34 +91,41 @@ int main() ...@@ -93,34 +91,41 @@ int main()
/* /*
We add a first person shooter camera to the scene for being able to move in the quake 3 We add a first person shooter camera to the scene for being able to
level like in tutorial 2. But this, time, we add a special animator to the move in the quake 3 level like in tutorial 2. But this, time, we add a
camera: A Collision Response animator. This thing modifies the scene node to which special animator to the camera: A Collision Response animator. This
it is attached to in that way, that it may no more move through walls and is affected thing modifies the scene node to which it is attached to in that way,
by gravity. The only thing we have to tell the animator is how the world looks like, that it may no more move through walls and is affected by gravity. The
how big the scene node is, how gravity and so on. After the collision response animator only thing we have to tell the animator is how the world looks like,
is attached to the camera, we do not have to do anything more for collision detection, how big the scene node is, how gravity and so on. After the collision
anything is done automaticly, all other collision detection code below is for picking. response animator is attached to the camera, we do not have to do
And please note another cool feature: The collsion response animator can be attached anything more for collision detection, anything is done automaticly,
also to all other scene nodes, not only to cameras. And it can be mixed with other all other collision detection code below is for picking. And please
scene node animators. In this way, collision detection and response in the Irrlicht note another cool feature: The collsion response animator can be
engine is really, really easy. attached also to all other scene nodes, not only to cameras. And it can
Now we'll take a closer look on the parameters of createCollisionResponseAnimator(). be mixed with other scene node animators. In this way, collision
The first parameter is the TriangleSelector, which specifies how the world, against detection and response in the Irrlicht engine is really, really easy.
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. Now we'll take a closer look on the parameters of
The third defines how big the object is, it is the radius of an ellipsoid. Try it out createCollisionResponseAnimator(). The first parameter is the
and change the radius to smaller values, the camera will be able to move closer to walls TriangleSelector, which specifies how the world, against collision
after this. The next parameter is the direction and speed of gravity. You could detection is done looks like. The second parameter is the scene node,
set it to (0,0,0) to disable gravity. And the last value is just a translation: Without which is the object, which is affected by collision detection, in our
this, the ellipsoid with which collision detection is done would be around the camera, case it is the camera. The third defines how big the object is, it is
and the camera would be in the middle of the ellipsoid. But as human beings, we are the radius of an ellipsoid. Try it out and change the radius to smaller
used to have our eyes on top of the body, with which we collide with our world, not values, the camera will be able to move closer to walls after this. The
in the middle of it. So we place the scene node 50 units over the center of the next parameter is the direction and speed of gravity. You could set it
ellipsoid with this parameter. And that's it, collision detection works now. to (0,0,0) to disable gravity. And the last value is just a
translation: Without this, 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, with which we collide with our world, 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.
*/ */
scene::ICameraSceneNode* camera = scene::ICameraSceneNode* camera =
smgr->addCameraSceneNodeFPS(0, 100.0f, 300.0f, -1, 0, 0, true); smgr->addCameraSceneNodeFPS(0, 100.0f, 300.0f, -1, 0, 0, true);
camera->setPosition(core::vector3df(-100,50,-150)); camera->setPosition(core::vector3df(-100,50,-150));
...@@ -128,7 +133,7 @@ int main() ...@@ -128,7 +133,7 @@ int main()
{ {
scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator( scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator(
selector, camera, core::vector3df(30,50,30), selector, camera, core::vector3df(30,50,30),
core::vector3df(0,-3,0), core::vector3df(0,-3,0),
core::vector3df(0,50,0)); core::vector3df(0,50,0));
camera->addAnimator(anim); camera->addAnimator(anim);
anim->drop(); anim->drop();
...@@ -137,7 +142,7 @@ int main() ...@@ -137,7 +142,7 @@ int main()
/* /*
Because collision detection is no big deal in irrlicht, I'll describe how to 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, 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 I'll prepare the scene a little. I need three animated characters which we
could pick later, a dynamic light for lighting them, could pick later, a dynamic light for lighting them,
a billboard for drawing where we found an intersection, and, yes, I need to a billboard for drawing where we found an intersection, and, yes, I need to
get rid of this mouse cursor. :) get rid of this mouse cursor. :)
...@@ -194,16 +199,16 @@ int main() ...@@ -194,16 +199,16 @@ int main()
/* /*
For not making it to complicated, I'm doing picking inside the drawing loop. For not making it to complicated, I'm doing picking inside the drawing
We take two pointers for storing the current and the last selected scene node and loop. We take two pointers for storing the current and the last
start the loop. selected scene node and start the loop.
*/ */
scene::ISceneNode* selectedSceneNode = 0; scene::ISceneNode* selectedSceneNode = 0;
scene::ISceneNode* lastSelectedSceneNode = 0; scene::ISceneNode* lastSelectedSceneNode = 0;
int lastFPS = -1; int lastFPS = -1;
while(device->run()) while(device->run())
...@@ -214,14 +219,16 @@ int main() ...@@ -214,14 +219,16 @@ int main()
smgr->drawAll(); smgr->drawAll();
/* /*
After we've drawn the whole scene whit smgr->drawAll(), we'll do the first After we've drawn the whole scene with smgr->drawAll(), we'll
picking: We want to know which triangle of the world we are looking at. In addition, do the first picking: We want to know which triangle of the
we want the exact point of the quake 3 level we are looking at. world we are looking at. In addition, we want the exact point
For this, we create a 3d line starting at the position of the camera and going of the quake 3 level we are looking at. For this, we create a
through the lookAt-target of it. Then we ask the collision manager if this line 3d line starting at the position of the camera and going
collides with a triangle of the world stored in the triangle selector. If yes, through the lookAt-target of it. Then we ask the collision
we draw the 3d triangle and set the position of the billboard to the intersection manager if this line collides with a triangle of the world
point. stored in the triangle selector. If yes, we draw the 3d
triangle and set the position of the billboard to the
intersection point.
*/ */
core::line3d<f32> line; core::line3d<f32> line;
...@@ -235,7 +242,7 @@ int main() ...@@ -235,7 +242,7 @@ int main()
line, selector, intersection, tri)) line, selector, intersection, tri))
{ {
bill->setPosition(intersection); bill->setPosition(intersection);
driver->setTransform(video::ETS_WORLD, core::matrix4()); driver->setTransform(video::ETS_WORLD, core::matrix4());
driver->setMaterial(material); driver->setMaterial(material);
driver->draw3DTriangle(tri, video::SColor(0,255,0,0)); driver->draw3DTriangle(tri, video::SColor(0,255,0,0));
...@@ -243,12 +250,13 @@ int main() ...@@ -243,12 +250,13 @@ int main()
/* /*
Another type of picking supported by the Irrlicht Engine is scene node picking Another type of picking supported by the Irrlicht Engine is
based on bouding boxes. Every scene node has got a bounding box, and because of scene node picking based on bounding boxes. Every scene node has
that, it's very fast for example to get the scene node which the camera looks got a bounding box, and because of that, it's very fast for
at. Again, we ask the collision manager for this, and if we've got a scene node, example to get the scene node which the camera looks at. Again,
we highlight it by disabling Lighting in its material, if it is not the we ask the collision manager for this, and if we've got a scene
billboard or the quake 3 level. node, we highlight it by disabling Lighting in its material, if
it is not the billboard or the quake 3 level.
*/ */
selectedSceneNode = smgr->getSceneCollisionManager()->getSceneNodeFromCameraBB(camera); selectedSceneNode = smgr->getSceneCollisionManager()->getSceneNodeFromCameraBB(camera);
...@@ -275,19 +283,21 @@ int main() ...@@ -275,19 +283,21 @@ int main()
if (lastFPS != fps) if (lastFPS != fps)
{ {
core::stringw str = L"Collision detection example - Irrlicht Engine ["; core::stringw str = L"Collision detection example - Irrlicht Engine [";
str += driver->getName(); str += driver->getName();
str += "] FPS:"; str += "] FPS:";
str += fps; str += fps;
device->setWindowCaption(str.c_str()); device->setWindowCaption(str.c_str());
lastFPS = fps; lastFPS = fps;
} }
} }
selector->drop(); selector->drop();
device->drop(); device->drop();
return 0; return 0;
} }
/*
**/
/* This tutorials describes how to do special effects. It shows how to use stencil /** Example 008 SpecialFX
buffer shadows, the particle system, billboards, dynamic light and the water
This tutorials 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. surface scene node.
We start like in some tutorials before. Please note that this time, the 'shadows' flag in We start like in some tutorials before. Please note that this time, the
createDevice() is set to true, for we want to have a dynamic shadow casted from 'shadows' flag in createDevice() is set to true, for we want to have a dynamic
an animated character. If your this example runs to slow, set it to false. shadow casted from an animated character. If this example runs too slow,
The Irrlicht Engine checks if your hardware doesn't support the stencil set it to false. The Irrlicht Engine checks if your hardware doesn't support
buffer, and disables shadows by itself, but just in case the demo runs slow the stencil buffer, and disables shadows by itself, but just in case the demo
on your hardware.*/ runs slow on your hardware.
*/
#include <irrlicht.h> #include <irrlicht.h>
#include <iostream> #include <iostream>
using namespace irr; using namespace irr;
#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib") #pragma comment(lib, "Irrlicht.lib")
#endif
int main() int main()
{ {
...@@ -25,7 +30,7 @@ int main() ...@@ -25,7 +30,7 @@ int main()
std::cin >> i; std::cin >> i;
bool shadows = (i == 'y'); const bool shadows = (i == 'y');
// ask user for driver // ask user for driver
...@@ -49,7 +54,10 @@ int main() ...@@ -49,7 +54,10 @@ int main()
default: return 1; default: return 1;
} }
// create device and exit if creation failed /*
Create device and exit if creation failed. We make the stencil flag
optional to avoid slow screen modes for runs without shadows.
*/
IrrlichtDevice *device = IrrlichtDevice *device =
createDevice(driverType, core::dimension2d<s32>(640, 480), createDevice(driverType, core::dimension2d<s32>(640, 480),
...@@ -63,41 +71,39 @@ int main() ...@@ -63,41 +71,39 @@ int main()
/* /*
For our environment, we load a .3ds file. It is a small room I modelled 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 with Anim8or and exported into the 3ds format because the Irrlicht
did not support the .an8 format when I wrote this tutorial. I am a very bad Engine does not support the .an8 format. I am a very bad 3d graphic
3d graphic artist, and so the texture mapping is not very nice in this model. 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 Luckily I am a better programmer than artist, and so the Irrlicht
is able to create a cool texture mapping for me: Just use the mesh manipulator Engine is able to create a cool texture mapping for me: Just use the
and create a planar texture mapping for the mesh. If you want to see the mapping mesh manipulator and create a planar texture mapping for the mesh. If
I made with Anim8or, uncomment this line. I also did not figure out how to you want to see the mapping I made with Anim8or, uncomment this line. I
set the material right in Anim8or, it has a specular light color which I don't really also did not figure out how to set the material right in Anim8or, it
like. I'll switch it off too with this code. has a specular light color which I don't really like. I'll switch it
off too with this code.
*/ */
scene::IAnimatedMesh* mesh = smgr->getMesh( scene::IAnimatedMesh* mesh = smgr->getMesh("../../media/room.3ds");
"../../media/room.3ds");
smgr->getMeshManipulator()->makePlanarTextureMapping( smgr->getMeshManipulator()->makePlanarTextureMapping(mesh->getMesh(0), 0.004f);
mesh->getMesh(0), 0.004f);
scene::ISceneNode* node = 0; scene::ISceneNode* node = 0;
node = smgr->addAnimatedMeshSceneNode(mesh); node = smgr->addAnimatedMeshSceneNode(mesh);
node->setMaterialTexture(0, driver->getTexture("../../media/wall.jpg")); node->setMaterialTexture(0, driver->getTexture("../../media/wall.jpg"));
node->getMaterial(0).SpecularColor.set(0,0,0,0); node->getMaterial(0).SpecularColor.set(0,0,0,0);
/* /*
Now, for the first special effect: Animated water. It works like this: The Now, for the first special effect: Animated water. It works like this:
WaterSurfaceSceneNode takes a mesh as input and makes The WaterSurfaceSceneNode takes a mesh as input and makes it wave like
it wave like a water surface. And if we let this scene node use a nice a water surface. And if we let this scene node use a nice material like
material like the EMT_REFLECTION_2_LAYER, it looks really cool. We are the EMT_REFLECTION_2_LAYER, it looks really cool. We are doing this
doing this with the next few lines of code. As input mesh, we create a hill with the next few lines of code. As input mesh, we create a hill plane
plane mesh, without hills. But any other mesh could be used for this, you could mesh, without hills. But any other mesh could be used for this, you
even use the room.3ds (which would look really strange) if you wanted to. could even use the room.3ds (which would look really strange) if you
want to.
*/ */
// add animated water
mesh = smgr->addHillPlaneMesh("myHill", mesh = smgr->addHillPlaneMesh("myHill",
core::dimension2d<f32>(20,20), core::dimension2d<f32>(20,20),
core::dimension2d<u32>(40,40), 0, 0, core::dimension2d<u32>(40,40), 0, 0,
...@@ -113,10 +119,10 @@ int main() ...@@ -113,10 +119,10 @@ int main()
node->setMaterialType(video::EMT_REFLECTION_2_LAYER); node->setMaterialType(video::EMT_REFLECTION_2_LAYER);
/* /*
The second special effect is very basic, I bet you saw it already in some The second special effect is very basic, I bet you saw it already in
Irrlicht Engine demos: A transparent billboard combined with a dynamic light. some Irrlicht Engine demos: A transparent billboard combined with a
We simply create a light scene node, let it fly around, an to make it look dynamic light. We simply create a light scene node, let it fly around,
more cool, we attach a billboard scene node to it. and to make it look more cool, we attach a billboard scene node to it.
*/ */
// create light // create light
...@@ -136,55 +142,62 @@ int main() ...@@ -136,55 +142,62 @@ int main()
node->setMaterialTexture(0, driver->getTexture("../../media/particlewhite.bmp")); node->setMaterialTexture(0, driver->getTexture("../../media/particlewhite.bmp"));
/* /*
The next special effect is a lot more interesting: A particle system. The particle The next special effect is a lot more interesting: A particle system.
system in the Irrlicht Engine is quit modular and extensible and yet easy to use. The particle system in the Irrlicht Engine is quite modular and
There is a particle system scene node into which you can put particle emitters, which extensible, but yet easy to use. There is a particle system scene node
make particles come out of nothing. These emitters are quite flexible and usually have into which you can put a particle emitter, which makes particles come out
lots of parameters like direction, amount and color of the particles they should create. of nothing. These emitters are quite flexible and usually have lots of
There are different emitters, for example a point emitter which lets particles pop out parameters like direction, amount, and color of the particles they
at a fixed point. If the particle emitters available in the engine are not enough for create.
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(). There are different emitters, for example a point emitter which lets
In this example we create a box particle emitter, which creates particles randomly particles pop out at a fixed point. If the particle emitters available
inside a box. The parameters define the box, direction of the particles, minimal and in the engine are not enough for you, you can easily create your own
maximal new particles per second, color and minimal and maximal livetime of the particles. ones, you'll simply have to create a class derived from the
IParticleEmitter interface and attach it to the particle system using
Because only with emitters particle system would be a little bit boring, setEmitter(). In this example we create a box particle emitter, which
there are particle affectors, which modify particles during they fly around. They can creates particles randomly inside a box. The parameters define the box,
be added to the particle system, simulating additional effects like gravity or wind. direction of the particles, minimal and maximal new particles per
The particle affector we use in this example is an affector, which modifies the color second, color, and minimal and maximal lifetime of the particles.
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 Because only with emitters particle system would be a little bit
IParticleAffector and add it with addAffector(). boring, there are particle affectors which modify particles while
they fly around. Affectors can be added to a particle system for
After we set a nice material to the particle system, we have a cool looking camp fire. simulating additional effects like gravity or wind.
By adjusting material, texture, particle emitter and affector parameters, it is also The particle affector we use in this example is an affector which
easily possible to create smoke, rain, explosions, snow, and so on. 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.
*/ */
// create a particle system // create a particle system
scene::IParticleSystemSceneNode* ps = 0; scene::IParticleSystemSceneNode* ps =
ps = smgr->addParticleSystemSceneNode(false); smgr->addParticleSystemSceneNode(false);
ps->setPosition(core::vector3df(-70,60,40)); ps->setPosition(core::vector3df(-70,60,40));
ps->setScale(core::vector3df(2,2,2)); ps->setScale(core::vector3df(2,2,2));
ps->setParticleSize(core::dimension2d<f32>(20.0f, 20.0f)); ps->setParticleSize(core::dimension2d<f32>(20.0f, 20.0f));
scene::IParticleEmitter* em = ps->createBoxEmitter( scene::IParticleEmitter* em = ps->createBoxEmitter(
core::aabbox3d<f32>(-7,0,-7,7,1,7), core::aabbox3d<f32>(-7,0,-7,7,1,7), // emitter size
core::vector3df(0.0f,0.06f,0.0f), core::vector3df(0.0f,0.06f,0.0f), // initial direction
80,100, 80,100, // emit rate
video::SColor(0,255,255,255), video::SColor(0,255,255,255), video::SColor(0,255,255,255), // darkest color
800,2000); video::SColor(0,255,255,255), // brightest color
800,2000); // min and max age
ps->setEmitter(em); ps->setEmitter(em); // this grabs the emitter
em->drop(); em->drop(); // so we can drop it here without deleting it
scene::IParticleAffector* paf = scene::IParticleAffector* paf = ps->createFadeOutParticleAffector();
ps->createFadeOutParticleAffector();
ps->addAffector(paf); ps->addAffector(paf); // same goes for the affector
paf->drop(); paf->drop();
ps->setMaterialFlag(video::EMF_LIGHTING, false); ps->setMaterialFlag(video::EMF_LIGHTING, false);
...@@ -192,24 +205,23 @@ int main() ...@@ -192,24 +205,23 @@ int main()
ps->setMaterialTexture(0, driver->getTexture("../../media/fire.bmp")); ps->setMaterialTexture(0, driver->getTexture("../../media/fire.bmp"));
ps->setMaterialType(video::EMT_TRANSPARENT_VERTEX_ALPHA); ps->setMaterialType(video::EMT_TRANSPARENT_VERTEX_ALPHA);
/* /*
Next we add a volumetric light node, which adds a glowing fake area light to 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 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 texture for the desired effect, though this time we'll use a texture animator
to create the illusion of a magical glowing area effect. to create the illusion of a magical glowing area effect.
*/ */
scene::IVolumeLightSceneNode * n = smgr->addVolumeLightSceneNode(0, -1, scene::IVolumeLightSceneNode * n = smgr->addVolumeLightSceneNode(0, -1,
32, // Subdivisions on U axis 32, // Subdivisions on U axis
32, // Subdivisions on V axis 32, // Subdivisions on V axis
video::SColor(0, 255, 255, 255), // foot color video::SColor(0, 255, 255, 255), // foot color
video::SColor(0, 0, 0, 0) // tail color video::SColor(0, 0, 0, 0)); // tail color
);
if (n)
if (n)
{ {
n->setScale(core::vector3df(56.0f, 56.0f, 56.0f)); n->setScale(core::vector3df(56.0f, 56.0f, 56.0f));
n->setPosition(core::vector3df(-120,50,40)); n->setPosition(core::vector3df(-120,50,40));
// load textures for animation // load textures for animation
core::array<video::ITexture*> textures; core::array<video::ITexture*> textures;
for (s32 g=7; g > 0; --g) for (s32 g=7; g > 0; --g)
...@@ -218,12 +230,12 @@ int main() ...@@ -218,12 +230,12 @@ int main()
tmp = "../../media/portal"; tmp = "../../media/portal";
tmp += g; tmp += g;
tmp += ".bmp"; tmp += ".bmp";
video::ITexture* t = driver->getTexture( tmp.c_str () ); video::ITexture* t = driver->getTexture( tmp.c_str() );
textures.push_back(t); textures.push_back(t);
} }
// create texture animator // create texture animator
scene::ISceneNodeAnimator *glow = smgr->createTextureAnimator(textures, 150); scene::ISceneNodeAnimator* glow = smgr->createTextureAnimator(textures, 150);
// add the animator // add the animator
n->addAnimator(glow); n->addAnimator(glow);
...@@ -233,17 +245,19 @@ int main() ...@@ -233,17 +245,19 @@ int main()
} }
/* /*
As our last special effect, we want a dynamic shadow be casted from an animated As our last special effect, we want a dynamic shadow be casted from an
character. For this we load a DirectX .x model and place it into our world. animated character. For this we load a DirectX .x model and place it
For creating the shadow, we simply need to call addShadowVolumeSceneNode(). into our world. For creating the shadow, we simply need to call
The color of shadows is only adjustable globally for all shadows, by calling addShadowVolumeSceneNode(). The color of shadows is only adjustable
ISceneManager::setShadowColor(). Voila, here is our dynamic shadow. 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 Because the character is a little bit too small for this scene, we make
to normalize the normals to make the lighting on it correct. This is always necessary if it bigger using setScale(). And because the character is lighted by a
the scale of a dynamic lighted model is not (1,1,1). Otherwise it would get too dark or dynamic light, we need to normalize the normals to make the lighting on
too bright because the normals will be scaled too. 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.
*/ */
// add animated character // add animated character
...@@ -260,7 +274,7 @@ int main() ...@@ -260,7 +274,7 @@ int main()
smgr->setShadowColor(video::SColor(150,0,0,0)); smgr->setShadowColor(video::SColor(150,0,0,0));
// make the model a little bit bigger and normalize its normals // make the model a little bit bigger and normalize its normals
// because of this for correct lighting // because of the scaling, for correct lighting
anode->setScale(core::vector3df(2,2,2)); anode->setScale(core::vector3df(2,2,2));
anode->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true); anode->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);
...@@ -274,8 +288,7 @@ int main() ...@@ -274,8 +288,7 @@ int main()
// disable mouse cursor // disable mouse cursor
device->getCursorControl()->setVisible(false); device->getCursorControl()->setVisible(false);
s32 lastFPS = -1;
int lastFPS = -1;
while(device->run()) while(device->run())
if (device->isWindowActive()) if (device->isWindowActive())
...@@ -286,7 +299,7 @@ int main() ...@@ -286,7 +299,7 @@ int main()
driver->endScene(); driver->endScene();
int fps = driver->getFPS(); const s32 fps = driver->getFPS();
if (lastFPS != fps) if (lastFPS != fps)
{ {
...@@ -305,3 +318,5 @@ int main() ...@@ -305,3 +318,5 @@ int main()
return 0; return 0;
} }
/*
**/
/* /** Example 009 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 scenemanagement of Irrlicht. This tutorial show how to create a more complex application with the engine.
The tutorial show how to create and use Buttons, Windows, Toolbars, Menus, ComboBoxes, We construct a simple mesh viewer using the user interface API and the
Tabcontrols, Editboxes, Images, MessageBoxes, SkyBoxes, and how to parse XML files scene management of Irrlicht. The tutorial show how to create and use Buttons,
with the integrated XML reader of the engine. Windows, Toolbars, Menus, ComboBoxes, Tabcontrols, Editboxes, Images,
MessageBoxes, SkyBoxes, and how to parse XML files with the integrated XML
We start like in most other tutorials: Include all nesessary header files, add a reader of the engine.
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 start like in most other tutorials: Include all nesessary header files, add
we do not need to write the whole names of all classes. In this tutorial, we use a a comment to let the engine be linked with the right .lib file in Visual
lot stuff from the gui namespace. 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
#include <irrlicht.h> tutorial, we use a lot stuff from the gui namespace.
#include <iostream> */
#include <irrlicht.h>
#include <iostream>
using namespace irr;
using namespace gui;
using namespace irr;
#pragma comment(lib, "Irrlicht.lib") using namespace gui;
#pragma comment(lib, "Irrlicht.lib")
IrrlichtDevice *Device = 0;
core::stringc StartUpModelFile;
core::stringw MessageText; /*
core::stringw Caption; Some global variables used later on
scene::IAnimatedMeshSceneNode* Model = 0; */
scene::ISceneNode* SkyBox = 0; IrrlichtDevice *Device = 0;
core::stringc StartUpModelFile;
scene::ICameraSceneNode* Camera[2] = { 0, 0}; core::stringw MessageText;
core::stringw Caption;
/* scene::IAnimatedMeshSceneNode* Model = 0;
toggles between various cameras scene::ISceneNode* SkyBox = 0;
*/
void setActiveCamera ( scene::ICameraSceneNode* newActive ) scene::ICameraSceneNode* Camera[2] = { 0, 0};
{
if ( 0 == Device ) /*
return; Toggle between various cameras
*/
scene::ICameraSceneNode* active = Device->getSceneManager()->getActiveCamera (); void setActiveCamera ( scene::ICameraSceneNode* newActive )
{
newActive->setInputReceiverEnabled ( true ); if ( 0 == Device )
Device->getSceneManager()->setActiveCamera ( newActive ); return;
}
scene::ICameraSceneNode* active = Device->getSceneManager()->getActiveCamera ();
/*
The three following functions do several stuff used by the mesh viewer. newActive->setInputReceiverEnabled ( true );
The first function showAboutText() simply displays a messagebox with a caption Device->getSceneManager()->setActiveCamera ( newActive );
and a message text. The texts will be stored in the MessageText and }
Caption variables at startup.
*/ /*
void showAboutText() The three following functions do several stuff used by the mesh viewer. The
{ first function showAboutText() simply displays a messagebox with a caption and
// create modal message box with the text a message text. The texts will be stored in the MessageText and Caption
// loaded from the xml file. variables at startup.
Device->getGUIEnvironment()->addMessageBox( */
Caption.c_str(), MessageText.c_str()); void showAboutText()
} {
// create modal message box with the text
// loaded from the xml file.
/* Device->getGUIEnvironment()->addMessageBox(
The second function loadModel() loads a model and displays it using an Caption.c_str(), MessageText.c_str());
addAnimatedMeshSceneNode and the scene manager. Nothing difficult. It also }
displays a short message box, if the model could not be loaded.
*/
void loadModel(const c8* fn) /*
{ The second function loadModel() loads a model and displays it using an
// modify the name if it a .pk3 file addAnimatedMeshSceneNode and the scene manager. Nothing difficult. It also
displays a short message box, if the model could not be loaded.
core::stringc filename ( fn ); */
void loadModel(const c8* fn)
core::stringc extension; {
core::getFileNameExtension ( extension, filename ); // modify the name if it a .pk3 file
extension.make_lower();
core::stringc filename ( fn );
// if a texture is loaded apply it to the current model..
if ( extension == ".jpg" || core::stringc extension;
extension == ".pcx" || core::getFileNameExtension ( extension, filename );
extension == ".png" || extension.make_lower();
extension == ".ppm" ||
extension == ".pgm" || // if a texture is loaded apply it to the current model..
extension == ".pbm" || if ( extension == ".jpg" ||
extension == ".psd" || extension == ".pcx" ||
extension == ".tga" || extension == ".png" ||
extension == ".bmp" extension == ".ppm" ||
) extension == ".pgm" ||
{ extension == ".pbm" ||
video::ITexture * texture = Device->getVideoDriver()->getTexture( filename.c_str() ); extension == ".psd" ||
if ( texture && Model ) extension == ".tga" ||
{ extension == ".bmp"
// always reload texture )
Device->getVideoDriver()->removeTexture ( texture ); {
texture = Device->getVideoDriver()->getTexture( filename.c_str() ); video::ITexture * texture = Device->getVideoDriver()->getTexture( filename.c_str() );
if ( texture && Model )
Model->setMaterialTexture ( 0, texture ); {
} // always reload texture
return; Device->getVideoDriver()->removeTexture ( texture );
} texture = Device->getVideoDriver()->getTexture( filename.c_str() );
// if a archive is loaded add it to the FileSystems.. Model->setMaterialTexture ( 0, texture );
if ( extension == ".pk3" || }
extension == ".zip" return;
) }
{
Device->getFileSystem()->addZipFileArchive( filename.c_str () ); // if a archive is loaded add it to the FileSystems..
return; if ( extension == ".pk3" ||
} extension == ".zip"
)
// load a model into the engine {
Device->getFileSystem()->addZipFileArchive( filename.c_str () );
if (Model) return;
Model->remove(); }
Model = 0; // load a model into the engine
scene::IAnimatedMesh* m = Device->getSceneManager()->getMesh( filename.c_str() ); if (Model)
Model->remove();
if (!m)
{ Model = 0;
// model could not be loaded
scene::IAnimatedMesh* m = Device->getSceneManager()->getMesh( filename.c_str() );
if (StartUpModelFile != filename)
Device->getGUIEnvironment()->addMessageBox( if (!m)
Caption.c_str(), L"The model could not be loaded. " \ {
L"Maybe it is not a supported file format."); // model could not be loaded
return;
} if (StartUpModelFile != filename)
Device->getGUIEnvironment()->addMessageBox(
// set default material properties Caption.c_str(), L"The model could not be loaded. " \
L"Maybe it is not a supported file format.");
Model = Device->getSceneManager()->addAnimatedMeshSceneNode(m); return;
Model->setMaterialFlag(video::EMF_LIGHTING, false); }
// Model->setMaterialFlag(video::EMF_BACK_FACE_CULLING, false);
Model->setDebugDataVisible(scene::EDS_OFF); // set default material properties
Model->setAnimationSpeed(30);
} Model = Device->getSceneManager()->addAnimatedMeshSceneNode(m);
Model->setMaterialFlag(video::EMF_LIGHTING, false);
// Model->setMaterialFlag(video::EMF_BACK_FACE_CULLING, false);
/* Model->setDebugDataVisible(scene::EDS_OFF);
Finally, the third function creates a toolbox window. In this simple mesh viewer, Model->setAnimationSpeed(30);
this toolbox only contains a tab control with three edit boxes for changing }
the scale of the displayed model.
*/
void createToolBox() /*
{ Finally, the third function creates a toolbox window. In this simple mesh
// remove tool box if already there viewer, this toolbox only contains a tab control with three edit boxes for
IGUIEnvironment* env = Device->getGUIEnvironment(); changing the scale of the displayed model.
IGUIElement* root = env->getRootGUIElement(); */
IGUIElement* e = root->getElementFromId(5000, true); void createToolBox()
if (e) e->remove(); {
// remove tool box if already there
// create the toolbox window IGUIEnvironment* env = Device->getGUIEnvironment();
IGUIWindow* wnd = env->addWindow(core::rect<s32>(600,25,800,480), IGUIElement* root = env->getRootGUIElement();
false, L"Toolset", 0, 5000); IGUIElement* e = root->getElementFromId(5000, true);
if (e) e->remove();
// create tab control and tabs
IGUITabControl* tab = env->addTabControl( // create the toolbox window
core::rect<s32>(2,20,800-602,480-7), wnd, true, true); IGUIWindow* wnd = env->addWindow(core::rect<s32>(600,25,800,480),
false, L"Toolset", 0, 5000);
IGUITab* t1 = tab->addTab(L"Scale");
// create tab control and tabs
// add some edit boxes and a button to tab one IGUITabControl* tab = env->addTabControl(
env->addEditBox(L"1.0", core::rect<s32>(40,50,130,70), true, t1, 901); core::rect<s32>(2,20,800-602,480-7), wnd, true, true);
env->addEditBox(L"1.0", core::rect<s32>(40,80,130,100), true, t1, 902);
env->addEditBox(L"1.0", core::rect<s32>(40,110,130,130), true, t1, 903); IGUITab* t1 = tab->addTab(L"Scale");
env->addButton(core::rect<s32>(10,150,100,190), t1, 1101, L"set"); // add some edit boxes and a button to tab one
env->addEditBox(L"1.0", core::rect<s32>(40,50,130,70), true, t1, 901);
// add senseless checkbox env->addEditBox(L"1.0", core::rect<s32>(40,80,130,100), true, t1, 902);
env->addCheckBox(true, core::rect<s32>(10,220,200,240), t1, -1, L"Senseless Checkbox"); env->addEditBox(L"1.0", core::rect<s32>(40,110,130,130), true, t1, 903);
// add undocumentated transparent control env->addButton(core::rect<s32>(10,150,100,190), t1, 1101, L"set");
env->addStaticText(L"Transparent Control:", core::rect<s32>(10,240,150,260), true, false, t1);
IGUIScrollBar* scrollbar = env->addScrollBar(true, core::rect<s32>(10,260,150,275), t1, 104); // add senseless checkbox
scrollbar->setMax(255); env->addCheckBox(true, core::rect<s32>(10,220,200,240), t1, -1, L"Senseless Checkbox");
scrollbar->setPos(255);
// add undocumented transparent control
// bring irrlicht engine logo to front, because it env->addStaticText(L"Transparent Control:", core::rect<s32>(10,240,150,260), true, false, t1);
// now may be below the newly created toolbox IGUIScrollBar* scrollbar = env->addScrollBar(true, core::rect<s32>(10,260,150,275), t1, 104);
root->bringToFront(root->getElementFromId(666, true)); scrollbar->setMax(255);
} scrollbar->setPos(255);
// bring irrlicht engine logo to front, because it
/* // now may be below the newly created toolbox
To get all the events sent by the GUI Elements, we need to create an event root->bringToFront(root->getElementFromId(666, true));
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.
*/ /*
class MyEventReceiver : public IEventReceiver 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
public: the caller and the event type, and starts an action based on these values. For
virtual bool OnEvent(const SEvent& event) example, if a menu item with id 100 was selected, if opens a file-open-dialog.
{ */
// Escape swaps Camera Input class MyEventReceiver : public IEventReceiver
if (event.EventType == EET_KEY_INPUT_EVENT && {
event.KeyInput.Key == irr::KEY_ESCAPE && public:
event.KeyInput.PressedDown == false) virtual bool OnEvent(const SEvent& event)
{ {
if ( Device ) // Escape swaps Camera Input
{ if (event.EventType == EET_KEY_INPUT_EVENT &&
scene::ICameraSceneNode * camera = Device->getSceneManager()->getActiveCamera (); event.KeyInput.Key == irr::KEY_ESCAPE &&
if ( camera ) event.KeyInput.PressedDown == false)
{ {
camera->setInputReceiverEnabled ( !camera->isInputReceiverEnabled() ); if ( Device )
} {
return true; scene::ICameraSceneNode * camera = Device->getSceneManager()->getActiveCamera ();
} if ( camera )
} {
camera->setInputReceiverEnabled ( !camera->isInputReceiverEnabled() );
if (event.EventType == EET_GUI_EVENT) }
{ return true;
s32 id = event.GUIEvent.Caller->getID(); }
IGUIEnvironment* env = Device->getGUIEnvironment(); }
switch(event.GUIEvent.EventType) if (event.EventType == EET_GUI_EVENT)
{ {
case EGET_MENU_ITEM_SELECTED: s32 id = event.GUIEvent.Caller->getID();
{ IGUIEnvironment* env = Device->getGUIEnvironment();
// a menu item was clicked
switch(event.GUIEvent.EventType)
IGUIContextMenu* menu = (IGUIContextMenu*)event.GUIEvent.Caller; {
s32 id = menu->getItemCommandId(menu->getSelectedItem()); case EGET_MENU_ITEM_SELECTED:
{
switch(id) // a menu item was clicked
{
case 100: // File -> Open Model IGUIContextMenu* menu = (IGUIContextMenu*)event.GUIEvent.Caller;
env->addFileOpenDialog(L"Please select a model file to open"); s32 id = menu->getItemCommandId(menu->getSelectedItem());
break;
case 101: // File -> Set Model Archive switch(id)
env->addFileOpenDialog(L"Please select your game archive/directory"); {
break; case 100: // File -> Open Model
case 200: // File -> Quit env->addFileOpenDialog(L"Please select a model file to open");
Device->closeDevice(); break;
break; case 101: // File -> Set Model Archive
case 300: // View -> Skybox env->addFileOpenDialog(L"Please select your game archive/directory");
SkyBox->setVisible(!SkyBox->isVisible()); break;
break; case 200: // File -> Quit
case 400: // View -> Debug Information Device->closeDevice();
if (Model) break;
Model->setDebugDataVisible(scene::EDS_OFF); case 300: // View -> Skybox
break; SkyBox->setVisible(!SkyBox->isVisible());
case 410: // View -> Debug Information break;
if (Model) case 400: // View -> Debug Information
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_BBOX)); if (Model)
break; Model->setDebugDataVisible(scene::EDS_OFF);
case 420: // View -> Debug Information break;
if (Model) case 410: // View -> Debug Information
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_NORMALS)); if (Model)
break; Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_BBOX));
case 430: // View -> Debug Information break;
if (Model) case 420: // View -> Debug Information
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_SKELETON)); if (Model)
break; Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_NORMALS));
case 440: // View -> Debug Information break;
if (Model) case 430: // View -> Debug Information
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_MESH_WIRE_OVERLAY)); if (Model)
break; Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_SKELETON));
case 450: // View -> Debug Information break;
if (Model) case 440: // View -> Debug Information
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_HALF_TRANSPARENCY)); if (Model)
break; Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_MESH_WIRE_OVERLAY));
case 460: // View -> Debug Information break;
if (Model) case 450: // View -> Debug Information
Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_BBOX_BUFFERS)); if (Model)
break; Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_HALF_TRANSPARENCY));
case 499: // View -> Debug Information break;
if (Model) case 460: // View -> Debug Information
Model->setDebugDataVisible(scene::EDS_FULL); if (Model)
break; Model->setDebugDataVisible((scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_BBOX_BUFFERS));
case 500: // Help->About break;
showAboutText(); case 499: // View -> Debug Information
break; if (Model)
case 610: // View -> Material -> Solid Model->setDebugDataVisible(scene::EDS_FULL);
if (Model) break;
Model->setMaterialType(video::EMT_SOLID); case 500: // Help->About
break; showAboutText();
case 620: // View -> Material -> Transparent break;
if (Model) case 610: // View -> Material -> Solid
Model->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR); if (Model)
break; Model->setMaterialType(video::EMT_SOLID);
case 630: // View -> Material -> Reflection break;
if (Model) case 620: // View -> Material -> Transparent
Model->setMaterialType(video::EMT_SPHERE_MAP); if (Model)
break; Model->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
break;
case 1000: case 630: // View -> Material -> Reflection
setActiveCamera ( Camera[0] ); if (Model)
break; Model->setMaterialType(video::EMT_SPHERE_MAP);
case 1100: break;
setActiveCamera ( Camera[1] );
break; case 1000:
setActiveCamera ( Camera[0] );
} break;
break; case 1100:
} setActiveCamera ( Camera[1] );
break;
case EGET_FILE_SELECTED:
{ }
// load the model file, selected in the file open dialog break;
IGUIFileOpenDialog* dialog = }
(IGUIFileOpenDialog*)event.GUIEvent.Caller;
loadModel(core::stringc(dialog->getFileName()).c_str()); case EGET_FILE_SELECTED:
} {
// load the model file, selected in the file open dialog
case EGET_SCROLL_BAR_CHANGED: IGUIFileOpenDialog* dialog =
(IGUIFileOpenDialog*)event.GUIEvent.Caller;
// control skin transparency loadModel(core::stringc(dialog->getFileName()).c_str());
if (id == 104) }
{
s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos(); case EGET_SCROLL_BAR_CHANGED:
for (s32 i=0; i<irr::gui::EGDC_COUNT ; ++i)
{ // control skin transparency
video::SColor col = env->getSkin()->getColor((EGUI_DEFAULT_COLOR)i); if (id == 104)
col.setAlpha(pos); {
env->getSkin()->setColor((EGUI_DEFAULT_COLOR)i, col); s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
} for (s32 i=0; i<irr::gui::EGDC_COUNT ; ++i)
} {
break; video::SColor col = env->getSkin()->getColor((EGUI_DEFAULT_COLOR)i);
col.setAlpha(pos);
case EGET_COMBO_BOX_CHANGED: env->getSkin()->setColor((EGUI_DEFAULT_COLOR)i, col);
}
// control anti-aliasing/filtering }
if (id == 108) break;
{
s32 pos = ((IGUIComboBox*)event.GUIEvent.Caller)->getSelected(); case EGET_COMBO_BOX_CHANGED:
switch (pos)
{ // control anti-aliasing/filtering
case 0: if (id == 108)
if (Model) {
{ s32 pos = ((IGUIComboBox*)event.GUIEvent.Caller)->getSelected();
Model->setMaterialFlag(video::EMF_BILINEAR_FILTER, false); switch (pos)
Model->setMaterialFlag(video::EMF_TRILINEAR_FILTER, false); {
Model->setMaterialFlag(video::EMF_ANISOTROPIC_FILTER, false); case 0:
} if (Model)
break; {
case 1: Model->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
if (Model) Model->setMaterialFlag(video::EMF_TRILINEAR_FILTER, false);
{ Model->setMaterialFlag(video::EMF_ANISOTROPIC_FILTER, false);
Model->setMaterialFlag(video::EMF_BILINEAR_FILTER, true); }
Model->setMaterialFlag(video::EMF_TRILINEAR_FILTER, false); break;
} case 1:
break; if (Model)
case 2: {
if (Model) Model->setMaterialFlag(video::EMF_BILINEAR_FILTER, true);
{ Model->setMaterialFlag(video::EMF_TRILINEAR_FILTER, false);
Model->setMaterialFlag(video::EMF_BILINEAR_FILTER, false); }
Model->setMaterialFlag(video::EMF_TRILINEAR_FILTER, true); break;
} case 2:
break; if (Model)
case 3: {
if (Model) Model->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
{ Model->setMaterialFlag(video::EMF_TRILINEAR_FILTER, true);
Model->setMaterialFlag(video::EMF_ANISOTROPIC_FILTER, true); }
} break;
break; case 3:
case 4: if (Model)
if (Model) {
{ Model->setMaterialFlag(video::EMF_ANISOTROPIC_FILTER, true);
Model->setMaterialFlag(video::EMF_ANISOTROPIC_FILTER, false); }
} break;
break; case 4:
} if (Model)
} {
break; Model->setMaterialFlag(video::EMF_ANISOTROPIC_FILTER, false);
}
case EGET_BUTTON_CLICKED: break;
}
switch(id) }
{ break;
case 1101:
{ case EGET_BUTTON_CLICKED:
// set scale
gui::IGUIElement* root = env->getRootGUIElement(); switch(id)
core::vector3df scale; {
core::stringc s; case 1101:
{
s = root->getElementFromId(901, true)->getText(); // set scale
scale.X = (f32)atof(s.c_str()); gui::IGUIElement* root = env->getRootGUIElement();
s = root->getElementFromId(902, true)->getText(); core::vector3df scale;
scale.Y = (f32)atof(s.c_str()); core::stringc s;
s = root->getElementFromId(903, true)->getText();
scale.Z = (f32)atof(s.c_str()); s = root->getElementFromId(901, true)->getText();
scale.X = (f32)atof(s.c_str());
if (Model) s = root->getElementFromId(902, true)->getText();
Model->setScale(scale); scale.Y = (f32)atof(s.c_str());
} s = root->getElementFromId(903, true)->getText();
break; scale.Z = (f32)atof(s.c_str());
case 1102:
env->addFileOpenDialog(L"Please select a model file to open"); if (Model)
break; Model->setScale(scale);
case 1103: }
showAboutText(); break;
break; case 1102:
case 1104: env->addFileOpenDialog(L"Please select a model file to open");
createToolBox(); break;
break; case 1103:
case 1105: showAboutText();
env->addFileOpenDialog(L"Please select your game archive/directory"); break;
break; case 1104:
} createToolBox();
break;
break; case 1105:
} env->addFileOpenDialog(L"Please select your game archive/directory");
} break;
}
return false;
} break;
}; }
}
/* return false;
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. Most of the hard work is done. We only need to create the Irrlicht Engine
As you can see, there is also a unusual call to IrrlichtDevice::setResizeAble(). device and all the buttons, menus and toolbars. We start up the engine as
This makes the render window resizeable, which is quite useful for a mesh viewer. usual, using createDevice(). To make our application catch events, we set our
*/ eventreceiver as parameter. The #ifdef WIN32 preprocessor commands are not
int main(int argc, char* argv[]) necessary, 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
// ask user for driver unusual call to IrrlichtDevice::setResizeAble(). This makes the render window
resizeable, which is quite useful for a mesh viewer.
video::E_DRIVER_TYPE driverType = video::EDT_DIRECT3D8; */
int main(int argc, char* argv[])
printf("Please select the driver you want for this example:\n"\ {
" (a) Direct3D 9.0c\n (b) Direct3D 8.1\n (c) OpenGL 1.5\n"\ // ask user for driver
" (d) Software Renderer\n (e) Burning's Software Renderer\n"\
" (f) NullDevice\n (otherKey) exit\n\n"); video::E_DRIVER_TYPE driverType = video::EDT_DIRECT3D8;
char key; printf("Please select the driver you want for this example:\n"\
std::cin >> key; " (a) Direct3D 9.0c\n (b) Direct3D 8.1\n (c) OpenGL 1.5\n"\
" (d) Software Renderer\n (e) Burning's Software Renderer\n"\
switch(key) " (f) NullDevice\n (otherKey) exit\n\n");
{
case 'a': driverType = video::EDT_DIRECT3D9;break; char key;
case 'b': driverType = video::EDT_DIRECT3D8;break; std::cin >> key;
case 'c': driverType = video::EDT_OPENGL; break;
case 'd': driverType = video::EDT_SOFTWARE; break; switch(key)
case 'e': driverType = video::EDT_BURNINGSVIDEO;break; {
case 'f': driverType = video::EDT_NULL; break; case 'a': driverType = video::EDT_DIRECT3D9;break;
default: return 1; case 'b': driverType = video::EDT_DIRECT3D8;break;
} case 'c': driverType = video::EDT_OPENGL; break;
case 'd': driverType = video::EDT_SOFTWARE; break;
// create device and exit if creation failed case 'e': driverType = video::EDT_BURNINGSVIDEO;break;
case 'f': driverType = video::EDT_NULL; break;
MyEventReceiver receiver; default: return 1;
Device = createDevice(driverType, core::dimension2d<s32>(800, 600), }
16, false, false, false, &receiver);
// create device and exit if creation failed
if (Device == 0)
return 1; // could not create selected driver. MyEventReceiver receiver;
Device = createDevice(driverType, core::dimension2d<s32>(800, 600),
Device->setResizeAble(true); 16, false, false, false, &receiver);
Device->setWindowCaption(L"Irrlicht Engine - Loading..."); if (Device == 0)
return 1; // could not create selected driver.
video::IVideoDriver* driver = Device->getVideoDriver();
IGUIEnvironment* env = Device->getGUIEnvironment(); Device->setResizeAble(true);
scene::ISceneManager* smgr = Device->getSceneManager();
smgr->getParameters()->setAttribute(scene::COLLADA_CREATE_SCENE_INSTANCES, true); Device->setWindowCaption(L"Irrlicht Engine - Loading...");
driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true); video::IVideoDriver* driver = Device->getVideoDriver();
IGUIEnvironment* env = Device->getGUIEnvironment();
smgr->addLightSceneNode(); scene::ISceneManager* smgr = Device->getSceneManager();
smgr->addLightSceneNode(0, core::vector3df(50,-50,100), video::SColorf(1.0f,1.0f,1.0f),20000); smgr->getParameters()->setAttribute(scene::COLLADA_CREATE_SCENE_INSTANCES, true);
// add our media directory as "search path"
Device->getFileSystem()->addFolderFileArchive ( "../../media/" ); driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true);
/* smgr->addLightSceneNode();
The next step is to read the configuration file. It is stored in the xml smgr->addLightSceneNode(0, core::vector3df(50,-50,100), video::SColorf(1.0f,1.0f,1.0f),20000);
format and looks a little bit like this: // add our media directory as "search path"
Device->getFileSystem()->addFolderFileArchive ( "../../media/" );
<?xml version="1.0"?>
<config> /*
<startUpModel file="some filename" /> The next step is to read the configuration file. It is stored in the xml
<messageText caption="Irrlicht Engine Mesh Viewer"> format and looks a little bit like this:
Hello!
</messageText> @verbatim
</config> <?xml version="1.0"?>
<config>
We need the data stored in there to be written into the global variables <startUpModel file="some filename" />
StartUpModelFile, MessageText and Caption. This is now done using the <messageText caption="Irrlicht Engine Mesh Viewer">
Irrlicht Engine integrated XML parser: Hello!
*/ </messageText>
</config>
// read configuration from xml file @endverbatim
io::IXMLReader* xml = Device->getFileSystem()->createXMLReader( We need the data stored in there to be written into the global variables
"config.xml"); StartUpModelFile, MessageText and Caption. This is now done using the
Irrlicht Engine integrated XML parser:
while(xml && xml->read()) */
{
switch(xml->getNodeType()) // read configuration from xml file
{
case io::EXN_TEXT: io::IXMLReader* xml = Device->getFileSystem()->createXMLReader("config.xml");
// in this xml file, the only text which occurs is the messageText
MessageText = xml->getNodeData(); while(xml && xml->read())
break; {
case io::EXN_ELEMENT: switch(xml->getNodeType())
{ {
if (core::stringw("startUpModel") == xml->getNodeName()) case io::EXN_TEXT:
StartUpModelFile = xml->getAttributeValue(L"file"); // in this xml file, the only text which occurs is the
else // messageText
if (core::stringw("messageText") == xml->getNodeName()) MessageText = xml->getNodeData();
Caption = xml->getAttributeValue(L"caption"); break;
} case io::EXN_ELEMENT:
break; {
} if (core::stringw("startUpModel") == xml->getNodeName())
} StartUpModelFile = xml->getAttributeValue(L"file");
else
if (xml) if (core::stringw("messageText") == xml->getNodeName())
xml->drop(); // don't forget to delete the xml reader Caption = xml->getAttributeValue(L"caption");
}
if (argc > 1) break;
StartUpModelFile = argv[1]; }
}
/*
That wasn't difficult. Now we'll set a nicer font and create the if (xml)
Menu. It is possible to create submenus for every menu item. The call xml->drop(); // don't forget to delete the xml reader
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 if (argc > 1)
that the menu item should be enabled, and the last one says, that StartUpModelFile = argv[1];
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. 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
// set a nicer font 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
IGUISkin* skin = env->getSkin(); should be a submenu. The submenu can now be accessed with
IGUIFont* font = env->getFont("fonthaettenschweiler.bmp"); menu->getSubMenu(0), because the "File" entry is the menu item with
if (font) index 0.
skin->setFont(font); */
// create menu // set a nicer font
gui::IGUIContextMenu* menu = env->addMenu();
menu->addItem(L"File", -1, true, true); IGUISkin* skin = env->getSkin();
menu->addItem(L"View", -1, true, true); IGUIFont* font = env->getFont("fonthaettenschweiler.bmp");
menu->addItem(L"Camera", -1, true, true); if (font)
menu->addItem(L"Help", -1, true, true); skin->setFont(font);
gui::IGUIContextMenu* submenu; // create menu
submenu = menu->getSubMenu(0); gui::IGUIContextMenu* menu = env->addMenu();
submenu->addItem(L"Open Model File & Texture...", 100); menu->addItem(L"File", -1, true, true);
submenu->addItem(L"Set Model Archive...", 101); menu->addItem(L"View", -1, true, true);
submenu->addSeparator(); menu->addItem(L"Camera", -1, true, true);
submenu->addItem(L"Quit", 200); menu->addItem(L"Help", -1, true, true);
submenu = menu->getSubMenu(1); gui::IGUIContextMenu* submenu;
submenu->addItem(L"toggle sky box visibility", 300); submenu = menu->getSubMenu(0);
submenu->addItem(L"toggle model debug information", -1, true, true); submenu->addItem(L"Open Model File & Texture...", 100);
submenu->addItem(L"model material", -1, true, true ); submenu->addItem(L"Set Model Archive...", 101);
submenu->addSeparator();
submenu = submenu->getSubMenu(1); submenu->addItem(L"Quit", 200);
submenu->addItem(L"Off", 400);
submenu->addItem(L"Bounding Box", 410); submenu = menu->getSubMenu(1);
submenu->addItem(L"Normals", 420); submenu->addItem(L"toggle sky box visibility", 300);
submenu->addItem(L"Skeleton", 430); submenu->addItem(L"toggle model debug information", -1, true, true);
submenu->addItem(L"Wire overlay", 440); submenu->addItem(L"model material", -1, true, true );
submenu->addItem(L"Half-Transparent", 450);
submenu->addItem(L"Buffers bounding boxes", 460); submenu = submenu->getSubMenu(1);
submenu->addItem(L"All", 499); submenu->addItem(L"Off", 400);
submenu->addItem(L"Bounding Box", 410);
submenu = menu->getSubMenu(1)->getSubMenu(2); submenu->addItem(L"Normals", 420);
submenu->addItem(L"Solid", 610); submenu->addItem(L"Skeleton", 430);
submenu->addItem(L"Transparent", 620); submenu->addItem(L"Wire overlay", 440);
submenu->addItem(L"Reflection", 630); submenu->addItem(L"Half-Transparent", 450);
submenu->addItem(L"Buffers bounding boxes", 460);
submenu = menu->getSubMenu(2); submenu->addItem(L"All", 499);
submenu->addItem(L"Maya Style", 1000);
submenu->addItem(L"First Person", 1100); submenu = menu->getSubMenu(1)->getSubMenu(2);
submenu->addItem(L"Solid", 610);
submenu = menu->getSubMenu(3); submenu->addItem(L"Transparent", 620);
submenu->addItem(L"About", 500); submenu->addItem(L"Reflection", 630);
/* submenu = menu->getSubMenu(2);
Below the toolbar, we want a toolbar, onto which we can place submenu->addItem(L"Maya Style", 1000);
colored buttons and important looking stuff like a senseless submenu->addItem(L"First Person", 1100);
combobox.
*/ submenu = menu->getSubMenu(3);
submenu->addItem(L"About", 500);
// create toolbar
/*
gui::IGUIToolBar* bar = env->addToolBar(); Below the menu we want a toolbar, onto which we can place colored
buttons and important looking stuff like a senseless combobox.
video::ITexture* image = driver->getTexture("open.png"); */
bar->addButton(1102, 0, L"Open a model",image, 0, false, true);
// create toolbar
image = driver->getTexture("tools.png");
bar->addButton(1104, 0, L"Open Toolset",image, 0, false, true); gui::IGUIToolBar* bar = env->addToolBar();
image = driver->getTexture("zip.png"); video::ITexture* image = driver->getTexture("open.png");
bar->addButton(1105, 0, L"Set Model Archive",image, 0, false, true); bar->addButton(1102, 0, L"Open a model",image, 0, false, true);
image = driver->getTexture("help.png"); image = driver->getTexture("tools.png");
bar->addButton(1103, 0, L"Open Help", image, 0, false, true); bar->addButton(1104, 0, L"Open Toolset",image, 0, false, true);
// create a combobox with some senseless texts image = driver->getTexture("zip.png");
bar->addButton(1105, 0, L"Set Model Archive",image, 0, false, true);
gui::IGUIComboBox* box = env->addComboBox(core::rect<s32>(250,4,350,23), bar, 108);
box->addItem(L"No filtering"); image = driver->getTexture("help.png");
box->addItem(L"Bilinear"); bar->addButton(1103, 0, L"Open Help", image, 0, false, true);
box->addItem(L"Trilinear");
box->addItem(L"Anisotropic"); // create a combobox with some senseless texts
box->addItem(L"Isotropic");
gui::IGUIComboBox* box = env->addComboBox(core::rect<s32>(250,4,350,23), bar, 108);
/* box->addItem(L"No filtering");
To make the editor look a little bit better, we disable transparent box->addItem(L"Bilinear");
gui elements, and add a Irrlicht Engine logo. In addition, a text box->addItem(L"Trilinear");
showing the current frame per second value is created and box->addItem(L"Anisotropic");
the window caption is changed. box->addItem(L"Isotropic");
*/
/*
// disable alpha 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
for (s32 i=0; i<gui::EGDC_COUNT ; ++i) the current frames per second value is created and the window caption is
{ changed.
video::SColor col = env->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i); */
col.setAlpha(255);
env->getSkin()->setColor((gui::EGUI_DEFAULT_COLOR)i, col); // disable alpha
}
for (s32 i=0; i<gui::EGDC_COUNT ; ++i)
// add a tabcontrol {
video::SColor col = env->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);
createToolBox(); col.setAlpha(255);
env->getSkin()->setColor((gui::EGUI_DEFAULT_COLOR)i, col);
// create fps text }
IGUIStaticText* fpstext = env->addStaticText(L"", core::rect<s32>(400,4,570,23), true, false, bar); // add a tabcontrol
// set window caption createToolBox();
Caption += " - ["; // create fps text
Caption += driver->getName();
Caption += "]"; IGUIStaticText* fpstext = env->addStaticText(L"", core::rect<s32>(400,4,570,23), true, false, bar);
Device->setWindowCaption(Caption.c_str());
// set window caption
/*
That's nearly the whole application. We simply show the about Caption += " - [";
message box at start up, and load the first model. To make everything Caption += driver->getName();
look better, a skybox is created and a user controled camera, Caption += "]";
to make the application a little bit more interactive. Finally, Device->setWindowCaption(Caption.c_str());
everything is drawed in a standard drawing loop.
*/ /*
That's nearly the whole application. We simply show the about message
// show about message box and load default model box at start up, and load the first model. To make everything look
if (argc==1) better, a skybox is created and a user controled camera, to make the
showAboutText(); application a little bit more interactive. Finally, everything is drawn
loadModel(StartUpModelFile.c_str()); in a standard drawing loop.
*/
// add skybox
// show about message box and load default model
SkyBox = smgr->addSkyBoxSceneNode( if (argc==1)
driver->getTexture("irrlicht2_up.jpg"), showAboutText();
driver->getTexture("irrlicht2_dn.jpg"), loadModel(StartUpModelFile.c_str());
driver->getTexture("irrlicht2_lf.jpg"),
driver->getTexture("irrlicht2_rt.jpg"), // add skybox
driver->getTexture("irrlicht2_ft.jpg"),
driver->getTexture("irrlicht2_bk.jpg")); SkyBox = smgr->addSkyBoxSceneNode(
driver->getTexture("irrlicht2_up.jpg"),
// add a camera scene node driver->getTexture("irrlicht2_dn.jpg"),
Camera[0] = smgr->addCameraSceneNodeMaya(); driver->getTexture("irrlicht2_lf.jpg"),
Camera[0]->setFarValue(20000.f); driver->getTexture("irrlicht2_rt.jpg"),
Camera[1] = smgr->addCameraSceneNodeFPS(); driver->getTexture("irrlicht2_ft.jpg"),
Camera[1]->setFarValue(20000.f); driver->getTexture("irrlicht2_bk.jpg"));
setActiveCamera ( Camera[0] ); // add a camera scene node
Camera[0] = smgr->addCameraSceneNodeMaya();
// load the irrlicht engine logo Camera[0]->setFarValue(20000.f);
IGUIImage *img = Camera[1] = smgr->addCameraSceneNodeFPS();
env->addImage(driver->getTexture("irrlichtlogo2.png"), Camera[1]->setFarValue(20000.f);
core::position2d<s32>(10, driver->getScreenSize().Height - 128));
setActiveCamera ( Camera[0] );
// lock the logo's edges to the bottom left corner of the screen
img->setAlignment(EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT); // load the irrlicht engine logo
IGUIImage *img =
// draw everything env->addImage(driver->getTexture("irrlichtlogo2.png"),
core::position2d<s32>(10, driver->getScreenSize().Height - 128));
while(Device->run() && driver)
{ // lock the logo's edges to the bottom left corner of the screen
if (Device->isWindowActive()) img->setAlignment(EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT);
{
driver->beginScene(true, true, video::SColor(150,50,50,50)); // draw everything
smgr->drawAll(); while(Device->run() && driver)
env->drawAll(); {
if (Device->isWindowActive())
driver->endScene(); {
driver->beginScene(true, true, video::SColor(150,50,50,50));
core::stringw str(L"FPS: ");
str.append(core::stringw(driver->getFPS())); smgr->drawAll();
str += L" Tris: "; env->drawAll();
str.append(core::stringw(driver->getPrimitiveCountDrawn()));
fpstext->setText(str.c_str()); driver->endScene();
}
else core::stringw str(L"FPS: ");
Device->yield(); str.append(core::stringw(driver->getFPS()));
} str += L" Tris: ";
str.append(core::stringw(driver->getPrimitiveCountDrawn()));
Device->drop(); fpstext->setText(str.c_str());
return 0; }
} else
Device->yield();
}
Device->drop();
return 0;
}
/*
**/
/* /** Example 010 Shaders
This tutorial shows how to use shaders for D3D8, D3D9 and OpenGL
with the engine and how to create new material types with them. It also This tutorial shows how to use shaders for D3D8, D3D9, and OpenGL with the
shows how to disable the generation of mipmaps at texture loading, and engine and how to create new material types with them. It also shows how to
how to use text scene nodes. 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 This tutorial does not explain how shaders work. I would recommend to read the
or OpenGL documentation, to search a tutorial, or to read a book about this. 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 At first, we need to include all headers and do the stuff we always do, like in
in nearly all other tutorials: nearly all other tutorials:
*/ */
#include <irrlicht.h> #include <irrlicht.h>
#include <iostream> #include <iostream>
using namespace irr; using namespace irr;
#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib") #pragma comment(lib, "Irrlicht.lib")
#endif
/* /*
Because we want to use some interesting shaders in this tutorials, we Because we want to use some interesting shaders in this tutorials, we need to
need to set some data for them to make them able to compute nice set some data for them to make them able to compute nice colors. In this
colors. In this example, we'll use a simple vertex shader which will example, we'll use a simple vertex shader which will calculate the color of the
calculate the color of the vertex based on the position of the camera. vertex based on the position of the camera.
For this, the shader needs the following data: The inverted world matrix For this, the shader needs the following data: The inverted world matrix for
for transforming the normal, the clip matrix for transforming the position, transforming the normal, the clip matrix for transforming the position, the
the camera position and the world position of the object for the calculation camera position and the world position of the object for the calculation of the
of the angle of light, and the color of the light. To be able to tell the angle of light, and the color of the light. To be able to tell the shader all
shader all this data every frame, we have to derive a class from the this data every frame, we have to derive a class from the
IShaderConstantSetCallBack interface and override its only method, IShaderConstantSetCallBack interface and override its only method, namely
namely OnSetConstants(). This method will be called every time the material OnSetConstants(). This method will be called every time the material is set.
is set.
The method setVertexShaderConstant() of the IMaterialRendererServices interface 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 is used to set the data the shader needs. If the user chose to use a High Level
language like HLSL instead of Assembler in this example, you have to set the shader language like HLSL instead of Assembler in this example, you have to set
variable name as parameter instead of the register index. the variable name as parameter instead of the register index.
*/ */
IrrlichtDevice* device = 0; IrrlichtDevice* device = 0;
...@@ -83,7 +84,7 @@ public: ...@@ -83,7 +84,7 @@ public:
else else
services->setVertexShaderConstant(reinterpret_cast<f32*>(&pos), 8, 1); services->setVertexShaderConstant(reinterpret_cast<f32*>(&pos), 8, 1);
// set light color // set light color
video::SColorf col(0.0f,1.0f,1.0f,0.0f); video::SColorf col(0.0f,1.0f,1.0f,0.0f);
...@@ -105,9 +106,9 @@ public: ...@@ -105,9 +106,9 @@ public:
}; };
/* /*
The next few lines start up the engine. Just like in most other tutorials 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 before. But in addition, we ask the user if he wants to use high level shaders
high level shaders if he selected a driver which is capable of doing so. in this example, if he selected a driver which is capable of doing so.
*/ */
int main() int main()
{ {
...@@ -135,7 +136,7 @@ int main() ...@@ -135,7 +136,7 @@ int main()
} }
// ask the user if we should use high level shaders for this example // ask the user if we should use high level shaders for this example
if (driverType == video::EDT_DIRECT3D9 || if (driverType == video::EDT_DIRECT3D9 ||
driverType == video::EDT_OPENGL) driverType == video::EDT_OPENGL)
{ {
printf("Please press 'y' if you want to use high level shaders.\n"); printf("Please press 'y' if you want to use high level shaders.\n");
...@@ -157,15 +158,15 @@ int main() ...@@ -157,15 +158,15 @@ int main()
gui::IGUIEnvironment* gui = device->getGUIEnvironment(); gui::IGUIEnvironment* gui = device->getGUIEnvironment();
/* /*
Now for the more interesting parts. Now for the more interesting parts. If we are using Direct3D, we want
If we are using Direct3D, we want to load vertex and pixel shader programs, if we have to load vertex and pixel shader programs, if we have OpenGL, we want to
OpenGL, we want to use ARB fragment and vertex programs. I wrote the use ARB fragment and vertex programs. I wrote the corresponding
corresponding programs down into the files d3d8.ps, d3d8.vs, d3d9.ps, d3d9.vs, programs down into the files d3d8.ps, d3d8.vs, d3d9.ps, d3d9.vs,
opengl.ps and opengl.vs. We only need the right filenames now. This is done in the opengl.ps and opengl.vs. We only need the right filenames now. This is
following switch. Note, that it is not necessary to write the shaders into text done in the following switch. Note, that it is not necessary to write
files, like in this example. You can even write the shaders directly as strings the shaders into text files, like in this example. You can even write
into the cpp source file, and use later addShaderMaterial() instead of the shaders directly as strings into the cpp source file, and use later
addShaderMaterialFromFiles(). addShaderMaterial() instead of addShaderMaterialFromFiles().
*/ */
c8* vsFileName = 0; // filename for the vertex shader c8* vsFileName = 0; // filename for the vertex shader
...@@ -205,15 +206,16 @@ int main() ...@@ -205,15 +206,16 @@ int main()
} }
/* /*
In addition, we check if the hardware and the selected renderer is capable In addition, we check if the hardware and the selected renderer is
of executing the shaders we want. If not, we simply set the filename string capable of executing the shaders we want. If not, we simply set the
to 0. This is not necessary, but useful in this example: For example, if filename string to 0. This is not necessary, but useful in this
the hardware is able to execute vertex shaders but not pixel shaders, we create example: For example, if the hardware is able to execute vertex shaders
a new material which only uses the vertex shader, and no pixel shader. but not pixel shaders, we create a new material which only uses the
Otherwise, if we would tell the engine to create this material and the engine vertex shader, and no pixel shader. Otherwise, if we would tell the
sees that the hardware wouldn't be able to fullfill the request completely, engine to create this material and the engine sees that the hardware
it would not create any new material at all. So in this example you would see wouldn't be able to fullfill the request completely, it would not
at least the vertex shader in action, without the pixel shader. create any new material at all. So in this example you would see at
least the vertex shader in action, without the pixel shader.
*/ */
if (!driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) && if (!driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
...@@ -233,22 +235,26 @@ int main() ...@@ -233,22 +235,26 @@ int main()
} }
/* /*
Now lets create the new materials. Now lets create the new materials. As you maybe know from previous
As you maybe know from previous examples, a material type in the Irrlicht engine examples, a material type in the Irrlicht engine is set by simply
is set by simply changing the MaterialType value in the SMaterial struct. And this changing the MaterialType value in the SMaterial struct. And this value
value is just a simple 32 bit value, like video::EMT_SOLID. So we only need the is just a simple 32 bit value, like video::EMT_SOLID. So we only need
engine to create a new value for us which we can set there. the engine to create a new value for us which we can set there. To do
To do this, we get a pointer to the IGPUProgrammingServices and call this, we get a pointer to the IGPUProgrammingServices and call
addShaderMaterialFromFiles(), which returns such a new 32 bit value. That's all. addShaderMaterialFromFiles(), which returns such a new 32 bit value.
The parameters to this method are the following: That's all.
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 The parameters to this method are the following: First, the names of
could write the code of the shader directly as string. the files containing the code of the vertex and the pixel shader. If
The following parameter is a pointer to the IShaderConstantSetCallBack class we wrote you would use addShaderMaterial() instead, you would not need file
at the beginning of this tutorial. If you don't want to set constants, set this to 0. names, then you could write the code of the shader directly as string.
The last paramter tells the engine which material it should use as base material. The following parameter is a pointer to the IShaderConstantSetCallBack
To demonstrate this, we create two materials with a different base material, one class we wrote at the beginning of this tutorial. If you don't want to
with EMT_SOLID and one with EMT_TRANSPARENT_ADD_COLOR. set constants, set this to 0. The last paramter 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 materials // create materials
...@@ -293,10 +299,10 @@ int main() ...@@ -293,10 +299,10 @@ int main()
} }
/* /*
Now time for testing out the materials. We create a test cube Now it's time for testing the materials. We create a test cube and set
and set the material we created. In addition, we add a text scene node to the material we created. In addition, we add a text scene node to the
the cube and a rotation animator to make it look more interesting and cube and a rotation animator to make it look more interesting and
important. important.
*/ */
// create test scene node 1, with the new created material type 1 // create test scene node 1, with the new created material type 1
...@@ -307,8 +313,8 @@ int main() ...@@ -307,8 +313,8 @@ int main()
node->setMaterialFlag(video::EMF_LIGHTING, false); node->setMaterialFlag(video::EMF_LIGHTING, false);
node->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType1); node->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType1);
smgr->addTextSceneNode(gui->getBuiltInFont(), smgr->addTextSceneNode(gui->getBuiltInFont(),
L"PS & VS & EMT_SOLID", L"PS & VS & EMT_SOLID",
video::SColor(255,255,255,255), node); video::SColor(255,255,255,255), node);
scene::ISceneNodeAnimator* anim = smgr->createRotationAnimator( scene::ISceneNodeAnimator* anim = smgr->createRotationAnimator(
...@@ -328,8 +334,8 @@ int main() ...@@ -328,8 +334,8 @@ int main()
node->setMaterialFlag(video::EMF_LIGHTING, false); node->setMaterialFlag(video::EMF_LIGHTING, false);
node->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType2); node->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType2);
smgr->addTextSceneNode(gui->getBuiltInFont(), smgr->addTextSceneNode(gui->getBuiltInFont(),
L"PS & VS & EMT_TRANSPARENT", L"PS & VS & EMT_TRANSPARENT",
video::SColor(255,255,255,255), node); video::SColor(255,255,255,255), node);
anim = smgr->createRotationAnimator(core::vector3df(0,0.3f,0)); anim = smgr->createRotationAnimator(core::vector3df(0,0.3f,0));
...@@ -337,11 +343,11 @@ int main() ...@@ -337,11 +343,11 @@ int main()
anim->drop(); anim->drop();
/* /*
Then we add a third cube without a shader on it, to be able to compare the Then we add a third cube without a shader on it, to be able to compare
cubes. the cubes.
*/ */
// add a scene node with no shader // add a scene node with no shader
node = smgr->addCubeSceneNode(50); node = smgr->addCubeSceneNode(50);
node->setPosition(core::vector3df(0,50,25)); node->setPosition(core::vector3df(0,50,25));
...@@ -394,13 +400,13 @@ int main() ...@@ -394,13 +400,13 @@ int main()
if (lastFPS != fps) if (lastFPS != fps)
{ {
core::stringw str = L"Irrlicht Engine - Vertex and pixel shader example ["; core::stringw str = L"Irrlicht Engine - Vertex and pixel shader example [";
str += driver->getName(); str += driver->getName();
str += "] FPS:"; str += "] FPS:";
str += fps; str += fps;
device->setWindowCaption(str.c_str()); device->setWindowCaption(str.c_str());
lastFPS = fps; lastFPS = fps;
} }
} }
...@@ -409,3 +415,6 @@ int main() ...@@ -409,3 +415,6 @@ int main()
return 0; return 0;
} }
/*
Compile and run this, and I hope you have fun with your new little shader writing tool :).
**/
/* /** Example 011 Per-Pixel Lighting
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 This tutorial shows how to use one of the built in more complex materials in
how to use fog and moving particle systems. And don't panic: You dont need any irrlicht: Per pixel lighted surfaces using normal maps and parallax mapping. It
experience with shaders to use these materials in Irrlicht. will also show how to use fog and moving particle systems. And don't panic: You
dont 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 At first, we need to include all headers and do the stuff we always do, like in
in nearly all other tutorials. nearly all other tutorials.
*/ */
#include <irrlicht.h> #include <irrlicht.h>
#include <iostream> #include <iostream>
using namespace irr; using namespace irr;
#pragma comment(lib, "Irrlicht.lib") #pragma comment(lib, "Irrlicht.lib")
/* /*
For this example, we need an event receiver, to make it possible for the user 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 to switch between the three available material types. In addition, the event
receiver will create some small GUI window which displays what material is 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 currently being used. There is nothing special done in this class, so maybe you
you want to skip reading it. want to skip reading it.
*/ */
class MyEventReceiver : public IEventReceiver class MyEventReceiver : public IEventReceiver
{ {
...@@ -120,13 +119,14 @@ private: ...@@ -120,13 +119,14 @@ private:
Room->setMaterialType(type); Room->setMaterialType(type);
/* /*
We need to add a warning if the materials will not be able to be We need to add a warning if the materials will not be able to
displayed 100% correctly. This is no problem, they will be renderered be displayed 100% correctly. This is no problem, they will be
using fall back materials, but at least the user should know that renderered using fall back materials, but at least the user
it would look better on better hardware. should know that it would look better on better hardware. We
We simply check if the material renderer is able to draw at full simply check if the material renderer is able to draw at full
quality on the current hardware. The IMaterialRenderer::getRenderCapability() quality on the current hardware. The
returns 0 if this is the case. IMaterialRenderer::getRenderCapability() returns 0 if this is
the case.
*/ */
video::IMaterialRenderer* renderer = Driver->getMaterialRenderer(type); video::IMaterialRenderer* renderer = Driver->getMaterialRenderer(type);
...@@ -186,11 +186,11 @@ int main() ...@@ -186,11 +186,11 @@ int main()
/* /*
Before we start with the interesting stuff, we do some simple things: Before we start with the interesting stuff, we do some simple things:
Store pointers to the most important parts of the engine (video driver, Store pointers to the most important parts of the engine (video driver,
scene manager, gui environment) to safe us from typing too much, scene manager, gui environment) to safe us from typing too much, add an
add an irrlicht engine logo to the window and a user controlled irrlicht engine logo to the window and a user controlled first person
first person shooter style camera. Also, we let the engine now shooter style camera. Also, we let the engine know that it should store
that it should store all textures in 32 bit. This necessary because all textures in 32 bit. This necessary because for parallax mapping, we
for parallax mapping, we need 32 bit textures. need 32 bit textures.
*/ */
video::IVideoDriver* driver = device->getVideoDriver(); video::IVideoDriver* driver = device->getVideoDriver();
...@@ -213,21 +213,21 @@ int main() ...@@ -213,21 +213,21 @@ int main()
/* /*
Because we want the whole scene to look a little bit scarier, we add some fog Because we want the whole scene to look a little bit scarier, we add
to it. This is done by a call to IVideoDriver::setFog(). There you can set some fog to it. This is done by a call to IVideoDriver::setFog(). There
various fog settings. In this example, we use pixel fog, because it will you can set various fog settings. In this example, we use pixel fog,
work well with the materials we'll use in this example. 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 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 'true' in every scene node which should be affected by this fog.
*/ */
driver->setFog(video::SColor(0,138,125,81), true, 250, 1000, 0, true); driver->setFog(video::SColor(0,138,125,81), true, 250, 1000, 0, true);
/* /*
To be able to display something interesting, we load a mesh from a .3ds file To be able to display something interesting, we load a mesh from a .3ds
which is a room I modeled with anim8or. It is the same room as 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, from the specialFX example. Maybe you remember from that tutorial, I am
I am no good modeler at all and so I totally messed up the texture no good modeler at all and so I totally messed up the texture mapping
mapping in this model, but we can simply repair it with the in this model, but we can simply repair it with the
IMeshManipulator::makePlanarTextureMapping() method. IMeshManipulator::makePlanarTextureMapping() method.
*/ */
...@@ -241,17 +241,19 @@ int main() ...@@ -241,17 +241,19 @@ int main()
roomMesh->getMesh(0), 0.003f); roomMesh->getMesh(0), 0.003f);
/* /*
Now for the first exciting thing: If we successfully loaded the mesh Now for the first exciting thing: If we successfully loaded the
we need to apply textures to it. Because we want this room to be mesh we need to apply textures to it. Because we want this room
displayed with a very cool material, we have to do a little bit more to be displayed with a very cool material, we have to do a
than just set the textures. Instead of only loading a color map as usual, little bit more than just set the textures. Instead of only
we also load a height map which is simply a grayscale texture. From this loading a color map as usual, we also load a height map which
height map, we create a normal map which we will set as second texture of the is simply a grayscale texture. From this height map, we create
room. If you already have a normal map, you could directly set it, but I simply a normal map which we will set as second texture of the room.
didnt find a nice normal map for this texture. If you already have a normal map, you could directly set it,
The normal map texture is being generated by the makeNormalMapTexture method but I simply didn't find a nice normal map for this texture.
of the VideoDriver. The second parameter specifies the height of the heightmap. The normal map texture is being generated by the
If you set it to a bigger value, the map will look more rocky. 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.
*/ */
video::ITexture* colorMap = driver->getTexture("../../media/rockwall.bmp"); video::ITexture* colorMap = driver->getTexture("../../media/rockwall.bmp");
...@@ -260,14 +262,16 @@ int main() ...@@ -260,14 +262,16 @@ int main()
driver->makeNormalMapTexture(normalMap, 9.0f); driver->makeNormalMapTexture(normalMap, 9.0f);
/* /*
But just setting color and normal map is not everything. The material we want to But just setting color and normal map is not everything. The
use needs some additional informations per vertex like tangents and binormals. material we want to use needs some additional informations per
Because we are too lazy to calculate that information now, we let Irrlicht do vertex like tangents and binormals. Because we are too lazy to
this for us. That's why we call IMeshManipulator::createMeshWithTangents(). It calculate that information now, we let Irrlicht do this for us.
creates a mesh copy with tangents and binormals from any other mesh. That's why we call IMeshManipulator::createMeshWithTangents().
After we've done that, we simply create a standard mesh scene node with this It creates a mesh copy with tangents and binormals from another
mesh copy, set color and normal map and adjust some other material settings. mesh. After we've done that, we simply create a standard
Note that we set EMF_FOG_ENABLE to true to enable fog in the room. 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.
*/ */
scene::IMesh* tangentMesh = smgr->getMeshManipulator()->createMeshWithTangents( scene::IMesh* tangentMesh = smgr->getMeshManipulator()->createMeshWithTangents(
...@@ -288,13 +292,13 @@ int main() ...@@ -288,13 +292,13 @@ int main()
} }
/* /*
After we've created a room shaded by per pixel lighting, we add a sphere After we've created a room shaded by per pixel lighting, we add a
into it with the same material, but we'll make it transparent. In addition, sphere into it with the same material, but we'll make it transparent.
because the sphere looks somehow like a familiar planet, we make it rotate. In addition, because the sphere looks somehow like a familiar planet,
The procedure is similar as before. The difference is that we are loading we make it rotate. The procedure is similar as before. The difference
the mesh from an .x file which already contains a color map so we do not is that we are loading the mesh from an .x file which already contains
need to load it manually. But the sphere is a little bit too small for our a color map so we do not need to load it manually. But the sphere is a
needs, so we scale it by the factor 50. little bit too small for our needs, so we scale it by the factor 50.
*/ */
// add earth sphere // add earth sphere
...@@ -341,10 +345,11 @@ int main() ...@@ -341,10 +345,11 @@ int main()
} }
/* /*
Per pixel lighted materials only look cool when there are moving lights. So we Per pixel lighted materials only look cool when there are moving
add some. And because moving lights alone are so boring, we add billboards lights. So we add some. And because moving lights alone are so boring,
to them, and a whole particle system to one of them. 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. We start with the first light which is red and has only the billboard
attached.
*/ */
// add light 1 (nearly red) // add light 1 (nearly red)
...@@ -369,15 +374,16 @@ int main() ...@@ -369,15 +374,16 @@ int main()
bill->setMaterialTexture(0, driver->getTexture("../../media/particlered.bmp")); bill->setMaterialTexture(0, driver->getTexture("../../media/particlered.bmp"));
/* /*
Now the same again, with the second light. The difference is that we add a particle Now the same again, with the second light. The difference is that we
system to it too. And because the light moves, the particles of the particlesystem add a particle system to it too. And because the light moves, the
will follow. If you want to know more about how particle systems are created in particles of the particlesystem will follow. If you want to know more
Irrlicht, take a look at the specialFx example. about how particle systems are created in Irrlicht, take a look at the
Maybe you will have noticed that we only add 2 lights, this has a simple reason: The specialFx example. Maybe you will have noticed that we only add 2
low end version of this material was written in ps1.1 and vs1.1, which doesn't allow lights, this has a simple reason: The low end version of this material
more lights. You could add a third light to the scene, but it won't be used to was written in ps1.1 and vs1.1, which doesn't allow more lights. You
shade the walls. But of course, this will change in future versions of Irrlicht were could add a third light to the scene, but it won't be used to shade the
higher versions of pixel/vertex shaders will be implemented too. walls. But of course, this will change in future versions of Irrlicht
where higher versions of pixel/vertex shaders will be implemented too.
*/ */
// add light 2 (gray) // add light 2 (gray)
...@@ -463,3 +469,5 @@ int main() ...@@ -463,3 +469,5 @@ int main()
return 0; return 0;
} }
/*
**/
/* /** Example 012 Terrain Rendering
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 This tutorial will briefly show how to use the terrain renderer of Irrlicht. It
terrain. 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. Note that the Terrain Renderer in Irrlicht is based on Spintz'
DeusXL provided a new elegant simple solution for building larger area on small heightmaps GeoMipMapSceneNode, lots of thanks go to him. DeusXL provided a new elegant
-> terrain smoothing. simple solution for building larger area on small heightmaps -> terrain
In the beginning there is nothing special. We include the needed header files and create smoothing.
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. In the beginning there is nothing special. We include the needed header files
and create an event listener to listen if the user presses a key: The 'W' key
switches to wireframe mode, the 'P' key to pointcloud mode, and the 'D' key
toggles between solid and detail mapped material.
*/ */
#include <irrlicht.h> #include <irrlicht.h>
#include <iostream> #include <iostream>
...@@ -46,7 +49,7 @@ public: ...@@ -46,7 +49,7 @@ public:
return true; return true;
case irr::KEY_KEY_D: // toggle detail map case irr::KEY_KEY_D: // toggle detail map
Terrain->setMaterialType( Terrain->setMaterialType(
Terrain->getMaterial(0).MaterialType == video::EMT_SOLID ? Terrain->getMaterial(0).MaterialType == video::EMT_SOLID ?
video::EMT_DETAIL_MAP : video::EMT_SOLID); video::EMT_DETAIL_MAP : video::EMT_SOLID);
return true; return true;
} }
...@@ -101,7 +104,7 @@ int main() ...@@ -101,7 +104,7 @@ int main()
First, we add standard stuff to the scene: A nice irrlicht engine First, we add standard stuff to the scene: A nice irrlicht engine
logo, a small help text, a user controlled camera, and we disable logo, a small help text, a user controlled camera, and we disable
the mouse cursor. the mouse cursor.
*/ */
video::IVideoDriver* driver = device->getVideoDriver(); video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager(); scene::ISceneManager* smgr = device->getSceneManager();
...@@ -122,7 +125,7 @@ int main() ...@@ -122,7 +125,7 @@ int main()
core::rect<s32>(10,440,250,475), true, true, 0, -1, true); core::rect<s32>(10,440,250,475), true, true, 0, -1, true);
// add camera // add camera
scene::ICameraSceneNode* camera = scene::ICameraSceneNode* camera =
smgr->addCameraSceneNodeFPS(0,100.0f,1200.f); smgr->addCameraSceneNodeFPS(0,100.0f,1200.f);
camera->setPosition(core::vector3df(1900*2,255*2,3700*2)); camera->setPosition(core::vector3df(1900*2,255*2,3700*2));
...@@ -133,31 +136,34 @@ int main() ...@@ -133,31 +136,34 @@ int main()
device->getCursorControl()->setVisible(false); device->getCursorControl()->setVisible(false);
/* /*
Here comes the terrain renderer scene node: We add it just like any Here comes the terrain renderer scene node: We add it just like any
other scene node to the scene using ISceneManager::addTerrainSceneNode(). other scene node to the scene using
The only parameter we use is a file name to the heightmap we use. A heightmap ISceneManager::addTerrainSceneNode(). The only parameter we use is a
is simply a gray scale texture. The terrain renderer loads it and creates file name to the heightmap we use. A heightmap is simply a gray scale
the 3D terrain from it. texture. The terrain renderer loads it and creates the 3D terrain from
To make the terrain look more big, we change the scale factor of it to (40, 4.4, 40). it.
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 To make the terrain look more big, we change the scale factor of
detailmap3.jpg as second texture, called detail map. At last, we set it to (40, 4.4, 40). Because we don't have any dynamic lights in the
the scale values for the texture: The first texture will be repeated only one time over scene, we switch off the lighting, and we set the file
the whole terrain, and the second one (detail map) 20 times. 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.
*/ */
// add terrain scene node // add terrain scene node
scene::ITerrainSceneNode* terrain = smgr->addTerrainSceneNode( scene::ITerrainSceneNode* terrain = smgr->addTerrainSceneNode(
"../../media/terrain-heightmap.bmp", "../../media/terrain-heightmap.bmp",
0, // parent node 0, // parent node
-1, // node id -1, // node id
core::vector3df(0.f, 0.f, 0.f), // position core::vector3df(0.f, 0.f, 0.f), // position
core::vector3df(0.f, 0.f, 0.f), // rotation core::vector3df(0.f, 0.f, 0.f), // rotation
core::vector3df(40.f, 4.4f, 40.f), // scale core::vector3df(40.f, 4.4f, 40.f), // scale
video::SColor ( 255, 255, 255, 255 ), // vertexColor, video::SColor ( 255, 255, 255, 255 ), // vertexColor
5, // maxLOD 5, // maxLOD
scene::ETPS_17, // patchSize scene::ETPS_17, // patchSize
4 // smoothFactor 4 // smoothFactor
); );
terrain->setMaterialFlag(video::EMF_LIGHTING, false); terrain->setMaterialFlag(video::EMF_LIGHTING, false);
...@@ -172,10 +178,10 @@ int main() ...@@ -172,10 +178,10 @@ int main()
/* /*
To be able to do collision with the terrain, we create a triangle selector. 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 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 collision tutorial. The terrain triangle selector works together with the
terrain. To demonstrate this, we create a collision response animator 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 and attach it to the camera, so that the camera will not be able to fly
through the terrain. through the terrain.
*/ */
...@@ -187,23 +193,24 @@ int main() ...@@ -187,23 +193,24 @@ int main()
// create collision response animator and attach it to the camera // create collision response animator and attach it to the camera
scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator( scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator(
selector, camera, core::vector3df(60,100,60), selector, camera, core::vector3df(60,100,60),
core::vector3df(0,0,0), core::vector3df(0,0,0),
core::vector3df(0,50,0)); core::vector3df(0,50,0));
selector->drop(); selector->drop();
camera->addAnimator(anim); camera->addAnimator(anim);
anim->drop(); anim->drop();
/* /*
To make the user be able to switch between normal and wireframe mode, we create To make the user be able to switch between normal and wireframe mode,
an instance of the event reciever from above and let Irrlicht know about it. In we create an instance of the event reciever from above and let Irrlicht
addition, we add the skybox which we already used in lots of Irrlicht examples. know about it. In addition, we add the skybox which we already used in
lots of Irrlicht examples.
*/ */
// create event receiver // create event receiver
MyEventReceiver receiver(terrain); MyEventReceiver receiver(terrain);
device->setEventReceiver(&receiver); device->setEventReceiver(&receiver);
// create skybox // create skybox
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
smgr->addSkyBoxSceneNode( smgr->addSkyBoxSceneNode(
...@@ -218,7 +225,7 @@ int main() ...@@ -218,7 +225,7 @@ int main()
/* /*
That's it, draw everything. Now you know how to use terrain in Irrlicht. That's it, draw everything.
*/ */
int lastFPS = -1; int lastFPS = -1;
...@@ -256,3 +263,6 @@ int main() ...@@ -256,3 +263,6 @@ int main()
return 0; return 0;
} }
/*
Now you know how to use terrain in Irrlicht.
**/
/* /** Example 013 Render To Texture
This tutorial shows how to render to a texture using Irrlicht. Render to texture is a feature with which
it is possible to create nice special effects. In addition, this tutorial shows how to enable specular This tutorial shows how to render to a texture using Irrlicht. Render to
highlights. texture is a feature with which it is possible 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 In the beginning, everything as usual. Include the needed headers, ask the user
driver, create the Irrlicht Device: for the rendering driver, create the Irrlicht Device:
*/ */
#include <irrlicht.h> #include <irrlicht.h>
...@@ -54,10 +55,10 @@ int main() ...@@ -54,10 +55,10 @@ int main()
/* /*
Now, we load an animated mesh to be displayed. As in most examples, 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 we'll take the fairy md2 model. The difference here: We set the
of the model to a value other than 0 which is the default value. This shininess of the model to a value other than 0 which is the default
enables specular highlights on the model if dynamic lighting is on. value. This enables specular highlights on the model if dynamic
The value influences the size of the highlights. lighting is on. The value influences the size of the highlights.
*/ */
// load and display animated fairy mesh // load and display animated fairy mesh
...@@ -75,9 +76,10 @@ int main() ...@@ -75,9 +76,10 @@ int main()
} }
/* /*
To make specular highlights appear on the model, we need a dynamic light in the scene. To make specular highlights appear on the model, we need a dynamic
We add one directly in vicinity of the model. In addition, to make the model not that light in the scene. We add one directly in vicinity of the model. In
dark, we set the ambient light to gray. addition, to make the model not that dark, we set the ambient light to
gray.
*/ */
// add white light // add white light
...@@ -88,8 +90,9 @@ int main() ...@@ -88,8 +90,9 @@ int main()
smgr->setAmbientLight(video::SColor(0,60,60,60)); smgr->setAmbientLight(video::SColor(0,60,60,60));
/* /*
The next is just some standard stuff: Add a user controlled camera to the scene, disable The next is just some standard stuff: Add a user controlled camera to
mouse cursor, and add a test cube and let it rotate to make the scene more interesting. the scene, disable mouse cursor, and add a test cube and let it rotate
to make the scene more interesting.
*/ */
// add fps camera // add fps camera
...@@ -115,14 +118,16 @@ int main() ...@@ -115,14 +118,16 @@ int main()
device->setWindowCaption(L"Irrlicht Engine - Render to Texture and Specular Highlights example"); device->setWindowCaption(L"Irrlicht Engine - Render to Texture and Specular Highlights example");
/* /*
To test out the render to texture feature, we need a render target texture. These are not To test out the render to texture feature, we need a render target
like standard textures, but need to be created first. To create one, we call texture. These are not like standard textures, but need to be created
IVideoDriver::createRenderTargetTexture() and specify the size of the texture. Please first. To create one, we call IVideoDriver::createRenderTargetTexture()
don't use sizes bigger than the frame buffer for this, because the render target shares and specify the size of the texture. Please don't use sizes bigger than
the zbuffer with the frame buffer. And because we want to render the scene not from the the frame buffer for this, because the render target shares the zbuffer
user camera into the texture, we add another, fixed camera to the scene. But before we with the frame buffer. And because we want to render the scene not from
do all this, we check if the current running driver is able to render to textures. If the user camera into the texture, we add another fixed camera to the
it is not, we simply display a warning text. 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.
*/ */
// create render target // create render target
...@@ -156,11 +161,12 @@ int main() ...@@ -156,11 +161,12 @@ int main()
} }
/* /*
Nearly finished. Now we need to draw everything. Every frame, we draw the scene twice. Nearly finished. Now we need to draw everything. Every frame, we draw
Once from the fixed camera into the render target texture and once as usual. When rendering the scene twice. Once from the fixed camera into the render target
into the render target, we need to disable the visibilty of the test cube, because it has texture and once as usual. When rendering into the render target, we
the render target texture applied to it. need to disable the visibilty of the test cube, because it has the
That's, wasn't quite complicated I hope. :) render target texture applied to it. That's it, wasn't too complicated
I hope. :)
*/ */
int lastFPS = -1; int lastFPS = -1;
...@@ -175,18 +181,18 @@ int main() ...@@ -175,18 +181,18 @@ int main()
// draw scene into render target // draw scene into render target
// set render target texture // set render target texture
driver->setRenderTarget(rt, true, true, video::SColor(0,0,0,255)); driver->setRenderTarget(rt, true, true, video::SColor(0,0,0,255));
// make cube invisible and set fixed camera as active camera // make cube invisible and set fixed camera as active camera
test->setVisible(false); test->setVisible(false);
smgr->setActiveCamera(fixedCam); smgr->setActiveCamera(fixedCam);
// draw whole scene into render buffer // draw whole scene into render buffer
smgr->drawAll(); smgr->drawAll();
// set back old render target // set back old render target
// The buffer might have been distorted, so clear it // The buffer might have been distorted, so clear it
driver->setRenderTarget(0, true, true, 0); driver->setRenderTarget(0, true, true, 0);
// make the cube visible and set the user controlled camera as active one // make the cube visible and set the user controlled camera as active one
test->setVisible(true); test->setVisible(true);
...@@ -194,7 +200,7 @@ int main() ...@@ -194,7 +200,7 @@ int main()
} }
// draw scene normally // draw scene normally
smgr->drawAll(); smgr->drawAll();
env->drawAll(); env->drawAll();
driver->endScene(); driver->endScene();
...@@ -218,3 +224,6 @@ int main() ...@@ -218,3 +224,6 @@ int main()
device->drop(); // drop device device->drop(); // drop device
return 0; return 0;
} }
/*
**/
// this example only runs in windows and demonstrates that Irrlicht /** Example 014 Win32 Window
// can run inside a win32 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 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.
*/
#include <irrlicht.h> #include <irrlicht.h>
#ifndef _IRR_WINDOWS_ #ifndef _IRR_WINDOWS_
...@@ -41,9 +49,6 @@ static LRESULT CALLBACK CustomWndProc(HWND hWnd, UINT message, WPARAM wParam, LP ...@@ -41,9 +49,6 @@ static LRESULT CALLBACK CustomWndProc(HWND hWnd, UINT message, WPARAM wParam, LP
} }
int main() int main()
//int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hpre, LPSTR cmd, int cc) //int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hpre, LPSTR cmd, int cc)
{ {
...@@ -99,6 +104,12 @@ int main() ...@@ -99,6 +104,12 @@ int main()
HWND hIrrlichtWindow = CreateWindow("BUTTON", "", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, HWND hIrrlichtWindow = CreateWindow("BUTTON", "", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
50, 80, 320, 220, hWnd, NULL, hInstance, NULL); 50, 80, 320, 220, hWnd, NULL, hInstance, NULL);
/*
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.
*/
// create irrlicht device in the button window // create irrlicht device in the button window
irr::SIrrlichtCreationParameters param; irr::SIrrlichtCreationParameters param;
...@@ -141,13 +152,17 @@ int main() ...@@ -141,13 +152,17 @@ int main()
// do message queue // do message queue
// Instead of this, you can also simply use your own message loop /*
// using GetMessage, DispatchMessage and whatever. Calling Now the only thing missing is the drawing loop using
// Device->run() will cause Irrlicht to dispatch messages internally too. IrrlichtDevice::run(). We do this as usual. But instead of this, there
// You need not call Device->run() if you want to do your own message is another possibility: You can also simply use your own message loop
// dispatching loop, but Irrlicht will not be able to fetch using GetMessage, DispatchMessage and whatever. Calling
// user input then and you have to do it on your own using the window Device->run() will cause Irrlicht to dispatch messages internally too.
// messages, DirectInput, or whatever. 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.
*/
while (device->run()) while (device->run())
{ {
...@@ -156,8 +171,10 @@ int main() ...@@ -156,8 +171,10 @@ int main()
driver->endScene(); driver->endScene();
} }
// the alternative, own message dispatching loop without Device->run() would /*
// look like this: The alternative, own message dispatching loop without Device->run()
would look like this:
*/
/*MSG msg; /*MSG msg;
while (true) while (true)
...@@ -187,3 +204,6 @@ int main() ...@@ -187,3 +204,6 @@ int main()
} }
#endif // if windows #endif // if windows
/*
That's it, Irrlicht now runs in your own windows window.
**/
/* /** Example 015 Loading Scenes from .irr Files
Since version 1.1, Irrlicht is able to save and load Since version 1.1, Irrlicht is able to save and load
the full scene graph into an .irr file, an xml based the full scene graph into an .irr file, an xml based
format. There is an editor available to edit format. There is an editor available to edit
those files, named irrEdit on http://www.ambiera.com/irredit, those files, named irrEdit (http://www.ambiera.com/irredit)
which can also be used as world and particle editor. which can also be used as world and particle editor.
This tutorial shows how to use .irr files. This tutorial shows how to use .irr files.
...@@ -13,7 +14,9 @@ Lets start: Create an Irrlicht device and setup the window. ...@@ -13,7 +14,9 @@ Lets start: Create an Irrlicht device and setup the window.
#include <iostream> #include <iostream>
using namespace irr; using namespace irr;
#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib") #pragma comment(lib, "Irrlicht.lib")
#endif
int main() int main()
{ {
...@@ -38,7 +41,7 @@ int main() ...@@ -38,7 +41,7 @@ int main()
case 'e': driverType = video::EDT_BURNINGSVIDEO;break; case 'e': driverType = video::EDT_BURNINGSVIDEO;break;
case 'f': driverType = video::EDT_NULL; break; case 'f': driverType = video::EDT_NULL; break;
default: return 1; default: return 1;
} }
// create device and exit if creation failed // create device and exit if creation failed
...@@ -53,30 +56,35 @@ int main() ...@@ -53,30 +56,35 @@ int main()
video::IVideoDriver* driver = device->getVideoDriver(); video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager(); scene::ISceneManager* smgr = device->getSceneManager();
/* Now load our .irr file. /*
.irr files can store the whole scene graph including animators, materials Now load our .irr file.
and particle systems. And there is also the possibility to store arbitrary .irr files can store the whole scene graph including animators,
user data for every scene node in that file. To keep this materials and particle systems. And there is also the possibility to
example simple, we are simply loading the scene here. See the documentation store arbitrary user data for every scene node in that file. To keep
at ISceneManager::loadScene and ISceneManager::saveScene for more information. this example simple, we are simply loading the scene here. See the
So to load and display a complicated huge scene, we only need a single call documentation at ISceneManager::loadScene and ISceneManager::saveScene
to loadScene(). for more information. So to load and display a complicated huge scene,
we only need a single call to loadScene().
*/ */
// load the scene // load the scene
smgr->loadScene("../../media/example.irr"); smgr->loadScene("../../media/example.irr");
// Now we'll create a camera, and give it a collision response animator /*
// that's built from the mesh nodes in the scene we just loaded. Now we'll create a camera, and give it a collision response animator
that's built from the mesh nodes in the scene we just loaded.
*/
scene::ICameraSceneNode * camera = smgr->addCameraSceneNodeFPS(0, 50, 100); scene::ICameraSceneNode * camera = smgr->addCameraSceneNodeFPS(0, 50, 100);
// Create a meta triangle selector to hold several triangle selectors. // Create a meta triangle selector to hold several triangle selectors.
scene::IMetaTriangleSelector * meta = smgr->createMetaTriangleSelector(); scene::IMetaTriangleSelector * meta = smgr->createMetaTriangleSelector();
// Now we will find all the nodes in the scene and create triangle /*
// selectors for all suitable nodes. Typically, you would want to make a Now we will find all the nodes in the scene and create triangle
// more informed decision about which nodes to performs collision checks selectors for all suitable nodes. Typically, you would want to make a
// on; you could capture that information in the node name or Id. more informed decision about which nodes to performs collision checks
on; you could capture that information in the node name or Id.
*/
core::array<scene::ISceneNode *> nodes; core::array<scene::ISceneNode *> nodes;
smgr->getSceneNodesFromType(scene::ESNT_ANY, nodes); // Find all nodes smgr->getSceneNodesFromType(scene::ESNT_ANY, nodes); // Find all nodes
...@@ -88,41 +96,44 @@ int main() ...@@ -88,41 +96,44 @@ int main()
switch(node->getType()) switch(node->getType())
{ {
case scene::ESNT_CUBE: case scene::ESNT_CUBE:
case scene::ESNT_ANIMATED_MESH: // Because the selector won't animate with the mesh, case scene::ESNT_ANIMATED_MESH:
// and is only being used for camera collision, we'll just use an approximate // Because the selector won't animate with the mesh,
// bounding box instead of ((scene::IAnimatedMeshSceneNode*)node)->getMesh(0) // and is only being used for camera collision, we'll just use an approximate
selector = smgr->createTriangleSelectorFromBoundingBox(node); // bounding box instead of ((scene::IAnimatedMeshSceneNode*)node)->getMesh(0)
break; selector = smgr->createTriangleSelectorFromBoundingBox(node);
break;
case scene::ESNT_MESH: case scene::ESNT_MESH:
case scene::ESNT_SPHERE: // Derived from IMeshSceneNode case scene::ESNT_SPHERE: // Derived from IMeshSceneNode
selector = smgr->createTriangleSelector(((scene::IMeshSceneNode*)node)->getMesh(), node); selector = smgr->createTriangleSelector(((scene::IMeshSceneNode*)node)->getMesh(), node);
break; break;
case scene::ESNT_TERRAIN: case scene::ESNT_TERRAIN:
selector = smgr->createTerrainTriangleSelector((scene::ITerrainSceneNode*)node); selector = smgr->createTerrainTriangleSelector((scene::ITerrainSceneNode*)node);
break; break;
case scene::ESNT_OCT_TREE: case scene::ESNT_OCT_TREE:
selector = smgr->createOctTreeTriangleSelector(((scene::IMeshSceneNode*)node)->getMesh(), node); selector = smgr->createOctTreeTriangleSelector(((scene::IMeshSceneNode*)node)->getMesh(), node);
break; break;
default: default:
// Don't create a selector for this node type // Don't create a selector for this node type
break; break;
} }
if(selector) if(selector)
{ {
// Add it to the meta selector, which will take a reference to it // Add it to the meta selector, which will take a reference to it
meta->addTriangleSelector(selector); meta->addTriangleSelector(selector);
// And drop my reference to it, so that the meta selector owns it. // And drop my reference to it, so that the meta selector owns it.
selector->drop(); selector->drop();
} }
} }
// Now that the mesh scene nodes have had triangle selectors created and added /*
// to the meta selector, create a collision response animator from that meta selector. Now that the mesh scene nodes have had triangle selectors created and added
to the meta selector, create a collision response animator from that meta selector.
*/
scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator( scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator(
meta, camera, core::vector3df(5,5,5), meta, camera, core::vector3df(5,5,5),
core::vector3df(0,0,0)); core::vector3df(0,0,0));
...@@ -138,8 +149,10 @@ int main() ...@@ -138,8 +149,10 @@ int main()
scene::ISceneNode * cube = smgr->getSceneNodeFromType(scene::ESNT_CUBE); scene::ISceneNode * cube = smgr->getSceneNodeFromType(scene::ESNT_CUBE);
if(cube) if(cube)
camera->setTarget(cube->getAbsolutePosition()); camera->setTarget(cube->getAbsolutePosition());
// and draw everything. /*
That's it. Draw everything and finish as usual.
*/
int lastFPS = -1; int lastFPS = -1;
...@@ -154,19 +167,21 @@ int main() ...@@ -154,19 +167,21 @@ int main()
if (lastFPS != fps) if (lastFPS != fps)
{ {
core::stringw str = L"Load Irrlicht File example - Irrlicht Engine ["; core::stringw str = L"Load Irrlicht File example - Irrlicht Engine [";
str += driver->getName(); str += driver->getName();
str += "] FPS:"; str += "] FPS:";
str += fps; str += fps;
device->setWindowCaption(str.c_str()); device->setWindowCaption(str.c_str());
lastFPS = fps; lastFPS = fps;
} }
} }
device->drop(); device->drop();
return 0; return 0;
} }
/*
**/
/* /** Example 016 Quake3 Map Shader Support
This Tutorial shows how to load a Quake 3 map into the This Tutorial shows how to load a Quake 3 map into the
engine, create a SceneNode for optimizing the speed of engine, create a SceneNode for optimizing the speed of
rendering and how to create a user controlled camera. rendering and how to create a user controlled camera.
...@@ -38,9 +39,9 @@ to ask the user for a driver type using the console. ...@@ -38,9 +39,9 @@ to ask the user for a driver type using the console.
/* /*
As already written in the HelloWorld example, in the Irrlicht As already written in the HelloWorld example, in the Irrlicht
Engine, everything can be found in the namespace 'irr'. Engine, everything can be found in the namespace 'irr'.
To get rid of the irr:: in front of the name of every class, 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, we tell the compiler that we use that namespace from now on,
and we will not have to write that 'irr::'. and we will not have to write that 'irr::'.
There are 5 other sub namespaces 'core', 'scene', 'video', There are 5 other sub namespaces 'core', 'scene', 'video',
'io' and 'gui'. Unlike in the HelloWorld example, 'io' and 'gui'. Unlike in the HelloWorld example,
...@@ -53,7 +54,7 @@ using namespace irr; ...@@ -53,7 +54,7 @@ using namespace irr;
using namespace scene; using namespace scene;
/* /*
Again, to be able to use the Irrlicht.DLL file, we need to link with the 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 Irrlicht.lib. We could set this option in the project settings, but
to make it easy, we use a pragma comment lib: to make it easy, we use a pragma comment lib:
*/ */
...@@ -109,14 +110,14 @@ private: ...@@ -109,14 +110,14 @@ private:
/* /*
Ok, lets start. Ok, lets start.
*/ */
int IRRCALLCONV main(int argc, char* argv[]) int IRRCALLCONV main(int argc, char* argv[])
{ {
/* /*
Like in the HelloWorld example, we create an IrrlichtDevice with Like in the HelloWorld example, we create an IrrlichtDevice with
createDevice(). The difference now is that we ask the user to select createDevice(). The difference now is that we ask the user to select
which hardware accelerated driver to use. The Software device would be 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 too slow to draw a huge Quake 3 map, but just for the fun of it, we make
this decision possible too. this decision possible too.
...@@ -188,7 +189,7 @@ int IRRCALLCONV main(int argc, char* argv[]) ...@@ -188,7 +189,7 @@ int IRRCALLCONV main(int argc, char* argv[])
/* /*
Now we can load the mesh by calling getMesh(). We get a pointer returned 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, 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 they are only a huge chunk of static geometry with some materials
...@@ -196,11 +197,11 @@ int IRRCALLCONV main(int argc, char* argv[]) ...@@ -196,11 +197,11 @@ int IRRCALLCONV main(int argc, char* argv[])
so we get the "first frame" of the "animation", which is our quake level so we get the "first frame" of the "animation", which is our quake level
and create an OctTree scene node with it, using addOctTreeSceneNode(). and create an OctTree scene node with it, using addOctTreeSceneNode().
The OctTree optimizes the scene a little bit, trying to draw only geometry The OctTree optimizes the scene a little bit, trying to draw only geometry
which is currently visible. An alternative to the OctTree would be a which is currently visible. An alternative to the OctTree would be a
AnimatedMeshSceneNode, which would draw always the complete geometry of AnimatedMeshSceneNode, which would draw always the complete geometry of
the mesh, without optimization. Try it out: Write addAnimatedMeshSceneNode the mesh, without optimization. Try it out: Write addAnimatedMeshSceneNode
instead of addOctTreeSceneNode and compare the primitives drawed by the instead of addOctTreeSceneNode and compare the primitives drawed by the
video driver. (There is a getPrimitiveCountDrawed() method in the video driver. (There is a getPrimitiveCountDrawed() method in the
IVideoDriver class). Note that this optimization with the Octree is only IVideoDriver class). Note that this optimization with the Octree is only
useful when drawing huge meshes consisting of lots of geometry. useful when drawing huge meshes consisting of lots of geometry.
*/ */
...@@ -291,14 +292,14 @@ int IRRCALLCONV main(int argc, char* argv[]) ...@@ -291,14 +292,14 @@ int IRRCALLCONV main(int argc, char* argv[])
} }
/* /*
Now we only need a Camera to look at the Quake 3 map. Now we only need a Camera to look at the Quake 3 map. And we want to
And we want to create a user controlled camera. There are some create a user controlled camera. There are some different cameras
different cameras available in the Irrlicht engine. For example the available in the Irrlicht engine. For example the Maya Camera which can
Maya Camera which can be controlled compareable to the camera in Maya: be controlled compareable to the camera in Maya: Rotate with left mouse
Rotate with left mouse button pressed, Zoom with both buttons pressed, button pressed, Zoom with both buttons pressed, translate with right
translate with right mouse button pressed. This could be created with mouse button pressed. This could be created with
addCameraSceneNodeMaya(). But for this example, we want to create a addCameraSceneNodeMaya(). But for this example, we want to create a
camera which behaves like the ones in first person shooter games (FPS). camera which behaves like the ones in first person shooter games (FPS).
*/ */
scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS(); scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS();
...@@ -379,8 +380,8 @@ int IRRCALLCONV main(int argc, char* argv[]) ...@@ -379,8 +380,8 @@ int IRRCALLCONV main(int argc, char* argv[])
/* /*
We have done everything, so lets draw it. We also write the current 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 frames per second and the drawn primitives to the caption of the
window. The 'if (device->isWindowActive())' line is optional, but window. The 'if (device->isWindowActive())' line is optional, but
prevents the engine render to set the position of the mouse cursor prevents the engine render to set the position of the mouse cursor
after task switching when other program are active. after task switching when other program are active.
*/ */
int lastFPS = -1; int lastFPS = -1;
...@@ -425,4 +426,5 @@ int IRRCALLCONV main(int argc, char* argv[]) ...@@ -425,4 +426,5 @@ int IRRCALLCONV main(int argc, char* argv[])
return 0; return 0;
} }
/*
**/
# Makefile for Irrlicht Examples
# It's usually sufficient to change just the target name and source file list
# and be sure that CXX is set to a valid compiler
Target = 17.SplitScreen
Sources = main.cpp
# general compiler settings
CPPFLAGS = -I../../include -I/usr/X11R6/include
CXXFLAGS = -O3 -ffast-math
#CXXFLAGS = -g -Wall
#default target is Linux
all: all_linux
ifeq ($(HOSTTYPE), x86_64)
LIBSELECT=64
endif
# target specific settings
all_linux: LDFLAGS = -L/usr/X11R6/lib$(LIBSELECT) -L../../lib/Linux -lIrrlicht -lGL -lXxf86vm -lXext -lX11
all_linux clean_linux: SYSTEM=Linux
all_win32: LDFLAGS = -L../../lib/Win32-gcc -lIrrlicht -lopengl32 -lm
all_win32 clean_win32: SYSTEM=Win32-gcc
all_win32 clean_win32: SUF=.exe
# name of the binary - only valid for targets which set SYSTEM
DESTPATH = ../../bin/$(SYSTEM)/$(Target)$(SUF)
all_linux all_win32:
$(warning Building...)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(Sources) -o $(DESTPATH) $(LDFLAGS)
clean: clean_linux clean_win32
$(warning Cleaning...)
clean_linux clean_win32:
@$(RM) $(DESTPATH)
.PHONY: all all_win32 clean clean_linux clean_win32
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "17.SplitScreen", "SplitScreen.vcproj", "{EB3B38EA-5CE7-4983-845B-880661E69D09}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Release = Release
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{EB3B38EA-5CE7-4983-845B-880661E69D09}.Debug.ActiveCfg = Debug|Win32
{EB3B38EA-5CE7-4983-845B-880661E69D09}.Debug.Build.0 = Debug|Win32
{EB3B38EA-5CE7-4983-845B-880661E69D09}.Release.ActiveCfg = Release|Win32
{EB3B38EA-5CE7-4983-845B-880661E69D09}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="17.SplitScreen"
ProjectGUID="{EB3B38EA-5CE7-4983-845B-880661E69D09}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\include"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="5"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="..\..\bin\Win32-VisualStudio\17.SplitScreen.exe"
LinkIncremental="1"
AdditionalLibraryDirectories="..\..\lib\Win32-visualstudio"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/SplitScreen.pdb"
SubSystem="1"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="1"
CharacterSet="2"
WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/QIfist /Oa"
Optimization="3"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="1"
OmitFramePointers="TRUE"
AdditionalIncludeDirectories="..\..\include"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
RuntimeLibrary="4"
BufferSecurityCheck="FALSE"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="0"
CallingConvention="1"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="..\..\bin\Win32-VisualStudio\17.SplitScreen.exe"
LinkIncremental="1"
SuppressStartupBanner="TRUE"
AdditionalLibraryDirectories="..\..\lib\Win32-visualstudio"
GenerateDebugInformation="FALSE"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath=".\main.cpp">
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="17.SplitScreen_vc8"
ProjectGUID="{EB3B38EA-5CE7-4983-845B-880661E69D09}"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\include"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="..\..\bin\Win32-VisualStudio\17.SplitScreen.exe"
LinkIncremental="2"
AdditionalLibraryDirectories="..\..\lib\Win32-visualstudio"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(OutDir)/SplitScreen.pdb"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1"
AdditionalIncludeDirectories="..\..\include"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
RuntimeLibrary="0"
BufferSecurityCheck="false"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="0"
CallingConvention="1"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="..\..\bin\Win32-VisualStudio\17.SplitScreen.exe"
LinkIncremental="1"
AdditionalLibraryDirectories="..\..\lib\Win32-visualstudio"
GenerateDebugInformation="false"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath=".\main.cpp"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="17.SplitScreen_vc9"
ProjectGUID="{EB3B38EA-5CE7-4983-845B-880661E69D09}"
RootNamespace="17.SplitScreen_vc9"
Keyword="Win32Proj"
TargetFrameworkVersion="131072"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\include"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="..\..\bin\Win32-VisualStudio\17.SplitScreen.exe"
LinkIncremental="2"
AdditionalLibraryDirectories="..\..\lib\Win32-visualstudio"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(OutDir)/SplitScreen.pdb"
SubSystem="1"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1"
AdditionalIncludeDirectories="..\..\include"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
RuntimeLibrary="0"
BufferSecurityCheck="false"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="0"
CallingConvention="1"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="..\..\bin\Win32-VisualStudio\17.SplitScreen.exe"
LinkIncremental="1"
AdditionalLibraryDirectories="..\..\lib\Win32-visualstudio"
GenerateDebugInformation="false"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath=".\main.cpp"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
[Project]
FileName=example.dev
Name=Irrlicht Example 17 SplitScreen
UnitCount=1
Type=1
Ver=1
ObjFiles=
Includes=..\..\include
Libs=
PrivateResource=
ResourceIncludes=
MakeIncludes=
Compiler=
CppCompiler=
Linker=../../lib/Win32-gcc/libIrrlicht.a_@@_
IsCpp=1
Icon=
ExeOutput=../../bin/Win32-gcc
ObjectOutput=obj
OverrideOutput=1
OverrideOutputName=17.SplitScreen.exe
HostApplication=
Folders=
CommandLine=
IncludeVersionInfo=0
SupportXPThemes=0
CompilerSet=0
CompilerSettings=0000000000000000000000
UseCustomMakefile=0
CustomMakefile=
[Unit1]
FileName=main.cpp
CompileCpp=1
Folder=Projekt1
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[VersionInfo]
Major=0
Minor=1
Release=1
Build=1
LanguageID=1033
CharsetID=1252
CompanyName=
FileVersion=
FileDescription=Irrlicht Engine example compiled using DevCpp and gcc
InternalName=
LegalCopyright=
LegalTrademarks=
OriginalFilename=
ProductName=
ProductVersion=
AutoIncBuildNr=0
/** Example 017 Splitscreen
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, wtih 3 fixed cameras and one user-controlled.
Ok, let's start with the headers (I think there's
nothing to say about it)
*/
#include <irrlicht.h>
#include <stdio.h>
#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib")
#endif
//Namespaces for the engine
using namespace irr;
using namespace video;
using namespace core;
using namespace scene;
using namespace io;
using namespace gui;
/*
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.
*/
//Resolution
const int ResX=800;
const int ResY=600;
const bool fullScreen=false;
//Use SplitScreen?
bool SplitScreen=true;
/*
Now we need four pointers to our cameras which are created later:
*/
//cameras
ICameraSceneNode *camera[4]={0,0,0,0};
/*
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.
*/
class MyEventReceiver : public IEventReceiver {
public:
virtual bool OnEvent(const SEvent& event)
{
//Key S enables/disables SplitScreen
if (event.EventType == irr::EET_KEY_INPUT_EVENT &&
event.KeyInput.Key == KEY_KEY_S && event.KeyInput.PressedDown)
{
SplitScreen = !SplitScreen;
return true;
}
//Send all other events to camera4
if (camera[3])
return camera[3]->OnEvent(event);
return false;
}
};
/*
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.
*/
int main()
{
//Instance of the EventReceiver
MyEventReceiver receiver;
//Initialise the engine
IrrlichtDevice *device = createDevice(
EDT_OPENGL, dimension2d<s32>(ResX,ResY), 32, fullScreen, false, false, &receiver);
ISceneManager *smgr = device->getSceneManager();
IVideoDriver *driver = device->getVideoDriver();
//Load model
IAnimatedMesh *model = smgr->getMesh("../../media/sydney.md2");
if (!model)
return 1;
IAnimatedMeshSceneNode *model_node = smgr->addAnimatedMeshSceneNode(model);
//Load texture
ITexture *texture = driver->getTexture("../../media/sydney.bmp");
model_node->setMaterialTexture(0,texture);
//Disable lighting (we've got no light)
model_node->setMaterialFlag(EMF_LIGHTING,false);
//Load map
device->getFileSystem()->addZipFileArchive("../../media/map-20kdm2.pk3");
IAnimatedMesh *map = smgr->getMesh("20kdm2.bsp");
if (map)
{
ISceneNode *map_node = smgr->addOctTreeSceneNode(map->getMesh(0));
//Set position
map_node->setPosition(vector3df(-850,-220,-850));
}
/*
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 3 fixed and one user-controlled cameras
//Front
camera[0] = smgr->addCameraSceneNode(0, vector3df(50,0,0), vector3df(0,0,0));
//Top
camera[1] = smgr->addCameraSceneNode(0, vector3df(0,50,0), vector3df(0,0,0));
//Left
camera[2] = smgr->addCameraSceneNode(0, vector3df(0,0,50), vector3df(0,0,0));
//User-controlled
camera[3] = smgr->addCameraSceneNodeFPS();
/*
Create a variable for counting the fps and hide the mouse:
*/
//Hide mouse
device->getCursorControl()->setVisible(false);
//We want to count the fps
int lastFPS = -1;
/*
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:
- Set the viewport to the whole screen
- Begin a new scene (Clear screen)
- The following 3 steps are repeated for every viewport in the splitscreen
- Set the viewport to the area you wish
- Activate the camera which should be "linked" with the viewport
- Render all objects
- If you have a GUI:
- Set the viewport the whole screen
- Display the GUI
- End scene
Sounds a little complicated, but you'll see it isn't:
*/
while(device->run())
{
//Set the viewpoint to the whole screen and begin scene
driver->setViewPort(rect<s32>(0,0,ResX,ResY));
driver->beginScene(true,true,SColor(255,100,100,100));
//If SplitScreen is used
if (SplitScreen)
{
//Activate camera1
smgr->setActiveCamera(camera[0]);
//Set viewpoint to the first quarter (left top)
driver->setViewPort(rect<s32>(0,0,ResX/2,ResY/2));
//Draw scene
smgr->drawAll();
//Activate camera2
smgr->setActiveCamera(camera[1]);
//Set viewpoint to the second quarter (right top)
driver->setViewPort(rect<s32>(ResX/2,0,ResX,ResY/2));
//Draw scene
smgr->drawAll();
//Activate camera3
smgr->setActiveCamera(camera[2]);
//Set viewpoint to the third quarter (left bottom)
driver->setViewPort(rect<s32>(0,ResY/2,ResX/2,ResY));
//Draw scene
smgr->drawAll();
//Set viewport the last quarter (right bottom)
driver->setViewPort(rect<s32>(ResX/2,ResY/2,ResX,ResY));
}
//Activate camera4
smgr->setActiveCamera(camera[3]);
//Draw scene
smgr->drawAll();
driver->endScene();
/*
As you can probably see, the image is rendered for every
viewport seperately. That means, that you'll loose much performance.
Ok, if you're aksing "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:
- X-coordinate of the corner left top
- Y-coordinate of the corner left top
- X-coordinate of the corner right bottom
- Y-coordinate of the corner right bottom
That means, if you want to split the screen into 2 viewports
you would give the following coordinates:
- 1st viewport: 0,0,ResX/2,ResY
- 2nd viewport: ResX/2,0,ResX,ResY
If you didn't fully understand, just play arround 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:
*/
//Get and show fps
if (driver->getFPS() != lastFPS)
{
lastFPS = driver->getFPS();
wchar_t tmp[1024];
swprintf( tmp, 1024, L"Irrlicht SplitScreen-Example (FPS: %d)", lastFPS);
device->setWindowCaption(tmp);
}
}
//Delete device
device->drop();
return 0;
}
/*
That's it! Just compile and play around with the program.
Note: With the S-Key you can switch between using splitscreen
and not.
**/
...@@ -45,7 +45,7 @@ void CDemo::run() ...@@ -45,7 +45,7 @@ void CDemo::run()
resolution.Height = 480; resolution.Height = 480;
} }
device = createDevice(driverType,resolution, 32, fullscreen, shadows, vsync, this); device = createDevice(driverType, resolution, 32, fullscreen, shadows, vsync, this);
if (!device) if (!device)
return; return;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#ifndef __C_DEMO_H_INCLUDED__ #ifndef __C_DEMO_H_INCLUDED__
#define __C_DEMO_H_INCLUDED__ #define __C_DEMO_H_INCLUDED__
//#define USE_IRRKLANG #define USE_IRRKLANG
//#define USE_SDL_MIXER //#define USE_SDL_MIXER
#include <irrlicht.h> #include <irrlicht.h>
......
...@@ -10,32 +10,30 @@ class CSceneNodeAnimatorFollowBoundingBox : public irr::scene::ISceneNodeAnimato ...@@ -10,32 +10,30 @@ class CSceneNodeAnimatorFollowBoundingBox : public irr::scene::ISceneNodeAnimato
public: public:
//! constructor //! constructor
CSceneNodeAnimatorFollowBoundingBox( irr::scene::ISceneNode* tofollow, const core::vector3df &offset, u32 frequency, s32 phase ) CSceneNodeAnimatorFollowBoundingBox(irr::scene::ISceneNode* tofollow,
const core::vector3df &offset, u32 frequency, s32 phase)
: Offset(offset), ToFollow(tofollow), Frequency(frequency), Phase(phase)
{ {
Frequency = frequency; if (ToFollow)
Phase = phase; ToFollow->grab();
Offset = offset;
ToFollow = tofollow;
if ( ToFollow )
ToFollow->grab ();
} }
//! destructor //! destructor
virtual ~CSceneNodeAnimatorFollowBoundingBox() virtual ~CSceneNodeAnimatorFollowBoundingBox()
{ {
if ( ToFollow ) if (ToFollow)
ToFollow->drop (); ToFollow->drop();
} }
//! animates a scene node //! animates a scene node
virtual void animateNode(irr::scene::ISceneNode* node, u32 timeMs) virtual void animateNode(irr::scene::ISceneNode* node, u32 timeMs)
{ {
if ( 0 == node || node->getType () != irr::scene::ESNT_LIGHT) if (0 == node || node->getType() != irr::scene::ESNT_LIGHT)
return; return;
irr::scene::ILightSceneNode* l = (irr::scene::ILightSceneNode*) node; irr::scene::ILightSceneNode* l = (irr::scene::ILightSceneNode*) node;
if ( ToFollow ) if (ToFollow)
{ {
core::vector3df now = l->getPosition(); core::vector3df now = l->getPosition();
now += ToFollow->getBoundingBox().getCenter(); now += ToFollow->getBoundingBox().getCenter();
...@@ -45,7 +43,7 @@ public: ...@@ -45,7 +43,7 @@ public:
irr::video::SColorHSL color; irr::video::SColorHSL color;
irr::video::SColor rgb(0); irr::video::SColor rgb(0);
color.Hue = ( ( timeMs + Phase ) % Frequency ) * ( 2.f * irr::core::PI / Frequency ); color.Hue = ( (timeMs + Phase) % Frequency ) * ( 2.f * irr::core::PI / Frequency );
color.Saturation = 1.f; color.Saturation = 1.f;
color.Luminance = 0.5f; color.Luminance = 0.5f;
color.toRGB(rgb); color.toRGB(rgb);
...@@ -55,7 +53,6 @@ public: ...@@ -55,7 +53,6 @@ public:
l->setLightData(light); l->setLightData(light);
} }
private: private:
core::vector3df Offset; core::vector3df Offset;
...@@ -65,8 +62,6 @@ private: ...@@ -65,8 +62,6 @@ private:
}; };
CMainMenu::CMainMenu() CMainMenu::CMainMenu()
: startButton(0), MenuDevice(0), selected(2), start(false), fullscreen(true), : startButton(0), MenuDevice(0), selected(2), start(false), fullscreen(true),
music(true), shadows(false), additive(false), transparent(true), vsync(false) music(true), shadows(false), additive(false), transparent(true), vsync(false)
...@@ -74,11 +69,10 @@ CMainMenu::CMainMenu() ...@@ -74,11 +69,10 @@ CMainMenu::CMainMenu()
} }
bool CMainMenu::run(bool& outFullscreen, bool& outMusic, bool& outShadows, bool CMainMenu::run(bool& outFullscreen, bool& outMusic, bool& outShadows,
bool& outAdditive, bool &outVSync, video::E_DRIVER_TYPE& outDriver) bool& outAdditive, bool &outVSync, video::E_DRIVER_TYPE& outDriver)
{ {
MenuDevice = createDevice( outDriver, //Varmint: 2007/12/18 video::EDT_BURNINGSVIDEO, MenuDevice = createDevice(video::EDT_BURNINGSVIDEO,
core::dimension2d<s32>(512, 384), 16, false, false, false, this); core::dimension2d<s32>(512, 384), 16, false, false, false, this);
if (MenuDevice->getFileSystem()->existFile("irrlicht.dat")) if (MenuDevice->getFileSystem()->existFile("irrlicht.dat"))
...@@ -95,7 +89,7 @@ bool CMainMenu::run(bool& outFullscreen, bool& outMusic, bool& outShadows, ...@@ -95,7 +89,7 @@ bool CMainMenu::run(bool& outFullscreen, bool& outMusic, bool& outShadows,
MenuDevice->setWindowCaption(str.c_str()); MenuDevice->setWindowCaption(str.c_str());
// set new Skin // set new Skin
gui::IGUISkin* newskin = guienv->createSkin( gui::EGST_BURNING_SKIN); gui::IGUISkin* newskin = guienv->createSkin(gui::EGST_BURNING_SKIN);
guienv->setSkin(newskin); guienv->setSkin(newskin);
newskin->drop(); newskin->drop();
...@@ -106,7 +100,6 @@ bool CMainMenu::run(bool& outFullscreen, bool& outMusic, bool& outShadows, ...@@ -106,7 +100,6 @@ bool CMainMenu::run(bool& outFullscreen, bool& outMusic, bool& outShadows,
// add images // add images
const s32 leftX = 260; const s32 leftX = 260;
// add tab control // add tab control
...@@ -144,49 +137,35 @@ bool CMainMenu::run(bool& outFullscreen, bool& outMusic, bool& outShadows, ...@@ -144,49 +137,35 @@ bool CMainMenu::run(bool& outFullscreen, bool& outMusic, bool& outShadows,
guienv->addCheckBox(vsync, core::rect<int>(20,185+d,230,210+d), guienv->addCheckBox(vsync, core::rect<int>(20,185+d,230,210+d),
optTab, 7, L"Vertical synchronisation"); optTab, 7, L"Vertical synchronisation");
// add text
/*wchar_t* text = L"Welcome to the Irrlicht Engine. Please select "\
L"the settings you prefer and press 'Start Demo'. "\
L"Right click for changing menu style.";
guienv->addStaticText(text, core::rect<int>(10, 220, 220, 280),
true, true, optTab);*/
// add about text // add about text
wchar_t* text2 = L"This is the tech demo of the Irrlicht engine. To start, "\ wchar_t* text2 = L"This is the tech demo of the Irrlicht engine. To start, "\
L"select a MenuDevice which works best with your hardware and press 'start demo'. "\ L"select a video driver which works best with your hardware and press 'Start Demo'.\n"\
L"What you currently see is displayed using the Burning Software Renderer (Thomas Alten). "\ L"What you currently see is displayed using the Burning Software Renderer (Thomas Alten).\n"\
L"The Irrlicht Engine was written by me, Nikolaus Gebhardt. The models, "\ L"The Irrlicht Engine was written by me, Nikolaus Gebhardt. The models, "\
L"maps and textures were placed at my disposal by B.Collins, M.Cook and J.Marton. The music was created by "\ L"maps and textures were placed at my disposal by B.Collins, M.Cook and J.Marton. The music was created by "\
L"M.Rohde and is played back by Audiere."\ L"M.Rohde and is played back by irrKlang.\n"\
L"For more informations, please visit the homepage of the Irrlicht engine:\nhttp://www.irrlicht.sourceforge.net"; L"For more informations, please visit the homepage of the Irrlicht engine:\nhttp://irrlicht.sourceforge.net";
guienv->addStaticText(text2, core::rect<int>(10, 10, 230, 320), guienv->addStaticText(text2, core::rect<int>(10, 10, 230, 320),
true, true, aboutTab); true, true, aboutTab);
// add md2 model // add md2 model
scene::IAnimatedMesh* mesh = smgr->getMesh("../../media/faerie.md2"); scene::IAnimatedMesh* mesh = smgr->getMesh("../../media/faerie.md2");
scene::IAnimatedMeshSceneNode* modelNode = smgr->addAnimatedMeshSceneNode(mesh); scene::IAnimatedMeshSceneNode* modelNode = smgr->addAnimatedMeshSceneNode(mesh);
if (modelNode) if (modelNode)
{ {
modelNode->setPosition ( core::vector3df ( 0.f, 0.f, -5.f ) ); modelNode->setPosition( core::vector3df(0.f, 0.f, -5.f) );
modelNode->setMaterialTexture(0, driver->getTexture("../../media/faerie2.bmp")); modelNode->setMaterialTexture(0, driver->getTexture("../../media/faerie2.bmp"));
modelNode->setMaterialFlag(video::EMF_LIGHTING, true); modelNode->setMaterialFlag(video::EMF_LIGHTING, true);
modelNode->getMaterial(0).Shininess = 28.f; modelNode->getMaterial(0).Shininess = 28.f;
modelNode->getMaterial(0).NormalizeNormals = true; modelNode->getMaterial(0).NormalizeNormals = true;
modelNode->setMD2Animation ( scene::EMAT_STAND ); modelNode->setMD2Animation(scene::EMAT_STAND);
//modelNode->setMD2Animation ( scene::EMAT_JUMP );
//modelNode->setDebugDataVisible ( scene::EDS_BBOX_ALL );
//modelNode->setFrameLoop ( 0, 0 );
} }
// set ambient light ( no sun light in the catacombs ) // set ambient light (no sun light in the catacombs)
smgr->setAmbientLight ( video::SColorf ( 0.f, 0.f, 0.f ) ); smgr->setAmbientLight( video::SColorf(0.f, 0.f, 0.f) );
scene::ISceneNodeAnimator* anim; scene::ISceneNodeAnimator* anim;
scene::ISceneNode* bill; scene::ISceneNode* bill;
...@@ -197,16 +176,15 @@ bool CMainMenu::run(bool& outFullscreen, bool& outMusic, bool& outShadows, ...@@ -197,16 +176,15 @@ bool CMainMenu::run(bool& outFullscreen, bool& outMusic, bool& outShadows,
video::SColorf(0.86f, 0.38f, 0.05f), 200.0f); video::SColorf(0.86f, 0.38f, 0.05f), 200.0f);
// add fly circle animator to light 1 // add fly circle animator to light 1
anim = smgr->createFlyCircleAnimator (core::vector3df(0,0,0),30.0f, -0.004f, core::vector3df ( 0.41f, 0.4f, 0.0f ) ); anim = smgr->createFlyCircleAnimator(core::vector3df(0,0,0),30.0f, -0.004f, core::vector3df(0.41f, 0.4f, 0.0f));
light1->addAnimator(anim); light1->addAnimator(anim);
anim->drop(); anim->drop();
// let the lights follow the model... // let the lights follow the model...
anim = new CSceneNodeAnimatorFollowBoundingBox ( modelNode, core::vector3df(0,16,0), 4000, 0 ); anim = new CSceneNodeAnimatorFollowBoundingBox(modelNode, core::vector3df(0,16,0), 4000, 0);
//light1->addAnimator(anim); //light1->addAnimator(anim);
anim->drop(); anim->drop();
// attach billboard to the light // attach billboard to the light
bill = smgr->addBillboardSceneNode(light1, core::dimension2d<f32>(10, 10)); bill = smgr->addBillboardSceneNode(light1, core::dimension2d<f32>(10, 10));
bill->setMaterialFlag(video::EMF_LIGHTING, false); bill->setMaterialFlag(video::EMF_LIGHTING, false);
...@@ -220,12 +198,12 @@ bool CMainMenu::run(bool& outFullscreen, bool& outMusic, bool& outShadows, ...@@ -220,12 +198,12 @@ bool CMainMenu::run(bool& outFullscreen, bool& outMusic, bool& outShadows,
video::SColorf(0.9f, 1.0f, 0.f, 0.0f), 200.0f); video::SColorf(0.9f, 1.0f, 0.f, 0.0f), 200.0f);
// add fly circle animator to light 1 // add fly circle animator to light 1
anim = smgr->createFlyCircleAnimator (core::vector3df(0,0,0),30.0f, 0.004f, core::vector3df ( 0.41f, 0.4f, 0.0f ) ); anim = smgr->createFlyCircleAnimator(core::vector3df(0,0,0),30.0f, 0.004f, core::vector3df(0.41f, 0.4f, 0.0f));
light2->addAnimator(anim); light2->addAnimator(anim);
anim->drop(); anim->drop();
// let the lights follow the model... // let the lights follow the model...
anim = new CSceneNodeAnimatorFollowBoundingBox ( modelNode, core::vector3df(0,-8,0), 2000, 0 ); anim = new CSceneNodeAnimatorFollowBoundingBox( modelNode, core::vector3df(0,-8,0), 2000, 0 );
//light2->addAnimator(anim); //light2->addAnimator(anim);
anim->drop(); anim->drop();
...@@ -242,21 +220,23 @@ bool CMainMenu::run(bool& outFullscreen, bool& outMusic, bool& outShadows, ...@@ -242,21 +220,23 @@ bool CMainMenu::run(bool& outFullscreen, bool& outMusic, bool& outShadows,
video::SColorf(0.f, 0.0f, 0.9f, 0.0f), 40.0f); video::SColorf(0.f, 0.0f, 0.9f, 0.0f), 40.0f);
// add fly circle animator to light 2 // add fly circle animator to light 2
anim = smgr->createFlyCircleAnimator (core::vector3df(0,0,0),40.0f, 0.004f, core::vector3df ( -0.41f, -0.4f, 0.0f ) ); anim = smgr->createFlyCircleAnimator(core::vector3df(0,0,0),40.0f, 0.004f, core::vector3df(-0.41f, -0.4f, 0.0f));
light3->addAnimator(anim); light3->addAnimator(anim);
anim->drop(); anim->drop();
// let the lights follow the model... // let the lights follow the model...
anim = new CSceneNodeAnimatorFollowBoundingBox ( modelNode, core::vector3df(0,8,0), 8000, 0 ); anim = new CSceneNodeAnimatorFollowBoundingBox(modelNode, core::vector3df(0,8,0), 8000, 0);
//light3->addAnimator(anim); //light3->addAnimator(anim);
anim->drop(); anim->drop();
// attach billboard to the light // attach billboard to the light
bill = smgr->addBillboardSceneNode(light3, core::dimension2d<f32>(10, 10)); bill = smgr->addBillboardSceneNode(light3, core::dimension2d<f32>(10, 10));
if (bill)
bill->setMaterialFlag(video::EMF_LIGHTING, false); {
bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR); bill->setMaterialFlag(video::EMF_LIGHTING, false);
bill->setMaterialTexture(0, driver->getTexture("../../media/portal1.bmp")); bill->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
bill->setMaterialTexture(0, driver->getTexture("../../media/portal1.bmp"));
}
#endif #endif
// create a fixed camera // create a fixed camera
...@@ -274,9 +254,8 @@ bool CMainMenu::run(bool& outFullscreen, bool& outMusic, bool& outShadows, ...@@ -274,9 +254,8 @@ bool CMainMenu::run(bool& outFullscreen, bool& outMusic, bool& outShadows,
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, oldMipMapState); driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, oldMipMapState);
// query original skin color // query original skin color
getOriginalSkinColor (); getOriginalSkinColor();
// set transparency // set transparency
setTransparency(); setTransparency();
...@@ -289,10 +268,9 @@ bool CMainMenu::run(bool& outFullscreen, bool& outMusic, bool& outShadows, ...@@ -289,10 +268,9 @@ bool CMainMenu::run(bool& outFullscreen, bool& outMusic, bool& outShadows,
{ {
driver->beginScene(false, true, video::SColor(0,0,0,0)); driver->beginScene(false, true, video::SColor(0,0,0,0));
if ( irrlichtBack ) if (irrlichtBack)
driver->draw2DImage(irrlichtBack, driver->draw2DImage(irrlichtBack,
core::position2d<int>(0,0) core::position2d<int>(0,0));
);
smgr->drawAll(); smgr->drawAll();
guienv->drawAll(); guienv->drawAll();
...@@ -321,7 +299,6 @@ bool CMainMenu::run(bool& outFullscreen, bool& outMusic, bool& outShadows, ...@@ -321,7 +299,6 @@ bool CMainMenu::run(bool& outFullscreen, bool& outMusic, bool& outShadows,
} }
bool CMainMenu::OnEvent(const SEvent& event) bool CMainMenu::OnEvent(const SEvent& event)
{ {
if (event.EventType == EET_KEY_INPUT_EVENT && if (event.EventType == EET_KEY_INPUT_EVENT &&
...@@ -369,7 +346,7 @@ bool CMainMenu::OnEvent(const SEvent& event) ...@@ -369,7 +346,7 @@ bool CMainMenu::OnEvent(const SEvent& event)
{ {
selected = ((gui::IGUIListBox*)event.GUIEvent.Caller)->getSelected(); selected = ((gui::IGUIListBox*)event.GUIEvent.Caller)->getSelected();
//startButton->setEnabled(selected != 4); //startButton->setEnabled(selected != 4);
startButton->setEnabled( true ); startButton->setEnabled(true);
} }
break; break;
case 2: case 2:
...@@ -410,21 +387,22 @@ void CMainMenu::getOriginalSkinColor() ...@@ -410,21 +387,22 @@ void CMainMenu::getOriginalSkinColor()
irr::gui::IGUISkin * skin = MenuDevice->getGUIEnvironment()->getSkin(); irr::gui::IGUISkin * skin = MenuDevice->getGUIEnvironment()->getSkin();
for (s32 i=0; i<gui::EGDC_COUNT ; ++i) for (s32 i=0; i<gui::EGDC_COUNT ; ++i)
{ {
SkinColor [ i ] = skin->getColor ( (gui::EGUI_DEFAULT_COLOR)i ); SkinColor[i] = skin->getColor( (gui::EGUI_DEFAULT_COLOR)i );
} }
} }
void CMainMenu::setTransparency() void CMainMenu::setTransparency()
{ {
irr::gui::IGUISkin * skin = MenuDevice->getGUIEnvironment()->getSkin(); irr::gui::IGUISkin * skin = MenuDevice->getGUIEnvironment()->getSkin();
for (u32 i=0; i<gui::EGDC_COUNT ; ++i) for (u32 i=0; i<gui::EGDC_COUNT ; ++i)
{ {
video::SColor col = SkinColor [ i ]; video::SColor col = SkinColor[i];
if ( false == transparent ) if (false == transparent)
col.setAlpha( 255); col.setAlpha(255);
skin->setColor((gui::EGUI_DEFAULT_COLOR)i, col); skin->setColor((gui::EGUI_DEFAULT_COLOR)i, col);
} }
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
#define __IRR_COMPILE_CONFIG_H_INCLUDED__ #define __IRR_COMPILE_CONFIG_H_INCLUDED__
//! Irrlicht SDK Version //! Irrlicht SDK Version
#define IRRLICHT_SDK_VERSION "1.4.1" #define IRRLICHT_SDK_VERSION "1.4.2"
//! The defines for different operating system are: //! The defines for different operating system are:
//! _IRR_XBOX_PLATFORM_ for XBox //! _IRR_XBOX_PLATFORM_ for XBox
...@@ -82,7 +82,7 @@ to the compiler settings: -DIRR_COMPILE_WITH_DX9_DEV_PACK ...@@ -82,7 +82,7 @@ to the compiler settings: -DIRR_COMPILE_WITH_DX9_DEV_PACK
and this to the linker settings: -ld3dx9 -ld3dx8 **/ and this to the linker settings: -ld3dx9 -ld3dx8 **/
#if defined(_IRR_WINDOWS_API_) && (!defined(__GNUC__) || defined(IRR_COMPILE_WITH_DX9_DEV_PACK)) #if defined(_IRR_WINDOWS_API_) && (!defined(__GNUC__) || defined(IRR_COMPILE_WITH_DX9_DEV_PACK))
//#define _IRR_COMPILE_WITH_DIRECT3D_8_ #define _IRR_COMPILE_WITH_DIRECT3D_8_
#define _IRR_COMPILE_WITH_DIRECT3D_9_ #define _IRR_COMPILE_WITH_DIRECT3D_9_
#endif #endif
......
...@@ -141,7 +141,7 @@ ...@@ -141,7 +141,7 @@
#include "SMeshBufferTangents.h" #include "SMeshBufferTangents.h"
#include "SViewFrustum.h" #include "SViewFrustum.h"
/*! \mainpage Irrlicht Engine 1.4.1 API documentation /*! \mainpage Irrlicht Engine 1.4.2 API documentation
* *
* <div align="center"><img src="logobig.png" ></div> * <div align="center"><img src="logobig.png" ></div>
* *
......
========================================================================== ==========================================================================
The Irrlicht Engine SDK version 1.4.1 The Irrlicht Engine SDK version 1.4.2
========================================================================== ==========================================================================
Welcome the Irrlicht Engine SDK. Welcome the Irrlicht Engine SDK.
......
No preview for this file type
...@@ -444,7 +444,7 @@ WARN_LOGFILE = ...@@ -444,7 +444,7 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories # directories like "/usr/src/myproject". Separate the files or directories
# with spaces. # with spaces.
INPUT = ../../../include/ INPUT = ../../../include/ tut.txt
# If the value of the INPUT tag contains directories, you can use the # If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
...@@ -504,7 +504,7 @@ EXAMPLE_RECURSIVE = NO ...@@ -504,7 +504,7 @@ EXAMPLE_RECURSIVE = NO
# directories that contain image that are included in the documentation (see # directories that contain image that are included in the documentation (see
# the \image command). # the \image command).
IMAGE_PATH = IMAGE_PATH = ../../../media
# The INPUT_FILTER tag can be used to specify a program that doxygen should # The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program # invoke to filter for each input file. Doxygen will invoke the filter program
......
...@@ -444,7 +444,7 @@ WARN_LOGFILE = ...@@ -444,7 +444,7 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories # directories like "/usr/src/myproject". Separate the files or directories
# with spaces. # with spaces.
INPUT = ../../../include/ INPUT = ../../../include/ tut.txt
# If the value of the INPUT tag contains directories, you can use the # If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
...@@ -504,7 +504,7 @@ EXAMPLE_RECURSIVE = NO ...@@ -504,7 +504,7 @@ EXAMPLE_RECURSIVE = NO
# directories that contain image that are included in the documentation (see # directories that contain image that are included in the documentation (see
# the \image command). # the \image command).
IMAGE_PATH = IMAGE_PATH = ../../../media
# The INPUT_FILTER tag can be used to specify a program that doxygen should # The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program # invoke to filter for each input file. Doxygen will invoke the filter program
...@@ -761,13 +761,13 @@ LATEX_HEADER = ...@@ -761,13 +761,13 @@ LATEX_HEADER =
# contain links (just like the HTML output) instead of page references # contain links (just like the HTML output) instead of page references
# This makes the output suitable for online browsing using a pdf viewer. # This makes the output suitable for online browsing using a pdf viewer.
PDF_HYPERLINKS = NO PDF_HYPERLINKS = YES
# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
# plain latex in the generated Makefile. Set this option to YES to get a # plain latex in the generated Makefile. Set this option to YES to get a
# higher quality PDF documentation. # higher quality PDF documentation.
USE_PDFLATEX = NO USE_PDFLATEX = YES
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
# command to the generated LaTeX files. This will instruct LaTeX to keep # command to the generated LaTeX files. This will instruct LaTeX to keep
......
...@@ -14,6 +14,6 @@ ...@@ -14,6 +14,6 @@
| <a class="qindex" href="namespacemembers.html"><font color="#FFFFFF"> | <a class="qindex" href="namespacemembers.html"><font color="#FFFFFF">
Namespace&nbsp;Members</font></a> | <a class="qindex" href="functions.html"><font color="#FFFFFF">Class Namespace&nbsp;Members</font></a> | <a class="qindex" href="functions.html"><font color="#FFFFFF">Class
members</font></a> | <a class="qindex" href="globals.html"><font color="#FFFFFF">File members</font></a> | <a class="qindex" href="globals.html"><font color="#FFFFFF">File
members</font></a></font> </td> members</font></a> | <a class="qindex" href="pages.html"><font color="#FFFFFF">Tutorials</font></a></font> </td>
</tr> </tr>
</table> </table>
...@@ -4,6 +4,25 @@ copy doxygen.css ..\..\..\doctemp\html ...@@ -4,6 +4,25 @@ copy doxygen.css ..\..\..\doctemp\html
copy irrlicht.png ..\..\..\doctemp\html copy irrlicht.png ..\..\..\doctemp\html
copy logobig.png ..\..\..\doctemp\html copy logobig.png ..\..\..\doctemp\html
rem for /F %%i in ('dir ..\..\..\examples\[01]*\main.cpp') DO ..\sed.exe -f tutorials.sed %i >>tut.txt
..\sed.exe -f tutorials.sed ..\..\..\examples\01.HelloWorld\main.cpp >tut.txt
..\sed.exe -f tutorials.sed ..\..\..\examples\02.Quake3Map\main.cpp >>tut.txt
..\sed.exe -f tutorials.sed ..\..\..\examples\03.CustomSceneNode\main.cpp >>tut.txt
..\sed.exe -f tutorials.sed ..\..\..\examples\04.Movement\main.cpp >>tut.txt
..\sed.exe -f tutorials.sed ..\..\..\examples\05.UserInterface\main.cpp >>tut.txt
..\sed.exe -f tutorials.sed ..\..\..\examples\06.2DGraphics\main.cpp >>tut.txt
..\sed.exe -f tutorials.sed ..\..\..\examples\07.Collision\main.cpp >>tut.txt
..\sed.exe -f tutorials.sed ..\..\..\examples\08.SpecialFX\main.cpp >>tut.txt
..\sed.exe -f tutorials.sed ..\..\..\examples\09.MeshViewer\main.cpp >>tut.txt
..\sed.exe -f tutorials.sed ..\..\..\examples\10.Shaders\main.cpp >>tut.txt
..\sed.exe -f tutorials.sed ..\..\..\examples\11.PerPixelLighting\main.cpp >>tut.txt
..\sed.exe -f tutorials.sed ..\..\..\examples\12.TerrainRendering\main.cpp >>tut.txt
..\sed.exe -f tutorials.sed ..\..\..\examples\13.RenderToTexture\main.cpp >>tut.txt
..\sed.exe -f tutorials.sed ..\..\..\examples\14.Win32Window\main.cpp >>tut.txt
..\sed.exe -f tutorials.sed ..\..\..\examples\15.LoadIrrFile\main.cpp >>tut.txt
..\sed.exe -f tutorials.sed ..\..\..\examples\16.Quake3MapShader\main.cpp >>tut.txt
..\sed.exe -f tutorials.sed ..\..\..\examples\17.SplitScreen\main.cpp >>tut.txt
..\doxygen.exe doxygen.cfg ..\doxygen.exe doxygen.cfg
pause pause
\ No newline at end of file
doxygen doxygen.cfg rm tut.txt || true;
for i in ../../../examples/[01]*/main.cpp; do
sed -f tutorials.sed $i >>tut.txt;
done
doxygen doxygen-pdf.cfg
cp doxygen.css irrlicht.png logobig.png ../../../doctemp/html cp doxygen.css irrlicht.png logobig.png ../../../doctemp/html
......
# Page start and end are delimited by /** and **/
# we keep the end unchanged, the header is extended
s/\/\*\* Example \(0*\)\([0-9]*\) \(.*\)$/\/\*\* \\page example\1\2 Tutorial \2: \3\n \\image html \"\1\2shot.jpg\"\n \\image latex \"\1\2shot.jpg\"/
# All other comments start and end code sections
s/\([^\*]\)\*\//\1\\code/
s/^\*\//\\code/
s/\/\*\([^\*]\)/\\endcode \1/
s/\/\*$/\\endcode\n/
#remove DOS line endings
s/\r//g
GNU sed version 4.0.7 - compiled for Win32.
Native executable requires only the Microsoft
C runtime MSVCRT.DLL, not an emulation layer
like Cygwin. This .EXE file was obtained from
http://unxutils.sourceforge.net on 2003-10-21.
For documentation, GPL license, source code,
etc., visit http://unxutils.sourceforge.net.
Downloaded from http://www.student.northpark.edu/pemente/sed/
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# norootforbuild # norootforbuild
Name: libIrrlicht1 Name: libIrrlicht1
Version: 1.4.beta Version: 1.4.2
Release: 0.pm.1 Release: 0.pm.1
Summary: The Irrlicht Engine SDK Summary: The Irrlicht Engine SDK
License: see readme.txt License: see readme.txt
......
...@@ -589,8 +589,8 @@ bool C3DSMeshFileLoader::readTrackChunk(io::IReadFile* file, ChunkData& data, ...@@ -589,8 +589,8 @@ bool C3DSMeshFileLoader::readTrackChunk(io::IReadFile* file, ChunkData& data,
file->read(&vec.Z, sizeof(f32)); file->read(&vec.Z, sizeof(f32));
#ifdef __BIG_ENDIAN__ #ifdef __BIG_ENDIAN__
vec.X = os::Byteswap::byteswap(vec.X); vec.X = os::Byteswap::byteswap(vec.X);
vec.Y = os::Byteswap::byteswap(vec.X); vec.Y = os::Byteswap::byteswap(vec.Y);
vec.Z = os::Byteswap::byteswap(vec.X); vec.Z = os::Byteswap::byteswap(vec.Z);
#endif #endif
data.read += 12; data.read += 12;
vec-=pivot; vec-=pivot;
......
VERSION = 1.4 VERSION = 1.4.2
# Irrlicht Engine 1.4 # Irrlicht Engine 1.4.2
# Makefile for Linux # Makefile for Linux
# #
# To use, just run: # To use, just run:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment