Friday, 2 October 2015

New Image Class

ngl::Image Class

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.

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 QImage (the default), ImageMagick and Open Image I/O.

The code to load the images is quite simple, and uses a boost::scoped_array to store the data as a contiguous block of unsigned char data that OpenGL can use as texture data.

The source code can be seen in Image.cpp and Image.h and the video below shows how to change the Qt Project to set the image library to use.

Friday, 21 November 2014

Using Qt Library templates

The 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 here

The main things you will need to do are in the .pro file as follows

TEMPLATE = lib
CONFIG+=staticlib

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.

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


 For more examples of this see this blog post




Tuesday, 4 November 2014

Drawing with Modern OpenGL

The following video demonstrate how modern OpenGL uses Vertex Array Objects to store buffers and generic vertex attributes together for faster drawing.

The first Video shows how the deprecated immediate mode OpenGL version would work as context for why we use Modern OpenGL.

The next videos show the basic framework code using ngl 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 here and suggested man pages are glGenVertexArrays glBindVertexArray glGenBuffers glBufferData glVertexAttribPointer glDrawArrays



Friday, 21 March 2014

Using emscripten to port NGL to the Web

Introduction

I have been using the ngl:: library 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 WebGL 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. 
I had a number of choices as to which approach to take, I could learn Java Script and  three.js however this would mean porting all my codebase to Java Script which seemed like too much work.
In the end I came across the emscripten system which is a LLVM-to-JavaScript Compiler which can convert my C++ code into LLVM and then into JavaScript and then into asm.js 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 here the rest of the blog will outline the process and how the webngl system was developed.

Installing Emscripten

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 here 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.

A Simple SDL demo program

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.

#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;
}

The emscripten_set_main_loop function is explained very well here 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.

Compiling the program

To compile the program we use the following command line (in this case I'm using c++ )
em++ -s FULL_ES2=1 SDL1.cpp -o SDL1.html
The flag -s FULL_ES2 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 opened in the browser 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.

Thursday, 20 February 2014

GamePlay 3D 101

Another Guest post on my Blog, this time from Callum James and Ramesh Balachandran from the BSc. Software Development for Animation, Games and Effects course at the NCCA

What is Gameplay 3D? 

 Gameplay 3D 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 Unreal Development Kit , 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.

Lack of Documentation
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. 

Our Preferred Gameplay 3D Setup
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.  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.
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.
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. 

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. 

Setting up Gameplay 3D on Unix - Linux and MacOSX
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.
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. 
Other directories to include are:


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
Libraries to link up to for your projects are as follows for Linux:
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
}
And for MacOSX:
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
}
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:
macx:QMAKE_CXXFLAGS+= -arch x86_64
macx:CONFIG+=x86_64
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:
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 \
 … \ 
}

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:
QMAKE_BUNDLE_DATA +=  APP_AUDIO_FILES \
                        APP_SPLASH_IMAGES \
   … \ 
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:
#ifdef DARWIN
    #define PATH_PREFIX "../Resources/"
#else
    #define PATH_PREFIX ""
#endif

std::string GeneralUtils::PLATFORM_FILE_PATH(std::string _path)
{
    return (PATH_PREFIX+_path);
}
The DARWIN define is set within the .pro file if the macx platform is detected, as follows:
unix:!macx: DEFINES += LINUX
macx: DEFINES += DARWIN
If this is all set up correctly, then local paths will work on all platforms without any need to change them.

Setting up Gameplay 3D on Windows

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:
../../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
In addition to this the .lib files need to be explicitly linked under Linker -> Input in the ‘Additional Dependencies’ section:
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)
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.

Using Config Files
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:
  • title The text you wish to appear at the top of the window if full screen is false
  • width  The resolution width you wish to use
  • height  The resolution height you wish to use
  • fullscreen  This can either be true or false and will set the game either full screen or windowed
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

aliases
{

}
Within this scope, declare a name and set what it is equal to. For example:
aliases
{
  komodo = res/textures/komodo.png
}
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:
{what_to_set_to} = @komodo
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:
gamepads
{

}
This will declare aliases for gamepad forms, which can then be used on touch devices as a way to control the game, for example:
gamepads
{
   form = res/common/gamepad.form

}
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.

Encoding Files


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:

gameplay-encoder ‘name of .fbx file’
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:
gameplay-encoder -g ‘name of root joint in Maya’  ‘name of animation group’ ‘name of .fbx file’
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:
animation name of animation group
{
  frameCount = 1100
 clip idle
 {
  begin = 27
  end = 167
  repeatCount = INDEFINITE
  loopBlendTime = 250
 }
}

Using the Scene Files

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:
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
 }
}

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’.

Setting up Physics

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:
collisionObject staticMesh
{
 type = RIGID_BODY
 shape = MESH
 static = true
 mass = 0
 restitution = 0.01
 linearDamping = 1.0
 angularDamping = 1.0
}
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:
node boycharacter
{
collisionObject = res/common/demo.physics#staticMesh
}

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.

Using Materials

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:
material demo
{

}
Within this material you can then specify certain techniques, such as:
material demo
{
 technique Default
 {

 }

 technique Edges
 {

 }
}
This will allow you to specify a single material but with multiple techniques. To access these in the code, use the following:
{__model__}->setMaterial("res/common/demo.material#demo");
{__model__}->setTechnique("Default");
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:
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
    }
  }
 }
}

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.

Animations

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:
m_animation = node->getAnimation("animations");
m_animation->createClips("res/common/boy.animation");
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:
play("idle", true);
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.

First Person Control System

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:
Game::setMouseCaptured(true);
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.

Use of external GL calls

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.

Wednesday, 13 November 2013

Designing a Software System

This is the first guest post on my Blog, this one comes from a PhD student (and previously an MSc at Bournemouth) Mathieu Sanchez.

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.

Design often takes experience, which is why it is so difficult to teach, but there are some "half rules".
  • 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 this and this)
  • 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).
  • 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 here here and here)
  • Don't build crazy associations everywhere. Data can travel along an association and should have a strong meaning such as "owns" "directs" etc...
  • 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. 
  • 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 Liskov substitution if you have inheritance.
  • Many of the common problems are solved with (famous) patterns. For instance, if there are two ways of doing one operations, but can also be combined together to achieve a better result, then there is a pattern for that.
  • 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.
  • Think at a higher level at first, don't go straight for details, 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.
  • Think about extensibility. 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.

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 "what is its responsibility, in one and only sentence?". 

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.


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.

Wednesday, 2 October 2013

Introduction 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!

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.

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.

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.

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.

There is a link to a workbook and other resources here


 

(for more info on ssh see here)









 
alias ls='ls --color'
alias ll='ls -al'
alias rm='rm -i'

some useful information on the prompt