Level Editing by (27 September 1999) | Return to The Archives

Introduction

Up until about six months ago, my biggest deterrent to writing 3D engines was the lack of test data. For example, once I had gotten my portal engine working with 2 cells and 2 portals working, I wanted to test the engine with a larger data set. I spent about four hours constructing (by hand) a level with around 15 cells and 30 portals. Once that was done I decided I REALLY needed to write a level editor. I started doing that, but soon became frustrated at the complexity of writing a good editor that was easy to use. So I went looking for some shareware or freeware editor capable of outputting cells and portals. Nothing I found worked the way I wanted.
My thought then was to use a quake editor to make a level, extract the polygons from the BSP, and then write a program to create cells and portals out of the set of polygons. This proved to be unnecessary since as a result of running qbsp.exe on a map file, I found a file with all the portals between leaves of the BSP-Tree was generated. Leaves of the BSP are convex by nature, so I had my set of cells and portals! Aw,Yeah. This worked well and I was able to make large data sets to test my engine. The only drawback was WAY to many polygons and non-optimal cell configurations, due to the bsp-ing.
Since my current engine is neither portal nor BSP, again I ran into the problem of needing test data. Again I looked to a quake editor, but instead of using the .bsp files, I used the .map files. The only problem was that map files are only used by qbsp.exe and other quake engine utilities. So I wrote a program to convert map files into just vertices and polygons.
So if you’re too lazy to write an editor like I am, I present a way to modify Worldcraft to be your custom editor.
The first thing you need is The Forge (http://www.planetquake.com/worldcraft/) - Everything you need is here, including all software downloads and tutorials that I’m going to talk about.

Downloading Worldcraft

Go to the Forge and select the Half-Life editing resource center. From there find the link to download Worldcraft 2.1. It’s easy. I promise. Once you’ve downloaded all of its 8.4 Megs of greatness, install it.

Using Textures with Worldcraft

To get the 3D previews of what you’re building and to get output in the map files with correct texture names, you need to put your textures in a format that Worldcraft can use. This format is the Half-Life WAD3 format. Go once again the Forge main page and select The Forge. From there go to the Files section. Select Editing Utilities and then scroll down until you find Wally. This program will make texture packages for most games that use the quake engine, including Half-Life. It’s really easy to use. Just take your textures and put them in a Half-Life texture wad. The Wally documentation explains it all.

Configuring Worldcraft

The first time Worldcraft starts, you should get a message that says no texture packages have been selected. It will then bring up the setup dialog. If it doesn’t bring up the setup dialog, you can do it manually by selecting Tools->Options. Under the ‘Textures’ tab, add the texture wad that you made using Wally.
For the ‘General’, ‘2D Views’, and ‘3D Views’ you can setup whatever way you like.
You need to make some changes under the ‘Game Configuration’ tab. Since it has been a while since I installed my copy of Worldcraft I don’t remember if the Half-Life game configuration is preinstalled, but in any case you can either remove it, modify it, or leave it alone and make a new game configuration.
What you need to do is select the game configuration file. These files have an extension of .fgd. You’ll probably want to make your own. What this file does is specify all the types of solid and point entities that you can put into your level. I personally use Worldcraft only as a model editor for models that don’t have any entities in them, so I don’t bother with the .fgd to often. Information on editing .fgd files can be found at the Forge, under the ‘Add-ons’ section.
Unless you’re going to be using external programs that process the map files, you can ignore the ‘Build Programs’ tab. Otherwise, you just need to substitute the paths and filenames of the programs you use to do builds.

Good To Go

At this point, you should be able the edit levels with your textures and entities within Worldcraft. If you have lots of problems getting Worldcraft setup, email me (hodorl@rpi.edu) with the problem and I’ll see if there is something I can do.
If you need help using Worldcraft or you’ve never used it before, just go to the Forge or the Half-Life editing resource center. They are the most comprehensive sites for info on editing using Worldcraft. I figure most of you have tried making a quake level, so you probably know the basics.
Once you’ve made your level there are two options on the file menu you’ll want to use: Export DXF and Export MAP. I’ve never used the Export DXF, but it’s there so it probably works. If you know DXF and like it go ahead and use it. If you export a MAP file, the output isn’t exactly friendly, so I’ve writing a little program to convert a MAP file to a list of vertices and faces called MapCon.
Before you download it though, you must know about a few restrictions on the program. This is software that I wrote to be useful for me, and if it doesn’t work for you, sorry, too bad. There is a limit of 10000 vertices and 10000 faces. If you have levels bigger than this then perhaps if you email me, I can change the program to handle more. The second thing is that the program does NOT handle entities. If you place any entities in the level, the program will probably crash terribly with either general protection faults or it will just hang. I know, bad coding to do this, please don’t yell about it.
With that said, you can download MapCon, here (28k).
The output format is described in the readme.txt that is included with MapCon.
Because there are limitations, I’m going to show how it works, so that you can write your own. =)
On PlanetQuake’s quake reference (http://www.planetquake.com/qref/bsps/index.html) you can get the document that describes the format of the map files. Basically it’s lists of planes that define convex solids. Here’s the algorithm I use for converting the list into a list of polygons. This particular code hasn’t been tested, as it’s an adaptation of the code I’m using. Lots more is going on in my code in terms of face properties and vertex sharing, so I apologize if I screwed something up. If you notice anything, please contact me and let me know.

    #define MAX_BOUNDS 16384    //this is the abs(max point in data set)

    //Planes is an array of planes that define a convex area in space
    //which has been loaded from the map file
    //NumPlanes is the number of planes in the list

    CFace* FacesFromPlaneList(CPlane *Planes, int NumPlanes)
    {
        //you need at least 4 planes to make a solid
        if(NumPlanes < 4)
            return 0;

        //allocate some memory for the new faces
        CFace *NewFaces = new CFace[NumPlanes];

        //need to make faces that lie on the planes of the solid that
        //extend to the bounds of the data set.
        for(int i = 0; i < NumPlanes; i++)
        {
            //the vertex count for each inital face will be 4
            NewFaces[i].VertexCount = 4;

            //check to see if the plane is x-axis oriented
            if(abs(Planes[i].x) >= abs(Planes[i].y) && abs(Planes[i].x) >= abs(Planes[i].z))
            {
                //set the bounds of the polygon, using y and z axis
                NewFaces[i].Vertex[0].Set(0, -MAX_BOUNDS, -MAX_BOUNDS);
                NewFaces[i].Vertex[1].Set(0, -MAX_BOUNDS, MAX_BOUNDS);
                NewFaces[i].Vertex[2].Set(0, MAX_BOUNDS, MAX_BOUNDS);
                NewFaces[i].Vertex[3].Set(0, MAX_BOUNDS, -MAX_BOUNDS);

                //calculate the x value of each vertex on the plane
                for(int j = 0; j < 4; j++)
                {
                    NewFaces[i].Vertex[j].x = Planes[i].d -
                        Planes[i].z * NewFaces[i].Vertex[j].z -
                        Planes[i].y * NewFaces[i].Vertex[j].y ) /
                        Planes[i].x;
                }
            }
            //check to see if the plane is y-axis oriented
            else if(abs(Planes[i].y) >= abs(Planes[i].x) && abs(Planes[i].y) >= abs(Planes[i].z))
            {
                //set the bounds of the polygon using the x and z axis
                NewFaces[i].Vertex[0].Set(-MAX_BOUNDS, 0, -MAX_BOUNDS);
                NewFaces[i].Vertex[1].Set(-MAX_BOUNDS, 0, MAX_BOUNDS);
                NewFaces[i].Vertex[2].Set(MAX_BOUNDS, 0, MAX_BOUNDS);
                NewFaces[i].Vertex[3].Set(MAX_BOUNDS, 0, -MAX_BOUNDS);

                //calculate the y value of each vertex on the plane
                for(int j = 0; j < 4; j++)
                {
                    NewFaces[i].Vertex[j].y = ( Planes[i].d -
                        Planes[i].z * NewFaces[i].Vertex[j].z -
                        Planes[i].x * NewFaces[i].Vertex[j].x ) /
                        Planes[i].y;
                }
            }
            //plane must be z-axis oriented
            else
            {
                //set the bounds of the polygon using the x and y axis
                NewFaces[i].Vertex[0].Set(-MAX_BOUNDS, -MAX_BOUNDS, 0);
                NewFaces[i].Vertex[1].Set(-MAX_BOUNDS, MAX_BOUNDS, 0);
                NewFaces[i].Vertex[2].Set(MAX_BOUNDS, MAX_BOUNDS, 0);
                NewFaces[i].Vertex[3].Set(MAX_BOUNDS, -MAX_BOUNDS, 0);

                //calculate the z of each vertex on the plane
                for(int j = 0; j < 4; j++)
                {
                    NewFaces[i].Vertex[i].z = ( Planes[i].d -
                        Planes[i].y * NewFaces[i].Vertex[j].y -
                        Planes[i].x * NewFaces[i].Vertex[j].x ) /
                        Planes[i].z;
                }
            }
        }

        //now for each face, we clip it against the planes of all the other faces
        //since it is convex, after all the clipping the face will be the original
        //as seen in the editor
        //NOTE: Depending on how you calculated your plane equations, you may need
        //to flip the plane before you clip the faces, since the wrong side of the
        //face will be clipped. And you will end up with faces with no vertices.
        for(i = 0; i < NumPlanes; i++)
            for(int j = 0; j < NumPlanes; j++)
                 if(i != j)
                     ClipFaceWithPlane(NewFaces[i], Planes[j]);

        return NewFaces;
    }

Conclusion

That’s about it. I hope this helps some of you so that you don’t need to waste time a lot of time creating test data so you can get straight to 3D coding. =) If anyone wants to work directly with Quake 1 BSP files, I have a document with the specifications of the BSP. I don’t remember where I got it and I couldn’t find the url. If you want it email me and I can hook you up. Luke Hodorowicz (hodorl@rpi.edu)
Until next time...

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.