måndag 15 augusti 2011

When to forward declare?

Ok. I have just realized that the structure of my source code files isnt very good at all. Ok, I didnt just realize it, I have known it for a while. But I havent bothered to fix it until now. First thing I'm doing is making sure that each class is contained in its own header file. Next up I'm going to separate my project into logical parts, which will serve as namespaces.
Im going to fix the directory structure aswell,to reflect the namespaces in the project.

My concern is; When should one forward declare a type?
Take the vtx_render.h (soon to be renamed to vtx_rendermanager.h!) for instance, which contains the following:

#ifndef VTX_RENDER_H
#define VTX_RENDER_H

// ...
#include <vortex/vtx_window.h>


class RenderManager : VortexBase
{
public:
        RenderManager(Root&);
        void init(RenderCreationParams &params, WindowCreationParams &windowParams);
        void destroy(void);
        RenderAPI *getRenderObject(void);
private:
        void createWindow(WindowCreationParams &params);
        NativeWindow *window;
        bool manageWindow;
        RenderAPI *render;
};


#endif

Notice that WindowCreationParams used as input parameter to the init and createWindow methods. The class WindowCreationParams is defined in vtx_window.h

Since our limited use of WindowCreationParams, we do not need the entire definition of the class and so the include of vtx_window isn't really necessary. I can just forward declare WindowCreationParams:

#ifndef VTX_RENDER_H
#define VTX_RENDER_H

// ...
class WindowCreationParams;


class RenderManager : VortexBase
{
public:
        RenderManager(Root&);
        void init(RenderCreationParams &params, WindowCreationParams &windowParams);
        void destroy(void);
        RenderAPI *getRenderObject(void);
private:
        void createWindow(WindowCreationParams &params);
        NativeWindow *window;
        bool manageWindow;
        RenderAPI *render;
};


#endif

The pros for this include:
  • Improved compilation time.
  • Reduces risk of cyclic dependency.
  • ... possibly something else I'm not thinking about.
The cons:
  •  If the class being forward declared is removed or renamed, the header using the forward declaration will  not be affected, instead the error will not show until in the source files including this header.
  • Semi-related to the above point; having to keep all forward declarations up to date concerning class name/containing namespace.
  •  Template classes can not be forward declared (?) This is not really an issue per se, just a restriction (that is easy to work around!).
  •  ... possibly something else I'm not thinking about ;)
I know no one is reading this, but I would still appreciate your input!

(Edit: I forgot to say, I intend to use forward declarations whenever possible, unless I find a good reason not to!)

lördag 13 augusti 2011

SIMD Vector normalization.

I've begun to work on one of the Camera classes in the engine, and when thinking about how to create my view matrices I found that I do not yet have any methods for normalizing my 3D vectors. Normalizing a vector is just about finding the length of the vector and then dividing each element of the vector by it:

Vnorm = V / |V|

Now I figured I'd do this with SIMD because I need all the speed I can get (but of course, optimizations are not top priority this early on!)
Here's what I came up with

void Vector3::normalize(void)
{
    // Must pad with a trailing 0, to store in 128-bit register
    ALIGNED_16 platform::F32_t vector[] = {this->x, this->y, this->z, 0};
    __m128 simdvector;
    __m128 result;
    simdvector = _mm_load_ps(vector);
    
    // (X^2, Y^2, Z^2, 0^2)
    result = _mm_mul_ps(simdvector, simdvector);

    // Add all elements together, giving us (X^2 + Y^2 + Z^2 + 0^2)
    result = _mm_hadd_ps(result, result);
    result = _mm_hadd_ps(result, result);
    
    // Calculate square root, giving us sqrt(X^2 + Y^2 + Z^2 + 0^2)
    result = _mm_sqrt_ps(result);

    // Calculate reciprocal, giving us 1 / sqrt(X^2 + Y^2 + Z^2 + 0^2)
    result = _mm_rcp_ps(result);

    // Finally, multiply the result with our original vector.
    simdvector = _mm_mul_ps(simdvector, result);

    _mm_store_ps(vector, simdvector);

    this->x = vector[0];
    this->y = vector[1];
    this->z = vector[2];
}

What I'm worried about though is that I might be loosing precision when using floats to calculate the normalized vector. For instance, XNA uses doubles for the intermediate calculations, but stores the result as a float. I tried normalizing the same vector in my engine and in XNA, and noticed slightly varying results. Nothing big, but by the 4th or 5th decimal, the normalized vectors would differ.

Does anyone have any input on this? Can I keep it as is? Or should I use two __m128 registers storing two 64-bit values each (instead of one __m128 storing 4x 32 bit values as I currently do). This would double the number of intrinsics in my code, but give me better precision.

(Thanks Andrew for helping me with the subscript formatting!)

onsdag 10 augusti 2011

Declaration does not declare anything.

This was new to me.
I had just set up Fedora (virtual machine) to use for linux development on my new computer. I checked out my source code through svn and tried to build it and the above warning shows up. Whats more, its pointing to one of the typedefs I wrote waaay back, and has compiled fine with g++ / msvc 2010 before. In fact, it still compiled well in msvc, the only one having the problem is g++.

The offending line of code was this:

vtx_atomic.h
typedef float F32;

And this in turn caused another problem!
I reference this F32 declaration from many places in my code, but there is one specific location where I use F32 as a template argument for a class, and thats where it freaked out.
The code looks like the following:

vtx_vbuffer.h
struct VertexPosNormTex
{
    core::Vector3 position;
    core::Vector3 normal;
    core::Vector2<platform::F32> texCoord;
};

It resulted in the error:
../include/vortex/vtx_vbuffer.h:11:31: error: template argument 1 is invalid

I renamed the typedef and all warnings and errors went away. Is F32 conflicting with something? If it is, how come it didn't do that earlier?


måndag 8 augusti 2011

VACP

Part of my offline processing tools for the engine is vacp. Awkward abbreviation, I know. It stands for Vortex Asset Conditioning Pipeline. It's job is to process content (aka assets) to be consumed by the engine, so that they need little to no further processing at runtime by the engine.
When processed by vacp, each asset is first exported using a particular content exporter, and the output from this stage is fed to the content compiler, which in turn produces the engine-ready file.
When vacp is first invoked, it first registers the exporters and compilers has available by scanning libraries in a predefined plugin folder. This enables a developer to, for example, write a PNG exporter to allow the use of PNGs as textures in the engine, or write their own implementation of a content compiler more suitable for their needs.

Right now, I've just semi-finished a BMP exporter and a DDS (DirectDraw Surface) compiler. This means that bitmaps can be fed into vacp, and it will output a dds file (provided that the asset in question is set up to use this exporter and compiler, that is)... its pretty neat, but it is also the only thing vacp can do at the moment :) I'll post more on that subject tomorrow!

First post!

So this is my new "blog" (more like project diary) where I'll be making posts about my progress in creating a game engine, or atleast something close to it ;).

The project is open source and hosted on Google Code and is split up into two repositories. The first one contains the engine and can be found here. The second one contains a set of tools that goes under the name of Maelstrom, which will be used to develop games for the engine. It can be found here.


As stated on the Vortex engine repository main page:
The main goal with this project is not to create something that is state-of-the-art or superior to any other free open-source engine out there. The goal is just to create a fully functional game engine from the ground up, and learn alot from the process. 
 
I know that people don't read blogs like these, but I hope I can attract someones interest!