WAD2BSP Conversion Sketch


There has been a recent thread on the Quake Developers on the possibility of converting WAD files. Some replies, including mine, stated that we would need a 3D BSP node builder and other tools. I thought again about the issue of WAD conversions, and recognized that I oversaw a ccouple of things in my earlier reply.

Any 2D DOOM BSP builder could create a valid Quake BSP.

This does not mean that it could handle any 3D geometry. Obviously, the well-known restrictions (one floor, one ceiling per point in the xy-plane only) still hold. In addition, automatic conversion of DOOM WAD levels suffers a lot of smaller problems (see texture issues, below). There is something a lot more important to this.

Namely, a separate conversion tool, or a modified 2D BSP Node builder might be done within a few weeks. We would be able to create levels from scratch, albeit with restricted geometry. We would be enabled to use all existing editors for this purpose. DEU and its offspring might be modified to use different thing/entitiy lists, different texture sets, and different texture offset handling. A couple of things will be learned about the pros and cons of the qtest1 BSP file format.

The most important point: the DOOM WAD map description as provided with VERTEXES, LINEDEFS etc. gives as one already agreed upon standard file format which we do not have with qtest1. Thus it will be a very useful intermediate step of creating tools (namely BSP Node builders or standalone conversion tools) that read DOOM WAD maps, but write qtest1 BSP's.

It might well be months until we see 3D scene editors, and for all I know that might be a commercial editor. There might be freely distributable tools for DXF, 3DS, VRML file conversion a lot earlier than a 3D Quake Editor, but you will still need a commercial 3D modeling tool to put those to full use. The GUI of a 3D Modeling tool is a time-consuming task. POVRAY has been around for quite some time, still there are only two or three tools as far as I heard.

DOOM BSP to Quake BSP conversion

Proposal by John Carmack

Quote: "The easiest way to do that is to take the DOOM 2D BSP tree, and just add two more nodes at each leaf -- floor and ceiling." This is obviously an alternative to the conversion I proposed, and might be a bit easier. It takes advantage of the fact that leafs do not represent closed polyhedra - the added leafs have partition planes in xy, at z = floor_height and z = ceiling_height. We will still have to create surfaces from SECTORS and LINEDEFS, and have to split them along the partition planes.

A remark on BSP generation from WADs

Note that while it is possible to create a 3D BSP from a DOOM map using "qbsp", it will possibly be far from optimal. The best way to split a DOOM map is using vertical splits, and avoid horizontal splits. The latter will increase the number of polygon splits and tree leafs. A 3D BSP Node builder might in general benefit from prefering such splits.

A DOOM shareware set of mipmaps

The textures

The DOOM shareware IWAD, that is available as doom-1.8.wad.gz, contains a well known set of textures. These are:

This is a total of 180 textures, that have to be converted to Mipmaps. Restriction: width and height must be 8,16,32,64,128, or 256. Flats are 64x64 already. The wall textures use widths ranging from 8 to 256 already. The texture heights sometimes are 24, 72, 96: a total of five cases in all id textures. In these cases the texture will be repeated to a height of 32 or 128, respectively. No valid WAD will use those on walls higher than the texture height, as in DOOM vertical tiling was always 128.

The conversion details

There has to be a COLORMAP lookup to map the DOOM PLAYPAL colors to their Quake qtest1 equivalents. This will have to be calculated once.

The shareware textures and flats will have to be prepared as pixmaps, using TEXTURE1, the patches, and all flat lumps. In some cases, additional repetition or clamping for heights that are not powers of two have to be done.

The GLUT library function gluBuild2DMipmaps might be used to generate multi-sampled, bilinear interpolated anti-aliased Mipmaps.

A ready to merge Mipmap lump has to be written. Guesstimate: the final MipMaps lump will be about 1.5 MB. A lookup table to assign texture names to indices has to be written. I propose an ASCII file, UNIX line breaks, called TEXTURES, with the following content:

  "wad"   "/usr/games/quake/gfx/doom1tex.wad"
  "0"     "AASTINKY"
  "2"     "BIGDOOR1"
  "3"     "BIGDOOR2"

  "87"    "FLOOR0_1"
  "88"    "FLOOR0_3"
This is the same lump as used by the a BSP file extension mechanism I proposed.

Partly transparent walls

Conversion of two-sided walls with partly transparent textures might be done for Quake: it is possible to use billboard objects (like torches) to stay world-aligned instead of rotating with the xy-projection of the LOS.

In general, walls with a small number of holes, and grates might be done using objects composed of triangles, as those do not need to be polyhedra. There is probably no transparency color index for skin textures. However, walls done as entities might even be shattered and destroyed.

Recycling existing WAD files

There are a couple of problems for automatic conversion of existing WAD files.

Disclaimer: below is the proposal I have not updated for months.


I got some problems with the notation in the UQS. Especially the Slab and Zone stuff seems to got confused. In addition, the DOOM WAD 2D elements (e.g. SEGs) create both edges (Edge3D) and surfaces (Polygon3D). I will more and more use the following conventions:

I appreciate any corrections, comments, or suggestions on this topic. It seems to be a good idea to relate to the well-known DOOM WAD descriptions, and have an easy mapping to the 3D or vertically extended equivalents.

Proposal of a conversion path

Here is a rather sketchy proposal that indicates that we do not need qbsp, light, or vis. There are a lot of different aspects. Let's go through this step by step. Examples are given in a more or less precise pseudo-code. There will be a coupleof more or less stupid mistakes, as long as it is not implemented. I try to separate minimal T test release requirements from P production release requirements.

Attempt at an overall loop

The problem with a separate conversion tool is that it will need a couple of lookups, because there are a lot of references in VERTEXES, LINEDEFS, SIDEDEFS, SECTORS, SSECTORS, SEGS, NODES that could not simply be mapped to the new lokkup/description lumps.

In consequence, it might be a lot easier to modify the output functions of any existing 2D BSP Node builder, as there is a lot more information available during the process.

I have not found the time to sort this out. It occurs that the following tasks might be separable:

  1. Create Plane3D, and lookups,
    from LINEDEFS and SECTORS.
  2. Create Vertex3D and lookups,
  3. Create Edges3D, and lookups,
    from SEGS and SECTORS.
  4. Create Polygon3D (surfaces) and lookups,
    including the Edge3D list.
  5. Create matching 3D BSP from 2D BSP,
    using lookups, NODES, and SSECTORS.
  6. Create Entities from THINGS,
    using BSP 2D or SECTORS info.

Generation of BSP file header

See UQS 2.3. We might exploit the possibility to have zero length records if those are simply omitted.

header.version = 0x17 or 27;  // UQS error, dunno which.
header.entities =  dummy      // Player start needed.
header.planes                 // Needed.
header.miptex  = dummy        // Single color. 
header.vislist = ( 0, 0 );    // None, crawls.
header.nodes                  // Needed.
header.surfaces               // Needed.
header.lightmaps = (0,0);     // Try.
header.slabsplit = dummy;     // Single slab.
header.leaves                 // Needed.
header.lstsurf                // Needed.
header.edges                  // Needed.
header.lstedges               // Needed.
header.slabs = dummy;         // Single slab.

Generation of list of entities

T: Minimal requirements. I took a quick glance. This might be a sample dummy file with one entity.

"angle" "180"
"wad" "./doom1.wad2"
"classname" "worldspawn"
"classname" "info_player_start"
"origin" "324 1156 24"
"angle" "180"
We do need the player start. Note that a converted shareware DOOM WAD file is referenced in current directory - of course, I do not know if this will work anyway. But we do need to take care of PLAYPAL in a production release.
Note that it is necessary to identify the SECTOR the player start is in, to determine the spwaning height (e.g. using the BSP).

P: The idea is to use what works with qtest1 levels, and assign it based on some ASCII list or lookup. A useful production release should assign these to similar THINGS:

"angle" "0"
"origin" "576 752 24"
"classname" "info_player_deathmatch"
"angle" "90"
"origin" "48 1152 0"
"classname" "weapon_supershotgun"
"classname" "item_health"
"origin" "440 808 0"
"spawnflags" "2"
"classname" "item_shells"
"origin" "-116 1160 -144"
I do have some doubts if these are needed:
"classname" "light"
"origin" "220 1308 128"
"angle" "0"
"light" "200"
"classname" "light_flame_large_yellow"
"origin" "494 1582 224"
"light" "200"
"classname" "light_torch_small_walltorch"
"origin" "1142 1322 108"
Finally, I think that semit-automatic conversion should probably ignore these, as 3D buttons and doors work differently.
"targetname" "t1"
"angle" "90"
"origin" "448 1028 16"
"classname" "info_teleport_destination"
"light" "250"
"model" "*3"
"target" "t1"
"classname" "trigger_teleport"
"model" "*4"
"classname" "func_door_secret"
"angle" "180"
"model" "*5"
"classname" "func_button"
"target" "t2"
"model" "*6"
"classname" "func_door"
"angle" "180"
"spawnflags" "1"
"targetname" "t3"
"speed" "175"
"wait" "8"
"model" "*7"
"classname" "func_button"
"target" "t3"
"angle" "-2"
"lip" "4"
"wait" "10"

Generation of List of Planes

This seems to be the easiest task. We have to create a plane for each LINEDEF, and two planes for each SECTOR.

// The idea is that each partition plane contains
// a seg or linedef, each seg is derived from a linedef,
// thus all planes are given by the linedefs.

// The normal is simply a rotation with 90 degree.
// Beware: might have to flip the sign.
Nx =  -(y2-y1);
Ny =     x2-x1;
Nz =         0;

// Normalization to unity length.
Nabs = sqrt( Nx*Nx + Ny*Ny );
Nx /= Nabs;
Ny /= Nabs;

// The distance in 2D is given by the z component
// of the cross product of the a vector within the
// plane (the linedef) and the point. 
dir_x   = x2-x1;      // Direction,
dir_y   = y2-y1;      //  is already in origin.
point_x = -x1;        // Translate point = origin, 
point_y = -y1;        //  with base vector of line.

point_z = dir_z = 0;  // Thus cross_x = cross_y = 0.
crossZ                // is z component of point cross dir
        =  (point_x)*(dir_y) - (point_y)*(dir_x)
        =      (-x1)*(y2-y1) -     (-y1)*(x2-x1);
        =                  x2*y1-x1*y2 
        // Negative means: point on right side of line,
        // as seen in direction.
        // Beware of sign again.

// The type of plane is given by the normal.
if ( abs(Nx)>abs(Ny))
  if ( Nx>0 ) 
     type = 0; // facing towards X
     type = 3; // facing towards -X
else // abs(Ny)>abs(Nx)
  if ( Ny > 0 (
     type = 1; // facing towards Y
     type = 4; // facing towards -Y

// Not handled: firstsurf, numsurf:
// This would be all SEGS created from the
// same LINEDEF. Needs lookups.

// The LineDef->Plane mapping is simple: 
// nth LINEDEF is represented by nth plane.
// The Seg->Plane mapping uses Seg->Linedef.
// Next, we have to handle all the planes
// that contain SECTOR floors/ceilings.
// This is even more easy. We create two
// planes for each SECTOR.
Nx = Ny = 0;
Nz = +1; type = 2;   // Floor, facing towards Z.
Nz = -1; type = 5;   // Ceiling, facing towards -Z.
dist = floor_height/ceiling_height;

// Finally: there usually will be a lot of
// redundant planes: SECTORS use identical heights,
// LINEDEFS are perfectly aligned.
// We have to merge those, and update the lookups
// that assign plane indices to LINDEF indices,
// and SECTOR floor/ceilings.
// Means comparison of normal and distance.


Generation of Mip Textures

T: For first test, use single color textures (trivial). Wether or not we use PLAYPAL or the qtest1 palette, we could create 256 dummy miptex entries.

// Names: "color0" up to "color255".
// Use 8x8 as minimum given by mipmap,  
// smallest is still 1x1.
// In this case it's 64+16+4+1 == 85 bytes raw
// data per mipmap, but we use only 64, plus
// name (16bytes) and 6x4 bytes header info,
// each record thus 84 (not 125) bytes large.
// Base offset is (numtex+1)*4 == 1028 bytes
// Have to replace  color palette in WAD2
// with PLAYPAL in production release.

  fopen( miplump )
  mipheader.numtex = 256;
  for ( int i= 0; i < 256; i++ )
    mipheader.offset[i] = i*84+1028;
  fwrite( mipheader );

  for ( int i= 0; i < 256; i++ )
    miptex.name = "color%d", i;
    miptex.width = 8;
    miptex.height = 8;
    // The offsets from the beginning of miptex,
    // would be 40, 104, 120, 124.
    // We simply reuse the largest.
    offset1 = 40;
    offset2 = 40; 
    offset4 = 40;
    offset8 = 40;
    for ( j = 0; j < 64, j++ )
      miptex.data[j] = i;
  fclose( miplump ); 

P: The issue of textures has a lot of different aspects, and clearly demonstrates that there is no point in writing such a conversion with recycling of old levels in mind. See below.

Basically we should create a single MipTextures lump as the simplest way to generate complete BSP files for possibly thousands of level without creating thousands of copies of 256 Mip textures. The lump with the 256 Mipmaps would be distrbuted once, and a simple tool might add it to any converted WAD file to create a BSP file. The problem, however, is which textures could and should be used.

Generation of List of Vertices
Generation of Edges
Generation of The List of Edges

A general problem with this proposal is that I tend to separate tasks that probably will have to be handled with some interleaving. The description already tries to handle vertices and edges at once.

For each WAD vertex, we create two, three or four with different z given by SECTOR floor/ceiling height. The simplest way is to create 4 vertices3D for each vertex2D. But as there are many single sided linedefs, or such without upper or lower, this will create a lot of bogus vertices that are never used.
All surfaces are created from SEGS. Thus we need all vertices in SEGs, not only those in LINEDEFS. We cannot use VERTEXES directly, as we need the height info, which means SEG->LINEDEF->SIDEDEF->SECTOR.height.
The algorithm needs to take into account the direction field in the SEGS, and the orientation of the edges with respect to newly generated surfaces from UPPER and LOWER. Need to order the edges counter-clockwise.

   // We introduce two arrays:
   Vertex2D[ NumVertexes ];  // contains all VERTEXES.
   Vertex3D[];               // allocates 4 times the space.

   // and we introduce four lookups:
   int  Vertex3D_floor[ NumVertexes ];
   int  Vertex3D_ceil [ NumVertexes ];
   int  Vertex3D_lowerup[ NumVertexes ];
   int  Vertex3D_upperlow[ NumVertexes ];

   // Each entry is -1 if there is no such 3D vertex
   // available.

   // The same has to be done for edges:
   Edge2D[ NumSegs ];  //  contains all SEGS
   Edge3D[];           //  allocates 10 times the space.

   For each SEG
     if ( vertexes[start].not_done )
         if ( seg.linedef.single_sided )
              = seg.linedef.right->sector.floorheight;
              = seg.linedef.right->sector.ceil_height;
            // Determine sidedef
            if ( seg.direction = 0 )
               front = seg.linedef.right;
               back = seg.linedef.left;

            // Determine if upper, lower, middle,
            // based on back/front heights,
            // check for transparent middle etc.


            vertices3D_lowerup[start] = ...;
            vertices3D_upperlow[start] = ...;

       // We have to create 4 edges for each seg,
       // if it is on a single sided LINEDEF.
       edge_floor.start = vertices3D_floor[ start ];
       edge_floor.end   = vertices3D_floor[ end ];
       edge_end.start   = vertices3D_floor[ end ];
       edge_end.end     = vertices3D_ceil[ end ];
       edge_ceil.start  = vertices3D_ceil[ end ];
       edge_ceil.end    = vertices3D_ceil[ start ];
       edge_start.start = vertices3D_ceil[ start ];
       edge_start.end   = vertices3D_floor[ start ];

       // We have to do 2 or 3 surfaces, and 6 or 8
       // edges if there are upper or lower, or both,
       // and middl

Generation of Visibility List

T: For first tests, just make all leaves visible, which is slow. Use a zero length entry in the header, or create unpacked full lists.

P: For a production release, use RMB and other REJECT builder results. In a WAD level, visibility is in 2D. First approximation is simply selecting a cut-off distance, but detailed LineOfSight calculation works as well. The problem is that the reject builder has to be modified to use SSECTORS instead of SECTORS, or SSECTORS will simply inherit the SECTORS reject list. On the other hand, all SSECTOR areas are convex, and the LOS algorithm might exploit this simplification.

Generation of Zone BSP Tree

The really neat thing about this is that we are in fact able to simply 3D enabled copy of the original 2D BSP without any additional processing.
We created a plane from NODES/SEGS, that has to be referenced by planenum. Front/back are equivalent to the NODE/SSECTOR references in the WAD. Bounding box has top be created from both boxes in NODES, plus the z from the max. SSECTOR floor/ceiling height in all childs.

     // The first thing we do is creating a
     // BSP_3D copy of the BSP_2D. The same number
     // of nodes, leafs, and structure.


     // Next thing we do, we map each Leaf_2D to
     // a Leaf_3D, and set up the info correctly.
     code = ? // [-6,-1], purpose unknown.
     // The bounding box is inherited from Node2D,
     // left or right. 
     bound.max_x = Leaf2D->Node2D.left/right_box.max_x;
     bound.min_x =
     bound.max_y =
	   bound.min_y = 

		 // The actual heights are given by
     // seg(any)->lindef->sidedef(direction)->sector.
     bound.min_z = sector->floor;
     bound.max_z = sector->ceil;

     // Leafs2D (SSECTORS) were lists of SEGS.
     // Leafs3D are lists of surfaces.
     // For each SEG, there are one, two, or three
     // surfaces.
		 firstsurf = current_surf;
     numsurf = 0;
     last_seg = Leaf2D.first_sef+Leaf2D.num_segs;
     for ( seg = Leaf2D.first_seg; seg < las_seg; seg++ )
        if ( Surface3D_lower[seg] != -1 )
            add: numsurf++; current_surf++; 
        if ( Surface_3D_middle[seg] != -1 )
        if ( Surface_3D_upper[seg] != -1 )
     zeros = 0,0,0
     zero = 0
     flag = -1;
     // Create visibility list for each Leaf3D:
     // Simple test: use one, set to size 0, will
     // crawl but work.

     // The vislist's number is simply the Leaf number.
     vislist = Numer(Leaf2D)
		 // Production release: Leaf3D gets REJECT
     // (no special effects) bits, which means
     // Leaf2D inherits from parent Sector2D.
     // We might want to have REJECT builder
     // working with Leaf2D (SSECTORS) later on.
     NumLeafs = NumSSectors;

     unsigned char vislist[ NumLeafs/8+1 ];
     vislist vislump[NumLeafs];

     // Inherits Reject[SSector->Sector];

		 // Next we do, we traverse the nodes. In each
     // Node3D, we have to identify the plane.
     // IIRC the partition lines are just copies
		 // of SEGs used. Thus we should be able to
     // identify a matching SEG, and the LINEDEF,
     // and use the LINDEFs number to find the Plane3D.
     planenum = ....

     // Front and back are hopefully just right and
     // left. Encoding of Node3D vs. Leaf3D childs
     // is identical to Node2D.
     // Beware of bit inversion in indices.
     front = ...
     back = ...

     // The bounding boxes is just the enclosing box
     // of the Node2D.
     box.min_y = min( node2d.left_box.min_y,
                      node2d.right_box.miny );

     // We might use the heights of the children nodes,
     // or just a static  max/min height over level
     // for first tests.
     box.min_z = min( child3d_left.box.min_z,
                      child3d_right.box.min_z );

Generation of Light Maps

T: Not done. Use -1 to flag that no lightmap is within the surfaces, and have a zero length lightmap in the header.

P: I do not know the minimal requirements for valid lightmaps. We might need 16x16 mipmaps for a 1x1 lightmap, or it doesn't matter.
However, we have 2D (and 3D) BSP builders, we do not have any radiosity tools/sources (except HELIOS) available. Once a conversion is working, we would have the opportunity to test out such tools and algorithms.

Generation of Slab BSP Tree

T: The UQS state that a level might be contained in a single slab. I do not know if there needs to be a BSP Slab Tree (has anybody set the header entry to zero length), if it had to be a convex hull if there is only a single slab, or if a boundig box were sufficient. If we do need a detailed Slab BSP Tree in any case, this will take some time.

P: In the long run, the whole conversion approach might be beneficial in this regard, as it would allow for writing a separate Slab BSP builder to try with differently sized and shaped DOOM WADs without the need to create an editor, a Zone BSP builder etc.

Generation of Surfaces
Generation of the List of Surfaces

We created a plane from SEGS/LINEDEFS. That has to be referenced by planenum. The side flag has to be chosen accordingly. Edges have to be referenced. In the List of Surfaces, sorting by leafs has to be taken into account. In rthe array of surfaces, the same is true for the references by the planes.

It is posisble a mistake to discuss this seperated from the Vertex3D and Edge3D generation. In principle we have to create a surface for each upper, lower, and middle texture of any SEG that has to be rendered. Thus we have to use SEGS, and LINEDEFS and SECTORS again for obtaining height (z) information.
The following sketch leaves out virtually all problems of resolving references. It is futile to attempt to provide more details without actually coding the thing.

     // Each SEG creates one, 2 or 3 surfaces.
     // For the edges, we need lookups that assign
     // a first edge (always lower, in xy plane)
     // to each SEG number.
     planenum = Number of seg.lindedef;
     side  = seg.direction (right or left side)

     // For tests chosen at random.
     texnum  = random%256;

     // Ignored for tests.
     // Might be derived from pegged.
     sofs = 0;
     tofs = 0;

     // Not used in DOOM WAD.
     flips = 0;

     firstedge =  Edge3D_1st_upper[ Number of seg ];
                // or 1st_lower, or 1st_middle, depending

     numedge = 4;

     // The base light level for the surfaces is the SECTOR
     // lighting level. Note that we know might have 256
     // instead of 32 lighting levels effectively, I don't
     // know.
     light = seg.linedef.sidedef.sector.light;
     // We do not use a light map.
     lightmap = -1; 

     unknown0 = 0xFF;
     unknown1 = 0xFFFF;

Now here's the part that's probably the most difficult one. We have to create surfaces for each floor and ceiling of each SEG. The problem is that the edges are not necessarily ordered in the SEGs, neither clock- nor counterclockwise. Moreover, not all edges are available - all the parts of partition lines are missing completely.

The best solution will probably be creating polygons from SECTOR and LINEDEF data. Next, those polygons are split using the partition lines (extended to planes). The child polygons have to be assigned to the right/left subtree, and the procedure has to continue until a leaf is reached. This means that there will be an unknown number of additional edges created from the partition lines.

This is precisely the reason I am thinking a modified BSP 2D Node builder could be done more easily, compared to a separate conversion tool.

Texture Issues

Practical Issues

There is no problem in creating Mipmaps from a given texture. In the free GLUT to OpenGL there is a function gluBuild2DMipmaps that will be perfectly sufficient, and filtering is not too difficult to do anyway.

WAD conversion, though, faces a couple of problems. In no particular order, these are:

The shareware WAD has 163 wall textures, and 54 flats plus the unused F_SKY1. That's a total of 217 Mipmaps. DOOM registered (including the shareware lumps) featured a total of 106 flats and 285 textures. The limitation to 256 Mipmaps rules out creating a single registered reference lump.
Note that it is possible to pack several small pixmaps within one Mipmap, using texture offsets t_ofs and s_ofs in the surfaces, as long as those pixmaps are not supposed to tile.
In addition, one might omit the switch textures, as they might not be of much use with Quake. There are different shades of identical textures as well, which might easily be omitted considering the new lighting maps

DOOM commercial featured 427 textures, and 146 flats. Here the problems are worse.

Legal Issues

There is a serious problem here: one cannot distribute converted shareware, registered or commercial DOOM textures. It is more complicated to introduce any tools to do the conversion on the fly.

There are different solutions, with rapidly decreasing probability.

A thought

Despite the fact that automatic conversion will not create useful WADs, we could expect a lot of high quality PWAD's to be reworked for Quake.

A set of converted and mipmapped textures from DOOM registered and commercial could be part of the registered/commercial Quake CD (or as a seperately sold DOOM3 CD). This would provide a well-defined and legal reference for all WAD conversion attempts, could be done at virtually no cost, and would even not decrease revenue from DOOM (you still have to buy it to get the sprites and the levels). Because of the necessary changes (tiling width), such a texture collection will not be useful for DOOM PWAD creation. A lot of sprite graphics (medikits, torches, explosions) could included as well. In addition, monster sprite graphics might be useful for creating Alias model skins.

Misc. conversion thoughts

Handling the following tasks with a conversion tool will probably make no sense:


There is no point in creating a fully automatic conversion tool. There is no point in recycling approx. 3500 DOOM WAD files. However, there are benefits more important.

As soon as conversion is possible, the WAD map data will be our first level description standard file format. We do not have a CSG/3D description, and probably will never agree on one. Using WADs, we would be able to create simple maps for qtest1 in preparation of more useful tools. We could even test 3D BSP builders with WAD levels, and compare results.

Modified DOOM Editors might offer different texture handling, and different things/entities lists, and it would be possible to create DOOM-style levels with restricted geometry for Quake within a few weeks, instead of many months. The major advantage is, as has been stated before by others, that we will be enabled to use DEU, WARM, RMB and other existing tools for test purposes as well as map editing.

On the way to a 3D editor, and a commonly agreed file format, there are quite a few possible intermediate workarounds: a modified DEU, for editing multiple PWAD's (each one storey of a building) and simple additional flags to indicate which sectors should be shared by both storeys. This would give us a migration path.

home qdev qdev dread rsc qdev doom license web
home dEr95 r3D dread netrsc quake doom legal web
Author: B., email to bernd@nero.uni-bonn.de, with public PGP key
Copyright (©) 1995, 1996 by author. All rights reserved.
Source: $Id: proposal.html,v 1.2 1996/06/16 23:56:53 b1 Exp $