Thursday 13 August 2015

Portal Rendering with Offscreen Render Targets

This is an attempt at explaining how to implement portals using an off-screen render target. It's a technique I didn't know a great deal about up until quite recently and after messing around with it for a while I thought it would be cool to describe the approach. Hopefully, people might find it interesting.

The problem consists of three main parts.
  1. Transform the portal camera relative to the portal destination, based on the translation and orientation of the main camera relative to the portal source.
  2. Render the scene from the perspective of the portal camera to an off-screen render target
  3. Apply a portion of that texture to geometry viewed from the main camera with the correct projection.
I will visit each point in turn over the course of this post and try and explain each one thoroughly.

I'm using Unity as it cuts out a lot of the nitty gritty that you might have to deal with getting setup with OpenGL or DirectX. The principles will all hold true no matter what library/engine you're using and porting these ideas to other APIs/platforms shouldn't be too difficult.

The Unity project is available on GitHub here. You're free to do with it what you'd like. Hopefully, this post along with the code should give you a good understanding of what's going on. There are two scenes included, Main and Simple. Simple contains just one portal and makes it a little easier to see what's going on, Main contains two portals and is (slightly) more interesting.

The Unity Main scene with some portals

Part 1: Transform the portal camera relative to the portal destination, based on the translation and orientation of the main camera relative to the portal source.

In the scene named Simple, there are two transforms of note, Source and Destination. The source transform is the centre of the portal and represents the position/orientation the main camera will be treated relative to. The destination transform (represented by the red cube) is the transform the portal camera is treated relative to. (Note: I make use of the layers and culling masks in Unity to ensure the red cube doesn't show up when rendering from the portal camera)

Source (right) and Destination (left) transforms

What we're trying to do is ensure the portal camera mimics the movement of the main camera exactly as it moves around, only relative to the destination transform instead of the source transform. If we look at the local position and orientation of the main camera relative to the source transform, and the local position and orientation of the portal camera relative to the destination transform, they would be exactly the same. Basically, if the main camera is 5 units behind, and 10 units left of the source transform, then the portal camera will be 5 units behind, and 10 units left of the destination transform. Below is an example in 2D.


To ensure the portal camera mimics the movement of the main camera relative to the destination transform, we multiply the world transform of the main camera by the inverse of the source transform to get the camera transform in the source transforms local space. We then multiply that transform by the destination transform to put the camera back into world space. This combines the local transform with the world space transform to give us our final position - the position/orientation of the portal camera.


Above are some scribbled notes to try and make some more sense of this. The diagram is simplified to be in 2D and we are only caring about the position. At #1, we have the main camera position in world space (9, 10) and the source transform at (5, 7). To get the position of the camera in the local space of the source transform, we add the inverse of the source transform (it negated) to the world position of the camera (-5, -7) + (9, 10). This gives us the local transform of (4, 3) at #2. Once we have that, we just add it to the world position of the destination transform #3 #4 (-8, 2) + (4, 3), and we have the final world position of the portal camera (-4, 5)! (Repeated at #5) This is all the matrix multiplications are really doing, they handily also manage rotations but the principle is exactly the same.

This is achieved in Unity with the following code:

public Camera Camera;
public Camera PortalCamera;
public Transform Source;
public Transform Destination;

Vector3 cameraPositionInSourceSpace = Source.InverseTransformPoint(MainCamera.transform.position);
Quaternion cameraRotationInSourceSpace = Quaternion.Inverse(Source.rotation) * MainCamera.transform.rotation;

PortalCamera.transform.position = Destination.TransformPoint(cameraPositionInSourceSpace);
PortalCamera.transform.rotation = Destination.rotation * cameraRotationInSourceSpace;


(Note: In other math libraries (glm/DirectXMath) you can likely just multiply the matrices but Unity prefers using position and rotation (exposed as Vector3 and Quaternion) directly from scripts so you have to do each individually)

It is also important to ensure the portal camera has the same field of view (FOV) and aspect ratio as the main camera to ensure the images match up correctly when doing the projection later.

Part 2: Render the scene from the perspective of the portal camera to an offscreen render target

Thanks to Unity this step is made very easy. You can see how it is setup in the example project, but basically, all you need to do is create a new asset of type RenderTexture, and then assign that to the Target Texture public property of the portal camera. This will cause the camera to render its view to that texture, which you can then use with a material in your scene.

Part 3:  Apply a portion of that texture to geometry viewed from the Main Camera with the correct projection.

This last part is probably the most difficult and requires you to have an understanding of projection transformations to appreciate what is going on. I'll do my best at giving an overview and link to some articles/references that do a better job of explaining it than me.

First off let's view the scene from the perspective of the portal camera (see below). This is the image that is being rendered to our texture

Scene rendered from portal camera perspective that ends up in our texture

If we now look at what we'd like to see from the main cameras perspective, this is what we'd expect (see below). (In the sample project linked at the top of this article you can toggle between these two cameras to observe this effect by hitting 'C')

Scene rendered from main camera perspective
If we ignore all the other geometry, what we actually want to do is map a portion of the texture (the first image from this section) to the red quad below.

Only rendering the geometry we want the texture to be 
applied to from the main cameras perspective

Geometry with the correct portion of the texture applied from 
the main cameras perspective

If you're reading this hopefully you're familiar with taking an object in world space and transforming it to screen space. (If not then check out the links at the bottom of this post). The quad we would like to apply our texture to gets transformed from world space to screen space as normal, the trick comes with how we calculate the texture coordinates for it to display the right portion of our texture.

Usually, models have texture coordinates authored for them (ranging from 0 - 1 in X and Y). If we used this approach with the quad in the above screenshot, we would see our texture, but it would be all squashed to fit on the quad and would look totally wrong (see below)

Squashed texture not mapped with the correct projection
Essentially what you want to do is copy a part of the texture into the other scene. The trick is to calculate the texture coordinates for the portal based on the current projection. To achieve this you need to write some custom shader code which I'll try and explain now.

// Values passed from Vertex to Pixel Shader
struct v2f {
    float4 pos : SV_POSITION;
    float4 pos_frag : TEXCOORD0;
};

// Vertex Shader
v2f vert(appdata_base v) {
    v2f o;
    float4 clipSpacePosition = mul(UNITY_MATRIX_MVP, v.vertex);
    o.pos = clipSpacePosition;

    // Copy of clip space position for fragment shader    
    o.pos_frag = clipSpacePosition;
    return o;
}

// Pixel Shader
half4 frag(v2f i) : SV_Target {
    // Perspective divide (Translate to NDC - (-1, 1))
    float2 uv = i.pos_frag.xy / i.pos_frag.w;
    // Map -1, 1 range to 0, 1 tex coord range
    uv = (uv + float2(1.0)) * 0.5;
    return tex2D(_MainTex, uv);
}


First, we define a struct to write to the SV_POSITION semantic (this is to provide the vertex position in clip space to the next stage of the graphics pipeline) and also to pass values from the vertex shader to the pixel shader. In this case, we want the vertex position in clip space in the pixel shader, but unfortunately, you cannot access a variable with the semantic SV_POSITION from the pixel shader, so in this case, we create a copy - pos_frag. The TEXCOORD0 semantic is not required on all platforms (though sometimes is necessary) and has nothing to do with the actual value we're passing (in this case the position of the vertex in clip space - it doesn't matter it's not actually a texture coordinate). Using the semantic will, however, guarantee the pixel shader can access it.

The pixel shader accesses the XY position of the vertex in clip space (clip space refers to the space a vertex is in after being multiplied by the projection matrix. x, y and z coords are in the range:
-w <= XYZ <= w at this point. See links below for more info) and then does the perspective divide by dividing by the w component. This takes the position from clip space to normalised device coordinates (NDC) which range from -1, 1 in x, y, and z. (In DirectX the range is from 0, 1 in z and in OpenGL it is from -1, 1. You don't have to worry about that in this case, though). It's worth mentioning that for vertices this perspective divide happens automatically and is hardwired into the graphics pipeline. It happens after the vertex shader runs - you don't usually see this happen explicitly.

It is also worth mentioning that w is the z value of the vertex in camera space, which is simply how far away from the camera the vertex is down the z-axis. In the shader, you could do this instead if you wanted...

// Add this to v2f struct
float4 pos_cam_frag : TEXCOORD1;

// Vertex Shader - Store camera space vertex position

v2f o;
o.pos_cam_frag = mul(UNITY_MATRIX_MV, v.vertex);

// Pixel Shader - Use the z value in camera space for perspective divide
float2 uv = i.pos_frag.xy / -i.pos_cam_frag.z;


There is no reason to do this as the MVP transform copies z into the w component which we use, but I just wanted to make it clear that they are the same. This is only true for perspective projection as with orthographic projection the w value will be 1. (Note: We have to invert z here otherwise the image will appear upside down - this is down to the coordinate system and whether positive z is going in or out of the screen) Whether to flip this value or not is handled by the projection matrix which will be slightly different depending on what underlying graphics API we're using.

Once we have the interpolated vertex position (I say interpolated as we're in the pixel shader) in NDC space, we bring it into the range 0, 1 which maps perfectly to a texture coordinate we can use. We then simply sample the texture at this location and return the colour, and we're done!

This might all seem a bit like magic, and I admit it did to me the first time I saw it, but if you can visualise taking the red quad from the earlier screenshot, laying it over the view of the portal camera that we rendered to a texture, then cutting a hole where the red quad was, that's basically what the projection is doing.

If you think about the top most corner of the quad we're applying the texture to (the red square), the Model View Projection transformation and perspective divide have moved it to an NDC value of roughly (0, 0.5) - the range is -1, 1 for x and y so roughly centre screen and 3/4 of the way up. We get that value in the pixel shader, and then transform that to a range 0 - 1 (tex coord range), so it becomes (0.5, 0.75). We then use that value to sample the texture we rendered off-screen at that coordinate, and that's what will show up at that position in the final image. When you think about how we talked about overlaying that part of the texture, you should hopefully see how we get the right bit of the texture at the right point on the screen.

I highly recommend reading these articles on projection to fully understand what is going on.

Useful Links:
  • http://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/projection-matrix-introduction
  • http://www.scratchapixel.com/lessons/3d-basic-rendering/computing-pixel-coordinates-of-3d-point/mathematics-computing-2d-coordinates-of-3d-points
  • http://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/projection-matrix-GPU-rendering-pipeline-clipping
  • http://http.developer.nvidia.com/CgTutorial/cg_tutorial_chapter04.html
  • http://ogldev.atspace.co.uk/www/tutorial12/tutorial12.html
  • http://fabiensanglard.net/polygon_codec/
Books:
  • Essential Mathematics For Game Developers 2nd Edition
  • 3D Math Primer for Graphics and Games Development 2nd Edition

The GitHub project is available here - Do have a poke around and see how it works. It is pretty basic. It does not handle viewing portals through other portals and has no logic to handle actually teleporting the camera. There is a completely different approach to portal rendering which involves using the stencil buffer and rendering the scene to the main camera twice, with one pass doing a stencil test on the area to view the portal through, that approach is not covered here but Part 1 of this article is still applicable to that case.

There are further optimisations you can make to this technique, one is to ensure the majority of the scene you render to the portal camera gets clipped by building a new view frustum from the extents of the portal. This requires a modification to the shader and the camera code but can drastically increase performance as you get rid of a bunch of stuff you don't need to draw as you can't actually see it. You can adjust the near clip plane of the portal camera with the technique outlined to reduce the amount you need to render too.

I'd like to thank Dave Smeathers (engineer and all round graphics ninja at Fireproof) for helping me out with this originally and Rob Dodd (technical director extraordinaire at Fireproof) for offering feedback on early versions of this post. Thank you to Jonny Hopper too for giving me feedback on earlier drafts.

Thanks for reading!

UPDATE (18/02/2017)

It was recently brought to my attention (thank you GitHub user madblade aka. Max) that there was an unfortunate oversight in my current/previous implementation of portal rendering. One thing I had neglected to do was ensure that any objects rendered between the portal camera and the destination transform were culled. This meant that if an object was positioned behind the destination transform, it would incorrectly show up in the source portal. An example of which is shown below:


As you can see in the lower image, the red pillar behind the blue door shows up in the red door frame. We definitely do not want to see this as we should only see things in front of the blue door in the red door portal.

To fix this I did a bit of pondering (and Googling) and realised I needed to correctly update the portal camera projection matrix to ensure the near clip plane aligned with the plane of the portal. I'd experimented with doing this by adjusting the near clip, but the issue is the near clip plane is orthogonal/perpendicular to the camera view direction, not the normal of the portal, so you get unwanted clipping when looking at the portal at sharp angles. To adjust the near clip plane correctly one must us a technique called oblique projection - you can read more about it here - http://www.terathon.com/lengyel/Lengyel-Oblique.pdf and here http://aras-p.info/texts/obliqueortho.html

I don't want to go into all the excruciating detail, but in order to ensure the normal of the plane of each portal was correct (facing out of the portal), for the destination/corresponding transform, I have to rotate it by 180 degrees about local up (Y in this case) in the Portal.cs script so the portal cameras transform is the mirror of the source camera. Before, I had ensured the source/destination transforms in Unity were the mirror of one another (as you can see in an earlier screenshot), but this was no good as then I couldn't use the forward vector of the transform (portal surface normal) for one of the portals to create the oblique projection matrix (essentially in the example above, one portal would look fine, and the other wouldn't work at all!)

So now each portal (door) has its transform set so that local Z is pointing out of the surface. I use this to create a plane (the surface normal/forward vector of the portal, and the position in world space of the portal), transform it to camera space (multiply the plane by the inverse transpose of the camera transform) and then build an oblique projection matrix from this plane. This ensures the near clip plane is aligned to the portal surface. With that, everything now looks correct! We don't see the red pillar rendered as it is now correctly clipped, and we don't see any incorrect clipping when looking at the portal from sharp angles as the near clip plane is correctly aligned with the portal! 

If you take a look at Portal.cs in the GitHub project you should be able to see all the individual steps!

I hope this has been some more help to anyone interested in this area!

Friday 8 August 2014

Premake and Visual Studio

I've been on an interesting journey over the last couple of days and thought it would be good to share what I've learnt.

It started with me wanting to check out bgfx - a very cool looking open source rendering library. I had poked around it in Sublime but wanted to be able to build it from Visual Studio so I could more easily navigate around and debug the code to get a better understanding of how everything works.

I hit a pretty big stumbling block though, and that was having exactly zero knowledge of the tool required to generate the Visual Studio solution - Premake.

Premake is a lot like CMake if you've heard of it - I've used CMake a bunch but have to admit to never writing my own CMakeLists.txt file (it's on my todo list). A number of open source projects I've been interested in have required CMake to generate project and solution files for Visual Studio - there is a bunch of useful information here (I usually just hit Ctrl-F and search for out-of-source build and run that command :))

bgfx required Premake as opposed to CMake. It turned out there wasn't much difference between the two and all you needed in order to use Premake was the Premake executable (4.4 beta5) and to run the command premake4  in the directory where premake4.lua is found for the project you're trying to build - in bgfx's case bgfx\premake. (I wasn't able to just run the make command, I may have missed something but I kind of prefer this approach as it's more explicit in what you're doing)

So in my case I ran - premake4 vs2012

(Update: Note: Premake 4.4b5 is available as part of the bx library too. In order to build bgfx you need to use premake 4.4b5 - Thank you Branimir Karadžić! @bkaradzic

premake4 is the name of the .exe you download from the link above. You can either copy it to where you want to use it or just add it to your Path environment variable (easier in the long run). I specified vs2012 as the argument (unfortunately vs2013 doesn't seem to work with the most recent version of premake4. premake5 does exist, and vs2013 works with this - you can get this by building from source, I also found premake5 here. premake5 won't work with bgfx though - use 4.4b5) Luckily if you do have vs2013, it will just happily update the vs2012 project files and it will all just work (tm).

(Update: premake5 is available here from sourceforge nightlies - Thank you Mihai Sebea! @mihai_sebea)

So now I had the project files for bgfx and I was feeling quite pleased with myself (it doesn't take much). I was about to jump head first into playing around in bgfx but instead decided to have a look at the premake4.lua file used to build it. I had been toying with the idea of switching to CMake or an alternative build tool to create my own solution/project files for my own projects and now seemed as good a time as any to give this a go.

Digression...
As a quick aside I thought it might be worth explaining why do any of this at all. Why not just maintain a Visual Studio .vcxproj and vcxproj.filters file and add/remove all your files from within VS? In real life this is absolutely fine for a lone developer or a small team, but as soon as you have more than a few people working on a project things can start getting unwieldy. It may surprise you to learn that this is actually what we did on Need For Speed: Most Wanted (2012). The .vcxproj and .vcxproj.filters files were both checked into version control, and every time you wanted to add a file, you had to check out the file and attempt to submit before someone else did (locking files was poor form). This lead to bad merges and broken builds. People often refused to undo local changes and re-add the files, they instead would try to hand merge things when there were conflicts and this would quite often go wrong. This wasn't a deal breaker but didn't help things either. Fortunately Frostbite does employ such a system where each time you get latest you more often than not need to regenerate your projects as files will likely have been added/removed from the depot. This eliminates the problems from before, but doesn't come without its drawbacks. Having to generate projects every time you get latest does slow you down (stuff is cached of course but it's not instant, especially with a source base as big as Frostbite) and if you forget to do it you can get some annoying compile/link errors. It's up to you what you do but it's good to know what options are available.
End Digression....

My reason for choosing Premake was first and foremost the documentation and the ease of use. The documentation serves as a fantastic introduction to Premake. It isn't daunting and does not overwhelm the reader with too much information at once. (I've often found the opposite when looking into CMake although I might have just found the wrong sources)

As an experiment I decided to retroactively produce a generation script of a project I am currently working on. This was super helpful as I could compare the project settings in my current solution to the one I was generating to ensure they matched. This took an afternoon of experimentation, googling and cursing until finally I had a script that faithfully produced my full Visual Studio solution.

solution "AS - GL4"
  configurations { "Debug", "Release" }
  location "Project"

-- Awesome Sauce Framework
project "AS"
  language "C++"
  kind "SharedLib"
  location "Project/AS"

files { "GLFW Win/**.h",
"GLFW Win/**.cpp",
"GLFW Win/**.frag",
"GLFW Win/**.vert" }
excludes { "GLFW Win/External/**" }
 
  includedirs { "GLFW Win/External/include/GL/GLFW",
"GLFW Win/External/include/include/assimp",
"GLFW Win/External/include/GL/GLLoadGen",
"GLFW Win/External/include/GL",
"GLFW Win/External/include/glm",
"GLFW Win/External/include",
"GLFW Win/ASframework",
"GLFW Win" }
 
  pchheader "Pch.h"
  pchsource "GLFW Win/ASframework/Pch.cpp"
 
  defines { "AS_FUNCDLL_EXPORT" }

buildoptions { "/DEBUG" }
flags { "Symbols", "FatalWarnings" }
warnings "Extra"

  configuration "Debug"
  buildoptions { "/MDd" }
libdirs { "GLFW Win/External/lib/Debug/assimp",
"GLFW Win/External/lib/Debug/GL3",
"GLFW Win/External/lib/Debug/GLFW",
"GLFW Win/External/lib/Debug/GLLoadGen" }
links { "assimpD" }
optimize "Off"

configuration "Release"
flags { "NoFramePointer" }
libdirs { "GLFW Win/External/lib/Release/assimp",
"GLFW Win/External/lib/Release/GL3",
"GLFW Win/External/lib/Release/GLFW",
"GLFW Win/External/lib/Release/GLLoadGen" }
links { "assimp" }
optimize "Speed"

configuration {} -- Clear configuration

links { "opengl32",
"glfw3",
"GLLoadGen" }

-- OpenGL 4.4 Test Project
project "GL4 Test Bed"
language "C++"
  kind "ConsoleApp"
  location "Project/GL4 Test Bed"

  files { "GL4TestBed/**.h",
  "GL4TestBed/**.cpp",
  "GL4TestBed/**.frag",
"GL4TestBed/**.vert" }

  includedirs { "GL4TestBed",
"GLFW Win" }

buildoptions { "/DEBUG" }
flags { "Symbols", "FatalWarnings" }
warnings "Extra"

configuration "Debug"
libdirs { "GLFW Win/External/lib/Debug/GLLoadGen" }
debugenvs { "PATH=%PATH%;../../GLFW Win/External/dll/Debug;../AS" }
buildoptions { "/MDd" }
optimize "Off"

configuration "Release"
libdirs { "GLFW Win/External/lib/Release/GLLoadGen" }
debugenvs { "PATH=%PATH%;../../GLFW Win/External/dll/Release;../AS" }
flags { "NoFramePointer" }
optimize "Speed"

configuration {} -- Clear configuration

links { "AS",
"opengl32",
"GLLoadGen" }

(As it happens this is actually the premake5.lua script which includes a few small changes - for example the warnings and optimize keywords are additions not included in premake4. Other than that it's much the same - you can find more info about it on the premake wiki)

Many of the options listed are covered in the Premake documentation mentioned before, but there are some interesting additions I had to do some googling for.

One interesting line is debugenvs. This is responsible for this option in the Visual Studio project settings


When you run your application from VS, if there are any other dlls it depends on, this is where you can tell it to look for them. I feel this is much better than just copy/pasting the dlls into the project root folder.

Another is links.These are library dependencies and map to this screen in Visual Studio


I am also using Precompiled Headers in my Library (mainly as an academic exercise to figure out how to set them up, I'm not really interested in if they're a good idea or not) To make sure the premake5.lua script knows this, you need to specify the file and the source for it.

pchheader "Pch.h"
pchsource "GLFW Win/ASframework/Pch.cpp"


The last thing to note is as I am using several other libraries. I have both the debug and release builds of each one and need to link against the correct dll/lib otherwise Visual Studio gives you lots of warnings (and rightly so!). Premake provides the ability to do this with the configuration keyword. Also notice the configuration {} statement which is used to make sure anything following it is not tied to a specific configuration.

I hope that this has given a good introduction to Premake (definitely go read all the docs if you're interested) and that my example script might be of some use as a reference for if you try this yourself. If you have any questions please feel free to shoot me a message (although I am far from an expert having only discovered this a short while ago!)

Thanks for reading - I didn't intend for it to be quite this long!

Saturday 24 December 2011

Load in Place data structures and Pointer Fixups

PROLOGUE:

When I first started this blog post my intention was to describe the process of loading full game assets using the Load in Place technique in C++, I quickly realised however that I probably needed a little more context before jumping into a full example so what you're reading now is the result.

Please bear in mind all of this is done purely as an example to learn the core concepts, you would never use this in a real project. You would ideally want some nice way of encapsulating what is happening by providing friendly interfaces to handle loading for you, but I find these interfaces can often obscure what is actually happening when you are first learning this stuff, to I have omitted this for clarity. I will hopefully at some point in the future provide an example of such an interface to use all this code with! (We also would want a generic implementation capable of loading lots of different types of files and also the ability to load more than one object at once, but we'll worry about that stuff later).

THE BEGINNING:

Simple File I/O in C:

I decided to use the file I/O in C for this example as opposed to C++. There are some differences and in retrospect C++ maybe have been a better call but they achieve pretty much the same ends. I am sure if you're that way inclined you could port these examples to use fstream instead and I may well revisit this in future to do just that.

Here is a simple example of saving a file with some data you have created:
(I suggest having a read through this article if you are not too familiar with File I/O in C:
http://www.cplusplus.com/doc/tutorial/files/ )

class Foo {
public:
    int i;
    int j;
};

int main(int argc, char** argv)

{
    FILE* file;
    file = fopen("MyFile.bin", "wb");

    Foo myFoo;
    myFoo.i = 1;
    myFoo.j = 2;

    fwrite(&myFoo, sizeof(Foo), 1, file);
    fclose(lfile);

    return 0;
}

So what's going on here. First we create a file in the local directory called "MyFile.bin". The extension is used to identify the file as being in binary format, when we create the file we open it for writing in binary mode which is what the "wb" represents - 'writing,binary'. We then fill in a very simple structure and write that structure to disk, making sure to close the file after. We have just saved the state of our object, which is pretty neat. Imagine if that was the score in a given level or the amount of health we had left at a particular save. The cool thing is getting that information back is super easy as well! All we need to do is this:

class Foo {
public:
    int i;
    int j;
};

int main(int argc, char** argv)
{
    FILE* file;
    file = fopen("MyFile.bin", "rb");

    Foo myLoadedFoo;

    fread(&myLoadedFoo, sizeof(Foo), 1, file);
    fclose(lfile);

    cout << "i: " << myFoo.i << "j: " << myFoo.j << endl;
    return 0;
}

To get the data back we just read the file and fill in a blank struct of the type we saved. We open the file for reading in binary mode "rb - reading,binary", call fread instead of fwrite and fill in our struct. If we print out the contents you will find we have the output of 1 and 2 on screen. Pretty cool right?

THE MIDDLE:

Where things get interesting is when we have pointers in those objects to some data else where in memory. How do we store that dependency? If we were to use the method above with a pointer in Foo, like this:

class Foo {
public:
    int   i;
    int   j;
    char* p;
};

The method we just discussed will unfortunately not work, lets see why. Take a look at this next example.

class MessageList {
public:
    char hello[6];
    char goodbye[8];
    char cheese[7];
};

int main(int argc, char** argv)
{
    // This is just an example of a standard resource 
    // load you can think of happening in a resource manager
    // This would probably also be loaded from a file at some 
    // earlier stage in the program in a real world situation.
    MessageList myMessageList;

    char* hello =   "Hello";
    char* goodbye = "Goodbye";
    char* cheese =  "Cheese";
    
    strcpy(myMessageList.hello,   hello); 
    strcpy(myMessageList.goodbye, goodbye);
    strcpy(myMessageList.cheese,  cheese); 
    // End of file load  

    FILE* file;
    file = fopen("MyFile.bin", "wb");

    Foo myFoo;
    myFoo.i = 1;
    myFoo.j = 2;
    myFoo.p = myMessageList.cheese; 

    fwrite(&myFoo, sizeof(Foo), 1, file);
    fclose(lfile);
    return 0;
}

Now there is a little bit more going on here but most of it isn't really that important, it's just to set up the example so don't worry too much about it if you don't get it all. Basically think of MessageList as a memory pool, which might easily contain all kinds of game assets like textures and models and sounds. I just set up some default strings and copy their value across into the structure in the same way I would load a texture and then store it in a block of memory somewhere. The way you load and store these assets is up to you, you can store them dynamically or allocate them statically, just make sure the object you're saving (in this case Foo) has access to that memory chunk. So going back to the example, I save the memory address of myMessageList.cheese and then write the myFoo object to disk.

The problem with doing only this is that we cannot guarantee MessageList will be at the same address in memory when we try to load it as when we saved it previously (in fact it is pretty much guaranteed this won't be the case). There is no way of going between the address it resided at when you saved it and the address you actually want when you come to load the object, so that just won't work. What we need is a way of translating our pointer from it's old address to the new address of MessageList when it is loaded. When we save Foo, if we know the start address of MessageList when we save it, and the address of what the pointer in our object is pointing to in MessageList, we can calculate the offset of that pointer by subtracting one from another!

class Foo {
public:
    int   i;
    int   j;
    char* p;
    uintptr_t offsetOfPointer;
};

class MessageList {
public:
    char hello[6];
    char goodbye[8];
    char cheese[7];
};

int main(int argc, char** argv)

    MessageList myMessageList;

    char* hello   = "Hello";
    char* goodbye = "Goodbye";
    char* cheese  = "Cheese";
    
    strcpy(myMessageList.hello,   hello); 
    strcpy(myMessageList.goodbye, goodbye);
    strcpy(myMessageList.cheese,  cheese);      

    FILE* file;
    file = fopen("MyFile.bin", "wb");

    Foo myFoo;
    myFoo.i = 1;
    myFoo.j = 2;
    myFoo.p = myMessageList.cheese; 

    // Here we store the offset of the pointer, this should 
    // really be stored in a pointer lookup table and not as 
    // part of the object but I have left it here for simplicity.
    myFoo.offsetOfPointer = (uintptr_t)myFoo.p - (uintptr_t)&myMessageList;

    fwrite(&myFoo, sizeof(Foo), 1, file);
    fclose(lfile);
    return 0;
}

The line

myFoo.offsetOfPointer = (uintptr_t)&myFoo.p - (uintptr_t)&myFoo;

might look a bit confusing but it really isn't. uintptr_t is just a typedef of an unsigned integer value and it is only used to guarantee cross platform compatibility. It provides a large bound for the size of the number it can store as well, (in this case we could probably just use 'long' and it would still work on most platforms). We cast the memory address to integers, and because the object is contiguous in memory, subtracting one address from the other gives us a value of how far the pointer in bytes is into the data structure. So all we need to do is save the offset of the pointer, not the pointer itself, and use that offset to 'Fix-up' the pointer when we load the object again. Ideally you store the pointer offsets in another file which is not part the object you're interested in, you'd then load them at the same time and use the offsets stored in your pointer lookup table,  I have just stuck the offset in the object for brevity.

THE PAYOFF:

Right, so we have saved our object and the offset of the pointer into the memory pool we are loading from (in this case MessageList). Lets see how we actually do the pointer fix-up.

class Foo {
public:
    int i;
    int j;
    char* p;
    uintptr_t offsetOfPointer;
};

class MessageList {
public:
    char hello[6];
    char goodbye[8];
    char cheese[7];
};

int main(int argc, char** argv)
{
    MessageList myMessageList;

    char* hello   = "Hello";
    char* goodbye = "Goodbye";
    char* cheese  = "Cheese";

    strcpy(myMessageList.hello,   hello);
    strcpy(myMessageList.goodbye, goodbye);
    strcpy(myMessageList.cheese,  cheese);

    FILE* file;
    file = fopen("MyFile.bin", "rb");

    Foo myFoo;
    fread(&myFoo, sizeof(Foo), 1, file);

    // Here we cast MessageList to be an array of chars 

    // in order to make sure when we use the offset to do 
    // some pointer arithmetic, we are adding only
    // 1 byte (char == 1 byte) per offset so we move the correct 

    // distance into the data structure for our pointer offset.
    char* data = (char*)&myMessageList + myFoo.offsetOfPointer;

    // We then cast the data back to the same type of the pointer. 

    // In this case we actually stored a char* pointer so the next
    // step is a bit pointless, but imagine it was another user
    // defined type such as Model, you would just do
    // myFoo.model = (Model*)data;
    myFoo.p = (char*)data;

    fclose(lfile);
    return 0;
}


The lines you want to pay attention to are these ones:

char* data = (char*)&myMessageList + myFoo.offsetOfPointer;
myFoo.p = (char*)data;


What we are doing is casting the MessageList to be an array of chars, this just means we can treat the structure as a chunk of bytes in memory that we can index into. When we calculated the offset before, that gave us the offset in bytes, so by adding the offset to the start address of MessageList after we have cast it to an array of chars will leave us at the correct place in memory where we want to fix-up our pointer! The second line in this case is actually redundant as it happens we are dealing with char arrays anyway with our string values, we don't need to cast the char* back to the object type of our pointer because it's already a char*, but what if our pointer was to another user or fundamental type such as Model or int, we would need to cast it back to the correct type before we could use it.

And that is pretty much it! Once you have done that you have completely loaded your object and can do with it what you please. I must stress that this really is the simplest example of Load in Place, and hopefully now you can see the power and potential of such a technique. As I said before, creating a lovely interface to handle all this nitty gritty stuff for you is absolutely the way to go, and I will try and dream up something as an example in not too long.

I hope this has been of use to you and made pointers and loading data not quite so scary as it may have been before. (Also if I have got something wildly wrong please let me know!)

(Also check out these articles on Load In Place which go into much more detail and are great resources which helped me)

http://entland.homelinux.com/blog/2007/02/21/fast-file-loading-ii-load-in-place/
http://www.gamasutra.com/view/feature/3984/delicious_data_baking.php?print=1

Thursday 9 September 2010

Angry Robot Rampage is OUT!

Angry Robot Rampage has been released on Xbox Live Marketplace!

The feeling is quite surreal that something I have made is now being played across the world (well I hope it is anyway)

If you have been so kind as to download and play my game, I am eternally grateful to you and would love nothing more than to give you an enormous hug and/or high five. I really hope you enjoy playing it and that it puts a smile on your face.

Here is a fan page if you are interested in spreading the love - http://www.facebook.com/pages/Angry-Robot-Rampage/112880442102923?v=page_getting_started

You are welcome to follow me on Twitter as well at http://twitter.com/pr0g89

Thank you so much for your time and interest, I appreciate it more than you'll ever know.

Monday 6 September 2010

Angry Robot Rampage

It has again been a long while since I have written anything here and to those of you who care (if there are indeed any of you out there) I apologize. On a positive note however, I have actually been working on something that might be worth writing about.

Over the past two months I have been working on a game for Xbox Live Indie Games, and it is now on the verge of release - This is my story.

In the beginning, I knew whatever I was going to work on would need to be small - I had to be able to complete it over the summer. That meant no sweeping story-arcs, no endless levels escalating into ever higher and obscure difficulties, and no torrents of exposition about the characters motivation and inner most feelings (not that there's anything wrong with these things - but I knew I didn't stand a chance of pulling off such a game). I needed something with a small enough scope so that it could be reasonably polished, fun to play, and artistically appealing.

In mulling over ideas for the game, one idea kept coming back up, and that was SHOOTER. I had recently played a fantastic game for the iPhone called 'Zombieville: USA' (I highly recommend checking it out if you have an iPhone) You play an intrepid adventurer batting through hordes of zombies while slowly leveling up and gaining new weapons, it has some really nice design, and a wonderful art style. I wanted to create something like this then, but what, and how?

Work began very slowly. The first thing I knew I needed was a protagonist, but how to create such a chap? I began by creating a little man through the use of a sprite sheet (where I would draw each individual frame of him running) but this soon proved to be far more arduous and time consuming than I had first anticipated. (I can draw, but an artist I am not - My respect for animators and people who do this full time has increased exponentially - especially the artists who worked on the XBLA game 'Shank'). To remedy my inadequacies in the art department, I decided that the protagonist could be updated and animated (though somewhat crudely) through the wonders of computer code. The hero was born.

I had a man on screen, bobbing up and down in front of the CornFlowerBlue background that all XNA coders will be familiar with, but then I realized - 'What the 'heck' do I do next!?'

This stage of development is probably one of the worst (perhaps just behind bug fixing). You know what you want, but as with anything in programming, there are about five million different ways of going about it. To get me moving again, I went in search of inspiration. I am eternally grateful to the example code and tutorials at creators.xna.com. I dug through many of them, looking at techniques and examples to give me a better understanding of what I should be doing, and how I should be doing it. In particular I would like to make mention of the GameStateManagement and SafeAreaBounds examples. They helped me a lot in the beginning in getting my game structure working as well as the lovely scrolling background.

A few weeks later and things were slowly starting to take shape. I had a robot who would follow you round, a scrolling background, different states to handle my game, and.... well that was about it. At this stage I had what you call programmer art. (Please see below)


It was time to step up the time I was working on the game and start making stuff look cool! I contacted an old friend of mine named Richard Dorran, a fantastic artist and video game compatriot. I realized if the game was going to look any good at all I was going to need some lovely background art (largely to distract from the mediocre game play). Richard happily agreed, and it was then that the game went from 'lame prototype' to 'OMFG, this looks like a real game!'

Many discussions ensued ranging from the number of enemies to the color of my protagonist bandanna. Slowly things started to take shape, and within a few weeks, we had something that looked like this.


It was looking better, but the game play was pretty dreary (far more than it is now believe you me). It was over this part of development where programming is the most fun. You have the basic structure in place, and adding features doesn't seem as painful as before. You can experiment a lot, and see what works, and more importantly, what doesn't. It was in this phase that grenades were added, as were the red patches on the enemies back to cause them to blow up in one shot, and finally a flying enemy to make the enemies ever slightly more varied.

Before I knew it we were nearing completion. At this stage focus was moved to the sounds and menus and all other manner of things not related to the game itself (which all add up to be a lot more than you think). Another good friend of mine, one Ed Trethowan provided some lovely background music while SoundSnap.com provided the screams and dulcet tones of my hero that grace your ears. It was here too that I realized we needed a developer name, and ToRchEd was born (See if you can guess why that was the name)




The last and final hurdle was the addition of a high scores table. This was one the most painful programming problems I have ever experienced. The save and load operations required for a high scores table worked perfectly on the computer, but as soon as you tried to run it on the 360.... BOOOOOM - Error Code 4, thank you, try again. You of course cannot debug your code while it is running on the 360, so good luck finding out exactly what went wrong. I was stumped for a while on this but finally managed to crack it (I will upload how I did it soon if anyone is interested)

Now came the scariest part of all - submission. Up until this point it had only been me, my family and a few close friends who had laid eyes on the game, seeing it slowly take shape over the weeks and moths I had been working on it. Their comments were always positive and encouraging, but what happens when you throw it out to the internet.. What if they hate it? What if all of this has been for nothing!? Luckily things went smoother than I had thought, the community at creators.xna.com are very friendly, and they were constructive and helpful in their criticism. It is thanks to them that multiple weapons were added as well as a slightly higher jump, and a slew of other small fixes.

So here ladies and gentlemen, is the finished article.


As I sit here typing the game is in the process of peer review and should be out within a week or so. It has been a roller coaster ride, with ups and downs, and thrills and chills. It has been a fantastic experience, and I cannot wait for the rest of you adorable people out there to be able to play it!

I'll post here again when the game is available for public consumption.

(P.S. Here is a link to a video of the game! http://www.youtube.com/watch?v=ix31gnNFgJU Enjoy :))

Wednesday 12 May 2010

Tower Defence is Finished!

Apologies it has been a while since I have written anything here, hopefully this will make up for it.


Well my Final Year Project is done, finished, finito! The hand in for not only the code but the 15,000 word dissertation was the 6th of May. In the week since I have been primarily breathing sigh after sigh of relief that it actually turned out okay. Below is a screen from the end result.






It wasn't perfect, there were bugs, there were things that I'd have done differently, things I wish I could change, but considering it was the first 'large' piece of software I have ever written, and definitely the one I have spent the most time on, it certainly could have been worse.


The experience was a roller coaster ride of emotions; Joy, despair, love, hate, pride and disappointment. There were times of pure ecstasy when features would come to life, and moments of sorrow and anger when things just didn't work. At times the code would seem majestic and beautiful, at others it would look like a hacky mess.

I have learnt so much from the experience. My knowledge of design, construction, debugging, and test has increased dramatically, but I feel the most important lesson I have learnt is the notion of compromise. Being realistic in your aims and what you hope to achieve is so very important to make sure you get something at the end. Now I'm not saying don't be ambitious, please set your sights high, but you have to realise you're not going to create a Call of Duty killer in the space of 6 months as an undergrad comp-sci student.

Now what I want more than anything is to take everything I've learnt and apply it to something new, something better, something even cooler!

Thursday 4 March 2010

Height Maps

Greetings and salutations my friends, I hope you're well! I am in a specially good mood today as I have recently implemented a new feature in my game, and it actually looks cool!

Over the last few days I have been working on a cool way of creating a background for my tower defence game. When speaking with my project supervisor Simon, he mentioned it might be a good idea to create a height map which can be used to render a terrain.

First off, a height map is a way of procedurally generating a graphical scene. The height map itself is basically a grey-scale image (think of clouds) which acts as data that you want your program to get hold of. In order to get hold of the data, you go through the image, taking each pixel in turn, finding the intensity (level of white/black) in each one. The values of each pixel correspond to the heights of your vertices when you go to draw your scene. So white would be the highest point, and black would be the lowest, with all the greys somewhere in between. As you draw your vertices, you go through the list of pixel data and set the height to the corresponding value (you can of course scale this afterwards if you want).

This all sounds perfectly simple and straightforward, and I guess it is compared to some problems you'll face, but as I have come to learn, things are never as simple as they first seem. The first problem I had was getting hold of the actual pixel information itself. I am using SDL to load my images, and while the SDL_Surface object is great, it is not at first blindingly obvious how to get hold of each pixel. Realising I wasn't going to get that working first, I decided to get the drawing code working, and then work out what the height values would be after. Here is what I got first try...


Looks bad I know, instead of finding the height values from the height map image, I randomly set the values between 0 and 100 for each vertex; this was the result. Green probably wasn't the best choice either. At least I knew something was drawing which was a start. I then went about getting the pixel information to work, and I solved it with this little method:

get_pixel(SDL_Surface *surface, int x, int y)
{
Uint8* p = (Uint8*)surface->pixels + 3 * (y * surface->w + x);
return *( Uint16* )p;
}

Here you pass in your SDL_surface that corresponds to the image you have loaded, and the x and y values of the pixel you want to find (the coordinates of the pixel), you next store the pixel information in a pointer to an integer, (the pixel value is stored as an int) and then return it.

Once you have all those values (stored helpfully in a two dimensional array) you simply have to put them into the appropriate place in your drawing code, (which I had finally figured out after several hours of research and bouts of trial and error). I finally got something that looked like this, based on the height map below.


I was skipping and dancing around after I first got this to work. There was no lighting, I was just incrementally increasing the colour from dark to light in each triangle I drew. I then went about getting the lighting code to work, and finally ended up with this:


Success at last! I understand it does kind of obscure the playing area but you get the idea! I have to thank www.videotutorialsrock.com for a lot of information on height maps and techniques on how to create such an effect, I will hopefully be able to move it out of the way of the grid soon too!