Sunday, 30 April 2017

Adding Simple Physics

Next up we can add some simple physics handling to the basic map and model loads under Urho3D, and this lets us handle simple objects and push cars round the map.

Introducing Physics

Urho uses the Bullet Physics library to provide a physics engine that supports collision detection and rigid body simulation.

Urho embeds a complete copy of Bullet under the Source/ThirdParty/Bullet/ directory, and there is a subset of the functionality exposed through AngelScript. However the AngelScript API doesn't support the complete feature set of Bullet that the C++ code can access, which will get annoying (as we see later).

Adding A Simple Colliding Entity

So initially we have to:

Enable Physics

This is a single line in the AngelScript


Turn on Collisions With the Scene

This is fairly simple we have the Node that the terrain Component was created in, and we want to tell the Physics engine that objects should collide with this terrain. To create this behaviour the engine wants us to do the following under the Terrain node:

  • Create a Rigid Body: A solid body, which doesn't deform, and has basic physics properties (such as mass and friction).
  • Add a Collision Shape: To support collisions, marked as Terrain in this case.

So, first we make a default RigidBody associated with the Terrain Node as a fixed object (the default, for a zero mass item).

RigidBody@ body = terrainNode.CreateComponent("RigidBody");
  body.collisionLayer = 2;

The collisionLayer parameter provides a bitmask that the Bullet engine uses to determine if objects should collide. The tutorials use the mask value of 2 throughout for terrain, and we'll keep that convention here.

There are actually two parameters here: collisionLayer and collisionMask. This is a detail we won't get into since it's not something that affects this demo, but when Objects 1 & 2 intersect then we evaluate:

  • the object 1 mask and object 2 collision layer
  • the object 2 mask and object 1 collision layer
If either of these operations are non-zero then we have a collision, otherwise they pass through each other.

Next we associate a collision shape - this is created alongside the static Rigid Body under the terrain node. The shape of this collider is marked as Terrain.

CollisionShape@ shape = terrainNode.CreateComponent("CollisionShape");
And that's it.

Add Shadows

Not necessary, but the relation of objects in the world is much clearer with shadows - otherwise entities have a tendency to look painted over, rather than on, the terrain. So we have to enable light shadows when we declare our light:

light.castShadows = true;
And when we create an object we'll also set the model castShadows property to true.

And The Object

We can add a simple colliding sphere (we'll call it a Marble), by creating a node with a Static Model based on "Sphere.mdl", and then adding the RigidBody and CollisionShape declaration.

For this example we use SetSphere() to set the collision shape to match the (spherical) model, and we give the RigidBody a mass and rolling friction and watch it go. Here's a complete working class, based on the code in

class Marble {
Node@ marbleNode;
StaticModel@ mdlObj;
RigidBody@ body;
CollisionShape@ shape;

bool doPrint = false;

  Marble(Scene@ scene, float sz, float speed, float mass) {
    Create(scene, sz, speed, mass);

  void Create(Scene@ scene, float sz, float speed, float mass) {
    marbleNode = scene.CreateChild();
    marbleNode.position = camera.cameraNode.position;
    marbleNode.rotation = camera.cameraNode.rotation;

    mdlObj = marbleNode.CreateComponent("StaticModel");
    mdlObj.model = cache.GetResource("Model", "Models/Sphere.mdl");
    mdlObj.material = cache.GetResource("Material", "Materials/Terrain.xml");
    mdlObj.castShadows = true;

    body = marbleNode.CreateComponent("RigidBody");
    body.mass = mass;
    body.rollingFriction = 0.9f;

    shape = marbleNode.CreateComponent("CollisionShape");

    body.linearVelocity = camera.cameraNode.rotation * Vector3(0.0f, 0.0f, 1.0f) * speed;

    SubscribeToEvent(marbleNode, "NodeCollision", "HandleNodeCollision");

  void HandleNodeCollision(StringHash eventType, VariantMap& eventData)  {
    if (doPrint) {
    RigidBody@ otherBody = eventData["OtherBody"].GetPtr();
    RigidBody@ hitBody = eventData["Body"].GetPtr();
      Print("Ding "+ +" against "+ + " !");
This provides the basic object and also an optional debugging report on collisions.

We can play around with this code and check the behaviour of the physics simulation. There are some problems when we fire very small and very fast marbles which have a tendency to fall through the terrain or when we combine very heavy and very light objects - this is expected and the Bullet and Urho docs mention the need to handle these cases carefully.

Adding A Car

There's an example of a simple vehicle provided by the Urho file ./bin/Data/Scripts/ It's worth taking a moment to look at how this works.

The car consists of a main hull body and four wheels. The main body is a RigidBody/CollisionShape and only has mass and air resistance, and all the power and steering is done by manipulating the wheels directly.

Each wheel is a cylinder model with an associated RigidBody and a spherical CollisionShape connected to the main body via a Hinge Constraint.

The hinge constraint is used to link the body to the wheel, and the wheel spins around this constraint. The hinge constraint limits are set from -180 to +180 degrees which allow the wheel to spin completely.

The constraint connecting the wheel to the body is also used for steering: by rotating the angle of the connection between the body and the wheel, the code deflects the front two wheels in response to steering commands.

Although the hinge is restricting motion around other axis there are some damped-spring style reactions to forces which can be seen at higher mass main body values, although I suspect this may be a bug involving the mass ratio of a light wheel to a heavy body. It's actually almost a usable hack for suspension style behaviour.

By default the reference code subclasses ScriptObject, which allows it to serialise the object to a file, and to handle control events directly. We can actually fire the event handler explicitly and break this connection if we want to simplify the implementation and don't care about serialising.

When accelerating the ApplyTorque() function is used to change the angular velocity of the wheel. In addition there's a directional component introduced to the front wheel (when steering is turned). Actual acceleration results from the interaction between the rotating wheels and terrain.

Lastly there's a downforce component which keeps the car connected to the terrain, by applying a downward force based on the car velocity.

Updating The Car

Although the code works with a basic setup, it's difficult to control and tune, and doesn't work when exposed to the kind of terrains we see in I76.

Firstly we need lower the downforce component. This works well to glue the car to the rolling terrain, but it tends to let the car drive down cliff faces on the I76 maps.

Next we modify the loaded model to be one of the one piece I76 car geometries, and tweak the wheel positions and collision bounds accordingly. We also move the body mass up to a more realistic (real world) value of around 1500 (assuming 1 unit = 1kg).

To simplify the control of acceleration we replace the "Torque" model of the demo with a simple ApplyImpulse() version. This doesn't rely on the torque for acceleration, but pushing the wheels directly. We put a simple check in to ensure that the wheel is in collision with the terrain before applying force through it, but that's all. This gives a simpler more controllable vehicle, although it's a bit like driving on glass.

How This Needs To Improve

Right now there's no suspension, or notion of vehicle simulation such as engine or tyre behaviour, weight transfer, etc. which would make the driving behaviour more like the original game.
We could add some of this in AngelScript, but that has an obvious overhead in terms of processing load and even a simplified model is a very complex problem. So are there any other options?

The good news is that the bullet physics library provides a complete abstraction - the btRayCastVehicle model. This supports a single solid body type which behaves like a vehicle, has a tunable suspension and wheel model, and takes care of all the details for us. There's a great example of it in action in this GitHub repository by the Urho user Lumak.

However the downside of the Bullet vehicle is that this is currently a C++ only thing - it's not exposed to the AngelScript interfaces. This is an annoyance, since using AngelScript to keep things cross platform is a definite advantage.

So we've hit a break where I need to figure out where to go next - Is there a plausible I76-like car behaviour without too much scripting code using a few approximations, or is native code for the car the way to go, or some mix and custom scripting interfaces down to the library? At this point experimentation will be required though, so that'll do for now...

Update - having just pulled the latest from the Urho3D Repo it turns out that RayCast vehicle integration & scripting hooks have been merged into the main release as of 20-something hours ago. So this decision is probably simpler than I thought.

Sunday, 23 April 2017

Urho I76 Model Viewer

Loading Up Models

The next thing to do under Urho3D is to load up the models for I76 assets.

The Hard Way

The hard way to do this is to manually generate an Urho VertexElement array and attach the model vertex and normal data, linking a VertexBuffer and IndexBuffer through a Geometry element.

This approach works, and there's an example of it in the sample application, but it's fiddly and my implementation is error prone. So let's not do that.

The Easier Way

The simplest way to do this is to use the AssetImporter tool from the Urho3D distribution. This can take an OBJ format file, which we can generate easily, and produce output files that Urho3D can load directly. It adds an extra step, but simplifies the process.

So we generate the OBJ file format files as we do in the existing C++ code, and then use the fileSystem.SystemRun() call in AngelScript to shell out to the AssetImporter binary. There's code in the default Urho application that we can use more or less directly for a prototype, that handles assembling the command line and also tacks on the .exe extension for windows. We'll replace this at some point, but for now let's just use it as is for the demo.

Otherwise there really isn't much clever here - we reimplement the ZFS unpacker in Angelscript to extract the resources, then we can view either individual models from GEO files, or complete vehicle assemblies from the VDF file. Extracting from the ZFS takes several minutes, and so the app should be run windowed, and the terminal will report the progress of the unpack. We could implement a background loader, but it's not worth the effort for a run-once process like this.

The only other annoyance is that the floating point output from AngelScript threw up errors with the AssetImporter by default - small values will be represented by scientific format (e.g. 3.3021e-05) and the importer doesn't like some of these, and there didn't seem to be a way to format the output more precisely. So we spot small values and treat these as exactly zero when we write them out.

Here's a tarball attached with:

  • AssetLoader: - Load a ZFS file, and unpack the ZFS itself, embedded PAK files and do the basic conversion for GEO to objects and VQM to texture images.
  • ObjLoader: - View individual object files. Does on the fly conversion.
  • CarLoad: - Load VDF files - this has some issues (the tendency to mess up interior geometry fragments, and some normals are iffy), but it's functional enough to pull out some basic geometry for the composite models.

The conversion process just applies a default image file for testing at present (whichever image you copy into Textures/test.png), and requires a defaultmat.xml Material file. It's lacking basic error checking, but as a proof of concept it holds together.

Also this will not work on the Nitro ZFS, since AngelScript doesn't know how to decompress the LZO compressed files without the platform specific libraries.

Otherwise, it mostly sorta works...

AngelScript: Some Thoughts

Having used AngelScript for a few days then the thoughts that keep cropping up are

The Good

  • Fast Prototyping.
  • Straightforward UI & 3D implementation.
  • Feature rich primitives.
  • Syntax: maps neatly to C++ versions.

The Bad

  • No debugger: This is a real PITA. The code has wound up with debug Print calls scattered around.
  • Silent Failures: Some setup errors leave things silently non functional, rather than producing more obvious error reports.
  • Slow: Although the heavy lifting is mostly done by the core engine having scripts generate things like texture images and bitmap resources can result in major slowdowns.

The Ugly

  • Ownership: The Urho Angelscript version uses reference counting for memory management, but without a debugger it's easy to lose track of what references are valid at times and leak resources (such as open file handles).
  • Not Quite Vanilla AngelScript: Enough custom types that the default AS docs don't always seem to apply directly or help understand Urho's use of the language.
  • Documentation: It's there, but not always useful, and the examples take some parsing to understand: it could be better.
  • No Printing Format control? I couldn't figure out how to persuade floats to output in a specific format, hence the low value rounding utility.

Sunday, 16 April 2017

Loading the Levels and Texturing

Loading The Map

This will bring together the stuff we've done so far to load up the levels from the I76 mission files.

Initially we copy the contents of the installed Mission directory under the Urho3D Data directory so we can locate the target files easily. Go to the the Urho3D Data directory, create a subdirectory Imports and copy the mission files into that.

The AngelScript code is available in this zip file. Unzip the file contents, and run the viewer with a line like "Urho3DPlayer ./ -w". This code doesn't do much in the way of error checking, so make sure that under the Urho3D Data directory you have a directory "Imports" and that the mission files (.msn and .ter) are contained in it. A description of how the code works is below.

Parsing The Level

File Load

We use the standard Urho3D file dialog system to locate a target .msn file, and since this is all boilerplate there's nothing special to notice here.

However to simplify interaction with this then we isolate it to a separate class for handling, and we have the dialog generate an event when it's complete to feed back to the main code.

So we have a class "OurFileSelector" which uses the stock FileSelector to generate a pop up window. The HandleFileSelected event is used to flag a selection and we create an event using a VariantMap and SendEvent() to signal the file chosen.

In the main code we've added the call to launch the selector with fselect.PickFile(), and to pick up the completion we add an event handler:

SubscribeToEvent("FileChosen", "HandleFileChosen");
We can just define this event and handler in either order without any setup and rely on the dispatch to take care of it - this is fast when prototyping, but obviously error prone. Also we use a global signal here, since there's only one file selector at a time and we don't try and associate a handler with a specific object.

Reading and Parsing

The actual file load resembles the code we generated before for the C++ level to Image map conversion process, although a little cleaner since we know what we're doing.

In this case the Urho3D File library provides routines for loading correct data sizes from the target file. The only specific piece of code we need is the format mangling to get the heightmap information into the right format.

In this case we extract the height data as

  • Mask out the upper 4 bits for the terrain flags
  • Scale up the 12 bit range to 16 bits by left shifting 4
  • Split out the Upper and Lower 8 bits as the rough & fine height components
  • Form the final color as :
    • Blue for Flags
    • Green as Fine detail (Low Byte of height)
    • Red as Rough detail (Top Byte of height)
  • The final 32 bit value is packed as BGR

The heightmap will use R and G for determining the height, but will ignore the Blue channel, however we will use this to modify the texture later.

This code fragment is:

      uint32 heightval;
      uint32 terrain_flags;

        heightval = data[cursor++];
        terrain_flags = heightval & 0xf000;
        terrain_flags = (terrain_flags << 4) &0xff0000;
        heightval = heightval & 0x0fff;         // Mask top four terrain bits....
        heightval = (heightval << 4) & 0xfff0;  // Scale up to full 16 bit range

        uint32 heightColor_fine = heightval & 0xff;
        uint32 heightColor_rough =  (heightval >>8)& 0xff;
        uint32 heightColor = terrain_flags | (heightColor_fine << 8) | heightColor_rough;
        heightIm.SetPixelInt(y, x, heightColor); //Note X/Y transpose to rotate....

We also restrict the level heightmap size to rendering the in use zones, rather than trying to handle the full I76 80*80 zone map to keep performance sane. So combining this logic with the existing heightmap render gets us a functional level render.

Adding a Debug HUD

Urho3D has a built in debug overlay which can be used to report the current state of the engine and this is trivial to enable, with the code

  debugHud.defaultStyle = cache.GetResource("XMLFile", "UI/DefaultStyle.xml");
And we can then turn this on and off with debugHud.ToggleAll()

Adding a SkyBox

Again, a simple operation which adds a node with a Skybox component to the root scene. The Skybox Model and Material are the stock Urho3D versions.

    skybxnode = thescene.CreateChild();

    Skybox@ skybox = skybxnode.CreateComponent("Skybox");
    skybox.model = cache.GetResource("Model", "Models/Box.mdl");
    skybox.material = cache.GetResource("Material", "Materials/Skybox.xml");

Putting it together

You get this: From the bottom of the bowl in level m01.msn

Modifying the terrain

We've put the terrain flags in the blue channel, and we can use this information to manually tweak the texture we put on the map.

For this version then what we'll try is:

  • Create a new image matching the height map size
  • Fill in this new image with colours based on the terrain flags
  • Create a default stone material
  • Get Texture used for the Diffuse layer of this material
  • Change the source Image data to our coloured bitmap
  • Update the material information

It's worth taking a moment to look at how Urho3d uses Texture Units: By default Urho3D has five predefined texture unit types: diffuse, normal, specular emissive and environment. The stone texture XML has the lines allocating these units for the diffuse and normal map.

In this case we're going to load the texture and replace the Diffuse Image with our own, and we can access the material and get a reference to the relevant texture unit. The Material class defines the textures in the material as an Array of Texture called "textures", and when we load a material then we can reference the target unit with textures[TU_DIFFUSE].

In this case we're actually going to grab it as a Texture2D rather than a Texture type: Texture2D is a subclass of Texture, but it will allow us to set a new Image reference. This is slightly confusing since the AngelScript header doesn't explicitly flag this relationship in the way that the C++ code does, but the sample code demonstrates the use of the subclass type for these cases.

(Note that additional units are available as "desktop only" features, and the units can be used by numeric references and remapped as the Terrain shader does, but that's detail we don't need to go into right now).

To get this change we will replace the terrainblock.material assignment in the level reader with this code: The code is:

Material@ renderMaterial = cache.GetResource("Material", "Materials/Stone.xml");
Texture2D@ inTex = renderMaterial.textures[TU_DIFFUSE];

  newImg.SetSize(msn.FinalHeightMap.width, msn.FinalHeightMap.height, 3);

    for (int srcx = 0; srcx < msn.FinalHeightMap.width; srcx++)
      for (int srcy = 0; srcy < msn.FinalHeightMap.height; srcy++) {
      int v = msn.FinalHeightMap.GetPixelInt(srcx,srcy);
        if ((v & 0xff0000) != 0) {
          if ((v & 0x010000) != 0)
            newImg.SetPixelInt(srcx, srcy, 0x770000); // Rough
          else if ((v & 0x020000) != 0)
            newImg.SetPixelInt(srcx, srcy, 0x007700); // Dirt
          else if ((v & 0x040000) != 0)
            newImg.SetPixelInt(srcx, srcy, 0x333333); // Tarmac
            newImg.SetPixelInt(srcx, srcy, 0xffffff); // Other?

        else {
          newImg.SetPixelInt(srcx, srcy, 0x888888); // Sand
  renderMaterial.textures[TU_DIFFUSE] = inTex;
  terrainblock.material = renderMaterial;
And this gives us the following from the training mission....
Which is less pretty, but more useful in highlighting the terrain type distribution.

Saturday, 15 April 2017

3D Scene Setup and Heightmaps

Minimal 3D application

This is a very (very) simple 3D application - we create a simple plane, a camera and a light and then set it up to render.

The Code

Scene@ thescene;
Node@ cameraNode;

void Start() {
  thescene = Scene();

  cameraNode = thescene.CreateChild();
  cameraNode.position = Vector3(0.0f, 5.0f, 0.0f);

Node@ planeNode = thescene.CreateChild();
  planeNode.scale = Vector3(100.0f, 1.0f, 100.0f);
StaticModel@ planeObject = planeNode.CreateComponent("StaticModel");
  planeObject.model = cache.GetResource("Model", "Models/Plane.mdl");
  planeObject.material = cache.GetResource("Material", "Materials/StoneTiled.xml");

Node@ lightNode = thescene.CreateChild();
  lightNode.direction = Vector3(0.6f, -1.0f, 0.8f);
Light@ light = lightNode.CreateComponent("Light");
  light.lightType = LIGHT_DIRECTIONAL;

  Viewport@ viewport = Viewport(thescene, cameraNode.GetComponent("Camera"));
  renderer.viewports[0] = viewport;

  SubscribeToEvent("KeyDown", "HandleKeyPress");

void HandleKeyPress(StringHash eventType, VariantMap& eventData) {
  if (eventData["Key"].GetInt() == KEY_ESCAPE) {

Taking This Line by Line

Initially we create a reference to the Scene object - every node in 3d space is a child of this. We also create an Octree Component at this level, which must be added to the root scene for the render to work.
The Octree is responsible for accelerating the render by subdividing the global 3D space and rapidly determining the renderable objects. In theory we could optimise this for a given scene, but we need at least one to render at all, so we add a default version to the root scene node.

Next we create the basic objects that will populate the scene: A plane, a light, and a camera. A camera so we we have something to view the scene through, a light so we can see things, a plane so we have something to actually see.

Our node graph is this:

   |         |         |
   |         |         |
[Plane]   [Light]   [Camera]   

And for the three children we have a two part process which is:

  • Create a Node, as a child of the Scene
  • Create the Component within the Node
In these cases we apply the basic 3D transforms (scaling, direction, position) to the Node, and the Component has any specific operations for the type of thing we create (Apply a model, Set the Type of Light, etc). The Material and Model for the plane are taken straight from the default Urho3D resources, available with the distribution.

The Material is provided as an XML file describing the texturing in terms of textures, shaders and rendering passes, and in this case references images which are stored in the DDS format; (a DirectDraw Surface) for the underlying texture images.

Finally we set up a Viewport, passing it the Scene and Camera reference, and then hand it to the global renderer, and it all goes. The KeyDown handler is our basic exit.

We make the Scene and Camera nodes file globals in this example. We have to do this for the Scene node, otherwise the reference drop when we leave Start() will result in deletion and a blank screen. We make the Camera node global so that we can access it from the event handler for the next example.

Spinning The Camera

Although this gives us a 3D view the fixed image does not prove much, but we can spin the camera using a simple event handler. In the Start() function then add an event call on each frame (the Update event).

SubscribeToEvent("Update", "HandleUpdate");
And in the update then we can call the camera Rotate() method:
void HandleUpdate(StringHash eventType, VariantMap& eventData) {
    cameraNode.Rotate(Quaternion(0.0, 0.2, 0.0));
And that'll perform a slow spin

Adding a Terrain Map

This is easy to do using a supplied heightmap image and texture from the Urho3D distribution: Simply remove the planeNode and planeObject and replace these with a call to MakeTerrain() and fill that function in as:

void MakeTerrain()
    Node@ terrainNode = thescene.CreateChild();
    terrainNode.position = Vector3(0.0f, 0.0f, 0.0f);

    Terrain@ terrain = terrainNode.CreateComponent("Terrain");
    terrain.patchSize = 64;
    terrain.spacing = Vector3(2.0f, 0.1f, 2.0f);
    terrain.smoothing = true;
    terrain.heightMap = cache.GetResource("Image", "Textures/HeightMap.png");
    terrain.material = cache.GetResource("Material", "Materials/Terrain.xml");
    terrain.occluder = true;

This creates a Node (terrainNode) and adds a Terrain Component object reference. The Terrain Component has a couple of simple parameters supplied:

  • patchSize: Must be a power of 2 between 4 and 128. This controls the level of Terrain detail generated by the engine, with lower values generating more (finer) data.
  • spacing: The scaling of the map to the world: the Y scales the map vertically (screen height) with X & Z as Width & Height
  • smoothing: Flag to smooth the output Terrain
  • occluder: Use Terrain when calculating Occlusion
  • material: This is a stock texture provided in the Urho3D resources, which consists of a mix of 3 textures
  • heightmap: In this case an 8 bit greyscale image

The source heightmap for Urho3D's terrain system must be square and be of a size of "2^n+1". For the default resource it's a 1025x1025 pixel 8 bit greyscale. Although this case is an 8 bit greyscale map, if the provided image has more channels it will be treated as a 16 bit heightmap with the Red and Green channels providing the 16 bit value when concatenated.

This material actually uses four images - The TerrainDetail1 to TerrainDetail3 DDS files provide the texture image and the TerrainWeights DDS file selects the texture at a location based on the R, G or B channel. In this case we're not too worried about this since we're just using it as a placeholder.

Generating a Higher Resolution Heightmap

This is actually fairly straightforward; generate an Image() instance, set the image to be 3 channel (although anything higher than 2 will work) and set the values in the pixel map on the Red and Green channel for height.

In setting the pixel values R is the lowest byte of the value, and G is the next, so setting up a manual stepping in the output image can be done as follows.

Image@ heightIm;

uint32 height1 = 0x000f;
uint32 height2 = 0x00ff;
uint32 height3 = 0x01ff;
uint32 height4 = 0x02ff;

void MakeHeightImage(int imgsz)
uint length = imgsz + 1;
  heightIm = Image();

  heightIm.SetSize(length, length, 3);
  uint32 heightColor_fine = 0;
  uint32 heightColor_rough = 0;

  for (int y = 0; y < heightIm.height; ++y) {
    for (int x = 0; x < heightIm.width; ++x) {
    uint32 heightval;

      if (y > (7* heightIm.height/10)) {
        heightval = height4;
      else if (y > (6* heightIm.height/10)) {
        heightval = height3;
      else if (y > (5* heightIm.height/10)) {
        heightval = height2;
      else if (y > (3* heightIm.height/10)) {
        heightval = height1;
      else {
        heightval = 0;

      heightColor_fine = heightval & 0xff;
      heightColor_rough =  (heightval >>8)& 0xff;
      uint32 heightColor = (heightColor_fine << 8) | heightColor_rough;
      heightIm.SetPixelInt(x, y, heightColor);
This generates the image which we can request with a call like:
And assign to the material used for the heightmap.
  terrain.heightMap = heightIm; 
And that's it...

Adding Fly Through Controls

This is very straightforward, and this is lifted directly from the sample code: It adds a basic Mouse look and WASD movement. It's invoked during the frame update, rather than the Key Down handler, and uses the input global to scan the keys and mouse and translate this to camera node rotation and position directly.

float yaw = 0;
float pitch =0;
void MoveCamera(float timeStep)
  const float MOVE_SPEED = 50.0f;
  const float MOUSE_SENSITIVITY = 0.5f;

  IntVector2 mouseMove = input.mouseMove;
  yaw += MOUSE_SENSITIVITY * mouseMove.x;
  pitch += MOUSE_SENSITIVITY * mouseMove.y;
  pitch = Clamp(pitch, -90.0f, 90.0f);

  cameraNode.rotation = Quaternion(pitch, yaw, 0.0f);

  if (input.keyDown[KEY_W])
      cameraNode.Translate(Vector3(0.0f, 0.0f, 1.0f) * MOVE_SPEED * timeStep);
  if (input.keyDown[KEY_S])
      cameraNode.Translate(Vector3(0.0f, 0.0f, -1.0f) * MOVE_SPEED * timeStep);
  if (input.keyDown[KEY_A])
      cameraNode.Translate(Vector3(-1.0f, 0.0f, 0.0f) * MOVE_SPEED * timeStep);
  if (input.keyDown[KEY_D])
      cameraNode.Translate(Vector3(1.0f, 0.0f, 0.0f) * MOVE_SPEED * timeStep);
This really is as simple as it looks: grab the mouseMove value and use it to calculate the value we put into camera rotation, then look for W,A,S and D and call cameraNode.Translate() to move the camera position. Timestep is pulled from the event information to ensure smooth movement but that's it. Next up we'll import some actual levels...

Friday, 14 April 2017

Urho3D and I76 Levels

Urho3D and AngelScript

What's Urho3D?

Urho3d is a game engine - it provides a simple method of implementing a:

free lightweight, cross-platform 2D and 3D game engine
The complete Urho3D release is available at the Urho3D homepage on GitHub, and describes the list of features provided by the engine.

What's AngelScript?

AngelScript is the main scripting language of Urho3D, and Urho3D ships with a slightly modified version in the source tree for running script applications.

Although AngelScript has many of the typical features of scripting languages (such as higher level data types, type inference, automatic memory management, etc) it supports a "C++ like" syntax and has a low overhead when binding to the native API.

The bin/Data/Scripts/ directory in the Urho3D distribution contains a set of example files which demonstrate the basic features of the engine, alongside a level editor and sample game constructed in AngelScript. The distribution also includes an Urho3DPlayer application, which can be used to run scripts directly.

Urho3D also supports Lua as an alternative scripting language, but AngelScript is the default and I'll stick with that.

And where are we going?

The idea is to use AngelScript and Urho3D together with the file format information we have on I76 to decode and provide a realtime fly through view of some of the I76 level geometry.

Over the next few posts I'll go over the basics of running up Urho3D - getting things running, the basic application structure, etc. Then the main flythrough application.

Getting Started

Urho3d Absolute Basics

A few basic concepts to keep in mind are:

  • Urho3D provides a set of subsystems for use in game code
  • Scripts access most of these subsystems via global references
    • e.g.: files, logging, network, input, ui, audio, engine, graphics, rendering, scripting, console, scene, octree, physics, resource cache, and time
  • The Urho3D Engine handles the main running loop for the script, and provides events for the script to react to
  • Scripts include each other directly
  • Many user created items are built around "components" and "nodes"
  • Components mainly provide functional game elements
  • Nodes track 3D properties, and contain components or other nodes
  • Nodes are placed in a graph hierarchy
    • This means that nodes can be attached as children to other nodes
    • The base of the Urho3D application is a root scene node
    • Things like lights, cameras, and 3D objects are created as children of this node
  • But not everything is a node
    • e.g. ui elements are not nodes, but have a similar parent/child relationship to each other
  • Urho3D provides an event driven framework where:
    • The script reacts to global events with a set of function hooks (e.g. Start() and Stop())
    • Scripts can subscribe listener functions to events (e.g. "KeyDown" or "Update)
    • Scripts can also generate events
The complete list of scripting objects and types are in the file AngelScriptAPI.h. The events available are described in various header files and can be found with the URHO3D_EVENT macro.

Urho3D has enough minor differences from the default AngelScript conventions that the primary AngelScript documentation is useful, but not comprehensive. The basic rule here seems to be to search for a usage in the example scripts to determine the canonical way of using the scripting language.

The simplest example

This is a basic graphical hello world - it's simpler than the sample example, and uses the minimal possible code. Just save this into a file

void Start() {
    Text@ txt =  Text();
    txt.SetFont(cache.GetResource("Font", "Fonts/Anonymous Pro.ttf"), 30);

    txt.text = "Hello World, It's " + String(time.systemTime);

    SubscribeToEvent("KeyDown", "HandleClicked");

void HandleClicked(StringHash eventType, VariantMap& eventData) {

How does that work then?

You run the example with the Urho3DPlayer application: try a line like

or in a window mode with
Urho3DPlayer -w
Either press a key (or close the window if in windowed mode) to exit.


The player application loads a script file from the command line, and executes the contents.

The primary entry point of the script is the "Start()" function. This is executed by the Urho3D engine. As the official docs say this is called at engine initialization and before running the main loop.

The first line here starts "Text@ txt" which defines an object handle. The "@" designation is used by AngelScript for reference counted object handles. In this case a Text object, the default Urho3D UI text type.

Given a txt object reference we can use a C++ style member reference through a dot operator to access properties and methods. Here we set the font face and size using txt.SetFont().
In this case the font loaded is taken through the global resources cache, which loads from the installed Urho3D directory, under bin/Data/, and uses the global cache reference.
So cache.GetResource("Font", "Fonts/Anonymous Pro.ttf") call is loading the TTF Font from the bin/Data/Fonts/ directory.

Next we set the "text" property, which is the string to render. The time.systemTime() call gives us the current time.

Both cache and time are two examples of the subsystems services provided by Urho3D on initialisation, and available for the scripts to access through global references.

As mentioned Urho3D uses a parent-child set of relationships, and the AddChild() call places the text entry as a child of the root of the ui. (Although you should be aware that these are UI elements, and not Nodes).

Finally SubscribeToEvent() is used to link the events from Key input ("KeyDown") to the function "HandleClicked()". Note that in scripts we use the name of events, which are converted to the identifiers that the C++ code uses, however these are case insensitive at the script layer, so subscribing to "KeyDown", "keydown" or KeYdoWn" will all do the same thing.
For this app then the HandleClicked() method simply calls an Exit(). This exits the entire Urho process and leave us back at the command line.

A Slightly More Verbose Version

This example is slightly more verbose, and resembles the default sample slightly more. It:

  • Uses input.mouseVisible to ensure the mouse remains visible
  • Has a different event handler for the first frame update, then switches for subsequent frames
    • Where the Update event is sent each frame
  • Has a handler called on every update which will drop out a flood of console debug
  • The text handle is a file global and on each keypress we:
    • Exit if the Escape Key is pressed, otherwise
    • update the text colour and position (only seen on the first keypress)
    • change the on screen text as key presses occur

One interesting feature of this version is that we can pull away focus from the main window, and should see the time step report change, since Urho3D will deliberately lower the frame rate when the Application loses focus. The engine SetMaxInactiveFps() can be changed to modify this.

Text@ instext;

void Start()
    Font@ font = cache.GetResource("Font", "Fonts/Anonymous Pro.ttf");
    instext = Text();
    instext.text = "Hello World, It's " + String(time.systemTime);
    instext.SetFont(font , 30);


    input.mouseVisible = true;

    SubscribeToEvent("KeyDown", "HandleClicked");
    SubscribeToEvent("Update", "FirstFrame");

void FirstFrame(StringHash eventType, VariantMap& eventData)
    instext.text += "\nFirst Frame at " + String(time.systemTime);

    SubscribeToEvent("Update", "HandleUpdate");

void HandleUpdate(StringHash eventType, VariantMap& eventData)
    Print("HandleUpdate Called  at " + String(time.systemTime) + "\n");
    float timeStep = eventData["TimeStep"].GetFloat();
    Print("  Time Step " + String(timeStep) + "\n");


void HandleClicked(StringHash eventType, VariantMap& eventData)
    if (eventData["Key"].GetInt() == KEY_ESCAPE)
        instext.text += "\n Keypress at " + String(time.systemTime);
        instext.horizontalAlignment = HA_CENTER;
        instext.verticalAlignment = VA_CENTER;
        instext.color = Color(0.0f, 1.0f, 0.0f, 1.0f);

And that's all for now - next time we'll cover a simple 3D scene setup, nodes and generate a simple 16-bit heightmap...