Quake3Map.png

In this Tutorial you will learn:
  • How to load a Quake 3 map into the engine,
  • How to create a SceneNode for optimizing the speed of rendering
  • How to create a user controlled camera.

Please note that you should know the basics of the engine before starting this tutorial. Just take a short look at the first tutorial, if you haven't done this yet:
Tutorial 1 – Hello World!

Getting Started

See Tutorial 1 for detailed instructions for these steps.
  1. Create a new Console Application project in Visual C# named Tutorial2.
  2. Add a reference to Irrlicht.NET.
  3. Add Irrlicht.dll and IrrlichtW.dll to the project.

Coding

Open Program.cs and it should look something like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Tutorial2
{
    class Program
    {
        static void Main(string[] args)
        {
        }
    }
}

Now you can add the Irrlicht.Net namespaces:

using Irrlicht.Net;
using Irrlicht.Net.Core;
using Irrlicht.Net.GUI;
using Irrlicht.Net.IO;
using Irrlicht.Net.Scene;
using Irrlicht.Net.Video;

Like in the HelloWorld example, we create an IrrlichtDevice with new Device(). The difference now is that we ask the user to select which video driver to use. The Software device might be too slow to draw a huge Quake 3 map, but just for the fun of it, we make this decision possible, too.

            // ask user for driver
            DriverTypes driverType = DriverChoice.FromConsole();

            if (driverType == DriverTypes.Count)
            {
                // Failed getting driver type.
                return 1;
            }            

            // create device and exit if creation failed
            Device device = new Device(driverType, new Dimension2D(640, 480), false);

            if (device == null)
            {
                // could not create selected driver.
                return 1;
            }

            string mediaPath = "../../../../../media/";

            // Get a pointer to the video driver and the SceneManager so that we do not
            // always have to call Device.VideoDriver and Device.SceneManager. 
            VideoDriver driver = device.VideoDriver;
            SceneManager scene = device.SceneManager;

To display the Quake 3 map, we first need to load it. Quake 3 maps are packed into .pk3 files which are nothing else than .zip files. So we add the .pk3 file to our Device.FileSystem. After it was added, we are able to read from the files in that archive as if they are directly stored on the disk.

            bool result = device.FileSystem.AddZipFileArchive(mediaPath + "map-20kdm2.pk3");

Now we can load the mesh by calling Scene.GetMesh(). We get a pointer returned to an AnimatedMesh. As you might know, Quake 3 maps are not really animated, they are only a huge chunk of static geometry with some materials attached. Hence the AnimatedMesh consists of only one frame, so we get the "first frame" of the "animation", which is our quake level and create an Octree scene node with it, using Scene.AddOctree(). The Octree optimizes the scene a little bit, trying to draw only geometry which is currently visible. An alternative to the Octree would be a Scene.MeshSceneNode, which would always draw the complete geometry of the mesh, without optimization. Try it: Use Scene.AddMeshSceneNode() instead of AddOctree() and compare the primitives drawn by the video driver. (There is a Video.GetPrimitiveCountDrawn() method in the VideoDriver class). Note that this optimization with the Octree is only useful when drawing huge meshes consisting of lots of geometry.

            AnimatedMesh mesh = scene.GetMesh("20kdm2.bsp");        
            SceneNode node = null;

            if (mesh != null)
            {
                node = scene.AddOctree(mesh, 1024);
            }
Because the level was not modelled around the origin (0,0,0), we translate the whole level a little bit. This is done on SceneNode level using the methods Node.Position (in this case), Node.Rotation, and Node.Scale.

            if (node != null)
            {
                node.Position =  new Vector3D(-1300,-144,-1249);
            }

Now we only need a camera to look at the Quake 3 map. We want to create a user controlled camera. There are some cameras available in the Irrlicht engine. For example the MayaCamera which can be controlled like the camera in Maya: Rotate with left mouse button pressed, Zoom with both buttons pressed, translate with right mouse button pressed. This could be created with Scene.AddCameraSceneNodeMaya(). But for this example, we want to create a camera which behaves like the ones in first person shooter games (FPS) and hence use Scene.AddCameraSceneNodeFPS().

            scene.AddCameraSceneNodeFPS();
The mouse cursor needs not be visible, so we hide it via the Device.CursorControl.

            device.CursorControl.Visible = false;
We have done everything, so lets draw it. We also write the current frames per second and the primitives drawn into the caption of the window. The test for device.IsWindowActive is optional, but prevents the engine to grab the mouse cursor after task switching when other programs are active. The call to Device.Yield() will avoid the busy loop to eat up all CPU cycles when the window is not active.

            int lastFPS = -1;
        
            while(device.Run())
            {
                if (device.IsWindowActive)
                {                        
                    driver.BeginScene(true, true, new Color(255,200,200,200));                        
                    scene.DrawAll();                        
                    driver.EndScene();
                        
                    int fps = driver.FPS;
                        
                    if (lastFPS != fps)
                    {
                        string str = "Irrlicht Engine - Quake 3 Map example [" +
                            driver.Name + "] FPS:" +  fps;
                        device.WindowCaption = str;                        
                        lastFPS = fps;
                    }
                }
                else
                {                 
                    device.Yield();
                }
            }
In the end, delete the Irrlicht device.

            device.Dispose();
            return 0;
        }

Last edited Jul 28, 2011 at 4:25 AM by VillageIdiot, version 4

Comments

epicus Nov 3, 2011 at 12:39 AM 
Can you fix it please?

dad72 Sep 16, 2011 at 10:21 PM 
Hello,

Small bug:
Device.FileSystem does not exist
driver.FPS does not exist
device.CursorControl.Visible does not exist
driver.Name does not exist
And return does not work in one functions of void type
And Or find files 20kdm2.bsp and map-20kdm2.pk3. You could put a link towards that this.

Thank you very much