ZDBSP is a stand-alone version of ZDoom's internal node builder. This node builder was written with two design goals in mind:
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You can also find a copy of the license as the file COPYING in the source distribution.
First, copy zdbsp.exe to your WadAuthor directory. Then start WadAuthor and choose "Options..." from its Tools menu. Select the "Files" tab and choose "External" for Node Building. This activates the Command text box so that you can type text into it. Copy and paste any of the following into it based on what you want to do.
Create a map that can be played with Doom or any source port:
zdbsp -R -m$_Mapname $_Wadfile -o$_Wadfile
Create a map that will only be played with ZDoom. This will be ZDoom-only because it creates a zero-length REJECT lump. ZDoom is smart enough to know that a zero-length REJECT lump is the same thing as a REJECT lump filled with zeros, so you can save space:
zdbsp -r -m$_Mapname $_Wadfile -o$_Wadfile
Create a map with both regular and GL nodes so that ZDoomGL does not need to build GL nodes:
zdbsp -rg -m$_Mapname $_Wadfile -o$_Wadfile
ZDBSP supports several command line options to affect its behavior. If you forget what they are, you can view a quick summary of them by running ZDBSP without any options. They are also listed below in more detail than the listing ZDBSP provides. Note that these options are case-sensitive, so -r is not the same thing as -R. You can use either the long form of an option or the short form depending on your preference.
One of ZDBSP's most important features is that it tries very hard to avoid polyobject bleeding. To make this feature work, however, you must design your maps properly. You do this be ensuring that your polyobjects are always shown inside a convex sector. This is referring to the area where the polyobjects appear in the game, not where they appear in an editor. If you do not know what convex means, think of triangles, squares and circles. They are all convex. If you have a sector shaped like the letter C, that is not convex.
Ironically, an example of what not to do is in Hexen's MAP01. The polyobject doors at the very start of that map do not appear in a convex area. ZDBSP has been tuned so that they will display properly with the default options, but you should not count on this for your own maps.
If ZDBSP has to split a linedef around a polyobject's display area, it will print a message indicating where this happened so that you can inspect the area and fix it. For example, when you use ZDBSP on hexen.wad, it outputs these warnings for MAP01:
Split seg 929 (-1176,1312)-(-1088,1312) of sector 265 on line 572 Split seg 931 (-1088,1312)-(-1000,1312) of sector 265 on line 573
The important pieces of information here are the coordinates of the segs that were split and the lines those segs were made from. In this case, both lines 572 and 573 were split. Because they surround a polyobject's display area, ideally they should not be split, so you need to look at the map in an editor to determine what made them split. This happens because the area is not convex, so you need to look for a line in the same "loop" that, if you made it longer, could cross the line that was split. In this example, lines 575 and 579 are responsible for splitting line 572, and lines 576 and 578 are responsible for splitting line 573. You can fix the error by reworking the area so that it is convex, either by moving lines 575, 579, 576, and 578, or by adding additional lines to separate each half into four convex pieces.
Below are some illustrations. The areas where the two polyobjects appear have been highlighted.
This first image shows the area as it appears in hexen.wad, unmodified. Note that neither side is convex, so ZDBSP will need to split each side into two subsectors. The extra subsectors have been highlighted in a brighter color to illustrate how ZDBSP splits them.
In the next image, the lines have been moved to make each side convex.
In the final image, new two-sided lines have been added to make each polyobject's display area rectangular. Unlike the line-moving method above, this does not alter the area's appearance. Notice that this looks a lot like the way ZDBSP split them in the first image. The difference is that by adding the extra lines yourself, you have control over how the split is done and ZDBSP does not need to guess about the best way to make the area convex.
Unfortunately, if you use WadAuthor, ZDBSP's output window will not normally appear long enough for you to actually read it. You can get around this by adding the -v option to the zdbsp command line that WadAuthor uses (see the Using ZDBSP with WadAuthor section). Then its output will stay around until you close the ZDBSP viewer.
The following information describes the format used to store compressed nodes. If you are just a regular user, you can skip this section.
Compressed nodes contain all the same information as regular nodes but are stored in a single lump and compressed as a zlib data stream. They also support more than 65535 segs and vertices by storing them using four bytes instead of two.
The first four bytes of the compressed nodes are a four-character (uncompressed) signature. This can be either 'ZNOD' for regular nodes or 'ZGLN' for GL nodes. Following the signature is the zlib data stream. For a description of its format, see the zlib documentation. When you decompress it, the following information is obtained in this order:
The following sections use these types:
All multi-byte numbers are stored with their least significant byte first (i.e. little-endian).
DWORD | OrgVerts | Number of vertices used from the VERTEXES lump |
DWORD | NewVerts | Number of additional vertices that follow |
Repeat NewVerts times: | ||
FIXED | X | X-Coordinate |
FIXED | Y | Y-Coordinate |
These are all the additional vertices that the segs use. Unlike normal nodes, extra vertices are not added to the VERTEXES lump. When determining which vertex v a seg uses, if v < OrgVerts, then v is a vertex in the VERTEXES lump. Otherwise, when v >= OrgVerts, v - OrgVerts is the index of a vertex stored here.
Like version 2 GL nodes, the vertices stored here are represented as 16.16 fixed point numbers in order to maintain the full precision of the Doom engine.
DWORD | NumSubsectors | Number of subsectors |
Repeat NumSubsectors times: | ||
DWORD | NumSegs | Number of segs for this subsector |
Unlike normal nodes, the first seg in each subsector is not stored. This can be inferred by the ordering of the subsectors. The first subsector always starts at seg 0, and each following subsector begins with the seg immediately after the previous subsector's last seg.
The specific layout for this section depends on whether the data stream represents normal nodes or GL nodes. In each case, the segs are stored in an 11 byte structure, but their contents differ slightly. There is no padding to make these align to DWORD boundaries.
DWORD | NumSegs | Number of segs |
Repeat NumSegs times: | ||
DWORD | v1 | Seg's first vertex |
DWORD | v2 | Seg's second vertex |
WORD | line | The linedef this seg came from |
BYTE | side | The linedef's side this seg came from (0=front, 1=back) |
Note that unlike uncompressed nodes, the seg's angle and offset are not included. ZDoom does not need this information, and other ports that wish to support compressed nodes can recompute them trivially.
DWORD | NumSegs | Number of segs |
Repeat NumSegs times: | ||
DWORD | v1 | Seg's first vertex |
DWORD | partner | Seg's partner seg (0xFFFFFFFF if none) |
WORD | line | The linedef this seg came from (0xFFFFFFFF if none) |
BYTE | side | The linedef's side this seg came from (0=front, 1=back) (ignored if no line) |
Unlike standard GL nodes, each seg's second vertex is not stored. This is because GL subsectors must form a closed area. In other words, one seg's second vertex is the same as the next seg's first vertex. The subsector information contains everything you need to know to close each area and start a new one.
Example: Suppose you have not read any segs yet, and the first subsector has four segs. Therefore, the second vertex for the first four segs can be determined to be:
Seg 0 Second vertex is Seg 1's first vertex Seg 1 Second vertex is Seg 2's first vertex Seg 2 Second vertex is Seg 3's first vertex Seg 3 Second vertex is Seg 0's first vertex (because this is the last seg in the subsector)
So for each subsector, all but the last seg's second vertex will be the same as the next seg's first vertex. The last seg's second vertex will be the same as the first seg's first vertex.
This is really no different from standard nodes.
DWORD | NumNodes | Number of nodes |
Repeat NumNodes times: | ||
4 SWORDs | X, Y, dX, dY | Splitter for this node |
4 SWORDs | Top, Bottom, Left, Right | Bounding box for Child0 |
4 SWORDs | Top, Bottom, Left, Right | Bounding box for Child1 |
2 DWORDs | Child0, Child1 | References to child nodes or subsectors |
As with standard nodes, a child's high bit is set to indicate that it is a subsector and cleared to indicate that it is another node. Just remember that the child references are stored using four bytes each instead of two.
Normal nodes (signature 'ZNOD') are stored in a map's NODES lump. Bear in mind that compressed nodes are contained entirely within a single lump rather than in three separate lumps.
GL nodes (signature 'ZGLN') are stored in a map's SSECTORS lump. Unlike regular GL nodes, no new lumps are created for compressed GL nodes.
The SEGS lump is left unused and should be written with a length of 0. I may find some way to "hijack" this lump in the future, so programs that read compressed nodes must not assume that if the SEGS lump is non-empty, then compressed nodes are not used.