You are on page 1of 102

Ogre Basic Tutorial (2010/06/18)

The content on this page is licensed under the terms of the Creative Commons Attribution-ShareAlike
License.
As an exception, any source code contributed ithin the content is released into the !ublic "omain.
#istory$
%&'&(&)('*$ The first release +by teraapi,
-asic Tutorial ' $ An introduction to the most basic .gre constructs$ Scene/anager, Scene0ode,
and 1ntity ob2ects.
-asic Tutorial % $ Cameras, Lights, and Shados
-asic Tutorial 3 $ Terrain, Sky, and 4og
-asic Tutorial 5 $ 4rame Listeners and 6nbuffered 7nput
-asic Tutorial 8 $ -uffered 7nput
-asic Tutorial ) $ The .gre Startup Se9uence
-asic Tutorial : $ C1;67 and .gre
-asic Tutorial * $ /ultiple and "ual Scene/anagers
Basic Tutorial 1 :
An introduction to the most basic Ogre
constructs: SceneManager, SceneNode, and
Entity objects.
Tutorial Introduction
7n this tutorial e ill be introducing you to the most basic .gre constructs$ Scene/anager,
Scene0ode, and 1ntity ob2ects. <e ill not cover a large amount of code= instead e ill be
focusing on the general concepts for you to begin learning .gre.
As you go through the tutorial you should be sloly adding code to your on pro2ect and
atching the results as e build it. There is no substitute for actual programming to get familiar
ith these concepts> ?esist the urge to simply read along.
Any problems you encounter hile orking ith this tutorial should be posted to the #elp 4orum .
rere!uisites
This tutorial assumes you have knoledge of C@@ programming and are able to setup and compile an
.gre application +if you have trouble setting up your application, see this guide for specific compiler
setups,. 0. knoledge of .gre is assumed for this tutorial outside of hat is contained in the setup
guide.
Table o" contents
!rere9uisites
;etting Started
7nitial Code
Troubleshooting
/essage -ox Trouble
/issing a Configuration 4ile or "LLs
?esources or !lugin !roblems
Cannot Launch the Application in Aisual Studio
#o .gre <orks
Scene/anager -asics
1ntity -asics
Scene0ode -asics
Bour first .gre application
Coordinates and Aectors
Adding another .b2ect
1ntities more in "epth
Scene0odes more in "epth
Things to Try
Scale
?otations
The .gre 1nvironment
"LLs and !lugins
Configuration 4iles
A -etter <ay to Test Bour Application
Conclusion
#etting Started
$nitial %ode
<e ill be using a pre-constructed code base for this tutorial. Bou should ignore all of the code except
for hat e ill be adding to the createScene method. 7n a later tutorial e ill go in depth explaining
ho .gre applications ork, but for no e ill be starting at the most basic level.
?ead Setting up an Application to learn ho to create the initial pro2ect and source files for your
particular 7"1 and environment.
Create a pro2ect named the pro2ect Tutorial.
Add the tutorial application frameork to it$
BaseApplication.h
BaseApplication.cpp
TutorialApplication.h
TutorialApplication.cpp
;et the files from here$ .gre <iki Tutorial 4rameork
.r, use the .gre App<iCard .
TutorialApplication.cpp is the only file that e ill be using for this tutorial and e ill only be orking
ith createScene+, member function.
TutorialApplication.cpp should contain the folloing code. 7 have removed the only header comments to
keep the clutter don.
#include "TutorialApplication.h"
TutorialApplication::TutorialApplication(void)
{
}
TutorialApplication::~TutorialApplication(void)
{
}
//-------------------------------------------------------------------------------
------
void TutorialApplication::createScene(void)
{
Ogre::ntit!" ogre#ead $ %Scene&gr'(createntit!("#ead") "ogrehead.%esh")*
Ogre::Scene+ode" head+ode $ %Scene&gr'(get,ootScene+ode()'
(create-hildScene+ode()*
head+ode'(attachO./ect(ogre#ead)*
// Set ambient light
%Scene&gr'(setA%.ient0ight(Ogre::-olour1alue(2.3) 2.3) 2.3))*
// Create a light
Ogre::0ight" l $ %Scene&gr'(create0ight("&ain0ight")*
l'(set4osition(52)62)32)*
}
#i7 O8,940AT:O,& $$ O8,940AT:O,&9;<+=5
#de7ine ;<+=590A+9A+>9&A+
#include "?indo?s.h"
#endi7
#i7de7 99cplusplus
e@tern "-" {
#endi7
#i7 O8,940AT:O,& $$ O8,940AT:O,&9;<+=5
<+T ;<+A4< ;in&ain( #<+STA+- h<nst) #<+STA+-) 04ST, str-%d0ine) <+T )
#else
int %ain(int argc) char "argvAB)
#endi7
{
// Create application object
TutorialApplication app*
tr!
{
app.go()*
} catch( Ogre::@ceptionC e ) {
#i7 O8,940AT:O,& $$ O8,940AT:O,&9;<+=5
&essageBo@( +D00) e.get:ull>escription().c9str()) "An e@ception has
occuredE") &B9OF G &B9<-O+,,O,G &B9TASF&O>A0)*
#else
std::cerr HH "An e@ception has occured: " HH
e.get:ull>escription().c9str() HH std::endl*
#endi7
}
return 2*
}
#i7de7 99cplusplus
}
#endi7
;o ahead and compile and run this program to make sure that your environment is set up correctly. .nce
the program is orking, use the <AS" keys to move, and the mouse to look around. The 1scape key
exits the program.
Troubleshooting
7f you have problems, check Setting 6p An Application to setup your compiler properly, or look in the
.gre.log file for more detailed information. 7f you need further help, search the forums. 7t is likely your
problem has happened to others many times. 7f this is a ne issue, read the forum rules then ask aay.
/ake sure to provide relevant details from your .gre.log, exceptions, error messages, and(or debugger
back traces.
Note that later tutorials &ill not contain this troubleshooting in"ormation, so 'lease 'ay s'ecial
attention to the "ollo&ing sections i" you are ha(ing 'roblems.
Message Bo) Trouble
7f you are using Aisual Studios ith 6nicode support turned on for the pro2ect you may encounter this
error$
error -5IIJ: K&essageBo@;K : cannot convert para%eter 5 7ro% Kconst char "K to
K04-;ST,K
T!pes pointed to are unrelated* conversion reLuires reinterpret9cast) -'
st!le cast or 7unction'st!le cast
The problem is that the /essage-ox function is +in this case, expecting 6nicode, and e are giving it an
A0S7 string. To fix this, change the folloing line$
&essageBo@( +D00) e.?hat()) "An e@ception has occuredE") &B9OF G &B9<-onerror
G &B9TASF&O>A0)*
to this$
&essageBo@KKKAKKK( +D00) e.?hat()) "An e@ception has occuredE") &B9OF G
&B9<-onerror G &B9TASF&O>A0)*
.r you can change your text format in the compiler from 6nicode to A0S7. #oever, you ill lose
support for international languages.
The reason for this is that D/essage-oxD is automatically resolved to either /essage-oxA +A0S7, or
/essage-ox< +<ide(6nicode,, depending on the pro2ect configuration. <e fix the error by being
explicit about it using A0S7.
Missing a %on"iguration *ile or +,,s
7f you try to launch your freshly built application but the program complains of missing "LLs or
configuration files +E.cfg,, then you probably did not copy them over from the .greS"F folder. 7n Aisual
Studios, hen you build your application in release mode, it puts the release executable in the
G!ro2ect4olderHIbinIrelease folder, and the debug executable in the G!ro2ect4olderHIbinIdebug folder. Bou
must copy all the D.dllD and D.cfgD files over from the .greS"F into the appropriate folders. That is, copy
the files from G.greS"FHIbinIrelease to G!ro2ect4olderHIbinIrelease and G.greS"FHIbinIdebug to
G!ro2ect4olderHIbinIdebug. Bou ill also need to edit the resources.cfg file to point at the correct paths.
See the next section for more information on this.
-esources or lugin roblems
/ake sure you have a plugins.cfg and a resources.cfg in the same directory as the executable. !lugins.cfg
tells .;?1 hich rendering libraries are available +"irect3"J, .pen;L, etc,. ?esources.cfg is used by
the 1xampleApplication and specifies paths to textures, meshes and scripts. -oth are text files, so edit
them and make sure the paths are correct. .therise your .;?1 setup dialog box may not have any
rendering libraries in it, or you may receive an error on your screen or in .gre.log that looks something
like this$
>escription: ..M..M&ediaMpacNsMOgre-ore.Oip ' error ?hilst opening archive:
Dna.le to read Oip 7ile
7f this is the case, open up the resources.cfg file and change the paths it contains to point to locations in
the /edia folder that came ith .gre. 0ote you cannot use environment variables such as K
+SomeAariable, in these paths.
%annot ,aunch the A''lication in .isual Studio
7f you are using Aisual Studio or Aisual C@@ to create the application and are having trouble launching it
from the environment, the problem is most likely due to the debugger settings. 7f you press the play
button +or go to the Start "ebugging menu item, and you get an exception saying that a configuration file
+E.cfg, cannot be found, then the <orking "irectory has probably not been set.
The exact instructions for fixing this ill vary based on which version of Aisual C@@ you are using, so 7
cannot give you a direct alk through, but the basic steps should be the same. ?ight click on your 'roject
in the solution explorer +not the solution itself, and go to properties. Somehere in the configuration
properties should be options for D"ebuggingD. 7n the debugging options there should be a field for
D<orking "irectoryD. This should be set to the location that the executable file for your pro2ect is being
placed.
7f you are having trouble figuring out hat to put there, try to mimic the DCommandD field hich should
also be in the debugging options. 4or example, in Aisual C@@ %&&3, the DCommandD field should be
something similar to D..I..IbinIK+Configuration0ame,IK+Target4ile0ame,D. 4or the <orking "irectory, e
need to remove the portion of the command hich is the target file name +the executable,. 7n this case, the
orking directory ould be D..I..IbinIK+Configuration0ame,D. The exact string you have to put there may
vary based on your version of Aisual C@@ and on your build environment, so be sure to check hat the
Command field is before doing this. -e sure to change the <orking "irectory for both the ?elease and
"ebug configuration.
7n Aisual C@@ %&&8 it ill probably be something different entirely. 7Lve found the D..I..IbinIK
+Configuration0ame,D directory a good thing to try first, if it still does not ork you may have to play
ith it some, or consult some help from the .gre forums.
The reason e have to do this is that .gre expects certain files to be in the same directory as the
executable, and ithout setting the orking directory to be a directory ith these files in it.
.nce you have successfully run the program, go ahead and remove the code from inside the createScene+,
function but do not remove the function itself. <e ill be place code back into this function and
examining it line by line.
/o& Ogre 0or1s
A broad topic. <e ill start ith Scene/anagers and ork our ay to 1ntities and Scene0odes. These
three classes are the fundamental building blocks of .gre applications.
SceneManager Basics
1verything that appears on the screen is managed by the Scene/anager +fancy that,. <hen you place
ob2ects in the scene, the Scene/anager is the class hich keeps track of their locations. <hen you create
Cameras to vie the scene +hich e ill cover in a later tutorial, the Scene/anager keeps track of
them. <hen you create planes, billboards, lights...and so on, the Scene/anager keeps track of them.
There are multiple types of Scene/anagers. There are Scene/anagers that render terrain, there is a
Scene/anager for rendering -S! maps, and so on. Bou can see the various types of Scene/anagers
listed here. <e ill cover more about other Scene/anagers as e progress through the tutorials.
Entity Basics
An 1ntity is one of the types of ob2ect that you can render on a scene. Bou can think of an 1ntity as being
anything thatLs represented by a 3" mesh. A robot ould be an entity, a fish ould be an entity, the
terrain your characters alk on ould be a very large entity. Things such as Lights, -illboards, !articles,
Cameras, etc ould not be entities.
.ne thing to note about .gre is that it separates renderable ob2ects from their location and orientation.
This means that you cannot directly place an 1ntity in a scene. 7nstead you must attach the 1ntity to a
Scene0ode ob2ect, and this Scene0ode contains the information about location and orientation.
SceneNode Basics
As already mentioned, Scene0odes keep track of location and orientation for all of the ob2ects attached to
it. <hen you create an 1ntity, it is not rendered in the scene until you attach it to a Scene0ode. 7n
addition a Scene0ode is not an ob2ect that is displayed on the screen. .nly hen you create a Scene0ode
and attach an 1ntity +or other ob2ect, to it is something actually displayed on the screen.
Scene0odes can have any number of ob2ects attached to them. LetLs say you have a character alking
around on the screen and you ant to have him generate a light around him. The ay you do this ould
be to first create a Scene0ode, then create an 1ntity for the character and attach it to the Scene0ode. Then
you ould create a Light ob2ect and attach it to the Scene0ode. Scene0odes may also be attached to other
Scene0odes hich allos you to create entire hierarchies of nodes. <e ill cover more advanced uses of
Scene0ode attachment in a later tutorial.
.ne ma2or concept to note about Scene0odes is that a Scene0odeLs position is al&ays relative to its
parent Scene0ode, and each Scene/anager contains a root node to hich all other Scene0odes are
attached.
2our "irst Ogre a''lication
0o go back to the code e created earlier. 4ind the TutorialApplication$$createScene member function.
<e ill only be manipulating the contents of this function in this tutorial. The first thing e ant to do is
set the ambient light for the scene so that e can see hat e are doing. <e do this by calling the
setAmbientLight function and specifying hat color e ant. 0ote that the ColourAalue constructor
expects values for red, green, and blue in the range beteen & and '. Add this line to createScene$
%Scene&gr'(setA%.ient0ight(Ogre::-olour1alue(P.2) P.2) P.2))*
The next thing e need to do is create an 1ntity. <e do this by calling the Scene/anagerLs create1ntity
member function$
Ogre::ntit!" ogre#ead $ %Scene&gr'(createntit!("#ead") "ogrehead.%esh")*
.kay, several 9uestions should pop up. 4irst of all, here did mScene/gr come from, and hat are the
parameters e are calling the function ithM The mScene/gr variable contains the current Scene/anager
ob2ect +this is done for us by the -aseApplication class,. The first parameter to create1ntity is the name of
the 1ntity e are creating. All entities must ha(e a uni!ue name. Bou ill get an error if you try to
create to entities ith the same name. The Dogrehead.meshD parameter specifies the mesh e ant to
use for the 1ntity. Dogrehead.meshD is a resource hich comes ith the .gre S"F. ?esource loading ill
be covered in a later tutorial as ill meshes. 4or no e are using the resource loading capabilities of the
-aseApplication class.
0o that e have created the 1ntity, e need to create a Scene0ode to attach it to. Since every
Scene/anager has a root Scene0ode, e ill be creating a child of that node$
Ogre::Scene+ode" head+ode $ %Scene&gr'(get,ootScene+ode()'
(create-hildScene+ode("#ead+ode")*
This long statement first calls the get?ootScene0ode of the current Scene/anager. Then it calls the
createChildScene0ode method of the root Scene0ode. The parameter to createChildScene0ode is the
name of the Scene0ode e are creating. Like the 1ntity class, no to Scene0odes can have the same
name.
4inally, e need to attach the 1ntity to the Scene0ode to give the ?obot a render location$
head+ode'(attachO./ect(ogre#ead)*
And thatLs it> Compile and run your application. Bou should see an .greLs head on your screen.
%oordinates and .ectors
-efore e go any further, e need to talk about screen coordinates and .gre Aector ob2ects. .gre +like
many graphics engines, uses the x and C axis as the horiContal plane, and the y axis as your vertical axis.
As you are looking at your monitor no, the x axis ould run from the left side to the right side of your
monitor, ith the right side being the positive x direction. The y axis ould run from the bottom of your
monitor to the top of your monitor, ith the top being the positive y direction. The C axis ould run into
and out of your screen, ith out of the screen being the positive C direction.
0otice ho our .gre #ead is facing toards us along the -x directionM This is a property of the mesh and
the camera position and facing. Cameras are covered in a later tutorial but for no 2ust recogniCe the the
.greLs head is located at the position +&,&,&, and the our vie of it is from in front a ays. The direction
that the head is facing is a result of ho the mesh as oriented hen it as created and saved by the
artist. .gre makes no assumptions about ho you orient your models. 1ach mesh that you load may have
a different Dstarting directionD hich it is facing.
.gre uses the Aector class to represent both position and direction +there is no !oint class,. There are
vectors defined for % +Aector%,, 3 +Aector3,, and 5 +Aector5, dimensions, ith Aector3 being the most
commonly used. 7f you are not familiar ith Aectors, 7 suggest you brush up on it before doing
anything serious ith .gre. The math behind Aectors ill become very useful hen you start orking on
complex programs.
Adding another Object
0o that you understand ho the coordinate systems ork, e can go back to our code. 7n the three lines
e rote, nohere did e specify the exact location here e anted our .gre head to appear. A large
ma2ority of the functions in .gre have default parameters for them. 4or example, the
Scene0ode$$createChildScene0ode member function in .gre has three parameters$ the name of the
Scene0ode, the position of the Scene0ode, and the initial rotation +orientation, the Scene0ode is facing.
The position, as you can see, has been set for us to the coordinates +&, &, &,. LetLs create another
Scene0ode, but this time eLll specify the starting location to be something other than the origin$
Ogre::ntit!" ogre#ead5 $ %Scene&gr'(createntit!( "#ead5") "ogrehead.%esh" )*
Ogre::Scene+ode" head+ode5 $ %Scene&gr'(get,ootScene+ode()'(create-hildScene+ode(
"#ead+ode5") Ogre::1ector=( P22) 2) 2 ) )*
head+ode5'(attachO./ect( ogre#ead5 )*
This should look familiar. <e have done the exact same thing as before, ith to exceptions. 4irst of all,
e have named the 1ntity and Scene0ode something slightly different. The second thing e have done is
specified that the starting position ill be '&& units in the x direction aay from the root Scene0ode
+remember that all Scene0ode positions are relative to their parents,. Compile and run the demo. 0o
there are to .gre heads side-by-side. Bou may have to move back using the LsL key or the don arro to
see both heads.
Entities more in +e'th
The 1ntity class is very extensive, and 7 ill not be covering ho to use every portion of the ob2ect
here...2ust enough to get you started. There are a fe immediately useful member functions in 1ntity that
7Ld like to point out.
The first is 1ntity$$setAisible and 1ntity$$isAisible. Bou can set any 1ntity to be visible or not by simply
calling this function. 7f you need to hide an 1ntity, but later display it, then call this function instead of
destroying the 1ntity and later recreating it. 0ote that you donLt need to DpoolD 1ntities up. .nly one copy
of any ob2ectLs mesh and texture are ever loaded into memory, so you are not saving yourself much by
trying to save them. The only thing you really save is the creation and destruction costs for the 1ntity
ob2ect itself, hich is relatively lo.
The get0ame function returns the name of 1ntity, and the get!arentScene0ode function returns the
Scene0ode that the 1ntity is attached to.
SceneNodes more in +e'th
The Scene0ode class is very complex. There are a lot of things that can be done ith a Scene0ode, so
eLll only cover some of the most useful.
Bou can get and set the position of a Scene0ode ith get!osition and set!osition +alays relative to the
parent Scene0ode,. Bou can move the ob2ect relative to its current position by using the translate method.
Scene0odes not only set position, but they also manage the scale and rotation of the ob2ect. Bou can set
the scale of an ob2ect ith the scale function. Bou can use the pitch, ya, and roll functions to rotate
ob2ects. Bou can use reset.rientation to reset all rotations done to the ob2ect. Bou can also use the
set.rientation, get.rientation, and rotate functions for more advanced rotations. <e ill not be covering
Nuaternions until a much later tutorial though.
Bou have already seen the attach.b2ect function. These related functions are also useful if you are
looking to manipulate the ob2ects that are attached to a Scene0ode$ numAttached.b2ects,
getAttached.b2ect +there are multiple versions of this function,, detach.b2ect +also multiple versions,,
detachAll.b2ects. There are also a hole set of functions for dealing ith parent and child Scene0odes as
ell.
Since all positioning and translating is done relative to the parent Scene0ode, e can make to
Scene0odes move together very easily. <e currently have this code in the application$
%Scene&gr'(setA%.ient0ight(Ogre::-olour1alue(P.2) P.2) P.2))*
Ogre::ntit!" ogre#ead $ %Scene&gr'(createntit!("#ead") "ogrehead.%esh")*
Ogre::Scene+ode" head+ode $ %Scene&gr'(get,ootScene+ode()'
(create-hildScene+ode("#ead+ode")*
head+ode'(attachO./ect(ogre#ead)*
Ogre::ntit!" ogre#ead5 $ %Scene&gr'(createntit!( "#ead5") "ogrehead.%esh" )*
Ogre::Scene+ode" head+ode5 $ %Scene&gr'(get,ootScene+ode()'(create-hildScene+ode(
"#ead+ode5") Ogre::1ector=( P22) 2) 2 ) )*
head+ode5'(attachO./ect( ogre#ead5 )*
7f e change the )th line from this$
Ogre::Scene+ode" head+ode5 $ %Scene&gr'(get,ootScene+ode()'(create-hildScene+ode(
"#ead+ode5") Ogre::1ector=( P22) 2) 2 ) )*
To this$
Ogre::Scene+ode" head+ode5 $ head+ode'(create-hildScene+ode( "#ead+ode5")
Ogre::1ector=( P22) 2) 2 ) )*
Then e have made head0ode% a child of head0ode. /oving head0ode ill move head0ode% along
ith it, but moving head0ode% ill not affect head0ode. 4or example this code ould move only
head0ode%$
head+ode5'(translate( 1ector=( P2) 2) P2 ) )*
The folloing code ould move head0ode, and since head0ode% is a child of head0ode, head0ode%
ould be moved as ell$
head+ode'(translate( 1ector=( 53) 2) 2 ) )*
7f you are having trouble ith this, the easiest thing to do is to start at the root Scene0ode and go
donards. LetLs say +as in this case,, e started head0ode and +&, &, &, and translated it by +%8, &, &,,
thus head0odeLs position is +%8, &, &, relative to its parent. head0ode% started at +'&&, &, &, and e
translated it by +'&, &, '&,, so its ne position is +''&, &, '&, relative to its parent.
0o letLs figure out here these things really are. Start at the root Scene0ode. 7ts position is alays +&, &,
&,. 0o, node'Ls position is +root @ head0ode,$ +&, &, &, @ +%8, &, &, O +%8, &, &,. 0ot surprising. 0o,
head0ode% is a child of node', so its position is +root @ head0ode @ head0ode%,$ +&, &, &, @ +%8, &, &, @
+''&, &, '&, O +'38, &, '&,. This is 2ust an example to explain ho to think about Scene0ode position
inheritance. Bou ill rarely ever need to calculate the absolute position of your nodes.
Lastly, note that you can get both Scene0odes and 1ntities by their name by calling getScene0ode and
get1ntity methods of the Scene/anager, so you donLt have to keep a pointer to every Scene0ode you
create. Bou should hang on to the ones you use often though.
Things to Try
-y no you should have a basic grasp of 1ntities, Scene0odes, and the Scene/anager. 7 suggest starting
ith the code above and adding and removing ?obots from the scene. .nce you have done that, clear all
the contents out of the createScene method, and play ith each of the folloing code segments$
Scale
Bou can scale the mesh by calling the scale method in Scene0ode. Try changing the values in scale and
see hat you get$
%Scene&gr'(setA%.ient0ight(Ogre::-olour1alue(P.2) P.2) P.2))*
Ogre::ntit!" ogre#ead $ %Scene&gr'(createntit!("#ead") "ogrehead.%esh")*
Ogre::Scene+ode" head+ode $ %Scene&gr'(get,ootScene+ode()'
(create-hildScene+ode("#ead+ode")*
head+ode'(attachO./ect(ogre#ead)*
head+ode'(scale( .3) P) 5 )*
Ogre::ntit!" ogre#ead5 $ %Scene&gr'(createntit!( "#ead5") "ogrehead.%esh" )*
Ogre::Scene+ode" head+ode5 $ %Scene&gr'(get,ootScene+ode()'(create-hildScene+ode(
"#ead+ode5") Ogre::1ector=( P22) 2) 2 ) )*
head+ode5'(attachO./ect( ogre#ead5 )*
head+ode5'(scale( P) 5) P )*
-otations
Bou can rotate the ob2ect by using the ya, pitch, and roll methods using either "egree or ?adian ob2ects.
!itch is rotation around the x axis, ya is around the y axis, and roll is around the C axis. 6sing your right
hand as a guide$ point your thumb in the direction of an axis, curl your remaining fingers. The direction of
the curl matches the positive rotation around that axis$

Try changing the "egree amount and combining multiple transforms$
%Scene&gr'(setA%.ient0ight(Ogre::-olour1alue(P.2) P.2) P.2))*
Ogre::ntit!" ogre#ead $ %Scene&gr'(createntit!("#ead") "ogrehead.%esh")*
Ogre::Scene+ode" head+ode $ %Scene&gr'(get,ootScene+ode()'
(create-hildScene+ode("#ead+ode")*
head+ode'(attachO./ect(ogre#ead)*
head+ode'(!a?( >egree( 'Q2 ) )*
Ogre::ntit!" ogre#ead5 $ %Scene&gr'(createntit!( "#ead5") "ogrehead.%esh" )*
Ogre::Scene+ode" head+ode5 $ %Scene&gr'(get,ootScene+ode()'(create-hildScene+ode(
"#ead+ode5") Ogre::1ector=( P22) 2) 2 ) )*
head+ode5'(attachO./ect( ogre#ead5 )*
head+ode5'(pitch( >egree( 'Q2 ) )*
Ogre::ntit!" ogre#ead= $ %Scene&gr'(createntit!( "#ead=") "ogrehead.%esh" )*
Ogre::Scene+ode" head+ode= $ %Scene&gr'(get,ootScene+ode()'(create-hildScene+ode(
"#ead+ode=") Ogre::1ector=( 522) 2) 2 ) )*
head+ode='(attachO./ect( ogre#ead= )*
head+ode='(roll( >egree( 'Q2 ) )*
The Ogre En(ironment
/ost of the files +."LL and .C4;, referred to in this section +and throughout the tutorials, can be found in
the .greS"F DbinD folder under either debug or release. "ebug programs hich you create should use
the files in the debug .greS"F folder, and release programs should use the files in the release folder.
0ote that a lot of this section discusses <indos specific monikers. 6nder a Linux the same information
basically applies, but the shared libraries end in .so and reside in another location, and some things may
be slightly different. 7f you have problems, be sure to post your 9uestion to the .gre help forums.
+,,s and lugins
0o that e have played ith the .gre environment a bit, 7Ld like to explain ho the .gre library orks
in general to make your life easier hen orking ith it.
.gre is divided into 3 large shared library groups$ The main library, the plugins, and the third-party
libraries.
Main library.
The first group consists of the library itself and the shared libraries it relies on. The .gre library is
contained, in its entirety in .gre/ain.dll. This dll re9uires a fe other libraries such as cg.dll. These
"LLs must be included ith every .gre application ithout exception.
lugins.
The second group of shared libraries are the plugins. .gre pushes a good portion of functionality out into
shared libraries so that they may be turned on or off depending on the needs of your application. The
basic plugins included ith .gre have filenames hich start ith the D!luginPD prefix. Bou can create
ne plugins yourself if your application needs them, but e ill not be covering this in any tutorial. .gre
also uses plugins for the render systems +such as .pen;L, "irectQ, etc,. These plugins start ith the
D?enderSystemPD prefix. These plugins exist so that you can add or remove render systems from your
application. This can be especially useful if you rite shaders or something hich is specific to +for
example, .pen;L and you need turn off the ability to run the program in "irectQ, you can simply
remove the appropriate ?enderSystem plugin and it ill be unavailable. Additionally if you are targeting
a non-standard platform, you can rite your on ?enderSystem plugin, though this ill not be covered in
the tutorial. <e ill cover ho to remove plugins in the next section.
Third 'arty libraries and hel'er libraries.
The third group of shared libraries are the third party libraries and helper libraries. .gre itself is just a
graphics rendering library. 7t does not include things such as ;67 systems, input control, physics engines,
and so on. Bou ill have to use other libraries to do these things. The .gre demos and S"F includes a
fe of these third party helper libraries. The C1;67 library is a ;67 system that integrates easily into
.gre, and the "LLs that begin ith DC1;67ED and the D.gre;67?enderer.dllD are part of this. 6sing
C1;67 ill be covered in a later tutorial. Feyboard and mouse input is accomplished through .7S +an
input system,. This is contained in .7S.dll. There are also other libraries +not included ith the S"F,
hich give more functionality +such as sound and physics, hich you can find more information about in
other places such as on the <iki and in the forums.
The moral of the story is that hen you are testing your application locally, you can leave everything
Dturned onD +that is, donLt remove anything, to test ith. <hen you are ready to distribute your
application, you ill need to build it in ?elease mode, and include all of the release "LLs that your
application uses, and you should remove the "LLs that you do not use. 7f your program doesnLt use
C1;67 but does use .7S, then you shouldnLt bother including the C1;67 "LLs, but you must include
the .7S dll or your application ill not run.
%on"iguration *iles
.gre runs off of several configuration files. They control hich plugins are loaded, here the
applicationLs resources are located, and so on. <e ill briefly look at each of the configuration files and
hat they do. 7f you have more specific 9uestions, you should direct them to the .gre help forums.
'lugins.c"g This file contains hich plugins your application uses. 7f you ant to add or remove a plugin
in application, you ill need to modify this file. To remove a plugin, simply remove the appropriate line,
or comment it out by putting a R at the beginning of the line. To add a plugin, you ill need to add a line
like D!luginOG!lugin0ameHD. 0ote that you do not put ."LL at the end of the plugin name. Bour plugin
also does not have to start ith D?enderSystemPD or D!luginPD. Bou can also define the location that .gre
looks for plugins by changing the D!lugin4olderD variable. Bou can use both absolute and relative paths,
but you cannot use environment variables like K+SomeAariable,.
resources.c"g This file contains a list of directories hich .gre should scan to look for resources.
?esources include scripts, meshes, textures, and so on. Bou can use both absolute and relative paths, but
you cannot use environment variables like K+SomeAariable,. 0ote that .gre ill not scan subfolders, so
you must manually enter them if you have multiple levels. 4or example, if you have a directory tree like
DresImeshesD and DresImeshesIsmallD, you ill have to add to entries to the resources file containing
both of these paths.
media.c"g This file tells .gre more detailed information about some of the resources. 7t is unlikely that
you ill need to modify this file at this time, so 7 ill skip over the details. /ore information can be
found in the /anual and in the .gre forums.
ogre.c"g This file is generated by .greLs configuration screen. This file ill be specific to your individual
computer and graphics setup. Bou should not distribute this file to other people hen you share your
application, as they are likely to have different settings than you do. 0ote you should not edit this file
directly, instead use the configuration screen.
!ua1e3settings.c"g This file is used ith the -S!Scene/anager. Bou ill not need this file unless you
are using this scene manager +hich you are not using at this point,, so ignore it. Bou should not
distribute this file ith your application unless, again, you are using the -S!Scene/anager, and even
then it ill likely be completely different depending on the needs of your program.
These are all of the configuration files that .gre manipulates directly. .gre must be able to find
Dplugins.cfgD, Dresources.cfgD, and Dmedia.cfgD to run properly. 7n a later tutorial e ill cover more
about these files and ho to change their location and manipulate them to do more advanced things.
A Better 0ay to Test 2our A''lication
Note this section is Windows and Visual C++ specific.
As mentioned in many places +including the Troubleshooting section above,, .gre must be able to find
the configuration files, "LLs, and media resources that your program uses. /ost people solve this by
manually copying the bin folder from the .greS"F into their pro2ectLs directory to put the correct "LLs
in the same folder as the executable file. This is probably the best thing to do if you are creating a game or
application hich ill be distributed to many people because you ill undoubtedly change the
configuration files and add(remove plugins from the norm. 7n many other situations though, copying all
the "LLs over to each .gre pro2ect you create ill aste space and a lot of time. #ere are a fe things
you can do instead.
.ne alternative is to copy the .greS"F "LL files +minus the plugins, over to the c$I<indosISystem
folder. This has the advantage that no matter here your executable files are, <indos ill alays be
able to find the appropriate "LL. To make this ork, modify the resources.cfg and plugins.cfg to contain
absolute paths to the media folder and plugins respectively. 0o, henever you create a pro2ect, you
simply have to copy the modified configuration files over to your binIdebug and binIrelease directories. 7
personally do not use this approach since itLs possible to lose track of hich .greS"F "LLs are in your
<indos directory. .gre releases ne versions often, so actually updating your install ith this method
could become 9uite a hassle.
A better alternative is to leave all .greS"F files here they are and set the orking directory of every
.gre application you create to be .greS"FLs binIrelease or binIdebug directory. To do this, go to your
pro2ectLs properties and change the D<orking "irectoryD field +in the "ebugging options, to be
DC$I.greS"FIbinIK+Configuration0ame,D. Bou may need to change DC$I.greS"FD to herever you
installed .gre= then, no files ill need to be copied to make your .gre programs ork. This is the
approach 7 personally use on my .gre pro2ects. The only draback is that if you need to make
modifications to the configuration files, you ill be modifying them for every .gre pro2ect, hich is
obviously bad. 7f you use this approach and need to modify the configuration files for your pro2ect, copy
all of the files into your pro2ect as you normally ould instead, then change the <orking "irectory back
to hat it originally as.
%onclusion
-y this point you should have a very basic grasp of the Scene/anager, Scene0ode, and 1ntity classes.
Bou do not have to be familiar ith all of the functions that 7 have introduced. Since these are the most
basic ob2ects, e ill be using them very often. Bou ill get more familiar ith them after orking
through the next fe tutorials.
Bou should also be familiar ith setting up a orking .gre environment for your pro2ects.
!roceed to -asic Tutorial % Cameras, Lights, and Shadows
Basic Tutorial 4 :
%ameras, ,ights, and Shado&s
Any problems you encounter hile orking ith this tutorial should be posted to the #elp 4orum .
rere!uisites
This tutorial assumes you have knoledge of C@@ programming and are able to setup and compile an
.gre application +if you have trouble setting up your application, see this guide for specific compiler
setups,. This tutorial builds on the first tutorial, and it assumes you have already orked through it.
$ntroduction
7n this tutorial 7 ill be introducing you to a fe more .gre constructs, as ell as expanding on hat you
have already learned. This tutorial ill deal mainly ith Light ob2ects and ho they are used to create
shados in .gre. <e ill also cover the absolute basics about Cameras.
As you go through the tutorial you should be sloly adding code to your on pro2ect and atching the
results as e build it. Bou can see the source code for the final state of this tutorial here. 7f you have
trouble ith the code, you should compare your pro2ectLs source to the final product.
Table o" contents
!rere9uisites
7ntroduction
;etting Started
Cameras
.gre Cameras
Creating a Camera
Aieports
.gre Aieports
Creating the Aieport
Lights and Shados
Shado Types that .gre Supports
6sing Shados in .gre
Troubleshooting
Types of Lights
Creating the Lights
Things to Try
"ifferent Shado Types
Light Attenuation
Scene/anager$$setAmbientLight
Aieport -ackground Colour
Camera$$set4arClip"istance
!lanes
4ull Source
#etting Started
As ith the last tutorial, e ill be using a pre-constructed code base as our starting point. <e ill add
to more methods to our TutorialApplication class$ createAieport and createCamera. These to
functions ere already defined in the base 1xampleApplication, but in this tutorial e ill no look at
them to see ho Cameras and Aieports are actually created and used.
Create a pro2ect in the compiler of your choice for this pro2ect, and add a source file hich contains this
code$
#include "@a%pleApplication.h"
class TutorialApplication : pu.lic @a%pleApplication
{
protected:
pu.lic:
TutorialApplication()
{
}
~TutorialApplication()
{
}
protected:
virtual void create-a%era(void)
{
}
virtual void create1ie?ports(void)
{
}
void createScene(void)
{
ntit! "ent*
0ight "light*
}
}*
#i7 O8,940AT:O,& $$ 40AT:O,&9;<+=5 GG O8,940AT:O,& $$ O8,940AT:O,&9;<+=5
#de7ine ;<+=590A+9A+>9&A+
#include "?indo?s.h"
<+T ;<+A4< ;in&ain( #<+STA+- h<nst) #<+STA+-) 04ST, str-%d0ine) <+T )
#else
int %ain(int argc) char ""argv)
#endi7
{
// Create application object
TutorialApplication app*
tr! {
app.go()*
} catch( @ceptionC e ) {
#i7 O8,940AT:O,& $$ 40AT:O,&9;<+=5 GG O8,940AT:O,& $$ O8,940AT:O,&9;<+=5
&essageBo@( +D00) e.get:ull>escription().c9str()) "An e@ception has
occurredE") &B9OF G &B9<-O+,,O, G &B9TASF&O>A0)*
#else
7print7(stderr) "An e@ception has occurred: RsSn")
e.get:ull>escription().c9str())*
#endi7
}
return 2*
}
7f you are using the .greS"F under <indos, be sure to add the
D.greS"FP"7?1CT.?BIsamplesIincludeD directory to this pro2ect +the 1xampleApplication.h file is
located there, in addition to the standard include. 7f youLre using the .gre source distribution, this should
be located in the D.greSourceP"7?1CT.?BISamplesICommonIincludeD directory. -e sure you can
compile this code before continuing to the next section +though do not try to run it as it &ill crash until
&e add more to it,. <e ill be adding code later to make this ork. 7f you have problems, check this
<iki page for information about setting up your compiler, and if you still have problems try the #elp
4orum.
%ameras
Ogre %ameras
A Camera is hat e use to vie the scene that e have created. A Camera is a special ob2ect hich
orks somehat like a Scene0ode does. The Camera ob2ect has set!osition, ya,roll and pitch functions,
and you can attach it to any Scene0ode. Sust like Scene0odes, a CameraLs position is relative to its
parents +itLs nice to respect oneLs elders,. 4or all movement and rotation, you can basically consider a
Camera a Scene0ode.
.ne thing about .gre Cameras that is different from hat you may expect is that you should only be
using one Camera at a time +for no,. That is, e do not create a Camera for vieing one portion of a
scene, a second camera for vieing another portion of the scene and then enabling or disabling cameras
based on hat portion of the scene e ant to display. 7nstead the ay to accomplish this is to create
Scene0odes hich act as Dcamera holdersD. These Scene0odes simply sit in the scene and point at hat
the Camera might ant to look at. <hen it is time to display a portion of the Scene, the Camera simply
attaches itself to the appropriate Scene0ode. <e ill revisit this techni9ue in the 4rameListener tutorial.
%reating a %amera
<e ill be replacing the default method that 1xampleApplication uses to create the Camera.
4ind the TutorialApplication$$createCamera member function. The first thing e are going to do is create
the Camera. Since Cameras are tied to the Scene/anager hich they reside in, e use the Scene/anager
ob2ect to create them. Add this line of code to create the Camera$
// create the camera
%-a%era $ %Scene&gr'(create-a%era("4la!er-a%")*
This creates a Camera ith the name D!layerCamD. 0ote that you can use the getCamera function of
Scene/anager to get Cameras based on their name if you decide not to hold a pointer to it.
The next thing e are going to do is set the position of the Camera and the ay that itLs facing. <e ill be
placing ob2ects around the origin, so eLll put the Camera a good distance in the @C direction and have the
Camera face the origin. Add this code after the previous bit$
// set its position, direction
%-a%era'(set4osition(1ector=(2)P2)322))*
%-a%era'(looNAt(1ector=(2)2)2))*
The lookAt function is pretty nifty. Bou can have the Camera face any position you ant to instead of
having to ya, rotate, and pitch your ay there. Scene0odes have this function as ell, hich can make
setting 1ntities facing the right direction much easier in many cases.
4inally e ill set a near clipping distance of 8 units. The clipping distance of a Camera specifies ho
close or far something can be before you no longer see it. Setting the near clipping distance makes it
easier to see through 1ntities on the screen hen you are very close to them. The alternative is being so
close to an ob2ect that it fills the screen and you canLt see anything but a tiny portion of it. Bou can also
set the far clipping distance as ell. This ill stop the engine from rendering anything farther aay than
the given value. This is primarily used to increase the framerate if you are rendering large amounts of
things on the screen for very long distances. To set the near clipping distance, add this line$
%-a%era'(set+ear-lip>istance(3)*
Setting the far clipping distance ould simply be a similar call to set4arClip"istance +though you should
not use a far clip distance ith Stencil Shados, hich e ill be using in this tutorial,.
.ie&'orts
Ogre .ie&'orts
<hen you start dealing ith multiple Cameras, the concept of a Aieport class ill become much more
useful to you. 7 bring up the topic no because 7 think it is important for you to understand ho .gre
decides hich Camera to use hen rendering a scene. 7t is possible in .gre to have multiple
Scene/anagers running at the same time. 7t is also possible to split the screen up into multiple areas, and
have separate cameras render to separate areas on the screen +think of a split vie for % players in a
console game, for example,. <hile it is possible to do these things, e ill not cover ho to do them
until the advanced tutorials.
To understand ho .gre renders a scene, consider three of .greLs constructs$ the Camera, the
Scene/anager, and the ?ender<indo. The ?ender<indo e have not covered, but it is basically the
indo in hich everything is displayed. The Scene/anager ob2ect creates Cameras to vie the scene.
Bou must tell the ?ender<indo hich Cameras to display on the screen, and hat portion of the
indo to render it in. The area in hich you tell the ?ender<indo to display the Camera is your
Aieport. 6nder most typical uses of .gre, you ill generally create only one Camera, register the
Camera to use the entire ?ender<indo, and thus only have one Aieport ob2ect.
7n this tutorial e ill go over ho to register the Camera to create the Aieport. <e can then use this
Aieport ob2ect to set the background color of the scene e are rendering.
%reating the .ie&'ort
<e ill be overriding the 1xampleApplicationLs creation of the Aieport, so find the
TutorialApplication$$createAieports member function. To create the Aieport e simply call the
addAieport function of ?ender<indo and supply it ith the Camera e are using. The
1xampleApplication class has already populated the m<indo class ith our ?ender<indo, so add
this line of code$
// Create one viewport, entire window
1ie?port" vp $ %;indo?'(add1ie?port(%-a%era)*
0o that e have our Aieport, hat can e do ith itM The anser is$ not much. The most important
thing e can do ith it is to call the set-ackgroundColour function to set the background to hatever
color e choose. Since e are dealing ith lighting in this tutorial e ill set the color to black$
vp'(setBacNground-olour(-olour1alue(2)2)2))*
0ote that ColourAalue expects a red, green, and blue color value for its parameters beteen the values of
& and '. The last, and most important thing e need to do is to set the aspect ratio of our Camera. 7f you
are using something other than the standard full-indo vieport, then failing to set this can result in a
very strange looking scene. <e ill go ahead and set it even though e are using the default aspect ratio$
// Alter the camera aspect ratio to match the viewport
%-a%era'(setAspect,atio(,eal(vp'(getActual;idth()) M ,eal(vp'
(getActual#eight()))*
ThatLs all that has to be done for our simple use of the Aieport class.
At this point you should be able to compile and run the application, though nothing ill appear but a
blank scene +use the 1scape key to exit,. -e sure you can run the application ithout it crashing before
continuing.
,ights and Shado&s
Shado& Ty'es that Ogre Su''orts
.gre currently supports three types of Shados$

'. /odulative Texture Shados +S#A".<TB!1PT1QT6?1P/."6LAT7A1, - The least
computationally expensive of the three. This creates a black and hite render-to-texture of shado
casters, hich is then applied to the scene.
%. /odulative Stencil Shados +S#A".<TB!1PST10C7LP/."6LAT7A1, - This techni9ue
renders all shado volumes as a modulation after all non-transparent ob2ects have been rendered
to the scene. This is not as intensive as Additive Stencil Shados, but it is also not as accurate.
3. Additive Stencil Shados +S#A".<TB!1PST10C7LPA""7T7A1, - This techni9ue renders
each light as a separate additive pass on the scene. This is very hard on the graphics card because
each additional light re9uires an additional pass at rendering the scene.
.gre does not support soft shados as part of the engine. 7f you ant soft shados you ill need to rite
your on vertex and fragment programs. 0ote that this is 2ust a 9uick introduction here - the .gre manual
fully describes shados in .gre and the implications of using them.
5sing Shado&s in Ogre
6sing shados in .gre is relatively simple. The Scene/anager class has a setShadoTechni9ue member
function that e can use to set the type of Shados e ant. Then henever you create an 1ntity, call the
setCastShados function to set hether or not it casts shados.
<e ill no set the ambient light to complete darkness, and set the shado type. 4ind the
TutorialApplication$$createScene member function and add this code to it$
%Scene&gr'(setA%.ient0ight(-olour1alue(2) 2) 2))*
%Scene&gr'(setShado?TechniLue(S#A>O;TT49ST+-<09A>><T<1)*
0o the Scene/anager uses additive stencil shados. LetLs create an ob2ect on the scene and make it cast
shados.
ent $ %Scene&gr'(createntit!("+in/a") "nin/a.%esh")*
ent'(set-astShado?s(true)*
%Scene&gr'(get,ootScene+ode()'(create-hildScene+ode()'(attachO./ect(ent)*
Again, the nin2a.mesh has been preloaded for us by the 1xampleApplication. <e also need something for
the 0in2a to stand on +so that he has something to cast shados onto,. To do this e ill create a simple
plane. This is not meant to be a tutorial on using /esh/anager, but e ill go over the very basics since
e have to use it to create a plane. 4irst e need to define the !lane ob2ect itself, hich is done by
supplying a normal and the distance from the origin. <e could +for example, use planes to make up parts
of orld geometry, in hich case e ould need to specify something other than & for our origin
distance. 4or no e 2ust ant a plane to have the positive y axis as its normal +that means e ant it to
face up,, and no distance from the origin$
4lane plane(1ector=::D+<T9T) 2)*
0o e need to register the plane so that e can use it in our application. The /esh/anager class keeps
track of all the meshes e have loaded into our application +for example, this keeps track of the
robot.mesh and the nin2a.mesh that e have been using,. The create!lane member function takes in a
!lane definition and makes a mesh from the parameters. This registers our plane for use$
&esh&anager::getSingleton().create4lane("ground")
,esource8roup&anager::>:AD0T9,SOD,-98,OD49+A&) plane)
P322)P322)52)52)true)P)3)3)1ector=::D+<T9U)*
Again, 7 do not ish to go into the specifics of ho to use the /esh/anager 2ust yet +consult the A!7
reference if you ant to see exactly hat each parameter is doing,. -asically e have registered our plane
to be '8&& by '8&& in siCe and ne mesh is called DgroundD. 0o, e can create an 1ntity from this mesh
and place it on the scene$
ent $ %Scene&gr'(createntit!("8roundntit!") "ground")*
%Scene&gr'(get,ootScene+ode()'(create-hildScene+ode()'(attachO./ect(ent)*
0eat huhM There are to more things e need to do ith our ground before e are finished ith it. The
first is to tell the Scene/anager that e donLt ant it to cast shados since it is hatLs being used for
shados to pro2ect on. The second thing is e need to put a texture on it. .ur robot and nin2a meshes
already have material scripts defined for them. <hen e manually created our ground mesh, e did not
specify hat texture to use on it. <e ill use the D1xamples(?ockallD material script that .gre includes
ith its samples$
ent'(set&aterial+a%e("@a%plesM,ocN?all")*
ent'(set-astShado?s(7alse)*
0o that e have a 0in2a and ground in the scene, letLs compile and run the program. <e see... nothing>
<hatLs going onM 7n the previous tutorial e added ?obots and they displayed fine. The reason the 0in2a
doesnLt sho up is because the sceneLs ambient light has been set to total darkness. So letLs add a light to
see hat is going on.
Troubleshooting
Some people have reported a problem ith ;CC and Code$$-locks they have had in this section. 7f you
receive an error similar to this$
varia.le Kvta.le 7or Ogre::&esh4trK canKt .e auto'i%ported. 4lease read the
docu%entation 7or ldKs ''ena.le'auto'i%port 7or details.
BouLll need to add the folloing to your linker options$
';l)''ena.le'runti%e'pseudo'reloc
7f using Code-locks$$7"1 right click on pro2ect name-Tbuild options-Tlinker options and set this option
there.
Stencil shado&s and !uery "lags
<hen using stencil shados, .gre finds the shado casters by making a scene 9uery. 1ntity +and static
geometry, 9uery flags are used for this, so if you have set 9uery flags for an ob2ect to & using
setNuery4lags+,, the ob2ect ill not ork for stencil shados.
Ty'es o" ,ights
There are three types of lighting that .gre provides.
'. !oint +LTP!.70T, - !oint light sources emit light from them in every direction.
%. Spotlight +LTPS!.TL7;#T, - A spotlight orks exactly like a flashlight does. Bou have a
position here the light starts, and then light heads out in a direction. Bou can also tell the light
ho large of an angle to use for the inner circle of light and the outer circle of light +you kno
ho flashlights are brighter in the center, then lighter after a certain pointM,.
3. "irectional +LTP"7?1CT7.0AL, - "irectional light simulates far-aay light that hits everything
in the scene from a direction. LetLs say you have a night time scene and you ant to simulate
moonlight. Bou could do this by setting the ambient light for the scene, but thatLs not exactly
realistic since the moon does not light everything e9ually +neither does the sun,. .ne ay to do
this ould be to set a directional light and point in the direction the moon ould be shining.
Lights have a ide range of properties that describes ho the light looks. To of the most important
properties of a light are its diffuse and specular color. 1ach material script defines ho much diffuse and
specular lighting the material reflects, hich e ill learn ho to control in a later tutorial.
%reating the ,ights
To create a Light in .gre e call Scene/anagerLs createLight member function and supply the lightLs
name, very much like ho e create an 1ntity or Camera. After e create a Light, e can either set the
position of it manually or attach it to a Scene0ode for movement. 6nlike the Camera ob2ect, light only
has set!osition and set"irection +and not the full suite of movement functions like translate, pitch, ya,
roll, etc,. So if you need to create a stationary light, you should call the set!osition member function. 7f
you need the light to move +such as creating a light that follos a character,, then you should attach it to a
Scene0ode instead.
So, letLs start ith a basic point Light. The first thing e ill do is create the light, set its type, and set its
position$
light $ %Scene&gr'(create0ight("0ightP")*
light'(setT!pe(0ight::0T94O<+T)*
light'(set4osition(1ector=(2) P32) 532))*
0o that e have created the light, e can set its diffuse and specular color. LetLs make it red$
light'(set>i77use-olour(P.2) 2.2) 2.2)*
light'(setSpecular-olour(P.2) 2.2) 2.2)*
0o compile and run the application. Success> <e can no see the 0in2a and he casts a shado. -e sure
to also look at him from the front, a complete silhouette. .ne thing to notice is that you do not DseeD the
light source. Bou see the light it generates but not the actual light ob2ect itself. /any of .greLs tutorials
add a simple entity to sho here the light is being emitted from. 7f you are having trouble ith lights in
your application you should consider creating something similar to hat they do so you can see exactly
here your light is.
0ext, letLs try out directional light. 0otice ho the front of the nin2a is pitch blackM LetLs add a small
amount of yello directional light that is shining toards the front of his body. <e create the light and set
the color 2ust like e do for a point light$
light $ %Scene&gr'(create0ight("0ight=")*
light'(setT!pe(0ight::0T9><,-T<O+A0)*
light'(set>i77use-olour(-olour1alue(.53) .53) 2))*
light'(setSpecular-olour(-olour1alue(.53) .53) 2))*
Since directional light is supposed to come from a far-off distance, e do not have to set its position, only
its direction. <eLll set the direction of the light to be in the positive C and negative y direction +like it is
coming from 58 degrees in front and above the nin2a,$
light'(set>irection(1ector=( 2) 'P) P ))*
Compile and run the application. <e no have to shados on the screen, though since the directional
light is so faint, the shado is also faint. The last type of light e are going to play ith is the spotlight.
<e ill no create a blue spotlight$
light $ %Scene&gr'(create0ight("0ight5")*
light'(setT!pe(0ight::0T9S4OT0<8#T)*
light'(set>i77use-olour(2) 2) P.2)*
light'(setSpecular-olour(2) 2) P.2)*
<e also need to set both the position and the direction that the spotlight shines in. <e ill create a
spotlight that hovers above the 0in2aLs right shoulder, and shines don directly on him$
light'(set>irection('P) 'P) 2)*
light'(set4osition(1ector=(=22) =22) 2))*
Spotlights also allo us to specify ho ide the beam of the light is. 7magine a flashlight beam for a
second. There is a core beam in the center that is brighter than the surrounding light. <e can set the idth
of both of these beams by calling the setSpotlight?ange member function$
light'(setSpotlight,ange(>egree(=3)) >egree(32))*
Compile and run the application. !urple 0in2a...dangerous>
Things to Try
+i""erent Shado& Ty'es
7n this demo e only set the shado type to be S#A".<TB!1PST10C7LPA""7T7A1. Try setting it to
the other to types of shados and see hat happens. There are also many other shado-related
functions in the Scene/anager class. Try playing ith some of them and seeing hat you come up ith.
,ight Attenuation
Lights define a setAttenuation function hich allos you to control ho the light dissipates as you get
farther aay from it. Add a function call to the !oint light that sets the attenuation to different values.
#o does this affect the lightM
SceneManager::setAmbient,ight
1xperiment ith the setAmbientLight function of mScene/gr.
.ie&'ort Bac1ground %olour
Change the default ColourAalue in the createAieports function. <hile it is not really appropriate to
change it to something other than black in this situation, it is a good thing to kno ho to change.
%amera::set*ar%li'+istance
7n createCamera e set the near clip distance. Add a function call to set4arClip"istance and set it to be
8&&, atch hat happens hen you move from seeing the 0in2a and not seeing the 0in2a ith stencil
shados turned on. 0otice the sloupM
0ote$ BouLll need to set mScene/gr-TsetShado6se7nfinite4ar!lane+false,, for this to ork, and you
might get some strange shados. +See this thread,
lanes
<e did not cover much about !lanes in this tutorial +it as not the focus of this article,. <e ill go back
and revisit this topic in a later tutorial, but for no you should look up the create!lane function and try
playing ith some of the inputs to the function.
*ull Source
7f you are having difficulty building this tutorial, take a look at the source code for it and compare it to
your pro2ect.
!roceed to -asic Tutorial 3 Terrain, Sy, and !og
Basic Tutorial 3 :
Terrain, S1y, and *og
Any problems you encounter hile orking ith this tutorial should be posted to the #elp 4orum .
rere!uisites
This tutorial assumes you have knoledge of C@@ programming and are able to setup and compile an
.gre application +if you have trouble setting up your application, see this guide for specific compiler
setups,. This tutorial builds on the previous beginner tutorials, and it assumes you have already orked
through them.
$ntroduction
7n this tutorial e ill be exploring ho to manipulate terrain, sky, and fog in your .gre applications.
After this tutorial you should understand the differences beteen Skyboxes, Skyplanes, and Skydomes,
and be able to use them. Bou ill also kno the difference beteen the different types of fog, and ho to
use them.
As you go through the tutorial you should be sloly adding code to your on pro2ect and atching the
results as e build it. Bou can see the source code for the final state of this tutorial here. 7f you have
trouble ith the code, you should compare your pro2ectLs source to this.
Table o" contents
!rere9uisites
7ntroduction
;etting Started
The ?oot .b2ect and Scene/anager Creation
?oot
Scene/anager Creation
Terrain
Adding Terrain to the Scene
The terrain.cfg 4ile
Lighting Terrain
Sky
Sky-oxes
Sky"omes
Sky!lanes
<hich to 6seM
4og
4og 7ntroduction
Types of 4og
4og and Sky
4og as "arkness
#etting Started
As ith the previous tutorials, e ill be using a pre-constructed code base as our starting point. Create a
pro2ect in the compiler of your choice for this pro2ect, and add a source file hich contains this code$
#include "@a%pleApplication.h"
class TutorialApplication : pu.lic @a%pleApplication
{
protected:
pu.lic:
TutorialApplication()
{
}
~TutorialApplication()
{
}
protected:
void chooseScene&anager(void)
{
}
void createScene(void)
{
}
}*
#i7 O8,940AT:O,& $$ 40AT:O,&9;<+=5 GG O8,940AT:O,& $$ O8,940AT:O,&9;<+=5
#de7ine ;<+=590A+9A+>9&A+
#include "?indo?s.h"
<+T ;<+A4< ;in&ain(#<+STA+- h<nst) #<+STA+-) 04ST, str-%d0ine) <+T)
#else
int %ain(int argc) char ""argv)
#endi7
{
// Create application object
TutorialApplication app*
tr! {
app.go()*
} catch(@ceptionC e) {
#i7 O8,940AT:O,& $$ 40AT:O,&9;<+=5 GG O8,940AT:O,& $$ O8,940AT:O,&9;<+=5
&essageBo@(+D00) e.get:ull>escription().c9str()) "An e@ception has
occurredE") &B9OF G &B9<-O+,,O, G &B9TASF&O>A0)*
#else
7print7(stderr) "An e@ception has occurred: RsSn")
e.get:ull>escription().c9str())*
#endi7
}
return 2*
}
7f you are using the .greS"F under <indos, be sure to add the
D.greS"FP"7?1CT.?BIsamplesIincludeD directory to this pro2ect +the 1xampleApplication.h file is
located there, in addition to the standard include. 7f using the .gre source distribution, this should be
located in the D.greSourceP"7?1CT.?BISamplesICommonIincludeD directory. -e sure you can
compile this code before continuing to the next section, though do not attem't to run the 'rogram until
&e ha(e "illed in more o" the code. 7f you have problems compiling, check this <iki page for
information about setting up your compiler, and if you still have problems try the #elp 4orum.
!rogram controls$ 6se the <AS" keys to move, and the mouse to look around. The 1scape key exits the
program.
The -oot Object and SceneManager %reation
-oot
7n this demo e ill be rendering Terrain in .gre. To do this e need to set the Scene/anager to the
TerrainScene/anager instead of the default one that the 1xampleApplication sets up for us. 4ind the
chooseScene/anager function, and add the folloing code$
%Scene&gr $ %,oot'(createScene&anager(ST9VT,<O,9-0OS)*
The ?oot ob2ect +m?oot is an instance of ?oot, is the DcoreD .gre ob2ect. Bou can see a 6/L diagram of
the relationships beteen .gre ob2ects here. Bou have no seen almost all of these ob2ects in practice,
ith the exception of the ?enderSystem. 7n this chunk of code, e are telling the ?oot node that e ant
a Scene/anager of the STP1QT1?7.?PCL.S1 type. The ?oot ob2ect then 9ueries the
Scene/anager1numerator to find the Scene/anager of the type you re9uested and returns it.
After your application is set up, you rarely ever have to deal ith .greLs ?oot ob2ect, and you donLt ever
interact ith the Scene/anager1numerator directly.
SceneManager %reation
7 ould like to go ahead and talk to you about Scene/anager creation and storage to save you the
confusion in the future. Scene/anagers are not Singletons. Bou can create as many of them as you ant,
and unlike Scene0odes(Lights(etc., you can create them directly ith a Dne Scene/anager+,D statement
+you do not have to use ?ootLs createScene/anager method, but you really should,. Bou can have
multiple Scene/anagers populated ith multiple separate geometries and entities at the same time. Bou
can sap beteen any of these at any time by recreating the Aieport +this is covered in 7ntermediate
Tutorial 5, or display multiple Scene/anagers at the same time using multiple Aieports.
<hy do e use the createScene/anager function instead of creating our Scene/anager ob2ect manuallyM
<ell, the plugin system in .gre gives us a great deal of flexibility hen orking ith single
Scene/anagers. There are only a fe scene types defined in the SceneType enum. 6ntil no, the
1xampleApplication has been choosing STP;101?7C as our Scene/anager. Bou might think that this is
the base Scene/anager class, but as long as you did not fiddle ith the plugins.cfg file, then thatLs not
hat you have been using> The .ctreeScene/anager registers itself as STP;101?7C and overrides the
base Scene/anager class if you are using the .ctreeScene/anager plugin. The .ctreeScene/anager
uses a system of culling ob2ects that are not visible and thus itLs generally faster than the regular
Scene/anager. 7f you removed the .ctreeScene/anager plugin from your plugins.cfg you ould
pro"a"ly be using the basic Scene/anager hen you re9uest STP;101?7C, or you could possibly be
using something better depending on your plugins. ThatLs the beauty of the system.
Thus far e have only covered the most basic use of the ?oot ob2ect hen creating Scene/anagers. 7n
fact, e can re9uest a Scene/anager from a string instead of using the SceneType enum. .gre uses
flexible Scene/anager factories, hich allo you to define any number of Scene/anager types and
create and destroy them as you need. 4or example, letLs say that e install a plugin hich allos you to
create Scene/anagers called D4ooScene/anagerD. <e ould create one of these by calling$
// do not add this to the project
%Scene&gr $ %,oot'(createScene&anager(":ooScene&anager")*
This ould create one of these ith a default name. 1ven though 7 ill not do so during these tutorials,
you should alays name your Scene/anagers ith the second parameter to createScene/anager. 4or
example, if e anted to create to Scene/anagers ith to names e could do the folloing$
// do not add this to the project
%Scene&grP $ %,oot'(createScene&anager(":ooScene&anager") "7oo")*
%Scene&gr5 $ %,oot'(createScene&anager(":ooScene&anager") ".ar")*
-y naming our Scene/anagers, e no longer have to keep track of them ith pointers. The ?oot ob2ect
ill do it for us. 7f you later ant to use the DfooD and DbarD Scene/anagers, you can do the folloing$
// do not add this to the project
Scene&anager "7oo $ %,oot'(getScene&anager("7oo")*
Scene&anager ".ar $ %,oot'(getScene&anager(".ar")*
<hen you are completely done ith a Scene/anager, use ?ootLs destroyScene/anager function to get
rid of it and save memory.
Though e ill not cover it in a tutorial, you can also define your on Scene/anager factories by
subclassing the Scene/anager4actory class. This is useful hen you have created your on
Scene/anager +by subclassing it, or if you ant to take a standard Scene/anager and perform a fe
changes to it before passing it off to your application +such as creating Cameras, creating Lights, loading
geometry, and so on,.
Terrain
Adding Terrain to the Scene
0o that e have that cleared up, time to actually create Terrain. The base Scene/anager defines the
set<orld;eometry method, hich subclasses use for most scene creation purposes. <ith the
TerrainScene/anager class, it expects a filename from hich to load a terrain configuration. 4ind the
TutorialA''lication::createScene member function and add this line of code$
%Scene&gr'(set;orld8eo%etr!("terrain.c7g")*
Compile and run your program. 7tLs that easy. Bou might ant to set the Camera to start in a place thatLs
over the terrain if it bothers you that its initial position is under the terrain.
The terrain.c"g *ile
There are many options in the terrain.cfg file, and 7 am only going to cover the most basic for changing
the images used to generate the terrain. A more detailed explanation of the terrain config file can be found
here. .ne ma2or thing to note about the TerrainScene/anager is that it has been designed ith paging
functionality in mind, but it has not been implemented yet. !aging terrain is a system here the terrain is
broken into chunks, and only displayed hen the user ould be able to see it. This allos you define a
huge orld and be able to use it ithout dropping the framerate by a significant amount. There is an .gre
plugin that does this$ !aging Scene /anager.
The TerrainScene/anager uses #eightmaps to generate terrain. Bou can specify the heightmap you ant
to use by setting the D#eightmap.imageD property. Bou can set the texture that is used for the terrain by
setting the <orldTexture property. The terrain scene manager also allos you to specify a
D"etailTextureD property, hich is interlaced ith the <orldTexture to make the terrain look more
realistic. Bou should find each of the images currently specified by terrain.cfg and take a look at them
+they should be in the /edia(materials(textures folder,.
"etails on ho to create heightmaps have been discussed ad nauseum on the forums. Search for
heightmap and you are sure to find something that you are looking for.
,ighting Terrain
<e 2ust spent the entire previous tutorial going over lights and shados, but the bad nes is itLs not easy
to get this to ork in the TerrainScene/anager. 4or no, 2ust kno that itLs much easier to take the detail
texture and add lighting effects to it than it is to get standard lighting orking. <e ill also go over a ay
to do D4ake "arknessD in the 4og section. 7f you are looking to use lighting ith the terrain, you should
look into using the !aging Scene /anager, since it has better support for these features.
S1y
.gre provides three different types of sky$ Sky-oxes, Sky"omes, and Sky!lanes. <e ill take a look at
each of these in detail.
Bou may have to add the folloing line to the chooseScene/anager method to use the 1xample(E
textures.
,esource8roup&anager::getSingleton().initialiseAll,esource8roups()*
S1yBo)es
A Sky-ox is basically a giant cube that surrounds all of the ob2ects in the scene. The best ay to describe
it is to 2ust sho it to you. Add this line of code to createScene$
%Scene&gr'(setSN!Bo@(true) "@a%plesMSpaceSN!Bo@")*
Compile and run the program. 0eat huhM +0ote the Sky-ox is grainy because the actual texture is lo
resolution= a higher resolution Sky-ox ould look much better., There are several useful parameters for
Sky-oxes that e can set hen calling setSky-ox. The first option is hether or not to enable the
Sky-ox. 7f you ant to later disable the Sky-ox simply call LmScene/gr-TsetSky-ox+false, DD,=L. The
second parameter is the material script to use for the Sky-ox.
The third parameter and fourth parameters to setSky-ox are fairly important to understand. The third
parameter sets the distance that the Sky-ox is aay from the Camera, and the fourth parameter sets
hether or not the Sky-ox is dran before the rest of the scene or afterards. So, lets see hat happens
hen you change the distance parameter for the Sky-ox from the default 8&&& units to something very
close$
%Scene&gr'(setSN!Bo@(true) "@a%plesMSpaceSN!Bo@") P2)*
0othing changed> This is because the fourth parameter that controls hether to dra the Sky-ox first or
not is set to true by default. 7f the Sky-ox is dran first, then anything rendered afterards +like our
Terrain, ill be dran on top of it, thus making the Sky-ox alays appear in the background. +0ote that
you shouldnLt set the distance above to be closer than the near clip distance on the Camera or it ill not be
shon>, 7t is not actually desirable to dra the Sky-ox first, because the full thing is rendered. <hen you
dra it last, only the visible portions are dran, hich ill provide a modest speed improvement. So, lets
try setting our Sky-ox to be dran last$
%Scene&gr'(setSN!Bo@(true) "@a%plesMSpaceSN!Bo@") 3222) 7alse)*
Again, this looks 2ust like it did before, but no the parts of the Sky-ox that are not visible onLt be
rendered. There is one thing you have to be careful about hen using this techni9ue though. 7f you set the
Sky-ox to be too close, you could be cutting part of the scene geometry off. 4or example, try this$
%Scene&gr'(setSN!Bo@(true) "@a%plesMSpaceSN!Bo@") P22) 7alse)*
As you can see no, the terrain Dpokes throughD the Sky-ox. "efinitely not hat e ant. 7f you use
Sky-oxes in your application you ill have to decide ho you ant to use them. The speedup you get
from rendering the Sky-ox after the terrain is very modest, and you have to be careful not to obscure
your geometry +unless that is hat you are going for,. ;enerally speaking, leaving everything past the
second parameter as default is a very safe choice.
S1y+omes
Sky"omes are very similar to Sky-oxes, and you use them by calling setSky"ome. A giant cube is
created around the Camera and rendered onto, but the biggest difference is that the texture is Dpro2ectedD
onto the Sky-ox in a spherical manner. Bou are still looking at a cube, but it looks as if the texture is
rapped around the surface of a sphere. The primary draback to this method is that the bottom of the
cube ill be untextured, so you alays need to have some type of terrain that hides the base.
The example texture that .gre provides for Sky"omes ill let you see this clearly. Clear out the
setSky-ox call from createScene and add this code instead$
%Scene&gr'(setSN!>o%e(true) "@a%plesM-loud!SN!") 3) 6)*
<hen you run this, move the Camera to the dead center of the terrain and move the Camera so that itLs
positioned fairly close to the surface of the terrain +this looks the best,. After looking at this, hit the ?
button to sitch to the mesh vie. As you can see, e are still looking at a cube +ithout the base,, but it
looks as if the clouds are rapped around a sphere at the top. +Also note that the movement of the clouds
is a property of the D1xamples(CloudySkyD material, not of Sky"omes in general.,
The first to paramaters of setSky"ome are the same as setSky-ox, and you can turn the Sky"ome off
by calling LmScene/gr-TsetSky"ome+false, DD,=L. The third parameter is the curvature used for the
Sky"ome. The A!7 reference suggests using values beteen % and )8= loer for better distance effect,
but higher values for less distortion and a smoother effect. Try setting the third paramater to % and )8 and
look at the difference. The distance effect that the A!7 reference as referring to can be clearly seen in
these screenshots. This is setting the curvature to %$
http$((.idleengineer.net(images(beginner&3P%.png
This is setting the curvature to )5$
http$((.idleengineer.net(images(beginner&3P)5.png
The fourth parameter is the number of times the texture is tiled, hich you ill need to teak depending
on the siCe of your texture. -e sure to note that this parameter is a ?eal value +floating point, and not an
integer. Bou can tile it '.%35 times, if thatLs hat looks good for your application. The fifth and sixth
parameters are distance and dra4irst, respectively, hich e have already covered in the Sky-ox
section.
S1ylanes
Sky!lanes are very different from Sky-oxes and Sky"omes. 7nstead of a cube to render the sky texture
on, e use 2ust a single plane. +0ote for all of the folloing Sky!lane configurations you need to be
somehere toards the middle of the terrain and close to the ground., Clear out all Sky"ome code from
createScene. The first thing e are going to do is create a plane, and face it donards. The setSky!lane
method that e ill be calling does not have a distance parameter like Sky-ox and Sky"ome. 7nstead
that parameter is set in the d variable of !lane$
4lane plane*
plane.d $ P222*
plane.nor%al $ 1ector=::+8AT<19D+<T9T*
0o that e have the plane defined, e can create the Sky!lane. 0ote that the fourth parameter is the
siCe of the Sky!lane +in this case '8&&x'8&& units, and the fifth parameter is ho many times to tile the
texture$
%Scene&gr'(setSN!4lane(true) plane) "@a%plesMSpaceSN!4lane") P322) W3)*
Compile and run the program. There are to problems ith the Sky!lane this creates here. 4irst of all, the
texture that is used is too lo resolution, and it doesnLt tile ell. That could be fixed by simply creating a
good, high resolution sky texture that tiles ell. #oever, the primary problem ith this techni9ue is that
if you look toards the horiCon, you can see here the Sky!lane ends. 1ven if you had a good texture, it
ould not look good at all if you can see to the horiCon. This basic use of a Sky!lane is really only useful
hen you have high alls +or hills, all around the viepoint. 6sing a Sky!lane in that situation ould be
considerably less graphics-intensive than creating a full Sky-ox(Sky"ome.
4ortunately, that is not all e can do ith a Sky!lane. The sixth parameter to the skyplane is the familiar
Drender4irstD parameter hich e have already covered in the Sky-ox and Sky"ome sections. The
seventh parameter allos you to specify the curvature of the Sky!lane, so that e are no longer using a
plane, but a curved surface instead. <e also have to no set the number of x and y segments used to
create the Sky!lane +initially the Sky!lane as one big s9uare, but if e ant curvature e need to have
the plane made up of smaller s9uares,. The eighth and ninth parameters to the function are the number of
x and y segments, respectively$
%Scene&gr'(setSN!4lane(true) plane) "@a%plesMSpaceSN!4lane") P322) 32) true)
P.37) P32) P32)*
Compile and run the application. 0o our Sky!lane looks much better, though again the tiling could use
some ork. Bou could also use this ith the cloud material instead$
%Scene&gr'(setSN!4lane(true) plane) "@a%plesM-loud!SN!") P322) J2) true) P.37)
P32) P32)*
Compile and run the application. The motion of the clouds and the ay it is tiled seems to make it look
slightly orse than a Sky"ome, especially hen you get near the edge of the Terrain and look out onto
the horiCon.
.ne other note, you can clear the Sky!lane by calling LmScene/gr-TsetSky!lane+false, !lane+,, DD,=L
0hich to 5se6
<hich sky to use depends entirely on your application. 7f you have to see all around you, even in the
negative y direction, then really your only real choice is to use a Sky-ox. 7f you have terrain, or some
kind of floor hich blocks the vie of the negative y direction, then using a Sky"ome seems to give
more realistic results. 4or areas here you cannot see to the horiCon +such as a valley surrounded by
mountains on all sides, or the inner courtyard of a castle,, a Sky!lane ill give you very good looking
results for very little ;!6 costs. The primary reason to use a Sky!lane, as e ill see in the next section,
is because it plays nicely ith fog effects.
These are only suggestions. 4or your application you should experiment and use hatever looks the best.
*og
*og $ntroduction
4og in .gre is very easy to use. There is one caveat that you need to kno about before you try to use fog
in your program. <hen you use the TerrainScene/anager, you must be careful to call the set4og function
before the set<orld;eometry function. +7n other Scene/anagers it generally doesnLt matter,. "epending
on hich is called first, a different vertex program ill be chosen to create the fog and terrain.
-efore e get started, clear out all contents of the createScene function except for the call to
set<orld;eometry.
The most important thing to kno about setting fog is that it doesnLt actually create a fog entity in empty
space as you might imagine you ould. 7nstead, fog is merely a filter applied to hatever ob2ects you are
currently looking at. This has some interesting implications, the most relevant of hich is that hen you
stare off into nothingness +i.e. hen you are not looking at an ob2ect,, you do not see fog. 7n fact, you
only see hatever the vieport background color is. So, in order to have fog look correct, e have to set
the background to hatever the fog color currently is.
There are to basic types of fog$ linear and exponential. Linear fog gets thicker in a linear fashion, hile
exponential fog gets thicker exponentially +every distance unit the fog thickness increases by more than it
did the previous distance unit,. 7tLs easier to see the difference than to explain it, so on to the examples.
Ty'es o" *og
The first type of fog e ill look at is linear, and itLs the easiest fog to understand. The first thing e are
going to do after e call set<orld;eometry is set the vieportLs background color. <e could do this by
overriding the createAieport function +like e did in the last tutorial,, but sometimes e need to set it
ithout recreating the vieport every time. This is ho e do that$
-olour1alue 7ade-olour(2.Q) 2.Q) 2.Q)*
%;indo?'(get1ie?port(2)'(setBacNground-olour(7ade-olour)*
Bou could use the get0umAieports member function to get the number of vieports and iterate through
them if you have more than one vieport, but since this is rarely the case +and since e kno e only
have one vieport,, e can 2ust get the vieport directly. .nce e set the background color, e can no
create the fog. ?emember, this code must appear "efore the set<orld;eometry call$
%Scene&gr'(set:og(:O890<+A,) 7ade-olour) 2.2) 32) 322)*
The first parameter to the set4og function is the type of fog +in this case, linear,. The second parameter to
set4og is the color of the fog e are using +in this case a very very light grey or D<hiteSmokeD for CR,.
The third parameter is not used in linear fog. The fourth and fifth parameters specify the range here the
fog gets thicker. 7n this case e have set the fog starting point to be 8& and the stopping point to be 8&&.
This means that from & to 8& units in front of the camera, there is no fog. 4rom 8& to 8&& units aay from
the Camera, the fog gets thicker in a linear fashion. At 8&& units aay from the Camera, you can no
longer see anything other than fog. Compile and run the application.
Another type of fog that e can use is exponential fog. 7nstead of setting starting and stopping bounds for
fog, e instead set a density for the fog +the fourth and fifth parameters are unused,. ?eplace the previous
call to set4og ith this$
%Scene&gr'(set:og(:O89V4) 7ade-olour) 2.223)*
Compile and run the application. 7f you are using the "irectQ ?enderer you may find it completely
fogged out= calling set4og after set<orld;eometry fixes this. The .pen;L ?enderer behaves as
documented. This creates a different look to the fog that is generated. There is also another exponential
fog function hich is more severe than the first one +i.e. fog gets much thicker each unit you move aay
from the Camera compared to the first fog function,. 0ote that there is more fog-per-density hen using
4.;P1Q!%. ?eplace the previous call to set4og ith this$
%Scene&gr'(set:og(:O89V45) 7ade-olour) 2.22=)*
Compile and run the application again. 4og is mostly interchangeable beteen the three functions that
.gre provides. Bou should experiment ith all three fog functions and see hich looks best in your
application.
*og and S1y
Bou can run into some interesting problems hen trying to use fog ith a Sky-ox and Sky"ome. Since
Sky"omes and Sky-oxes are 2ust cubes, using them ith fog is problematic since fog orks in a
spherical manner. Clear out the contents of the createScene method. 7f e cleverly choose our Sky"ome
and fog parameters, e can see the problem directly$
-olour1alue 7ade-olour(2.Q) 2.Q) 2.Q)*
%Scene&gr'(set:og(:O890<+A,) 7ade-olour) 2.2) 32) 3P3)*
%;indo?'(get1ie?port(2)'(setBacNground-olour(7ade-olour)*
%Scene&gr'(set;orld8eo%etr!("terrain.c7g")*
%Scene&gr'(setSN!>o%e(true) "@a%plesM-loud!SN!") 3) 6) 322)*
Compile and run the application. 7f you move the camera around, you ill see different portions of the
Sky"ome poke through the fog depending on hat part of the Sky"ome you are looking at +notice the
blue coming through on the sides, but not in the middle,$
http$((.idleengineer.net(images(beginner&3Pfogbox.png
This is certainly not hat e ant. Another option is to use a Sky!lane instead. ?eplace the code in
createScene ith this$
-olour1alue 7ade-olour(2.Q) 2.Q) 2.Q)*
%Scene&gr'(set:og(:O890<+A,) 7ade-olour) 2.2) 2) P=2)*
%;indo?'(get1ie?port(2)'(setBacNground-olour(7ade-olour)*
4lane plane*
plane.d $ P22*
plane.nor%al $ 1ector=::+8AT<19D+<T9T*
%Scene&gr'(set;orld8eo%etr!("terrain.c7g")*
%Scene&gr'(setSN!4lane(true) plane) "@a%plesM-loud!SN!") 322) 52) true) 2.3)
P32) P32)*
This looks correct. 7f e look upards e can see sky +hich is the case in real life if the fog is 2ust
right,, but itLs not poking through in funny ays. 0o matter if you use curvature or not, this solves our
problem of the user being able to see the horiCon here the Sky!lane does not look right.
There is a ay to make fog not affect the sky entirely, but it re9uires modifying the material script for the
sky texture. That is beyond the scope of this tutorial, but for future reference this parameter is hat
disables fog for a material.
*og as +ar1ness
Bou may not ant to use sky at all hen you set fog, because if the fog is thick enough you cannot see
the sky anyay. The trick ith fog that e described above allos us to perform a nifty graphic hack that
can be useful in some cases. 7nstead of setting the fog to a bright color, lets set it to be very dark and see
hat happens +note e have set the Sky!lane to be only '& units aay from the camera, hich is before
the fog sets in,$
-olour1alue 7ade-olour(2.P) 2.P) 2.P)*
%;indo?'(get1ie?port(2)'(setBacNground-olour(7ade-olour)*
%Scene&gr'(set:og(:O890<+A,) 7ade-olour) 2.2) P2) P32)*
%Scene&gr'(set;orld8eo%etr!("terrain.c7g")*
4lane plane*
plane.d $ P2*
plane.nor%al $ 1ector=::+8AT<19D+<T9T*
%Scene&gr'(setSN!4lane(true) plane) "@a%plesMSpaceSN!4lane") P22) J3) true) 2.3)
P32) P32)*
Compile and run the application. This is hat e get$
http$((.idleengineer.net(images(beginner&3Pdarkness.png
0ot too terrible. .f course, once you are able to, you should use proper lighting instead of this hack, but it
does sho the flexibility of fog, and some of the interesting things you can do ith the engine. 6sing
black fog might also be an interesting ay to do a DblindnessD or DdarknessD spell effect if you are riting
a game that uses first-person vie.
!roceed to -asic Tutorial 5 !rame Listeners and #n"uffered $nput
Basic Tutorial 7 :
*rame ,isteners and 5nbu""ered $n'ut
Any problems you encounter hile orking ith this tutorial should be posted to the #elp 4orum .
rere!uisites
This tutorial assumes you have knoledge of C@@ programming and are able to set up and compile an
.gre application +if you have trouble setting up your application, see this guide for specific compiler
setups,. This tutorial builds on the previous beginner tutorials, and it assumes you have already orked
through them.
$ntroduction
7n this tutorial e ill be introducing one of the most useful .gre constructs$ the 4rameListener. -y the
end of this tutorial you ill understand 4rameListeners, ho to use 4rameListeners to do things that
re9uire updates every frame, and ho to use .greLs unbuffered input system.
Bou can find the code for this tutorial here. As you go through the tutorial you should be sloly adding
code to your on pro2ect and atching the results as e build it.
Table o" contents
!rere9uisites
7ntroduction
;etting Started
4rameListeners
7ntroduction
?egistering a 4rameListener
Setting up the Scene
7ntroduction
The Code
Tutorial4rameListener
Aariables
Constructor
The frameStarted /ethod
#etting Started
As ith the previous tutorials, e ill be using a pre-constructed code base as our starting point. Create a
pro2ect in the compiler of your choice for this pro2ect, and add a source file hich contains this code$
#include "@a%pleApplication.h"
class Tutorial:ra%e0istener : pu.lic @a%ple:ra%e0istener
{
pu.lic:
Tutorial:ra%e0istener(,ender;indo?" ?in) -a%era" ca%) Scene&anager "scene&gr)
: @a%ple:ra%e0istener(?in) ca%) 7alse) 7alse)
{
}
// Overriding the default processUnbufferedKe!nput so the "e updates we
define
// later on wor" as intended#
.ool processDn.u77eredFe!<nput(const :ra%eventC evt)
{
return true*
}
// Overriding the default processUnbuffered$ouse!nput so the $ouse updates we
define
// later on wor" as intended#
.ool processDn.u77ered&ouse<nput(const :ra%eventC evt)
{
return true*
}
.ool 7ra%eStarted(const :ra%event Cevt)
{
return @a%ple:ra%e0istener::7ra%eStarted(evt)*
}
protected:
.ool %&ouse>o?n* // %hether or not the left mouse button was down last
frame
,eal %Toggle* // &he time left until ne't toggle
,eal %,otate* // &he rotate constant
,eal %&ove* // &he movement constant
Scene&anager "%Scene&gr* // &he current Scene$anager
Scene+ode "%-a%+ode* // &he Scene(ode the camera is currentl attached to
}*
class TutorialApplication : pu.lic @a%pleApplication
{
pu.lic:
TutorialApplication()
{
}
~TutorialApplication()
{
}
protected:
void create-a%era(void)
{
}
void createScene(void)
{
}
void create:ra%e0istener(void)
{
}
}*
#i7 O8,940AT:O,& $$ 40AT:O,&9;<+=5 GG O8,940AT:O,& $$ O8,940AT:O,&9;<+=5
#de7ine ;<+=590A+9A+>9&A+
#include "?indo?s.h"
<+T ;<+A4< ;in&ain(#<+STA+- h<nst) #<+STA+-) 04ST, str-%d0ine) <+T)
#else
int %ain(int argc) char ""argv)
#endi7
{
// Create application object
TutorialApplication app*
tr! {
app.go()*
} catch(@ceptionC e) {
#i7 O8,940AT:O,& $$ 40AT:O,&9;<+=5 GG O8,940AT:O,& $$ O8,940AT:O,&9;<+=5
&essageBo@(+D00) e.get:ull>escription().c9str()) "An e@ception has
occurredE") &B9OF G &B9<-O+,,O, G &B9TASF&O>A0)*
#else
7print7(stderr) "An e@ception has occurred: RsSn")
e.get:ull>escription().c9str())*
#endi7
}
return 2*
}
7f you are using the .greS"F under <indos, be sure to add the
D.greS"FP"7?1CT.?BIsamplesIincludeD directory to this pro2ect +the 1xampleApplication.h file is
located there, in addition to the standard include. 7f using the .gre source distribution, this should be
located in the D.greSourceP"7?1CT.?BISamplesICommonIincludeD directory. +o NOT try to run
this 'rogram yet, since e have not defined keyboard behaviour yet. 7f you have problems, check this
<iki page for information about setting up your compiler, and if you still have problems try the #elp
4orum.
<e ill be defining the program controls during this tutorial.
*rame,isteners
$ntroduction
7n the previous tutorials e only looked at hat e could do hen e add code to the createScene
method. 7n .gre, e can register a class to receive notification before and after a frame is rendered to the
screen. This 4rameListener interface defines to functions$
.ool 7ra%eStarted(const :ra%eventC evt)
.ool 7ra%ended(const :ra%eventC evt)
.greLs main loop +?oot$$start?endering, looks like this$
'. The ?oot ob2ect calls the frameStarted method on all registered 4rameListeners.
%. The ?oot ob2ect renders one frame.
3. The ?oot ob2ect calls the frame1nded method on all registered 4rameListeners.
This loops until any of the 4rameListeners return false from frameStarted or frame1nded. The return
values for these functions basically mean Dkeep renderingD. 7f you return false from either, the program
ill exit. The 4rame1vent ob2ect contains to variables, but only the timeSinceLast4rame is useful in a
4rameListener. This variable keeps track of ho long itLs been since the frameStarted or frame1nded last
fired. 0ote that in the frameStarted method, 4rame1vent$$timeSinceLast4rame ill contain ho long it
has been since the last "rameStarted event as last fired +not the last time a frame1nded method as
fired,.
.ne important concept to realiCe about .greLs 4rameListeners is that the order in hich they are called is
entirely up to .gre. Bou cannot determine hich 4rameListener is called first, second, third...and so on.
7f you need to ensure that 4rameListeners are called in a certain order, then you should register only one
4rameListener and have it call all of the ob2ects in the proper order.
Bou might also notice that the main loop really only does three things, and since nothing happens in
beteen the frame1nded and frameStarted methods being called, you can use them almost
interchangably. <here you decide to put all of your code is entirely up to you. Bou can put it all in one
big frameStarted or frame1nded method, or you could divide it up beteen the to.
-egistering a *rame,istener
Currently the above code ill compile, but since e have overridden the create4rameListener method of
1xampleApplication and createCamera, if you run the application you ill not be able to kill it. <eLll first
fix this problem before continuing on to the rest of the tutorial.
4ind the TutorialApplication$$createCamera method and add the folloing code to it$
// create camera, but leave at default position
%-a%era $ %Scene&gr'(create-a%era("4la!er-a%")*
%-a%era'(set+ear-lip>istance(3)*
<e have not done anything out of the ordinary ith this. The only reason e need to override
1xampleApplicationLs createCamera method is because the createCamera method moves the camera and
changes its orientation, hich e do not ant for this tutorial.
Since the ?oot class is hat renders frames, it is also in charge of keeping track of 4rameListeners. The
first thing e need to do is create an instance of our Tutorial4rameListener and register it ith the ?oot
ob2ect. 4ind the TutorialApplication$$create4rameListener method, and add this code to it$
// Create the )rame*istener
%:ra%e0istener $ ne? Tutorial:ra%e0istener(%;indo?) %-a%era) %Scene&gr)*
%,oot'(add:ra%e0istener(%:ra%e0istener)*
The m?oot and m4rameListener variables are defined in the 1xampleApplication class. The
add4rameListener method adds a 4rameListener, and the remove4rameListener method removes a
4rameListener +that is, the 4rameListener ill no longer receive updates,. 0ote that the addU
remove4rameListener methods only take in a pointer to a 4rameListener +that is, 4rameListeners do not
have names you can use to remove them,. This means that you ill need to hold a pointer to each
4rameListener you create so that you can later remove them.
The 1xample4rameListener +hich our Tutorial4rameListener is derived from,, also provides a
sho"ebug.verlay+bool, function, hich tells the 1xampleApplication hether or not to sho the
framerate box in the bottom left corner. <eLll turn that on as ell$
// Show the frame stats overla
%:ra%e0istener'(sho?>e.ugOverla!(true)*
-e sure you can compile the application before continuing.
Setting u' the Scene
$ntroduction
-efore e dive directly into the code, 7 ould like to briefly outline hat e ill be doing so that you
understand here 7 am going hen e create and add things to the scene.
<e ill be placing one ob2ect +a nin2a, in the scene, and one point light in the scene. 7f you left click the
mouse, the light ill toggle on and off. #olding don the right mouse button turns on Dmouse lookD
mode +that is, you look around ith the Camera,. <e ill also be placing Scene0odes around the scene
hich e ill be attaching the Camera to for different viepoints. !ressing the ' and % buttons chooses
hich Camera viepoint to vie the scene from.
The %ode
4ind the TutorialApplication$$createScene method. The first thing e ill be doing is setting the ambient
light of the scene very lo. <e ant scene ob2ects to still be visible hen the light is off, but e also
ant the light going on(off to be noticable$
%Scene&gr'(setA%.ient0ight(-olour1alue(2.53) 2.53) 2.53))*
0o, add a 0in2a entity to the scene at the origin$
ntit! "ent $ %Scene&gr'(createntit!("+in/a") "nin/a.%esh")*
Scene+ode "node $ %Scene&gr'(get,ootScene+ode()'
(create-hildScene+ode("+in/a+ode")*
node'(attachO./ect(ent)*
0o e ill create a hite point light and place it in the Scene, a small distance +relatively, aay from
the 0in2a$
0ight "light $ %Scene&gr'(create0ight("0ightP")*
light'(setT!pe(0ight::0T94O<+T)*
light'(set4osition(1ector=(532) P32) 532))*
light'(set>i77use-olour(-olour1alue::;hite)*
light'(setSpecular-olour(-olour1alue::;hite)*
0o e need to create the Scene0odes hich the Camera ill be attached to$
// Create the scene node
node $ %Scene&gr'(get,ootScene+ode()'(create-hildScene+ode("-a%+odeP") 1ector=('
J22) 522) J22))*
node'(!a?(>egree('J3))*
node'(attachO./ect(%-a%era)*
// create the second camera node
node $ %Scene&gr'(get,ootScene+ode()'(create-hildScene+ode("-a%+ode5") 1ector=(2)
522) J22))*
0o e are done ith the TutorialApplication class. .nto the Tutorial4rameListener...
Tutorial*rame,istener
.ariables
<e have defined a fe variables in the Tutorial4rameListener class hich 7Ld like to go over before e
get any further$
.ool %&ouse>o?n* // %hether or not the left mouse button was down last
frame
,eal %Toggle* // &he time left until ne't toggle
,eal %,otate* // &he rotate constant
,eal %&ove* // &he movement constant
Scene&anager "%Scene&gr* // &he current Scene$anager
Scene+ode "%-a%+ode* // &he Scene(ode the camera is currentl attached to
The mScene/gr holds a pointer to the current Scene/anager and the mCam0ode holds the current
Scene0ode that the Camera is attached to. The m?otate and m/ove are our constants of rotation and
movement. 7f you ant the movement or rotation to be faster or sloer, teak these variables to be higher
or loer.
The other to variables +mToggle and m/ouse"on, control our input. <e ill be using DunbufferedD
mouse and key input in this tutorial +buffered input ill be the sub2ect of our next tutorial,. This means
that e ill be calling methods during our frame listener to 9uery the state of the keyboard and mouse.
<e run into an interesting problem hen e try to use the keyboard to change the state of some ob2ect on
the screen. 7f e see that a key is don, e can act on this information, but hat happens the next frameM
"o e see that the same key is don and do the same thing againM 7n some cases +like movement ith the
arro keys, this is hat e ant to do. #oever, letLs say e ant the DTD key to toggle beteen a light
being on or off. The first frame the T key is don, the light gets toggled, the next frame the T key is still
don, so itLs toggled again... and again and again until the key is released. <e have to keep track of the
keyLs state beteen frames to avoid this problem. 7 ill present to separate methods for solving this.
The m/ouse"on keeps track of hether or not the mouse as also don the previous frame +so if
m/ouse don is true, e do not perform the same action again until the mouse is released,. The
mToggle button specifies the time until e are alloed to perform an action again. That is, hen a button
is pressed, mToggle is set to some length of time here no other actions can occur.
%onstructor
The first thing to notice about the constructor is that e make a call to the 1xample4rameListenerLs
constructor$
: @a%ple:ra%e0istener(?in) ca%) 7alse) 7alse)
The important thing to note is that the third and fourth variables are set to false. The third variable
specifies if e ant to use buffered key input, the fourth is if e ant to use buffered mouse input +hich
e donLt in this tutorial,.
7n the Tutorial4rameListener constructor, e ill set default values for all variables$
// "e and mouse state trac"ing
%&ouse>o?n $ 7alse*
%Toggle $ 2.2*
// +opulate the camera and scene manager containers
%-a%+ode $ ca%'(get4arentScene+ode()*
%Scene&gr $ scene&gr*
// set the rotation and move speed
%,otate $ 2.P=*
%&ove $ 532*
ThatLs it. The mCam0ode variable is initialiCed to be hatever the current parent of the camera is.
The "rameStarted Method
0o e are going to get into the real meat of the tutorial$ performing actions every frame. Currently our
frameStarted method has the folloing code in it$
return @a%ple:ra%e0istener::7ra%eStarted(evt)*
This chunk of code is hat has alloed the tutorial application to run until e could get to this point. The
1xample4rameListener$$frameStarted method defines a lot of behavior +such as all of the key bindings, all
of the camera movement, etc,. %lear out the contents o" the Tutorial*rame,istener::"rameStarted
method.
The .pen 7nput System +.7S, provides three primary classes to retrieve input$ Feyboard, /ouse, and
Soystick. 7n these tutorials e ill really only be covering ho to use the Feyboard and /ouse ob2ects. 7f
you are interested in using a 2oystick +or gamepad, ith .gre, you should look into the Soystick class.
The first thing e ill need to do hen using unbuffered input is to capture the current state of the
keyboard and mouse. <e do this by calling the capture method of the /ouse and Feyboard ob2ects. The
example frameork already creates these ob2ects for us in the m/ouse and mFeyboard variables. Add
the folloing code to the no empty Tutorial4rameListener$$frameStarted member function$
%&ouse'(capture()*
%Fe!.oard'(capture()*
0ext, e ant to be sure that the program exits if the 1scape key is pressed. <e check to see if a button is
pressed by calling the isFey"on method of 7nput?eader and specifying a FeyCode. 7f the 1scape key is
pressed, eLll 2ust return false to end the program$
i7(%Fe!.oard'(isFe!>o?n(O<S::F-9S-A4))
return 7alse*
7n order to continue rendering the frameStarted method must return a positive boolean value. To do e
ill add the folloing line to the end of the method.
return true*
All of the folloing code that e ill be discussing goes abo(e that final Dreturn trueD line.
The first thing e are going to do ith our 4rameListener is make the left mouse button toggle the light
on and off. <e can find out if a mouse button is don by calling the get/ouse-utton method of
7nput?eader ith the button e ant to 9uery for. 6sually & is the left mouse button, ' is the right mouse
button, and % is the center mouse button. .n some systems button ' is the middle and % is the right mouse
button. Try this configuration if the mouse buttons donLt ork as expected.
.ool curr&ouse $ %&ouse'(get&ouseState()..utton>o?n(O<S::&B90e7t)*
The curr/ouse variable ill be true if the mouse button is don. 0o e ill toggle the light depending
on hether or not curr/ouse is true, and if the mouse as not held don the previous frame +because e
only ant to toggle the light once every time the mouse is pressed,. Also note that the setAisible method
of the Light class determines if the ob2ect actually emits light or not$
i7 (curr&ouse CC E %&ouse>o?n)
{
0ight "light $ %Scene&gr'(get0ight("0ightP")*
light'(set1isi.le(E light'(is1isi.le())*
}
0o e need to set the m/ouse"on variable to e9ual hatever the curr/ouse variable contains. 0ext
frame this ill tell us if the mouse button as up or don previously.
%&ouse>o?n $ curr&ouse*
Compile and run the application. 0o left clicking toggles the light on and off> 0ote that since e no
longer call the 1xample4rameListenerLs frameStarted method, e cannot move the camera around +yet,.
This method of storing the previous state of the mouse button orks ell, since e kno e already have
acted on the mouse state. The draback is to use this for every key e bind to an action, eLd need a
boolean variable for it. .ne ay e can get around this is to keep track of the last time any button as
pressed, and only allo actions to happen after a certain amount of time has elapsed. <e keep track of
this state in the mToggle variable. 7f mToggle is greater than &, then e do not perform any actions, if
mToggle is less than &, then e do perform actions. <eLll use this method for the folloing to key
bindings.
The first thing e ant to do is decrement the mToggle variable by the time that has elapsed since the last
frame$
%Toggle '$ evt.ti%eSince0ast:ra%e*
0o that e have updated mToggle, e can act on it. .ur next key binding is making the ' key attach the
Camera to the first Scene0ode. mToggle acts as a &.8 second delay before any additional changes can
take place. 7n practice, this delay is longer than necessary, but it illustrates the point.
i7 ((%Toggle H 2.27 ) CC %Fe!.oard'(isFe!>o?n(O<S::F-9P))
{
%Toggle $ 2.37*
%-a%era'(get4arentScene+ode()'(detachO./ect(%-a%era)*
%-a%+ode $ %Scene&gr'(getScene+ode("-a%+odeP")*
%-a%+ode'(attachO./ect(%-a%era)*
}
The camera is DmovedD to Cam0ode' by first detaching itself from itLs parent Scene0ode and then
reattaching itself to the Cam0ode' Scene0ode. <e ill also do this for Cam0ode% hen the % button is
pressed. The code is identical except for changing ' to %, and using an else if instead of if +because e
ouldnLt be doing both at the same time,$
else i7 ((%Toggle H 2.27) CC %Fe!.oard'(isFe!>o?n(O<S::F-95))
{
%Toggle $ 2.37*
%-a%era'(get4arentScene+ode()'(detachO./ect(%-a%era)*
%-a%+ode $ %Scene&gr'(getScene+ode("-a%+ode5")*
%-a%+ode'(attachO./ect(%-a%era)*
}
Compile and run the tutorial. <e can no sap the CameraLs viepoint by pressing ' and %.
The next thing e need to do is translate mCam0ode henever the user holds don one of the arro
keys or <AS". 6nlike the code above, e do not need to keep track of the last time e moved the
camera, since for every frame the key is held don e ant to translate it again. This makes our code
relatively simple. 4irst e ill create a Aector3 to hold here e ant to translate to$
1ector= trans1ector $ 1ector=::U,O*
0o, hen the < key or the up arro is pressed, e ant to move straight forard +hich is the
negative C axis, remember negative C is straight into the computer screen,$
i7 (%Fe!.oard'(isFe!>o?n(O<S::F-9D4) GG %Fe!.oard'(isFe!>o?n(O<S::F-9;))
trans1ector.O '$ %&ove*
<e do almost the same thing for the S and "on arro keys, but e move in the positive C axis instead$
i7 (%Fe!.oard'(isFe!>o?n(O<S::F-9>O;+) GG %Fe!.oard'(isFe!>o?n(O<S::F-9S))
trans1ector.O X$ %&ove*
4or left and right movement, e go in the positive or negative x direction$
i7 (%Fe!.oard'(isFe!>o?n(O<S::F-90:T) GG %Fe!.oard'(isFe!>o?n(O<S::F-9A))
trans1ector.@ '$ %&ove*
i7 (%Fe!.oard'(isFe!>o?n(O<S::F-9,<8#T) GG %Fe!.oard'(isFe!>o?n(O<S::F-9>))
trans1ector.@ X$ %&ove*
4inally, e also ant to give a ay to move up and don along the y axis. 7 personally use 1(!age"on
for donards motion and N(!age6p for upards motion$
i7 (%Fe!.oard'(isFe!>o?n(O<S::F-948D4) GG %Fe!.oard'(isFe!>o?n(O<S::F-9Y))
trans1ector.! X$ %&ove*
i7 (%Fe!.oard'(isFe!>o?n(O<S::F-948>O;+) GG %Fe!.oard'(isFe!>o?n(O<S::F-9))
trans1ector.! '$ %&ove*
0o, our transAector variable has the translation e ish to apply to the cameraLs Scene0ode. The first
pitfall e can encounter hen doing this is that if you rotate the Scene0ode, then our x, y, and C
coordinates ill be rong hen translating. To fix this, e need to apply all of the rotations e have
done to the Scene0ode to our translation node. This is actually simpler than it sounds.
To represent rotations, .gre does not use transformation matrices like some graphics engines. 7nstead it
uses Nuaternions for all rotation operations. The math behind Nuaternions involves four dimensional
linear algebra, hich is very difficult to understand. Thankfully, you do not have to understand the math
behind them to understand ho to use them. Nuite simply, to use a Nuaternion to rotate a vector, all you
have to do is multiply the to together. 7n this case, e ant to apply all of the rotations done to the
Scene0ode to the translation vector. <e can get a Nuaternion representing these rotations by calling
Scene0ode$$get.rientation+,, then e can apply them to the translation node using multiplication.
The second pitfall e have to atch out for is e have to scale the amount e translate by the amount of
time since the last frame. .therise, ho fast you move ould be dependent on the framerate of the
application. "efinitely not hat e ant. This is the function call e need to make to translate our
camera node ithout encountering these problems$
%-a%+ode'(translate(trans1ector " evt.ti%eSince0ast:ra%e) +ode::TS90O-A0)*
0o e have introduced something ne. <henever you translate a node, or rotate it about any axis, you
can specify hich Transformation Space you ant to use to move the ob2ect. 0ormally hen you
translate an ob2ect, you do not have to set this parameter. 7t defaults to TSP!A?10T, meaning that the
ob2ect is moved in hatever transformation space the parent node is in. 7n this case, the parent node is the
root scene node. <hen e press the < button +to move forard,, e subtracted from the V direction,
meaning e move toards the negative V axis. 7f e did not specify TSPL.CAL in this previous line of
code, e ould move the camera along the global -V axis. #oever, since e are trying to make a
camera hich goes forward hen e press <, e need it to go in the direction that the node is actually
facing. #ence, e use the DlocalD transformation space.
There is another ay e can do this +though it is less direct,. <e could have gotten the orientation of the
node, a 9uaternion, and multiplied this by the direction vector to get the same result. This ould be
perfectly valid$
// ,o not add this to the program
%-a%+ode'(translate(%-a%+ode'(getOrientation() " trans1ector "
evt.ti%eSince0ast:ra%e) +ode::TS9;O,0>)*
This also translates the camera node in the local space. 7n this case, there is no real reason to do this. .gre
defines three transform spaces$ TSPL.CAL, TSP!A?10T, and TSP<.?L". There may be a case
here you need to make a translation or a rotation in another vector space than these three. 7f that is the
case, you ould do it similar to the previous line of code. Take a 9uaternion representing the vector space
+or the orientation of hatever ob2ect you are trying to match,, multiply it by the translation vector to get
the corrected translation vector, and then move it in the TSP<.?L" space. This ill probably not come
up for 9uite a hile though, and e ill not refer to it in any of the future tutorials.
0o that e have key movement don, e ant to have the mouse affect hich direction e are looking
in, but only if the user is holding don the right mouse button$
i7 (%&ouse'(get&ouseState()..utton>o?n(O<S::&B9,ight))
{
%-a%+ode'(!a?(>egree('%,otate " %&ouse'(get&ouseState().V.rel))
+ode::TS9;O,0>)*
%-a%+ode'(pitch(>egree('%,otate " %&ouse'(get&ouseState().T.rel))
+ode::TS90O-A0)*
}
<e ya and pitch the camera based on the amount the mouse has moved since the last frame. To do this,
e ill take the Q and B relative changes and turn these into pitch and ya function calls.
0ote that e have used the TSP<.?L" vector space for the ya +rotation functions alays use
TSPL.CAL as a default, if not specified,. <e are trying to ensure that the pitch of the ob2ect does not
affect the ya in any ay. <e alays ant the ya to rotate us around the same axis. This is the third
pitfall$ forgetting the interactions beteen rotations. 7f e set the ya to take place in TSPL.CAL, e
ould get something like this happening$
"ead Link - http$((.idleengineer.net(images(beginner&5Prot.png
Alternate$ http$((tatis3.springnote.com(pages('&%535*(attachments(535'*&
Compile the program and try it out.
This tutorial is not meant to be a full alkthrough on rotations and Nuaternions +that is enough material to
fill an entire tutorial by itself,. 7n the next tutorial, e ill use buffered mouse input instead of checking
for keys being don every frame.
!roceed to -asic Tutorial 8 %uffered $nput
Basic Tutorial 8 :
Bu""ered $n'ut
Any problems you encounter hile orking ith this tutorial should be posted to the #elp 4orum .
rere!uisites
This tutorial assumes you have knoledge of C@@ programming and are able to setup and compile an
.gre application +if you have trouble setting up your application, see this guide for specific compiler
setups,. This tutorial builds on the previous beginner tutorials, and it assumes you have already orked
through them.
$ntroduction
7n this short tutorial you ill be learning to use .7SLs buffered input as opposed to the unbuffered input
e used last tutorial. This tutorial differs from the last in that e ill be handling keyboard and mouse
events immediately, as they happen, instead of once per frame. 0ote that this is only meant as an
introduction to buffered input, and not a complete tutorial on ho to use .7S. 4or more information on
that, be sure to look at the 6sing .7S article.
Bou can find the code for this tutorial here. As you go through the tutorial you should be sloly adding
code to your on pro2ect and atching the results as e build it.
Table o" contents
!rere9uisites
7ntroduction
;etting Started
-uffered 7nput in a 0utshell
7ntroduction
The FeyListener 7nterface
The /ouseListener 7nterface
The Code
The Tutorial4rameListener Constructor
Aariables
Tutorial4rameListener Constructor
Fey -indings
/ouse -indings
.ther 7nput Systems
#etting Started
This tutorial ill be building on the last tutorial, but e are changing the ay that e do input. Since the
functionality ill be basically the same, e ill use the same TutorialApplication class from last time,
but e ill be starting over on the Tutorial4rameListener. Create a pro2ect in the compiler of your choice
for this pro2ect, and add a source file hich contains this code$
#include "@a%pleApplication.h"
class Tutorial:ra%e0istener : pu.lic @a%ple:ra%e0istener) pu.lic
O<S::&ouse0istener) pu.lic O<S::Fe!0istener
{
pu.lic:
Tutorial:ra%e0istener(,ender;indo?" ?in) -a%era" ca%) Scene&anager "scene&gr)
: @a%ple:ra%e0istener(?in) ca%) true) true)
{
}
.ool 7ra%eStarted(const :ra%event Cevt)
{
i7(%&ouse)
%&ouse'(capture()*
i7(%Fe!.oard)
%Fe!.oard'(capture()*
return %-ontinue*
}
// $ouse*istener
.ool %ouse&oved(const O<S::&ousevent Ce) { return true* }
.ool %ouse4ressed(const O<S::&ousevent Ce) O<S::&ouseButton<> id) { return
true* }
.ool %ouse,eleased(const O<S::&ousevent Ce) O<S::&ouseButton<> id) { return
true* }
// Ke*istener
.ool Ne!4ressed(const O<S::Fe!vent Ce) { return true* }
.ool Ne!,eleased(const O<S::Fe!vent Ce) { return true* }
protected:
,eal %,otate* // &he rotate constant
,eal %&ove* // &he movement constant
Scene&anager "%Scene&gr* // &he current Scene$anager
Scene+ode "%-a%+ode* // &he Scene(ode the camera is currentl attached to
.ool %-ontinue* // %hether to continue rendering or not
1ector= %>irection* // -alue to move in the correct direction
}*
class TutorialApplication : pu.lic @a%pleApplication
{
pu.lic:
void create-a%era(void)
{
// create camera, but leave at default position
%-a%era $ %Scene&gr'(create-a%era("4la!er-a%")*
%-a%era'(set+ear-lip>istance(3)*
}
void createScene(void)
{
%Scene&gr'(setA%.ient0ight(-olour1alue(2.53) 2.53) 2.53))*
// add the ninja
ntit! "ent $ %Scene&gr'(createntit!("+in/a") "nin/a.%esh")*
Scene+ode "node $ %Scene&gr'(get,ootScene+ode()'
(create-hildScene+ode("+in/a+ode")*
node'(attachO./ect(ent)*
// create the light
0ight "light $ %Scene&gr'(create0ight("0ightP")*
light'(setT!pe(0ight::0T94O<+T)*
light'(set4osition(1ector=(532) P32) 532))*
light'(set>i77use-olour(-olour1alue::;hite)*
light'(setSpecular-olour(-olour1alue::;hite)*
// Create the scene node
node $ %Scene&gr'(get,ootScene+ode()'(create-hildScene+ode("-a%+odeP")
1ector=('J22) 522) J22))*
// $a"e it loo" towards the ninja
node'(!a?(>egree('J3))*
// Create the pitch node
node $ node'(create-hildScene+ode("4itch+odeP")*
node'(attachO./ect(%-a%era)*
// create the second camera node/pitch node
node $ %Scene&gr'(get,ootScene+ode()'(create-hildScene+ode("-a%+ode5")
1ector=(2) 522) J22))*
node $ node'(create-hildScene+ode("4itch+ode5")*
}
void create:ra%e0istener(void)
{
// Create the )rame*istener
%:ra%e0istener $ ne? Tutorial:ra%e0istener(%;indo?) %-a%era) %Scene&gr)*
%,oot'(add:ra%e0istener(%:ra%e0istener)*
// Show the frame stats overla
%:ra%e0istener'(sho?>e.ugOverla!(true)*
}
}*
#i7 O8,940AT:O,& $$ 40AT:O,&9;<+=5 GG O8,940AT:O,& $$ O8,940AT:O,&9;<+=5
#de7ine ;<+=590A+9A+>9&A+
#include "?indo?s.h"
<+T ;<+A4< ;in&ain(#<+STA+- h<nst) #<+STA+-) 04ST, str-%d0ine) <+T)
#else
int %ain(int argc) char ""argv)
#endi7
{
// Create application object
TutorialApplication app*
tr! {
app.go()*
} catch(@ceptionC e) {
#i7 O8,940AT:O,& $$ 40AT:O,&9;<+=5 GG O8,940AT:O,& $$ O8,940AT:O,&9;<+=5
&essageBo@(+D00) e.get:ull>escription().c9str()) "An e@ception has
occurredE") &B9OF G &B9<-O+,,O, G &B9TASF&O>A0)*
#else
7print7(stderr) "An e@ception has occurred: RsSn")
e.get:ull>escription().c9str())*
#endi7
}
return 2*
}
7f you are using the .greS"F under <indos, be sure to add the
D.greS"FP"7?1CT.?BIsamplesIincludeD directory to this pro2ect +the 1xampleApplication.h file is
located there, in addition to the standard include. 7f using the .gre source distribution, this should be
located in the D.greSourceP"7?1CT.?BISamplesICommonIincludeD directory. "o NOT try to run this
program yet, since e have not defined keyboard behaviour yet. 7f you have problems, check this <iki
page for information about setting up your compiler, and if you still have problems try the #elp 4orum.
0ote$ 7f you have not set up your pro2ect to use Ansi C@@ and receive complaints about /essage-ox, you
may need to change the reference from /essage-ox to /essage-oxA.
The program controls ill be the same as in the last tutorial.
Bu""ered $n'ut in a Nutshell
$ntroduction
7n the previous tutorial e used unbuffered input, that is, every frame e 9ueried the state of
.7S$$Feyboard and .7S$$/ouse instances to see hat keys and mouse buttons ere being held don.
-uffered input uses listener interfaces to inform your program that events have occurred. 4or example,
hen a key is pressed, a FeyListener$$key!ressed event is fired and hen the button is released +no
longer being pressed, a FeyListener$$key?eleased event is fired to all registered FeyListener classes.
This takes care of having to keep track of toggle times or hether the key as unpressed the previous
frame.
.7S also supports unbuffered Soystick events through the .7S$$SoystickListener interface, though e ill
not cover ho to use this in this tutorial.
.ne important thing to note about .7SLs listener system is that you can only have one listener per
Feyboard, /ouse, or Soystick ob2ect. This is done for simplicity +and for speed,. Calling the
set1ventCallback function +hich e ill cover later, multiple times ill result in only the last registered
listener getting events. 7f you need multiple ob2ects to get Fey, /ouse, or Soystick events, you ill have
to rite a message dispatch yourself. Also, be sure to note that e still call the Feyboard$$capture and
/ouse$$capture in the frameStarted method. .7S does not use threads +or magic, to determine the
keyboard and mouse states, so you ill have to specify hen it should capture the input.
The 9ey,istener $nter"ace
.7SLs FeyListener interface provides to pure virtual functions. The first is the key!ressed function
+hich is called every time a key is pressed, and the key?eleased +hich is called every time a key is let
up,. The parameter passed to these functions is a Fey1vent, hich contains the key code of hat is being
pressed(released.
The Mouse,istener $nter"ace
The /ouseListener interface is only slightly more complex than the FeyListener interface. 7t contains
functions to see hen a mouse button as pressed or released$ /ouseListener$$mouse!ressed and
/ouseListener$$mouse?eleased. 7t also contains a mouse/oved function, hich is called hen the
mouse is moved. 1ach of these functions receive a /ouse1vent ob2ect, hich contains the current state of
the mouse in the DstateD variable.
The most important thing to note about the /ouseState ob2ect is that it contains not only the relative Q
and B coordinates of the mouse move +that is, ho far it has moved since the last time the
/ouseListener$$mouse/oved function as called,, but also the absolute Q and B coordinates +that is,
here exactly on the screen they are,.
The %ode
The Tutorial*rame,istener %onstructor
-efore e start modifying the Tutorial4rameListener, note that e have made to ma2or changes to the
Tutorial4rameListener class. 4irst, e implement more interfaces in it, and second, e modify the
1xample4rameListener parameters.
class Tutorial:ra%e0istener : pu.lic @a%ple:ra%e0istener) pu.lic
O<S::&ouse0istener) pu.lic O<S::Fe!0istener
: @a%ple:ra%e0istener(?in) ca%) true) true)
<e subclass the .7S /ouseListener and FeyListener classes so that e can receive events from them.
0ote that the .7S /ouseListener handles both mouse button events and mouse movement events. The
third and forth parameters of 1xample4rameListener have been change to true, hich specifies that e
ill be using buffered input for the keyboard and mouse. <e ill go into more detail on ho to manually
set up .7S as ell as the rest of .gre in the next tutorial.
.ariables
A fe variables have changed from the last tutorial. 7 have removed mToggle and m/ouse"on +hich
are no longer needed,. 7 have added a fe as ell$
,eal %,otate* // &he rotate constant
,eal %&ove* // &he movement constant
Scene&anager "%Scene&gr* // &he current Scene$anager
Scene+ode "%-a%+ode* // &he Scene(ode the camera is currentl attached to
.ool %-ontinue* // %hether to continue rendering or not
1ector= %>irection* // -alue to move in the correct direction
The m?otate, m/ove, mScene/gr, and mCam0ode are the same as the last tutorial +though e ill be
changing the value of m?otate since e are using it differently,. The mContinue variable is returned from
the frameStarted method. <hen e set mContinue to be false the program ill exit. The m"irection
variable contains information on ho e are going to translate camera node every frame.
Tutorial*rame,istener %onstructor
7n the constructor, e ill initialiCe some of the variables as e did in the previous tutorial, and e ill
set the mContinue rendering to be true. Add the folloing code to Tutorial4rameListenerLs constructor$
// +opulate the camera and scene manager containers
%-a%+ode $ ca%'(get4arentScene+ode()*
%Scene&gr $ scene&gr*
// set the rotation and move speed
%,otate $ 2.P=*
%&ove $ 532*
// continue rendering
%-ontinue $ true*
The .7S m/ouse and mFeyboard ob2ects are already obtained in the 1xample4rameListener constructor.
<e can register the Tutorial4rameListener as the listener by calling the set1ventCallback method on
these input ob2ects as follos$
%&ouse'(setvent-all.acN(this)*
%Fe!.oard'(setvent-all.acN(this)*
Last, e need to initialise m"irection to be the Cero vector +since e are initially not moving,$
%>irection $ 1ector=::U,O*
9ey Bindings
-efore e go any further, e should bind the 1scape key to exiting the program so e can run it. 4ind the
Tutorial4rameListener$$key!ressed method. This method is called ith a Fey1vent ob2ect every time a
button on the keyboard goes don. <e can obtain the key code +FCPE, of the key that as pressed by
checking the DkeyD variable on the ob2ect. <e ill build a sitch for all of the key bindings e use in the
application based on this value. 4ind the key!ressed method and replace it ith the folloing code$
.ool Ne!4ressed(const O<S::Fe!vent Ce)
{
s?itch (e.Ne!)
{
case O<S::F-9S-A4:
%-ontinue $ 7alse*
.reaN*
de7ault:
.reaN*
}
return %-ontinue*
}
/ake sure you can compile and run the application before continuing.
<e need to add bindings for other keys in that sitch statement. The first thing e are going to do is
allo the user to sitch beteen the viepoints by pressing ' and %. The code for this +needs to be
included in the sitch statement, is the same as it as in the previous tutorial, except e no longer have
to deal ith the mToggle variable$
case O<S::F-9P:
%-a%era'(get4arentScene+ode()'(detachO./ect(%-a%era)*
%-a%+ode $ %Scene&gr'(getScene+ode("-a%+odeP")*
%-a%+ode'(attachO./ect(%-a%era)*
.reaN*
case O<S::F-95:
%-a%era'(get4arentScene+ode()'(detachO./ect(%-a%era)*
%-a%+ode $ %Scene&gr'(getScene+ode("-a%+ode5")*
%-a%+ode'(attachO./ect(%-a%era)*
.reaN*
As you can see, this is much cleaner than dealing ith a temporary variable to keep track of toggle times.
The next thing e are going to add is keyboard movement. 1very time the user presses a key that is
bound for movement, e ill add or subtract m/ove +depending on direction, from the correct direction
in the vector$
case O<S::F-9D4:
case O<S::F-9;:
%>irection.O $ '%&ove*
.reaN*
case O<S::F-9>O;+:
case O<S::F-9S:
%>irection.O $ %&ove*
.reaN*
case O<S::F-90:T:
case O<S::F-9A:
%>irection.@ $ '%&ove*
.reaN*
case O<S::F-9,<8#T:
case O<S::F-9>:
%>irection.@ $ %&ove*
.reaN*
case O<S::F-948>O;+:
case O<S::F-9:
%>irection.! $ '%&ove*
.reaN*
case O<S::F-948D4:
case O<S::F-9Y:
%>irection.! $ %&ove*
.reaN*
0o e need to DundoD the change to the m"irection vector henever the key is released to stop the
movement. 4ind the key?eleased method and add this code to it$
s?itch (e.Ne!)
{
case O<S::F-9D4:
case O<S::F-9;:
%>irection.O $ 2*
.reaN*
case O<S::F-9>O;+:
case O<S::F-9S:
%>irection.O $ 2*
.reaN*
case O<S::F-90:T:
case O<S::F-9A:
%>irection.@ $ 2*
.reaN*
case O<S::F-9,<8#T:
case O<S::F-9>:
%>irection.@ $ 2*
.reaN*
case O<S::F-948>O;+:
case O<S::F-9:
%>irection.! $ 2*
.reaN*
case O<S::F-948D4:
case O<S::F-9Y:
%>irection.! $ 2*
.reaN*
de7ault:
.reaN*
}
return true*
0o that e have m"irection updated based on key input, e need to actually make the translation
happen. This code is the exact same as the last tutorial, so add this to the frameStarted function$
%-a%+ode'(translate(%>irection " evt.ti%eSince0ast:ra%e) +ode::TS90O-A0)*
Compile and run the application. <e no have key-based movement using buffered input>
Mouse Bindings
0o that e have key bindings completed, e need to ork on getting the mouse orking. <eLll start
ith toggling the light on and off based on a left mouse click. 4ind the mouse!ressed function and take a
look at the parameters. <ith .7S, e have access to both a /ouse1vent as ell as a /ouse-utton7". <e
can sitch on the /ouse-utton7" to determine the button that as pressed. ?eplace the code in the
mouse!ressed function ith the folloing$
0ight "light $ %Scene&gr'(get0ight("0ightP")*
s?itch (id)
{
case O<S::&B90e7t:
light'(set1isi.le(E light'(is1isi.le())*
.reaN*
de7ault:
.reaN*
}
return true*
Compile and run the application. AoilW > 0o that this is orking, the only thing e have left is to bind
the right mouse button to a mouse look mode. 1very time the mouse is moved, e ill check to see if the
right mouse button is don. 7f it is, e ill rotate the camera based on the relative movement. <e can
access the relative movement of the mouse from the /ouse1vent ob2ect passed into this function. 7t
contains a variable called DstateD hich contains the /ouseState +hich is basically detailed information
about the mouse,. The /ouseState$$button"on ill tell us hether or not a particular mouse button is
held don, and the DQD and DBD variables ill tell us the relative mouse movement. 4ind the
mouse/oved function and replace the code in it ith the folloing$
i7 (e.state..utton>o?n(O<S::&B9,ight))
{
%-a%+ode'(!a?(>egree('%,otate " e.state.V.rel)) +ode::TS9;O,0>)*
%-a%+ode'(pitch(>egree('%,otate " e.state.T.rel)) +ode::TS90O-A0)*
}
return true*
Compile and run the application and the camera ill act in free-look mode hile the right mouse button is
held don.
Other $n'ut Systems
.7S is generally very good, and should suit most purposes for your application. <ith that said, there are
alternatives if you ish to use something different. Some indoing systems may be hat you are
looking for, such as x<idgets , hich people have successfully integrated ith .gre. Bou can use the
standard <indos message system or one of the many Linux ;67 toolkits for input, if you donLt mind
your application being platform specific.
Bou can also try S"L, hich provides not only cross platform indoing(input systems, but also
2oystick(gamepad input. <hile 7 cannot give you guidance on setting up x(gtk(9t(etc ith .gre +as 7Lve
never done it before,, 7 have had a good amount of success getting S"LLs 2oystick(gamepad input to ork
ell ith .gre. To get S"LLs 2oystick system started, rap your applicationLs intial startup ith S"LP7nit
and S"LPNuit calls +this can be in your applicationLs main function, or possibly in your application
ob2ect,$
S>09<nit(S>09<+<T9ZOTST<-F G S>09<+<T9+O4A,A-#DT)*
S>09Zo!sticNventState(S>09+AB0)*
app.go()*
S>09Yuit()*
To setup the Soystick, call S"LPSoystick.pen ith the Soystick number +you can specify multiple
2oysticks by calling ith &, ', %...,$
S>09Zo!sticN" %Zo!sticN*
%Zo!sticN $ S>09Zo!sticNOpen(2)*
i7 ( %Zo!sticN $$ +D00 )
* // error handling
7f S"LPSoystick.pen returns 06LL, then there as a problem opening the 2oystick. This almost alays
means that the 2oystick you re9uested doesnLt exist. 6se S"LP0umSoysticks to find out ho many
2oysticks are attached to the system. Bou also need to close the 2oystick after you are done ith it$
S>09Zo!sticN-lose(%Zo!sticN)*
To use the 2oystick, call the S"LPSoystick;et-utton and S"LPSoystick;etAxis buttons. 7 personally
used this ith a playstation% controller , so 7 had four axes to play ith and telve buttons to play ith.
This is my movement code$
S>09Zo!sticNDpdate()*
%Trans.O X$ evt.ti%eSince0ast:ra%e " %&oveA%ount " S>09Zo!sticN8etA@is(%Zo!sticN)
P) M =5WIW*
%Trans.@ X$ evt.ti%eSince0ast:ra%e " %&oveA%ount " S>09Zo!sticN8etA@is(%Zo!sticN)
2) M =5WIW*
@,ot '$ evt.ti%eSince0ast:ra%e " %,otA%ount " S>09Zo!sticN8etA@is(%Zo!sticN) =) M
=5WIW*
!,ot '$ evt.ti%eSince0ast:ra%e " %,otA%ount " S>09Zo!sticN8etA@is(%Zo!sticN) 5) M
=5WIW*
mTrans as later fed into the cameraLs Scene0ode$$translate method, x?ot as fed into Scene0ode$$ya,
and y?ot as fed into Scene0ode$$pitch. 0ote that the S"LPSoystick;etAxis returns a value beteen
-3%:): and 3%:):, so 7 have scaled it to be beteen -' and '. This should get you started using S"L
2oystick input. 7f you are looking for more information in this area, the best documentation comes from
the S"L 2oystick header .
Bou should also refer to the standard S"L documentation if you start to seriously use this in your
application.
!roceed to -asic Tutorial ) The &gre Startup Se'uence
Basic Tutorial : :
The Ogre Startu' Se!uence
Any problems you encounter hile orking ith this tutorial should be posted to the #elp 4orum .
rere!uisites
This tutorial assumes you have knoledge of C@@ programming and are able to setup and compile an
.gre application +if you have trouble setting up your application, see GSetting6pAnApplicationUthis
guideHH for specific compiler setups,. This tutorial builds on the previous beginner tutorials, and it
assumes you have already orked through them.
Table o" contents
!rere9uisites
7ntroduction
;etting Started
The 7nitial Code
The Startup !rocess in a 0utshell
Starting up .gre
Creating the ?oot .b2ect
?esources
Creating the ?enderSystem
Creating a ?ender<indo
7nitialiCing ?esources
Creating a Scene
Starting up Third !arty Libraries
.7S
Setup and 6nbuffered 7nput
Setting 6p the 4ramelistener
Troubleshooting -uffered 7nput
C1;67
4inaliCing Startup and the ?ender Loop
4rame Listener
The ?ender Loop
.ptional #andling of <indo 1vents
Cleanup
/ac .S Q
$ntroduction
7n this tutorial you ill learn ho to start up .gre ithout using the example frameork. -y the time you
are done orking through this, you should be able to create your on .gre applications hich do not use
the 1xampleApplication or the 1xample4rameListener.
Bou can find the code for this tutorial here. As you go through the tutorial you should be sloly adding
code to your on pro2ect and atching the results as e build it.
#etting Started
The $nitial %ode
7n this tutorial, e ill be using a predefined code base as a starting point. As long as you have orked
through the previous tutorials, this should all be familiar to you. Create a pro2ect in the compiler of your
choice for this pro2ect, and add a source file hich contains this code$
#include HOgre.h(
#include HO<SMO<S.h(
#include H-8D<M-8D<.h(
#include H-8D<M,enderer&odulesMOgreM-8D<Ogre,enderer.h(
using na%espace Ogre*
class @it0istener : pu.lic :ra%e0istener
{
pu.lic:
@it0istener(O<S::Fe!.oard "Ne!.oard)
: %Fe!.oard(Ne!.oard)
{
}
.ool 7ra%eStarted(const :ra%eventC evt)
{
%Fe!.oard'(capture()*
return E%Fe!.oard'(isFe!>o?n(O<S::F-9S-A4)*
}
private:
O<S::Fe!.oard "%Fe!.oard*
}*
class Application
{
pu.lic:
void go()
{
create,oot()*
de7ine,esources()*
setup,enderS!ste%()*
create,ender;indo?()*
initialiOe,esource8roups()*
setupScene()*
setup<nputS!ste%()*
setup-8D<()*
create:ra%e0istener()*
start,ender0oop()*
}
~Application()
{
}
private:
,oot "%,oot*
O<S::Fe!.oard "%Fe!.oard*
O<S::<nput&anager "%<nput&anager*
-8D<::Ogre,enderer "%,enderer*
@it0istener "%0istener*
void create,oot()
{
}
void de7ine,esources()
{
}
void setup,enderS!ste%()
{
}
void create,ender;indo?()
{
}
void initialiOe,esource8roups()
{
}
void setupScene()
{
}
void setup<nputS!ste%()
{
}
void setup-8D<()
{
}
void create:ra%e0istener()
{
}
void start,ender0oop()
{
}
}*
#i7 O8,940AT:O,& 40AT:O,&9;<+=5 GG O8,940AT:O,& O8,940AT:O,&9;<+=5
#de7ine ;<+=590A+9A+>9&A+
#include "?indo?s.h"
<+T ;<+A4< ;in&ain(#<+STA+- h<nst) #<+STA+-) 04ST, str-%d0ine) <+T)
#else
int %ain(int argc) char ""argv)
#endi7
{
tr!
{
Application app*
app.go()*
}
catch(@ceptionC e)
{
#i7 O8,940AT:O,& 40AT:O,&9;<+=5 GG O8,940AT:O,& O8,940AT:O,&9;<+=5
&essageBo@A(+D00) e.get:ull>escription().c9str()) "An e@ception has
occurredE") &B9OF G &B9<-O+,,O, G &B9TASF&O>A0)*
#else
7print7(stderr) "An e@ception has occurred: RsSn")
e.get:ull>escription().c9str())*
#endi7
}
return 2*
}
-e sure you can compile this code before continuing. 7f you are having errors ith missing C1;67
dependencies such as C1;67Singleton.h or linker problems, make sure the folloing paths are in the
include search paths directive$ K+.;?1P#./1,Iinclude, K+.;?1P#./1,IincludeIC1;67, and K
+.;?1P#./1,IsamplesIinclude. Bou ill also need to add C1;67-asePd.lib and
C1;67.gre?endererPd.lib to the linker dependencies.
The Startu' rocess in a Nutshell
.nce you understand hatLs going on under the hood, getting .gre running is actually very easy to do.
The example frameork looks daunting at first since it tries to do a lot of things that may or may not be
needed for your application. After finishing this tutorial, you ill be able to pick and choose hat exactly
is needed for your application and you can build a class ith exactly that. -efore e dive into this, eLll
first take a 9uick look at ho the startup process orks at a high level.
The basic .gre life cycle looks like this$
'. Create the ?oot ob2ect.
%. "efine the resources that .gre ill use.
3. Choose and set up the ?enderSystem +that is, "irectQ, .pen;L, etc,.
5. Create the ?ender<indo +the indo hich .gre resides in,.
8. 7nitialiCe the resources that you are going to use.
). Create a scene using those resources.
:. Set up any third party libraries and plugins.
*. Create any number of frame listeners.
J. Start the render loop.
<e ill be going through each one of these in-depth in this tutorial.
7 ould like to note that hile you really should do steps '-5 in order, steps 8 and ) +initialiCing resources
and creating the scene, can come much later in your startup process if you like. Bou could initialiCe third
party plugins and create frame listeners before steps 8 and ) if you so choose, but you really shouldnLt do
them before finishing step 5. Also, the frame listeners(third party libraries cannot access any game related
resources +such as your cameras, entities, etc, until the resources are initialiCed and the scene has been
created. 7n short, you can do some of these steps out of order if you feel it ill be better for your
application, but 7 do not recommend doing so unless you are sure you understand the conse9uences of
hat you are doing.
Starting u' Ogre
%reating the -oot Object
The first thing e need to do is the simplest. The ?oot ob2ect is the core of the .gre library, and must be
created before you can do almost anything ith the engine. 4ind the Application$$create?oot function and
add the folloing code$
%,oot $ ne? ,oot()*
ThatLs all e need to do. The ?ootLs constructor takes 3 parameters. The first is the name and location of
the plugins config file. The second is the location of the ogre config file +hich tells ogre things like the
Aideo card, visual settings, etc,. The last is the location and name of the log file that .gre ill rite to.
Since e donLt really need to change any of these things, e ill leave them as their default values.
-esources
Note$ This section ill make a lot more sense if you open up Dresources.cfgD and take a look at it before
continuing. Bou can find this in the bin(release folder of your S"F.
The next thing e have to do is define the resources that the application uses. This includes the textures,
models, scripts, and so on. <e ill not be going over all there is to kno about resources in this tutorial.
4or no, 2ust keep in mind that you must first define all the resources that you might use during the
application, then you must initialiCe the specific resources you need before .gre can use them. 7n this step
e are defining all resources that our application ill possibly use.
To do this, e have to add each folder that resources reside in to the ?esource;roup/anager. 4ind the
define?esources function and add the folloing code$
String sec+a%e) t!pe+a%e) arch+a%e*
-on7ig:ile c7*
c7.load("resources.c7g")*
This uses .greLs Config4ile class to parse all of the resources from Dresources.cfgD, but this does not load
them into .gre +you have to do that manually,. Feep in mind that in your on application you are free to
use your on parser and config file formats if you like, 2ust replace .greLs Config4ile parser ith your
on. The method for loading resources in doesnLt really matter as long as you add the resources to the
?esource;roup/anager. 0o that e have parsed the config file, e need to add the sections to the
?esource;roup/anager. The folloing code starts looping through the parsed config file$
-on7ig:ile::Section<terator seci $ c7.getSection<terator()*
?hile (seci.has&orele%ents())
{
4or each section, e loop again, getting all the contents out of it$
sec+a%e $ seci.peeN+e@tFe!()*
-on7ig:ile::Settings&ulti&ap "settings $ seci.get+e@t()*
-on7ig:ile::Settings&ulti&ap::iterator i*
4inally, e add the section name +hich is the group of the resources,, the type of resource +Cip, folder,
etc,, and finally the filename of the resource itself to the ?esource;roup/anager$
7or (i $ settings'(.egin()* i E$ settings'(end()* XXi)
{
t!pe+a%e $ i'(7irst*
arch+a%e $ i'(second*
,esource8roup&anager::getSingleton().add,esource0ocation(arch+a%
e) t!pe+a%e) sec+a%e)*
}
}
This function e have no filled in adds all of the resources from the config file, but it only tells .gre
here they are. -efore you can use any of them you have to either initialiCe the group that you ant to
use, or you must initialiCe them all. <e ill discuss this further in the D7nitialiCing ?esourcesD function.
%reating the -enderSystem
0ext e need to choose the ?enderSystem +usually either "irectQ or .pen;L on a <indos machine,
and then configure it. /ost of the demo applications use the .gre config dialog, hich is a perfectly
reasonable ay to set up your application. .gre also offers a ay to restore the config that a user has
already set, meaning you ill never have to configure it after the first time. 4ind the setup?enderSystem
function and add the folloing code$
i7 (E%,oot'(restore-on7ig() CC E%,oot'(sho?-on7ig>ialog())
thro? @ception(35) "Dser canceled the con7ig dialogE")
"Application::setup,enderS!ste%()")*
7n the first part of the if statement, e attempt to restore the config file. 7f that function returns false it
means that the file does not exist so e should sho the config dialog, hich is the second portion of that
if statement. 7f that also returns false it means the user canceled out of config dialog +meaning they ant
to exit the program,. 7n this example, e have thron an exception, but in practice 7 think it ould
probably be better to simply return false and close out the application that ay, the reason being that the
restoreConfig and shoConfig"ialog could possibly thro an exception as ell, and it ould be better to
save exceptions for an actual failure. #oever, since making this change ould needlessly complicate the
tutorial, 7Lve used an exception here.
7f you use this techni9ue in practice 7 ould recommend that if you catch an exception during .greLs
startup that you delete the ogre.cfg file in the catch block. 7t is possible that the settings they have chosen
in the config dialog has caused a problem and they need to change them. 1ven if you do not use this for
your application hen you distribute it to others, turning off the config dialog can help cut don on
development time by a small amount since you do not have to keep confirming the graphics settings hen
the program runs.
Bour application may also manually setup the ?enderSystem if you choose to use something other than
.greLs config dialog. A basic example of this ould be as follos$
// ,o not add this to the application
,enderS!ste% "rs $ %,oot'(get,enderS!ste%B!+a%e(">irect=>Q ,endering
Su.s!ste%")*
// or use .Open/* 0endering
Subsstem.
%,oot'(set,enderS!ste%(rs)*
rs'(set-on7igOption(":ull Screen") "+o")*
rs'(set-on7igOption("1ideo &ode") "622 @ I22 [ =5'.it colour")*
Bou can use the ?oot$$getAvailable?enderers to find out hich ?enderSystems are available for your
application to use. .nce you have retrieved a ?enderSystem, you can use the
?enderSystem$$getConfig.ptions to see hat options are available for the user. -y combining these to
function calls, you can create your on config dialog for your application.
%reating a -ender0indo&
0o that e have chosen the ?enderSystem, e need a indo to render .gre in. There are actually a
lot of options for ho to do this, but e ill really only cover a couple.
7f you ant .gre to create a render indo for you, then this is very easy to do. 4ind the
create?ender<indo function and add the folloing code$
%,oot'(initialise(true) "Tutorial ,ender ;indo?")*
This call initialiCes the ?enderSystem e set in the previous section. The first parameter is hether or not
.gre should create a ?ender<indo for you. Alternatively, you can create a render indo yourself
using the in3% A!7, x<idgets, or one of the many other <indos or Linux ;67 systems. A 9uick
example of ho to do this under <indos ould look something like this$
// ,o not add this to the application
%,oot'(initialise(7alse)*
#;+> h;nd $ 2* // /et the h%nd of the application1
+a%e1alue4air0ist %isc*
%iscA"e@ternal;indo?#andle"B $ String-onverter::toString((int)h;nd)*
,ender;indo? "?in $ %,oot'(create,ender;indo?("&ain ,ender;indo?") 622)
I22) 7alse) C%isc)*
0ote that you still have to call ?oot$$initialise, but the first parameter is set to false. Then, you must get
the #<0" of the indo you ant to render .gre in. #o you get this ill be determined entirely by
the ;67 toolkit you use to create the indo +and under Linux 7 ould imagine this ould be a bit
different as ell,. After you have this, you use the 0ameAalue!airList to assign the handle to
Dexternal<indo#andleD. The ?oot$$create?ender<indo function then can be used to create the
?ender<indo class from the indo you have already created. Consult the A!7 documentation on this
function for more information.
$nitiali;ing -esources
0o that e have our ?oot ob2ect and our ?enderSystem and ?ender<indo ob2ects created and ready
to go, e are very close to being ready to create our scene. The only thing left to do is to initialiCe the
resources e are about to use. 7n a very large game or application, e may have hundreds or even
thousands of resources that our game uses - everything from meshes to textures to scripts. At any given
time though, e probably ill only be using a small subset of these resources. To keep don memory
re9uirements, e can load only the resources that our application is using. <e do this by dividing the
resources into sections and only initialiCing them as e go. <e ill not be covering that in this tutorial,
hoever. See ?esources and ?esource/anagers for a full tutorial devoted to resources.
-efore e initialiCe the resources, e should also set the default number of mipmaps that textures use.
<e must set that before e initialiCe the resources for it to have any effect. 4ind the
initialiCe?esource;roups function and add the folloing code$
Te@ture&anager::getSingleton().set>e7ault+u%&ip%aps(3)*
,esource8roup&anager::getSingleton().initialiseAll,esource8roups()*
The application no has all resource groups initialiCed and ready to be used.
%reating a Scene
0ext e ill need to create the scene. <e have done this many times in other tutorials, so e ill not
actually add anything to the scene e are about to create. 7nstead, you need to kno that there are three
things that must be done before you start adding things to a scene$ creating the Scene/anager, creating
the Camera, and creating the Aieport. 4ind the setupScene function and add the folloing code$
Scene&anager "%gr $ %,oot'(createScene&anager(ST98+,<-) ">e7ault
Scene&anager")*
-a%era "ca% $ %gr'(create-a%era("-a%era")*
1ie?port "vp $ %,oot'(getAuto-reated;indo?()'(add1ie?port(ca%)*
7f your render indo is not in focus on startup you may get an exception on m(oot)*start(endering+,
as described in http$((.ogre3d.org(forums(vietopic.phpMfO%XtO8333) this thread. 7f so, add the
folloing line$
// ,o not add this to the project
vp'(update()*
Bou may create as many Scene/anagers as you like and as many Cameras as you like, but you have to be
careful that hen you actually ant to render something on the screen using a Camera, you have to add a
Aieport for it. Bou do this by using the ?ender<indo class that as created in the DCreating a
?ender<indoD section. Since e did not hold onto a pointer to this ob2ect, e access it through the
?oot$$getAutoCreated<indo function.
After these three things, you may no add hatever to your scene that you like.
Starting u' Third arty ,ibraries
O$S
Though not the only option for input in .gre, .7S is one of the best. <e ill briefly cover ho to startup
.7S in your application. 4or the actual uses of the library, you should check the various tutorials here
+hich use it extensively, and the .7S documentation itself.
Setu' and 5nbu""ered $n'ut
.7S uses a general 7nput/anager hich is a touch difficult to set up, but easy to use once you have
created it properly. .7S does not integrate into .gre= itLs a standalone library, hich means that you ill
need to provide it ith some information at the beginning for it to ork properly. 7n practice it really only
needs the indo handle hich .gre is rendering in. Thankfully, since e have used the auto created
indo, .gre makes this easy for us. 4ind the setup7nputSystem function and add the folloing code$
siOe9t ?indo?#nd $ 2*
std::ostringstrea% ?indo?#ndStr*
O<S::4ara%0ist pl*
,ender;indo? "?in $ %,oot'(getAuto-reated;indo?()*
?in'(get-usto%Attri.ute(";<+>O;") C?indo?#nd)*
?indo?#ndStr HH ?indo?#nd*
pl.insert(std::%aNe9pair(std::string(";<+>O;")) ?indo?#ndStr.str()))*
%<nput&anager $ O<S::<nput&anager::create<nputS!ste%(pl)*
This sets up the 7nput/anager for use, but to actually use .7S to get input for the Feyboard, /ouse, or
Soystick of your choice, youLll need to create those ob2ects$
tr!
{
%Fe!.oard $ static9castHO<S::Fe!.oard"((%<nput&anager'
(create<nputO./ect(O<S::O<SFe!.oard) 7alse))*
//m$ouse 2 static3cast4O!S55$ouse678m!nput$anager-
7create!nputObject8O!S55O!S$ouse, false99:
//m;o 2 static3cast4O!S55;oStic"678m!nput$anager-
7create!nputObject8O!S55O!S;oStic", false99:
}
catch (const O<S::@ception Ce)
{
thro? @ception(J5) e.eTe@t) "Application::setup<nputS!ste%")*
}
7Lve commented out the /ouse and Soystick ob2ects since e ill not use them in this application, but that
is ho you create them. The second parameter to 7nput/anager$$create7nput.b2ect is hether or not to
use buffered input +hich e discussed in the last to tutorials,. Setting the second parameter to false
creates an unbuffered input ob2ect, hich e are using in this tutorial.
Note$ 7f you ish to use buffered input +meaning you get event callbacks to mouse/oved,
mouse!ressed, key?eleased, and so on,, then you must set the second parameter to create7nput.b2ect to
be true.
Setting 5' the *ramelistener
0o matter if you are using buffered or unbuffered input, every frame you must call the capture method on
all Feyboard, /ouse, and Soystick ob2ects you use. 7n this tutorial, the starting code already has done this.
4or unbuffered input, this is all you need to do. 1very frame you can call the various Feyboard and
/ouse functions to 9uery for the state of these ob2ects. 4or buffered input, e have slightly more ork to
do.
To use buffered input, you need to add a class to handle the input +or you could 2ust add code to the
4rameListener you have created,. The to things you need to do to set up buffered input +aside from
passing true to the create7nput.b2ect method, is to implement the appropriate listener interfaces and to
register the class youLve created as the event callback. Bou can see examples of doing this in the previous
tutorial specifically about buffered input. #ere is a class hich implements everything$
// ,on<t add this to the project
class Bu77ered<nput#andler : pu.lic O<S::Fe!0istener) pu.lic O<S::&ouse0istener)
pu.lic O<S::Zo!SticN0istener
{
pu.lic:
Bu77ered<nput#andler(O<S::Fe!.oard "Ne!.oard $ 2) O<S::&ouse "%ouse $ 2)
O<S::Zo!SticN "/o!sticN $ 2)
{
i7 (Ne!.oard)
Ne!.oard'(setvent-all.acN(this)*
i7 (%ouse)
%ouse'(setvent-all.acN(this)*
i7 (/o!sticN)
/o!sticN'(setvent-all.acN(this)*
}
// Ke*istener
virtual .ool Ne!4ressed(const O<S::Fe!vent Carg) { return true* }
virtual .ool Ne!,eleased(const O<S::Fe!vent Carg) { return true* }
// $ouse*istener
virtual .ool %ouse&oved(const O<S::&ousevent Carg) { return true* }
virtual .ool %ouse4ressed(const O<S::&ousevent Carg) O<S::&ouseButton<> id)
{ return true* }
virtual .ool %ouse,eleased(const O<S::&ousevent Carg) O<S::&ouseButton<>
id) { return true* }
// ;ostic"*istener
virtual .ool .utton4ressed(const O<S::Zo!SticNvent Carg) int .utton) {
return true* }
virtual .ool .utton,eleased(const O<S::Zo!SticNvent Carg) int .utton) {
return true* }
virtual .ool a@is&oved(const O<S::Zo!SticNvent Carg) int a@is) { return
true* }
}*
7 recommend that you implement only the listeners that you actually use though.
Troubleshooting Bu""ered $n'ut
7f you are not receiving buffered input like you think you should in your application, then there are a fe
things you should check before doing anything else$
'. "o the calls to 7nput/anager$$create7nput.b2ect set the buffered input flag +second parameter, to
trueM
%. #ave you called set1ventCallback on each buffered input ob2ectM
3. Are any other classes calling set1ventCallbackM +0ote that .7S only allos one event callback.
Bou cannot register more than one event callback for it.,
7f you have checked these three things, post your problem to the help forums.
%E#5$
C1;67 is a very flexible ;67 library hich integrates into .gre directly. <hile e ill not be using any
of C1;67Ls functionality in this application, 7 ill briefly go over ho to set it up for future applications.
C1;67 re9uires the ?ender<indo and the Scene/anager hich it ill render in.
+0.T1$ to correctly use C1;67 and compile the pro2ect source ithout error messages, add
C1;67-asePd.lib .gre;67?endererPd.lib to LinkerT7nputTAdditional "ependencies,
7nsert this code into the setupC1;67 function$
%,enderer $ C-8D<::Ogre,enderer::.ootstrapS!ste%()*
ThatLs it. 0o C1;67 is ready for you to use.
*inali;ing Startu' and the -ender ,oo'
*rame ,istener
-efore e start the render loop and have our application run, e need to add the frame listeners that the
application ill use. !lease note that 7 have already created a very simple 4rameListener called
1xitListener, hich aits for the 1scape key to be pressed to end the program. 7n your program you ill
probably have a lot more frame listeners doing much more complex things. Take a look at the
1xitListener and make sure you understand everything that is going on there, then add the folloing code
to the create4rameListener function$
%0istener $ ne? @it0istener(%Fe!.oard)*
%,oot'(add:ra%e0istener(%0istener)*
The -ender ,oo'
The last thing e need to do to start .gre is to start the render loop. .gre makes this very easy for us.
4ind the start?enderLoop function and add the folloing code$
%,oot'(start,endering()*
This ill render the application until a 4rameListener returns false. Bou can also pump a single frame and
ork in beteen each frame if you so choose. The ?oot$$render.ne4rame renders a frame and then
returns false if any 4rameListener returned false$
// ,o not add this to the application
?hile (%,oot'(renderOne:ra%e())
{
// ,o some things here, li"e sleep for ' milliseconds or perform
other actions#
// =owever, ma"e sure ou call the displa update function5
;indo?ventDtilities::%essage4u%p()*
}
#oever, in my opinion you should probably 2ust add hatever code you ould have put in that hile
loop to a 4rameListener instead. The only use 7 can think of to use this pattern is to sleep for a certain
number of milliseconds to artificially loer the framerate don to a set number. Bou generally ouldnLt
ant to do that in a 4rameListener because it messes ith the 4rame1vent$$timeSinceLast4rame variable.
O'tional /andling o" 0indo& E(ents
7f you ish to intercept certain <indo 1vents, you can add a <indo1ventListener instead of manually
checking in a message pump loop as shon above. 4or example$
// ,o not add this to the application
class ;in0istener : pu.lic ;indo?vent0istener
{
pu.lic:
;in0istener()
{
}
.ool ?indo?-losing(,ender;indo?" r?)
{
// ,isables standard e'it methods such as A*&-)> and the close
button
return 7alse*
}
}*
And then do this before calling m?oot-Tstart?endering+,$
// ,o not add this to the application
Scene&anager "%gr $ %,oot'(getScene&anager(">e7ault Scene&anager")*
,ender;indo? "?in $ %,oot'(getAuto-reated;indo?()*
;indo?ventDtilities::add;indo?vent0istener(?in) ne? ;in0istener())*
%leanu'
The last thing e have to orry about is cleaning up all of the ob2ects e have created hen the
application terminates. To do this, e ill basically delete or destroy all ob2ects in the reverse order of
their creation. <e ill start ith .7S, hich has specific functions that should be called to destroy its
ob2ects. 4ind the YApplication function and add the folloing code$
%<nput&anager'(destro!<nputO./ect(%Fe!.oard)*
O<S::<nput&anager::destro!<nputS!ste%(%<nput&anager)*
C1;67$
-8D<::Ogre,enderer::destro!S!ste%()*
4inally e need to delete the ?oot and 4rameListener ob2ects. The other ob2ects e have created +the
Scene/anager, the ?ender<indo and so on, ill be cleaned up hen e delete ?oot.
delete %0istener*
delete %,oot*
ThatLs it> Bou can no compile and run your application, though you ill only see a black screen since
e never added anything to the scene. 7f you have linker errors hen attempting to compile the
application, be sure that C1;67-asePd.lib and .gre;67?endererPd.lib are added to the input of the
linker +for debug mode, for release mode, remove the Pd on them,. Bou should no be familiar enough
ith .greLs startup process to use something other than the example frameork in your applications. 4or
the sake of simplicity, hoever, the tutorials ill continue to use the example frameork.
7f you are curious about other parts of the example frameork and ho it orks, see the in-depth tutorial
1xample 4rameork "emystified.
Mac OS <
Since /ac .S Q uses app bundles, a concept radically different from hat is used on <indos and
Linux, the code described above is going to crash on /ac .S Q.
Add the folloing function$
#i7 O8,940AT:O,& O8,940AT:O,&9A440
#include H-ore:oundationM-ore:oundation.h(
// &his function will locate the path to our application on OS ?,
// unli"e windows ou cannot rel on the current wor"ing director
// for locating our configuration files and resources#
std::string %acBundle4ath()
{
char pathAP25JB*
-:Bundle,e7 %ainBundle $ -:Bundle8et&ainBundle()*
assert(%ainBundle)*
-:D,0,e7 %ainBundleD,0 $ -:Bundle-op!BundleD,0(%ainBundle)*
assert(%ainBundleD,0)*
-:String,e7 c7String,e7 $ -:D,0-op!:ileS!ste%4ath( %ainBundleD,0)
N-:D,04OS<V4athSt!le)*
assert(c7String,e7)*
-:String8et-String(c7String,e7) path) P25J) N-:StringncodingAS-<<)*
-:,elease(%ainBundleD,0)*
-:,elease(c7String,e7)*
return std::string(path)*
}
#endi7
7n create?oot+,, change
%,oot $ ne? ,oot()*
to
#i7 O8,940AT:O,& O8,940AT:O,&9A440
%,oot $ ne? ,oot(%acBundle4ath() X "M-ontentsM,esourcesMplugins.c7g")*
#else
%,oot $ ne? ,oot()*
#endi7
7n define?esources+,, change
c7.load("resources.c7g")*
to
#i7 O8,940AT:O,& O8,940AT:O,&9A440
c7.load(%acBundle4ath() X "M-ontentsM,esourcesMresources.c7g")*
#else
c7.load("resources.c7g")*
#endi7
Also in define?esources+,, change
,esource8roup&anager::getSingleton().add,esource0ocation( arch+a%e) t!pe+a%e)
sec+a%e)*
to
#i7 O8,940AT:O,& O8,940AT:O,&9A440
,esource8roup&anager::getSingleton().add,esource0ocation( String(%acBundle4a
th() X "M" X arch+a%e)) t!pe+a%e) sec+a%e)*
#else
,esource8roup&anager::getSingleton().add,esource0ocation( arch+a%e)
t!pe+a%e) sec+a%e)*
#endi7
!roceed to -asic Tutorial : %E#5$ and Ogre
Basic Tutorial = :
%E#5$ and Ogre
Any problems you encounter hile orking ith this tutorial should be posted to the #elp 4orum .
rere!uisites
This tutorial assumes you have knoledge of C@@ programming and are able to setup and compile an
.gre application +if you have trouble setting up your application, see GSetting6pAnApplicationUthis
guideHH for specific compiler setups,. This tutorial builds on the previous beginner tutorials, and it
assumes you have already orked through them.
Table o" contents
!rere9uisites
7ntroduction
;etting Started
The 7nitial Code
Compile the Code
A -rief 7ntroduction
7ntegrating ith .gre
"efining C1;67 resource groups
7nitialiCing C1;67
7n2ecting Fey 1vents
Converting and 7n2ecting /ouse 1vents
<indos, Sheets, and <idgets
7ntroduction
Loading a Sheet
/anually creating an .b2ect
1vents
?ender to Texture
Conclusion
Alternatives
/ore 7nformation
$ntroduction
7n this tutorial e ill be exploring ho to use C1;67 ith .gre. -y the end of this tutorial you should
be able to add basic C1;67 functionality to your application. NOTE: This tutorial is not intended to fully
teach you ho to use C1;67. This tutorial is intended to get you started. All further C1;67 9uestions
and help should be directed to their home page .
/uch deeper and better explained C1;67 tutorials are found in its doxygen documentation ith the
C1;67 distribution or here on-line
Bou can find the code for this tutorial here. As you go through the tutorial you should be sloly adding
code to your on pro2ect and atching the results as e build it.
#etting Started
The $nitial %ode
7n this tutorial, e ill be using a predefined code base as a starting point. As long as you have orked
through the previous tutorials, this should all be familiar to you. Create a pro2ect in the compiler of your
choice for this pro2ect, and add a source file hich contains this code$
#include "@a%pleApplication.h"
#include HO<SMO<S.h(
#include H-8D<M-8D<.h(
#include H-8D<M,enderer&odulesMOgreM-8D<Ogre,enderer.h(
class Tutorial0istener : pu.lic @a%ple:ra%e0istener) pu.lic O<S::&ouse0istener)
pu.lic O<S::Fe!0istener
{
pu.lic:
Tutorial0istener(,ender;indo?" ?in) -a%era" ca%)
: @a%ple:ra%e0istener(?in) ca%) true) true)
{
%-ontinue$true*
%&ouse'(setvent-all.acN(this)*
%Fe!.oard'(setvent-all.acN(this)*
} // C@/U!,emo*istener
.ool 7ra%eStarted(const :ra%event Cevt)
{
%Fe!.oard'(capture()*
%&ouse'(capture()*
return %-ontinue CC E%Fe!.oard'(isFe!>o?n(O<S::F-9S-A4)*
}
.ool Luit(const -8D<::ventArgs Ce)
{
%-ontinue $ 7alse*
return true*
}
// $ouse*istener
.ool %ouse&oved(const O<S::&ousevent Carg)
{
return true*
}
.ool %ouse4ressed(const O<S::&ousevent Carg) O<S::&ouseButton<> id)
{
return true*
}
.ool %ouse,eleased(const O<S::&ousevent Carg) O<S::&ouseButton<> id)
{
return true*
}
// Ke*istener
.ool Ne!4ressed(const O<S::Fe!vent Carg)
{
return true*
}
.ool Ne!,eleased(const O<S::Fe!vent Carg)
{
return true*
}
private:
.ool %-ontinue*
}*
class -8D<>e%oApplication : pu.lic @a%pleApplication
{
pu.lic:
-8D<>e%oApplication()
{
}
~-8D<>e%oApplication()
{
-8D<::Ogre,enderer::destro!S!ste%()*
}
protected:
-8D<::Ogre,enderer "%,enderer*
void createScene(void)
{
}
void create:ra%e0istener(void)
{
%:ra%e0istener$ ne? Tutorial0istener(%;indo?) %-a%era)*
%:ra%e0istener'(sho?>e.ugOverla!(true)*
%,oot'(add:ra%e0istener(%:ra%e0istener)*
}
}*
#i7 O8,940AT:O,& EEO8,940AT:O,&9;<+=5
#de7ine ;<+=590A+9A+>9&A+
#include "?indo?s.h"
<+T ;<+A4< ;in&ain(#<+STA+- h<nst) #<+STA+-) 04ST, str-%d0ine) <+T)
#else
int %ain(int argc) char ""argv)
#endi7
{
// Create application object
-8D<>e%oApplication app*
tr! {
app.go()*
} catch(@ceptionC e) {
#i7 O8,940AT:O,& EEO8,940AT:O,&9;<+=5
&essageBo@A(+D00) e.get:ull>escription().c9str()) "An e@ception has
occurredE")
&B9OF G &B9<-O+,,O, G &B9TASF&O>A0)*
#else
7print7(stderr) "An e@ception has occurred: RsSn")
e.get:ull>escription().c9str())*
#endi7
}
return 2*
}
%om'ile the %ode
-e sure you can compile and run this code before continuing. The application should do nothing other
than present you ith a blank screen +press 1scape to exit,. 7f you have linker errors hen attempting to
compile the application, be sure that C1;67-asePd.lib and C1;67.gre?endererPd.lib are added to the
input of the linker +for debug mode= for release mode, remove the Pd on them,.
A Brie" $ntroduction
C1;67 is a fully featured ;67 library that can be embedded in 3" applications such as .gre +it also
supports .pen;L , "irectQ , and 7rrlicht backends,. /uch in the same ay that .gre is only a
graphics library +and doesnLt do other things such as sound, physics, etc,, C1;67 is only a ;67 library,
meaning it does not do its on rendering nor does it hook into any mouse or keyboard events. 7n fact, in
order for C1;67 to render at all, you have to provide a renderer for it +hich is the C1;67.gre?enderer
library shipped ith C1;67,, and in order for it to even understand mouse and keyboard events you have
to manually in2ect them into the system. This may seem like a pain at first, but in reality very little code is
re9uired to make this happen. 7t also allos you to have full control over the rendering and the input=
C1;67 ill never get in the ay.
There are many aspects to C1;67 and many 9uirks that ill be unfamiliar to you +even if you have used
;67 systems before,. 7 ill try to sloly introduce them to you as e go along.
$ntegrating &ith Ogre
+e"ining %E#5$ resource grou's
C1;67 like .gre has several types of resources it needs to function. 7t has several resource managers
+like .gre, hich need to find their respective resource locations. Thus, you need to define the necessary
resource groups and their locations ithin resources.cfg.
C1;67 distribution installs its resources to different locations depending on you platform. 4or usual
Linux install they all get installed into (usr(local(share(C1;67 or (usr(share(C1;67.
Add the folloing to resources.cfg$
A<%agesetsB
:ileS!ste%$MusrMlocalMshareM-8D<Mi%agesets
A:ontsB
:ileS!ste%$MusrMlocalMshareM-8D<M7onts
ASche%esB
:ileS!ste%$MusrMlocalMshareM-8D<Msche%es
A0ooN+:eelB
:ileS!ste%$MusrMlocalMshareM-8D<MlooNn7eel
A0a!outsB
:ileS!ste%$MusrMlocalMshareM-8D<Mla!outs
$nitiali;ing %E#5$
4ind the createScene function and add the folloing code$
%,enderer $ C-8D<::Ogre,enderer::.ootstrapS!ste%()*
0o that C1;67 has been initialiCed, e need to set the so-called default resource groups for each of
C1;67 resource managers.
Add the folloing$
-8D<::<%ageset::set>e7ault,esource8roup("<%agesets")*
-8D<:::ont::set>e7ault,esource8roup(":onts")*
-8D<::Sche%e::set>e7ault,esource8roup("Sche%es")*
-8D<::;idget0ooN&anager::set>e7ault,esource8roup("0ooN+:eel")*
-8D<::;indo?&anager::set>e7ault,esource8roup("0a!outs")*
As you see, e used those resource groups e defined ithin resources.cfg.
C1;67 is highly customiCable, and allos you to define the look and feel of your application by
changing its skin +scheme, in terms of C1;67,. <e ill not be covering ho to skin the library in any
tutorial, so if you ish to learn more about it, consult the C1;67 ebsite. The folloing line of code
selects the skin$
-8D<::Sche%e&anager::getSingleton().create("TahareO0ooN.sche%e")*
The next thing e need to do is set the default mouse cursor$
-8D<::S!ste%::getSingleton().set>e7ault&ouse-ursor("TahareO0ooN") "&ouseArro?")*
The first parameter specefies the 7mageset and the second one specifies the name of the 7mage to use
from that 7mageset.
Throughout this tutorial series e ill be using C1;67 to display the mouse cursor, even hen e have
no other use for the ;67 library. 7t is possible to use another ;67 library to render the mouse, or to
simply create your on mouse cursor using .gre directly +though this latter option can be a bit involved,.
7f you are only using C1;67 for the mouse cursor and are concerned about memory usage or the disk
space that your game takes up, you can look into one of these options to replace C1;67.
Lastly note that in that last code snippet e have set the default mouse cursor, but e did not set the
mouse cursor directly using the MouseCursor::setImage function as e ill in later tutorials. This
is because in this tutorial e ill alays be over some kind of C1;67 indo +though it may be
invisible,, so setting the default cursor ill, in effect, make the mouse cursor be the image e selected. 7f
e set the mouse cursor directly and did not set the default, the mouse cursor ould be invisible every
time it passed over a C1;67 indo +hich, in this tutorial, ill be all the time,. .n the other hand,
setting the default mouse image does nothing if you do not have any C1;67 indos displayed, as ill
be the case in later tutorials. 7n that situation, calling /ouseCursor$$set7mage ill display the cursor for
the application. 1xample$
-8D<::&ouse-ursor::getSingleton().set<%age( -8D<::S!ste%::getSingleton().get>e7
ault&ouse-ursor())*
$njecting 9ey E(ents
C1;67 does not handle input in any ay. 7t does not read mouse movements or keyboard input. 7nstead it
relies on the user to in2ect key and mouse events into the system. The next thing e ill need to do is to
handle the key events. 7f you are orking ith C1;67, you ill need to have the mouse and keyboard in
buffered mode so you can receive the events directly and in2ect them as they happen. 4ind the key!ressed
function and add the folloing code to it$
-8D<::S!ste% Cs!s $ -8D<::S!ste%::getSingleton()*
s!s.in/ectFe!>o?n(arg.Ne!)*
s!s.in/ect-har(arg.te@t)*
After getting the system ob2ect, e need to do to things. The first is to in2ect the key don event into
C1;67. The second is to in2ect the actual character that as pressed. 7t is very important to in2ect the
character properly since in2ecting the key don ill not alays bring about the desired result hen using
a non-1nglish keyboard. The in2ectChar as designed ith 6nicode support in mind.
0o e need to in2ect the key up event into the system. 4ind the key?eleased function and add the
folloing code$
-8D<::S!ste%::getSingleton().in/ectFe!Dp(arg.Ne!)*
0ote that e do not need to in2ect a character up event, only the key up event is re9uired.
%on(erting and $njecting Mouse E(ents
0o that e have finished dealing ith keyboard input, e need to take care of mouse input. <e have a
small issue that e ill need to address, hoever. <hen e in2ected the key up and don events into
C1;67 e never had to convert the key. -oth .7S and C1;67 use the same key codes for keyboard
input. The same is not true for mouse buttons. -efore e can in2ect mouse button presses into C1;67, e
ill need to rite a function hich converts .7S button 7"s into C1;67 button 7"s. Add the folloing
function near the top of your source code, 2ust before the TutorialListener class$
-8D<::&ouseButton convertButton(O<S::&ouseButton<> .utton<>)
{
s?itch (.utton<>)
{
case O<S::&B90e7t:
return -8D<::0e7tButton*
case O<S::&B9,ight:
return -8D<::,ightButton*
case O<S::&B9&iddle:
return -8D<::&iddleButton*
de7ault:
return -8D<::0e7tButton*
}
}
0o e are ready to in2ect mouse events. 4ind the mouse!ressed function and add the folloing code$
-8D<::S!ste%::getSingleton().in/ect&ouseButton>o?n(convertButton(id))*
This should be roughly self-explanatory. <e convert the button 7" hich as passed in, and pass the
result to C1;67. 4ind the mouse?eleased function and add this line of code$
-8D<::S!ste%::getSingleton().in/ect&ouseButtonDp(convertButton(id))*
Lastly, e need to in2ect mouse motion into C1;67. The C1;67$$System ob2ect has an
in2ect/ouse/ove function hich expects relative mouse movements. The .7S$$mouse/oved handler
gives us those relative movements in the state.Q.rel variable and the state.B.rel variables. 4ind the
mouse/oved function and add the folloing code$
-8D<::S!ste%::getSingleton().in/ect&ouse&ove(arg.state.V.rel) arg.state.T.rel)*
// Scroll wheel#
i7 (arg.state.U.rel)
%S!ste%'(in/ect&ouse;heel-hange(arg.state.U.rel M P52.27)*
'%& is a sort of Lmagical numberL used by /icrosoft back in the days and pretty much in noadays
systems. .7S uses the same magical number. ;L6T, for example, does not use it. ;oogle to find out
more.
ThatLs it. 0o C1;67 is fully set up and receiving mouse and keyboard events.
0indo&s, Sheets, and 0idgets
$ntroduction
C1;67 is very different from most ;67 systems. 7n C1;67, everything that is displayed is a subclass of
the C1;67$$<indo class, and a indo can have any number of children indos. This means that
hen you create a frame to contain multiple buttons, that frame is a <indo. This also leads to some
strange things to happen. Bou can place a button inside another button, though that ould really never
happen in practice. The reason that 7 mention all of this is hen you are looking for a particular idget
that you have placed in the application, they are all called <indos, and are accessed by functions hich
call them as such.
7n most practical uses of C1;67, you ill not create each individual ob2ect through code. 7nstead you
create a ;67 layout for your application in an editor such as the C1;67 Layout 1ditor. After placing all
of your indos, buttons, and other idgets onto the screen as you like them, the editor saves the layout
into a text file. Bou may later load this layout into hat C1;67 calls a ;67 sheet +hich is also a
subclass of C1;67$$<indo,.
Lastly, kno that C1;67 contains a large number of idgets that you can use in your application. <e
ill not cover them in this tutorial, so if you decide to use C1;67, be sure to take a good look at their
ebsite for more information.
,oading a Sheet
7n C1;67 loading a sheet is very easy to do. The <indo/anager class provides a
Dload<indoLayoutD function hich loads the sheet and puts it into a C1;67$$<indo ob2ect. Then you
call C1;67$$System$$set;67Sheet to display it. <e ill not be using this in this tutorial, but 7 ould feel
remiss if 7 did not at least sho you an example of its use. "o not add this to the tutorial +or if you do,
remove it after you have seen the results,$
// ,o not add this to the program
-8D<::;indo? "gui,oot $
-8D<::;indo?&anager::getSingleton().load;indo?0a!out("Te@t>e%o.la!out")*
-8D<::S!ste%::getSingleton().set8D<Sheet(gui,oot)*
This sets the sheet currently being displayed. Bou can later retrieve this sheet by calling
System$$get;67Sheet. Bou can also sap the ;67 sheet seamlessly by calling set;67Sheet ith
hatever sheet you ant to sap to +though be sure to hold onto a pointer to the current sheet if you ish
to sap it back,.
Manually creating an Object
As 7 said before, most of the time you use C1;67, you ill be using ;67 sheets that you create using an
editor. .ccasionally, hoever, you ill need to manually create a idget to put on the screen. 7n this
example, e ill be adding a Nuit button hich e ill later add functionality to. Since e ill be
adding more than 2ust the Nuit button to the screen by the time the tutorial is over, e need to first create
a default C1;67$$<indo hich ill contain all of the idgets e ill be creating. Add this to the end
of the createScene function$
-8D<::;indo?&anager C?%gr $ -8D<::;indo?&anager::getSingleton()*
-8D<::;indo? "sheet $ ?%gr.create;indo?(">e7ault;indo?") "-8D<>e%oMSheet")*
This uses the <indo/anager to create a D"efault<indoD called DC1;67"emo(SheetD. <hile e
could name the indo anything e like, itLs very common +and encouraged, to name the idget in a
hierarchical manner such as DSomeApp(/ain/enu(Submenu3(Cancel-uttonD. The next thing e need to
do is to create the Nuit button and set its siCe$
-8D<::;indo? "Luit $ ?%gr.create;indo?("TahareO0ooNMButton")
"-8D<>e%oMYuitButton")*
Luit'(setTe@t("Yuit")*
Luit'(setSiOe(-8D<::D1ector5(-8D<::D>i%(2.P3) 2)) -8D<::D>i%(2.23) 2)))*
This is very close to being cryptic. C1;67 uses a Dunified dimensionD system for its siCes and positions.
<hen setting the siCe you must create a 6"im ob2ect to tell it hat siCe it should be. The first parameter
is the relative siCe of the ob2ect in relation to its parent. The second parameter is the absolute siCe of the
ob2ect +in pixels,. The important thing to realiCe is that you are only supposed to set one of the to
parameters to 6"im. The other parameter must be &. So in this case e have made a button hich is '8Z
as ide as its parent and 8Z as tall. 7f e anted to specify that it should be %& pixels by 8 pixels, e
ould do that by setting the second parameter in both of the 6"im calls to be %& and 8 respectively.
The last thing e have to do is attach the Nuit button to the sheet e have created, and then set the current
;67 sheet for the system to be that sheet$
sheet'(add-hild;indo?(Luit)*
-8D<::S!ste%::getSingleton().set8D<Sheet(sheet)*
0o if you compile and run your application you ill see a Nuit button in the top left hand corner of the
screen, but it does not yet do anything hen you click on it.
E(ents
1vents in C1;67 are very flexible. 7nstead of using an interface that you implement to receive events, it
uses a callback mechanism hich binds any public function +ith the appropriate method signature, to be
the event handler. 6nfortunately this also means that registering events is a bit more complicated than it is
for .gre. <e ill no register to handle the Nuit buttonLs click event to exit the program hen it is
pressed. To do that, e ill first need a pointer to the Nuit button e created in the previous section. 4ind
the TutorialListenerLs constructor and add the folloing code$
-8D<::;indo?&anager C?%gr $ -8D<::;indo?&anager::getSingleton()*
-8D<::;indo? "Luit $ ?%gr.get;indo?("-8D<>e%oMYuitButton")*
0o that e have a pointer to the button, e no ill subscribe to the clicked event. 1very idget in
C1;67 has a set of events that it supports, and they all begin ith D1ventD. #ere is the code to subscribe
to the event$
Luit'(su.scri.event(-8D<::4ushButton::vent-licNed)
-8D<::vent::Su.scri.er(CTutorial0istener::Luit) this))*
The first parameter to subscribe1vent is the event itself. The second parameter is an 1vent$$Subscriber
ob2ect. <hen creating a Subcriber ob2ect, the first thing e pass in is a pointer to the function that ill
handle the event +note the X symbol hich gives us the pointer to the function,. The second thing e pass
to subscriber is the TutorialListener ob2ect hich ill handle the event +hich is the DthisD ob2ect,. ThatLs
it> .ur TutorialListener$$9uit function +hich has already been defined, ill handle the mouse click and
terminate the program.
%om'ile and run your a''lication to test this out.
.ne thing to note is that e can create any number of functions to handle events for C1;67. The only
restriction on them is that they must return a bool and they must take in a single parameter of type Dconst
C1;67$$1ventArgs XD. 4or more information about events +and ho to unsubscribe from them,, be sure
to read more on the C1;67 ebsite.
-ender to Te)ture
.ne of the more interesting things e can do ith C1;67 is to create a render to texture indo +full
G?TTU?TT TutorialHH,. This allos us to create a second Aieport hich can be rendered directly into a
C1;67 idget. To do this, e first need to set up a scene for us to look at. Add the folloing code to the
bottom of the createScene function$
%Scene&gr'(setA%.ient0ight(-olour1alue(P) P) P))*
%Scene&gr'(setSN!>o%e(true) "@a%plesM-loud!SN!") 3) 6)*
ntit!" ogre#ead $ %Scene&gr'(createntit!("#ead") "ogrehead.%esh")*
Scene+ode" head+ode $ %Scene&gr'(get,ootScene+ode()'
(create-hildScene+ode(1ector=(2) 2) '=22))*
head+ode'(attachO./ect(ogre#ead)*
0o e must create the ?enderTexture. The ?enderSystem ob2ect provides the functionality to render to
a texture. To do this e create a texture ith the Texture/anager$$create/anual function. 4or this
program e ill create a 8'% x 8'% texture$
Te@ture4tr te@ $ %,oot'(getTe@ture&anager()'(create&anual(
",TT")
,esource8roup&anager::>:AD0T9,SOD,-98,OD49+A&)
TV9TT495>)
3P5)
3P5)
2)
4:9,686B6)
TD9,+>,TA,8T)*
,enderTe@ture "rte@ $ te@'(getBu77er()'(get,enderTarget()*
See the A!7 reference for more information on this function. 0ext e need to create a Camera and a
Aieport to look at the scene e have created. 0ote that e have changed a couple of Aieport options,
including turning off .verlays...hich is very important to do or you ill get C1;67 and .gre overlays
ithin our mini-indo.
-a%era "ca% $ %Scene&gr'(create-a%era(",TT-a%")*
ca%'(set4osition(P22) 'P22) 'J22)*
ca%'(looNAt(2) 2) '=22)*
1ie?port "v $ rte@'(add1ie?port(ca%)*
v'(setOverla!sna.led(7alse)*
v'(set-learver!:ra%e(true)*
v'(setBacNground-olour(-olour1alue::BlacN)*
0ote that e have added the Aieport to the texture itself +as opposed to the ?ender<indo, hich is
here e usually add Aieports,. 0o that e have created our scene and our texture, e need to embed
it ithin C1;67. Bou can create a C1;67$$Texture from any .gre texture by calling the
C1;67$$.gre?enderer$$createTexture function$
-8D<::Te@ture CguiTe@ $ %,enderer'(createTe@ture(te@)*
6nfortunately, this is here things get complicated. 7n C1;67 you never 2ust deal ith a single Texture
or a single image. C1;67 orks ith image sets instead of individual images. 7t is very useful to ork
ith entire grids of images hen you are trying to define the look and feel of a skin you are creating +for
example, take a look at TahareCLook.tga in the datafiles(imagesets folder of the C1;67 S"F to see hat
an image set looks like,. #oever, even hen you are only trying to define a single image, you must
create an entire image set for it. This is hat e ill be doing$
-8D<::<%ageset Ci%ageSet $
-8D<::<%ageset&anager::getSingleton().create(",TT<%ageset") guiTe@)*
i%ageSet.de7ine<%age(",TT<%age")
-8D<::4oint(2.27) 2.27))
-8D<::SiOe(guiTe@.getSiOe().d9?idth)
guiTe@.getSiOe().d9height))
-8D<::4oint(2.27) 2.27))*
The first line creates the image set +called D?TT7magesetD, from the texture that e have provided it. The
next line +hich calls define7mage,, specifies that the first and only image is called D?TT7mageD and it is
as large as the entire guiTex texture e have provided. 4inally e need to create the Static7mage idget
hich ill house the render texture. The first part is no different from creating any other indo$
-8D<::;indo? "si $
-8D<::;indo?&anager::getSingleton().create;indo?("TahareO0ooNMStatic<%age")
",TT;indo?")*
si'(setSiOe(-8D<::D1ector5(-8D<::D>i%(2.37) 2))
-8D<::D>i%(2.J7) 2)))*
si'(set4osition(-8D<::D1ector5(-8D<::D>i%(2.37) 2))
-8D<::D>i%(2.27) 2)))*
0o e need to specify hich image this Static7mage idget ill display. .nce again, since C1;67
alays deals ith image sets and not individual images, e must no retrieve the exact image name from
the image set, and to display it$
si'(set4ropert!("<%age")
-8D<::4ropert!#elper::i%ageToString(Ci%ageSet.get<%age(",TT<%age")))*
7f it seems like e have packed a texture into an image set only to unpack it again, itLs because thatLs
exactly hat e have done. /anipulating images in C1;67 is not one of the easiest or most
straightforard things in the library. The last thing e need to do is to add the Static7mage idget to the
;67 sheet e created earlier$
sheet'(add-hild;indo?(si)*
0o e are finished. Compile and run the application.
%onclusion
Alternati(es
#ere are a fe alternatives to C1;67$
Nuick;67
-eta;67
/y;67
0avi
?ight -rain ;ames ;67
More $n"ormation
There are also several other places you can get more information about C1;67M.
!ractical Application - Something <ith A -it /ore /eat - A more in-depth tutorial than the one
here.
C1;67Ls .fficial Tutorials
The C1;67 <ebsite
!roceed to -asic Tutorial * #sing -ultiple Scene-anagers
Basic Tutorial > :
Multi'le and +ual SceneManagers
Any problems you encounter hile orking ith this tutorial should be posted to the #elp 4orum .
$ntroduction
7n this short tutorial e ill be covering ho to sap beteen multiple scene managers.
Bou can find the code for this tutorial here. As you go through the tutorial you should be sloly adding
code to your on pro2ect and atching the results as e build it.
Table o" contents
!rere9uisites
Setting up the Application
Creating the Scene/anagers
Creating the Cameras
Creating the Aieports
Creating the Scene
Adding 4unctionality
"ual Scene/anagers
Sapping Scene/anagers
Conclusion
.verlays
.ne Last 0ote
rere!uisites
Create a cpp file in the 7"1 of your choice and add the folloing code to it$
#include "@a%pleApplication.h"
#de7ine -A&,A9+A& "Scene-a%era"
void setup1ie?port(,ender;indo? "?in) Scene&anager "curr)
{
}
void dual1ie?port(,ender;indo? "?in) Scene&anager "pri%ar!) Scene&anager
"secondar!)
{
}
class S&Tutorial0istener : pu.lic @a%ple:ra%e0istener) pu.lic O<S::Fe!0istener
{
pu.lic:
S&Tutorial0istener(,ender;indo?" ?in) Scene&anager "pri%ar!) Scene&anager
"secondar!)
: @a%ple:ra%e0istener(?in) pri%ar!'(get-a%era(-A&,A9+A&)) true)
7alse))
%4ri%ar!(pri%ar!)) %Secondar!(secondar!)) %>ual(7alse)) %-ontinue(true)
{
%Fe!.oard'(setvent-all.acN(this)*
}
.ool 7ra%eStarted(const :ra%eventC evt)
{
%Fe!.oard'(capture()*
return %-ontinue*
}
.ool Ne!4ressed(const O<S::Fe!vent Carg)
{
s?itch (arg.Ne!)
{
case O<S::F-9S-A4:
%-ontinue $ 7alse*
.reaN*
de7ault:
.reaN*
}
return true*
}
.ool Ne!,eleased(const O<S::Fe!vent C) {return true*}
private:
Scene&anager "%4ri%ar!) "%Secondar!*
.ool %>ual) %-ontinue*
static void s?ap(Scene&anager "C7irst) Scene&anager "Csecond)
{
Scene&anager "t%p $ 7irst*
7irst $ second*
second $ t%p*
}
}*
class S&TutorialApplication : pu.lic @a%pleApplication
{
pu.lic:
S&TutorialApplication()
{
}
~S&TutorialApplication()
{
}
protected:
Scene&anager "%4ri%ar!) "%Secondar!*
void chooseScene&anager(void)
{
}
void create-a%era()
{
}
void create1ie?ports()
{
}
void createScene(void)
{
}
void create:ra%e0istener(void)
{
%:ra%e0istener $ ne? S&Tutorial0istener(%;indo?) %4ri%ar!) %Secondar!)*
%:ra%e0istener'(sho?>e.ugOverla!(true)*
%,oot'(add:ra%e0istener(%:ra%e0istener)*
}
}*
#i7 O8,940AT:O,& $$ O8,940AT:O,&9;<+=5
#de7ine ;<+=590A+9A+>9&A+
#include "?indo?s.h"
<+T ;<+A4< ;in&ain(#<+STA+- h<nst) #<+STA+-) 04ST, str-%d0ine) <+T)
#else
int %ain(int argc) char ""argv)
#endi7
{
// Create application object
S&TutorialApplication app*
tr! {
app.go()*
} catch(@ceptionC e) {
#i7 O8,940AT:O,& $$ O8,940AT:O,&9;<+=5
&essageBo@A(+D00) e.get:ull>escription().c9str()) "An e@ception has
occurredE") &B9OF G &B9<-O+,,O, G &B9TASF&O>A0)*
#else
7print7(stderr) "An e@ception has occurred: RsSn")
e.get:ull>escription().c9str())*
#endi7
}
return 2*
}
-e sure you can compile this code before continuing, but do not attempt to run the program at this point.
Setting u' the A''lication
%reating the SceneManagers
<e have previously covered ho to select your Scene/anager, so 7 ill not go into detail about this
function. The only thing e have changed is that e are creating to of them. 4ind the
chooseScene/anager function and add the folloing code$
%4ri%ar! $ %,oot'(createScene&anager(ST98+,<-) "pri%ar!")*
%Secondar! $ %,oot'(createScene&anager(ST98+,<-) "secondar!")*
%reating the %ameras
The next thing e need to do is create a Camera ob2ect for each of the to Scene/anagers. The only
difference from previous tutorials is that e are creating to of them, ith the same name. 4ind the
createCamera function and add the folloing code$
%4ri%ar!'(create-a%era(-A&,A9+A&)*
%Secondar!'(create-a%era(-A&,A9+A&)*
%reating the .ie&'orts
7n creating the Aieport for this application, e ill be taking a small departure from previous tutorials.
<hen you create a Aieport, you must do to things$ setup the Aieport itself and then set the aspect
ratio of the camera you are using. To begin ith, add the folloing code to the createAieports function$
setup1ie?port(%;indo?) %4ri%ar!)*
The actual code for setting up the Aieport resides in this setupAieport function since e ill use this
code again elsehere. The first thing e need to do is remove all the previously created Aieports. 0one
have been created yet, but hen e call this function again later, e ill need to make sure that they are
all removed before creating ne ones. After that e ill setup the Aieports 2ust like e have in
previous tutorials. Add the folloing code to the setupAieport function at the top of the file$
?in'(re%oveAll1ie?ports()*
-a%era "ca% $ curr'(get-a%era(-A&,A9+A&)*
1ie?port "vp $ ?in'(add1ie?port(ca%)*
vp'(setBacNground-olour(-olour1alue(2)2)2))*
ca%'(setAspect,atio(,eal(vp'(getActual;idth()) M ,eal(vp'(getActual#eight()))*
%reating the Scene
Lastly, e need to create a scene for each Scene/anager to contain. <e onLt make anything complex,
2ust something different so that e kno hen e have sapped beteen the to. 4ind the createScene
function and add the folloing code$
// Setup the &errainScene$anager
%4ri%ar!'(setSN!Bo@(true) "@a%plesMSpaceSN!Bo@")*
// Setup the /eneric Scene$anager
%Secondar!'(setSN!>o%e(true) "@a%plesM-loud!SN!") 3) 6)*
-e sure your code compiles before continuing. Bou may run the program at this point, but it currently has
no functionality other than exiting hen you press 1scape.
Adding *unctionality
+ual SceneManagers
The first piece of functionality e ant to add to the program is to allo the user to render both
Scene/anagers side by side. <hen the A key is pressed e ill toggle dual Aieport mode. The basic
plan for this is simple. To turn off dual Aieport mode, e simply call setupAieport +hich e created
in the previous section, ith the primary Scene/anager to recreate the Aieport in single mode. <hen
e ant to turn it on, e ill call a ne function called dualAieport. <e ill keep track of the state of
the Aieport ith the m"ual variable. Add the folloing code to the sitch in the key!ressed function$
case O<S::F-91:
%>ual $ E%>ual*
i7 (%>ual)
dual1ie?port(%;indo?) %4ri%ar!) %Secondar!)*
else
setup1ie?port(%;indo?) %4ri%ar!)*
.reaN*
0o e have sapped the m"ual variable and called the appropriate function based on hich mode e
are in. 0o e ill define the dualAieport function hich actually contains the code to sho to
Aieports at once.
7n order to display to Scene/anagers side by side, e basically do the same thing e have already done
in the setupAieport function. The only difference is that e ill create to Aieports, one for each
Camera in our Scene/anagers. Add the folloing code to the dualAieport function$
?in'(re%oveAll1ie?ports()*
1ie?port "vp $ 2*
-a%era "ca% $ pri%ar!'(get-a%era(-A&,A9+A&)*
vp $ ?in'(add1ie?port(ca%) 2) 2) 2) 2.3) P)*
vp'(setBacNground-olour(-olour1alue(2)2)2))*
ca%'(setAspect,atio(,eal(vp'(getActual;idth()) M ,eal(vp'(getActual#eight()))*
ca% $ secondar!'(get-a%era(-A&,A9+A&)*
vp $ ?in'(add1ie?port(ca%) P) 2.3) 2) 2.3) P)*
vp'(setBacNground-olour(-olour1alue(2)2)2))*
ca%'(setAspect,atio(,eal(vp'(getActual;idth()) M ,eal(vp'(getActual#eight()))*
All of this should be familiar except for the extra parameters e have added to the addAieport function
call. The first parameter to this function is still the Camera e are using. The second parameter is the C
order of the Aieport. A higher C order sits on top of the loer C orders. 0ote that you cannot have to
Aieports ith the same C order, even if they do not overlap. The next to parameters are the left and top
positions of the Aieport, hich must be beteen & and '. 4inally, the last to parameters are the idth
and the height of the Aieport as a percentage of the screen +again, they must be beteen & and ',. So in
this case, the first Aieport e create ill be at the position +&, &, and ill take up half of the screen
horiContally and all of the screen vertically. The second Aieport ill be at position +&.8, &, and also take
up half the horiContal space and all of the vertical space.
Compile and run the application. -y pressing A you can no display to Scene/anagers at the same
time.
S&a''ing SceneManagers
The last piece of functionality e ant to add to our program is to sap the Scene/anagers henever the
C key is pressed. To do that, e ill first sap the m!rimary and mSecondary variables so that hen the
setupAieport or dualAieport functions are called, e never need to orry about hich Scene/anager
is in hich variable. The primary Scene/anager ill alays be displayed in single mode, and the
primary ill alays be on the left side in dualAieport mode. Add the folloing code to the sitch in the
key!ressed function$
case O<S::F-9-:
s?ap(%4ri%ar!) %Secondar!)*
i7 (%>ual)
dual1ie?port(%;indo?) %4ri%ar!) %Secondar!)*
else
setup1ie?port(%;indo?) %4ri%ar!)*
.reaN*
After sapping the variables, e perform the change. All e have to do is call the appropriate Aieport
setup function depending on hether e are in dual or single mode.
ThatLs it> Compile and run the application. <e can no sap the Scene/anagers ith the C key, and
sap single and dual mode ith the A key.
%onclusion
O(erlays
7Lm sure you have noticed in your program that hen you run in dual Aieport mode, the .gre debug
.verlay shos up on both sides. Bou may turn off .verlay rendering on a per-Aieport basis. 6se the
Aieport$$set.verlays1nabled function to turn them on and off. 7 have made this relatively simple change
to the full source of this tutorial, so if you are confused as to ho this is done, see that page for the
details.
One ,ast Note
Alays keep in mind that the Aieport class, hile not having a lot of functionality itself, is the key to all
.gre rendering. 7t doesnLt matter ho many Scene/anagers you create or ho many Cameras in each
Scene/anager, none of them ill be rendered to the indo unless you setup a Aieport for each
Camera you are shoing. Also donLt forget to clear out Aieports you are not using before creating more.
Contirbuters$
Tutorial '$ 2acmoe , peters , Subei , Sacob/ and Emmentaler .
Tutorial %$ peters , Tp , Sacob/ and 2acmoe .
Tutorial 3$ 2acmoe , peters , Sacob/ and #arkathmaker .
Tutorial 5$ peters , Sacob/ , 2acmoe and #arkathmaker .
Tutorial 8$ peters , Sacob/ , 2acmoe and #arkathmaker .
Tutorial )$ 2acmoe , peters and #arkathmaker .
Tutorial :$ 2acmoe , peters and #arkathmaker .
Tutorial *$ peters , Spacegaier and 2acmoe .
!"4 Convert$ #iroki 6tsunomiya

You might also like