This week I made a decision for the Responders Project, and that decision is to continue development on the Unity3D engine for now.

Don't misunderstand, I still intend to switch engines in the future to something more built for the task at hand. However for testing purposes, I figured if I kept the main logic code engine-agnostic I could get away with using Unity.

So what kind of progress have I made on Unity?


Packed & Unpacked file loader

I have updated the file loader to detect wether a file is packed or not, this saves some duplicate code in the future and allows for easy utilization of the file loaders (which I also interfaced, just in case I want to support other games as well.)

The file loader is now a part of the Responders.FileFormat assembly, which is injected into the Unity3D plugins folder upon build.

Currently, using it looks a little like this:

public Mesh LoadFromFile(string fileName)
{
    EmergencyFileLoader fileLoader = new EmergencyFileLoader();
    fileLoader.ReadFromFile(fileName);

    return MeshFromV3O(fileLoader.GetFileContents());
}

And yes you're reading that right, it's currently being used in a functional V3O mesh loader!


Mesh loading and rendering

It took a lot of trial and error but I can proudly say that I've managed to get Emergency 4's models to load in Unity3D!

Whoop whoop, that's the sound of the Police

As you can probably tell the models in Emergency 4 were not made with the highest of definitions in mind, the model was created in 2004 afterall.

To achieve the loading and rendering of this mesh I basically just took Unity3D's Mesh object and started filling in the vertices, triangles and uv arrays. After that, I simply attached the Mesh to the GameObject with a MeshFilter and badabing, badaboom you got yourself a Emergency 4 model in Unity3D!

The code to achieve this currently looks like this, and is pending some cleanup.

private Mesh MeshFromV3O(string v3oData)
{
    Mesh mesh = new Mesh();

    string[] lines = v3oData.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
    List<Vector3> vertices = new List<Vector3>();
    List<int> triangles = new List<int>();
    List<Vector2> uvs = new List<Vector2>();

    foreach (string line in lines)
    {
        string[] parts = line.Split(',');
        
        if (parts[0] == "D")
        {
            // Vertex
            Vector3 vertex = new Vector3(
                ((float)Int32.Parse(parts[1])) / 10000,
                ((float)Int32.Parse(parts[2])) / 10000,
                ((float)Int32.Parse(parts[3])) / 10000
            );

            // UV / Texture coordinate
            Vector2 uvCrd = new Vector2(
                ((float)Int32.Parse(parts[7])) / 1024,
                ((float)Int32.Parse(parts[8])) / 1024 * -1 // inverted
            );

            uvs.Add(uvCrd);
            vertices.Add(vertex);
        }

        if (parts[0] == "P")
        {
            // Polygon
            triangles.Add(Int32.Parse(parts[2]) - 1);
            triangles.Add(Int32.Parse(parts[3]) - 1);
            triangles.Add(Int32.Parse(parts[4]) - 1);
        }
    }

    mesh.vertices = vertices.ToArray();
    mesh.triangles = triangles.ToArray();
    mesh.uv = uvs.ToArray();
    mesh.RecalculateBounds();

    Debug.Log("[EmergencyMeshLoader] loaded " + mesh.vertices.Length + " vertices (" + mesh.triangles.Length + " tris, " + mesh.uv.Length + " uv coords)");

    return mesh;
}

Next steps

The next step is to parse the files that specify the composition of these models in Emergency 4 to come to a full vehicle with wheels, a body and lighting.

I'm excited to see what kind of result this new challenge will bring, but with any luck the next time you see this vehicle it will be with it's flashing blues!

Until next time, with hopefully another exciting update.