tag:blogger.com,1999:blog-69585339292858608742024-03-18T03:03:55.885+00:00Jon's Teapotlots of random code, usually involving the drawing of a teapot.Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.comBlogger91125tag:blogger.com,1999:blog-6958533929285860874.post-69892008708604848782015-10-02T11:23:00.001+01:002015-10-02T11:23:50.305+01:00New Image Class<span style="font-size: large;">ngl::Image Class</span><br />
<br />
I've been meaning to update the ngl::Texture class for a while, a lot of time the texture class is used to load and image then load it into an OpenGL texture. Sometimes we just want an image and not access to OpenGL.<br />
<br />
I've just split the two classes to have a separate image class and the Texture class is now much simpler (and in some cases can be ignored). To allow the loading of different images I've usually used the QImage class in Qt, this works really well and is simple to use, however sometimes I port my code to platforms that don't use Qt (raspberry pi for example) and I have to use another library. To this end I decided to support 3 different loading libraries <a href="http://doc.qt.io/qt-4.8/qimage.html">QImage</a> (the default), <a href="http://www.imagemagick.org/script/index.php">ImageMagick</a> and <a href="https://github.com/OpenImageIO/oiio">Open Image I/O</a>.<br />
<br />
The code to load the images is quite simple, and uses a <a href="http://www.boost.org/doc/libs/1_57_0/libs/smart_ptr/scoped_array.htm">boost::scoped_array</a> to store the data as a contiguous block of unsigned char data that OpenGL can use as texture data.<br />
<br />
The source code can be seen in <a href="https://github.com/NCCA/NGL/blob/master/src/Image.cpp">Image.cpp</a> and <a href="https://github.com/NCCA/NGL/blob/master/include/ngl/Image.h">Image.h</a> and the video below shows how to change the Qt Project to set the image library to use.<br />
<br />
<iframe allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/O6CtzsdghrA" width="420"></iframe>
Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com0tag:blogger.com,1999:blog-6958533929285860874.post-14144766708901182502014-11-21T15:01:00.000+00:002014-11-21T15:02:56.781+00:00Using Qt Library templatesThe following video shows how to configure a Qt project to create a static library to use in your own projects, the main code for this can be found on github <a href="https://github.com/NCCA/LoggerLib">here</a>
<br />
<br />
The main things you will need to do are in the .pro file as follows<br />
<br />
<pre class="brush:cpp" title=".pro file">TEMPLATE = lib
CONFIG+=staticlib
</pre>
<br />
If you omit the staticlib it will create a dynamic library and the runtime linker will need to be told where to find your lib.<br />
<br />
In the project you intend to use the library in you need to set the LIBS Qt variable passing in the -L[path to lib] and -l lib(s) to link<br />
<br />
<iframe width="420" height="315" src="//www.youtube.com/embed/Av4zSGWA7V0" frameborder="0" allowfullscreen></iframe>
<br />
For more examples of this see <a href="http://jonmacey.blogspot.co.uk/2012/11/libraries-include-paths-and-other-linux.html">this blog post</a><br />
<br />
<br />
<br />
<br />Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com0tag:blogger.com,1999:blog-6958533929285860874.post-10558846754714108282014-11-04T15:50:00.000+00:002014-11-04T16:30:22.887+00:00Drawing with Modern OpenGLThe following video demonstrate how modern OpenGL uses <a href="https://www.opengl.org/sdk/docs/man3/xhtml/glGenVertexArrays.xml">Vertex Array Objects</a> to store buffers and generic vertex attributes together for faster drawing.<br />
<br />
The first Video shows how the deprecated immediate mode OpenGL version would work as context for why we use Modern OpenGL.<br />
<br />
The next videos show the basic framework code using <a href="https://github.com/NCCA/NGL">ngl</a> and a simple colour shader. The first demo will then use OpenGL calls to create and display a series of points. The second uses the ngl::VertexArrayObject class to do the same thing. The source code can be found <a href="https://github.com/NCCA/SimpleDrawing">here</a> and suggested man pages are <a href="https://www.opengl.org/sdk/docs/man3/xhtml/glGenVertexArrays.xml">glGenVertexArrays</a> <a href="https://www.opengl.org/sdk/docs/man3/xhtml/glBindVertexArray.xml">glBindVertexArray</a> <a href="https://www.opengl.org/sdk/docs/man3/xhtml/glBindVertexArray.xml">glGenBuffers</a> <a href="https://www.opengl.org/sdk/docs/man3/xhtml/glBufferData.xml">glBufferData</a> <a href="https://www.opengl.org/sdk/docs/man/html/glVertexAttribPointer.xhtml">glVertexAttribPointer</a> <a href="https://www.opengl.org/sdk/docs/man3/xhtml/glDrawArrays.xml">glDrawArrays</a><br />
<br />
<iframe width="420" height="315" src="//www.youtube.com/embed/nRm-szvVUP8" frameborder="0" allowfullscreen></iframe>
<br />
<iframe width="420" height="315" src="//www.youtube.com/embed/uX56LM_1QDY" frameborder="0" allowfullscreen></iframe>
<br/>
<iframe width="420" height="315" src="//www.youtube.com/embed/LcRLD1J7Jp4" frameborder="0" allowfullscreen></iframe>Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com0tag:blogger.com,1999:blog-6958533929285860874.post-13089541545412127422014-03-21T10:46:00.001+00:002014-03-21T10:46:53.735+00:00Using emscripten to port NGL to the Web<h2>
Introduction</h2>
<div>
I have been using the <a href="http://nccastaff.bournemouth.ac.uk/jmacey/GraphicsLib/" target="_blank">ngl:: library</a> for many years as part of teaching various graphic programming courses. I decided recently it would be interesting to port the core library and many of the demos to work interactively on the web using <a href="http://www.khronos.org/webgl/" target="_blank">WebGL</a> so started investigating a number of ways to do this. The main library is written in C++ and uses either Qt or SDL to create the OpenGL context. </div>
<div>
I had a number of choices as to which approach to take, I could learn <a href="http://en.wikipedia.org/wiki/JavaScript" target="_blank">Java Script</a> and <a href="http://threejs.org/docs/index.html#Manual/Introduction/Creating_a_scene">three.js</a> however this would mean porting all my codebase to Java Script which seemed like too much work.</div>
<div>
In the end I came across the <a href="https://github.com/kripken/emscripten/wiki">emscripten</a> system which is a LLVM-to-JavaScript Compiler which can convert my C++ code into LLVM and then into JavaScript and then into <a href="http://asmjs.org/">asm.js</a> the process was quite a steep learning curve, however I manage to get quite a lot of demos ported very quickly which can be seen <a href="http://nccastaff.bournemouth.ac.uk/jmacey/WebGL/">here</a> the rest of the blog will outline the process and how the webngl system was developed.</div>
<h3>
Installing Emscripten</h3>
<div>
My main development environment is a mac, however I have also tested the files under linux and it also works well. To get started I followed the tutorial <a href="https://github.com/kripken/emscripten/wiki/Tutorial">here</a> and all worked first time. The next stage was to try a simple WebGL demo that is provided with the examples. There are several WebGL demos using different libraries for OpenGL context creation however as I'm most familiar with SDL I chose to use this as the basis of the framework.<br />
<br />
<h3>
A Simple SDL demo program</h3>
</div>
<div>
The following code is a simple SDL program (very similar to a normal SDL program) the only difference is the call to emscripten_set_main_loop.</div>
<div>
<br /></div>
<pre class="brush:cpp" title="a simple SDL framework">#include "SDL.h"
#include <GLES2/gl2.h>
#define GL_GLEXT_PROTOTYPES 1
#include <GLES2/gl2ext.h>
#include <emscripten.h>
#include <iostream>
#include <cstdlib>
void process()
{
// as we don't have a timer we need to do something here
// using a static to update at an interval
static int t=0;
if(++t > 100)
{
float r=(double)rand() / ((double)RAND_MAX + 1);
float g=(double)rand() / ((double)RAND_MAX + 1);
float b=(double)rand() / ((double)RAND_MAX + 1);
glClearColor(r,g,b,1);
t=0;
}
glClear(GL_COLOR_BUFFER_BIT);
// this is where we draw
SDL_GL_SwapBuffers();
}
int main(int argc, char *argv[])
{
SDL_Surface *screen;
// Init SDL
if ( SDL_Init(SDL_INIT_VIDEO) != 0 )
{
std::cerr<<"Unable to initialize SDL: "<<SDL_GetError();
return EXIT_FAILURE;
}
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
screen = SDL_SetVideoMode( 720, 576, 16, SDL_OPENGL | SDL_RESIZABLE);
if ( !screen )
{
std::cerr<<"Unable to set video mode: "<<SDL_GetError();
return EXIT_FAILURE;
}
glEnable(GL_DEPTH_TEST);
// let emscripten process something then
// give control back to the browser
emscripten_set_main_loop (process, 0, true);
SDL_Quit();
return EXIT_SUCCESS;
}
</pre>
The emscripten_set_main_loop function is explained very well <a href="https://github.com/kripken/emscripten/wiki/Emscripten-browser-environment#implementing-an-asynchronous-main-loop-in-cc">here</a> basically we create a function that is called asynchronously to allow the browser to regain control after every iteration of the function. It is important that this function does exit else the browser will hang up and I have had several times when I get a complete lockup of the system.
<br />
<h3>
Compiling the program</h3>
<div>
To compile the program we use the following command line (in this case I'm using c++ )</div>
<pre class="brush:cpp" title="compiling the code">em++ -s FULL_ES2=1 SDL1.cpp -o SDL1.html
</pre>
The flag -s <a href="https://github.com/kripken/emscripten/wiki/OpenGL-support">FULL_ES2</a> tells emscripten to use full OpenGL ES 2 specification when compiling the code, the -o SDL1.html will generate an html file as well as the javascript file for the canvas to use.
The html file can now be <a href="http://nccastaff.bournemouth.ac.uk/jmacey/WebGL/Blog1/SDL1.html">opened in the browser</a> an in this case you will see a screen that changes colour every 100 cycles of the main loop.
In the next post I will begin to discuss how I ported the rest of ngl to use emscripten.Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com0tag:blogger.com,1999:blog-6958533929285860874.post-3416285729473797692014-02-20T18:03:00.004+00:002014-02-20T18:03:47.188+00:00GamePlay 3D 101Another Guest post on my Blog, this time from Callum James and Ramesh Balachandran from the <a href="http://courses.bournemouth.ac.uk/courses/undergraduate-degree/software-development-for-animation-games-effects/none/1082/" target="_blank">BSc. Software Development for Animation, Games and Effects</a> course at the <a href="http://ncca.bournemouth.ac.uk/" target="_blank">NCCA</a><br />
<br />
<h2>
<b>What is Gameplay 3D? </b></h2>
<a href="http://gameplay3d.org/" target="_blank">Gameplay 3D</a> is an open-source, code based engine that is aimed at being cross-platform compatible. We decided to use this engine over others as we would have the most control over the features and optimisations of the program / game we create. Whilst giving you the tools to produce a simple piece of high quality in relatively little time, other game engines such as the <a href="http://www.unrealengine.com/udk/" target="_blank">Unreal Development Kit</a> , are restrictive to their scripting functionality and UI interaction. Therefore, by using an open-source engine that has an established rendering engine, we are able to extend upon and create a new version of the engine in our own desired way.<br />
<br />
<h3>
<div class="p1">
<b>Lack of Documentation</b></div>
<div class="p1">
<span style="font-weight: normal;"><span style="font-size: small;">One of the greatest obstacles we are still striving to overcome whilst using the Gameplay 3D engine is its lack of clear and precise documentation for its use. Whilst there exists basic documentation on the engine and classes, a lot of features found within the engine do not have any form of detailed information regarding their uses or function. The sections are ways we have found to set-up the game engine and use its features to hopefully serve as a 101 guide to getting started with Gameplay 3D. </span></span></div>
<div class="p1">
<span style="font-weight: normal;"><span style="font-size: small;"><br /></span></span></div>
</h3>
<h2>
<div class="p1">
<b>Our Preferred Gameplay 3D Setup</b></div>
<div class="p1">
<span style="font-size: small; font-weight: normal;">There are multiple ways you can use the Gameplay 3D engine on different platforms. By default, the engine comes with source and project files for Visual Studio on Windows and an XCode project for MacOSX. </span><span style="font-size: small; font-weight: normal;">It is then up to you to get an environment set up for a Linux build. However this makes it a little cumbersome to be easily platform independant for efficient development. We however have come up with a simple solution to make it as easy as possible to pass your project between all three major platforms and quickly get up and running for development.</span></div>
<div class="p1">
<span style="font-size: small; font-weight: normal;"><span class="Apple-tab-span"> </span>Whilst it would be ideal to have a single development project for all three platforms, due to our desire to support not only Windows 7 but also Windows 8, we have had to separate the Windows build to its own Visual Studio project. For Mac and Linux, we then have a single Qt Creator project (.pro file) that very easily compiles and runs on both of the Unix flavours.</span></div>
<div class="p1">
<span style="font-size: small; font-weight: normal;"><span class="Apple-tab-span"> </span>As the VS project file and the Qt project files all read from the same sources, cross platform development is still quick, easy and affects all platforms. To ensure this works however it is important to keep a strict directory hierarchy to your project so that no file gets lost and you keep independant local file paths to a minimum. </span></div>
<div class="p2">
<span style="font-size: small; font-weight: normal;"><br /></span></div>
<div class="p1">
</div>
<div class="p3">
<span style="font-size: small; font-weight: normal;">Following is a quick overview into how to set up Gameplay 3D on each of the three major platforms in the way we have discussed here. </span></div>
</h2>
<h3>
<div class="p1">
<b>Setting up Gameplay 3D on Unix - Linux and MacOSX</b></div>
<div class="p1">
<span style="font-weight: normal;"><span style="font-size: small;">Setting up Gameplay 3D to work on a Unix platform (either Linux or MacOSX) using Qt Creator, there are a few things you need to make sure are set and linked correctly. Here we will discuss what you need to ensure is set correctly and included in the .pro file so that your project will build and run successfully.</span></span></div>
<div class="p1">
<span style="font-weight: normal;"><span style="font-size: small;"><span class="Apple-tab-span"> </span>The first thing you need to look at is your include and library paths. You need to ensure that your include paths are at least set to ./include to pick up on your header files. </span></span></div>
<div class="p1">
</div>
<div class="p1">
<span style="font-weight: normal;"><span style="font-size: small;"><span class="Apple-tab-span"> </span>Other directories to include are:</span></span></div>
</h3>
<div class="p3">
<span style="font-size: small; font-weight: normal;"><br /></span></div>
<pre class="brush:cpp" title="include Directories">INCLUDEPATH += $$GAMEPLAY_DIR/gameplay/src
INCLUDEPATH += $$GAMEPLAY_DIR/gameplay/src/lua
INCLUDEPATH += $$GAMEPLAY_DIR/external-deps/bullet/include
INCLUDEPATH += $$GAMEPLAY_DIR/external-deps/lua/include
INCLUDEPATH += $$GAMEPLAY_DIR/external-deps/oggvorbis/include
INCLUDEPATH += $$GAMEPLAY_DIR/external-deps/png/include
</pre>
Libraries to link up to for your projects are as follows for Linux:
<br />
<pre class="brush:cpp" title="Linux Libs">unix:!macx{
LIBS += -L$$GAMEPLAY_DIR/external-deps/lua/lib/linux/x64/ -llua
LIBS += -L/usr/local/lib -lBulletCollision -lBulletDynamics -lLinearMath
LIBS += -L$$GAMEPLAY_DIR/external-deps/glew/lib/linux/x64/ -lGLEW
QMAKE_CXXFLAGS += $$system(pkg-config --cflags gtk+-2.0)
LIBS += -lgtk-x11-2.0 -lglib-2.0 -lgobject-2.0
LIBS += -L$$GAMEPLAY_DIR/external-deps/oggvorbis/lib/linux/x64/ -lvorbis -logg
LIBS+= -lrt -ldl -lpng -lopenal -lz -pthread -lGL -lX11
}
</pre>
And for MacOSX:
<br />
<pre class="brush:cpp" title="OSX Libs">macx:{
INCLUDEPATH+=/usr/local/include/
LIBS+= -L/usr/local/lib -lBulletDynamics -lBulletCollision -lLinearMath
LIBS+= -L/usr/local/lib -lpng
LIBS += -L/ext-deps/fmod/lib/macosx -lfmodex
LIBS += -framework Cocoa -framework GameKit -framework IOKit -framework QuartzCore -framework OpenGL -framework OpenAL
LIBS+= -llua -lvorbis -lvorbisfile -logg -lz -ldl -lpthread
}
</pre>
These are all the include paths and libraries you will need to get started. It is however important to note on Mac, you need to make sure you are linking against the right architecture for your build. The external dependency libraries supplied with the Gameplay 3D library are all 32 bit so if you want to build 64 bit projects you will need to recompile the external libraries as 64 bit and then link to these. You will the need to include in your .pro file the following:
<br />
<pre class="brush:cpp" title="Make Flags">macx:QMAKE_CXXFLAGS+= -arch x86_64
macx:CONFIG+=x86_64
</pre>
Secondly, local path set-up is vital to ensuring your project will run on all platforms without having to go through and change all of the paths to files and assets. The paths differ due to the way that the game is built on different platforms. On Linux (and Windows) it is built as a simple executable. Gameplay 3D built on OSX however utilises the MacOSX app bundle feature.
When compiling on Mac, the application will be built into the directory ./application_name.app/Contents/MacOS. This is also where it will be run from. However because the executable is run from here and not the root directory, any assets it requires are no longer visible to it. As such, all the required assets need to be copied into the correct directory for the application to find them. On Linux and Windows, this is simple as the executable will look from assets in a res/ folder from the root directory. So within your root directory as long as your assets are stored within a res folder, you will be fine. However on Mac, the files you require for the game need to be copied into the Resources folder into a folder called res. The gameplay engine will then pick up on these resources. The config files also go into the Resources folder (but not the res) folder. These can then be picked up and read by the application when run. In the .pro file, you just need to ensure all the files you require are passed to QMAKE_BUNDLE_DATA. So for example, to copy some splash screen images to the correct directory and use them with a local path, you need the following in your .pro file:
<br />
<pre class="brush:cpp" title="Splash Bundle">SPLASHIMAGES += res/splash/logo_powered_white.png
macx:{
APP_SPLASH_IMAGES.path = Contents/Resources/res/splash
APP_SPLASH_IMAGES.files += $$SPLASHIMAGES
QMAKE_BUNDLE_DATA += … \
APP_SPLASH_IMAGES \
… \
}
</pre>
Any other files you need also need to be added to QMAKE_BUNDLE_DATA in this manner, so for example to also add audio files, use:
<br />
<pre class="brush:cpp" title="Splash Bundle">QMAKE_BUNDLE_DATA += APP_AUDIO_FILES \
APP_SPLASH_IMAGES \
… \
</pre>
The Gameplay engine will automatically pick up on them when located in this directry, but anything you write yourself using paths needs to be prefixed. Adding ../Resources/ to the front of any local paths used in your code will ensure your game looks into the right folder on Mac. To automatically do this, we have developed a very simple function as below:
<br />
<pre class="brush:cpp" title="Mac Resource path settings">#ifdef DARWIN
#define PATH_PREFIX "../Resources/"
#else
#define PATH_PREFIX ""
#endif
std::string GeneralUtils::PLATFORM_FILE_PATH(std::string _path)
{
return (PATH_PREFIX+_path);
}
</pre>
The DARWIN define is set within the .pro file if the macx platform is detected, as follows:
<br />
<pre class="brush:cpp" title="Platform Specific Defines">unix:!macx: DEFINES += LINUX
macx: DEFINES += DARWIN
</pre>
If this is all set up correctly, then local paths will work on all platforms without any need to change them.
<br />
<br />
<h3>
<b>Setting up Gameplay 3D on Windows</b></h3>
The setup for programming with Gameplay 3D on Windows differs slightly from the Unix build. Due to the current operating system used for development on Windows (Windows 8.1 64-bit), there were issues in setting up Qt Creator to enable complete cross-platform programming. The IDE of choice was shifted to Visual Studio 2010. In order to set up the project to work with Unix build, the Visual Studio project settings need to be set up to correctly link to the Gameplay3D libraries as well as the correct Windows external dependencies.
To make sure this is done correctly, the engine needs to be built using the Visual Studio project file accompanying the engine. The Gameplay3D files are compiled for a 64-bit architecture of Windows to work alongside the 64-bit architecture setup of the OSX and Linux builds. Once this is compiled, the Visual Studio project needs to correctly link to the engine header files as well as the necessary external dependency files. This is done under Project -> Properties -> Configuration Properties -> C/C++ in the ‘Additional Include Directories’ section. In this section, the paths to all of the header files would be added:
<br />
<pre class="brush:cpp" title="lib directories">../../external-deps/lua/lib/windows/x64
../../external-deps/bullet/lib/windows/x64
../../external-deps/openal/lib/windows/x64
../../external-deps/oggvorbis/lib/windows/x64
../../external-deps/glew/lib/windows/x64
../../external-deps/png/lib/windows/x64
../../external-deps/zlib/lib/windows/x64
../../gameplay/windows/x64/$(Configuration)
ext-deps/fmod/lib/windows
</pre>
In addition to this the .lib files need to be explicitly linked under Linker -> Input in the ‘Additional Dependencies’ section:
<br />
<pre class="brush:cpp" title="adding the libs">lua.lib;OpenAL32.lib;OpenGL32.lib;GLU32.lib;glew32.lib;libpng14.lib;zlib.lib;gameplay.lib;libogg.lib;libvorbis.lib;libvorbisfile.lib;BulletDynamics.lib;BulletCollision.lib;LinearMath.lib;fmodex64_vc.lib;%(AdditionalDependencies)
</pre>
Once this is set, all that is necessary is to include the source files we were currently using to the project and make sure that it compiles. At this point, the project folder is transferrable between platforms as it contains both the Qt .pro file as well as the Visual Studio .vcxproj file, keeping the order of source and include files as they were.
<br />
<h2>
<div class="p1">
<b>Using Config Files</b></div>
<div class="p1">
</div>
<div class="p1">
<span style="font-size: small; font-weight: normal;">When you run your Gameplay 3D project or game, the window it creates will be generated from a game.config file located within the root directory of your project. If no config file is found, then it will default to standard values to best fit the situation. The basic options you can specify in the game.config file within the window scope (window {}) are:</span></div>
<ul class="ul1">
<li><span style="font-size: small;">title</span><span style="font-size: small; font-weight: normal;"> The text you wish to appear at the top of the window if full screen is false</span></li>
<li class="li1"><span style="font-size: small;">width<span style="font-weight: normal;"> The resolution width you wish to use</span></span></li>
<li class="li1"><span style="font-size: small;">height<span style="font-weight: normal;"> The resolution height you wish to use</span></span></li>
<li class="li1"><span style="font-size: small;">fullscreen<span style="font-weight: normal;"> This can either be true or false and will set the game either full screen or windowed</span></span></li>
</ul>
<div class="p1">
<span style="font-weight: normal;"><span style="font-size: small;">The .config file can also be used to set up aliases. These aliases can be used across your project, in both material, scene and physics files and also within the code when specifying paths and passing them to the engine. To set up an alias, simply first specify the scope aliases</span></span></div>
<div class="p1">
<span style="font-weight: normal;"><span style="font-size: small;"><br /></span></span></div>
<ul class="ul1">
</ul>
</h2>
<pre class="brush:cpp">aliases
{
}
</pre>
Within this scope, declare a name and set what it is equal to. For example:
<br />
<pre class="brush:cpp">aliases
{
komodo = res/textures/komodo.png
}
</pre>
This will create an alias to the texture file called komodo.png. If you then wanted to use this alias within another file, all you need to do is reference it as follows:
<br />
<pre class="brush:cpp">{what_to_set_to} = @komodo
</pre>
The engine will then replace @komodo with the right path. You can have as many aliases as you like within one project. Another use for the .config file is in the gamepad scope, declared as:
<br />
<pre class="brush:cpp">gamepads
{
}
</pre>
This will declare aliases for gamepad forms, which can then be used on touch devices as a way to control the game, for example:
<br />
<pre class="brush:cpp">gamepads
{
form = res/common/gamepad.form
}
</pre>
It is important to remember that whilst on Windows and Linux the game.config file can remain in the root directory, on Mac, it must be copied into the .app/Contents/Resources folder when building the game. If it is not, then the executable will not find the file and so will resort to default values.
<br />
<h2>
Encoding Files</h2>
<br />
<div class="p1">
Encoding files is an important aspect of using the engine, as Gameplay3D works with .gpb files, which are a Gameplay3D binary file format. This is then read in by the engine for assets used in the game. To encode files, we need to use the encoder that is compiled upon compiling the Gameplay source files. The encoder takes in a .fbx file exported from Autodesk Maya and encodes it into the .gpb file format. Using the encoder at its basic level is just running the command in terminal:</div>
<div class="p1">
<br /></div>
<pre class="brush:cpp">gameplay-encoder ‘name of .fbx file’
</pre>
This will create a .gpb file of the same name as the input .fbx file which can then be read into the engine either by passing the reference to the file in the .scene file used by the engine or explicitly loading the file in the source code.
The encoder will also pick up on any animation present in the .fbx file, prompting the user when encoding if they wish to group the animations.
If you intend to use the animations for a character, for example if the character has multiple animation cycles, you would run a different version of the encoder command in the terminal:
<br />
<pre class="brush:cpp">gameplay-encoder -g ‘name of root joint in Maya’ ‘name of animation group’ ‘name of .fbx file’
</pre>
This would group the animations for the specified joint hierarchy under the name of the input animation group from the .fbx file. The animation group name is the name of the animation set specified in the .animation file following the structure:
<br />
<pre class="brush:cpp">animation name of animation group
{
frameCount = 1100
clip idle
{
begin = 27
end = 167
repeatCount = INDEFINITE
loopBlendTime = 250
}
}
</pre>
<h1>
Using the Scene Files</h1>
Using scene files is a matter of specifying the contents of the encoded .gpb file to easily load them into the game without having to specify each asset and its respective material and/or physics profile in the code. A simplistic .scene file would follow the format:
<br />
<pre class="brush:cpp">scene
{
path = res/models/boy.gpb
node boycharacter
{
collisionObject = res/common/demo.physics#boy
}
node boymesh
{
material = res/common/demo.material#boy
}
node boyshadow
{
material = res/common/demo.material#demo
tags
{
transparent
dynamic
}
}
node camera
{
collisionObject = res/common/demo.physics#camera
}
}
</pre>
This file is then loaded into the scene using ‘Scene::load("res/common/demo.scene");’. Given the specified .scene file and all the nodes in the file, we are able to use the findNode(“asset name”); to get the necessary asset and manipulate it as necessary. Static objects in the scene, as mentioned, don’t need to be found from the scene file and are loaded into the game scene based on the material and physics tags given in the .scene file. Note in the example above that the nodes are in reference to the .gpb file given under ‘path’.<br />
<h1>
<b>Setting up Physics</b></h1>
In order to get physics working within the game, there are two methods that can be taken. The first is the more straightforward approach, using a .physics file which contains an outline of the physics objects that can be assigned to assets in the .scene file. An example of a physics object from the .physics file is as follows:
<br />
<pre class="brush:cpp">collisionObject staticMesh
{
type = RIGID_BODY
shape = MESH
static = true
mass = 0
restitution = 0.01
linearDamping = 1.0
angularDamping = 1.0
}
</pre>
This can then be referenced in the .scene file for a node using the # symbol after the reference to location of the .physics file in collisionObject. For example as seen in the example .scene file for instance, if you were to set the boyCharacter node as a static object using the above collision object the path would read as:
<br />
<pre class="brush:cpp">node boycharacter
{
collisionObject = res/common/demo.physics#staticMesh
}
</pre>
The second approach to physics in the game engine, would be to attach a physics character node to the asset in code. This would mean instantiating a PhysicsCharacter that has the properties of the node’s collision object, but this would allow you to manipulate the node such as updating it’s velocity, step height, etc.
<br />
<h1>
<b>Using Materials</b></h1>
One easy way of controlling and using materials within your project is through the use of material files (.material). You can have multiple material files per project, and they simply need to be referenced with the correct local path when using them. So if you had a foo.material and a foo2.material file, you can extract materials from either by simply quoting the correct path when setting a material in the engine.
A material file has a fairly similar structure to both the scene and physics files described previously. It makes use of a scope to define a single material. Within that scope, a number of attributes are then defined. For example, to create a material called demo:
<br />
<pre class="brush:cpp">material demo
{
}
</pre>
Within this material you can then specify certain techniques, such as:
<br />
<pre class="brush:cpp">material demo
{
technique Default
{
}
technique Edges
{
}
}
</pre>
This will allow you to specify a single material but with multiple techniques. To access these in the code, use the following:
<br />
<pre class="brush:cpp">{__model__}->setMaterial("res/common/demo.material#demo");
{__model__}->setTechnique("Default");
</pre>
This will look into the demo.material file and find the demo material (denoted by the #). The next line will then set the active technique to Default. If there are no techniques specified within the material, it will simply use the information supplied within the material scope.
To specify which shaders and any uniforms to set in the shader, simply declare these within this scope. So for example:
<br />
<pre class="brush:cpp">material demo
{
technique Default
{
pass
{
// shaders
vertexShader = res/shaders/colouredVertex.glsl
fragmentShader = res/shaders/colouredFragment.glsl
// uniforms
u_worldViewProjectionMatrix = WORLD_VIEW_PROJECTION_MATRIX
u_inverseTransposeWorldViewMatrix = INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX
u_diffuseColor = 1.0, 1.0, 1.0, 1.0
renderState
{
cullFace = true
depthTest = true
}
}
}
}
</pre>
Within the technique, the pass scope declares a single render pass and everything declared within the pass scope will be used in a single pass. More passes can be defined by defining more pass scopes. The vertexShader and fragmentShader paths simply declare the shader file to use for each. Below this are some uniforms being set. WORLD_VIEW_PROJECTION_MATRIX and INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX are Gameplay 3D built in values. However if you wish to upload your own values to these uniforms, you can do through setting the material within the main code.
The render state scope is optional and simply sets some OpenGL options for rendering of this pass. If you are using a shader that requires a texture or image path, this can be set by using the keyword path = and then setting either a declared path or an alias such as @komodo.
This is the basic use of a material file for your project.
<br />
<h1>
<b>Animations</b></h1>
Animation in the game engine works based on animations that are done in Maya and encoded in the .gpb file as stated above. In order to get animations working in your scene you would need the .animation file that defines the different animation clips as mentioned in the explanation of encoding files. The animation is loaded using code such as:
<br />
<pre class="brush:cpp">m_animation = node->getAnimation("animations");
m_animation->createClips("res/common/boy.animation");
</pre>
From here, you can use the loaded animation to store and/or play specific clips to be used in the scene when needed. For instance, in the initialize function, if you needed the character in your game to start playing the idle animation when it loads you would use:
<br />
<pre class="brush:cpp">play("idle", true);
</pre>
Using this, the animation clips specified in the .animation file can be called explicitly to make the character animate with the chosen animation clip. The loop blending time can be specified in code or in the .animation file to determine the smoothness of the blending between different animation clips when switching animations, for example from idle, to walking to running.The different clips can also be linked to character velocities in order to simulate changes in animation based on the speed at which the character is moving.
<br />
<h1>
<b>First Person Control System</b></h1>
In order to set up a first-person camera system in a Gameplay3D scene, a few things need to be determined. Firstly, you would need to include a camera in the encoded .gpb file. This camera node is then found using the aforementioned findNode function in order to work with the camera is the scene.
Secondly, you would need to ensure that the mouse event is set to capture the mouse within the game window using:
<br />
<pre class="brush:cpp">Game::setMouseCaptured(true);
</pre>
The reason for this is to make sure that you are able to have full control of camera movement in the scene without having the mouse leave the game window.
Once this is all set up, it is a matter of determining how to link the values from the mouse event function to the movement and rotation of the camera. If there isn’t a character set up in the scene for your game, the linking is much simpler. The y change of the mouse in the mouse event function, gives you a value with which you can determine how much to rotate the camera in the x-axis (look up and down). The x value in this function would then be used to determine the y-axis rotation for the camera (look left and right).
If a character was used in the scene, you would then need to make sure that the PhysicsCharacter assigned to the character looks where the camera looks and vice-versa. The easiest method to doing this is to parent the camera to the character in the scene in Maya, but could potentially result in orientation issues. As such, what needs to be done, is that using the x mouse value, you would rotate character and ensure the the camera is similarly oriented using the character’s forward vector.
This would handle the ‘looking’ aspect of the first-person camera system. In order to move the camera, you would register key-inputs and respectively use the key inputs to determine the direction of movement. This can then be used to affect and update the camera’s position in the update function. Once again, if a character was used, you would update the camera’s position not based on key inputs but by getting the character’s position using the getTranslation function and moving the camera to that location. Note that the camera would thus be correctly oriented using the forward vector of the character as mentioned above.
The basis of the first-person camera system is now set, but can be further developed should the need arise for different camera actions, such as leaning around corners or peeking over obstacles.
<br />
<h1>
<b>Use of external GL calls</b></h1>
Even though Gameplay 3D has its own GL context and its own rendering engine (used through the render() function) you are able to use your own calls to GL functions and GL draw calls if you wish. These will apply to the same GL context as every other Gameplay 3D draw call. This can give you a good deal of extra control over certain rendering aspects and GL attributes used within your project.
Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com2tag:blogger.com,1999:blog-6958533929285860874.post-35998293774456185802013-11-13T20:41:00.002+00:002013-11-13T20:41:35.741+00:00Designing a Software SystemThis is the first guest post on my Blog, this one comes from a PhD student (and previously an MSc at Bournemouth) <a href="http://nccastaff.bournemouth.ac.uk/jmacey/MastersProjects/MSc11/Mathieu/index.html">Mathieu Sanchez</a>.<br />
<br />
This post is specifically aimed at the design of complex software systems and is in general feedback on how to so the initial design required for some of our assignments. I was really impressed with this email and decided to share it with everyone.<br />
<br />
<div class="p1">
Design often takes experience, which is why it is so difficult to teach, but there are some "half rules".</div>
<ul class="ul1">
<li class="li1">Write down your concepts, keywords and actions on a piece of paper, there is no need to draw anything. Verbs often translate to a relation and/or a class method (important). Nouns often refer to a class. ( see <a href="http://www.sa-depot.com/?p=336">this</a> and <a href="http://dl.acm.org/citation.cfm?id=944242">this</a>)</li>
<li class="li1">Classes are most likely a singular noun. If it is not then maybe you are doing something wrong. In this case, check your multiplicity, and try to find a better name. It can happen that you have "container" classes. Don't name them by what they contain. An example would be a container for several wolves. If you name it wolves, it is unclear, and will lead to confusion. Do you mean a "pack of wolves"? Naming is very important, and will help you get a clearer vision, and help the markers (which is always good).</li>
<li class="li1">Classes ending in -ER are a warning flag. It can happen, but if it does, you need to be sure of yourself. Once again, naming might be the issue, not the actual design. (see <a href="http://programmers.stackexchange.com/questions/129537/can-manager-classes-be-a-sign-of-bad-architecture">here</a> <a href="http://steve-yegge.blogspot.co.uk/2006/03/execution-in-kingdom-of-nouns.html">here</a> and <a href="http://stackoverflow.com/questions/1866794/naming-classes-how-to-avoid-calling-everything-a-whatevermanager">here</a>)</li>
<li class="li1">Don't build crazy associations everywhere. Data can travel along an association and should have a strong meaning such as "owns" "directs" etc...</li>
<li class="li1">Triangle relations are nasty. If you have class A, B and C, there should not be a link between each of them with each other. </li>
<li class="li1">If you find that there are many ways to achieve the same task, then there might be some inheritance in there. For instance, shadows in rendering can be done through shadow mapping or shadow feelers. This is crying for inheritance. Make sure you have a look at<a href="http://en.wikipedia.org/wiki/Liskov_substitution_principle"> Liskov substitution</a> if you have inheritance.</li>
</ul>
<ul class="ul1">
<li class="li1">Many of the common problems are solved with (<a href="http://en.wikipedia.org/wiki/Software_design_pattern">famous</a>) patterns. For instance, if there are two ways of doing one operations, but can also be combined together to achieve a better result, then <b>there is a pattern for that</b>.</li>
<li class="li1">When I read a diagram, I first look for a point of entry. And so should you. A point of entry for me is where everything starts, the class that controls the entire system. If it is unclear to you where it starts, then you might have missed something.</li>
<li class="li1">Think at a higher level at first, don't go straight for <a href="http://stackoverflow.com/questions/385506/when-is-optimisation-premature">details</a>, in fact implementation details such as acceleration structures only come last. The first diagram gives an overview of the system. If the interfaces are correctly made, adding spatial data structures is a piece of cake.</li>
<li class="li1">Think about <a href="http://en.wikipedia.org/wiki/Extensibility">extensibility</a>. What if someone else wants to extend your library/system? If I have to jump into your code to add some if/else and edit your interface, then it is just plain wrong. Hence inheritance and factories.</li>
</ul>
<div class="p2">
<br /></div>
<div class="p1">
Finally, once you have a draft, you need to review your diagram. The only thing I do when I try to help you is ask you my famous "<b>what is its responsibility, in one and only sentence?</b>". </div>
<div class="p1">
<br /></div>
<div class="p1">
Do it yourself. Once the diagram is under your eyes, you can see if one of the classes overlaps with another, or worse, there is no class for a particular class. Then, double check your multiplicity. Read it out loud if needed. You should have two sentences to read. Let s say we have [ A ] 1 ------- * [ B ], then it would read "A has many B, and B belongs to one and only one A". Multiplicity can be: 0..1 (at most one), 1 (one and only one), 0..* (any number), 1..* (one or more). Your inheritance should be solid if it respects the Liskov substitution principle.</div>
<div class="p2">
<br /></div>
<br />
<div class="p1">
Don't leave your diagrams without explanation, and stand your ground. Design is all about making decisions and trade-offs. I want to know those, because this is what lets me know if you actually worked on this, and are an able analyst, or if you are just fighting to just get a working system.</div>
Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com0tag:blogger.com,1999:blog-6958533929285860874.post-34363188224064117752013-10-02T12:43:00.001+01:002013-10-02T12:45:00.289+01:00Introduction to using the bash shell (NCCA Version)So it's the first week of term, and many new students have arrived to start their lab sessions only to find that we don't use windows!<br />
<br />
There are many reasons for this, however the main one is the our main output industry is VFX and the majority of (large) VFX houses use linux / unix. This is due to a number of reasons, however mainly stability, scalability and ease of customisation.<br />
<br />
Learning to use the linux command line and linux in general is quite a daunting task for a new user, and many people often wonder why they should bother when there is a perfectly good GUI. However as I shall explain in the following videos it will make you a more efficient / better operator if you can master some of the basic shell commands.<br />
<br />
Also it has the added benefit that once you have learnt them, most of them will also be available in both shell scripts, python programs and C / C++ programs so you are learning valuable transferable skills all in one go.<br />
<br />
Whilst these videos will concentrate on the university lab setup they will also be relevant to other linux distributions and linux in general and are mainly a repetition of what we do in the introduction lab sessions.<br />
<br />
There is a link to a workbook and other resources <a href="http://nccastaff.bournemouth.ac.uk/jmacey/UnixLinux/index.html">here</a><br />
<div>
<br /></div>
<br />
<iframe allowfullscreen="" frameborder="0" height="315" src="//www.youtube.com/embed/Bd4Pyqpy8zs" width="560"></iframe><br />
<br />
(for more info on ssh see <a href="http://www.openssh.org/">here</a>)<br />
<br />
<iframe allowfullscreen="" frameborder="0" height="315" src="//www.youtube.com/embed/_6A9KKGXK-g" width="560"></iframe><br />
<br />
<iframe allowfullscreen="" frameborder="0" height="315" src="//www.youtube.com/embed/vvEMvKfhGE8" width="560"></iframe>
<br />
<iframe allowfullscreen="" frameborder="0" height="315" src="//www.youtube.com/embed/I916vHBK1jc" width="560"></iframe><br />
<br />
<iframe allowfullscreen="" frameborder="0" height="315" src="//www.youtube.com/embed/BH2KbWT9lJE" width="560"></iframe><br />
<br />
<iframe allowfullscreen="" frameborder="0" height="315" src="//www.youtube.com/embed/xxe32F-I7z8" width="560"></iframe>
<br />
<pre class="brush:cpp" title="alias in .bashrc">
alias ls='ls --color'
alias ll='ls -al'
alias rm='rm -i'
</pre>
<br />
<iframe allowfullscreen="" frameborder="0" height="315" src="//www.youtube.com/embed/7457dlFSbvY" width="560"></iframe>
some useful information on the <a href="http://www.thegeekstuff.com/2008/09/bash-shell-ps1-10-examples-to-make-your-linux-prompt-like-angelina-jolie/">prompt</a><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5TPpjeYTaCnzZLcBl2P0RBcUkAh8f7Bkb-CZWWp1bdkpIZanlafwf09vzdWhkQXIsnCzailL5C5DFy11HWbDwF03PHhuXTdE37KhkqVkdjKH6NQCV7oFPKHvTlpJqoz3191Sqs2D7PDn8/s1600/Chmod.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="124" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5TPpjeYTaCnzZLcBl2P0RBcUkAh8f7Bkb-CZWWp1bdkpIZanlafwf09vzdWhkQXIsnCzailL5C5DFy11HWbDwF03PHhuXTdE37KhkqVkdjKH6NQCV7oFPKHvTlpJqoz3191Sqs2D7PDn8/s320/Chmod.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<iframe allowfullscreen="" frameborder="0" height="315" src="//www.youtube.com/embed/4HG77lloO4I" width="560"></iframe>
<iframe allowfullscreen="" frameborder="0" height="315" src="//www.youtube.com/embed/3xyt_DqRzLw" width="560"></iframe>
Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com0tag:blogger.com,1999:blog-6958533929285860874.post-73599864254499417852013-08-30T14:01:00.000+01:002013-08-30T14:01:37.599+01:00Getting Started with GamePlay3D under Mac OSXI've been researching different game engines to use with our teaching next year. Of the many engines <a href="http://gameplay3d.org/">gameplay3D</a> stood out for a number of reasons.<br />
<ol>
<li>Open Source</li>
<li>Written in C++ and Lua scriptable</li>
<li>Works under Mac, Linux, Windows and mobile devices</li>
</ol>
<div>
This blog post is going to talk about the basic setup under mac osx and how to start a basic project, In this case I'm going to use xcode, however I do also have a basic qt creator project as well which I may do in another blog post.</div>
<div>
<br /></div>
<h3>
Downloading the source</h3>
<div>
I'm going to download the source using git into my main root directory as this will make paths easier. To do this I do the following</div>
<pre>cd
git clone https://github.com/blackberry/GamePlay.git
</pre>
This may take a while but once it is done you should have a new directory called $(HOME)/GamePlay. Now we have to download the external dependancies. This is done via a script called install.sh Change into the GamePlay directory and run this script. This will take a while as it is quite a large file but it will download pre-built libs for all the platforms.
Under mac osx these are built as 32bit static libs and may cause problems if you wish to link against other 64bit libs and I will do another blog post at a later date on how to build and link your own 64 bit version of the library but it is quite an involved process. In most cases the 32bit pre-built lib will be fine.
<br />
<h3>
Compiling with xcode</h3>
<div>
Now we can open the xcode workspace (gameplay.xcworkspace) and configure and build the main gameplay static library.</div>
<div>
<br /></div>
<div>
To make development easier I'm going to setup the targets to build the library in the same root GamePlay directory. To do this we do the following first goto File->Workspace Settings in the xcode menu</div>
<div>
<br /></div>
<div>
Choose WorkSpace relative as shown below</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNyC2ZbDEQn39-PFAC8kEMQ68pAD0JUS1iZAlYZ1tydCDyo_e1VozfbYXtsvsN6zW6PRcQNf5rD4_Twk2HeRzyUpibDDyd40RDScCAA-7ckZpDmDfdziu_NNWHfnTvoeoh61Gs2xW9189D/s1600/gp1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNyC2ZbDEQn39-PFAC8kEMQ68pAD0JUS1iZAlYZ1tydCDyo_e1VozfbYXtsvsN6zW6PRcQNf5rD4_Twk2HeRzyUpibDDyd40RDScCAA-7ckZpDmDfdziu_NNWHfnTvoeoh61Gs2xW9189D/s640/gp1.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Now we can build the library and the final lib should be placed in the directory GamePlay/DerivedData/gameplay/Build/Products/Debug. This actually builds a mac framework that we can copy into some other directory to use in our own projects. However for now we will leave it as it is.</div>
<h3>
Creating a new project</h3>
<div>
Gameplay comes with a newproject script that will copy a template project to a new location. Again I have modified this to make it easier to create new projects in directories other than the main GamePlay one. </div>
<div>
<br /></div>
<div>
In an editor open up the GamePlay/newproject.sh script look for each instance of the cp command like this</div>
<pre>cp "template/template.vcxproj" "$projPath/$projName.vcxproj"
</pre>
Where it says "template/ we are going to pre-pend the path of the GamePlay install so in my example it's going to be $HOME/GamePlay/
<br />
<pre>cp "$HOME/GamePlay/template/template.vcxproj" "$projPath/$projName.vcxproj"</pre>
Do this for every cp command in the script.<br />
<br />
Now this is done we can create a new directory to put our demos in. In my case I've created one called GamePlayDemos<br />
<br />
<br />
<pre>mkdir GamePlayDemos
cd GamePlayDemos
~/GamePlay/newproject.sh
1. Enter a name for the new project.
This name will be given to the project
executable and a folder with this name
will be created to store all project files.
Project Name: Test
2. Enter a game title.
On some platforms, this title is used to
identify the game during installation and
on shortcuts/icons.
Title: Test
3. Enter a short game description.
Description:
4. Enter a unique identifier for your project.
This should be a human readable package name,
containing at least two words separated by a
period (eg. com.surname.gamename).
Unique ID: ncca
5. Enter author name.
On BlackBerry targets, this is used for
signing and must match the developer name
of your development certificate.
Author: jm
6. Enter your game's main class name.
Your initial game header and source file
will be given this name and a class with
this name will be created in these files.
Class name: Test
7. Enter the project path.
This can be a relative path, absolute path,
or empty for the current folder. Note that
a project folder named Test will also
be created inside this folder.
Path:./
</pre>
Once the script has run you should see a folder like this
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiecNHJQJFjRfd1EjefKlk7khj6D4aYfx81W3jG8igwPgI25p5P2gO6WVyJbrdUFxneHSfFNJcmOge56wa2BJB91WBuYN31xPL49DlNd3JPYyTHGHlsm0ijXFA_9IdGKArGi8vV-HKzGExY/s1600/gp2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="235" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiecNHJQJFjRfd1EjefKlk7khj6D4aYfx81W3jG8igwPgI25p5P2gO6WVyJbrdUFxneHSfFNJcmOge56wa2BJB91WBuYN31xPL49DlNd3JPYyTHGHlsm0ijXFA_9IdGKArGi8vV-HKzGExY/s400/gp2.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
Now we can open the Test.xcodeproj file and get ready to build the demo. First we need to change the search paths for headers. By default they look like this</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijGmo__CgdEG_i2EEIIWZhYqXl93nzIIPeRpd-nxJVdpWr-sTSn-IlQnf5m6x9waa-1p98OkNEcLPryNrKOtVXBhXG750B3FXaTrEn-YcvWiLM_q4BjFi_uUBWu8dhwCm6g-3jeKsAjO9g/s1600/gp3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="260" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijGmo__CgdEG_i2EEIIWZhYqXl93nzIIPeRpd-nxJVdpWr-sTSn-IlQnf5m6x9waa-1p98OkNEcLPryNrKOtVXBhXG750B3FXaTrEn-YcvWiLM_q4BjFi_uUBWu8dhwCm6g-3jeKsAjO9g/s400/gp3.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
We need to add $(HOME)/GamePlay to each of these paths (or the directory you installed it into)</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSzZ9z4o0PxjYaMLrxLwxRBj503iDT164rb6BxCSeYexYjBus8tgYY18TFnp5_TIYXNrlsqvb_j9M41wGR43DNCbNwljfrJ171NAzDW_eMkXJxrteQh5JF0S9dgsDdWluHyv_uhdo9mFf7/s1600/gp4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="207" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSzZ9z4o0PxjYaMLrxLwxRBj503iDT164rb6BxCSeYexYjBus8tgYY18TFnp5_TIYXNrlsqvb_j9M41wGR43DNCbNwljfrJ171NAzDW_eMkXJxrteQh5JF0S9dgsDdWluHyv_uhdo9mFf7/s400/gp4.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
This will now allow the project to compile, however we still need to set the linker paths and do the same path addition</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEho-xBL51_AwlVb7BjcUNV9S4merkhQQs8DMAY4NyL1-91MBaNzt3idvkpc_-FG6eRoDTkMvyNlV6-lGgrDBLNf1xDkFF62BDybUAwURQcBPvIsj96p7oKyf04tgDvosKDhYP3fM8qfZdrw/s1600/gp5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="165" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEho-xBL51_AwlVb7BjcUNV9S4merkhQQs8DMAY4NyL1-91MBaNzt3idvkpc_-FG6eRoDTkMvyNlV6-lGgrDBLNf1xDkFF62BDybUAwURQcBPvIsj96p7oKyf04tgDvosKDhYP3fM8qfZdrw/s400/gp5.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Add $(HOME)/GamePlay to the ../ paths as shown</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgM7BHbPsxSJw4flW_yTOqBsSzsG5xYBu4o6Ov1ojPx98-FIBmVg9agdKnKEsNfnsmhpNbXWjHRVS-H70ps6bUrO9V9KvFH0tE5NOR8A501X2yZv5codrBKoja_nWlGGaUhyphenhyphenm8JNuJbOu9r/s1600/gp6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="136" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgM7BHbPsxSJw4flW_yTOqBsSzsG5xYBu4o6Ov1ojPx98-FIBmVg9agdKnKEsNfnsmhpNbXWjHRVS-H70ps6bUrO9V9KvFH0tE5NOR8A501X2yZv5codrBKoja_nWlGGaUhyphenhyphenm8JNuJbOu9r/s320/gp6.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Finally we need to add an additional path for the libgameplay.a location this can be done by selecting the build options and removing the original reference and locating the one we built earlier in the DerivedData directory as shown</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUoFPLfUU6q9CDBglmKszRJ6RyXMqNxOmMy2WlIsC1gabVpzqBeASLDept8MOLcBO2gMoOFkmQLFMLqe1EkcP2VbkNli_KNw6Pwvwcpcf00PkMgWjIk7JjCTe1ZSJCpG5AwASX3wefrhpD/s1600/gp7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="257" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUoFPLfUU6q9CDBglmKszRJ6RyXMqNxOmMy2WlIsC1gabVpzqBeASLDept8MOLcBO2gMoOFkmQLFMLqe1EkcP2VbkNli_KNw6Pwvwcpcf00PkMgWjIk7JjCTe1ZSJCpG5AwASX3wefrhpD/s400/gp7.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The program should now run and give you the following screen.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtXTg-Dt-MTItux_LD8GEJr3vJgBDs3CeUnwtr1r0B8h_Jv8YsXtTFpzchenAHMb7gFXZbpyAMNUTz2sl1B4Evo97edKtV0PFhW7BJLXUMMRPmHeVO_jujX7YXbA3O51WYzbZGVshmWuS5/s1600/gp8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="235" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtXTg-Dt-MTItux_LD8GEJr3vJgBDs3CeUnwtr1r0B8h_Jv8YsXtTFpzchenAHMb7gFXZbpyAMNUTz2sl1B4Evo97edKtV0PFhW7BJLXUMMRPmHeVO_jujX7YXbA3O51WYzbZGVshmWuS5/s400/gp8.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
I will do some more blog posts soon on using the game engine with maya.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<br />Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com0tag:blogger.com,1999:blog-6958533929285860874.post-10772234016786980872013-05-11T08:57:00.002+01:002013-05-11T15:33:46.084+01:00GLSL tessellation Shaders under Mac OSXSo <a href="http://www.geeks3d.com/20130507/gputest-0-4-0-cross-platform-opengl-benchmark-released-opengl-4-tessellation-test-enabled-under-mac-osx/">this</a> interesting post appeared the other day saying that tessellation shaders were working on Mac OSX. According to the documents and other things like <a href="http://www.realtech-vr.com/glview/">GLView</a> this is not the case.<br />
<br />
I decided to spend the day investigating the claims to a) see if they were true, and b) see how I could replicate this in my own library.<br />
<br />
The following video shows how I used the Mac OpenGL profiler to dig into the source code and find out how to do this.<br />
<br />
<iframe width="560" height="315" src="http://www.youtube.com/embed/QNpO3x68dHs" frameborder="0" allowfullscreen></iframe>
<br />
The main code elements you need are the following defines<br />
<br />
<pre class="brush:cpp" title="Tessellation defines">#ifdef DARWIN
#ifndef GL_TESS_CONTROL_SHADER
#define GL_TESS_CONTROL_SHADER 0x00008e88
#endif
#ifndef GL_TESS_EVALUATION_SHADER
#define GL_TESS_EVALUATION_SHADER 0x00008e87
#endif
#ifndef GL_PATCHES
#define GL_PATCHES 0x0000000e
#endif
#endif
</pre>
Once this has been defined somewhere you can use the default OpenGL commands to create a shader, I chose to use the demo code / shader <a href="http://prideout.net/blog/?p=48">here</a> the main thing to remember is that you must use GL_PATCHES to draw to the tessellation units.<br />
<br />
The other problem is that code like<br />
<pre class="brush:cpp">glPatchParameteri(GL_PATCH_VERTICES, 16);
</pre>
is not available as the glPatchParam functions are not exposed, the good news is that you can set all of this in the shader so it is not too much of an issue. The updates have now been rolled into the core <a href="http://nccastaff.bournemouth.ac.uk/jmacey/GraphicsLib/index.html">ngl</a> library, and I will add some demos soon.Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com1tag:blogger.com,1999:blog-6958533929285860874.post-55915749596857485492013-05-03T11:55:00.001+01:002013-05-03T11:55:22.561+01:00Install NGL / Qt on a new MacThis video blog shows how to install all of the NGL environment on a brand new mac running Mountain Lion. The links to download qt are <a href="http://qt-project.org/">here</a> and the main configuration for ngl etc is <a href="http://nccastaff.bournemouth.ac.uk/jmacey/GraphicsLib/index.html">here</a>.<br />
<br />
<iframe allowfullscreen="" frameborder="0" height="315" src="http://www.youtube.com/embed/BpI71VNPCG0" width="560"></iframe>
<br />
<iframe allowfullscreen="" frameborder="0" height="315" src="http://www.youtube.com/embed/7Fp5T54Npk0" width="560"></iframe>
<iframe allowfullscreen="" frameborder="0" height="315" src="http://www.youtube.com/embed/OiMN1bPd15o" width="560"></iframe>
<br />
This is how I set the alias for qt creator
<br />
<pre class="brush:cpp" title="setting the Qt alias">export PATH=$PATH:/Users/jmacey/Qt5.0.2/Qt\ Creator.app/Contents/MacOS
alias qtcreator='Qt\ Creator'
</pre>
<br />
<iframe allowfullscreen="" frameborder="0" height="315" src="http://www.youtube.com/embed/Klbo3Tkl3aU" width="560"></iframe>
<br/>
Next you need to follow the instructions <a href="http://nccastaff.bournemouth.ac.uk/jmacey/GraphicsLib/index.html">here</a> to install and setup NGL, you will need to install bzr which is a simple package from <a href="http://bazaar.canonical.com/en/">here</a>.
<br />
<iframe allowfullscreen="" frameborder="0" height="315" src="http://www.youtube.com/embed/Hfqwd-Q_P88" width="420"></iframe>
Finally this example shows how to build the Qt 5 version of NGL and a basic demo
<br />
<iframe allowfullscreen="" frameborder="0" height="315" src="http://www.youtube.com/embed/6MEioQb3cK0" width="560"></iframe>
Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com0tag:blogger.com,1999:blog-6958533929285860874.post-83685299609285948792013-03-11T09:21:00.001+00:002013-03-11T09:21:56.087+00:00Adding Movement in nglThis video blog shows how to add movement using the Model, View, Project matrix in ngl you can get the demo program <a href="http://nccastaff.bournemouth.ac.uk/jmacey/Code/Blog/Movement.tgz">here</a> and should also read the lecture notes <a href="http://nccastaff.bournemouth.ac.uk/jmacey/CA1/Slides/Lecture5TransformCamera.pdf">here</a><br />
<br />
<iframe allowfullscreen="" frameborder="0" height="315" src="http://www.youtube.com/embed/8tsDw3bNVeQ?rel=0" width="420"></iframe>
<br />
<iframe allowfullscreen="" frameborder="0" height="315" src="http://www.youtube.com/embed/VV36C-FmB1I?rel=0" width="420"></iframe>Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com0tag:blogger.com,1999:blog-6958533929285860874.post-31546783615143095842013-02-14T20:26:00.001+00:002013-03-04T13:32:43.851+00:00When it all goes wrong!It's that time of year again, (no not Valentines day). Students have finally realised that they have assignments to do and are finally testing and writing code!<br />
<br />
So far today I've had 12 email (and this week about 30) with problems and errors, so I've decided to collate as much wisdom and help as I can here which hopefully will help not only you but also me!<br />
<br />
This post is intentionally sarcastic and not aimed at anyone in particular!<br />
<h3>
RTFEM</h3>
<div>
A lot of the time the errors are quite easy to spot but you get the blind panic of it not working, first thing you should do is "read the <a href="http://www.acronymattic.com/RTFEM.html">(fine)</a> error message".</div>
<div>
<br /></div>
<div>
In the following example</div>
<pre class="brush:cpp">src/GLWindow.cpp: In member function 'void GLWindow::persp(GLWindow::MODE)':
src/GLWindow.cpp:256: error: expected ',' or ';' before 'm_transformStack'
make: *** [obj/GLWindow.o] Error 1
</pre>
In this case we can read that there is an error in the file src/GLWindow.cpp at line 256 so I would suggest looking there!
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcRnong5ZjnjEc69YeUX6QxqJIEHhA4z1d2vzPEZWCb00GEmenu-6RYSVgTpdb2j76cD8m5j_9bZBkAx23CtkZs7MC9r-a8-XvnLNH3UINryL9S4o0ig2AvJGz1BR30NRVC0tYw0OOzDm-/s1600/error1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="102" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcRnong5ZjnjEc69YeUX6QxqJIEHhA4z1d2vzPEZWCb00GEmenu-6RYSVgTpdb2j76cD8m5j_9bZBkAx23CtkZs7MC9r-a8-XvnLNH3UINryL9S4o0ig2AvJGz1BR30NRVC0tYw0OOzDm-/s400/error1.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
As I'm using (and most of you are) QtCreator we only have to double click on the error message to goto the error. Even better it also underlines it in red! (BTW green underlined usually indicates unused variables so we can remove them as well) and yes in this case I've missed a ;</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Now some errors are not as obvious and I will add a list of the common ones as I get sent them at the bottom of this post. </div>
<h3>
Different Error types</h3>
<div>
It is important to differentiate between error types. We can roughly split the errors into three categories.</div>
<ol>
<li>Compilation errors</li>
<li>Linker errors</li>
<li>Runtime errors</li>
</ol>
<div>
Compilation errors are the most common and may be due to many different factors, some can be due to a missing header / include such as</div>
<pre class="brush:cpp" title="missing header">src/main.cpp: In function 'int main(int, char**)':
src/main.cpp:11: error: 'MainWindow' was not declared in this scope
src/main.cpp:11: error: expected `;' before 'w'
src/main.cpp:13: error: 'w' was not declared in this scope
make: *** [obj/main.o] Error 1
</pre>
In this case we are just missing the #include "MainWindow.h" but the error seems worse, the clue is the "not declared in this scope" which should give you a hint that the compiler doesn't know about something.
Another error along the same lines is the following
<br />
<pre class="brush:cpp">int main()
{
std::cout<<"hello world\n";
}
</pre>
In this case we get the error
<br />
<pre class="brush:cpp">1.cpp: In function 'int main()':
1.cpp:3: error: 'cout' is not a member of 'std'
</pre>
Just because we are missing the #include <iostream>. When you do get these errors <a href="http://lmgtfy.com/">this</a> is a good resource for finding out what has gone wrong as is <a href="http://clang.llvm.org/diagnostics.html">this</a><br />
<br />
Linker errors are harder to find but usually are due to the fact that you don't have the correct libraries installed, the also seem much more scary as they seem to go on forever in some cases<br />
<br />
For example the following<br />
<pre class="brush:cpp" title="linker errors">clang++ -Wall -g ClearScreen.cpp -o ClearScreen `sdl-config --cflags`
Undefined symbols for architecture x86_64:
"_SDL_FillRect", referenced from:
clearScreen(SDL_Surface*, char, char, char) in ClearScreen-vFrFBN.o
"_SDL_Flip", referenced from:
clearScreen(SDL_Surface*, char, char, char) in ClearScreen-vFrFBN.o
"_SDL_Init", referenced from:
_SDL_main in ClearScreen-vFrFBN.o
"_SDL_MapRGB", referenced from:
clearScreen(SDL_Surface*, char, char, char) in ClearScreen-vFrFBN.o
"_SDL_PollEvent", referenced from:
_SDL_main in ClearScreen-vFrFBN.o
"_SDL_Quit", referenced from:
_SDL_main in ClearScreen-vFrFBN.o
"_SDL_SetVideoMode", referenced from:
_SDL_main in ClearScreen-vFrFBN.o
"_SDL_WM_SetCaption", referenced from:
_SDL_main in ClearScreen-vFrFBN.o
"_main", referenced from:
-u command line option
(maybe you meant: _SDL_main)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
</pre>
This is due to the fact that the compiler is not using the SDL libs flags "-L/usr/local/lib -lSDLmain -lSDL" Once these are added it usually fixes things. One of the most difficult problems you will encounter is finding which function lives in which lib, again you can google. Or I have a handy shell script
<br />
<pre class="brush:cpp" title="checkLib.sh">#!/bin/bash
for f in *.a *.so *.dylib
do
echo "checking for $1 in - $f"
strings $f | grep $1
done
</pre>
Which using checkLib.sh glVertex in the directory /usr/lib/ gives
<br />
<pre>checkLib.sh glVertex | more
checking for glVertex in - libGLEW.a
glVertexAttrib1dNV
glVertexAttrib1dvNV
glVertexAttrib1fNV
glVertexAttrib1fvNV
....
</pre>
Runtime errors are usually created when we cant find the dynamic libs we need to link to, for example
<br />
<pre>dyld: Library not loaded: libNGL.1.0.0.dylib
Referenced from: /Volumes/home/jmacey/teaching/NGL5Demos/SimpleNGL/./SimpleNGL
Reason: image not found
Trace/BPT trap: 5
</pre>
Means that the LD_LIBRARY_PATH (actually DYLD on mac) has not been set for the NGL lib (see <a href="http://nccastaff.bournemouth.ac.uk/jmacey/GraphicsLib/index.html">here</a>)
<br />
<br />
<h3>
If in doubt make clean</h3>
<div>
Sometimes things get out of sync and dependancies are not re-read. The simplest solution is to do a qmake; make clean ; make;l</div>
<div>
<br /></div>
<div>
In QtCreator this is the same as doing a re-build all. You will be surprised how often this solves things (usually to deps not being updated)</div>
<h3>
Still Stuck do this</h3>
<div>
If you need to send me some errors, please don't do this </div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhc6yobeU8yXi-uRPR-YBUlMAwrxvWthvk5vDrnAiBDqvm4DwSO_9eO3rHocz4jdmMCH4Y-POhJiCUB5QdvUH_tVFdjogtLPZiOYyuouDdpxZSd7UwJWbb8TNsr3qBa8gnsuRAoVZ7DKWgU/s1600/IMG_1970.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhc6yobeU8yXi-uRPR-YBUlMAwrxvWthvk5vDrnAiBDqvm4DwSO_9eO3rHocz4jdmMCH4Y-POhJiCUB5QdvUH_tVFdjogtLPZiOYyuouDdpxZSd7UwJWbb8TNsr3qBa8gnsuRAoVZ7DKWgU/s320/IMG_1970.JPG" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
Yes that is an iPhone photo of the error message on my monitor, yes I have had this mailed to me before, and no I can't figure out what is wrong! My eyesight used to be that good but not anymore!</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
This is not much better</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuDwmVEyZaVgjQuxpXxPSrIFtjD9k0zTicBePbyckAt8jv5dj3cHb1vPA5j9S-auxRs917NZUlpYGDJuUHVgtBuU005jQyjkUCLibTMlKIGLf1s_truwUDc0WY7KOXbVXzTitxdqURetPh/s1600/Screenshot.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="250" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuDwmVEyZaVgjQuxpXxPSrIFtjD9k0zTicBePbyckAt8jv5dj3cHb1vPA5j9S-auxRs917NZUlpYGDJuUHVgtBuU005jQyjkUCLibTMlKIGLf1s_truwUDc0WY7KOXbVXzTitxdqURetPh/s400/Screenshot.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
Yes I can see the errors in this one but it still doesn't help much, I really need to see the compiler output / flags as well as the error messages (these are on different tabs on Qt).</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The easiest way of sending me errors etc is via plain ASCII text (I'm old fashioned like that ;-) To do this will require a little typing.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<pre>cd [your project root]
make &>err.txt
</pre>
<br />
If you do this in the root of the project where the makefile is it will run make and output all of the errors to the file err.txt. Mail it to me as this will then help me to find the errors.<br />
<h3>
Send me the code</h3>
<div>
If I ask you to send me the code, I only need the source and other files not the .o and exe. The easiest way of sending this to me is as follows</div>
<div>
<br /></div>
<pre>cd [your project root]
make distclean
cd ..
tar vfcz code.tgz [your project root]
</pre>
<br />
Then mail me the code, it also helps if I have the following information<br />
<ul>
<li>Operating System (and version if Mac or Linux)</li>
<li>Compiler used (use g++ -v or clang -v) </li>
<li>Graphics Card Make Model and version of OpenGL drivers installed. </li>
<li>Versions of any extra libs etc you may be using. </li>
</ul>
A lot of the time this could be the cause of the problem, I will test all my code against Mac OSX (Mountain Lion) using<br />
<br />
clang++
( Apple clang version 4.0 (tags/Apple/clang-421.0.60) (based on LLVM 3.1svn)
Target: x86_64-apple-darwin12.2.0
Thread model: posix)<br />
<br />
and the lab build<br />
<br />
clang++ -v
clang version 3.2 (trunk 163783)
Target: x86_64-unknown-linux-gnu
Thread model: posix
g++ -v
Using built-in specs.
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
Thread model: posix
gcc version 4.4.6 20120305 (Red Hat 4.4.6-4) (GCC)<br />
<br />
Also make sure you have pulled the latest versions of any of my code using a bzr pull as I do bug fixes as they are reported (there will soon be a more official way of reporting this using the redmine system)<br />
<h2>
Some Common Errors (and Fixes)</h2>
I get quite a lot of common errors so I will try and list them here<br />
<h3>
GLEW Errors</h3>
<div>
If you get something like this</div>
<pre>/usr/include/GL/glew.h:84:2: error: gl.h included before glew.h
#error gl.h included before glew.h
^
/usr/include/GL/glew.h:90:2: error: glext.h included before glew.h
#error glext.h included before glew.h
</pre>
It is due to the GLEW libs not being included properly (you may also get lots of PFNGL..... errors as well)
Some of the old versions of my .pro files have a subtle bug in them where the defines are not done correctly check the .pro file and make sure this is correct
<br />
<pre>linux-g++*{
DEFINES += LINUX
LIBS+= -lGLEW
}
linux-clang* {
DEFINES += LINUX
LIBS+= -lGLEW
}</pre>
<pre>
</pre>
<h3>
xxx does not name a type</h3>
<div>
Errors such as include/GLWindow.h:50: error: ‘Vector’ in namespace ‘ngl’ does not name a type means that you have either not included the correct header or something is missing. In this case it is due to the fact that ngl::Vector has now been replaced with ngl::Vec3 so you will need to #include <ngl/Vec3.h> and also replace all versions of ngl::Vector with ngl::Vec3</div>
Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com1tag:blogger.com,1999:blog-6958533929285860874.post-59055070377341929572013-01-24T18:26:00.003+00:002013-01-29T09:53:23.970+00:00CA 1 Initial Design General FeedbackThis is the general feedback for the CA1 Initial Design in addition to some of the comments <a href="http://jonmacey.blogspot.co.uk/2011/01/asd-ca1-assignment-feedback-and.html">here</a><br />
<br />
<h3>
Class Diagrams</h3>
<div>
A lot of the class diagrams didn't use standard UML format. This is quite important as I can then see a number of things about the class at a glance. There are more details in my lecture notes but these slides show the main things</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrpby_qF5P1NPRBXweEoJjkfxU5K-Wowi5AkZpwm6lwnb1Il_cL4P_MaTBIimPO1NzDV5BNWF3W5thyphenhyphenzKjDHw_jrvp1t3muB_3yeBzeuNCPZHtOlsLgZS4x8IYLGUm7FRMON5Ky43uNnBC/s1600/Class1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="106" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrpby_qF5P1NPRBXweEoJjkfxU5K-Wowi5AkZpwm6lwnb1Il_cL4P_MaTBIimPO1NzDV5BNWF3W5thyphenhyphenzKjDHw_jrvp1t3muB_3yeBzeuNCPZHtOlsLgZS4x8IYLGUm7FRMON5Ky43uNnBC/s320/Class1.png" width="320" /></a></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkXl57cTrGbfSrfg3L2d96ScFkFdUWLyL8NBxjARnQ4BgY1Lg4SSw3XHtJPU4lDnt5CjfF23xJvxHjwgdtQJf-VoTTpQ55pfWbWKDI3HmsAn2F1LZKxX5FL-1Fdf9yLaIo5yIhVQyvCHJ0/s1600/Class2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="235" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkXl57cTrGbfSrfg3L2d96ScFkFdUWLyL8NBxjARnQ4BgY1Lg4SSw3XHtJPU4lDnt5CjfF23xJvxHjwgdtQJf-VoTTpQ55pfWbWKDI3HmsAn2F1LZKxX5FL-1Fdf9yLaIo5yIhVQyvCHJ0/s400/Class2.png" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQrtctei-e-5fQC5lqEK4CYnuzsaifMmP35HH3cGHEWpqojSgRBkCWjdlQmX0mQLvFh6mOrdJlpWkkC9RNspdoa_SmcYxIh3l3MjdfOomRTiJG3M9VPWPR4zePZiF-K07QeI8tBvBLl1PQ/s1600/Class3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="235" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQrtctei-e-5fQC5lqEK4CYnuzsaifMmP35HH3cGHEWpqojSgRBkCWjdlQmX0mQLvFh6mOrdJlpWkkC9RNspdoa_SmcYxIh3l3MjdfOomRTiJG3M9VPWPR4zePZiF-K07QeI8tBvBLl1PQ/s400/Class3.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
I mentioned in a lot of the feedback that you need to show the multiplicity / associations of the classes. This can be done as shown</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtPt7I2FcQdDhV478-AuHyTRSd_C_KgTNDtvfiVbG4wAwtrCpW0NpDB3z02dPpj2_3drtypSafMqIQSahdGkFGgVBACzzqjHQScezlg1wVtMgr6cnWUL4vZSFjFk8Pi_6zke15-EPVP64r/s1600/Class4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="286" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtPt7I2FcQdDhV478-AuHyTRSd_C_KgTNDtvfiVbG4wAwtrCpW0NpDB3z02dPpj2_3drtypSafMqIQSahdGkFGgVBACzzqjHQScezlg1wVtMgr6cnWUL4vZSFjFk8Pi_6zke15-EPVP64r/s320/Class4.png" width="320" /></a></div>
<h3>
Associations and Containment</h3>
<div>
In a lot of the designs there are classes that show some sort of relation, however no mention of a container is shown in the attributes.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7hZJntYeGcF4G4rQ1rbi0XDUKmfr0YjDy9A_AYKaNoHNP0NazSRFC89PEfeNFVqu2jruEN1bunZx-dRT77IYwgjqzluNBuYDc11cBEwHdwrswidkIhck1H9rkObbYPbwhIe74KFIoxW9-/s1600/Class5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="227" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7hZJntYeGcF4G4rQ1rbi0XDUKmfr0YjDy9A_AYKaNoHNP0NazSRFC89PEfeNFVqu2jruEN1bunZx-dRT77IYwgjqzluNBuYDc11cBEwHdwrswidkIhck1H9rkObbYPbwhIe74KFIoxW9-/s640/Class5.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
In this case we use a filled diamond and it always gives a multiplicity of 1 or 0 .. 1, this implies ownership and when the car is destroyed so it the Engine, this is broadly know as <a href="http://en.wikipedia.org/wiki/Object_composition">composition</a>.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdIEwK1k0lbToUVDefIShQXV2dqh2uBEQFLxRV651n4vYBZXtXcJPkxs3EYwKf6Oe8GjNy58pF8MyWTyZAjYJvrtxoVz2Dp7Uet-DH4xDUCUyas46ev3UpqBoGvxRGUpjwiukTIMursFWs/s1600/Class6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="153" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdIEwK1k0lbToUVDefIShQXV2dqh2uBEQFLxRV651n4vYBZXtXcJPkxs3EYwKf6Oe8GjNy58pF8MyWTyZAjYJvrtxoVz2Dp7Uet-DH4xDUCUyas46ev3UpqBoGvxRGUpjwiukTIMursFWs/s640/Class6.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
<a href="http://en.wikipedia.org/wiki/Aggregation_(object-oriented_programming)#Aggregation">Aggregation</a> differs from composition as it doesn’t necessarily imply ownership. This is usually implemented by containing a reference to another object where the lifetime is determined elsewhere.</div>
<div class="separator" style="clear: both;">
<br /></div>
<h3>
Physics</h3>
<div>
Those of you that mentioned doing some form of physics need to look at two things. Once getting a time into your program. This can be done easily in Qt using the <a href="http://qt-project.org/doc/qt-4.8/qtimer.html">QTimer</a> classes. There are several NGL demos that use this and you can see how in the code.</div>
<div>
<br /></div>
<div>
The other thing you will need to write is an integrator. If you code is well designed this should be able to be replaced with different types. I suggest starting with a basic <a href="http://en.wikipedia.org/wiki/Euler_method">Euler integrator</a> then progress to a more stable <a href="http://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods">RK 4 integrator</a>. </div>
<div>
<br /></div>
<div>
If you are not writing your own Physics but need to do some basic physics for a game there are a number of solutions, the labs have both <a href="http://www.ode.org/">ODE</a> and <a href="http://bulletphysics.org/wordpress/">Bullet</a> installed and there is already an ODE demo for NGL with a bullet one coming soon.</div>
<div>
<br /></div>
<div>
If you are doing a 2D game or a basic 2.5D platform I would suggest <a href="http://box2d.org/">Box2D</a> as it is much simpler and more suited to these style of game. </div>
<div>
<br /></div>
<h3>
L-Systems</h3>
<div>
If you are writing an L-System I would suggest reading "<a href="http://algorithmicbotany.org/papers/#abop">The algorithmic beauty of plants</a>". For a general design I would suggest reading in your grammar rules from a text file (you get marks for this anyway). There is a basic parser framework in the lecture code <a href="http://nccastaff.bournemouth.ac.uk/jmacey/ASD/code/Lecture3Code.tgz">here</a> and you can use <a href="http://www.boost.org/doc/libs/1_51_0/libs/tokenizer/index.html">boost::tokenize</a> to most of the hard work.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
It is also important to only build the grammar up once and create the geometry and store it. As this is a recursive system the generation may be slow and adding in drawing will make this a really slow system once a few iterations are used. The system should only update when a parameter is changed and this should generate geometry to be drawn every frame and not the other way around.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Also start in 2D and generate a simple <a href="http://en.wikipedia.org/wiki/Turtle_graphics">turtle class</a>, this can later be upgraded to a 3D system once the basic system is working.</div>
<h3>
Flocking System</h3>
<div>
One of the hardest problems with a flocking system is managing the communication between the boids. All of the boids need to know where they are in the world as well as have some knowledge of each other. It is possible to use a naive list and check each boid against the others however this will lead to an <a href="http://en.wikipedia.org/wiki/Computational_complexity_theory">O(n^2) complexity</a> and slow things down. </div>
<div>
<br /></div>
<div>
For the initials test this will be ok, however it should be factored into the design that at some stage this may become a problem at a later stage.</div>
<div>
<br /></div>
<div>
To get the flock working initially start with the flock centre rule. If you add the position of all the boids and divide by the number of boids this will give you the <a href="http://en.wikipedia.org/wiki/Centroid#Of_a_finite_set_of_points">centroid</a>. You can then calculate the direction vector for the flock centre on a per boid basis.</div>
<div>
<br /></div>
<div>
The other basic rules can then be added. It is also a good idea to add a weight to each of the rules and see the different effects. This can be loaded in a text file (or using a GUI) .<br />
<br />
<h3>
Next Steps</h3>
</div>
<div>
You should have a basic design, re-visit it based on the comments above and see what is missing. Once you have done this you should start to write the classes. I usually create the basic classes so they can be instantiated and connected together. Once this is done start adding the functionality as required.</div>
<div>
<br /></div>
<div>
For a more in detail step by step guide look as the examples from last year <a href="http://jonmacey.blogspot.co.uk/2012/02/getting-started-with-programming.html">here</a> note that some of the data types from these examples have changed but the principles are still the same.</div>
<div>
<br /></div>
<div>
Good luck and if you have any more questions ask me in the lab.</div>
<div>
<br /></div>
<div>
Jon</div>
<div>
<br /></div>
Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com0tag:blogger.com,1999:blog-6958533929285860874.post-83159651238095692992012-12-13T14:17:00.000+00:002012-12-13T14:17:37.448+00:00Creating a local cmake library installIn one of my previous <a href="http://jonmacey.blogspot.co.uk/2012/11/libraries-include-paths-and-other-linux.html">posts</a> I talked about how to install your own versions of a library when you don't have root access.<br />
<br />
In this post I will show you how to install a <a href="http://www.cmake.org/">cmake</a> style project in the same way.<br />
<br />
For this example I'm going to use <a href="http://code.google.com/p/alembic/">alembic</a> as the target library to build and it will be installed in the directory $(HOME)/<br />
<br />
First we will download the alembic source<br />
<br />
<pre>hg clone https://code.google.com/p/alembic/
cd alembic
</pre>
Now we need to configure cmake to use the correct path for our local install this is done with the -DCMAKE_INSTALL_PREFIX:PATH= command as follows where the = is followed by where you want to install alembic
<br />
<pre>cmake -DCMAKE_INSTALL_PREFIX:PATH=/home/jmacey/
make -j 4
make install
</pre>
In the case of the current version of Alembic this will install to the directory alembic-1.1.2<br />
<br />
<h3>
Testing</h3>
<div>
A simple test program to read alembic files from the command line and write out the contents has been created as follows</div>
<pre class="brush:cpp" title="read">
#include <Alembic/AbcGeom/All.h>
#include <Alembic/AbcCoreAbstract/All.h>
#include <Alembic/AbcCoreHDF5/All.h>
#include <Alembic/Abc/ErrorHandler.h>
#include <iostream>
#include <cstdlib>
using namespace Alembic::AbcGeom; // Contains Abc, AbcCoreAbstract
int main(int argc, char **argv)
{
if(argc <2 )
{
std::cerr <<"usage Alembic [filename]\n";
exit(EXIT_FAILURE);
}
IArchive archive( Alembic::AbcCoreHDF5::ReadArchive(),
argv[1] );
std::cout<<"traversing archive for elements\n";
IObject obj=archive.getTop();
unsigned int numChildren=obj.getNumChildren();
std::cout<< "found "<<numChildren<<" children in file\n";
for(int i=0; i<numChildren; ++i)
{
std::cout<<obj.getChildHeader(i).getFullName()<<"\n";
IObject child(obj,obj.getChildHeader(i).getName());
std::cout<<"Children "<<child.getNumChildren()<<"\n";
const MetaData &md = child.getMetaData();
std::cout<<md.serialize() <<"\n";
for(int x=0; x<child.getNumChildren(); x++)
{
IObject child2(child,child.getChildHeader(x).getName());
const MetaData &md2 = child2.getMetaData();
if( IPolyMeshSchema::matches( md2 ) || ISubDSchema::matches( md2 ))
{
std::cout<<"Found a mesh "<<child2.getName()<<"\n";
}
}
}
return EXIT_SUCCESS;
}
</pre>
To compile this I have created a QMAKE project which sets the paths to point to the correct install of alembic
<pre class="brush:cpp" title="alembic.pro">
TARGET=Alembic
DESTDIR=./
CONFIG += console
CONFIG -= app_bundle
SOURCES+=read.cpp
INCLUDEPATH+=/home/jmacey/alembic-1.1.2/include/
INCLUDEPATH+=/usr/local/include/OpenEXR
ALEMBIC_DIR=/home/jmacey/alembic-1.1.2
ALEMBIC_LIB=/home/jmacey/alembic-1.1.2/lib/static
LIBS+= -L$$ALEMBIC_LIB
LIBS+= -lAbcWFObjConvert
LIBS+= -lAlembicAbcCollection
LIBS+= -lAlembicAbcCoreHDF5
LIBS+= -lAlembicAbc
LIBS+= -lAlembicAbcCoreAbstract
LIBS+= -lAlembicAbcGeom
LIBS+= -lAlembicUtil
LIBS+=-lImath
LIBS+=-lHalf
LIBS+=-lIex
LIBS+=-lhdf5
LIBS+=-lhdf5_hl
</pre>
In the university labs most of these libs will be in the paths but you will need to change the ALEMBIC_DIR to the correct path for your install.
Finally the LD_LIBRARY_PATH needed to be amended to point to the correct OpenEXR files by adding the following export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib/ to my .bashrc, this may not be needed on your own versions.Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com0tag:blogger.com,1999:blog-6958533929285860874.post-84914048518942359702012-11-29T10:19:00.000+00:002012-11-29T10:19:50.009+00:00Using NGL with SDL<a href="http://www.libsdl.org/">SDL</a> is a very good library for games development and very useful for cross platform development. In this post I will explain how to install and configure <a href="http://www.libsdl.org/hg.php">SDL 2.0 (HG)</a> for use with OpenGL and my NGL:: library. The source code can be downloaded using bzr branch http://nccastaff.bournemouth.ac.uk/jmacey/Code/SDLNGL from <a href="http://nccastaff.bournemouth.ac.uk/jmacey/GraphicsLib/Demos/index.html">here</a><br />
<h3>
SDL installation</h3>
<div>
The latest version of SDL handles creating "core profile" OpenGL contexts on mac so this will be required. Earlier version of SDL will not work as they do not support the creation of the correct context for OpenGL under the mac. I decided to do a local install of SDL and if you wish to use this in the Labs at the University you will have to do the same thing as you don't have root permission to install the libs. The process of installation is similar to the one outlined <a href="http://jonmacey.blogspot.co.uk/2012/11/libraries-include-paths-and-other-linux.html">here</a> and I'm going to install the libraries in a directory called $(HOME)/SDL2.0 this is important as the makefile will also use this location to find the sdl2-config script at a later date.</div>
<div>
<br /></div>
<div>
The following commands will download and install the libraries and build it into the correct directory.</div>
<pre>mkdir SDL2.0
tar vfxz SDL-2.0.tar.gz
cd SDL-2.0.0-6673/
./configure --prefix=/home/jmacey/SDL2.0 (change to your home dir)
make -j 8
make install
</pre>
This will install everything into the SDL2 directory and you will have a structure like this
<br />
<pre>bin include lib share
</pre>
To test this is working do the following
<br />
<pre>cd ~/SDL2.0/bin
./sdl2-config --cflags --libs
-I/Volumes/home/jmacey/SDL2.0/include/SDL2 -D_THREAD_SAFE
-L/Volumes/home/jmacey/SDL2.0/lib -lSDL2
</pre>
<h3>
SDL NGL Demo</h3>
<div>
The demo is split into two main modules. The main.cpp file will create the SDL and OpenGL context, and handle the processing of events. The NGLDraw class will contain all OpenGL setup and drawing routines.</div>
<h4>
Setup and basic SDL</h4>
<div>
To use SDL we need to include the <SDL.h> header, this will be placed in the path by the following command in the Qt .pro file.</div>
<pre class="brush:cpp" title="adding sdl2-config to qmake">QMAKE_CXXFLAGS+=$$system($$(HOME)/SDL2.0/bin/sdl2-config --cflags)
message(output from sdl2-config --cflags added to CXXFLAGS= $$QMAKE_CXXFLAGS)
LIBS+=$$system($$(HOME)/SDL2.0/bin/sdl2-config --libs)
message(output from sdl2-config --libs added to LIB=$$LIBS)
</pre>
For more info see this <a href="http://jonmacey.blogspot.co.uk/2012/10/how-to-run-sdl-config-in-qt-project.html">post</a>
<br />
<br />
First we need to initialise the SDL video subsystem using the following command<br />
<br />
<pre class="brush:cpp" title="init sdl">// Initialize SDL's Video subsystem
if (SDL_Init(SDL_INIT_VIDEO) < 0 )
{
// Or die on error
SDLErrorExit("Unable to initialize SDL");
}
</pre>
There is also a helper function to exit SDL gracefully
<br />
<pre class="brush:cpp" title="SDLErrorExit">void SDLErrorExit(const std::string &_msg)
{
std::cerr<<_msg<<"\n";
std::cerr<<SDL_GetError()<<"\n";
SDL_Quit();
exit(EXIT_FAILURE);
}
</pre>
Next we create the basic window, in this case I get the size of the screen and configure the screen to be centred and half max screen width and height
<br />
<pre class="brush:cpp" title="creating a window">// now get the size of the display and create a window we need to init the video
SDL_Rect rect;
SDL_GetDisplayBounds(0,&rect);
// now create our window
SDL_Window *window=SDL_CreateWindow("SDLNGL",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,
rect.w/2,rect.h/2,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
// check to see if that worked or exit
if (!window)
{
SDLErrorExit("Unable to create window");
}
</pre>
<h3>
Creating an OpenGL context</h3>
<div>
SDL 2.0 uses a <a href="http://wiki.libsdl.org/moin.cgi/SDL_GL_CreateContext">SDL_GLContext</a> to hold the information about the current GL context. There are many flags we need to setup our context and these are handled using the <a href="http://wiki.libsdl.org/moin.cgi/SDL_GL_SetAttribute">SDL_GL_SetAttribute</a> function. I've also discovered on my linux build that some of these flags don't work and cause crashes (particularly creating a core profile context). To overcome this conditional compilation is used as shown in the following function.</div>
<div>
<br /></div>
<pre class="brush:cpp" title="createOpenGLContext">SDL_GLContext createOpenGLContext(SDL_Window *window)
{
// Request an opengl 3.2 context first we setup our attributes, if you need any
// more just add them here before the call to create the context
// SDL doesn't have the ability to choose which profile at this time of writing,
// but it should default to the core profile
// for some reason we need this for mac but linux crashes on the latest nvidia drivers
// under centos
#ifdef DARWIN
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
#endif
// set multi sampling else we get really bad graphics that alias
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES,4);
// Turn on double buffering with a 24bit Z buffer.
// You may need to change this to 16 or 32 for your system
// on mac up to 32 will work but under linux centos build only 16
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
// enable double buffering (should be on by default)
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
//
return SDL_GL_CreateContext(window);
}
</pre>
Care must be taken with setting the depth size, under mac osx it works with 32 bit, under linux I set to 16 and on some machines 24 will work.
The following code configures the GL context and clears the screen.
<br />
<pre class="brush:cpp">SDL_GLContext glContext=createOpenGLContext(window);
if(!glContext)
{
SDLErrorExit("Problem creating OpenGL context");
}
// make this our current GL context (we can have more than one window but in this case not)
SDL_GL_MakeCurrent(window, glContext);
/* This makes our buffer swap syncronized with the monitor's vertical refresh */
SDL_GL_SetSwapInterval(1);
// now clear the screen and swap whilst NGL inits (which may take time)
glClear(GL_COLOR_BUFFER_BIT);
SDL_GL_SwapWindow(window);
</pre>
Now this has been done we can use NGL and create our graphics. In this case the NGLDraw class is a re-working of the SimpleNGL demo, it initialises GLEW if required. The following code shows the creation of the NGLDraw class and the key and mouse processing.
<br />
<pre class="brush:cpp" title="processing loop">NGLDraw ngl;
// resize the ngl to set the screen size and camera stuff
ngl.resize(rect.w,rect.h);
while(!quit)
{
while ( SDL_PollEvent(&event) )
{
switch (event.type)
{
// this is the window x being clicked.
case SDL_QUIT : quit = true; break;
// process the mouse data by passing it to ngl class
case SDL_MOUSEMOTION : ngl.mouseMoveEvent(event.motion); break;
case SDL_MOUSEBUTTONDOWN : ngl.mousePressEvent(event.button); break;
case SDL_MOUSEBUTTONUP : ngl.mouseReleaseEvent(event.button); break;
case SDL_MOUSEWHEEL : ngl.wheelEvent(event.wheel);
// if the window is re-sized pass it to the ngl class to change gl viewport
// note this is slow as the context is re-create by SDL each time
case SDL_WINDOWEVENT :
int w,h;
// get the new window size
SDL_GetWindowSize(window,&w,&h);
ngl.resize(w,h);
break;
// now we look for a keydown event
case SDL_KEYDOWN:
{
switch( event.key.keysym.sym )
{
// if it's the escape key quit
case SDLK_ESCAPE : quit = true; break;
case SDLK_w : glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); break;
case SDLK_s : glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); break;
case SDLK_f :
SDL_SetWindowFullscreen(window,SDL_TRUE);
glViewport(0,0,rect.w,rect.h);
break;
case SDLK_g : SDL_SetWindowFullscreen(window,SDL_FALSE); break;
default : break;
} // end of key process
} // end of keydown
default : break;
} // end of event switch
} // end of poll events
// now we draw ngl
ngl.draw();
// swap the buffers
SDL_GL_SwapWindow(window);
}
</pre>
The most important call here is the SDL_GL_SwapWindow call which tells SDL to swap the buffers and re-draw.
<br />
<h3>
NGLDraw class </h3>
Most of the NGLDraw class is basic ngl code, the constructor is used to initialise ngl and create the camera, light and materials. The draw method grabs and instance of the primitives class and draws the teapot, both of which are similar to the Qt NGL demos. The main difference is the processing of the mouse input. I still use the same flags and attributes to store the rotations and position data, however the SDL mouse data is used to grab x,y and button values. This is shown in the following code.<br />
<pre class="brush:cpp" title="mouse processing">void NGLDraw::mouseMoveEvent (const SDL_MouseMotionEvent &_event)
{
if(m_rotate && _event.state &SDL_BUTTON_LMASK)
{
int diffx=_event.x-m_origX;
int diffy=_event.y-m_origY;
m_spinXFace += (float) 0.5f * diffy;
m_spinYFace += (float) 0.5f * diffx;
m_origX = _event.x;
m_origY = _event.y;
this->draw();
}
// right mouse translate code
else if(m_translate && _event.state &SDL_BUTTON_RMASK)
{
int diffX = (int)(_event.x - m_origXPos);
int diffY = (int)(_event.y - m_origYPos);
m_origXPos=_event.x;
m_origYPos=_event.y;
m_modelPos.m_x += INCREMENT * diffX;
m_modelPos.m_y -= INCREMENT * diffY;
this->draw();
}
}
void NGLDraw::mousePressEvent (const SDL_MouseButtonEvent &_event)
{
// this method is called when the mouse button is pressed in this case we
// store the value where the maouse was clicked (x,y) and set the Rotate flag to true
if(_event.button == SDL_BUTTON_LEFT)
{
m_origX = _event.x;
m_origY = _event.y;
m_rotate =true;
}
// right mouse translate mode
else if(_event.button == SDL_BUTTON_RIGHT)
{
m_origXPos = _event.x;
m_origYPos = _event.y;
m_translate=true;
}
}
void NGLDraw::mouseReleaseEvent (const SDL_MouseButtonEvent &_event)
{
// this event is called when the mouse button is released
// we then set Rotate to false
if (_event.button == SDL_BUTTON_LEFT)
{
m_rotate=false;
}
// right mouse translate mode
if (_event.button == SDL_BUTTON_RIGHT)
{
m_translate=false;
}
}
void NGLDraw::wheelEvent(const SDL_MouseWheelEvent &_event)
{
// check the diff of the wheel position (0 means no change)
if(_event.y > 0)
{
m_modelPos.m_z+=ZOOM;
this->draw();
}
else if(_event.y <0 )
{
m_modelPos.m_z-=ZOOM;
this->draw();
}
// check the diff of the wheel position (0 means no change)
if(_event.x > 0)
{
m_modelPos.m_x-=ZOOM;
this->draw();
}
else if(_event.x <0 )
{
m_modelPos.m_x+=ZOOM;
this->draw();
}
}
</pre>
The rest of the code is fairly self explanatory if you've use NGL before. Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com0tag:blogger.com,1999:blog-6958533929285860874.post-69221918040284187042012-11-22T09:39:00.004+00:002012-11-22T09:57:02.912+00:00Libraries, Include paths and other Linux funI've been getting a few mails about installing libraries on the Lab machines and also where to find certain things. This post will explain a few things about how to setup your build environment to allow you to install different libs in your home directories and use them your self. It will also help people who wish to install / setup a build environment when you don't have root on the machine you are using.<br />
<br />
<h3>
Getting Started</h3>
<div>
First are you sure the library is not installed? On the lab centos machine we have installed most libraries you may need for doing computer graphics work. You can list the currently installed libs by using the <a href="http://linux.die.net/man/8/ldconfig">ldconfig -p</a> command. If you feed this into <a href="http://unixhelp.ed.ac.uk/CGI/man-cgi?grep">grep</a> you can filter the results. For example to search for the location of the iMath library we can do the following<br />
<br /></div>
<pre>ldconfig -p | grep -i imath
libImath.so.6 (libc6,x86-64) => /usr/lib64/libImath.so.6
</pre>
<br />
You can see the path of the library from this ( /usr/lib64 ) and this can be added to the link path using the -L command on the compiler (more on this later).
<br />
<br />
If this doesn't find what you are looking for, the package may not be a dynamic library. We can search for static libs using the <a href="http://linux.die.net/man/1/locate">locate</a> command as follows
<br />
<pre></pre>
<pre>locate libode
/usr/local/lib/libode.a
/usr/local/lib/libode.la
</pre>
<br />
If you can confirm that the library is installed the next thing is to find the headers, again we can use the locate command. The following will find a specific header file (usually we will get a compile message saying can't find xxx.h).<br />
<br />
<pre>locate ImathColor.h
/opt/autodesk/maya2012-x64/devkit/Alembic/include/AlembicPrivate/OpenEXR/ImathColor.h
/opt/hfs12.1.77/toolkit/include/OpenEXR/ImathColor.h
/usr/local/include/OpenEXR/ImathColor.h
/usr/local/include/OpenEXR/PyImathColor.h
</pre>
You will see that in this case it is in several locations as some of the packages installed have included it. It is best to always use the /usr paths as these will correspond to the installed libraries. In this case we can add the include path -I/usr/local/include/<br />
<h3>
Setting things in Qt Creator</h3>
<div>
Qt creator uses <a href="http://qt-project.org/doc/qt-4.8/qmake-manual.html">qmake</a> to configure the projects and the project locations. In particular there are two flags we need to set to add libraries and include paths as follows.</div>
<div>
<br /></div>
<pre class="brush:cpp">INCLUDEPATH+=/usr/local/include/collada-dom2.4/
LIBS+=-L/usr/lib -lcolladadom150
</pre>
Using the += option we can concatenate to the INCLUDEPATH keyword and absolute path to search for the libs, this will be translated to a -I flag in the compiler command line.
The LIBS flag is passed verbatim to the linker so we need to use the correct commands in this case we use -L to indicate a library search path and -l for the library to be included. Note that the -l flag ignores the prefix lib and the postfix .so.x.x etc.
<br />
<br />
Once this is done your projects should be fine to run. You can also build and include libs in your own directories and link them using the project paths similar to above. If the lib created is a .a file it is a <a href="http://en.wikipedia.org/wiki/Static_library">static lib</a> it will be included in the build of the program. If you are linking to a dynamic lib (.so) you will need to tell the <a href="http://en.wikipedia.org/wiki/Dynamic_linker">runtime linker</a> where to find the library by setting the LD_LIBRARY_PATH environment variable (this is how the <a href="http://nccastaff.bournemouth.ac.uk/jmacey/GraphicsLib/index.html">NGL lib</a> is configured).<br />
<h3>
An Example</h3>
<div>
This example will show how to install a source package in a custom location (your home dir) using a typical <a href="http://www.gnu.org/software/automake/">automake</a> style project found in most linux source packages. </div>
<div>
<br /></div>
<div>
First I'm going to download the <a href="http://www.ode.org/">ode source</a> and extract it.</div>
<pre>
wget http://sourceforge.net/projects/opende/files/latest/download?source=files
tar vfxj ode-0.12.tar.bz2
cd ode-0.12
</pre>
Typically now you would run ./configure; make; sudo make install; however as most users do not have access to sudo this will not work as the install will attempt to write files in the /usr file system which you don't have permission to.
Instead we can ask the configure script to use another custom location which we do have permission to. In this case I'm going to use /home/jmacey/myOde as follows
<pre>
./configure --prefix /home/jmacey/myOde
make
make install
</pre>
The install will now place all the files in the directory $(HOME)/myOde and we can adjust our build paths accordingly, the following list shows what has been installed.
<pre>
find .
.
./include
./include/ode
./include/ode/error.h
./include/ode/odeconfig.h
./include/ode/timer.h
./include/ode/odemath.h
./include/ode/contact.h
./include/ode/odeinit.h
./include/ode/rotation.h
./include/ode/memory.h
./include/ode/collision.h
./include/ode/objects.h
./include/ode/collision_space.h
./include/ode/collision_trimesh.h
./include/ode/compatibility.h
./include/ode/common.h
./include/ode/mass.h
./include/ode/ode.h
./include/ode/export-dif.h
./include/ode/odemath_legacy.h
./include/ode/odecpp.h
./include/ode/matrix.h
./include/ode/misc.h
./include/ode/odecpp_collision.h
./lib
./lib/libode.la
./lib/pkgconfig
./lib/pkgconfig/ode.pc
./lib/libode.a
./bin
./bin/ode-config
</pre>
Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com0tag:blogger.com,1999:blog-6958533929285860874.post-13223506359656282862012-11-12T19:50:00.001+00:002012-11-12T19:51:55.441+00:00Sponza Demo Pt 3 The GroupedObj classIn the previous <a href="http://jonmacey.blogspot.co.uk/2012/11/sponza-demo-pt-2-mtl-class.html">post</a> I described the Mtl class. This video blog will show the design and ideas behind the the GroupedObj class as shown in the following diagram<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVKECP9dtx9gOh9W4nhq8mbhOUjmHtMXJlL5h-dObd1O1J-jzkPmhMvM_uKDCcE_lph3VV21YdHnhyphenhyphenfncCN1Z55YVnGdwWir7c0PqcoQaEqiwxw0MXR7lYyNvwUERaGbKHKurBRGHsuHcT/s1600/GroupedObj.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVKECP9dtx9gOh9W4nhq8mbhOUjmHtMXJlL5h-dObd1O1J-jzkPmhMvM_uKDCcE_lph3VV21YdHnhyphenhyphenfncCN1Z55YVnGdwWir7c0PqcoQaEqiwxw0MXR7lYyNvwUERaGbKHKurBRGHsuHcT/s640/GroupedObj.png" width="636" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<br />
<iframe allowfullscreen="allowfullscreen" frameborder="0" height="315" src="http://www.youtube.com/embed/IYjiIyEr_T8?list=UUOs9ZDVMPIzzqTtJHm8Tb4w&hl=en_GB" width="560"></iframe>
<br />
<br />
<br />
<iframe allowfullscreen="allowfullscreen" frameborder="0" height="315" src="http://www.youtube.com/embed/HGDjVL80Ljg?rel=0" width="420"></iframe>
<br />
<iframe allowfullscreen="allowfullscreen" frameborder="0" height="315" src="http://www.youtube.com/embed/Qa2GthFNG3o?rel=0" width="420"></iframe>
<iframe allowfullscreen="allowfullscreen" frameborder="0" height="315" src="http://www.youtube.com/embed/LtxFOweReOU?rel=0" width="420"></iframe>
<iframe allowfullscreen="allowfullscreen" frameborder="0" height="315" src="http://www.youtube.com/embed/XM0NewXzMt8?rel=0" width="420"></iframe><br />
You can get the code from <a href="http://nccastaff.bournemouth.ac.uk/jmacey/GraphicsLib/Demos/index.html">here</a> Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com0tag:blogger.com,1999:blog-6958533929285860874.post-54876800727989445682012-11-12T13:58:00.000+00:002012-11-12T13:58:33.297+00:00Sponza Demo Pt 2 Mtl classIn the previous <a href="http://jonmacey.blogspot.co.uk/2012/11/sponza-demo-pt-1-initial-design.html">post</a> I discussed the basic overview of the system this post will explain how the Mtl class works and how is was developed.<br />
<br />
The mtl file has the following basic structure, where each element may or may not be present.<br />
<br />
<pre class="brush:cpp" title="mtl file example">newmtl leaf
Ns 10.0000
Ni 1.5000
d 1.0000
Tr 0.0000
Tf 1.0000 1.0000 1.0000
illum 2
Ka 0.5880 0.5880 0.5880
Kd 0.5880 0.5880 0.5880
Ks 0.0000 0.0000 0.0000
Ke 0.0000 0.0000 0.0000
map_Ka textures\sponza_thorn_diff.tga
map_Kd textures\sponza_thorn_diff.tga
map_d textures\sponza_thorn_mask.tga
map_bump textures\sponza_thorn_ddn.tga
bump textures\sponza_thorn_ddn.tga
</pre>
<br />
The newmtl keyword is used to indicate that a new material is being specified and the rest of the elements are part of that material. To store this information I decided to use a std::map using a std::string as the key which will be the name following the newmtl (in the above example this is "leaf"). The map will then store the following structure.
<br />
<pre class="brush:cpp" title="mtlItem">typedef struct
{
float Ns;
float Ni;
float d;
float Tr;
int illum;
ngl::Vec3 Tf;
ngl::Vec3 Ka;
ngl::Vec3 Kd;
ngl::Vec3 Ks;
ngl::Vec3 Ke;
std::string map_Ka;
std::string map_Kd;
std::string map_d;
std::string map_bump;
std::string bump;
GLuint map_KaId;
GLuint map_KdId;
GLuint map_dId;
GLuint map_bumpId;
GLuint bumpId;
}mtlItem;
</pre>
You will notice that this replicates the mtl format shown above and also have several extra items which have the extra postfix ID, these will be used to store the OpenGL texture ID's of the textures once loaded. I also made the design decision not to follow my usual coding standard for the structure as this would make it easier to follow what is happening in the mtl file.
<br />
<br />
<h3>
<span style="font-size: large;"><b>Class functional design</b></span></h3>
<br />
The main elements of the class are shown in the following class diagram.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKB8wGmP8qoKeUOSfV5hoBXPTUiQNXUnpeNuJhssjqL_-Uc276l1F2N6hziibsgCUoy4x2mWxzqTa9rSU7ExMLM1cmD8FtClXJ0K_EdBObHPSRKCziGdIMj12-ILvC5Aok_GWJqwsm1p92/s1600/MtlClass.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="419" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKB8wGmP8qoKeUOSfV5hoBXPTUiQNXUnpeNuJhssjqL_-Uc276l1F2N6hziibsgCUoy4x2mWxzqTa9rSU7ExMLM1cmD8FtClXJ0K_EdBObHPSRKCziGdIMj12-ILvC5Aok_GWJqwsm1p92/s640/MtlClass.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
The main functional design of the Mtl class is split into two areas, first the loading and parsing of the original mtl file. This can either be done in the constructor or using the load method. Next is the actual use of the class data. To allow easy access to this data iterators have been exposed for the std::map as well as other methods. Finally we have the ability to save and load the data in a binary format to save the parse time of reading the original files.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<h3>
<span style="font-size: large;"><b>Parsing the mtl file</b></span></h3>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
As the structure of the mtl file is quite simple I decided a full blown parser was not required. Instead I decided to use the <a href="http://www.boost.org/doc/libs/1_52_0/libs/tokenizer/">boost::tokenizer</a> template to process the data. The file is opened and the data read a line at a time. The tokenizer splits the data and looks for the keywords, which are then processed one at a time. This is shown in the following code.</div>
<pre class="brush:cpp"> // this is the line we wish to parse
std::string lineBuffer;
// say which separators should be used in this
// case Spaces, Tabs and return \ new line
boost::char_separator<char> sep(" \t\r\n");
// loop through the file
while(!fileIn.eof())
{
// grab a line from the input
getline(fileIn,lineBuffer,'\n');
// make sure it's not an empty line
if(lineBuffer.size() >1)
{
// now tokenize the line
tokenizer tokens(lineBuffer, sep);
// and get the first token
tokenizer::iterator firstWord = tokens.begin();
// now see if it's a valid one and call the correct function
if( *firstWord =="newmtl")
{
// add to our map it is possible that a badly formed file would not have an mtl
// def first however this is so unlikely I can't be arsed to handle that case.
// If it does crash it could be due to this code.
//std::cout<<"found "<<m_currentName<<"\n";
parseString(firstWord,m_currentName);
m_current= new mtlItem;
// These are the OpenGL texture ID's so set to zero first (for no texture)
m_current->map_KaId=0;
m_current->map_KdId=0;
m_current->map_dId=0;
m_current->map_bumpId=0;
m_current->bumpId=0;
m_materials[m_currentName]=m_current;
}
else if(*firstWord =="Ns")
{
parseFloat(firstWord,m_current->Ns);
}
else if(*firstWord =="Ni")
{
parseFloat(firstWord,m_current->Ni);
}
else if(*firstWord =="d")
{
parseFloat(firstWord,m_current->d);
}
else if(*firstWord =="Tr")
{
parseFloat(firstWord,m_current->Tr);
}
else if(*firstWord =="Tf")
{
parseVec3(firstWord,m_current->Tf);
}
else if(*firstWord =="illum")
{
parseInt(firstWord,m_current->illum);
}
else if(*firstWord =="Ka")
{
parseVec3(firstWord,m_current->Ka);
}
else if(*firstWord =="Kd")
{
parseVec3(firstWord,m_current->Kd);
}
else if(*firstWord =="Ks")
{
parseVec3(firstWord,m_current->Ks);
}
else if(*firstWord =="Ke")
{
parseVec3(firstWord,m_current->Ke);
}
else if(*firstWord == "map_Ka")
{
parseString(firstWord,m_current->map_Ka);
}
else if(*firstWord == "map_Kd")
{
parseString(firstWord,m_current->map_Kd);
}
else if(*firstWord == "map_d")
{
parseString(firstWord,m_current->map_d);
}
else if(*firstWord == "map_bump")
{
parseString(firstWord,m_current->map_bump);
}
else if(*firstWord == "bump")
{
parseString(firstWord,m_current->bump);
}
} // end zero line
} // end while
// as the trigger for putting the meshes back is the newmtl we will always have a hanging one
// this adds it to the list
m_materials[m_currentName]=m_current;
</pre>
The individual parse functions then use the boost::lexical_cast template to convert the values as shown in the following example
<br />
<pre class="brush:cpp" title="using lexical_cast">void Mtl::parseFloat(tokenizer::iterator &_firstWord, float &io_f)
{
// skip first token
++_firstWord;
// use lexical cast to convert to float then increment the itor
io_f=boost::lexical_cast<float>(*_firstWord++);
}</pre>
<h3>
<span style="font-size: large;"><b>A Subtle Bug</b></span></h3>
On problem I had when initially using this system was that the texture files were not found when loading. It turned out that as this was a windows mtl file it was using \ in the file names and I was running under mac osx and linux which expected /. To overcome this problem the filename paths are parsed and / converted to \ and visa-versa depending upon operating system.<br />
<br />
<pre class="brush:cpp" title="parsing the /">void Mtl::parseString(tokenizer::iterator &_firstWord, std::string &io_s)
{
++_firstWord;
// there is a chance that we have either windows or linux slashes
// need to process file name for either
io_s=*_firstWord;
#ifdef WIN32
std::replace(io_s.begin(), io_s.end(), '/', '\\');
#else
std::replace(io_s.begin(), io_s.end(), '\\', '/');
#endif
}
</pre>
<h3>
Designing for efficiency </h3>
<div>
One of the many things to think about when designing the class is the efficiency of the data storage / texture usage. It is quite possible that the maps used are loaded by several materials and only the multipliers are changed. To ensure that the data is not replicated, the textures are processed when loaded. First I step through each of the materials and load them into a <a href="http://www.cplusplus.com/reference/stl/list/">std::list</a>. then the <a href="http://www.cplusplus.com/reference/stl/list/unique/">std::list::unique</a> method is called to remove any duplicates. Once this is done the textures are loaded and the ID's stored in a std::vector. Finally these are re-associated with the mtlItem data to store all the values.</div>
<pre class="brush:cpp" title="loadTextures">void Mtl::loadTextures()
{
m_textureID.clear();
std::cout<<"loading textures this may take some time\n";
// first loop and store all the texture names in the container
std::list <std::string> names;
std::map<std::string, mtlItem *>::const_iterator end=m_materials.end();
std::map<std::string, mtlItem *>::const_iterator i = m_materials.begin();
for( ; i != end; ++i )
{
if(i->second->map_Ka.size() !=0)
names.push_back(i->second->map_Ka);
if(i->second->map_Kd.size() !=0)
names.push_back(i->second->map_Kd);
if(i->second->map_d.size() !=0)
names.push_back(i->second->map_d);
if(i->second->map_bump.size() !=0)
names.push_back(i->second->map_bump);
if(i->second->map_bump.size() !=0)
names.push_back(i->second->bump);
}
std::cout<<"we have this many textures "<<names.size()<<"\n";
// now remove duplicates
names.unique();
std::cout<<"we have "<<names.size()<<" unique textures to load\n";
// now we load the textures and get the GL id
// now we associate the ID with the mtlItem
BOOST_FOREACH(std::string name , names)
{
std::cout<<"loading texture "<<name<<"\n";
ngl::Texture t(name);
GLuint textureID=t.setTextureGL();
m_textureID.push_back(textureID);
std::cout<<"processing "<<name<<"\n";
i=m_materials.begin();
for( ; i != end; ++i )
{
if(i->second->map_Ka == name)
i->second->map_KaId=textureID;
if(i->second->map_Kd == name)
i->second->map_KdId=textureID;
if(i->second->map_d == name)
i->second->map_dId=textureID;
if(i->second->map_bump == name)
i->second->map_bumpId=textureID;
if(i->second->bump == name)
i->second->bumpId=textureID;
}
}
std::cout <<"done \n";
}
</pre>
<h3>
Serialisation
</h3>
<div>
Whilst the parsing of the mtl file is relatively quick it was decided to allow for both binary read and write of the data. As there is a lot of text data to save the process is not quite as simple as it could be. For most of the data we need to determine the length of the string to write out then I write out the size of the string followed by the string data. I also decided to write out a unique ID for the file header so we can check that the file being loaded is the correct one.</div>
<div>
<br /></div>
<div>
The code to write the data is as follows</div>
<div>
<br /></div>
<pre class="brush:cpp" title="saveBinary">bool Mtl::saveBinary(const std::string &_fname) const
{
std::ofstream fileOut;
fileOut.open(_fname.c_str(),std::ios::out | std::ios::binary);
if (!fileOut.is_open())
{
std::cout <<"File : "<<_fname<<" could not be written for output"<<std::endl;
return false;
}
// write our own id into the file so we can check we have the correct type
// when loading
const std::string header("ngl::mtlbin");
fileOut.write(header.c_str(),header.length());
unsigned int size=m_materials.size();
fileOut.write(reinterpret_cast<char *>(&size),sizeof(size));
std::map<std::string, mtlItem *>::const_iterator start=m_materials.begin();
std::map<std::string, mtlItem *>::const_iterator end=m_materials.end();
for(; start!=end; ++start)
{
//std::cout<<"writing out "<<start->first<<"\n";
// first write the length of the string
size=start->first.length();
fileOut.write(reinterpret_cast<char *>(&size),sizeof(size));
// now the string
fileOut.write(reinterpret_cast<const char *>(start->first.c_str()),size);
// now we do the different data elements of the mtlItem.
fileOut.write(reinterpret_cast<char *>(&start->second->Ns),sizeof(float));
fileOut.write(reinterpret_cast<char *>(&start->second->Ni),sizeof(float));
fileOut.write(reinterpret_cast<char *>(&start->second->d),sizeof(float));
fileOut.write(reinterpret_cast<char *>(&start->second->Tr),sizeof(float));
fileOut.write(reinterpret_cast<char *>(&start->second->illum),sizeof(int));
fileOut.write(reinterpret_cast<char *>(&start->second->Tf),sizeof(ngl::Vec3));
fileOut.write(reinterpret_cast<char *>(&start->second->Ka),sizeof(ngl::Vec3));
fileOut.write(reinterpret_cast<char *>(&start->second->Kd),sizeof(ngl::Vec3));
fileOut.write(reinterpret_cast<char *>(&start->second->Ks),sizeof(ngl::Vec3));
fileOut.write(reinterpret_cast<char *>(&start->second->Ke),sizeof(ngl::Vec3));
// first write the length of the string
size=start->second->map_Ka.length();
fileOut.write(reinterpret_cast<char *>(&size),sizeof(size));
// now the string
fileOut.write(reinterpret_cast<const char *>(start->second->map_Ka.c_str()),size);
// first write the length of the string
size=start->second->map_Kd.length();
fileOut.write(reinterpret_cast<char *>(&size),sizeof(size));
// now the string
fileOut.write(reinterpret_cast<const char *>(start->second->map_Kd.c_str()),size);
// first write the length of the string
size=start->second->map_d.length();
fileOut.write(reinterpret_cast<char *>(&size),sizeof(size));
// now the string
fileOut.write(reinterpret_cast<const char *>(start->second->map_d.c_str()),size);
// first write the length of the string
size=start->second->map_bump.length();
fileOut.write(reinterpret_cast<char *>(&size),sizeof(size));
// now the string
fileOut.write(reinterpret_cast<const char *>(start->second->map_bump.c_str()),size);
// first write the length of the string
size=start->second->bump.length();
fileOut.write(reinterpret_cast<char *>(&size),sizeof(size));
// now the string
fileOut.write(reinterpret_cast<const char *>(start->second->bump.c_str()),size);
}
fileOut.close();
return true;
}
</pre>
Loading in the data is almost the reverse of writing it, we first read in the header bytes and check to see if it is the correct file type then read in the data re-sizing the strings to we have enough room to read the data into it.
<br />
<pre class="brush:cpp" title="loadBinary">bool Mtl::loadBinary(const std::string &_fname)
{
std::ifstream fileIn;
fileIn.open(_fname.c_str(),std::ios::in | std::ios::binary);
if (!fileIn.is_open())
{
std::cout <<"File : "<<_fname<<" could not be opened for reading"<<std::endl;
return false;
}
// clear out what we already have.
clear();
unsigned int mapsize;
char header[12];
fileIn.read(header,11*sizeof(char));
header[11]=0; // for strcmp we need \n
// basically I used the magick string ngl::bin (I presume unique in files!) and
// we test against it.
if(strcmp(header,"ngl::mtlbin"))
{
// best close the file and exit
fileIn.close();
std::cout<<"this is not an ngl::mtlbin file "<<std::endl;
return false;
}
fileIn.read(reinterpret_cast<char *>(&mapsize),sizeof(mapsize));
unsigned int size;
std::string materialName;
std::string s;
for(unsigned int i=0; i<mapsize; ++i)
{
mtlItem *item = new mtlItem;
fileIn.read(reinterpret_cast<char *>(&size),sizeof(size));
// now the string we first need to allocate space then copy in
materialName.resize(size);
fileIn.read(reinterpret_cast<char *>(&materialName[0]),size);
// now we do the different data elements of the mtlItem.
fileIn.read(reinterpret_cast<char *>(&item->Ns),sizeof(float));
fileIn.read(reinterpret_cast<char *>(&item->Ni),sizeof(float));
fileIn.read(reinterpret_cast<char *>(&item->d),sizeof(float));
fileIn.read(reinterpret_cast<char *>(&item->Tr),sizeof(float));
fileIn.read(reinterpret_cast<char *>(&item->illum),sizeof(int));
fileIn.read(reinterpret_cast<char *>(&item->Tf),sizeof(ngl::Vec3));
fileIn.read(reinterpret_cast<char *>(&item->Ka),sizeof(ngl::Vec3));
fileIn.read(reinterpret_cast<char *>(&item->Kd),sizeof(ngl::Vec3));
fileIn.read(reinterpret_cast<char *>(&item->Ks),sizeof(ngl::Vec3));
fileIn.read(reinterpret_cast<char *>(&item->Ke),sizeof(ngl::Vec3));
// more strings
fileIn.read(reinterpret_cast<char *>(&size),sizeof(size));
// now the string we first need to allocate space then copy in
s.resize(size);
fileIn.read(reinterpret_cast<char *>(&s[0]),size);
item->map_Ka=s;
fileIn.read(reinterpret_cast<char *>(&size),sizeof(size));
// now the string we first need to allocate space then copy in
s.resize(size);
fileIn.read(reinterpret_cast<char *>(&s[0]),size);
item->map_Kd=s;
fileIn.read(reinterpret_cast<char *>(&size),sizeof(size));
// now the string we first need to allocate space then copy in
s.resize(size);
fileIn.read(reinterpret_cast<char *>(&s[0]),size);
item->map_d=s;
fileIn.read(reinterpret_cast<char *>(&size),sizeof(size));
// now the string we first need to allocate space then copy in
s.resize(size);
fileIn.read(reinterpret_cast<char *>(&s[0]),size);
item->map_bump=s;
fileIn.read(reinterpret_cast<char *>(&size),sizeof(size));
// now the string we first need to allocate space then copy in
s.resize(size);
fileIn.read(reinterpret_cast<char *>(&s[0]),size);
item->bump=s;
m_materials[materialName]=item;
}
m_loadTextures=true;
loadTextures();
return true;
}
</pre>
<h3>
Using the class</h3>
<div>
It is quite easy to use the class as the following code demonstrates</div>
<div>
<br /></div>
<pre class="brush:cpp" title="using the class">
Mtl *m_mtl = new Mtl("models/sponza.mtl",true);
m_mtl->saveBinary("sponzaMtl.bin");
bool loaded=m_mtl->loadBinary("sponzaMtl.bin");
if(loaded == false)
{
std::cerr<<"error loading mtl file ";
exit(EXIT_FAILURE);
}
m_mtl->debugPrint();
</pre>
That is about it for the Mtl class, the next post will describe the design of the GroupedObj class.Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com0tag:blogger.com,1999:blog-6958533929285860874.post-67859237235969671622012-11-12T12:31:00.002+00:002012-11-12T13:59:14.350+00:00Sponza Demo Pt 1 Initial DesignThe Sponza model is quite popular for real-time graphics visualisation, It can be downloaded from the CryTek <a href="http://www.crytek.com/cryengine/cryengine3/downloads">website</a>, and you can see many demos of it being used for different lighting tests on <a href="http://www.youtube.com/results?search_query=Sponza&oq=Sponza&gs_l=youtube-reduced.3..35i39j0l3.5142.6172.0.6272.6.6.0.0.0.0.164.606.2j3.5.0...0.0...1ac.1.eGk5GxVEC1g">youtube</a>.<br />
<br />
I decided it would be a good example to use in a bigger system of how to load and process meshes / textures in OpenGL and also as part of a bigger modelling / game pipeline.<br />
<br />
The main model comes in two parts, a <a href="http://en.wikipedia.org/wiki/Wavefront_.obj_file">wavefront obj file</a> (obj) and a Material template library file (mtl). These files are simple text files and can be exported from all major animation packages.<br />
<br />
<span style="font-size: large;"><b>Initial Design</b></span><br />
My initial design for the program is as follows<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpa1nLjRE3VEmZkmiYSDHybJhEcX3DCNNPX4f3K41i3lrydngvub2yMjFRYpNgg4UHy7DfGM2LK-I4DQyIE943aK4xxKu-HTGaAvIFcZPOOk9yd7eUDTVvV-Ft_kJC36TIYhLRrhpLLzg6/s1600/Sponza1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="278" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpa1nLjRE3VEmZkmiYSDHybJhEcX3DCNNPX4f3K41i3lrydngvub2yMjFRYpNgg4UHy7DfGM2LK-I4DQyIE943aK4xxKu-HTGaAvIFcZPOOk9yd7eUDTVvV-Ft_kJC36TIYhLRrhpLLzg6/s320/Sponza1.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
I will split the Mtl and Obj files into two different classes, the Mtl class will be responsible for loading the textures and storing OpenGL texture ID's. The ObjG (GroupedObj) class will load the Obj and then determine and process the groups in the file and store all the information required to draw all the individual grouped elements.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The mesh itself will be uploaded as a single OpenGL Vertex Array Object (VAO) and elements will be drawn as sub meshes with the correct textures enabled.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
I decided to design / write the Mtl class first. This design can be seen in the next <a href="http://jonmacey.blogspot.co.uk/2012/11/sponza-demo-pt-2-mtl-class.html">post</a>.</div>
<br />Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com0tag:blogger.com,1999:blog-6958533929285860874.post-69240780883494117982012-10-19T13:50:00.001+01:002012-10-19T13:53:51.890+01:00Generic Polygon ClassThe following video gives one solution to the creation of the generic polygon class exercise from the ASD lecture.
I will add some more features after next week's lab session and do another video post.
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrsFUdmYtrl5pu1hyphenhyphenZyQBHMzOGUcMqQ1T7AGo22bRSO3Ujn8h0bms6EgjxdExmzH6ynFT5mZh0Fn4dN8Z3bpI6Ux93sdQLYQp6a1PqSTiiCXe8dMc9x_Keib-xxka5NF5vkIFxm61Pg3j1/s1600/PolyClass.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="219" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrsFUdmYtrl5pu1hyphenhyphenZyQBHMzOGUcMqQ1T7AGo22bRSO3Ujn8h0bms6EgjxdExmzH6ynFT5mZh0Fn4dN8Z3bpI6Ux93sdQLYQp6a1PqSTiiCXe8dMc9x_Keib-xxka5NF5vkIFxm61Pg3j1/s320/PolyClass.png" width="208" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div style="text-align: center;">
<iframe allowfullscreen="allowfullscreen" frameborder="0" height="315" src="http://www.youtube.com/embed/9vLvyHFj56A?rel=0" width="420"></iframe></div>
Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com0tag:blogger.com,1999:blog-6958533929285860874.post-14260522417746120112012-10-04T19:31:00.000+01:002012-10-04T19:31:26.466+01:00How to run sdl-config in a Qt ProjectI did a quick google search for this and didn't find anything so I thought I would figure it out myself.
It is actually quite easy, you need to use the $$system() function in qmake to run the sdl-config script (which should be in your path) and then assign it to the correct qmake variables.
The following code snippet shows what to add
<br />
<br />
<pre class="brush:cpp">LIBS+=$$system(sdl-config --libs)
message(output from sdl-config --libs added to LIBS =$$LIBS)
CXX_FLAGS+=$$system(sdl-config --cflags)
message(output from sdl-config --cflags added to CXX_FLAGS= $$CXX_FLAGS)
</pre>
The message calls are there to display the output for debug and can be removed. This will output the following (on my mac)
<pre>
Project MESSAGE: output from sdl-config --libs added to LIBS =-L/usr/local/lib -lSDLmain -lSDL -Wl,-framework,Cocoa
Project MESSAGE: output from sdl-config --cflags added to CXX_FLAGS= -I/usr/local/include/SDL -D_GNU_SOURCE=1 -D_THREAD_SAFE
</pre>
Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com1tag:blogger.com,1999:blog-6958533929285860874.post-76038398262115795012012-09-24T21:41:00.000+01:002012-09-25T17:32:43.777+01:00Getting Started with SDL (Part 2 A Simple Window) In the <a href="http://jonmacey.blogspot.co.uk/2012/09/getting-started-with-sdl-part-1.html">last post</a> we talked about how to install <a href="http://www.libsdl.org/">SDL</a> in this post we will create a simple program to create initialise SDL and create a simple window.<br />
<br />
All the code for this post can be found <a href="http://nccastaff.bournemouth.ac.uk/jmacey/GraphicsLib/SDLDemos/index.html">here</a> and downloaded via version control using <a href="http://bazaar.canonical.com/en/">bzr</a><br />
<h3>
SDL.h</h3>
<div>
The first thing we need to do when using SDL is to include the SDL.h header file. This is done using the following line</div>
<pre class="brush:cpp" title="SDL.h">#include <SDL/SDL.h>
</pre>
Note that the directory prefix SDL/ is part of this path, as we shall see later the sdl-config script will give us the correct include paths when we compile the program relative to this directory.
<br />
<br />
<h3>
SDL_main</h3>
<div>
Depending upon the operating system, SDL uses different native code to generate the window / interactions with the operating system. Under linux this is done be default, however under Mac OSX and Windows we need to include a different version of <a href="http://en.wikipedia.org/wiki/Main_function">main</a>. To allow this and make the code portable we can use the C/C++ <a href="http://en.wikipedia.org/wiki/Conditional_compilation">conditional compilation</a> pre-processor. To do this we use the following code</div>
<div>
<pre class="brush:cpp" title="Conditional compilation for main">/// note that under mac osx (and windows) there is a different
/// way to build SDL so we need to use SDL_main under linux
/// normal main is fine so we use this conditional compilation
/// to incude the correct version (DARWIN being mac os x)
#if defined (DARWIN) || defined (WIN32)
int SDL_main(int argc, char **argv)
#else
int main(int argc, char **argv)
#endif
</pre>
</div>
<h3>
SDL_Init</h3>
<div>
The first thing we need to do when using SDL is to initialise the library, to do this we use the <a href="http://www.libsdl.org/docs/html/sdlinit.html">SDL_Init</a> function, this is passed one parameter which is a flag to indicate which sub-systems should be initialised. These values are combined together using a logical or ( | ). The subsystems available are as follows</div>
<div>
<table border="1">
<tbody>
<tr>
<td align="left" valign="top">SDL_INIT_TIMER</td>
<td align="left" valign="top">Initializes the <a href="http://www.libsdl.org/docs/html/time.html">timer</a> sub system.</td>
</tr>
<tr>
<td align="left" valign="top">SDL_INIT_AUDIO</td>
<td align="left" valign="top">Initializes the <a href="http://www.libsdl.org/docs/html/audio.html">audio</a> sub system.</td>
</tr>
<tr>
<td align="left" valign="top">SDL_INIT_VIDEO</td>
<td align="left" valign="top">Initializes the <a href="http://www.libsdl.org/docs/html/video.html">video</a> sub system.</td>
</tr>
<tr>
<td align="left" valign="top">SDL_INIT_CDROM</td>
<td align="left" valign="top">Initializes the <a href="http://www.libsdl.org/docs/html/cdrom.html">cdrom</a> sub system.</td>
</tr>
<tr>
<td align="left" valign="top">SDL_INIT_JOYSTICK</td>
<td align="left" valign="top">Initializes the <a href="http://www.libsdl.org/docs/html/joystick.html">joystick</a> sub system.</td>
</tr>
<tr>
<td align="left" valign="top">SDL_INIT_EVERYTHING</td>
<td align="left" valign="top">Initialize all of the above.</td>
</tr>
<tr>
<td align="left" valign="top">SDL_INIT_NOPARACHUTE</td>
<td align="left" valign="top">Prevents SDL from catching fatal signals.</td>
</tr>
<tr>
<td align="left" valign="top">SDL_INIT_EVENTTHREAD</td>
<td align="left" valign="top"></td>
</tr>
</tbody>
</table>
For example if we wish to initialise both the video and joystick sub sytems we would use the following code </div>
<pre class="brush:cpp" title="init sdl">SDL_Init( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK);
</pre>
In the following examples we will use just the video subsystem but we will also check to see if the initialisation actually worked by checking the return value from SDL_init and making sure it's a zero
<br />
<pre class="brush:cpp" title="init sdl">if (SDL_Init( SDL_INIT_VIDEO ) !=0)
{
std::cerr <<"error initialising SDL exiting\n";
exit(EXIT_FAILURE);
}
</pre>
<h3>
Setting Video mode</h3>
<div>
To give us a video surface we use the <a href="http://www.libsdl.org/docs/html/sdlsetvideomode.html">SDL_SetVideoMode</a> function, it has 4 parameters width and height, bits per pixel (bpp) and flags.<br />
<br />
If the bpp value is set to 0 it will attempt to use the system value for the current display, the flags parameter can be a logical or combination of the values below, however some of these flags will cancel each other out.<br />
<br /></div>
<table border="1">
<tbody>
<tr>
<td align="left" valign="top">SDL_SWSURFACE</td>
<td align="left" valign="top">Surface is stored in system memory</td>
</tr>
<tr>
<td align="left" valign="top">SDL_HWSURFACE</td>
<td align="left" valign="top">Surface is stored in video memory</td>
</tr>
<tr>
<td align="left" valign="top">SDL_ASYNCBLIT</td>
<td align="left" valign="top">Surface uses asynchronous blits if possible</td>
</tr>
<tr>
<td align="left" valign="top">SDL_ANYFORMAT</td>
<td align="left" valign="top">Allows any pixel-format (Display surface)</td>
</tr>
<tr>
<td align="left" valign="top">SDL_HWPALETTE</td>
<td align="left" valign="top">Surface has exclusive palette</td>
</tr>
<tr>
<td align="left" valign="top">SDL_DOUBLEBUF</td>
<td align="left" valign="top">Surface is double buffered (Display surface)</td>
</tr>
<tr>
<td align="left" valign="top">SDL_FULLSCREEN</td>
<td align="left" valign="top">Surface is full screen (Display Surface)</td>
</tr>
<tr>
<td align="left" valign="top">SDL_OPENGL</td>
<td align="left" valign="top">Surface has an OpenGL context (Display Surface)</td>
</tr>
<tr>
<td align="left" valign="top">SDL_OPENGLBLIT</td>
<td align="left" valign="top">Surface supports OpenGL blitting (Display Surface)</td>
</tr>
<tr>
<td align="left" valign="top">SDL_RESIZABLE</td>
<td align="left" valign="top">Surface is resizable (Display Surface)</td>
</tr>
<tr>
<td align="left" valign="top">SDL_HWACCEL</td>
<td align="left" valign="top">Surface blit uses hardware acceleration</td>
</tr>
<tr>
<td align="left" valign="top">SDL_SRCCOLORKEY</td>
<td align="left" valign="top">Surface use colorkey blitting</td>
</tr>
<tr>
<td align="left" valign="top">SDL_RLEACCEL</td>
<td align="left" valign="top">Colorkey blitting is accelerated with RLE</td>
</tr>
<tr>
<td align="left" valign="top">SDL_SRCALPHA</td>
<td align="left" valign="top">Surface blit uses alpha blending</td>
</tr>
<tr>
<td align="left" valign="top">SDL_PREALLOC</td>
<td align="left" valign="top">Surface uses preallocated memory</td>
</tr>
</tbody>
</table>
<br />
<div>
This function will return an <a href="http://www.libsdl.org/docs/html/sdlsurface.html">SDL_Surface</a> structure if successful which will be referred to in other drawing functions. If this fails NULL will be returned to we can check if there was an error.</div>
<div>
<br /></div>
<pre class="brush:cpp" title="setting the video mode">/// @brief the width of the window
const int WINDOW_WIDTH = 1024;
/// @brief the height of the window
const int WINDOW_HEIGHT = 720;
SDL_Surface* screen = SDL_SetVideoMode( WINDOW_WIDTH, WINDOW_HEIGHT,
0,SDL_HWSURFACE | SDL_DOUBLEBUF );
if( screen == NULL)
{
std::cerr<<"error setting SDL Video Mode\n";
exit(EXIT_FAILURE);
}
</pre>
In this example we are setting the video to be a Hardware surface (in GPU memory) and to use <a href="http://en.wikipedia.org/wiki/Multiple_buffering#Double_buffering_in_computer_graphics">double buffering</a> which should give use better graphics performance in the later examples.<br />
<br />
<h3>
Setting the window caption</h3>
<div>
To set the text in the titlebar of the window created by SDL we can use the following code</div>
<pre class="brush:cpp" title="setting WM title">// next we set the window bar caption to the text 2nd param is for an icon
// this is a char * to a pixmap data but if we use 0 none is loaded
SDL_WM_SetCaption( "A Simple SDL Window", 0 );
</pre>
<h3>
Event processing
</h3>
SDL uses an event structure called <a href="http://www.libsdl.org/docs/html/sdlevent.html">SDL_Event</a> to store all the information about the various events the host system / Windows manager is passing. This structure is actually a structure or many other structures and we can process the information in a number of ways. For these first simple examples we are going to look for a key down press and the windows system passing a Quit message. The structure of this is a continuous while loop, where we check a flag to see if we should exit.
<pre class="brush:cpp" title="event loop processing">SDL_Event event;
bool quit=false;
// now we loop until the quit flag is set to true
while(!quit)
{
// process SDL events, in this case we are looking for keys
while ( SDL_PollEvent(&event) )
{
switch (event.type)
{
// this is the window x being clicked.
case SDL_QUIT : quit = true; break;
// now we look for a keydown event
case SDL_KEYDOWN:
{
switch( event.key.keysym.sym )
{
// if it's the escape key quit
case SDLK_ESCAPE : quit = true; break;
default : break;
}
}
default : break;
}
}
} // end processing loop
</pre>
<h3>
Exiting SDL
</h3>
<div>
Once processing has finished it is important to shutdown SDL as it may have grabbed resources that other programs need access. To do this we use the SDL_Quit function.</div>
<h3>
Compiling the program</h3>
<div>
To compile our completed program we need to pass several flags to the c++ compiler we are using, this is what the sdl-config program is for. If we run sdl-config we get the following </div>
<pre>sdl-config --cflags --libs
-I/usr/include/SDL -D_GNU_SOURCE=1 -D_REENTRANT
-L/usr/lib/arm-linux-gnueabihf -lSDL
</pre>
We can combine this into the call to g++ by using the single back quotes as follows
<br />
<pre>g++ InitSDL.cpp -o InitSDL `sdl-config --cflags --libs`
</pre>
The full listing of the program can be downloaded from the bzr repository at the top of the page, however here is the source for the basic demo (without comments)
<br />
<pre class="brush:cpp" title="full program">#include <SDL/SDL.h>
#include <cstdlib>
#include <iostream>
const int WINDOW_WIDTH = 1024;
const int WINDOW_HEIGHT = 720;
#if defined (DARWIN) || defined (WIN32)
int SDL_main(int argc, char **argv)
#else
int main(int argc, char **argv)
#endif
{
if (SDL_Init( SDL_INIT_VIDEO ) !=0)
{
std::cerr <<"error initialising SDL exiting\n";
exit(EXIT_FAILURE);
}
SDL_Surface* screen = SDL_SetVideoMode( WINDOW_WIDTH, WINDOW_HEIGHT, 0,SDL_HWSURFACE | SDL_DOUBLEBUF );
if( screen == NULL)
{
std::cerr<<"error setting SDL Video Mode\n";
exit(EXIT_FAILURE);
}
SDL_WM_SetCaption( "A Simple SDL Window", 0 );
SDL_Event event;
bool quit=false;
while(!quit)
{
while ( SDL_PollEvent(&event) )
{
switch (event.type)
{
case SDL_QUIT : quit = true; break;
case SDL_KEYDOWN:
{
switch( event.key.keysym.sym )
{
case SDLK_ESCAPE : quit = true; break;
default : break;
}
}
default : break;
}
}
} // end processing loop
SDL_Quit();
return EXIT_SUCCESS;
}</pre>Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com2tag:blogger.com,1999:blog-6958533929285860874.post-24528709468031278752012-09-24T20:07:00.001+01:002012-09-25T08:18:43.432+01:00Getting Started with SDL (Part 1 installation)<a href="http://www.libsdl.org/">SDL</a> is an ideal cross platform API for basic games development and other non GUI graphics systems. To quote the website above<br />
<br />
<i> "Simple DirectMedia Layer is a cross-platform multimedia library designed to provide low level access to audio, keyboard, mouse, joystick, 3D hardware via OpenGL, and 2D video framebuffer. It is used by MPEG playback software, emulators, and many popular games, including the award winning Linux port of "Civilization: Call To Power."</i><br />
<i><br /></i>
In this series of blog posts I will look at the basic use of SDL with a focus on using it on the <a href="http://www.raspberrypi.org/">Raspberry Pi</a>, however all the code should work under all linux distributions as well as Mac OSX ( Windows should also just work, however I don't have a windows machine to test against).<br />
<h3>
Installing SDL using apt-get</h3>
<div>
The easiest way to install SDL on the rpi is to use apt-get and install the pre-build development packages. To do this use the following commands<br />
<br /></div>
<div>
<pre>sudo apt-get install libsdl1.2-dev
</pre>
<br />
To check that this has been successful we can now execute the sdl-config script as follows
<br />
<pre></pre>
<pre>sdl-config
Usage: sdl-config [--prefix[=DIR]] [--exec-prefix[=DIR]] [--version] [--cflags] [--libs] [--static-libs]
</pre>
<h3>
Installing from Source</h3>
</div>
<div>
The source code for SDL is available from this link <a href="http://www.libsdl.org/download-1.2.php">http://www.libsdl.org/download-1.2.php</a>. This is the easiest way to get SDL working on Linux system without apt as well as for Mac OSX. To build from the <a href="http://www.libsdl.org/release/SDL-1.2.15.tar.gz">.tgz</a> version do the following<br />
<br /></div>
<div>
<pre>tar vfxz SDL-1.2.15.tar.gz
cd SDL-1.2.15
./configure
make
sudo make install</pre>
</div>
<br />
Once this is done we can again check to ensure that things are working by testing the sdl-config program above.<br />
<br />
<h3>
Raspberry Pi user config for the console</h3>
<div>
If you intend to use SDL on the raspberry pi <b><u>without</u></b> using X windows the SDL library will attempt to access the framebuffer directly. By default only the root user has access to the framebuffer device so we need to add the current user (i.e. what you logged in as) to this group. To do this we need to add the user to the group video, input and audio groups (audio if we use it later) for a minimum you must have video and input.</div>
<div>
<pre>sudo usermod -a -G video,input,audio [your username]
</pre>
<br />
Once this is done logout and the user will be added to the group on the next login.</div>
<a href="http://jonmacey.blogspot.co.uk/2012/09/getting-started-with-sdl-part-2-simple.html">part 2</a>
Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com2tag:blogger.com,1999:blog-6958533929285860874.post-61404079513581703922012-07-09T16:51:00.001+01:002012-07-09T16:57:31.130+01:00Raspberry Pi and the KinectThere are several forum posts asking if the Raspberry Pi could be used with the kinect so I decided to give it a try. It is important to note that you will need a powered USB hub, as whilst the kinect does have a PSU this is only used for the motor, the Camera and Audio sub systems still need more power than the Pi can produce.<br />
<br />
First you will need to get a couple of libraries, first off <a href="http://www.libusb.org/">libusb</a> is required, I downloaded the latest 1.0.9 tarball and built it using the following commands<br />
<br />
<pre>tar vfxj libusb-1.0.9.tar.bz2
cd libusb-1.0.9/
./configure
make
sudo make install
</pre>
This should work fine for both of the debian versions and this will install the developer libraries and headers for libusb.
Next I downloaded the OpenKinect source code from <a href="https://github.com/OpenKinect/libfreenect">git hub</a> unzip this file and change into the source directory.<br />
<br />
You may need to install cmake if you have not already done so, this can be done by using sudo apt-get install cmake. Next we need to edit some of the cmake files as for this example I don't want to build the demos which require libraries which will not work properly on the pi.<br />
<br />
If you edit the CMakeLists.txt file and search for the following line<br />
<br />
<pre>OPTION(BUILD_EXAMPLES "Build example programs" ON)
</pre>
And change the ON to OFF
you should now be able to build by typing the following
<br />
<pre>cmake CMakeLists.txt
make
sudo make install
</pre>
This will then install the following files
<br />
<pre>ls /usr/local/include/libfreenect/
libfreenect.h </pre>
<pre>libfreenect-registration.h </pre>
<pre>libfreenect_sync.h
</pre>
and
<br />
<pre>ls /usr/local/lib/libfree*
/usr/local/lib/libfreenect.a</pre>
<pre>/usr/local/lib/libfreenect.so.0.1</pre>
<pre>/usr/local/lib/libfreenect_sync.a</pre>
<pre>/usr/local/lib/libfreenect_sync.so.0.1
/usr/local/lib/libfreenect.so</pre>
<pre>/usr/local/lib/libfreenect.so.0.1.2
</pre>
The first demo I've tried is a modified version of the <a href="https://github.com/OpenKinect/libfreenect/blob/master/examples/tiltdemo.c">tiltdemo.c</a> There are reports of this working fine for some people, however it didn't for me under the latest wheezy build so I investigated more and found that the sync library wasn't working for me. The following program uses the Normal freenect library calls instead.
<br />
<pre class="brush:cpp" title="tiltdemo.cpp">#include "libfreenect.h"
#include <cstdlib>
#include <ctime>
#include <iostream>
int main(int argc, char *argv[])
{
// seed rng generator
srand(time(0));
// pointer to the freenect context
freenect_context *ctx;
// pointer to the device
freenect_device *dev;
if (freenect_init(&ctx, NULL) < 0)
{
std::cout<<"freenect_init() failed\n";
exit(EXIT_FAILURE);
}
// set the highest log level so we can see what is going on
freenect_set_log_level(ctx, FREENECT_LOG_SPEW);
int nr_devices = freenect_num_devices (ctx);
std::cout<<"Number of devices found: "<<nr_devices<<"\n";
// I only have one kinect so open device 0
if (freenect_open_device(ctx, &dev, 0) < 0)
{
std::cout<<"could not open device error\n";
freenect_shutdown(ctx);
exit(EXIT_FAILURE);
}
// now I'm going to loop and set random value
// these are basically from the tiltdemo.c that comes with
// the freenect lib modified not to use the sync lib
while (1)
{
// Pick a random tilt and a random LED state
freenect_led_options led = (freenect_led_options) (rand() % 6); // explicit cast
int tilt = (rand() % 30)-15;
freenect_raw_tilt_state *state = 0;
double dx, dy, dz;
// Set the LEDs to one of the possible states
freenect_set_led(dev,led);
// Set the tilt angle (in degrees)
freenect_set_tilt_degs(dev,tilt);
// Get the raw accelerometer values and tilt data
state=freenect_get_tilt_state(dev);
std::cout<<"led["<<led<<"] tilt["<<tilt<<"]\r" ;
std::cout.flush();
sleep(1);
}
}
</pre>
To build this I used the following makefile
<br />
<pre class="brush:cpp" title="Makefile">CC=g++
CFLAGS=-c -Wall -O3 -I/usr/local/include/libfreenect
LDFLAGS=-L/usr/local/lib -lfreenect
SOURCES=tiltdemo.cpp
OBJECTS=$(SOURCES:%.cpp=%.o)
EXECUTABLE=tiltdemo
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $@
.cpp.o:
$(CC) $(CFLAGS) $< -o $@
clean :
rm -f *.o $(EXECUTABLE)
</pre>
A video of it in action can be seen here
<iframe allowfullscreen="" frameborder="0" height="315" src="http://www.youtube.com/embed/UfmiPEVQoRA?rel=0" width="560"></iframe>Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com43tag:blogger.com,1999:blog-6958533929285860874.post-38734077097174591162012-06-21T19:54:00.001+01:002012-06-21T19:54:11.927+01:00Embedding a Python interpreter in C++In my feedback for the MSc project proposals I suggested it would be a good idea to embed some form of interpreter for the crowd / multi agent systems instead of hard coding them in C++. This allows for a quicker development cycle and a more flexible tool. In this video tutorial I explain the example code (<a href="http://nccastaff.bournemouth.ac.uk/jmacey/Code/Blog/EmbededPython.tgz">here</a>) and the basic design behind it. For more details I would read <a href="http://docs.python.org/c-api/">this</a><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6FqOtPnMgL0hI-Lh9pWDBh1hUwBCNzdI4qjMoXhmF15foVvalaF48lVlmaGj6ILy8E7-TrmQWYuGbA_ojQo-1CnFI1Nv7-cAsBIuXG8-H9BlxZw2XRUfKtFd_UiQ576uc_RbKjIz3ECqi/s1600/EmbedPy.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="236" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6FqOtPnMgL0hI-Lh9pWDBh1hUwBCNzdI4qjMoXhmF15foVvalaF48lVlmaGj6ILy8E7-TrmQWYuGbA_ojQo-1CnFI1Nv7-cAsBIuXG8-H9BlxZw2XRUfKtFd_UiQ576uc_RbKjIz3ECqi/s640/EmbedPy.png" width="640" /></a></div>
<iframe allowfullscreen="" frameborder="0" height="315" src="http://www.youtube.com/embed/fdQZK0_ADKM?rel=0" width="420"></iframe>Anonymoushttp://www.blogger.com/profile/11346071501033561015noreply@blogger.com0