Initial commit of zdbsp.

SVN r12 (trunk)
This commit is contained in:
Randy Heit 2006-02-24 05:17:19 +00:00
parent fbbfdcf196
commit 24d4f0b45c
57 changed files with 21226 additions and 0 deletions

340
COPYING Normal file
View file

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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 should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

1146
Unused/nodebuild.cpp-nogl Normal file

File diff suppressed because it is too large Load diff

98
Unused/nodebuild.h-nogl Normal file
View file

@ -0,0 +1,98 @@
#include "doomdata.h"
#include "workdata.h"
#include "tarray.h"
class FNodeBuilder
{
struct FPrivSeg
{
int v1, v2;
int sidedef;
int linedef;
int frontsector;
int backsector;
int next;
int nextforvert;
int loopnum; // loop number for split avoidance (0 means splitting is okay)
angle_t angle;
fixed_t offset;
int planenum;
FPrivSeg *hashnext;
};
struct FPrivVert
{
fixed_t x, y;
WORD segs; // segs that use this vertex as v1
bool operator== (const FPrivVert &other)
{
return x == other.x && y == other.y;
}
};
union USegPtr
{
int SegNum;
FPrivSeg *SegPtr;
};
public:
struct FPolyStart
{
int polynum;
fixed_t x, y;
};
FNodeBuilder (FLevel &level,
TArray<FPolyStart> &polyspots, TArray<FPolyStart> &anchors,
const char *name);
void GetVertices (WideVertex *&verts, int &count);
void GetSegs (MapSeg *&segs, int &count);
void GetNodes (MapNode *&nodes, int &count);
void GetSubsectors (MapSubsector *&ssecs, int &count);
private:
TArray<node_t> Nodes;
TArray<MapSubsector> Subsectors;
TArray<FPrivSeg> Segs;
TArray<FPrivVert> Vertices;
TArray<USegPtr> SegList;
TArray<BYTE> PlaneChecked;
TArray<int> Touched; // Loops a splitter touches on a vertex
TArray<int> Colinear; // Loops with edges colinear to a splitter
FLevel &Level;
// Progress meter stuff
int SegsStuffed;
const char *MapName;
void FindUsedVertices (WideVertex *vertices, int max);
void BuildTree ();
void MakeSegsFromSides ();
void GroupSegPlanes ();
void FindPolyContainers (TArray<FPolyStart> &spots, TArray<FPolyStart> &anchors);
bool GetPolyExtents (int polynum, fixed_t bbox[4]);
int MarkLoop (int firstseg, int loopnum);
void AddSegToBBox (fixed_t bbox[4], const FPrivSeg *seg);
int CreateNode (WORD set, fixed_t bbox[4]);
int CreateSubsector (WORD set, fixed_t bbox[4]);
bool CheckSubsector (WORD set, node_t &node, int setsize);
int SelectSplitter (WORD set, node_t &node, int step, bool nosplit);
void SplitSegs (WORD set, node_t &node, WORD &outset0, WORD &outset1);
int Heuristic (node_t &node, WORD set, bool honorNoSplit);
int ClassifyLine (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2);
int CountSegs (WORD set) const;
static int SortSegs (const void *a, const void *b);
// < 0 : in front of line
// == 0 : on line
// > 0 : behind line
inline int PointOnSide (int x, int y, int x1, int y1, int dx, int dy);
fixed_t InterceptVector (const node_t &splitter, const FPrivSeg &seg);
void PrintSet (int l, WORD set);
};

215
Unused/rejectbuilder.cpp Normal file
View file

@ -0,0 +1,215 @@
// The old code used the same algorithm as DoomBSP:
//
// Represent each sector by its bounding box. Then for each pair of
// sectors, see if any chains of one-sided lines can walk from one
// side of the convex hull for that pair to the other side.
//
// It works, but it's far from being perfect. It's quite easy for
// this algorithm to consider two sectors as being visible from
// each other when they are really not. But it won't erroneously
// flag two sectors as obstructed when they're really not, and that's
// the only thing that really matters when building a REJECT lump.
//
// Because that was next to useless, I scrapped that code and adapted
// Quake's vis utility to work in a 2D world. Since this is basically vis,
// it depends on GL nodes being present to function. As the usefulness
// of a REJECT lump is debatable, I have chosen to not compile this module
// in with ZDBSP. Save yourself some space and run ZDBSP with the -r option.
#include <string.h>
#include <stdio.h>
#include "zdbsp.h"
#include "nodebuild.h"
#include "rejectbuilder.h"
#include "templates.h"
bool MergeVis=1;
FRejectBuilder::FRejectBuilder (FLevel &level)
: Level (level), testlevel (2), totalvis (0)
{
LoadPortals ();
if (MergeVis)
{
MergeLeaves ();
MergeLeafPortals ();
}
CountActivePortals ();
CalcVis ();
BuildReject ();
}
FRejectBuilder::~FRejectBuilder ()
{
}
BYTE *FRejectBuilder::GetReject ()
{
WORD *sectormap;
int i, j;
int rejectSize = (Level.NumSectors*Level.NumSectors + 7) / 8;
BYTE *reject = new BYTE[rejectSize];
memset (reject, 0xff, rejectSize);
int pvs_size = (Level.NumGLSubsectors * Level.NumGLSubsectors) + 7 / 8;
Level.GLPVS = new BYTE[pvs_size];
Level.GLPVSSize = pvs_size;
memset (Level.GLPVS, 0, pvs_size);
sectormap = new WORD[Level.NumGLSubsectors];
for (i = 0; i < Level.NumGLSubsectors; ++i)
{
const MapSegGLEx *seg = &Level.GLSegs[Level.GLSubsectors[i].firstline];
sectormap[i] = Level.Sides[Level.Lines[seg->linedef].sidenum[seg->side]].sector;
}
for (i = 0; i < Level.NumGLSubsectors; ++i)
{
int rowpvs = i*Level.NumGLSubsectors;
int rowrej = sectormap[i]*Level.NumSectors;
BYTE *bytes = visBytes + i*leafbytes;
for (j = 0; j < Level.NumGLSubsectors; ++j)
{
if (bytes[j>>3] & (1<<(j&7)))
{
int mark = rowpvs + j;
Level.GLPVS[mark>>3] |= 1<<(mark&7);
mark = rowrej + sectormap[j];
reject[mark>>3] &= ~(1<<(mark&7));
}
}
}
return reject;
}
void FRejectBuilder::BuildReject ()
{
}
inline const WideVertex *FRejectBuilder::GetVertex (WORD vertnum)
{
return &Level.Vertices[vertnum];
}
FRejectBuilder::FLeaf::FLeaf ()
: numportals (0), merged (-1), portals (NULL)
{
}
FRejectBuilder::FLeaf::~FLeaf ()
{
if (portals != NULL)
{
delete[] portals;
}
}
int FRejectBuilder::PointOnSide (const FPoint &point, const FLine &line)
{
return FNodeBuilder::PointOnSide (point.x, point.y, line.x, line.y, line.dx, line.dy);
}
void FRejectBuilder::LoadPortals ()
{
WORD *segleaf;
int i, j, k, max;
VPortal *p;
FLeaf *l;
FWinding *w;
portalclusters = Level.NumGLSubsectors;
for (numportals = 0, i = 0; i < Level.NumGLSegs; ++i)
{
if (Level.GLSegs[i].partner != DWORD_MAX)
{
++numportals;
}
}
// these counts should take advantage of 64 bit systems automatically
leafbytes = ((portalclusters+63)&~63)>>3;
leaflongs = leafbytes/sizeof(long);
portalbytes = ((numportals+63)&~63)>>3;
portallongs = portalbytes/sizeof(long);
portals = new VPortal[numportals];
memset (portals, 0, numportals*sizeof(VPortal));
leafs = new FLeaf[portalclusters];
numVisBytes = portalclusters*leafbytes;
visBytes = new BYTE[numVisBytes];
segleaf = new WORD[Level.NumGLSegs];
for (i = 0; i < Level.NumGLSubsectors; ++i)
{
j = Level.GLSubsectors[i].firstline;
max = j + Level.GLSubsectors[i].numlines;
for (; j < max; ++j)
{
segleaf[j] = i;
}
}
p = portals;
l = leafs;
for (i = 0; i < Level.NumGLSubsectors; ++i, ++l)
{
j = Level.GLSubsectors[i].firstline;
max = j + Level.GLSubsectors[i].numlines;
// Count portals in this leaf
for (; j < max; ++j)
{
if (Level.GLSegs[j].partner != DWORD_MAX)
{
++l->numportals;
}
}
if (l->numportals == 0)
{
continue;
}
l->portals = new VPortal *[l->numportals];
for (k = 0, j = Level.GLSubsectors[i].firstline; j < max; ++j)
{
const MapSegGLEx *seg = &Level.GLSegs[j];
if (seg->partner == DWORD_MAX)
{
continue;
}
// create portal from seg
l->portals[k++] = p;
w = &p->winding;
w->points[0] = GetVertex (seg->v1);
w->points[1] = GetVertex (seg->v2);
p->hint = seg->linedef != NO_INDEX;
p->line.x = w->points[1].x;
p->line.y = w->points[1].y;
p->line.dx = w->points[0].x - p->line.x;
p->line.dy = w->points[0].y - p->line.y;
p->leaf = segleaf[seg->partner];
p++;
}
}
delete[] segleaf;
}

View file

@ -0,0 +1,330 @@
// This is the same algorithm used by DoomBSP:
//
// Represent each sector by its bounding box. Then for each pair of
// sectors, see if any chains of one-sided lines can walk from one
// side of the convex hull for that pair to the other side.
//
// It works, but it's far from being perfect. It's quite easy for
// this algorithm to consider two sectors as being visible from
// each other when they are really not. But it won't erroneously
// flag two sectors as obstructed when they're really not, and that's
// the only thing that really matters when building a REJECT lump.
#include <string.h>
#include <stdio.h>
#include "rejectbuilder.h"
#include "templates.h"
FRejectBuilder::FRejectBuilder (FLevel &level)
: Level (level), BlockChains (NULL)
{
RejectSize = (Level.NumSectors*Level.NumSectors + 7) / 8;
Reject = new BYTE[RejectSize];
memset (Reject, 0, RejectSize);
FindSectorBounds ();
FindBlockChains ();
BuildReject ();
}
FRejectBuilder::~FRejectBuilder ()
{
FBlockChain *chain, *next;
chain = BlockChains;
while (chain != NULL)
{
next = chain->Next;
delete chain;
chain = next;
}
}
BYTE *FRejectBuilder::GetReject ()
{
return Reject;
}
void FRejectBuilder::FindSectorBounds ()
{
int i;
SectorBounds = new BBox[Level.NumSectors];
for (i = 0; i < Level.NumSectors; ++i)
{
SectorBounds[i].Bounds[LEFT] = SectorBounds[i].Bounds[BOTTOM] = INT_MAX;
SectorBounds[i].Bounds[RIGHT] = SectorBounds[i].Bounds[TOP] = INT_MIN;
}
for (i = 0; i < Level.NumLines; ++i)
{
if (Level.Lines[i].sidenum[0] != NO_INDEX)
{
int secnum = Level.Sides[Level.Lines[i].sidenum[0]].sector;
SectorBounds[secnum].AddPt (Level.Vertices[Level.Lines[i].v1]);
SectorBounds[secnum].AddPt (Level.Vertices[Level.Lines[i].v2]);
}
if (Level.Lines[i].sidenum[1] != NO_INDEX)
{
int secnum = Level.Sides[Level.Lines[i].sidenum[1]].sector;
SectorBounds[secnum].AddPt (Level.Vertices[Level.Lines[i].v1]);
SectorBounds[secnum].AddPt (Level.Vertices[Level.Lines[i].v2]);
}
}
}
void FRejectBuilder::FindBlockChains ()
{
bool *marked = new bool[Level.NumLines];
WORD *nextForVert = new WORD[Level.NumLines];
WORD *firstLine = new WORD[Level.NumVertices];
int i, j, k;
FBlockChain *chain;
FPoint pt;
TArray<FPoint> pts;
memset (nextForVert, 0xff, Level.NumLines*sizeof(*nextForVert));
memset (firstLine, 0xff, Level.NumVertices*sizeof(*firstLine));
memset (marked, 0, Level.NumLines*sizeof(*marked));
for (i = 0; i < Level.NumLines; ++i)
{
if (Level.Lines[i].sidenum[0] == NO_INDEX || Level.Lines[i].sidenum[1] != NO_INDEX)
{
marked[i] = true;
}
else
{
nextForVert[Level.Lines[i].v1] = firstLine[Level.Lines[i].v1];
firstLine[Level.Lines[i].v1] = i;
}
}
for (i = 0; i < Level.NumLines; ++i)
{
if (marked[i])
{
continue;
}
pt.x = Level.Vertices[Level.Lines[i].v1].x >> FRACBITS;
pt.y = Level.Vertices[Level.Lines[i].v1].y >> FRACBITS;
pts.Clear ();
pts.Push (pt);
chain = new FBlockChain;
chain->Bounds(LEFT) = chain->Bounds(RIGHT) = pt.x;
chain->Bounds(TOP) = chain->Bounds(BOTTOM) = pt.y;
for (j = i; j != NO_INDEX; )
{
marked[j] = true;
pt.x = Level.Vertices[Level.Lines[j].v2].x >> FRACBITS;
pt.y = Level.Vertices[Level.Lines[j].v2].y >> FRACBITS;
pts.Push (pt);
chain->Bounds.AddPt (pt);
k = firstLine[Level.Lines[j].v2];
if (k == NO_INDEX)
{
break;
}
if (nextForVert[k] == NO_INDEX)
{
j = marked[k] ? NO_INDEX : k;
}
else
{
int best = NO_INDEX;
angle_t bestang = ANGLE_MAX;
angle_t ang1 = PointToAngle (Level.Vertices[Level.Lines[j].v2].x - Level.Vertices[Level.Lines[j].v1].x,
Level.Vertices[Level.Lines[j].v2].y - Level.Vertices[Level.Lines[j].v1].y) + (1 << 31);
while (k != NO_INDEX)
{
if (!marked[k])
{
angle_t ang2 = PointToAngle (Level.Vertices[Level.Lines[k].v2].x - Level.Vertices[Level.Lines[k].v1].x,
Level.Vertices[Level.Lines[k].v2].y - Level.Vertices[Level.Lines[k].v1].y) + (1 << 31);
angle_t angdiff = ang2 - ang1;
if (angdiff < bestang && angdiff > 0)
{
bestang = angdiff;
best = k;
}
}
k = nextForVert[k];
}
j = best;
}
}
chain->NumPoints = pts.Size();
chain->Points = new FPoint[chain->NumPoints];
memcpy (chain->Points, &pts[0], chain->NumPoints*sizeof(*chain->Points));
chain->Next = BlockChains;
BlockChains = chain;
}
}
void FRejectBuilder::HullSides (const BBox &box1, const BBox &box2, FPoint sides[4])
{
static const int vertSides[4][2] = {
{ LEFT, BOTTOM },
{ LEFT, TOP },
{ RIGHT, TOP },
{ RIGHT, BOTTOM }
};
static const int stuffSpots[4] = { 0, 3, 2, 1 };
const int *boxp1, *boxp2;
boxp1 = box2.Bounds;
boxp2 = box1.Bounds;
for (int mainBox = 2; mainBox != 0; )
{
const int *stuffs = stuffSpots + (--mainBox)*2;
int outerEdges[4];
outerEdges[LEFT] = boxp1[LEFT] <= boxp2[LEFT];
outerEdges[TOP] = boxp1[TOP] >= boxp2[TOP];
outerEdges[RIGHT] = boxp1[RIGHT] >= boxp2[RIGHT];
outerEdges[BOTTOM] = boxp1[BOTTOM] <= boxp2[BOTTOM];
for (int vertex = 0; vertex < 4; ++vertex)
{
if (outerEdges[(vertex-1)&3] != outerEdges[vertex])
{
FPoint *pt = &sides[stuffs[outerEdges[vertex]]];
pt->x = boxp1[vertSides[vertex][0]];
pt->y = boxp1[vertSides[vertex][1]];
}
}
boxp1 = box1.Bounds;
boxp2 = box2.Bounds;
}
}
int FRejectBuilder::PointOnSide (const FPoint *pt, const FPoint &lpt1, const FPoint &lpt2)
{
return (pt->y - lpt1.y) * (lpt2.x - lpt1.x) >= (pt->x - lpt1.x) * (lpt2.y - lpt1.y);
}
bool FRejectBuilder::ChainBlocks (const FBlockChain *chain,
const BBox *hullBounds, const FPoint *hullPts)
{
int startSide, side, i;
if (chain->Bounds[LEFT] > hullBounds->Bounds[RIGHT] ||
chain->Bounds[RIGHT] < hullBounds->Bounds[LEFT] ||
chain->Bounds[TOP] < hullBounds->Bounds[BOTTOM] ||
chain->Bounds[BOTTOM] > hullBounds->Bounds[TOP])
{
return false;
}
startSide = -1;
for (i = 0; i < chain->NumPoints; ++i)
{
const FPoint *pt = &chain->Points[i];
if (PointOnSide (pt, hullPts[1], hullPts[2]))
{
startSide = -1;
continue;
}
if (PointOnSide (pt, hullPts[3], hullPts[0]))
{
startSide = -1;
continue;
}
if (PointOnSide (pt, hullPts[0], hullPts[1]))
{
side = 0;
}
else if (PointOnSide (pt, hullPts[2], hullPts[3]))
{
side = 1;
}
else
{
continue;
}
if (startSide == -1 || startSide == side)
{
startSide = side;
}
else
{
return true;
}
}
return false;
}
void FRejectBuilder::BuildReject ()
{
int s1, s2;
for (s1 = 0; s1 < Level.NumSectors-1; ++s1)
{
printf (" Reject: %3d%%\r", s1*100/Level.NumSectors);
for (s2 = s1 + 1; s2 < Level.NumSectors; ++s2)
{
BBox HullBounds;
FPoint HullPts[4];
const BBox *sb1, *sb2;
sb1 = &SectorBounds[s1];
sb2 = &SectorBounds[s2];
int pos = s1*Level.NumSectors + s2;
if (Reject[pos>>3] & (1<<(pos&7)))
{
continue;
}
// Overlapping and touching sectors are considered to always
// see each other.
if (sb1->Bounds[LEFT] <= sb2->Bounds[RIGHT] &&
sb1->Bounds[RIGHT] >= sb2->Bounds[LEFT] &&
sb1->Bounds[TOP] >= sb2->Bounds[BOTTOM] &&
sb1->Bounds[BOTTOM] <= sb2->Bounds[TOP])
{
continue;
}
HullBounds(LEFT) = MIN (sb1->Bounds[LEFT], sb2->Bounds[LEFT]);
HullBounds(RIGHT) = MAX (sb1->Bounds[RIGHT], sb2->Bounds[RIGHT]);
HullBounds(BOTTOM) = MIN (sb1->Bounds[BOTTOM], sb2->Bounds[BOTTOM]);
HullBounds(TOP) = MAX (sb1->Bounds[TOP], sb2->Bounds[TOP]);
HullSides (*sb1, *sb2, HullPts);
for (FBlockChain *chain = BlockChains; chain != NULL; chain = chain->Next)
{
if (ChainBlocks (chain, &HullBounds, HullPts))
{
break;
}
}
if (chain == NULL)
{
continue;
}
Reject[pos>>3] |= 1 << (pos & 7);
pos = s2*Level.NumSectors + s1;
Reject[pos>>3] |= 1 << (pos & 7);
}
}
printf (" Reject: 100%%\n");
}

View file

@ -0,0 +1,278 @@
// This is the same algorithm used by DoomBSP:
//
// Represent each sector by its bounding box. Then for each pair of
// sectors, see if any chains of one-sided lines can walk from one
// side of the convex hull for that pair to the other side.
//
// It works, but it's far from being perfect. It's quite easy for
// this algorithm to consider two sectors as being visible from
// each other when they are really not. But it won't erroneously
// flag two sectors as obstructed when they're really not, and that's
// the only thing that really matters when building a REJECT lump.
#include <string.h>
#include <stdio.h>
#include "zdbsp.h"
#include "nodebuild.h"
#include "rejectbuilder.h"
#include "templates.h"
FRejectBuilder::FRejectBuilder (FLevel &level)
: Level (level)
{
int i;
i = Level.NumGLSubsectors * Level.NumGLSubsectors;
SubSeeMatrix = new BYTE[i];
memset (SubSeeMatrix, 0, i);
SegSubsectors = new WORD[Level.NumGLSegs];
for (i = 0; i < Level.NumGLSubsectors; ++i)
{
for (int j = 0; j < Level.GLSubsectors[i].numlines; ++j)
{
SegSubsectors[j + Level.GLSubsectors[i].firstline] = i;
}
}
BuildReject ();
}
FRejectBuilder::~FRejectBuilder ()
{
delete[] SubSeeMatrix;
delete[] SegSubsectors;
}
BYTE *FRejectBuilder::GetReject ()
{
int i, j;
int rejectSize = (Level.NumSectors*Level.NumSectors + 7) / 8;
BYTE *reject = new BYTE[rejectSize];
memset (reject, 0xff, rejectSize);
int pvs_size = (Level.NumGLSubsectors * Level.NumGLSubsectors) + 7 / 8;
Level.GLPVS = new BYTE[pvs_size];
Level.GLPVSSize = pvs_size;
memset (Level.GLPVS, 0, pvs_size);
for (i = 0; i < Level.NumGLSubsectors; ++i)
{
int row = i*Level.NumGLSubsectors;
int sector1 =
Level.Sides[
Level.Lines[
Level.GLSegs[
Level.GLSubsectors[i].firstline].linedef]
.sidenum[
Level.GLSegs[
Level.GLSubsectors[i].firstline].side]]
.sector;
int srow = sector1*Level.NumSectors;
for (j = 0; j < Level.NumGLSubsectors; ++j)
{
if (SubSeeMatrix[row + j])
{
int sector2 =
Level.Sides[
Level.Lines[
Level.GLSegs[
Level.GLSubsectors[j].firstline].linedef]
.sidenum[
Level.GLSegs[
Level.GLSubsectors[j].firstline].side]]
.sector;
int l = (srow + sector2) >> 3;
int r = (srow + sector2) & 7;
reject[l] &= ~(1 << r);
l = (row + j) >> 3;
r = (row + j) & 7;
Level.GLPVS[l] |= 1 << r;
}
}
}
return reject;
}
void FRejectBuilder::BuildReject ()
{
int s1, s2;
for (s1 = 0; s1 < Level.NumGLSubsectors; ++s1)
{
//printf (" Reject: %3d%%\r",s1*100/Level.NumGLSubsectors);
printf ("%d/%d\r", s1, Level.NumGLSubsectors);
// A subsector can always see itself
SourceRow = s1 * Level.NumGLSubsectors;
SubSeeMatrix[SourceRow + s1] = 1;
WORD pusher = s1;
for (s2 = 0; s2 < Level.GLSubsectors[s1].numlines; ++s2)
{
int segnum = s2 + Level.GLSubsectors[s1].firstline;
const MapSegGL *seg = &Level.GLSegs[segnum];
if (seg->partner == NO_INDEX)
{
continue;
}
SourceSeg = segnum;
SegRow = segnum * Level.NumGLSegs;
TracePath (s1, seg);
}
}
printf (" Reject: 100%%\n");
}
inline const WideVertex *FRejectBuilder::GetVertex (WORD vertnum)
{
if (vertnum & 0x8000)
{
return &Level.GLVertices[vertnum & 0x7fff];
}
else
{
return &Level.Vertices[vertnum];
}
}
void FRejectBuilder::TracePath (int subsector, const MapSegGL *window)
{
// Neighboring subsectors can always see each other
SubSeeMatrix[SourceRow + SegSubsectors[window->partner]] = 1;
const MapSubsector *backsub = &Level.GLSubsectors[SegSubsectors[window->partner]];
Portal source;
source.Subsector = backsub;
source.Left = GetVertex (window->v1);
source.Right = GetVertex (window->v2);
PortalStack.Clear ();
PortalStack.Push (source);
fixed_t wdx = source.Right->x - source.Left->x;
fixed_t wdy = source.Right->y - source.Left->y;
// printf ("start window %d\n", window - Level.GLSegs);
for (int i = 0; i < backsub->numlines; ++i)
{
int segnum = backsub->firstline + i;
if (segnum == window->partner)
{
continue;
}
const MapSegGL *cseg = &Level.GLSegs[segnum];
if (cseg->partner == NO_INDEX)
{
continue;
}
const WideVertex *cv1 = GetVertex (cseg->v1);
const WideVertex *cv2 = GetVertex (cseg->v2);
if (FNodeBuilder::PointOnSide (cv1->x, cv1->y, source.Left->x, source.Left->y, wdx, wdy) == 0 &&
FNodeBuilder::PointOnSide (cv2->x, cv2->y, source.Left->x, source.Left->y, wdx, wdy) == 0)
{
continue;
}
TracePathDeep (cseg);
}
}
void FRejectBuilder::TracePathDeep (const MapSegGL *window)
{
SubSeeMatrix[SourceRow + SegSubsectors[window->partner]] = 1;
const MapSubsector *backsub = &Level.GLSubsectors[SegSubsectors[window->partner]];
size_t j;
for (j = PortalStack.Size(); j-- > 0; )
{
if (PortalStack[j].Subsector == backsub)
{
return;
}
}
Portal entrance;
entrance.Subsector = backsub;
entrance.Left = GetVertex (window->v1);
entrance.Right = GetVertex (window->v2);
PortalStack.Push (entrance);
fixed_t wdx = entrance.Right->x - entrance.Left->x;
fixed_t wdy = entrance.Right->y - entrance.Left->y;
//printf ("deep through %d\n", window - Level.GLSegs);
for (int i = 0; i < backsub->numlines; ++i)
{
int segnum = backsub->firstline + i;
if (segnum == window->partner)
{
continue;
}
const MapSegGL *cseg = &Level.GLSegs[segnum];
if (cseg->partner == NO_INDEX)
{
continue;
}
const WideVertex *cv1 = GetVertex (cseg->v1);
const WideVertex *cv2 = GetVertex (cseg->v2);
if (FNodeBuilder::PointOnSide (cv1->x, cv1->y, entrance.Left->x, entrance.Left->y, wdx, wdy) <= 0 &&
FNodeBuilder::PointOnSide (cv2->x, cv2->y, entrance.Left->x, entrance.Left->y, wdx, wdy) <= 0)
{
continue;
}
fixed_t leftx = PortalStack[0].Left->x;
fixed_t lefty = PortalStack[0].Left->y;
fixed_t rightx = PortalStack[0].Right->x;
fixed_t righty = PortalStack[0].Right->y;
fixed_t leftdx = cv1->x - leftx;
fixed_t leftdy = cv1->y - lefty;
fixed_t rightdx = rightx - cv2->x;
fixed_t rightdy = righty - cv2->y;
if (FNodeBuilder::PointOnSide (cv1->x, cv1->y, rightx, righty, rightdx, rightdy) >= 0 ||
FNodeBuilder::PointOnSide (cv2->x, cv2->y, leftx, lefty, leftdx, leftdy) >= 0)
{
continue;
}
for (j = PortalStack.Size(); j-- > 1; )
{
if (FNodeBuilder::PointOnSide (PortalStack[j].Left->x, PortalStack[j].Left->y,
rightx, righty, rightdx, rightdy) >= 0 ||
FNodeBuilder::PointOnSide (PortalStack[j].Right->x, PortalStack[j].Right->y,
leftx, lefty, leftdx, leftdy) >= 0)
{
break;
}
}
if (j == 0)
{
TracePathDeep (cseg);
}
}
PortalStack.Pop (entrance);
}

211
Unused/rejectbuilder.h Normal file
View file

@ -0,0 +1,211 @@
// A slight adaptation of Quake's vis utility.
#include "zdbsp.h"
#include "tarray.h"
#include "doomdata.h"
class FRejectBuilder
{
public:
FRejectBuilder (FLevel &level);
~FRejectBuilder ();
BYTE *GetReject ();
private:
void BuildReject ();
void LoadPortals ();
inline const WideVertex *GetVertex (WORD vertnum);
FLevel &Level;
/* Looky! Stuff from vis.h: */
// seperator caching helps a bit
//#define SEPERATORCACHE
// can't have more seperators than the max number of points on a winding
static const int MAX_SEPERATORS = 2;
static const int MAX_PORTALS = 65536*2/3;
static const int MAX_MAP_LEAFS = 32768;
static const int MAX_PORTALS_ON_LEAF = MAX_PORTALS;
struct FPoint
{
fixed_t x, y;
const FPoint &operator= (const WideVertex *other)
{
x = other->x;
y = other->y;
return *this;
}
};
struct FLine : public FPoint
{
fixed_t dx, dy;
void Flip ()
{
x += dx;
y += dy;
dx = -dx;
dy = -dy;
}
};
struct FWinding
{
FPoint points[2];
};
struct FPassage
{
FPassage *next;
BYTE cansee[1]; //all portals that can be seen through this passage
};
enum VStatus
{
STAT_None,
STAT_Working,
STAT_Done
};
struct VPortal
{
bool removed;
bool hint;
FLine line; // neighbor is on front/right side
int leaf; // neighbor
FWinding winding;
VStatus status;
BYTE *portalfront; // [portals], preliminary
BYTE *portalflood; // [portals], intermediate
BYTE *portalvis; // [portals], final
int nummightsee; // bit count on portalflood for sort
FPassage *passages; // there are just as many passages as there
// are portals in the leaf this portal leads to
};
struct FLeaf
{
FLeaf ();
~FLeaf ();
int numportals;
int merged;
VPortal **portals;
};
struct PStack
{
BYTE mightsee[MAX_PORTALS/8]; // bit string
PStack *next;
FLeaf *leaf;
VPortal *portal; // portal exiting
FWinding *source;
FWinding *pass;
FWinding windings[3]; // source, pass, temp in any order
bool freewindings[3];
FLine portalline;
int depth;
#ifdef SEPERATORCACHE
FLine seperators[2][MAX_SEPERATORS];
int numseperators[2];
#endif
};
struct FThreadData
{
VPortal *base;
int c_chains;
PStack pstack_head;
};
int numportals;
int portalclusters;
VPortal *portals;
FLeaf *leafs;
int c_portaltest, c_portalpass, c_portalcheck;
int c_portalskip, c_leafskip;
int c_vistest, c_mighttest;
int c_chains;
int testlevel;
BYTE *uncompressed;
int leafbytes, leaflongs;
int portalbytes, portallongs;
int numVisBytes;
BYTE *visBytes;
int totalvis;
void LeafFlow (int leafnum);
void BasePortalVis (int portalnum);
void BetterPortalVis (int portalnum);
void PortalFlow (int portalnum);
void PassagePortalFlow (int portalnum);
void CreatePassages (int portalnum);
void PassageFlow (int portalnum);
VPortal *sorted_portals[65536];
static int CountBits (BYTE *bits, int numbits);
void SortPortals ();
static int PComp (const void *a, const void *b);
int LeafVectorFromPortalVector (BYTE *portalbits, BYTE *leafbits);
void ClusterMerge (int leafnum);
void PassageMemory ();
void CalcFastVis ();
void CalcVis ();
void CalcPortalVis ();
void CalcPassagePortalVis ();
int CountActivePortals ();
bool pacifier;
int workcount;
int dispatch;
int oldf;
int oldcount;
void RunThreadsOnIndividual (int workcnt, bool showpacifire, void (FRejectBuilder::*func)(int));
int GetThreadWork ();
void CheckStack (FLeaf *leaf, FThreadData *thread);
FWinding *AllocStackWinding (PStack *stack) const;
void FreeStackWinding (FWinding *w, PStack *stack) const;
FWinding *VisChopWinding (FWinding *in, PStack *stack, FLine *split);
FWinding *ClipToSeperators (FWinding *source, FWinding *pass, FWinding *target, bool flipclip, PStack *stack);
void RecursiveLeafFlow (int leafnum, FThreadData *thread, PStack *prevstack);
void RecursivePassageFlow (VPortal *portal, FThreadData *thread, PStack *prevstack);
void RecursivePassagePortalFlow (VPortal *portal, FThreadData *thread, PStack *prevstack);
FWinding *PassageChopWinding (FWinding *in, FWinding *out, FLine *split);
int AddSeperators (FWinding *source, FWinding *pass, bool flipclip, FLine *seperators, int maxseperators);
void SimpleFlood (VPortal *srcportal, int leafnum);
void RecursiveLeafBitFlow (int leafnum, BYTE *mightsee, BYTE *cansee);
int PointOnSide (const FPoint &point, const FLine &line);
bool TryMergeLeaves (int l1num, int l2num);
void UpdatePortals ();
void MergeLeaves ();
FWinding *TryMergeWinding (FWinding *f1, FWinding *f2, const FLine &line);
void MergeLeafPortals ();
bool Winding_PlanesConcave (const FWinding *w1, const FWinding *w2, const FLine &line1, const FLine &line2);
};

View file

@ -0,0 +1,77 @@
#include "zdbsp.h"
#include "tarray.h"
#include "doomdata.h"
class FRejectBuilder
{
struct FPoint
{
int x, y;
};
struct BBox
{
int Bounds[4];
const int &operator[] (int index) const
{
return Bounds[index];
}
int &operator() (int index)
{
return Bounds[index];
}
void AddPt (int x, int y)
{
if (x < Bounds[LEFT]) Bounds[LEFT] = x;
if (x > Bounds[RIGHT]) Bounds[RIGHT] = x;
if (y < Bounds[BOTTOM]) Bounds[BOTTOM] = y;
if (y > Bounds[TOP]) Bounds[TOP] = y;
}
void AddPt (WideVertex vert)
{
AddPt (vert.x >> FRACBITS, vert.y >> FRACBITS);
}
void AddPt (FPoint pt)
{
AddPt (pt.x, pt.y);
}
};
struct FBlockChain
{
FBlockChain() : Points(0) {}
~FBlockChain() { if (Points) delete[] Points; }
BBox Bounds;
FPoint *Points;
int NumPoints;
FBlockChain *Next;
};
enum { LEFT, TOP, RIGHT, BOTTOM };
friend struct BBox;
public:
FRejectBuilder (FLevel &level);
~FRejectBuilder ();
BYTE *GetReject ();
private:
void FindSectorBounds ();
void FindBlockChains ();
void HullSides (const BBox &box1, const BBox &box2, FPoint sides[4]);
bool ChainBlocks (const FBlockChain *chain, const BBox *hullBounds, const FPoint *hullPts);
void BuildReject ();
inline int PointOnSide (const FPoint *pt, const FPoint &lpt1, const FPoint &lpt2);
BBox *SectorBounds;
BYTE *Reject;
FLevel &Level;
int RejectSize;
FBlockChain *BlockChains;
};

View file

@ -0,0 +1,40 @@
#include "zdbsp.h"
#include "tarray.h"
#include "doomdata.h"
class FRejectBuilder
{
public:
FRejectBuilder (FLevel &level);
~FRejectBuilder ();
BYTE *GetReject ();
private:
struct Portal
{
const MapSubsector *Subsector;
const WideVertex *Left;
const WideVertex *Right;
};
enum ESegSeeStatus
{
MIGHT_SEE,
CAN_SEE,
CANNOT_SEE
};
void BuildReject ();
void TracePath (int subsector, const MapSegGL *window);
void TracePathDeep (const MapSegGL *window);
inline const WideVertex *GetVertex (WORD vertnum);
BYTE *SubSeeMatrix;
WORD *SegSubsectors;
TArray<Portal> PortalStack;
FLevel &Level;
int SourceRow;
int SourceSeg, SegRow;
};

580
Unused/vis.cpp Normal file
View file

@ -0,0 +1,580 @@
// An adaptation of the Quake vis utility.
#include <string.h>
#include <stdio.h>
#include "zdbsp.h"
#include "nodebuild.h"
#include "rejectbuilder.h"
#include "templates.h"
bool FastVis=0;
bool NoPassageVis=1;
bool NoSort;
//=============================================================================
/*
=============
GetThreadWork
=============
*/
int FRejectBuilder::GetThreadWork ()
{
int r;
int f;
if (dispatch == workcount)
{
return -1;
}
if (pacifier)
{
if (dispatch >= workcount-1)
{
fprintf (stderr, "100%%\n");
}
else if (oldcount < 0 || dispatch - oldcount > 200)
{
oldcount = dispatch;
f = 100*dispatch / workcount;
if (f != oldf)
{
oldf = f;
fprintf (stderr, "% 3d%%\b\b\b\b", f);
}
}
}
r = dispatch++;
return r;
}
void FRejectBuilder::RunThreadsOnIndividual (int workcnt, bool showpacifier, void(FRejectBuilder::*func)(int))
{
int work;
pacifier = showpacifier;
workcount = workcnt;
dispatch = 0;
oldf = -1;
oldcount = -1;
while (-1 != (work = GetThreadWork ()))
{
(this->*func) (work);
}
}
//=============================================================================
/*
=============
SortPortals
Sorts the portals from the least complex, so the later ones can reuse
the earlier information.
=============
*/
int FRejectBuilder::PComp (const void *a, const void *b)
{
return (*(VPortal **)a)->nummightsee - (*(VPortal **)b)->nummightsee;
}
void FRejectBuilder::SortPortals ()
{
for (int i = 0; i < numportals; i++)
{
sorted_portals[i] = &portals[i];
}
if (!NoSort)
{
qsort (sorted_portals, numportals, sizeof(sorted_portals[0]), PComp);
}
}
/*
==============
LeafVectorFromPortalVector
==============
*/
int FRejectBuilder::LeafVectorFromPortalVector (BYTE *portalbits, BYTE *leafbits)
{
int i, j, leafnum;
VPortal *p;
int c_leafs;
for (i = 0; i < numportals; i++)
{
if (portalbits[i>>3] & (1<<(i&7)) )
{
p = portals+i;
leafbits[p->leaf>>3] |= (1<<(p->leaf&7));
//printf ("pleaf: from %d to %d\n", i, p->leaf);
}
}
for (j = 0; j < portalclusters; j++)
{
leafnum = j;
while (leafs[leafnum].merged >= 0)
{
leafnum = leafs[leafnum].merged;
}
//if the merged leaf is visible then the original leaf is visible
if (leafbits[leafnum>>3] & (1<<(leafnum&7)))
{
leafbits[j>>3] |= (1<<(j&7));
}
}
c_leafs = CountBits (leafbits, portalclusters);
return c_leafs;
}
/*
===============
ClusterMerge
Merges the portal visibility for a leaf
===============
*/
void FRejectBuilder::ClusterMerge (int leafnum)
{
FLeaf *leaf;
BYTE portalvector[MAX_PORTALS/8];
BYTE uncompressed[MAX_MAP_LEAFS/8];
int i, j;
int numvis, mergedleafnum;
VPortal *p;
int pnum;
// OR together all the portalvis bits
mergedleafnum = leafnum;
while (leafs[mergedleafnum].merged >= 0)
{
mergedleafnum = leafs[mergedleafnum].merged;
}
memset (portalvector, 0, portalbytes);
leaf = &leafs[mergedleafnum];
for (i = 0; i < leaf->numportals; i++)
{
p = leaf->portals[i];
if (p->removed)
continue;
if (p->status != STAT_Done)
{
throw exception("portal not done");
}
for (j = 0; j < portallongs; j++)
{
((long *)portalvector)[j] |= ((long *)p->portalvis)[j];
}
pnum = p - portals;
portalvector[pnum>>3] |= 1<<(pnum&7);
}
memset (uncompressed, 0, leafbytes);
// convert portal bits to leaf bits
uncompressed[mergedleafnum>>3] |= (1<<(mergedleafnum&7));
numvis = LeafVectorFromPortalVector (portalvector, uncompressed);
totalvis += numvis;
//printf ("cluster %4i : %4i visible\n", leafnum, numvis);
memcpy (visBytes + leafnum*leafbytes, uncompressed, leafbytes);
}
/*
==================
CalcPortalVis
==================
*/
void FRejectBuilder::CalcPortalVis ()
{
#ifdef MREDEBUG
_printf("%6d portals out of %d", 0, numportals);
//get rid of the counter
RunThreadsOnIndividual (numportals, false, PortalFlow);
#else
RunThreadsOnIndividual (numportals, true, PortalFlow);
#endif
}
/*
==================
CalcPassagePortalVis
==================
*/
void FRejectBuilder::CalcPassagePortalVis ()
{
PassageMemory();
#ifdef MREDEBUG
_printf("%6d portals out of %d", 0, numportals);
RunThreadsOnIndividual (numportals, false, CreatePassages);
_printf("\n");
_printf("%6d portals out of %d", 0, numportals);
RunThreadsOnIndividual (numportals, false, PassagePortalFlow);
_printf("\n");
#else
RunThreadsOnIndividual (numportals, true, CreatePassages);
printf (" Vis 3: ");
RunThreadsOnIndividual (numportals, true, PassagePortalFlow);
#endif
}
/*
==================
CalcFastVis
==================
*/
void FRejectBuilder::CalcFastVis ()
{
// fastvis just uses mightsee for a very loose bound
for (int i = 0; i < numportals; i++)
{
portals[i].portalvis = portals[i].portalflood;
portals[i].status = STAT_Done;
}
}
/*
==================
CalcVis
==================
*/
void FRejectBuilder::CalcVis ()
{
printf (" Vis 1: ");
RunThreadsOnIndividual (numportals, true, BasePortalVis);
// RunThreadsOnIndividual (numportals, true, BetterPortalVis);
SortPortals ();
printf (" Vis 2: ");
if (FastVis)
CalcFastVis();
else if (NoPassageVis)
CalcPortalVis ();
else
CalcPassagePortalVis();
//
// assemble the leaf vis lists by oring and compressing the portal lists
//
printf ("creating leaf vis...\n");
for (int i = 0; i < portalclusters; i++)
{
ClusterMerge (i);
}
printf ("Average clusters visible: %i\n", totalvis / portalclusters);
}
/*
=============
Winding_PlanesConcave
=============
*/
bool FRejectBuilder::Winding_PlanesConcave (const FWinding *w1, const FWinding *w2,
const FLine &line1, const FLine &line2)
{
// check if one of the points of winding 1 is at the front of the line of winding 2
if (PointOnSide (w1->points[0], line2) < 0 ||
PointOnSide (w1->points[1], line2) < 0)
{
return true;
}
// check if one of the points of winding 2 is at the front of the line of winding 1
if (PointOnSide (w2->points[0], line1) < 0 ||
PointOnSide (w2->points[1], line1) < 0)
{
return true;
}
return false;
}
/*
============
TryMergeLeaves
============
*/
bool FRejectBuilder::TryMergeLeaves (int l1num, int l2num)
{
int i, j, numportals;
FLeaf *l1, *l2;
VPortal *p1, *p2;
VPortal *portals[MAX_PORTALS_ON_LEAF];
l1 = &leafs[l1num];
for (i = 0; i < l1->numportals; i++)
{
p1 = l1->portals[i];
if (p1->leaf == l2num) continue;
l2 = &leafs[l2num];
for (j = 0; j < l2->numportals; j++)
{
p2 = l2->portals[j];
if (p2->leaf == l1num) continue;
//
if (Winding_PlanesConcave (&p1->winding, &p2->winding, p1->line, p2->line))
return false;
}
}
l1 = &leafs[l1num];
l2 = &leafs[l2num];
numportals = 0;
//the leaves can be merged now
for (i = 0; i < l1->numportals; i++)
{
p1 = l1->portals[i];
if (p1->leaf == l2num)
{
p1->removed = true;
continue;
}
portals[numportals++] = p1;
}
for (j = 0; j < l2->numportals; j++)
{
p2 = l2->portals[j];
if (p2->leaf == l1num)
{
p2->removed = true;
continue;
}
portals[numportals++] = p2;
}
delete[] l1->portals;
l1->portals = NULL;
l1->numportals = 0;
delete[] l2->portals;
l2->portals = new VPortal *[numportals];
for (i = 0; i < numportals; i++)
{
l2->portals[i] = portals[i];
}
l2->numportals = numportals;
l1->merged = l2num;
return true;
}
/*
============
UpdatePortals
============
*/
void FRejectBuilder::UpdatePortals ()
{
int i;
VPortal *p;
for (i = 0; i < numportals; i++)
{
p = &portals[i];
if (!p->removed)
{
while (leafs[p->leaf].merged >= 0)
{
p->leaf = leafs[p->leaf].merged;
}
}
}
}
/*
============
MergeLeaves
try to merge leaves but don't merge through hint splitters
============
*/
void FRejectBuilder::MergeLeaves ()
{
int i, j, nummerges, totalnummerges;
FLeaf *leaf;
VPortal *p;
totalnummerges = 0;
do
{
printf (".");
nummerges = 0;
for (i = 0; i < portalclusters; i++)
{
leaf = &leafs[i];
//if this leaf is merged already
if (leaf->merged >= 0)
continue;
//
for (j = 0; j < leaf->numportals; j++)
{
p = leaf->portals[j];
//
if (p->removed)
continue;
//never merge through hint portals
if (p->hint)
continue;
if (TryMergeLeaves(i, p->leaf))
{
UpdatePortals();
nummerges++;
break;
}
}
}
totalnummerges += nummerges;
} while (nummerges);
printf("\r%6d leaves merged\n", totalnummerges);
}
/*
============
TryMergeWinding
============
*/
FRejectBuilder::FWinding *FRejectBuilder::TryMergeWinding (FWinding *f1, FWinding *f2, const FLine &line)
{
static FWinding result;
int i, j;
//
// find a common point
//
for (i = 0; i < 2; ++i)
{
for (j = 0; j < 2; ++j)
{
if (f1->points[i].x == f2->points[j].x &&
f1->points[i].y == f2->points[j].y)
{
goto found;
}
}
}
// no shared point
return NULL;
found:
//
// if the lines are colinear, the point can be removed
//
if (PointOnSide (f2->points[0], line) != 0 ||
PointOnSide (f2->points[1], line) != 0)
{ // not colinear
return NULL;
}
//
// build the new segment
//
if (i == 0)
{
result.points[0] = f2->points[!j];
result.points[1] = f1->points[1];
}
else
{
result.points[0] = f1->points[0];
result.points[1] = f2->points[!j];
}
return &result;
}
/*
============
MergeLeafPortals
============
*/
void FRejectBuilder::MergeLeafPortals ()
{
int i, j, k, nummerges, hintsmerged;
FLeaf *leaf;
VPortal *p1, *p2;
FWinding *w;
nummerges = 0;
hintsmerged = 0;
for (i = 0; i < portalclusters; i++)
{
leaf = &leafs[i];
if (leaf->merged >= 0) continue;
for (j = 0; j < leaf->numportals; j++)
{
p1 = leaf->portals[j];
if (p1->removed)
continue;
for (k = j+1; k < leaf->numportals; k++)
{
p2 = leaf->portals[k];
if (p2->removed)
continue;
if (p1->leaf == p2->leaf)
{
w = TryMergeWinding (&p1->winding, &p2->winding, p1->line);
if (w)
{
p1->winding = *w;
if (p1->hint && p2->hint)
hintsmerged++;
p1->hint |= p2->hint;
p2->removed = true;
nummerges++;
i--;
break;
}
}
}
if (k < leaf->numportals)
break;
}
}
printf("%6d portals merged\n", nummerges);
printf("%6d hint portals merged\n", hintsmerged);
}
/*
============
CountActivePortals
============
*/
int FRejectBuilder::CountActivePortals ()
{
int num, hints, j;
VPortal *p;
num = 0;
hints = 0;
for (j = 0; j < numportals; j++)
{
p = portals + j;
if (p->removed)
continue;
if (p->hint)
hints++;
num++;
}
printf("%6d of %d active portals\n", num, numportals);
printf("%6d hint portals\n", hints);
return num;
}

1345
Unused/visflow.cpp Normal file

File diff suppressed because it is too large Load diff

455
blockmapbuilder.cpp Normal file
View file

@ -0,0 +1,455 @@
/*
Routines for building a Doom map's BLOCKMAP lump.
Copyright (C) 2002 Randy Heit
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 should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include "zdbsp.h"
#include "templates.h"
#include "tarray.h"
#include "blockmapbuilder.h"
#undef BLOCK_TEST
FBlockmapBuilder::FBlockmapBuilder (FLevel &level)
: Level (level)
{
BuildBlockmap ();
}
#ifdef BLOCK_TEST
inline int PointOnSide (int x, int y, int x1, int y1, int dx, int dy)
{
int foo = DMulScale32 ((y-y1) << 16, dx<<16, (x1-x)<<16, (dy)<<16);
//return abs(foo) < 4 ? 0 : foo;
return foo > 0;
}
int BoxOnSide (int bx1, int by1, int bx2, int by2,
int lx1, int ly1, int lx2, int ly2)
{
int p1;
int p2;
if (ly1 == ly2)
{
p1 = by1 > ly1;
p2 = by2 > ly1;
}
else if (lx1 == lx2)
{
p1 = bx2 < lx1;
p2 = bx1 < lx1;
}
else if (((ly2-ly1) ^ (lx2-lx1)) >= 0)
{
p1 = PointOnSide (bx1, by1, lx1, ly1, lx2-lx1, ly2-ly1);
p2 = PointOnSide (bx2, by2, lx1, ly1, lx2-lx1, ly2-ly1);
}
else
{
p1 = PointOnSide (bx2, by1, lx1, ly1, lx2-lx1, ly2-ly1);
p2 = PointOnSide (bx1, by2, lx1, ly1, lx2-lx1, ly2-ly1);
}
return (p1 == p2) ? 0 : 1;
}
#endif
WORD *FBlockmapBuilder::GetBlockmap (int &size)
{
#ifdef BLOCK_TEST
FILE *f = fopen ("blockmap.lmp", "rb");
if (f)
{
size_t fsize;
fseek (f, 0, SEEK_END);
fsize = ftell (f);
fseek (f, 0, SEEK_SET);
short *stuff = (short *)alloca (fsize);
fread (stuff, 2, fsize/2, f);
fclose (f);
if ((WORD)stuff[0] != BlockMap[0] ||
(WORD)stuff[1] != BlockMap[1] ||
(WORD)stuff[2] != BlockMap[2] ||
(WORD)stuff[3] != BlockMap[3])
{
printf ("different blockmap sizes\n");
goto notest;
}
int i, x, y;
for (i = 0; i < stuff[2] * stuff[3]; ++i)
{
WORD i1, i2;
i1 = stuff[4+i] + 1;
while (stuff[i1] != -1)
{
i2 = BlockMap[4+i] + 1;
while (BlockMap[i2] != 0xffff)
{
if (BlockMap[i2] == stuff[i1])
break;
i2++;
}
if (BlockMap[i2] == 0xffff)
{
y = i / stuff[2];
x = i - y * stuff[2];
int l = stuff[i1];
// If a diagonal line passed near a block (within 2 or 4 units, I think),
// it could be considered in the block even if it's really outside it,
// so if things differ, see if DoomBSP was at fault.
if (BoxOnSide (
stuff[0] + 128*x, stuff[1] + 128*y,
stuff[0] + 128*x + 127, stuff[1] + 128*y + 127,
Vertices[Lines[l].v1].x, Vertices[Lines[l].v1].y,
Vertices[Lines[l].v2].x, Vertices[Lines[l].v2].y))
{
printf ("not in cell %4d: line %4d [%2d,%2d] : (%5d,%5d)-(%5d,%5d)\n", i, stuff[i1],
x, y,
stuff[0] + 128*x, stuff[1] + 128*y,
stuff[0] + 128*x + 127, stuff[1] + 128*y + 127
);
}
}
i1 ++;
}
i1 = BlockMap[4+i] + 1;
while (BlockMap[i1] != 0xffff)
{
i2 = stuff[4+i] + 1;
while (stuff[i2] != -1)
{
if ((WORD)stuff[i2] == BlockMap[i1])
break;
i2++;
}
if (stuff[i2] == -1)
{
y = i / BlockMap[2];
x = i - y * BlockMap[2];
int l = BlockMap[i1];
if (!BoxOnSide (
(short)BlockMap[0] + 128*x, (short)BlockMap[1] + 128*y,
(short)BlockMap[0] + 128*x + 127, (short)BlockMap[1] + 128*y + 127,
Vertices[Lines[l].v1].x, Vertices[Lines[l].v1].y,
Vertices[Lines[l].v2].x, Vertices[Lines[l].v2].y))
{
printf ("EXT in cell %4d: line %4d [%2d,%2d] : (%5d,%5d)-(%5d,%5d)\n", i, (short)BlockMap[i1],
x, y,
(short)BlockMap[0] + 128*x, (short)BlockMap[1] + 128*y,
(short)BlockMap[0] + 128*x + 127, (short)BlockMap[1] + 128*y + 127
);
}
}
i1 ++;
}
}
}
notest:
#endif
size = BlockMap.Size();
return &BlockMap[0];
}
void FBlockmapBuilder::BuildBlockmap ()
{
TArray<WORD> *BlockLists, *block, *endblock;
WORD adder;
int bmapwidth, bmapheight;
int minx, maxx, miny, maxy;
int i;
WORD line;
if (Level.NumVertices <= 0)
return;
// Find map extents for the blockmap
minx = maxx = Level.Vertices[0].x;
miny = maxy = Level.Vertices[0].y;
for (i = 1; i < Level.NumVertices; ++i)
{
if (Level.Vertices[i].x < minx) minx = Level.Vertices[i].x;
else if (Level.Vertices[i].x > maxx) maxx = Level.Vertices[i].x;
if (Level.Vertices[i].y < miny) miny = Level.Vertices[i].y;
else if (Level.Vertices[i].y > maxy) maxy = Level.Vertices[i].y;
}
maxx >>= FRACBITS;
minx >>= FRACBITS;
maxy >>= FRACBITS;
miny >>= FRACBITS;
/*
// DoomBSP did this to give the map a margin when drawing it
// in a window on NeXT machines. It's not necessary, but
// it lets me verify my output against DoomBSP's for correctness.
minx -= 8;
miny -= 8;
maxx += 8;
maxy += 8;
// And DeepBSP seems to do this.
minx &= ~7;
miny &= ~7;
*/
bmapwidth = ((maxx - minx) >> BLOCKBITS) + 1;
bmapheight = ((maxy - miny) >> BLOCKBITS) + 1;
adder = WORD(minx); BlockMap.Push (adder);
adder = WORD(miny); BlockMap.Push (adder);
adder = WORD(bmapwidth); BlockMap.Push (adder);
adder = WORD(bmapheight); BlockMap.Push (adder);
BlockLists = new TArray<WORD>[bmapwidth * bmapheight];
for (line = 0; line < Level.NumLines; ++line)
{
int x1 = Level.Vertices[Level.Lines[line].v1].x >> FRACBITS;
int y1 = Level.Vertices[Level.Lines[line].v1].y >> FRACBITS;
int x2 = Level.Vertices[Level.Lines[line].v2].x >> FRACBITS;
int y2 = Level.Vertices[Level.Lines[line].v2].y >> FRACBITS;
int dx = x2 - x1;
int dy = y2 - y1;
int bx = (x1 - minx) >> BLOCKBITS;
int by = (y1 - miny) >> BLOCKBITS;
int bx2 = (x2 - minx) >> BLOCKBITS;
int by2 = (y2 - miny) >> BLOCKBITS;
block = &BlockLists[bx + by * bmapwidth];
endblock = &BlockLists[bx2 + by2 * bmapwidth];
if (block == endblock) // Single block
{
block->Push (line);
}
else if (by == by2) // Horizontal line
{
if (bx > bx2)
{
swap (block, endblock);
}
do
{
block->Push (line);
block += 1;
} while (block <= endblock);
}
else if (bx == bx2) // Vertical line
{
if (by > by2)
{
swap (block, endblock);
}
do
{
block->Push (line);
block += bmapwidth;
} while (block <= endblock);
}
else // Diagonal line
{
int xchange = (dx < 0) ? -1 : 1;
int ychange = (dy < 0) ? -1 : 1;
int ymove = ychange * bmapwidth;
int adx = abs (dx);
int ady = abs (dy);
if (adx == ady) // 45 degrees
{
int xb = (x1 - minx) & (BLOCKSIZE-1);
int yb = (y1 - miny) & (BLOCKSIZE-1);
if (dx < 0)
{
xb = BLOCKSIZE-xb;
}
if (dy < 0)
{
yb = BLOCKSIZE-yb;
}
if (xb < yb)
adx--;
}
if (adx >= ady) // X-major
{
int yadd = dy < 0 ? -1 : BLOCKSIZE;
do
{
int stop = (Scale ((by << BLOCKBITS) + yadd - (y1 - miny), dx, dy) + (x1 - minx)) >> BLOCKBITS;
while (bx != stop)
{
block->Push (line);
block += xchange;
bx += xchange;
}
block->Push (line);
block += ymove;
by += ychange;
} while (by != by2);
while (block != endblock)
{
block->Push (line);
block += xchange;
}
block->Push (line);
}
else // Y-major
{
int xadd = dx < 0 ? -1 : BLOCKSIZE;
do
{
int stop = (Scale ((bx << BLOCKBITS) + xadd - (x1 - minx), dy, dx) + (y1 - miny)) >> BLOCKBITS;
while (by != stop)
{
block->Push (line);
block += ymove;
by += ychange;
}
block->Push (line);
block += xchange;
bx += xchange;
} while (bx != bx2);
while (block != endblock)
{
block->Push (line);
block += ymove;
}
block->Push (line);
}
}
}
BlockMap.Reserve (bmapwidth * bmapheight);
CreatePackedBlockmap (BlockLists, bmapwidth, bmapheight);
delete[] BlockLists;
}
void FBlockmapBuilder::CreateUnpackedBlockmap (TArray<WORD> *blocks, int bmapwidth, int bmapheight)
{
TArray<WORD> *block;
WORD zero = 0;
WORD terminator = 0xffff;
for (int i = 0; i < bmapwidth * bmapheight; ++i)
{
BlockMap[4+i] = WORD(BlockMap.Size());
BlockMap.Push (zero);
block = &blocks[i];
for (size_t j = 0; j < block->Size(); ++j)
{
BlockMap.Push ((*block)[j]);
}
BlockMap.Push (terminator);
}
}
static unsigned int BlockHash (TArray<WORD> *block)
{
int hash = 0;
WORD *ar = &(*block)[0];
for (size_t i = 0; i < block->Size(); ++i)
{
hash = hash * 12235 + ar[i];
}
return hash & 0x7fffffff;
}
static bool BlockCompare (TArray<WORD> *block1, TArray<WORD> *block2)
{
size_t size = block1->Size();
if (size != block2->Size())
{
return false;
}
if (size == 0)
{
return true;
}
WORD *ar1 = &(*block1)[0];
WORD *ar2 = &(*block2)[0];
for (size_t i = 0; i < size; ++i)
{
if (ar1[i] != ar2[i])
{
return false;
}
}
return true;
}
void FBlockmapBuilder::CreatePackedBlockmap (TArray<WORD> *blocks, int bmapwidth, int bmapheight)
{
WORD buckets[4096];
WORD *hashes, hashblock;
TArray<WORD> *block;
WORD zero = 0;
WORD terminator = 0xffff;
WORD *array;
int i, hash;
int hashed = 0, nothashed = 0;
hashes = new WORD[bmapwidth * bmapheight];
memset (hashes, 0xff, sizeof(WORD)*bmapwidth*bmapheight);
memset (buckets, 0xff, sizeof(buckets));
for (i = 0; i < bmapwidth * bmapheight; ++i)
{
block = &blocks[i];
hash = BlockHash (block) % 4096;
hashblock = buckets[hash];
while (hashblock != 0xffff)
{
if (BlockCompare (block, &blocks[hashblock]))
{
break;
}
hashblock = hashes[hashblock];
}
if (hashblock != 0xffff)
{
BlockMap[4+i] = BlockMap[4+hashblock];
hashed++;
}
else
{
hashes[i] = buckets[hash];
buckets[hash] = WORD(i);
BlockMap[4+i] = WORD(BlockMap.Size());
BlockMap.Push (zero);
array = &(*block)[0];
for (size_t j = 0; j < block->Size(); ++j)
{
BlockMap.Push (array[j]);
}
BlockMap.Push (terminator);
nothashed++;
}
}
delete[] hashes;
// printf ("%d blocks written, %d blocks saved\n", nothashed, hashed);
}

18
blockmapbuilder.h Normal file
View file

@ -0,0 +1,18 @@
#include "doomdata.h"
#include "workdata.h"
#include "tarray.h"
class FBlockmapBuilder
{
public:
FBlockmapBuilder (FLevel &level);
WORD *GetBlockmap (int &size);
private:
FLevel &Level;
TArray<WORD> BlockMap;
void BuildBlockmap ();
void CreateUnpackedBlockmap (TArray<WORD> *blocks, int bmapwidth, int bmapheight);
void CreatePackedBlockmap (TArray<WORD> *blocks, int bmapwidth, int bmapheight);
};

177
doomdata.h Normal file
View file

@ -0,0 +1,177 @@
#ifndef __DOOMDATA_H__
#define __DOOMDATA_H__
#ifdef _MSC_VER
#pragma once
#endif
enum
{
BOXTOP, BOXBOTTOM, BOXLEFT, BOXRIGHT
};
struct MapVertex
{
short x, y;
};
struct WideVertex
{
fixed_t x, y;
};
struct MapSideDef
{
short textureoffset;
short rowoffset;
char toptexture[8];
char bottomtexture[8];
char midtexture[8];
short sector;
};
struct MapLineDef
{
WORD v1;
WORD v2;
short flags;
short special;
short tag;
WORD sidenum[2];
};
struct MapLineDef2
{
WORD v1;
WORD v2;
short flags;
unsigned char special;
unsigned char args[5];
WORD sidenum[2];
};
struct MapSector
{
short floorheight;
short ceilingheight;
char floorpic[8];
char ceilingpic[8];
short lightlevel;
short special;
short tag;
};
struct MapSubsector
{
WORD numlines;
WORD firstline;
};
struct MapSubsectorEx
{
DWORD numlines;
DWORD firstline;
};
struct MapSeg
{
WORD v1;
WORD v2;
WORD angle;
WORD linedef;
short side;
short offset;
};
struct MapSegGL
{
WORD v1;
WORD v2;
WORD linedef;
WORD side;
WORD partner;
};
struct MapSegGLEx
{
WORD v1;
WORD v2;
WORD linedef;
WORD side;
DWORD partner;
};
#define NF_SUBSECTOR 0x8000
#define NFX_SUBSECTOR 0x80000000
struct MapNode
{
short x,y,dx,dy;
short bbox[2][4];
WORD children[2];
};
struct MapNodeEx
{
short x,y,dx,dy;
short bbox[2][4];
DWORD children[2];
};
struct MapThing
{
short x;
short y;
short angle;
short type;
short flags;
};
struct MapThing2
{
unsigned short thingid;
short x;
short y;
short z;
short angle;
short type;
short flags;
char special;
char args[5];
};
struct FLevel
{
FLevel ();
~FLevel ();
WideVertex *Vertices; int NumVertices;
MapSideDef *Sides; int NumSides;
MapLineDef2 *Lines; int NumLines;
MapSector *Sectors; int NumSectors;
MapSubsectorEx *Subsectors; int NumSubsectors;
MapSeg *Segs; int NumSegs;
MapNodeEx *Nodes; int NumNodes;
MapThing2 *Things; int NumThings;
WORD *Blockmap; int BlockmapSize;
BYTE *Reject; int RejectSize;
MapSubsectorEx *GLSubsectors; int NumGLSubsectors;
MapSegGLEx *GLSegs; int NumGLSegs;
MapNodeEx *GLNodes; int NumGLNodes;
WideVertex *GLVertices; int NumGLVertices;
BYTE *GLPVS; int GLPVSSize;
int NumOrgVerts;
void RemoveExtraLines ();
void RemoveExtraSides ();
void RemoveExtraSectors ();
};
const int BLOCKSIZE = 128;
const int BLOCKFRACSIZE = BLOCKSIZE<<FRACBITS;
const int BLOCKBITS = 7;
const int BLOCKFRACBITS = FRACBITS+7;
#endif //__DOOMDATA_H__

1053
getopt.c Normal file

File diff suppressed because it is too large Load diff

133
getopt.h Normal file
View file

@ -0,0 +1,133 @@
/* Declarations for getopt.
Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc.
NOTE: The canonical source of this file is maintained with the GNU C Library.
Bugs can be reported to bug-glibc@prep.ai.mit.edu.
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, 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 should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA. */
#ifndef _GETOPT_H
#define _GETOPT_H 1
#ifdef __cplusplus
extern "C" {
#endif
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
extern char *optarg;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns -1, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
extern int optind;
/* Callers store zero here to inhibit the error message `getopt' prints
for unrecognized options. */
extern int opterr;
/* Set to an option character which was unrecognized. */
extern int optopt;
/* Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
of `struct option' terminated by an element containing a name which is
zero.
The field `has_arg' is:
no_argument (or 0) if the option does not take an argument,
required_argument (or 1) if the option requires an argument,
optional_argument (or 2) if the option takes an optional argument.
If the field `flag' is not NULL, it points to a variable that is set
to the value given in the field `val' when the option is found, but
left unchanged if the option is not found.
To have a long-named option do something other than set an `int' to
a compiled-in constant, such as set a value from `optarg', set the
option's `flag' field to zero and its `val' field to a nonzero
value (the equivalent single-letter option character, if there is
one). For long options that have a zero `flag' field, `getopt'
returns the contents of the `val' field. */
struct option
{
#if defined (__STDC__) && __STDC__
const char *name;
#else
char *name;
#endif
/* has_arg can't be an enum because some compilers complain about
type mismatches in all the code that assumes it is an int. */
int has_arg;
int *flag;
int val;
};
/* Names for the values of the `has_arg' field of `struct option'. */
#define no_argument 0
#define required_argument 1
#define optional_argument 2
#if (defined (__STDC__) && __STDC__) || (defined (__cplusplus))
#ifdef __GNU_LIBRARY__
/* Many other libraries have conflicting prototypes for getopt, with
differences in the consts, in stdlib.h. To avoid compilation
errors, only prototype getopt for the GNU C library. */
extern int getopt (int argc, char *const *argv, const char *shortopts);
#else /* not __GNU_LIBRARY__ */
extern int getopt ();
#endif /* __GNU_LIBRARY__ */
extern int getopt_long (int argc, char *const *argv, const char *shortopts,
const struct option *longopts, int *longind);
extern int getopt_long_only (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind);
/* Internal only. Users should not call this directly. */
extern int _getopt_internal (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind,
int long_only);
#else /* not __STDC__ */
extern int getopt ();
extern int getopt_long ();
extern int getopt_long_only ();
extern int _getopt_internal ();
#endif /* __STDC__ */
#ifdef __cplusplus
}
#endif
#endif /* _GETOPT_H */

189
getopt1.c Normal file
View file

@ -0,0 +1,189 @@
/* getopt_long and getopt_long_only entry points for GNU getopt.
Copyright (C) 1987,88,89,90,91,92,93,94,96,97 Free Software Foundation, Inc.
NOTE: The canonical source of this file is maintained with the GNU C Library.
Bugs can be reported to bug-glibc@prep.ai.mit.edu.
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, 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 should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "getopt.h"
#if !defined (__STDC__) || !__STDC__
/* This is a separate conditional since some stdc systems
reject `defined (const)'. */
#ifndef const
#define const
#endif
#endif
#include <stdio.h>
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling
and linking in this code is a waste when using the GNU C library
(especially if it is a shared library). Rather than having every GNU
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
#define GETOPT_INTERFACE_VERSION 2
#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
#include <gnu-versions.h>
#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
#define ELIDE_CODE
#endif
#endif
#ifndef ELIDE_CODE
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
#include <stdlib.h>
#endif
#ifndef NULL
#define NULL 0
#endif
int
getopt_long (argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
const char *options;
const struct option *long_options;
int *opt_index;
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
}
/* Like getopt_long, but '-' as well as '--' can indicate a long option.
If an option that starts with '-' (not '--') doesn't match a long option,
but does match a short option, it is parsed as a short option
instead. */
int
getopt_long_only (argc, argv, options, long_options, opt_index)
int argc;
char *const *argv;
const char *options;
const struct option *long_options;
int *opt_index;
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
}
#endif /* Not ELIDE_CODE. */
#ifdef TEST
#include <stdio.h>
int
main (argc, argv)
int argc;
char **argv;
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] =
{
{"add", 1, 0, 0},
{"append", 0, 0, 0},
{"delete", 1, 0, 0},
{"verbose", 0, 0, 0},
{"create", 0, 0, 0},
{"file", 1, 0, 0},
{0, 0, 0, 0}
};
c = getopt_long (argc, argv, "abc:d:0123456789",
long_options, &option_index);
if (c == -1)
break;
switch (c)
{
case 0:
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value `%s'\n", optarg);
break;
case 'd':
printf ("option d with value `%s'\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
#endif /* TEST */

524
main.cpp Normal file
View file

@ -0,0 +1,524 @@
/*
The main glue for ZDBSP.
Copyright (C) 2002,2003 Randy Heit
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 should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
// HEADER FILES ------------------------------------------------------------
#ifdef _WIN32
// Need windows.h for QueryPerformanceCounter
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define HAVE_TIMING 1
#define START_COUNTER(s,e,f) \
LARGE_INTEGER s, e, f; QueryPerformanceCounter (&s);
#define END_COUNTER(s,e,f,l) \
QueryPerformanceCounter (&e); QueryPerformanceFrequency (&f); \
if (!NoTiming) printf (l, double(e.QuadPart - s.QuadPart) / double(f.QuadPart));
#else
#define HAVE_TIMING 0
#define START_COUNTER(s,e,f)
#define END_COUNTER(s,e,f)
// Need these to check if input/output are the same file
#include <sys/types.h>
#include <sys/stat.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdarg.h>
#include "zdbsp.h"
#include "wad.h"
#include "processor.h"
#include "getopt.h"
// MACROS ------------------------------------------------------------------
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
// TYPES -------------------------------------------------------------------
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
static void ParseArgs (int argc, char **argv);
static void ShowUsage ();
static void ShowVersion ();
static bool CheckInOutNames ();
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
extern "C" int optind;
extern "C" char *optarg;
// PUBLIC DATA DEFINITIONS -------------------------------------------------
const char *Map = NULL;
const char *InName;
const char *OutName = "tmp.wad";
bool BuildNodes = true;
bool BuildGLNodes = false;
bool ConformNodes = false;
bool NoPrune = false;
EBlockmapMode BlockmapMode = EBM_Rebuild;
ERejectMode RejectMode = ERM_DontTouch;
int MaxSegs = 64;
int SplitCost = 8;
int AAPreference = 16;
bool CheckPolyobjs = true;
bool ShowMap = false;
bool ShowWarnings = false;
bool NoTiming = false;
bool CompressNodes = false;
bool CompressGLNodes = false;
bool GLOnly = false;
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static option long_opts[] =
{
{"help", no_argument, 0, 1000},
{"version", no_argument, 0, 'V'},
{"view", no_argument, 0, 'v'},
{"warn", no_argument, 0, 'w'},
{"map", required_argument, 0, 'm'},
{"output", required_argument, 0, 'o'},
{"output-file", required_argument, 0, 'o'},
{"file", required_argument, 0, 'f'},
{"no-nodes", no_argument, 0, 'N'},
{"gl", no_argument, 0, 'g'},
{"gl-matching", no_argument, 0, 'G'},
{"empty-blockmap", no_argument, 0, 'b'},
{"empty-reject", no_argument, 0, 'r'},
{"zero-reject", no_argument, 0, 'R'},
{"full-reject", no_argument, 0, 'e'},
{"no-reject", no_argument, 0, 'E'},
{"partition", required_argument, 0, 'p'},
{"split-cost", required_argument, 0, 's'},
{"diagonal-cost", required_argument, 0, 'd'},
{"no-polyobjs", no_argument, 0, 'P'},
{"no-prune", no_argument, 0, 'q'},
{"no-timing", no_argument, 0, 't'},
{"compress", no_argument, 0, 'z'},
{"compress-normal", no_argument, 0, 'Z'},
{"gl-only", no_argument, 0, 'x'},
{0,0,0,0}
};
static const char short_opts[] = "wVgGvbNrReEm:o:f:p:s:d:PqtzZx";
// CODE --------------------------------------------------------------------
int main (int argc, char **argv)
{
bool fixSame = false;
ParseArgs (argc, argv);
if (InName == NULL)
{
if (optind >= argc || optind < argc-1)
{ // Source file is unspecified or followed by junk
ShowUsage ();
return 0;
}
InName = argv[optind];
}
try
{
START_COUNTER(t1a, t1b, t1c)
if (CheckInOutNames ())
{
// When the input and output files are the same, output will go to
// a temporary file. After everything is done, the input file is
// deleted and the output file is renamed to match the input file.
char *out = new char[strlen(OutName)+3], *dot;
if (out == NULL)
{
throw exception("Could not create temporary file name.");
}
strcpy (out, OutName);
dot = strrchr (out, '.');
if (dot && (dot[1] == 'w' || dot[1] == 'W')
&& (dot[2] == 'a' || dot[2] == 'A')
&& (dot[3] == 'd' || dot[3] == 'D')
&& dot[4] == 0)
{
// *.wad becomes *.daw
dot[1] = 'd';
dot[3] = 'w';
}
else
{
// * becomes *.x
strcat (out, ".x");
}
OutName = out;
fixSame = true;
}
{
FWadReader inwad (InName);
FWadWriter outwad (OutName, inwad.IsIWAD());
int lump = 0;
int max = inwad.NumLumps ();
while (lump < max)
{
if (inwad.IsMap (lump) &&
(!Map || stricmp (inwad.LumpName (lump), Map) == 0))
{
START_COUNTER(t2a, t2b, t2c)
FProcessor builder (inwad, lump);
builder.Write (outwad);
END_COUNTER(t2a, t2b, t2c, " %g seconds.\n")
lump = inwad.LumpAfterMap (lump);
}
else if (inwad.IsGLNodes (lump))
{
// Ignore GL nodes from the input for any maps we process.
if (BuildNodes && (Map == NULL || stricmp (inwad.LumpName (lump)+3, Map) == 0))
{
lump = inwad.SkipGLNodes (lump);
}
else
{
outwad.CopyLump (inwad, lump);
++lump;
}
}
else
{
//printf ("copy %s\n", inwad.LumpName (lump));
outwad.CopyLump (inwad, lump);
++lump;
}
}
outwad.Close ();
}
if (fixSame)
{
remove (InName);
if (0 != rename (OutName, InName))
{
printf ("The output file could not be renamed to %s.\nYou can find it as %s.\n",
InName, OutName);
}
}
END_COUNTER(t1a, t1b, t1c, "\nTotal time: %g seconds.\n")
}
catch (exception msg)
{
printf ("%s\n", msg.what());
return 20;
}
return 0;
}
//==========================================================================
//
// ParseArgs
//
//==========================================================================
static void ParseArgs (int argc, char **argv)
{
int ch;
while ((ch = getopt_long (argc, argv, short_opts, long_opts, NULL)) != EOF)
{
switch (ch)
{
case 0:
break;
case 'v':
ShowMap = true;
break;
case 'w':
ShowWarnings = true;
break;
case 'm':
Map = optarg;
break;
case 'o':
OutName = optarg;
break;
case 'f':
InName = optarg;
break;
case 'N':
BuildNodes = false;
break;
case 'b':
BlockmapMode = EBM_Create0;
break;
case 'r':
RejectMode = ERM_Create0;
break;
case 'R':
RejectMode = ERM_CreateZeroes;
break;
case 'e':
RejectMode = ERM_Rebuild;
break;
case 'E':
RejectMode = ERM_DontTouch;
break;
case 'p':
MaxSegs = atoi (optarg);
if (MaxSegs < 3)
{ // Don't be too unreasonable
MaxSegs = 3;
}
break;
case 's':
SplitCost = atoi (optarg);
if (SplitCost < 1)
{ // 1 means to add no extra weight at all
SplitCost = 1;
}
break;
case 'd':
AAPreference = atoi (optarg);
if (AAPreference < 1)
{
AAPreference = 1;
}
break;
case 'P':
CheckPolyobjs = false;
break;
case 'g':
BuildGLNodes = true;
ConformNodes = false;
break;
case 'G':
BuildGLNodes = true;
ConformNodes = true;
break;
case 'z':
CompressNodes = true;
CompressGLNodes = true;
break;
case 'Z':
CompressNodes = true;
CompressGLNodes = false;
break;
case 'x':
GLOnly = true;
BuildGLNodes = true;
ConformNodes = false;
break;
case 'q':
NoPrune = true;
break;
case 't':
NoTiming = true;
break;
case 'V':
ShowVersion ();
exit (0);
break;
case 1000:
ShowUsage ();
exit (0);
default:
printf ("Try `zdbsp --help' for more information.\n");
exit (0);
}
}
}
//==========================================================================
//
// ShowUsage
//
//==========================================================================
static void ShowUsage ()
{
printf (
"Usage: zdbsp [options] sourcefile.wad\n"
" -m, --map=MAP Only affect the specified map\n"
" -o, --output=FILE Write output to FILE instead of tmp.wad\n"
" -q, --no-prune Keep unused sidedefs and sectors\n"
" -N, --no-nodes Do not rebuild nodes\n"
" -g, --gl Build GL-friendly nodes\n"
" -G, --gl-matching Build GL-friendly nodes that match normal nodes\n"
" -x, --gl-only Only build GL-friendly nodes\n"
" -b, --empty-blockmap Create an empty blockmap\n"
" -r, --empty-reject Create an empty reject table\n"
" -R, --zero-reject Create a reject table of all zeroes\n"
//" -e, --full-reject Rebuild reject table (unsupported)\n"
" -E, --no-reject Leave reject table untouched\n"
" -p, --partition=NNN Maximum number of segs to consider at each node\n"// (default 64)\n"
" -s, --split-cost=NNN Adjusts the cost for splitting segs\n"// (default 8)\n"
" -d, --diagonal-cost=NNN Adjusts the cost for avoiding diagonal splitters\n"// (default 16)\n"
" -P, --no-polyobjs Do not check for polyobject subsector splits\n"
" -z, --compress Compress the nodes (including GL nodes, if created)\n"
" -Z, --compress-normal Compress normal nodes but not GL nodes\n"
#ifdef _WIN32
" -v, --view View the nodes\n"
#endif
" -w, --warn Show warning messages\n"
#if HAVE_TIMING
" -t, --no-timing Suppress timing information\n"
#endif
" -V, --version Display version information\n"
" --help Display this usage information\n"
);
}
//==========================================================================
//
// ShowVersion
//
//==========================================================================
static void ShowVersion ()
{
printf ("ZDBSP " ZDBSP_VERSION "\n");
}
//==========================================================================
//
// CheckInOutNames
//
// Returns true if InName and OutName refer to the same file. This needs
// to be implemented different under Windows than Unix because the inode
// information returned by stat is always 0, so it cannot be used to
// determine duplicate files.
//
//==========================================================================
static bool CheckInOutNames ()
{
#ifndef _WIN32
struct stat info;
dev_t outdev;
ino_t outinode;
if (0 != stat (OutName, &info))
{ // If out doesn't exist, it can't be duplicated
return false;
}
outdev = info.st_dev;
outinode = info.st_ino;
if (0 != stat (InName, &info))
{
return false;
}
return outinode == info.st_ino && outdev == info.st_dev;
#else
HANDLE inFile, outFile;
outFile = CreateFile (OutName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if (outFile == INVALID_HANDLE_VALUE)
{
return false;
}
inFile = CreateFile (InName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if (inFile == INVALID_HANDLE_VALUE)
{
CloseHandle (outFile);
return false;
}
BY_HANDLE_FILE_INFORMATION inInfo, outInfo;
bool same = false;
if (GetFileInformationByHandle (inFile, &inInfo) &&
GetFileInformationByHandle (outFile, &outInfo))
{
same = inInfo.dwVolumeSerialNumber == outInfo.dwVolumeSerialNumber &&
inInfo.nFileIndexLow == outInfo.nFileIndexLow &&
inInfo.nFileIndexHigh == outInfo.nFileIndexHigh;
}
CloseHandle (inFile);
CloseHandle (outFile);
return same;
#endif
}
//==========================================================================
//
// PointToAngle
//
//==========================================================================
angle_t PointToAngle (fixed_t x, fixed_t y)
{
const double rad2bam = double(1<<30) / M_PI;
double ang = atan2 (double(y), double(x));
if (ang < 0.0)
{
ang = 2*M_PI+ang;
}
return angle_t(ang * rad2bam) << 1;
}
//==========================================================================
//
// Warn
//
//==========================================================================
void Warn (const char *format, ...)
{
va_list marker;
if (!ShowWarnings)
{
return;
}
va_start (marker, format);
vprintf (format, marker);
va_end (marker);
}

1108
nodebuild.cpp Normal file

File diff suppressed because it is too large Load diff

189
nodebuild.h Normal file
View file

@ -0,0 +1,189 @@
#include "doomdata.h"
#include "workdata.h"
#include "tarray.h"
struct FEventInfo
{
int Vertex;
DWORD FrontSeg;
};
struct FEvent
{
FEvent *Parent, *Left, *Right;
enum { RED, BLACK } Color;
double Distance;
FEventInfo Info;
};
class FEventTree
{
public:
FEventTree ();
~FEventTree ();
FEvent *GetMinimum ();
FEvent *GetSuccessor (FEvent *event) const { FEvent *node = Successor(event); return node == &Nil ? NULL : node; }
FEvent *GetPredecessor (FEvent *event) const { FEvent *node = Predecessor(event); return node == &Nil ? NULL : node; }
FEvent *GetNewNode ();
void Insert (FEvent *event);
void Delete (FEvent *event);
FEvent *FindEvent (double distance) const;
void DeleteAll ();
private:
FEvent Nil;
FEvent *Root;
FEvent *Spare;
void LeftRotate (FEvent *event);
void RightRotate (FEvent *event);
void DeleteFixUp (FEvent *event);
void DeletionTraverser (FEvent *event);
FEvent *Successor (FEvent *event) const;
FEvent *Predecessor (FEvent *event) const;
};
class FNodeBuilder
{
struct FPrivSeg
{
int v1, v2;
int sidedef;
int linedef;
int frontsector;
int backsector;
DWORD next;
DWORD nextforvert;
DWORD nextforvert2;
int loopnum; // loop number for split avoidance (0 means splitting is okay)
DWORD partner; // seg on back side
DWORD storedseg; // seg # in the GL_SEGS lump
angle_t angle;
fixed_t offset;
int planenum;
bool planefront;
FPrivSeg *hashnext;
};
struct FPrivVert
{
fixed_t x, y;
DWORD segs; // segs that use this vertex as v1
DWORD segs2; // segs that use this vertex as v2
bool operator== (const FPrivVert &other)
{
return x == other.x && y == other.y;
}
};
struct FSimpleLine
{
fixed_t x, y, dx, dy;
};
union USegPtr
{
DWORD SegNum;
FPrivSeg *SegPtr;
};
struct FSplitSharer
{
double Distance;
DWORD Seg;
bool Forward;
};
public:
struct FPolyStart
{
int polynum;
fixed_t x, y;
};
FNodeBuilder (FLevel &level,
TArray<FPolyStart> &polyspots, TArray<FPolyStart> &anchors,
const char *name, bool makeGLnodes);
void GetVertices (WideVertex *&verts, int &count);
void GetNodes (MapNodeEx *&nodes, int &nodeCount,
MapSeg *&segs, int &segCount,
MapSubsectorEx *&ssecs, int &subCount);
void GetGLNodes (MapNodeEx *&nodes, int &nodeCount,
MapSegGLEx *&segs, int &segCount,
MapSubsectorEx *&ssecs, int &subCount);
// < 0 : in front of line
// == 0 : on line
// > 0 : behind line
static int PointOnSide (int x, int y, int x1, int y1, int dx, int dy);
private:
TArray<node_t> Nodes;
TArray<subsector_t> Subsectors;
TArray<DWORD> SubsectorSets;
TArray<FPrivSeg> Segs;
TArray<FPrivVert> Vertices;
TArray<USegPtr> SegList;
TArray<BYTE> PlaneChecked;
TArray<FSimpleLine> Planes;
size_t InitialVertices; // Number of vertices in a map that are connected to linedefs
TArray<int> Touched; // Loops a splitter touches on a vertex
TArray<int> Colinear; // Loops with edges colinear to a splitter
FEventTree Events; // Vertices intersected by the current splitter
TArray<FSplitSharer> SplitSharers; // Segs collinear with the current splitter
DWORD HackSeg; // Seg to force to back of splitter
FLevel &Level;
bool GLNodes;
// Progress meter stuff
int SegsStuffed;
const char *MapName;
void FindUsedVertices (WideVertex *vertices, int max);
int SelectVertexExact (FPrivVert &vertex);
void BuildTree ();
void MakeSegsFromSides ();
FPrivSeg *CheckSegForDuplicate (const FPrivSeg *check);
void GroupSegPlanes ();
void FindPolyContainers (TArray<FPolyStart> &spots, TArray<FPolyStart> &anchors);
bool GetPolyExtents (int polynum, fixed_t bbox[4]);
int MarkLoop (DWORD firstseg, int loopnum);
void AddSegToBBox (fixed_t bbox[4], const FPrivSeg *seg);
DWORD CreateNode (DWORD set, fixed_t bbox[4]);
DWORD CreateSubsector (DWORD set, fixed_t bbox[4]);
void CreateSubsectorsForReal ();
bool CheckSubsector (DWORD set, node_t &node, DWORD &splitseg, int setsize);
int SelectSplitter (DWORD set, node_t &node, DWORD &splitseg, int step, bool nosplit);
void SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &outset0, DWORD &outset1);
DWORD SplitSeg (DWORD segnum, int splitvert, int v1InFront);
int Heuristic (node_t &node, DWORD set, bool honorNoSplit);
int ClassifyLine (node_t &node, const FPrivSeg *seg, int &sidev1, int &sidev2);
int CountSegs (DWORD set) const;
void FixSplitSharers ();
double AddIntersection (const node_t &node, int vertex);
void AddMinisegs (const node_t &node, DWORD splitseg, DWORD &fset, DWORD &rset);
DWORD CheckLoopStart (fixed_t dx, fixed_t dy, int vertex1, int vertex2);
DWORD CheckLoopEnd (fixed_t dx, fixed_t dy, int vertex2);
void RemoveSegFromVert1 (DWORD segnum, int vertnum);
void RemoveSegFromVert2 (DWORD segnum, int vertnum);
DWORD AddMiniseg (int v1, int v2, DWORD partner, DWORD seg1, DWORD splitseg);
void SetNodeFromSeg (node_t &node, const FPrivSeg *pseg) const;
int RemoveMinisegs (MapNodeEx *nodes, TArray<MapSeg> &segs, MapSubsectorEx *subs, int node, short bbox[4]);
int StripMinisegs (TArray<MapSeg> &segs, int subsector, short bbox[4]);
void AddSegToShortBBox (short bbox[4], const FPrivSeg *seg);
int CloseSubsector (TArray<MapSegGLEx> &segs, int subsector);
DWORD PushGLSeg (TArray<MapSegGLEx> &segs, const FPrivSeg *seg);
void PushConnectingGLSeg (int subsector, TArray<MapSegGLEx> &segs, int v1, int v2);
static int SortSegs (const void *a, const void *b);
double InterceptVector (const node_t &splitter, const FPrivSeg &seg);
void PrintSet (int l, DWORD set);
};

407
nodebuild_events.cpp Normal file
View file

@ -0,0 +1,407 @@
/*
A red-black tree implementation for building minisegs.
Copyright (C) 2002,2003 Randy Heit
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 should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "zdbsp.h"
#include "nodebuild.h"
FEventTree::FEventTree ()
: Root (&Nil), Spare (NULL)
{
}
FEventTree::~FEventTree ()
{
FEvent *probe;
DeleteAll ();
probe = Spare;
while (probe != NULL)
{
FEvent *next = probe->Left;
delete probe;
probe = next;
}
}
void FEventTree::DeleteAll ()
{
DeletionTraverser (Root);
Root = &Nil;
}
void FEventTree::DeletionTraverser (FEvent *node)
{
if (node != &Nil && node != NULL)
{
DeletionTraverser (node->Left);
DeletionTraverser (node->Right);
node->Left = Spare;
Spare = node;
}
}
void FEventTree::LeftRotate (FEvent *x)
{
FEvent *y = x->Right;
x->Right = y->Left;
if (y->Left != &Nil)
{
y->Left->Parent = x;
}
y->Parent = x->Parent;
if (x->Parent != &Nil)
{
Root = y;
}
else if (x == x->Parent->Left)
{
x->Parent->Left = y;
}
else
{
x->Parent->Right = y;
}
y->Left = x;
x->Parent = y;
}
void FEventTree::RightRotate (FEvent *x)
{
FEvent *y = x->Left;
x->Left = y->Right;
if (y->Right != &Nil)
{
y->Right->Parent = x;
}
y->Parent = x->Parent;
if (x->Parent != &Nil)
{
Root = y;
}
else if (x == x->Parent->Left)
{
x->Parent->Left = y;
}
else
{
x->Parent->Right = y;
}
y->Right = x;
x->Parent = y;
}
FEvent *FEventTree::GetNewNode ()
{
FEvent *node;
if (Spare != NULL)
{
node = Spare;
Spare = node->Left;
}
else
{
node = new FEvent;
}
return node;
}
void FEventTree::Insert (FEvent *z)
{
FEvent *y = &Nil;
FEvent *x = Root;
while (x != &Nil)
{
y = x;
if (z->Distance < x->Distance)
{
x = x->Left;
}
else
{
x = x->Right;
}
}
z->Parent = y;
if (y == &Nil)
{
Root = z;
}
else if (z->Distance < y->Distance)
{
y->Left = z;
}
else
{
y->Right = z;
}
z->Left = &Nil;
z->Right = &Nil;
z->Color = FEvent::RED;
while (z != Root && z->Parent->Color != FEvent::RED)
{
if (z->Parent == z->Parent->Parent->Left)
{
y = z->Parent->Parent->Right;
if (y->Color == FEvent::RED)
{
z->Parent->Color = FEvent::BLACK;
y->Color = FEvent::BLACK;
z->Parent->Parent->Color = FEvent::RED;
z = z->Parent->Parent;
}
else
{
if (z == z->Parent->Right)
{
z = z->Parent;
LeftRotate (z);
}
z->Parent->Color = FEvent::BLACK;
z->Parent->Parent->Color = FEvent::RED;
RightRotate (z->Parent->Parent);
}
}
else
{
y = z->Parent->Parent->Left;
if (y->Color == FEvent::RED)
{
z->Parent->Color = FEvent::BLACK;
y->Color = FEvent::BLACK;
z->Parent->Parent->Color = FEvent::RED;
z = z->Parent->Parent;
}
else
{
if (z == z->Parent->Left)
{
z = z->Parent;
RightRotate (z);
}
z->Parent->Color = FEvent::BLACK;
z->Parent->Parent->Color = FEvent::RED;
RightRotate (z->Parent->Parent);
}
}
}
}
void FEventTree::Delete (FEvent *z)
{
FEvent *x, *y;
if (z->Left == &Nil || z->Right == &Nil)
{
y = z;
}
else
{
y = Successor (z);
}
if (y->Left != &Nil)
{
x = y->Left;
}
else
{
x = y->Right;
}
x->Parent = y->Parent;
if (y->Parent == &Nil)
{
Root = x;
}
else if (y == y->Parent->Left)
{
y->Parent->Left = x;
}
else
{
y->Parent->Right = x;
}
if (y != z)
{
z->Distance = y->Distance;
z->Info = y->Info;
}
if (y->Color == FEvent::BLACK)
{
DeleteFixUp (x);
}
y->Left = Spare;
Spare = y;
}
void FEventTree::DeleteFixUp (FEvent *x)
{
FEvent *w;
while (x != Root && x->Color == FEvent::BLACK)
{
if (x == x->Parent->Left)
{
w = x->Parent->Right;
if (w->Color == FEvent::RED)
{
w->Color = FEvent::BLACK;
x->Parent->Color = FEvent::RED;
LeftRotate (x->Parent);
w = x->Parent->Right;
}
if (w->Left->Color == FEvent::BLACK && w->Right->Color == FEvent::BLACK)
{
w->Color = FEvent::RED;
x = x->Parent;
}
else
{
if (w->Right->Color == FEvent::BLACK)
{
w->Left->Color = FEvent::BLACK;
w->Color = FEvent::RED;
RightRotate (w);
w = x->Parent->Right;
}
w->Color = x->Parent->Color;
x->Parent->Color = FEvent::BLACK;
w->Right->Color = FEvent::BLACK;
LeftRotate (x->Parent);
x = Root;
}
}
else
{
w = x->Parent->Left;
if (w->Color == FEvent::RED)
{
w->Color = FEvent::BLACK;
x->Parent->Color = FEvent::RED;
RightRotate (x->Parent);
w = x->Parent->Left;
}
if (w->Right->Color == FEvent::BLACK && w->Left->Color == FEvent::BLACK)
{
w->Color = FEvent::RED;
x = x->Parent;
}
else
{
if (w->Left->Color == FEvent::BLACK)
{
w->Right->Color = FEvent::BLACK;
w->Color = FEvent::RED;
LeftRotate (w);
w = x->Parent->Left;
}
w->Color = x->Parent->Color;
x->Parent->Color = FEvent::BLACK;
w->Left->Color = FEvent::BLACK;
RightRotate (x->Parent);
x = Root;
}
}
}
}
FEvent *FEventTree::Successor (FEvent *event) const
{
if (event->Right != &Nil)
{
event = event->Right;
while (event->Left != &Nil)
{
event = event->Left;
}
return event;
}
else
{
FEvent *y = event->Parent;
while (y != &Nil && event == y->Right)
{
event = y;
y = y->Parent;
}
return y;
}
}
FEvent *FEventTree::Predecessor (FEvent *event) const
{
if (event->Left != &Nil)
{
event = event->Left;
while (event->Right != &Nil)
{
event = event->Right;
}
return event;
}
else
{
FEvent *y = event->Parent;
while (y != &Nil && event == y->Left)
{
event = y;
y = y->Parent;
}
return y;
}
}
FEvent *FEventTree::FindEvent (double key) const
{
FEvent *node = Root;
while (node != &Nil)
{
if (node->Distance == key)
{
return node;
}
else if (node->Distance > key)
{
node = node->Left;
}
else
{
node = node->Right;
}
}
return NULL;
}
FEvent *FEventTree::GetMinimum ()
{
FEvent *node = Root;
if (node == &Nil)
{
return NULL;
}
while (node->Left != &Nil)
{
node = node->Left;
}
return node;
}

349
nodebuild_extract.cpp Normal file
View file

@ -0,0 +1,349 @@
/*
Routines for extracting usable data from the new BSP tree.
Copyright (C) 2002,2003 Randy Heit
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 should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <string.h>
#include <stdio.h>
#include "zdbsp.h"
#include "nodebuild.h"
#include "templates.h"
void FNodeBuilder::GetGLNodes (MapNodeEx *&outNodes, int &nodeCount,
MapSegGLEx *&outSegs, int &segCount,
MapSubsectorEx *&outSubs, int &subCount)
{
TArray<MapSegGLEx> segs (Segs.Size()*5/4);
int i, j, k;
nodeCount = Nodes.Size ();
outNodes = new MapNodeEx[nodeCount];
for (i = 0; i < nodeCount; ++i)
{
const node_t *orgnode = &Nodes[i];
MapNodeEx *newnode = &outNodes[i];
newnode->x = short(orgnode->x >> FRACBITS);
newnode->y = short(orgnode->y >> FRACBITS);
newnode->dx = short(orgnode->dx >> FRACBITS);
newnode->dy = short(orgnode->dy >> FRACBITS);
for (j = 0; j < 2; ++j)
{
for (k = 0; k < 4; ++k)
{
newnode->bbox[j][k] = orgnode->bbox[j][k] >> FRACBITS;
}
newnode->children[j] = orgnode->intchildren[j];
}
}
subCount = Subsectors.Size();
outSubs = new MapSubsectorEx[subCount];
for (i = 0; i < subCount; ++i)
{
int numsegs = CloseSubsector (segs, i);
outSubs[i].numlines = numsegs;
outSubs[i].firstline = segs.Size() - numsegs;
}
segCount = segs.Size ();
outSegs = new MapSegGLEx[segCount];
memcpy (outSegs, &segs[0], segCount*sizeof(MapSegGLEx));
for (i = 0; i < segCount; ++i)
{
if (outSegs[i].partner != DWORD_MAX)
{
outSegs[i].partner = Segs[outSegs[i].partner].storedseg;
}
}
}
int FNodeBuilder::CloseSubsector (TArray<MapSegGLEx> &segs, int subsector)
{
FPrivSeg *seg, *prev;
angle_t prevAngle;
double accumx, accumy;
fixed_t midx, midy;
int i, j, first, max, count, firstVert;
first = Subsectors[subsector].firstline;
max = first + Subsectors[subsector].numlines;
count = 0;
accumx = accumy = 0.0;
for (i = first; i < max; ++i)
{
seg = &Segs[SegList[i].SegNum];
accumx += double(Vertices[seg->v1].x) + double(Vertices[seg->v2].x);
accumy += double(Vertices[seg->v1].y) + double(Vertices[seg->v2].y);
}
midx = fixed_t(accumx / (max - first) / 2);
midy = fixed_t(accumy / (max - first) / 2);
seg = &Segs[SegList[first].SegNum];
prevAngle = PointToAngle (Vertices[seg->v1].x - midx, Vertices[seg->v1].y - midy);
seg->storedseg = PushGLSeg (segs, seg);
count = 1;
prev = seg;
firstVert = seg->v1;
#if 0
printf("--%d--\n", subsector);
for (j = first; j < max; ++j)
{
seg = &Segs[SegList[j].SegNum];
angle_t ang = PointToAngle (Vertices[seg->v1].x - midx, Vertices[seg->v1].y - midy);
printf ("%d: %5d(%5d,%5d)->%5d(%5d,%5d) - %3.3f\n", j,
seg->v1, Vertices[seg->v1].x>>16, Vertices[seg->v1].y>>16,
seg->v2, Vertices[seg->v2].x>>16, Vertices[seg->v2].y>>16,
double(ang/2)*180/(1<<30));
}
#endif
for (i = first + 1; i < max; ++i)
{
angle_t bestdiff = ANGLE_MAX;
FPrivSeg *bestseg = NULL;
int bestj = -1;
for (j = first; j < max; ++j)
{
seg = &Segs[SegList[j].SegNum];
angle_t ang = PointToAngle (Vertices[seg->v1].x - midx, Vertices[seg->v1].y - midy);
angle_t diff = prevAngle - ang;
if (seg->v1 == prev->v2)
{
bestdiff = diff;
bestseg = seg;
bestj = j;
break;
}
if (diff < bestdiff && diff > 0)
{
bestdiff = diff;
bestseg = seg;
bestj = j;
}
}
if (bestseg != NULL)
{
seg = bestseg;
}
if (prev->v2 != seg->v1)
{
// Add a new miniseg to connect the two segs
PushConnectingGLSeg (subsector, segs, prev->v2, seg->v1);
count++;
}
#if 0
printf ("+%d\n", bestj);
#endif
prevAngle -= bestdiff;
seg->storedseg = PushGLSeg (segs, seg);
count++;
prev = seg;
if (seg->v2 == firstVert)
{
prev = seg;
break;
}
}
#if 0
printf ("\n");
#endif
if (prev->v2 != firstVert)
{
PushConnectingGLSeg (subsector, segs, prev->v2, firstVert);
count++;
}
return count;
}
DWORD FNodeBuilder::PushGLSeg (TArray<MapSegGLEx> &segs, const FPrivSeg *seg)
{
MapSegGLEx newseg;
newseg.v1 = seg->v1;
newseg.v2 = seg->v2;
newseg.linedef = seg->linedef;
newseg.side = newseg.linedef != NO_INDEX
? Level.Lines[newseg.linedef].sidenum[1] == seg->sidedef ? 1 : 0
: 0;
newseg.partner = seg->partner;
return segs.Push (newseg);
}
void FNodeBuilder::PushConnectingGLSeg (int subsector, TArray<MapSegGLEx> &segs, int v1, int v2)
{
MapSegGLEx newseg;
Warn ("Unclosed subsector %d, from (%d,%d) to (%d,%d)\n", subsector,
Vertices[v1].x >> FRACBITS, Vertices[v1].y >> FRACBITS,
Vertices[v2].x >> FRACBITS, Vertices[v2].y >> FRACBITS);
newseg.v1 = v1;
newseg.v2 = v2;
newseg.linedef = NO_INDEX;
newseg.side = 0;
newseg.partner = DWORD_MAX;
segs.Push (newseg);
}
void FNodeBuilder::GetVertices (WideVertex *&verts, int &count)
{
count = Vertices.Size ();
verts = new WideVertex[count];
for (int i = 0; i < count; ++i)
{
verts[i].x = Vertices[i].x;
verts[i].y = Vertices[i].y;
}
}
void FNodeBuilder::GetNodes (MapNodeEx *&outNodes, int &nodeCount,
MapSeg *&outSegs, int &segCount,
MapSubsectorEx *&outSubs, int &subCount)
{
short bbox[4];
TArray<MapSeg> segs (Segs.Size());
// Walk the BSP and create a new BSP with only the information
// suitable for a standard tree. At a minimum, this means removing
// all minisegs. As an optional step, I also recompute all the
// nodes' bounding boxes so that they only bound the real segs and
// not the minisegs.
nodeCount = Nodes.Size ();
outNodes = new MapNodeEx[nodeCount];
subCount = Subsectors.Size ();
outSubs = new MapSubsectorEx[subCount];
RemoveMinisegs (outNodes, segs, outSubs, Nodes.Size() - 1, bbox);
segCount = segs.Size ();
outSegs = new MapSeg[segCount];
memcpy (outSegs, &segs[0], segCount*sizeof(MapSeg));
}
int FNodeBuilder::RemoveMinisegs (MapNodeEx *nodes,
TArray<MapSeg> &segs, MapSubsectorEx *subs, int node, short bbox[4])
{
if (node & NFX_SUBSECTOR)
{
int subnum = node == -1 ? 0 : node & ~NFX_SUBSECTOR;
int numsegs = StripMinisegs (segs, subnum, bbox);
subs[subnum].numlines = numsegs;
subs[subnum].firstline = segs.Size() - numsegs;
return NFX_SUBSECTOR | subnum;
}
else
{
const node_t *orgnode = &Nodes[node];
MapNodeEx *newnode = &nodes[node];
int child0 = RemoveMinisegs (nodes, segs, subs, orgnode->intchildren[0], newnode->bbox[0]);
int child1 = RemoveMinisegs (nodes, segs, subs, orgnode->intchildren[1], newnode->bbox[1]);
newnode->x = orgnode->x >> FRACBITS;
newnode->y = orgnode->y >> FRACBITS;
newnode->dx = orgnode->dx >> FRACBITS;
newnode->dy = orgnode->dy >> FRACBITS;
newnode->children[0] = child0;
newnode->children[1] = child1;
bbox[BOXTOP] = MAX(newnode->bbox[0][BOXTOP], newnode->bbox[1][BOXTOP]);
bbox[BOXBOTTOM] = MIN(newnode->bbox[0][BOXBOTTOM], newnode->bbox[1][BOXBOTTOM]);
bbox[BOXLEFT] = MIN(newnode->bbox[0][BOXLEFT], newnode->bbox[1][BOXLEFT]);
bbox[BOXRIGHT] = MAX(newnode->bbox[0][BOXRIGHT], newnode->bbox[1][BOXRIGHT]);
return node;
}
}
int FNodeBuilder::StripMinisegs (TArray<MapSeg> &segs, int subsector, short bbox[4])
{
int count, i, max;
// The bounding box is recomputed to only cover the real segs and not the
// minisegs in the subsector.
bbox[BOXTOP] = -32768;
bbox[BOXBOTTOM] = 32767;
bbox[BOXLEFT] = 32767;
bbox[BOXRIGHT] = -32768;
i = Subsectors[subsector].firstline;
max = Subsectors[subsector].numlines + i;
for (count = 0; i < max; ++i)
{
const FPrivSeg *org = &Segs[SegList[i].SegNum];
// Because of the ordering guaranteed by SortSegs(), all mini segs will
// be at the end of the subsector, so once one is encountered, we can
// stop right away.
if (org->linedef == -1)
{
break;
}
else
{
MapSeg newseg;
AddSegToShortBBox (bbox, org);
newseg.v1 = org->v1;
newseg.v2 = org->v2;
newseg.angle = org->angle >> 16;
newseg.offset = org->offset >> FRACBITS;
newseg.linedef = org->linedef;
newseg.side = Level.Lines[org->linedef].sidenum[1] == org->sidedef ? 1 : 0;
segs.Push (newseg);
++count;
}
}
return count;
}
void FNodeBuilder::AddSegToShortBBox (short bbox[4], const FPrivSeg *seg)
{
const FPrivVert *v1 = &Vertices[seg->v1];
const FPrivVert *v2 = &Vertices[seg->v2];
short v1x = v1->x >> FRACBITS;
short v1y = v1->y >> FRACBITS;
short v2x = v2->x >> FRACBITS;
short v2y = v2->y >> FRACBITS;
if (v1x < bbox[BOXLEFT]) bbox[BOXLEFT] = v1x;
if (v1x > bbox[BOXRIGHT]) bbox[BOXRIGHT] = v1x;
if (v1y < bbox[BOXBOTTOM]) bbox[BOXBOTTOM] = v1y;
if (v1y > bbox[BOXTOP]) bbox[BOXTOP] = v1y;
if (v2x < bbox[BOXLEFT]) bbox[BOXLEFT] = v2x;
if (v2x > bbox[BOXRIGHT]) bbox[BOXRIGHT] = v2x;
if (v2y < bbox[BOXBOTTOM]) bbox[BOXBOTTOM] = v2y;
if (v2y > bbox[BOXTOP]) bbox[BOXTOP] = v2y;
}

388
nodebuild_gl.cpp Normal file
View file

@ -0,0 +1,388 @@
/*
Routines only necessary for building GL-friendly nodes.
Copyright (C) 2002,2003 Randy Heit
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 should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <assert.h>
#include "zdbsp.h"
#include "nodebuild.h"
#define Printf printf
#if 0
#include <stdio.h>
#define D(x) x
#else
#define D(x) do{}while(0)
#endif
double FNodeBuilder::AddIntersection (const node_t &node, int vertex)
{
static const FEventInfo defaultInfo =
{
-1, DWORD_MAX
};
// Calculate signed distance of intersection vertex from start of splitter.
// Only ordering is important, so we don't need a sqrt.
FPrivVert *v = &Vertices[vertex];
double dx = double(v->x - node.x);
double dy = double(v->y - node.y);
double dist = dx*dx + dy*dy;
if (node.dx != 0)
{
if ((node.dx > 0 && dx < 0.0) || (node.dx < 0 && dx > 0.0))
{
dist = -dist;
}
}
else
{
if ((node.dy > 0 && dy < 0.0) || (node.dy < 0 && dy > 0.0))
{
dist = -dist;
}
}
FEvent *event = Events.FindEvent (dist);
if (event == NULL)
{
event = Events.GetNewNode ();
event->Distance = dist;
event->Info = defaultInfo;
event->Info.Vertex = vertex;
Events.Insert (event);
}
return dist;
}
// If there are any segs on the splitter that span more than two events, they
// must be split. Alien Vendetta is one example wad that is quite bad about
// having overlapping lines. If we skip this step, these segs will still be
// split later, but minisegs will erroneously be added for them, and partner
// seg information will be messed up in the generated tree.
void FNodeBuilder::FixSplitSharers ()
{
for (size_t i = 0; i < SplitSharers.Size(); ++i)
{
DWORD seg = SplitSharers[i].Seg;
int v2 = Segs[seg].v2;
FEvent *event = Events.FindEvent (SplitSharers[i].Distance);
FEvent *next;
if (event == NULL)
{ // Should not happen
continue;
}
if (SplitSharers[i].Forward)
{
event = Events.GetSuccessor (event);
if (event == NULL)
{
continue;
}
next = Events.GetSuccessor (event);
}
else
{
event = Events.GetPredecessor (event);
if (event == NULL)
{
continue;
}
next = Events.GetPredecessor (event);
}
while (event != NULL && next != NULL && event->Info.Vertex != v2)
{
D(Printf("Forced split of seg %d(%d->%d) at %d(%d,%d)\n", seg,
Segs[seg].v1, Segs[seg].v2,
event->Info.Vertex,
Vertices[event->Info.Vertex].x>>16,
Vertices[event->Info.Vertex].y>>16));
DWORD newseg = SplitSeg (seg, event->Info.Vertex, 1);
Segs[newseg].next = Segs[seg].next;
Segs[seg].next = newseg;
DWORD partner = Segs[seg].partner;
if (partner != DWORD_MAX)
{
int endpartner = SplitSeg (partner, event->Info.Vertex, 1);
Segs[endpartner].next = Segs[partner].next;
Segs[partner].next = endpartner;
Segs[seg].partner = endpartner;
//Segs[endpartner].partner = seg;
Segs[partner].partner = newseg;
assert (Segs[Segs[seg].partner].partner == seg);
assert (Segs[Segs[newseg].partner].partner == newseg);
assert (Segs[seg].v1 == Segs[endpartner].v2);
assert (Segs[seg].v2 == Segs[endpartner].v1);
assert (Segs[partner].v1 == Segs[newseg].v2);
assert (Segs[partner].v2 == Segs[newseg].v1);
}
seg = newseg;
if (SplitSharers[i].Forward)
{
event = next;
next = Events.GetSuccessor (next);
}
else
{
event = next;
next = Events.GetPredecessor (next);
}
}
}
}
void FNodeBuilder::AddMinisegs (const node_t &node, DWORD splitseg, DWORD &fset, DWORD &bset)
{
FEvent *event = Events.GetMinimum (), *prev = NULL;
while (event != NULL)
{
if (prev != NULL)
{
DWORD fseg1, bseg1, fseg2, bseg2;
DWORD fnseg, bnseg;
// Minisegs should only be added when they can create valid loops on both the front and
// back of the splitter. This means some subsectors could be unclosed if their sectors
// are unclosed, but at least we won't be needlessly creating subsectors in void space.
// Unclosed subsectors can be closed trivially once the BSP tree is complete.
if ((fseg1 = CheckLoopStart (node.dx, node.dy, prev->Info.Vertex, event->Info.Vertex)) != DWORD_MAX &&
(bseg1 = CheckLoopStart (-node.dx, -node.dy, event->Info.Vertex, prev->Info.Vertex)) != DWORD_MAX &&
(fseg2 = CheckLoopEnd (node.dx, node.dy, event->Info.Vertex)) != DWORD_MAX &&
(bseg2 = CheckLoopEnd (-node.dx, -node.dy, prev->Info.Vertex)) != DWORD_MAX)
{
// Add miniseg on the front side
fnseg = AddMiniseg (prev->Info.Vertex, event->Info.Vertex, DWORD_MAX, fseg1, splitseg);
Segs[fnseg].next = fset;
fset = fnseg;
// Add miniseg on the back side
bnseg = AddMiniseg (event->Info.Vertex, prev->Info.Vertex, fnseg, bseg1, splitseg);
Segs[bnseg].next = bset;
bset = bnseg;
int fsector, bsector;
fsector = Segs[fseg1].frontsector;
bsector = Segs[bseg1].frontsector;
Segs[fnseg].frontsector = fsector;
Segs[fnseg].backsector = bsector;
Segs[bnseg].frontsector = bsector;
Segs[bnseg].backsector = fsector;
// Only print the warning if this might be bad.
if (fsector != bsector &&
fsector != Segs[fseg1].backsector &&
bsector != Segs[bseg1].backsector)
{
Warn ("Sectors %d at (%d,%d) and %d at (%d,%d) don't match.\n",
Segs[fseg1].frontsector,
Vertices[prev->Info.Vertex].x>>FRACBITS, Vertices[prev->Info.Vertex].y>>FRACBITS,
Segs[bseg1].frontsector,
Vertices[event->Info.Vertex].x>>FRACBITS, Vertices[event->Info.Vertex].y>>FRACBITS
);
}
D(Printf ("**Minisegs** %d/%d added %d(%d,%d)->%d(%d,%d)\n", fnseg, bnseg,
prev->Info.Vertex,
Vertices[prev->Info.Vertex].x>>16, Vertices[prev->Info.Vertex].y>>16,
event->Info.Vertex,
Vertices[event->Info.Vertex].x>>16, Vertices[event->Info.Vertex].y>>16));
}
}
prev = event;
event = Events.GetSuccessor (event);
}
}
DWORD FNodeBuilder::AddMiniseg (int v1, int v2, DWORD partner, DWORD seg1, DWORD splitseg)
{
DWORD nseg;
FPrivSeg *seg = &Segs[seg1];
FPrivSeg newseg;
newseg.sidedef = NO_INDEX;
newseg.linedef = -1;
newseg.loopnum = 0;
newseg.next = DWORD_MAX;
newseg.planefront = true;
if (splitseg != DWORD_MAX)
{
newseg.planenum = Segs[splitseg].planenum;
}
else
{
newseg.planenum = -1;
}
newseg.v1 = v1;
newseg.v2 = v2;
newseg.nextforvert = Vertices[v1].segs;
newseg.nextforvert2 = Vertices[v2].segs2;
newseg.next = seg->next;
if (partner != DWORD_MAX)
{
newseg.partner = partner;
assert (Segs[partner].v1 == newseg.v2);
assert (Segs[partner].v2 == newseg.v1);
}
else
{
newseg.partner = DWORD_MAX;
}
nseg = Segs.Push (newseg);
if (newseg.partner != DWORD_MAX)
{
Segs[partner].partner = nseg;
}
Vertices[v1].segs = nseg;
Vertices[v2].segs2 = nseg;
//Printf ("Between %d and %d::::\n", seg1, seg2);
return nseg;
}
DWORD FNodeBuilder::CheckLoopStart (fixed_t dx, fixed_t dy, int vertex, int vertex2)
{
FPrivVert *v = &Vertices[vertex];
angle_t splitAngle = PointToAngle (dx, dy);
DWORD segnum;
angle_t bestang;
DWORD bestseg;
// Find the seg ending at this vertex that forms the smallest angle
// to the splitter.
segnum = v->segs2;
bestang = ANGLE_MAX;
bestseg = DWORD_MAX;
while (segnum != DWORD_MAX)
{
FPrivSeg *seg = &Segs[segnum];
angle_t segAngle = PointToAngle (Vertices[seg->v1].x - v->x, Vertices[seg->v1].y - v->y);
angle_t diff = splitAngle - segAngle;
if (diff < ANGLE_EPSILON &&
PointOnSide (Vertices[seg->v1].x, Vertices[seg->v1].y, v->x, v->y, dx, dy) == 0)
{
// If a seg lies right on the splitter, don't count it
}
else
{
if (diff <= bestang)
{
bestang = diff;
bestseg = segnum;
}
}
segnum = seg->nextforvert2;
}
if (bestseg == DWORD_MAX)
{
return DWORD_MAX;
}
// Now make sure there are no segs starting at this vertex that form
// an even smaller angle to the splitter.
segnum = v->segs;
while (segnum != DWORD_MAX)
{
FPrivSeg *seg = &Segs[segnum];
if (seg->v2 == vertex2)
{
return DWORD_MAX;
}
angle_t segAngle = PointToAngle (Vertices[seg->v2].x - v->x, Vertices[seg->v2].y - v->y);
angle_t diff = splitAngle - segAngle;
if (diff < bestang && seg->partner != bestseg)
{
return DWORD_MAX;
}
segnum = seg->nextforvert;
}
return bestseg;
}
DWORD FNodeBuilder::CheckLoopEnd (fixed_t dx, fixed_t dy, int vertex)
{
FPrivVert *v = &Vertices[vertex];
angle_t splitAngle = PointToAngle (dx, dy) + ANGLE_180;
DWORD segnum;
angle_t bestang;
DWORD bestseg;
// Find the seg starting at this vertex that forms the smallest angle
// to the splitter.
segnum = v->segs;
bestang = ANGLE_MAX;
bestseg = DWORD_MAX;
while (segnum != DWORD_MAX)
{
FPrivSeg *seg = &Segs[segnum];
angle_t segAngle = PointToAngle (Vertices[seg->v2].x - v->x, Vertices[seg->v2].y - v->y);
angle_t diff = segAngle - splitAngle;
if (diff < ANGLE_EPSILON &&
PointOnSide (Vertices[seg->v1].x, Vertices[seg->v1].y, v->x, v->y, dx, dy) == 0)
{
// If a seg lies right on the splitter, don't count it
}
else
{
if (diff <= bestang)
{
bestang = diff;
bestseg = segnum;
}
}
segnum = seg->nextforvert;
}
if (bestseg == DWORD_MAX)
{
return DWORD_MAX;
}
// Now make sure there are no segs ending at this vertex that form
// an even smaller angle to the splitter.
segnum = v->segs2;
while (segnum != DWORD_MAX)
{
FPrivSeg *seg = &Segs[segnum];
angle_t segAngle = PointToAngle (Vertices[seg->v1].x - v->x, Vertices[seg->v1].y - v->y);
angle_t diff = segAngle - splitAngle;
if (diff < bestang && seg->partner != bestseg)
{
return DWORD_MAX;
}
segnum = seg->nextforvert2;
}
return bestseg;
}

500
nodebuild_utility.cpp Normal file
View file

@ -0,0 +1,500 @@
/*
Various utility functions.
Copyright (C) 2002,2003 Randy Heit
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 should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <malloc.h>
#include <string.h>
#include <stdio.h>
#include "zdbsp.h"
#include "nodebuild.h"
static const int PO_LINE_START = 1;
static const int PO_LINE_EXPLICIT = 5;
#if 0
#define D(x) x
#else
#define D(x) do{}while(0)
#endif
#if 0
#define P(x) x
#define Printf printf
#else
#define P(x) do{}while(0)
#endif
void FNodeBuilder::FindUsedVertices (WideVertex *oldverts, int max)
{
size_t *map = (size_t *)alloca (max*sizeof(size_t));
int i;
FPrivVert newvert;
memset (&map[0], -1, sizeof(size_t)*max);
newvert.segs = DWORD_MAX;
newvert.segs2 = DWORD_MAX;
for (i = 0; i < Level.NumLines; ++i)
{
int v1 = Level.Lines[i].v1;
int v2 = Level.Lines[i].v2;
if (map[v1] == (size_t)-1)
{
newvert.x = oldverts[v1].x;
newvert.y = oldverts[v1].y;
map[v1] = SelectVertexExact (newvert);
}
if (map[v2] == (size_t)-1)
{
newvert.x = oldverts[v2].x;
newvert.y = oldverts[v2].y;
map[v2] = SelectVertexExact (newvert);
}
Level.Lines[i].v1 = map[v1];
Level.Lines[i].v2 = map[v2];
}
InitialVertices = Vertices.Size ();
Level.NumOrgVerts = InitialVertices;
}
int FNodeBuilder::SelectVertexExact (FPrivVert &vertex)
{
for (size_t i = 0; i < Vertices.Size(); ++i)
{
if (Vertices[i].x == vertex.x && Vertices[i].y == vertex.y)
{
return (int)i;
}
}
return (int)Vertices.Push (vertex);
}
// For every sidedef in the map, create a corresponding seg.
void FNodeBuilder::MakeSegsFromSides ()
{
FPrivSeg *share1, *share2;
FPrivSeg seg;
int i, j;
seg.next = DWORD_MAX;
seg.loopnum = 0;
seg.offset = 0;
seg.partner = DWORD_MAX;
for (i = 0; i < Level.NumLines; ++i)
{
if (Level.Lines[i].sidenum[0] != NO_INDEX)
{
WORD backside;
seg.linedef = i;
seg.sidedef = Level.Lines[i].sidenum[0];
backside = Level.Lines[i].sidenum[1];
seg.frontsector = Level.Sides[seg.sidedef].sector;
seg.backsector = backside != NO_INDEX ? Level.Sides[backside].sector : -1;
seg.v1 = Level.Lines[i].v1;
seg.v2 = Level.Lines[i].v2;
seg.nextforvert = Vertices[seg.v1].segs;
seg.nextforvert2 = Vertices[seg.v2].segs2;
share1 = CheckSegForDuplicate (&seg);
if (share1 == NULL)
{
seg.angle = PointToAngle (Vertices[seg.v2].x-Vertices[seg.v1].x,
Vertices[seg.v2].y-Vertices[seg.v1].y);
j = (int)Segs.Push (seg);
Vertices[seg.v1].segs = j;
Vertices[seg.v2].segs2 = j;
}
else
{
printf ("Linedefs %d and %d share endpoints.\n", i, share1->linedef);
}
}
else
{
printf ("Linedef %d does not have a front side.\n", i);
}
if (Level.Lines[i].sidenum[1] != NO_INDEX)
{
WORD backside;
seg.linedef = i;
seg.sidedef = Level.Lines[i].sidenum[1];
backside = Level.Lines[i].sidenum[0];
seg.frontsector = Level.Sides[seg.sidedef].sector;
seg.backsector = backside != NO_INDEX ? Level.Sides[backside].sector : -1;
seg.v1 = Level.Lines[i].v2;
seg.v2 = Level.Lines[i].v1;
seg.nextforvert = Vertices[seg.v1].segs;
seg.nextforvert2 = Vertices[seg.v2].segs2;
seg.angle = PointToAngle (Vertices[seg.v2].x-Vertices[seg.v1].x,
Vertices[seg.v2].y-Vertices[seg.v1].y);
share2 = CheckSegForDuplicate (&seg);
if (share2 == NULL)
{
j = (int)Segs.Push (seg);
Vertices[seg.v1].segs = j;
Vertices[seg.v2].segs2 = j;
if (Level.Lines[i].sidenum[0] != NO_INDEX && share1 == NULL)
{
Segs[j-1].partner = j;
Segs[j].partner = j-1;
}
}
else if (share2->linedef != share1->linedef)
{
printf ("Linedefs %d and %d share endpoints.\n", i, share2->linedef);
}
}
}
}
// Check for another seg with the same start and end vertices as this one.
// Combined with its use above, this will find two-sided lines that are shadowed
// by another one- or two-sided line, and it will also find one-sided lines that
// shadow each other. It will not find one-sided lines that share endpoints but
// face opposite directions. Although they should probably be a single two-sided
// line, leaving them in will not generate bad nodes.
FNodeBuilder::FPrivSeg *FNodeBuilder::CheckSegForDuplicate (const FNodeBuilder::FPrivSeg *check)
{
DWORD segnum;
// Check for segs facing the same direction
for (segnum = check->nextforvert; segnum != DWORD_MAX; segnum = Segs[segnum].nextforvert)
{
if (Segs[segnum].v2 == check->v2)
{
return &Segs[segnum];
}
}
return NULL;
}
// Group colinear segs together so that only one seg per line needs to be checked
// by SelectSplitter().
void FNodeBuilder::GroupSegPlanes ()
{
const int bucketbits = 12;
FPrivSeg *buckets[1<<bucketbits] = { 0 };
int i, planenum;
for (i = 0; i < (int)Segs.Size(); ++i)
{
FPrivSeg *seg = &Segs[i];
seg->next = i+1;
seg->hashnext = NULL;
}
Segs[Segs.Size()-1].next = DWORD_MAX;
for (i = planenum = 0; i < (int)Segs.Size(); ++i)
{
FPrivSeg *seg = &Segs[i];
fixed_t x1 = Vertices[seg->v1].x;
fixed_t y1 = Vertices[seg->v1].y;
fixed_t x2 = Vertices[seg->v2].x;
fixed_t y2 = Vertices[seg->v2].y;
angle_t ang = PointToAngle (x2 - x1, y2 - y1);
if (ang >= 1u<<31)
ang += 1u<<31;
FPrivSeg *check = buckets[ang >>= 31-bucketbits];
while (check != NULL)
{
fixed_t cx1 = Vertices[check->v1].x;
fixed_t cy1 = Vertices[check->v1].y;
fixed_t cdx = Vertices[check->v2].x - cx1;
fixed_t cdy = Vertices[check->v2].y - cy1;
if (PointOnSide (x1, y1, cx1, cy1, cdx, cdy) == 0 &&
PointOnSide (x2, y2, cx1, cy1, cdx, cdy) == 0)
{
break;
}
check = check->hashnext;
}
if (check != NULL)
{
seg->planenum = check->planenum;
const FSimpleLine *line = &Planes[seg->planenum];
if (line->dx != 0)
{
if ((line->dx > 0 && x2 > x1) || (line->dx < 0 && x2 < x1))
{
seg->planefront = true;
}
else
{
seg->planefront = false;
}
}
else
{
if ((line->dy > 0 && y2 > y1) || (line->dy < 0 && y2 < y1))
{
seg->planefront = true;
}
else
{
seg->planefront = false;
}
}
}
else
{
seg->hashnext = buckets[ang];
buckets[ang] = seg;
seg->planenum = planenum++;
seg->planefront = true;
FSimpleLine pline = { Vertices[seg->v1].x,
Vertices[seg->v1].y,
Vertices[seg->v2].x - Vertices[seg->v1].x,
Vertices[seg->v2].y - Vertices[seg->v1].y };
Planes.Push (pline);
}
}
D(Printf ("%d planes from %d segs\n", planenum, Segs.Size()));
planenum = (planenum+7)/8;
PlaneChecked.Reserve (planenum);
}
// Find "loops" of segs surrounding polyobject's origin. Note that a polyobject's origin
// is not solely defined by the polyobject's anchor, but also by the polyobject itself.
// For the split avoidance to work properly, you must have a convex, complete loop of
// segs surrounding the polyobject origin. All the maps in hexen.wad have complete loops of
// segs around their polyobjects, but they are not all convex: The doors at the start of MAP01
// and some of the pillars in MAP02 that surround the entrance to MAP06 are not convex.
// Heuristic() uses some special weighting to make these cases work properly.
void FNodeBuilder::FindPolyContainers (TArray<FPolyStart> &spots, TArray<FPolyStart> &anchors)
{
int loop = 1;
for (size_t i = 0; i < spots.Size(); ++i)
{
FPolyStart *spot = &spots[i];
fixed_t bbox[4];
if (GetPolyExtents (spot->polynum, bbox))
{
FPolyStart *anchor;
size_t j;
for (j = 0; j < anchors.Size(); ++j)
{
anchor = &anchors[j];
if (anchor->polynum == spot->polynum)
{
break;
}
}
if (j < anchors.Size())
{
vertex_t mid;
vertex_t center;
mid.x = bbox[BOXLEFT] + (bbox[BOXRIGHT]-bbox[BOXLEFT])/2;
mid.y = bbox[BOXBOTTOM] + (bbox[BOXTOP]-bbox[BOXBOTTOM])/2;
center.x = mid.x - anchor->x + spot->x;
center.y = mid.y - anchor->y + spot->y;
// Scan right for the seg closest to the polyobject's center after it
// gets moved to its start spot.
fixed_t closestdist = FIXED_MAX;
DWORD closestseg = 0;
P(Printf ("start %d,%d -- center %d, %d\n", spot->x>>16, spot->y>>16, center.x>>16, center.y>>16));
for (size_t j = 0; j < Segs.Size(); ++j)
{
FPrivSeg *seg = &Segs[j];
FPrivVert *v1 = &Vertices[seg->v1];
FPrivVert *v2 = &Vertices[seg->v2];
fixed_t dy = v2->y - v1->y;
if (dy == 0)
{ // Horizontal, so skip it
continue;
}
if ((v1->y < center.y && v2->y < center.y) || (v1->y > center.y && v2->y > center.y))
{ // Not crossed
continue;
}
fixed_t dx = v2->x - v1->x;
if (PointOnSide (center.x, center.y, v1->x, v1->y, dx, dy) <= 0)
{
fixed_t t = DivScale30 (center.y - v1->y, dy);
fixed_t sx = v1->x + MulScale30 (dx, t);
fixed_t dist = sx - spot->x;
if (dist < closestdist && dist >= 0)
{
closestdist = dist;
closestseg = (long)j;
}
}
}
if (closestseg >= 0)
{
loop = MarkLoop (closestseg, loop);
P(Printf ("Found polyobj in sector %d (loop %d)\n", Segs[closestseg].frontsector,
Segs[closestseg].loopnum));
}
}
}
}
}
int FNodeBuilder::MarkLoop (DWORD firstseg, int loopnum)
{
int seg;
int sec = Segs[firstseg].frontsector;
if (Segs[firstseg].loopnum != 0)
{ // already marked
return loopnum;
}
seg = firstseg;
do
{
FPrivSeg *s1 = &Segs[seg];
s1->loopnum = loopnum;
P(Printf ("Mark seg %d (%d,%d)-(%d,%d)\n", seg,
Vertices[s1->v1].x>>16, Vertices[s1->v1].y>>16,
Vertices[s1->v2].x>>16, Vertices[s1->v2].y>>16));
DWORD bestseg = DWORD_MAX;
DWORD tryseg = Vertices[s1->v2].segs;
angle_t bestang = ANGLE_MAX;
angle_t ang1 = s1->angle;
while (tryseg != DWORD_MAX)
{
FPrivSeg *s2 = &Segs[tryseg];
if (s2->frontsector == sec)
{
angle_t ang2 = s2->angle + ANGLE_180;
angle_t angdiff = ang2 - ang1;
if (angdiff < bestang && angdiff > 0)
{
bestang = angdiff;
bestseg = tryseg;
}
}
tryseg = s2->nextforvert;
}
seg = bestseg;
} while (seg != DWORD_MAX && Segs[seg].loopnum == 0);
return loopnum + 1;
}
// Find the bounding box for a specific polyobject.
bool FNodeBuilder::GetPolyExtents (int polynum, fixed_t bbox[4])
{
size_t i;
bbox[BOXLEFT] = bbox[BOXBOTTOM] = FIXED_MAX;
bbox[BOXRIGHT] = bbox[BOXTOP] = FIXED_MIN;
// Try to find a polyobj marked with a start line
for (i = 0; i < Segs.Size(); ++i)
{
if (Level.Lines[Segs[i].linedef].special == PO_LINE_START &&
Level.Lines[Segs[i].linedef].args[0] == polynum)
{
break;
}
}
if (i < Segs.Size())
{
vertex_t start;
size_t vert;
vert = Segs[i].v1;
start.x = Vertices[vert].x;
start.y = Vertices[vert].y;
do
{
AddSegToBBox (bbox, &Segs[i]);
vert = Segs[i].v2;
i = Vertices[vert].segs;
} while (i != DWORD_MAX && (Vertices[vert].x != start.x || Vertices[vert].y != start.y));
return true;
}
// Try to find a polyobj marked with explicit lines
bool found = false;
for (i = 0; i < Segs.Size(); ++i)
{
if (Level.Lines[Segs[i].linedef].special == PO_LINE_EXPLICIT &&
Level.Lines[Segs[i].linedef].args[0] == polynum)
{
AddSegToBBox (bbox, &Segs[i]);
found = true;
}
}
return found;
}
void FNodeBuilder::AddSegToBBox (fixed_t bbox[4], const FPrivSeg *seg)
{
FPrivVert *v1 = &Vertices[seg->v1];
FPrivVert *v2 = &Vertices[seg->v2];
if (v1->x < bbox[BOXLEFT]) bbox[BOXLEFT] = v1->x;
if (v1->x > bbox[BOXRIGHT]) bbox[BOXRIGHT] = v1->x;
if (v1->y < bbox[BOXBOTTOM]) bbox[BOXBOTTOM] = v1->y;
if (v1->y > bbox[BOXTOP]) bbox[BOXTOP] = v1->y;
if (v2->x < bbox[BOXLEFT]) bbox[BOXLEFT] = v2->x;
if (v2->x > bbox[BOXRIGHT]) bbox[BOXRIGHT] = v2->x;
if (v2->y < bbox[BOXBOTTOM]) bbox[BOXBOTTOM] = v2->y;
if (v2->y > bbox[BOXTOP]) bbox[BOXTOP] = v2->y;
}

BIN
poly_bad.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 471 B

BIN
poly_mov.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 458 B

BIN
poly_new.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 B

1268
processor.cpp Normal file

File diff suppressed because it is too large Load diff

95
processor.h Normal file
View file

@ -0,0 +1,95 @@
#ifndef __PROCESSOR_H__
#define __PROCESSOR_H__
#ifdef _MSC_VER
#pragma once
#endif
#include "wad.h"
#include "doomdata.h"
#include "workdata.h"
#include "tarray.h"
#include "nodebuild.h"
#include "blockmapbuilder.h"
#include <zlib.h>
class ZLibOut
{
public:
ZLibOut (FWadWriter &out);
~ZLibOut ();
ZLibOut &operator << (BYTE);
ZLibOut &operator << (WORD);
ZLibOut &operator << (SWORD);
ZLibOut &operator << (DWORD);
ZLibOut &operator << (fixed_t);
void Write (BYTE *data, int len);
private:
enum { BUFFER_SIZE = 8192 };
z_stream Stream;
BYTE Buffer[BUFFER_SIZE];
FWadWriter &Out;
};
class FProcessor
{
public:
FProcessor (FWadReader &inwad, int lump);
void Write (FWadWriter &out);
private:
void LoadThings ();
void LoadLines ();
void LoadVertices ();
void LoadSides ();
void LoadSectors ();
void GetPolySpots ();
MapNodeEx *NodesToEx (const MapNode *nodes, int count);
MapSubsectorEx *SubsectorsToEx (const MapSubsector *ssec, int count);
MapSegGLEx *SegGLsToEx (const MapSegGL *segs, int count);
void WriteLines (FWadWriter &out);
void WriteVertices (FWadWriter &out, int count);
void WriteSectors (FWadWriter &out);
void WriteSides (FWadWriter &out);
void WriteSegs (FWadWriter &out);
void WriteSSectors (FWadWriter &out) const;
void WriteNodes (FWadWriter &out) const;
void WriteBlockmap (FWadWriter &out);
void WriteReject (FWadWriter &out);
void WriteGLVertices (FWadWriter &out);
void WriteGLSegs (FWadWriter &out);
void WriteGLSSect (FWadWriter &out);
void WriteGLNodes (FWadWriter &out);
void WriteBSPZ (FWadWriter &out, const char *label);
void WriteGLBSPZ (FWadWriter &out, const char *label);
void WriteVerticesZ (ZLibOut &out, const WideVertex *verts, int orgverts, int newverts);
void WriteSubsectorsZ (ZLibOut &out, const MapSubsectorEx *subs, int numsubs);
void WriteSegsZ (ZLibOut &out, const MapSeg *segs, int numsegs);
void WriteGLSegsZ (ZLibOut &out, const MapSegGLEx *segs, int numsegs);
void WriteNodesZ (ZLibOut &out, const MapNodeEx *nodes, int numnodes);
void WriteNodes2 (FWadWriter &out, const char *name, const MapNodeEx *zaNodes, int count) const;
void WriteSSectors2 (FWadWriter &out, const char *name, const MapSubsectorEx *zaSubs, int count) const;
FLevel Level;
TArray<FNodeBuilder::FPolyStart> PolyStarts;
TArray<FNodeBuilder::FPolyStart> PolyAnchors;
bool Extended;
FWadReader &Wad;
int Lump;
};
#endif //__PROCESSOR_H__

20
resource.h Normal file
View file

@ -0,0 +1,20 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by resource.rc
//
#define IDD_MAPVIEW 101
#define IDC_MAPVIEW 1004
#define IDC_STATICNUMBER 1007
#define IDC_COMBO3 1010
#define IDC_COMBO1 1010
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1011
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

103
resource.rc Normal file
View file

@ -0,0 +1,103 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_MAPVIEW DIALOGEX 0, 0, 510, 446
STYLE DS_SETFONT | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP |
WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
EXSTYLE WS_EX_APPWINDOW
CAPTION "ZDBSP Map Viewer"
FONT 8, "MS Sans Serif", 0, 0, 0x0
BEGIN
CONTROL "Custom2",IDC_MAPVIEW,"MapViewer",WS_VSCROLL |
WS_HSCROLL,7,7,496,411,WS_EX_CLIENTEDGE
PUSHBUTTON "OK",IDOK,7,423,53,16
LTEXT "Static",IDC_STATICNUMBER,68,425,60,14
COMBOBOX IDC_COMBO1,142,427,123,250,CBS_DROPDOWNLIST | WS_VSCROLL |
WS_TABSTOP
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_MAPVIEW, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 503
TOPMARGIN, 7
BOTTOMMARGIN, 439
END
END
#endif // APSTUDIO_INVOKED
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

207
tarray.h Normal file
View file

@ -0,0 +1,207 @@
/*
** tarray.h
** Templated, automatically resizing array
**
**---------------------------------------------------------------------------
** Copyright 1998-2001 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#ifndef __TARRAY_H__
#define __TARRAY_H__
#include <stdlib.h>
template <class T>
class TArray
{
public:
TArray ()
{
Most = 0;
Count = 0;
Array = NULL;
}
TArray (int max)
{
Most = max;
Count = 0;
Array = new T[max];
}
TArray (const TArray<T> &other)
{
DoCopy (other);
}
TArray<T> &operator= (const TArray<T> &other)
{
if (&other != this)
{
if (Array != NULL)
{
delete[] Array;
}
DoCopy (other);
}
return *this;
}
~TArray ()
{
if (Array)
free (Array);
}
T &operator[] (size_t index) const
{
return Array[index];
}
size_t Push (const T &item)
{
if (Count >= Most)
{
Most = (Most >= 16) ? Most + Most / 2 : 16;
Realloc (Count, Most);
}
Array[Count] = item;
return Count++;
}
bool Pop (T &item)
{
if (Count > 0)
{
item = Array[--Count];
return true;
}
return false;
}
void Delete (int index)
{
if (index < Count-1)
memmove (Array + index, Array + index + 1, (Count - index) * sizeof(T));
else if (index < Count)
Count--;
}
void Realloc (size_t count, size_t most)
{
T *copy = new T[most];
for (size_t i = 0; i < count; ++i)
{
copy[i] = Array[i];
}
delete[] Array;
Array = copy;
}
void ShrinkToFit ()
{
if (Most > Count)
{
Most = Count;
if (Most == 0)
{
if (Array != NULL)
{
free (Array);
Array = NULL;
}
}
else
{
Realloc (Count, Most);
}
}
}
// Grow Array to be large enough to hold amount more entries without
// further growing.
void Grow (size_t amount)
{
if (Count + amount > Most)
{
const size_t choicea = Count + amount;
const size_t choiceb = Most + Most/2;
Most = (choicea > choiceb ? choicea : choiceb);
Realloc (Count, Most);
}
}
// Resize Array so that it has exactly amount entries in use.
void Resize (size_t amount)
{
if (Count < amount)
{
Grow (amount - Count);
}
else if (Count > amount)
{
Count = amount;
}
}
// Reserves amount entries at the end of the array, but does nothing
// with them.
size_t Reserve (size_t amount)
{
if (Count + amount > Most)
{
Grow (amount);
}
size_t place = Count;
Count += amount;
return place;
}
size_t Size () const
{
return Count;
}
size_t Max () const
{
return Most;
}
void Clear ()
{
Count = 0;
}
private:
T *Array;
size_t Most;
size_t Count;
void DoCopy (const TArray<T> &other)
{
Most = Count = other.Count;
if (Count != 0)
{
Array = new T[Most];
for (size_t i = 0; i < Count; ++i)
{
Array[i] = other.Array[i];
}
}
else
{
Array = NULL;
}
}
};
#endif //__TARRAY_H__

202
templates.h Normal file
View file

@ -0,0 +1,202 @@
/*
** templates.h
** Some useful template functions
**
**---------------------------------------------------------------------------
** Copyright 1998-2001 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#ifndef __TEMPLATES_H__
#define __TEMPLATES_H__
#ifdef _MSC_VER
#pragma once
#endif
#include <stdlib.h>
//==========================================================================
//
// BinarySearch
//
// Searches an array sorted in ascending order for an element matching
// the desired key.
//
// Template parameters:
// ClassType - The class to be searched
// KeyType - The type of the key contained in the class
//
// Function parameters:
// first - Pointer to the first element in the array
// max - The number of elements in the array
// keyptr - Pointer to the key member of ClassType
// key - The key value to look for
//
// Returns:
// A pointer to the element with a matching key or NULL if none found.
//==========================================================================
template<class ClassType, class KeyType>
inline
const ClassType *BinarySearch (const ClassType *first, int max,
const KeyType ClassType::*keyptr, const KeyType key)
{
int min = 0;
--max;
while (min <= max)
{
int mid = (min + max) / 2;
const ClassType *probe = &first[mid];
const KeyType &seekey = probe->*keyptr;
if (seekey == key)
{
return probe;
}
else if (seekey < key)
{
min = mid + 1;
}
else
{
max = mid - 1;
}
}
return NULL;
}
//==========================================================================
//
// BinarySearchFlexible
//
// THIS DOES NOT WORK RIGHT WITH VISUAL C++
// ONLY ONE COMPTYPE SEEMS TO BE USED FOR ANY INSTANCE OF THIS FUNCTION
// IN A DEBUG BUILD. RELEASE MIGHT BE DIFFERENT--I DIDN'T BOTHER TRYING.
//
// Similar to BinarySearch, except another function is used to copmare
// items in the array.
//
// Template parameters:
// IndexType - The type used to index the array (int, size_t, etc.)
// KeyType - The type of the key
// CompType - A class with a static DoCompare(IndexType, KeyType) method.
//
// Function parameters:
// max - The number of elements in the array
// key - The key value to look for
// noIndex - The value to return if no matching element is found.
//
// Returns:
// The index of the matching element or noIndex.
//==========================================================================
template<class IndexType, class KeyType, class CompType>
inline
IndexType BinarySearchFlexible (IndexType max, const KeyType key, IndexType noIndex)
{
IndexType min = 0;
--max;
while (min <= max)
{
IndexType mid = (min + max) / 2;
int lexx = CompType::DoCompare (mid, key);
if (lexx == 0)
{
return mid;
}
else if (lexx < 0)
{
min = mid + 1;
}
else
{
max = mid - 1;
}
}
return noIndex;
}
//==========================================================================
//
// MIN
//
// Returns the minimum of a and b.
//==========================================================================
template<class T>
inline
const T MIN (const T a, const T b)
{
return a < b ? a : b;
}
//==========================================================================
//
// MAX
//
// Returns the maximum of a and b.
//==========================================================================
template<class T>
inline
const T MAX (const T a, const T b)
{
return a > b ? a : b;
}
//==========================================================================
//
// clamp
//
// Clamps in to the range [min,max].
//==========================================================================
template<class T>
inline
T clamp (const T in, const T min, const T max)
{
return in <= min ? min : in >= max ? max : in;
}
//==========================================================================
//
// swap
//
// Swaps the values of a and b.
//==========================================================================
template<class T>
inline
void swap (T &a, T &b)
{
T temp = a; a = b; b = temp;
}
#endif //__TEMPLATES_H__

1049
view.cpp Normal file

File diff suppressed because it is too large Load diff

423
wad.cpp Normal file
View file

@ -0,0 +1,423 @@
/*
WAD-handling routines.
Copyright (C) 2002,2003 Randy Heit
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 should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "wad.h"
static const char MapLumpNames[12][9] =
{
"THINGS",
"LINEDEFS",
"SIDEDEFS",
"VERTEXES",
"SEGS",
"SSECTORS",
"NODES",
"SECTORS",
"REJECT",
"BLOCKMAP",
"BEHAVIOR",
"SCRIPTS"
};
static const bool MapLumpRequired[12] =
{
true, // THINGS
true, // LINEDEFS
true, // SIDEDEFS
true, // VERTEXES
false, // SEGS
false, // SSECTORS
false, // NODES
true, // SECTORS
false, // REJECT
false, // BLOCKMAP
false, // BEHAVIOR
false // SCRIPTS
};
static const char GLLumpNames[5][9] =
{
"GL_VERT",
"GL_SEGS",
"GL_SSECT",
"GL_NODES",
"GL_PVS"
};
FWadReader::FWadReader (const char *filename)
: Lumps (NULL), File (NULL)
{
File = fopen (filename, "rb");
if (File == NULL)
{
throw exception("Could not open input file");
}
SafeRead (&Header, sizeof(Header));
if (Header.Magic[0] != 'P' && Header.Magic[0] != 'I' &&
Header.Magic[1] != 'W' &&
Header.Magic[2] != 'A' &&
Header.Magic[3] != 'D')
{
fclose (File);
File = NULL;
throw exception("Input file is not a wad");
}
Header.NumLumps = LONG(Header.NumLumps);
Header.Directory = LONG(Header.Directory);
if (fseek (File, Header.Directory, SEEK_SET))
{
throw exception("Could not read wad directory");
}
Lumps = new WadLump[Header.NumLumps];
SafeRead (Lumps, Header.NumLumps * sizeof(*Lumps));
for (int i = 0; i < Header.NumLumps; ++i)
{
Lumps[i].FilePos = LONG(Lumps[i].FilePos);
Lumps[i].Size = LONG(Lumps[i].Size);
}
}
FWadReader::~FWadReader ()
{
if (File) fclose (File);
if (Lumps) delete[] Lumps;
}
bool FWadReader::IsIWAD () const
{
return Header.Magic[0] == 'I';
}
int FWadReader::NumLumps () const
{
return Header.NumLumps;
}
int FWadReader::FindLump (const char *name, int index) const
{
if (index < 0)
{
index = 0;
}
for (; index < Header.NumLumps; ++index)
{
if (strnicmp (Lumps[index].Name, name, 8) == 0)
{
return index;
}
}
return -1;
}
int FWadReader::FindMapLump (const char *name, int map) const
{
int i, j, k;
++map;
for (i = 0; i < 12; ++i)
{
if (strnicmp (MapLumpNames[i], name, 8) == 0)
{
break;
}
}
if (i == 12)
{
return -1;
}
for (j = k = 0; j < 12; ++j)
{
if (strnicmp (Lumps[map+k].Name, MapLumpNames[j], 8) == 0)
{
if (i == j)
{
return map+k;
}
k++;
}
}
return -1;
}
bool FWadReader::IsMap (int index) const
{
int i, j;
index++;
for (i = j = 0; i < 12; ++i)
{
if (strnicmp (Lumps[index+j].Name, MapLumpNames[i], 8) != 0)
{
if (MapLumpRequired[i])
{
return false;
}
}
else
{
j++;
}
}
return true;
}
int FWadReader::FindGLLump (const char *name, int glheader) const
{
int i, j, k;
++glheader;
for (i = 0; i < 5; ++i)
{
if (strnicmp (Lumps[glheader+i].Name, name, 8) == 0)
{
break;
}
}
if (i == 5)
{
return -1;
}
for (j = k = 0; j < 5; ++j)
{
if (strnicmp (Lumps[glheader+k].Name, GLLumpNames[j], 8) == 0)
{
if (i == j)
{
return glheader+k;
}
k++;
}
}
return -1;
}
bool FWadReader::IsGLNodes (int index) const
{
if (index + 4 >= Header.NumLumps)
{
return false;
}
if (Lumps[index].Name[0] != 'G' ||
Lumps[index].Name[1] != 'L' ||
Lumps[index].Name[2] != '_')
{
return false;
}
index++;
for (int i = 0; i < 4; ++i)
{
if (strnicmp (Lumps[i+index].Name, GLLumpNames[i], 8) != 0)
{
return false;
}
}
return true;
}
int FWadReader::SkipGLNodes (int index) const
{
index++;
for (int i = 0; i < 5 && index < Header.NumLumps; ++i, ++index)
{
if (strnicmp (Lumps[index].Name, GLLumpNames[i], 8) != 0)
{
break;
}
}
return index;
}
bool FWadReader::MapHasBehavior (int map) const
{
return FindLump ("BEHAVIOR", map) != -1;
}
int FWadReader::NextMap (int index) const
{
if (index < 0)
{
index = 0;
}
else
{
index++;
}
for (; index < Header.NumLumps; ++index)
{
if (IsMap (index))
{
return index;
}
}
return -1;
}
int FWadReader::LumpAfterMap (int i) const
{
int j, k;
++i;
for (j = k = 0; j < 12; ++j)
{
if (strnicmp (Lumps[i+k].Name, MapLumpNames[j], 8) != 0)
{
if (MapLumpRequired[j])
{
break;
}
}
else
{
k++;
}
}
return i+k;
}
void FWadReader::SafeRead (void *buffer, size_t size)
{
if (fread (buffer, 1, size, File) != size)
{
throw exception("Failed to read");
}
}
const char *FWadReader::LumpName (int lump)
{
static char name[9];
strncpy (name, Lumps[lump].Name, 8);
name[8] = 0;
return name;
}
FWadWriter::FWadWriter (const char *filename, bool iwad)
: File (NULL)
{
File = fopen (filename, "wb");
if (File == NULL)
{
throw exception("Could not open output file");
}
WadHeader head;
if (iwad)
{
head.Magic[0] = 'I';
}
else
{
head.Magic[0] = 'P';
}
head.Magic[1] = 'W';
head.Magic[2] = 'A';
head.Magic[3] = 'D';
SafeWrite (&head, sizeof(head));
}
FWadWriter::~FWadWriter ()
{
if (File)
{
Close ();
}
}
void FWadWriter::Close ()
{
if (File)
{
__int32 head[2];
head[0] = LONG(Lumps.Size());
head[1] = LONG(ftell (File));
SafeWrite (&Lumps[0], sizeof(WadLump)*Lumps.Size());
fseek (File, 4, SEEK_SET);
SafeWrite (head, 8);
fclose (File);
File = NULL;
}
}
void FWadWriter::CreateLabel (const char *name)
{
WadLump lump;
strncpy (lump.Name, name, 8);
lump.FilePos = LONG(ftell (File));
lump.Size = 0;
Lumps.Push (lump);
}
void FWadWriter::WriteLump (const char *name, const void *data, int len)
{
WadLump lump;
strncpy (lump.Name, name, 8);
lump.FilePos = LONG(ftell (File));
lump.Size = LONG(len);
Lumps.Push (lump);
SafeWrite (data, len);
}
void FWadWriter::CopyLump (FWadReader &wad, int lump)
{
BYTE *data;
int size;
ReadLump<BYTE> (wad, lump, data, size);
if (data != NULL)
{
WriteLump (wad.LumpName (lump), data, size);
delete[] data;
}
}
void FWadWriter::StartWritingLump (const char *name)
{
CreateLabel (name);
}
void FWadWriter::AddToLump (const void *data, int len)
{
SafeWrite (data, len);
Lumps[Lumps.Size()-1].Size += len;
}
void FWadWriter::SafeWrite (const void *buffer, size_t size)
{
if (fwrite (buffer, 1, size, File) != size)
{
fclose (File);
File = NULL;
throw exception(
"Failed to write. Check that this directory is writable and\n"
"that you have enough free disk space.");
}
}

107
wad.h Normal file
View file

@ -0,0 +1,107 @@
#ifndef __WAD_H__
#define __WAD_H__
#ifdef _MSC_VER
#pragma once
#endif
#include <stdio.h>
#include <string.h>
#include "zdbsp.h"
#include "tarray.h"
struct WadHeader
{
char Magic[4];
__int32 NumLumps;
__int32 Directory;
};
struct WadLump
{
__int32 FilePos;
__int32 Size;
char Name[8];
};
class FWadReader
{
public:
FWadReader (const char *filename);
~FWadReader ();
bool IsIWAD () const;
int FindLump (const char *name, int index=0) const;
int FindMapLump (const char *name, int map) const;
int FindGLLump (const char *name, int glheader) const;
const char *LumpName (int lump);
bool IsMap (int index) const;
bool IsGLNodes (int index) const;
int SkipGLNodes (int index) const;
bool MapHasBehavior (int map) const;
int NextMap (int startindex) const;
int LumpAfterMap (int map) const;
int NumLumps () const;
void SafeRead (void *buffer, size_t size);
// VC++ 6 does not support template member functions in non-template classes!
template<class T>
friend void ReadLump (FWadReader &wad, int index, T *&data, int &size);
private:
WadHeader Header;
WadLump *Lumps;
FILE *File;
};
template<class T>
void ReadLump (FWadReader &wad, int index, T *&data, int &size)
{
if ((unsigned)index >= (unsigned)wad.Header.NumLumps)
{
data = NULL;
size = 0;
return;
}
if (fseek (wad.File, wad.Lumps[index].FilePos, SEEK_SET))
{
throw exception("Failed to seek");
}
size = wad.Lumps[index].Size / sizeof(T);
data = new T[size];
wad.SafeRead (data, size*sizeof(T));
}
template<class T>
void ReadMapLump (FWadReader &wad, const char *name, int index, T *&data, int &size)
{
ReadLump (wad, wad.FindMapLump (name, index), data, size);
}
class FWadWriter
{
public:
FWadWriter (const char *filename, bool iwad);
~FWadWriter ();
void CreateLabel (const char *name);
void WriteLump (const char *name, const void *data, int len);
void CopyLump (FWadReader &wad, int lump);
void Close ();
// Routines to write a lump in segments.
void StartWritingLump (const char *name);
void AddToLump (const void *data, int len);
private:
TArray<WadLump> Lumps;
FILE *File;
void SafeWrite (const void *buffer, size_t size);
};
#endif //__WAD_H__

29
workdata.h Normal file
View file

@ -0,0 +1,29 @@
#ifndef __WORKDATA_H__
#define __WORKDATA_H__
#ifdef _MSC_VER
#pragma once
#endif
#include "zdbsp.h"
struct vertex_t
{
fixed_t x, y;
};
struct node_t
{
fixed_t x, y, dx, dy;
fixed_t bbox[2][4];
unsigned int intchildren[2];
};
struct subsector_t
{
DWORD numlines;
DWORD firstline;
};
#endif //__WORKDATA_H__

398
zdbsp.dsp Normal file
View file

@ -0,0 +1,398 @@
# Microsoft Developer Studio Project File - Name="zdbsp" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=zdbsp - Win32 Release
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "zdbsp.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "zdbsp.mak" CFG="zdbsp - Win32 Release"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "zdbsp - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "zdbsp - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "zdbsp - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir ".\Release"
# PROP BASE Intermediate_Dir ".\Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir ".\Release"
# PROP Intermediate_Dir ".\Release"
# PROP Target_Dir ""
MTL=midl.exe
# ADD BASE MTL /nologo /tlb".\Release\zdbsp.tlb" /win32
# ADD MTL /nologo /tlb".\Release\zdbsp.tlb" /win32
# ADD BASE CPP /nologo /W3 /GX /Zi /Ot /Og /Oi /Oy /Ob2 /Gy /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /GA /GF /c
# ADD CPP /nologo /MD /W3 /GX /Zi /Ot /Og /Oi /Oy /Ob2 /Gy /I "zlib" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /GA /GF /c
# SUBTRACT CPP /YX /Yc /Yu
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# SUBTRACT BASE LINK32 /pdb:none
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# SUBTRACT LINK32 /pdb:none
!ELSEIF "$(CFG)" == "zdbsp - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir ".\Debug"
# PROP BASE Intermediate_Dir ".\Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir ".\Debug"
# PROP Intermediate_Dir ".\Debug"
# PROP Target_Dir ""
MTL=midl.exe
# ADD BASE MTL /nologo /tlb".\Debug\zdbsp.tlb" /win32
# ADD MTL /nologo /tlb".\Debug\zdbsp.tlb" /win32
# ADD BASE CPP /nologo /W3 /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /GZ /c
# ADD CPP /nologo /W3 /GX /ZI /Od /I "zlib" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# SUBTRACT BASE LINK32 /pdb:none
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# SUBTRACT LINK32 /pdb:none
!ENDIF
# Begin Target
# Name "zdbsp - Win32 Release"
# Name "zdbsp - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Group "Reject(ed)"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\Unused\rejectbuilder.cpp
# PROP Exclude_From_Build 1
# End Source File
# Begin Source File
SOURCE=.\Unused\rejectbuilder.h
# PROP Exclude_From_Build 1
# End Source File
# Begin Source File
SOURCE=.\Unused\vis.cpp
# PROP Exclude_From_Build 1
# End Source File
# Begin Source File
SOURCE=.\Unused\visflow.cpp
# PROP Exclude_From_Build 1
# End Source File
# End Group
# Begin Source File
SOURCE=.\blockmapbuilder.cpp
DEP_CPP_BLOCK=\
".\blockmapbuilder.h"\
".\doomdata.h"\
".\tarray.h"\
".\templates.h"\
".\workdata.h"\
".\zdbsp.h"\
# End Source File
# Begin Source File
SOURCE=.\getopt.c
DEP_CPP_GETOP=\
".\getopt.h"\
# End Source File
# Begin Source File
SOURCE=getopt1.c
DEP_CPP_GETOPT=\
".\getopt.h"\
# End Source File
# Begin Source File
SOURCE=.\main.cpp
DEP_CPP_MAIN_=\
".\blockmapbuilder.h"\
".\doomdata.h"\
".\getopt.h"\
".\nodebuild.h"\
".\processor.h"\
".\tarray.h"\
".\wad.h"\
".\workdata.h"\
".\zdbsp.h"\
# End Source File
# Begin Source File
SOURCE=.\nodebuild.cpp
DEP_CPP_NODEB=\
".\doomdata.h"\
".\nodebuild.h"\
".\tarray.h"\
".\templates.h"\
".\workdata.h"\
".\zdbsp.h"\
# End Source File
# Begin Source File
SOURCE=nodebuild_events.cpp
DEP_CPP_NODEBU=\
".\doomdata.h"\
".\nodebuild.h"\
".\tarray.h"\
".\workdata.h"\
".\zdbsp.h"\
# End Source File
# Begin Source File
SOURCE=nodebuild_extract.cpp
DEP_CPP_NODEBUI=\
".\doomdata.h"\
".\nodebuild.h"\
".\tarray.h"\
".\templates.h"\
".\workdata.h"\
".\zdbsp.h"\
# End Source File
# Begin Source File
SOURCE=nodebuild_gl.cpp
DEP_CPP_NODEBUIL=\
".\doomdata.h"\
".\nodebuild.h"\
".\tarray.h"\
".\workdata.h"\
".\zdbsp.h"\
# End Source File
# Begin Source File
SOURCE=nodebuild_utility.cpp
DEP_CPP_NODEBUILD=\
".\doomdata.h"\
".\nodebuild.h"\
".\tarray.h"\
".\workdata.h"\
".\zdbsp.h"\
# End Source File
# Begin Source File
SOURCE=.\processor.cpp
DEP_CPP_PROCE=\
".\blockmapbuilder.h"\
".\doomdata.h"\
".\nodebuild.h"\
".\processor.h"\
".\tarray.h"\
".\wad.h"\
".\workdata.h"\
".\zdbsp.h"\
# End Source File
# Begin Source File
SOURCE=.\view.cpp
DEP_CPP_VIEW_=\
".\doomdata.h"\
".\tarray.h"\
".\templates.h"\
".\zdbsp.h"\
# End Source File
# Begin Source File
SOURCE=.\wad.cpp
DEP_CPP_WAD_C=\
".\tarray.h"\
".\wad.h"\
".\zdbsp.h"\
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\blockmapbuilder.h
# End Source File
# Begin Source File
SOURCE=.\doomdata.h
# End Source File
# Begin Source File
SOURCE=getopt.h
# End Source File
# Begin Source File
SOURCE=.\nodebuild.h
# End Source File
# Begin Source File
SOURCE=.\processor.h
# End Source File
# Begin Source File
SOURCE=.\resource.h
# End Source File
# Begin Source File
SOURCE=.\tarray.h
# End Source File
# Begin Source File
SOURCE=.\templates.h
# End Source File
# Begin Source File
SOURCE=.\wad.h
# End Source File
# Begin Source File
SOURCE=.\workdata.h
# End Source File
# Begin Source File
SOURCE=.\zdbsp.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# Begin Source File
SOURCE=.\resource.rc
# End Source File
# End Group
# Begin Group "zlib"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\zlib\adler32.c
DEP_CPP_ADLER=\
".\zlib\zconf.h"\
".\zlib\zlib.h"\
# End Source File
# Begin Source File
SOURCE=.\zlib\compress.c
DEP_CPP_COMPR=\
".\zlib\zconf.h"\
".\zlib\zlib.h"\
# End Source File
# Begin Source File
SOURCE=.\zlib\crc32.c
DEP_CPP_CRC32=\
".\zlib\crc32.h"\
".\zlib\zconf.h"\
".\zlib\zlib.h"\
".\zlib\zutil.h"\
# End Source File
# Begin Source File
SOURCE=.\zlib\crc32.h
# End Source File
# Begin Source File
SOURCE=.\zlib\deflate.c
DEP_CPP_DEFLA=\
".\zlib\deflate.h"\
".\zlib\zconf.h"\
".\zlib\zlib.h"\
".\zlib\zutil.h"\
# End Source File
# Begin Source File
SOURCE=.\zlib\deflate.h
# End Source File
# Begin Source File
SOURCE=.\zlib\trees.c
DEP_CPP_TREES=\
".\zlib\deflate.h"\
".\zlib\trees.h"\
".\zlib\zconf.h"\
".\zlib\zlib.h"\
".\zlib\zutil.h"\
# End Source File
# Begin Source File
SOURCE=.\zlib\trees.h
# End Source File
# Begin Source File
SOURCE=.\zlib\zconf.h
# End Source File
# Begin Source File
SOURCE=.\zlib\zlib.h
# End Source File
# Begin Source File
SOURCE=.\zlib\zutil.c
DEP_CPP_ZUTIL=\
".\zlib\zconf.h"\
".\zlib\zlib.h"\
".\zlib\zutil.h"\
# End Source File
# Begin Source File
SOURCE=.\zlib\zutil.h
# End Source File
# End Group
# Begin Source File
SOURCE=.\zdbsp.html
# End Source File
# End Target
# End Project

29
zdbsp.dsw Normal file
View file

@ -0,0 +1,29 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "zdbsp"=zdbsp.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

134
zdbsp.h Normal file
View file

@ -0,0 +1,134 @@
#ifndef __ZDBSP_H__
#define __ZDBSP_H__
#ifdef _MSC_VER
#pragma once
#endif
#include <limits.h>
#include <exception>
#define ZDBSP_VERSION "1.5"
enum EBlockmapMode
{
EBM_Rebuild,
EBM_Create0
};
enum ERejectMode
{
ERM_DontTouch,
ERM_CreateZeroes,
ERM_Create0,
ERM_Rebuild
};
extern const char *Map;
extern const char *InName;
extern const char *OutName;
extern bool BuildNodes, BuildGLNodes, ConformNodes, GLOnly;
extern bool NoPrune;
extern EBlockmapMode BlockmapMode;
extern ERejectMode RejectMode;
extern int MaxSegs;
extern int SplitCost;
extern int AAPreference;
extern bool CheckPolyobjs;
extern bool ShowMap;
extern bool CompressNodes, CompressGLNodes;
#define FIXED_MAX INT_MAX
#define FIXED_MIN INT_MIN
#define FRACBITS 16
typedef int fixed_t;
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef signed short SWORD;
typedef unsigned long DWORD;
typedef unsigned __int32 angle_t;
angle_t PointToAngle (fixed_t x, fixed_t y);
static const WORD NO_INDEX = 0xffff;
static const angle_t ANGLE_MAX = 0xffffffff;
static const DWORD DWORD_MAX = 0xffffffff;
static const angle_t ANGLE_180 = (1u<<31);
static const angle_t ANGLE_EPSILON = 5000;
void Warn (const char *format, ...);
#ifdef _MSC_VER
#pragma warning (disable: 4035)
inline fixed_t Scale (fixed_t a, fixed_t b, fixed_t c)
{
__asm mov eax,a
__asm mov ecx,c
__asm imul b
__asm idiv ecx
}
inline fixed_t DivScale30 (fixed_t a, fixed_t b)
{
__asm mov edx,a
__asm sar edx,2
__asm mov eax,a
__asm shl eax,30
__asm idiv b
}
inline fixed_t MulScale30 (fixed_t a, fixed_t b)
{
__asm mov eax,a
__asm imul b
__asm shrd eax,edx,30
}
inline fixed_t DMulScale32 (fixed_t a, fixed_t b, fixed_t c, fixed_t d)
{
__asm mov eax,a
__asm imul b
__asm mov ebx,eax
__asm mov eax,c
__asm mov esi,edx
__asm imul d
__asm add eax,ebx
__asm adc edx,esi
__asm mov eax,edx
}
#pragma warning (default: 4035)
#else
inline fixed_t Scale (fixed_t a, fixed_t b, fixed_t c)
{
return (fixed_t)(double(a)*double(b)/double(c));
}
inline fixed_t DivScale30 (fixed_t a, fixed_t b)
{
return (fixed_t)(double(a)/double(b)*double(1<<30));
}
inline fixed_t MulScale30 (fixed_t a, fixed_t b)
{
return (fixed_t)(double(a)*double(b)/double(1<<30));
}
inline fixed_t DMulScale30 (fixed_t a, fixed_t b, fixed_t c, fixed_t d)
{
return (fixed_t)((double(a)*double(b)+double(c)*double(d))/double(1<<30));
}
#endif
#define SHORT(x) (x)
#define LONG(x) (x)
#endif //__ZDBSP_H__

476
zdbsp.html Normal file
View file

@ -0,0 +1,476 @@
<HTML>
<HEAD>
<TITLE>ZDBSP Documentation</TITLE>
<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
<META NAME="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">
</HEAD>
<BODY>
<H1>About ZDBSP</H1>
<P>ZDBSP is a stand-alone version of ZDoom's internal node builder. This node
builder was written with two design goals in mind:</P>
<OL>
<LI>
It must be fast. The original node builder was just going to be used to fix map
errors in ZDoom. After adding GL nodes support, ZDoomGL also started using it
as a preprocessing step for any maps without existing GL nodes.&nbsp;In both
cases,&nbsp;the node builder&nbsp;needed to be quick in order to minimize the
time the user was forced to wait before playing a map.
<LI>
Polyobject bleeding must be minimized. The node builder was tested with the
standard Hexen maps and several user maps, and it has been able to prevent
bleeding on all properly-formed maps. (Note that it is impossible to prevent
polyobject bleeding in all circumstances. See the polyobjects section below for
rules you should follow for best results.)</LI></OL>
<h1>License</h1>
<p>This program is free software; you can redistribute it and/or modify it under
the terms of the <a href="http://www.gnu.org/licenses/gpl.html">GNU General Public
License</a> as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.</p>
<p>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.</p>
<p>You can also find a copy of the license as the file COPYING in the source
distribution.</p>
<H1>Using ZDBSP with WadAuthor</H1>
<P>First, copy zdbsp.exe to your WadAuthor directory. Then start WadAuthor and
choose "Options..." from its Tools menu. Select the "Files" tab and&nbsp;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.</P>
<P>Create a map that can be played with Doom or any source port:</P>
<BLOCKQUOTE dir="ltr" style="MARGIN-RIGHT: 0px">
<P>zdbsp -R -m$_Mapname $_Wadfile -o$_Wadfile</P>
</BLOCKQUOTE>
<P dir="ltr">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:</P>
<BLOCKQUOTE dir="ltr" style="MARGIN-RIGHT: 0px">
<P dir="ltr">zdbsp -r -m$_Mapname $_Wadfile -o$_Wadfile</P>
</BLOCKQUOTE>
<P dir="ltr">Create a map with both regular and GL nodes so that ZDoomGL does not
need to build GL nodes:</P>
<BLOCKQUOTE dir="ltr" style="MARGIN-RIGHT: 0px">
<P dir="ltr">zdbsp -rg -m$_Mapname $_Wadfile -o$_Wadfile</P>
</BLOCKQUOTE>
<H1 dir="ltr">ZDBSP command line options</H1>
<P dir="ltr">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.</P>
<dl>
<dt>--help</dt>
<dd>
Displays a summary of all ZDBSP's command line options, as if you had run ZDBSP
without any options.</dd>
<dt>--version or -V</dt>
<dd>
Displays ZDBSP's version number.</dd>
<dt>--map=<i>MAP</i> or -m<i>MAP</i></dt>
<dd>
When you use this option, ZDBSP will only build the nodes for one map in a wad
instead of rebuilding the nodes for every map contained in the wad. <i>MAP</i> should
be the map's full name (e.g. MAP01 or E1M1)</dd>
<dt>--output=<i>FILE</i> or -o<i>FILE</i></dt>
<dd>
Normally, ZDBSP creates a new wad named tmp.wad. You can use this option to
make it write to a different file instead. In the case of WadAuthor, this is
used to make ZDBSP overwrite the original file with the new one, because that
is what WadAuthor expects the nodebuilder to do.</dd>
<dt>--no-prune or -q</dt>
<dd>
When you use this option, ZDBSP will not remove unused sidedefs or sectors from
a map. ZDBSP will always remove 0-length linedefs from a map even when you use
this option because it is possible for them to make the game crash under
certain circumstances. Moreover, ZDoom will itself remove 0-length linedefs and
rebuild the nodes if it finds any.</dd>
<dt>--no-nodes or -N</dt>
<dd>
This option causes ZDBSP to take the node information from the old wad file and
write it to the new wad file. I can't think of any reason why you would want to
do this, but it is provided as an option nonetheless.</dd>
<dt>--gl or -g</dt>
<dd>
This option causes ZDBSP to build two sets of nodes for a map: One set of
regular nodes and one set of GL nodes. Because ZDBSP is doing twice the work,
it will take twice as long to finish.</dd>
<dt>--gl-matching or -G</dt>
<dd>
Like the previous option, this one will also make ZDBSP generate GL nodes.
However, it will only build one set of nodes and then strip the extra GL
information from them to create the normal nodes. Because of this, it is faster
than the previous option when you want to create GL nodes, but the normal nodes
will generally be less efficient because they were created from the GL nodes.</dd>
<dt>--compress or -z</dt>
<dd>Compresses the node information. Compressed nodes take up less space than
uncompressed nodes, and they are also the only way to save nodes with more than 65535 segs.
If GL nodes are built, they will be compressed as well.</dd>
<dt>--compress-normal or -Z</dt>
<dd>This is exactly like the previous option, except GL nodes will not be compressed.</dd>
<dt>--empty-blockmap or -b</dt>
<dd>
This option writes a zero-length BLOCKMAP to the wad. As of this writing, ZDoom
is the only port that will detect this and build the BLOCKMAP itself.</dd>
<dt>--empty-reject or -r</dt>
<dd>
When this option is used, ZDBSP will write a zero-length REJECT to the wad. As
of this writing, ZDoom is the only port that supports this. A zero-length
REJECT is the same thing as a reject filled with zeros. Since ZDBSP does not
generate a REJECT table, and the usefulness of having a REJECT is questionable,
you should always use this option if you intend for the map to be played solely
with ZDoom.</dd>
<dt>--zero-reject or -R</dt>
<dd>
This option is similar to the previous one, except ZDBSP will actually write
out a full-sized REJECT lump filled with zeros. If you play with ZDoom, this is
just wasted space, but other ports and Doom itself require a full-sized REJECT
lump to work.</dd>
<dt>--no-reject or -E</dt>
<dd>
This option makes ZDBSP copy the REJECT lump from the old wad to the new wad
unchanged. However, if it detects that the old REJECT is the wrong size for the
number of sectors in the map, it will be removed as if you had used the
--empty-reject option.</dd>
<dt>--no-polyobjs or -P</dt>
<dd>
This option disables ZDBSP's polyobject detection code. If you are building
nodes for a map without polyobjects, you might be able to save a fraction of a
second from the build time by using this option, but there is generally no
reason to use it.</dd>
<dt>--no-timing or -t</dt>
<dd>
If you don't care how long it takes to build nodes, use this option and ZDBSP
won't tell you.</dd>
<dt>--warn or -w</dt>
<dd>
Displays extra warning messages that ZDBSP might generate while building GL
nodes. The nodes will still be usable if warnings occur, and warnings are not
unlikely. If you have strange display problems with GL nodes, turning on the
warning messages may help you locate the problem.</dd>
<dt>--partition=<i>NNN</i> or -p<i>NNN</i></dt>
<dd>
This option controls the maximum number of segs that will be considered for
splitters at each node. The default is 64. By increasing it, you might be able
to generate "better" nodes, but you get diminishing returns the higher you make
it. High values are also slower than low ones.</dd>
<dt>--split-cost=<i>NNN</i> or -s<i>NNN</i></dt>
<dd>
This option adjusts how hard ZDBSP tries to avoid splitting segs. The default
value is 8. By increasing this, ZDBSP will try harder to avoid splitting segs.
If you decrease it, ZDBSP will split segs more frequently. More splits mean the
BSP tree will usually be more balanced, but it will also take up more room.</dd>
<dt>--diagonal-cost=<i>NNN</i> or -d<i>NNN</i></dt>
<dd>
This option controls how hard ZDBSP tries to avoid using diagonal splitters.
The default value is 16. A higher value means that diagonal splitters will be
more likely to be used. This can sometimes help to reduce the number of segs in
a map. The reason avoiding diagonal splitters is important is because normal
nodes do not store any fractional information for the vertices that segs use,
so you are more likely to see slime trails with diagonal splitters than with
horizontal or vertical splitters.</dd>
<dt>--view or -v</dt>
<dd>
Under Windows, this displays a viewer that will let you inspect a map's
subsectors, nodes, and REJECT. To scroll the map around, drag it with your
right mouse button. The viewer was created to assist with debugging with the GL
nodes. It is not very user-friendly nor is it bug-free. In fact, if you try to
build nodes for more than one map with this option, there is a good chance
ZDBSP will crash.</dd>
</dl>
<h1>Polyobjects</h1>
<p>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 <i>convex</i> 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.</p>
<p>Ironically, an example of what <i>not</i> 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.</p>
<p>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:</p>
<pre class="code"> 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</pre>
<p>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.
</p>
<p>Below are some illustrations. The areas where the two polyobjects appear have
been highlighted.</p>
<blockquote>
<p align="center">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.<br />
<img src="poly_bad.png" alt="The Original Area"></p>
<p align="center">In the next image, the lines have been moved to make each side
convex.<br />
<img src="poly_mov.png" alt="Convex Areas made by Moving Lines">
</p>
<p align="center">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.<br />
<img src="poly_new.png" alt="Convex Areas made by Adding Lines"></p>
</blockquote>
<p>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.</p>
<h1>Compressed Nodes</h1>
<p>The following information describes the format used to store compressed nodes.
If you are just a regular user, you can skip this section.</p>
<p>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.</p>
<p>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:</p>
<ol>
<li>
Vertex information</li>
<li>
Subsector information</li>
<li>
Segs information</li>
<li>
Nodes information</li></ol>
<h2>Types</h2>
<p>The following sections use these types:</p>
<dl>
<dt><b>BYTE</b></dt><dd>A single unsigned byte. The number can be in the range [0,
255].</dd>
<dt><b>WORD</b></dt><dd>An unsigned integer stored in two bytes. The number can be
in the range [0, 65535].</dd>
<dt><b>SWORD</b></dt><dd>A signed integer stored in two bytes. The number can be
in the range [-32768, 32767].</dd>
<dt><b>DWORD</b></dt><dd>An unsigned integer stored in four bytes. The number can
be in the range [0, 4294967295].</dd>
<dt><b>FIXED</b></dt><dd>A signed 16.16 fixed-point number stored in four bytes. The
most-significant two bytes store the integer part of the number, and the
least-significant two bytes store the fractional part of the number. The number can
be in the approximate range [-32768.99998, 32767.99998].</dd>
</dl>
<p>All multi-byte numbers are stored with their least significant byte first (i.e.
little-endian).</p>
<h2>Vertex information</h2>
<table>
<tr>
<td>DWORD</td>
<td><i>OrgVerts</i></td>
<td>Number of vertices used from the VERTEXES lump</td>
</tr>
<tr>
<td>DWORD</td>
<td><i>NewVerts</i></td>
<td>Number of additional vertices that follow</td>
</tr>
<tr>
<td colspan="3" bgcolor="#dddddd">Repeat <i>NewVerts</i> times:</td>
</tr>
<tr>
<td>FIXED</td>
<td><i>X</i></td>
<td>X-Coordinate</td>
</tr>
<tr>
<td>FIXED</td>
<td><i>Y</i></td>
<td>Y-Coordinate</td>
</tr>
</table>
<p>These are all the <i>additional</i> vertices that the segs use. Unlike normal
nodes, extra vertices are not added to the VERTEXES lump. When determining
which vertex <i>v</i> a seg uses, if <i>v</i> < <i>OrgVerts</i>, then <i>v</i> is
a vertex in the VERTEXES lump. Otherwise, when <i>v</i> >= <i>OrgVerts</i>, <i>v</i>
- <i>OrgVerts</i> is the index of a vertex stored here.</p>
<p>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.</p>
<h2>Subsector information</h2>
<table>
<tr>
<td>DWORD</td>
<td><i>NumSubsectors</i></td>
<td>Number of subsectors</td>
</tr>
<tr>
<td colspan="3" bgcolor="#dddddd">Repeat <i>NumSubsectors</i> times:</td>
</tr>
<tr>
<td>DWORD</td>
<td>NumSegs</td>
<td>Number of segs for this subsector</td>
</tr>
</table>
<p>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.</p>
<h2>Segs information</h2>
<p>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. <i>There is no padding to make
these align to DWORD boundaries.</i>
</p>
<h3>Normal nodes ('ZNOD' signature)</h3>
<table>
<tr>
<td>DWORD</td>
<td><i>NumSegs</i></td>
<td>Number of segs</td>
</tr>
<tr>
<td colspan="3" bgcolor="#dddddd">Repeat <i>NumSegs</i> times:</td>
</tr>
<tr>
<td>DWORD</td>
<td><i>v1</i></td>
<td>Seg's first vertex</td>
</tr>
<tr>
<td>DWORD</td>
<td><i>v2</i></td>
<td>Seg's second vertex</td>
</tr>
<tr>
<td>WORD</td>
<td><i>line</i></td>
<td>The linedef this seg came from</td>
</tr>
<tr>
<td>BYTE</td>
<td><i>side</i></td>
<td>The linedef's side this seg came from (0=front, 1=back)</td>
</tr>
</table>
<p>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.</p>
<h3>GL nodes ('ZGLN' signature)</h3>
<table>
<tr>
<td>DWORD</td>
<td><i>NumSegs</i></td>
<td>Number of segs</td>
</tr>
<tr>
<td colspan="3" bgcolor="#dddddd">Repeat <i>NumSegs</i> times:</td>
</tr>
<tr>
<td>DWORD</td>
<td><i>v1</i></td>
<td>Seg's first vertex</td>
</tr>
<tr>
<td>DWORD</td>
<td><i>partner</i></td>
<td>Seg's partner seg (0xFFFFFFFF if none)</td>
</tr>
<tr>
<td>WORD</td>
<td><i>line</i></td>
<td>The linedef this seg came from (0xFFFFFFFF if none)</td>
</tr>
<tr>
<td>BYTE</td>
<td><i>side</i></td>
<td>The linedef's side this seg came from (0=front, 1=back) (ignored if no line)</td>
</tr>
</table>
<p>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.</p>
<p>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:</p>
<blockquote><table>
<tr>
<td>Seg 0</td>
<td>Second vertex is Seg 1's first vertex</td>
</tr>
<tr>
<td>Seg 1</td>
<td>Second vertex is Seg 2's first vertex</td>
</tr>
<tr>
<td>Seg 2</td>
<td>Second vertex is Seg 3's first vertex</td>
</tr>
<tr>
<td>Seg 3</td>
<td>Second vertex is Seg 0's first vertex (because this is the last seg in the
subsector)</td>
</tr>
</table>
</blockquote>
<p>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.</p>
<h2>Node information</h2>
<p>This is really no different from standard nodes.</p>
<table>
<tr>
<td>DWORD</td>
<td><i>NumNodes</i></td>
<td>Number of nodes</td>
</tr>
<tr>
<td colspan="3" bgcolor="#dddddd">Repeat <i>NumNodes</i> times:</td>
</tr>
<tr>
<td>4 SWORDs</td>
<td><i>X</i>, <i>Y</i>, <i>dX</i>, <i>dY</i></td>
<td>Splitter for this node</td>
</tr>
<tr>
<td>4 SWORDs</td>
<td><i>Top</i>, <i>Bottom</i>, <i>Left</i>, <i>Right</i></td>
<td>Bounding box for <i>Child0</i></td>
</tr>
<tr>
<td>4 SWORDs</td>
<td><i>Top</i>, <i>Bottom</i>, <i>Left</i>, <i>Right</i></td>
<td>Bounding box for <i>Child1</i></td>
</tr>
<tr>
<td>2 DWORDs</td>
<td><i>Child0</i>, <i>Child1</i></td>
<td>References to child nodes or subsectors</td>
</tr>
</table>
<p>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.</p>
<h2>Compressed node storage</h2>
<p>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.</p>
<p>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.</p>
<p>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.</p>
</BODY>
</HTML>

21
zdbsp.sln Normal file
View file

@ -0,0 +1,21 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zdbsp", "zdbsp.vcproj", "{3C32111E-76E8-47C9-95A6-A103C861F45F}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Release = Release
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{3C32111E-76E8-47C9-95A6-A103C861F45F}.Debug.ActiveCfg = Debug|Win32
{3C32111E-76E8-47C9-95A6-A103C861F45F}.Debug.Build.0 = Debug|Win32
{3C32111E-76E8-47C9-95A6-A103C861F45F}.Release.ActiveCfg = Release|Win32
{3C32111E-76E8-47C9-95A6-A103C861F45F}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal

334
zdbsp.vcproj Normal file
View file

@ -0,0 +1,334 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="zdbsp"
SccProjectName=""
SccLocalPath="">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Release|Win32"
OutputDirectory=".\Release"
IntermediateDirectory=".\Release"
ConfigurationType="1"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2"
WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
Optimization="4"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="1"
OmitFramePointers="TRUE"
OptimizeForProcessor="0"
OptimizeForWindowsApplication="TRUE"
AdditionalIncludeDirectories="zlib"
PreprocessorDefinitions="WIN32,NDEBUG,_CONSOLE"
StringPooling="TRUE"
RuntimeLibrary="4"
EnableFunctionLevelLinking="TRUE"
UsePrecompiledHeader="0"
PrecompiledHeaderFile=".\Release/zdbsp.pch"
AssemblerListingLocation=".\Release/"
ObjectFile=".\Release/"
ProgramDataBaseFileName=".\Release/"
WarningLevel="3"
SuppressStartupBanner="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalOptions="/MACHINE:I386"
OutputFile=".\Release/zdbsp.exe"
LinkIncremental="1"
SuppressStartupBanner="TRUE"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile=".\Release/zdbsp.pdb"
SubSystem="1"
OptimizeForWindows98="1"/>
<Tool
Name="VCMIDLTool"
TypeLibraryName=".\Release/zdbsp.tlb"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="1033"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Debug|Win32"
OutputDirectory=".\Debug"
IntermediateDirectory=".\Debug"
ConfigurationType="1"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="zlib"
PreprocessorDefinitions="WIN32,_DEBUG,_CONSOLE"
BasicRuntimeChecks="3"
RuntimeLibrary="5"
UsePrecompiledHeader="0"
PrecompiledHeaderFile=".\Debug/zdbsp.pch"
AssemblerListingLocation=".\Debug/"
ObjectFile=".\Debug/"
ProgramDataBaseFileName=".\Debug/"
WarningLevel="3"
SuppressStartupBanner="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalOptions="/MACHINE:I386"
OutputFile=".\Debug/zdbsp.exe"
LinkIncremental="2"
SuppressStartupBanner="TRUE"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile=".\Debug/zdbsp.pdb"
SubSystem="1"/>
<Tool
Name="VCMIDLTool"
TypeLibraryName=".\Debug/zdbsp.tlb"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1033"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
<File
RelativePath=".\blockmapbuilder.cpp">
</File>
<File
RelativePath=".\getopt.c">
</File>
<File
RelativePath="getopt1.c">
</File>
<File
RelativePath=".\main.cpp">
</File>
<File
RelativePath=".\nodebuild.cpp">
</File>
<File
RelativePath="nodebuild_events.cpp">
</File>
<File
RelativePath="nodebuild_extract.cpp">
</File>
<File
RelativePath="nodebuild_gl.cpp">
</File>
<File
RelativePath="nodebuild_utility.cpp">
</File>
<File
RelativePath=".\processor.cpp">
</File>
<File
RelativePath=".\view.cpp">
</File>
<File
RelativePath=".\wad.cpp">
</File>
<Filter
Name="Reject(ed)"
Filter="">
<File
RelativePath=".\Unused\rejectbuilder.cpp">
<FileConfiguration
Name="Release|Win32"
ExcludedFromBuild="TRUE">
<Tool
Name="VCCLCompilerTool"/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32"
ExcludedFromBuild="TRUE">
<Tool
Name="VCCLCompilerTool"/>
</FileConfiguration>
</File>
<File
RelativePath=".\Unused\rejectbuilder.h">
<FileConfiguration
Name="Release|Win32"
ExcludedFromBuild="TRUE">
<Tool
Name="VCCustomBuildTool"/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32"
ExcludedFromBuild="TRUE">
<Tool
Name="VCCustomBuildTool"/>
</FileConfiguration>
</File>
<File
RelativePath=".\Unused\vis.cpp">
<FileConfiguration
Name="Release|Win32"
ExcludedFromBuild="TRUE">
<Tool
Name="VCCLCompilerTool"/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32"
ExcludedFromBuild="TRUE">
<Tool
Name="VCCLCompilerTool"/>
</FileConfiguration>
</File>
<File
RelativePath=".\Unused\visflow.cpp">
<FileConfiguration
Name="Release|Win32"
ExcludedFromBuild="TRUE">
<Tool
Name="VCCLCompilerTool"/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32"
ExcludedFromBuild="TRUE">
<Tool
Name="VCCLCompilerTool"/>
</FileConfiguration>
</File>
</Filter>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl">
<File
RelativePath=".\blockmapbuilder.h">
</File>
<File
RelativePath=".\doomdata.h">
</File>
<File
RelativePath="getopt.h">
</File>
<File
RelativePath=".\nodebuild.h">
</File>
<File
RelativePath=".\processor.h">
</File>
<File
RelativePath=".\resource.h">
</File>
<File
RelativePath=".\tarray.h">
</File>
<File
RelativePath=".\templates.h">
</File>
<File
RelativePath=".\wad.h">
</File>
<File
RelativePath=".\workdata.h">
</File>
<File
RelativePath=".\zdbsp.h">
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
<File
RelativePath=".\resource.rc">
</File>
</Filter>
<Filter
Name="zlib"
Filter="">
<File
RelativePath=".\zlib\adler32.c">
</File>
<File
RelativePath=".\zlib\compress.c">
</File>
<File
RelativePath=".\zlib\crc32.c">
</File>
<File
RelativePath=".\zlib\crc32.h">
</File>
<File
RelativePath=".\zlib\deflate.c">
</File>
<File
RelativePath=".\zlib\deflate.h">
</File>
<File
RelativePath=".\zlib\trees.c">
</File>
<File
RelativePath=".\zlib\trees.h">
</File>
<File
RelativePath=".\zlib\zconf.h">
</File>
<File
RelativePath=".\zlib\zlib.h">
</File>
<File
RelativePath=".\zlib\zutil.c">
</File>
</Filter>
<File
RelativePath=".\zdbsp.html">
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

1
zipbin.bat Normal file
View file

@ -0,0 +1 @@
kzip %1 release\zdbsp.exe zdbsp.html *.png

4
zipsrc.bat Normal file
View file

@ -0,0 +1,4 @@
zip -9 %1 COPYING *.cpp *.h *.c *.rc *.ds? *.sln *.vcproj unused/* zlib/*
kzip b%1 COPYING *.cpp *.h *.c *.rc *.ds? *.sln *.vcproj
zipmix %1 b%1
del b%1

74
zlib/adler32.c Normal file
View file

@ -0,0 +1,74 @@
/* adler32.c -- compute the Adler-32 checksum of a data stream
* Copyright (C) 1995-2003 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
#define ZLIB_INTERNAL
#include "zlib.h"
#define BASE 65521UL /* largest prime smaller than 65536 */
#define NMAX 5552
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
#define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
#define DO16(buf) DO8(buf,0); DO8(buf,8);
#ifdef NO_DIVIDE
# define MOD(a) \
do { \
if (a >= (BASE << 16)) a -= (BASE << 16); \
if (a >= (BASE << 15)) a -= (BASE << 15); \
if (a >= (BASE << 14)) a -= (BASE << 14); \
if (a >= (BASE << 13)) a -= (BASE << 13); \
if (a >= (BASE << 12)) a -= (BASE << 12); \
if (a >= (BASE << 11)) a -= (BASE << 11); \
if (a >= (BASE << 10)) a -= (BASE << 10); \
if (a >= (BASE << 9)) a -= (BASE << 9); \
if (a >= (BASE << 8)) a -= (BASE << 8); \
if (a >= (BASE << 7)) a -= (BASE << 7); \
if (a >= (BASE << 6)) a -= (BASE << 6); \
if (a >= (BASE << 5)) a -= (BASE << 5); \
if (a >= (BASE << 4)) a -= (BASE << 4); \
if (a >= (BASE << 3)) a -= (BASE << 3); \
if (a >= (BASE << 2)) a -= (BASE << 2); \
if (a >= (BASE << 1)) a -= (BASE << 1); \
if (a >= BASE) a -= BASE; \
} while (0)
#else
# define MOD(a) a %= BASE
#endif
/* ========================================================================= */
uLong ZEXPORT adler32(adler, buf, len)
uLong adler;
const Bytef *buf;
uInt len;
{
unsigned long s1 = adler & 0xffff;
unsigned long s2 = (adler >> 16) & 0xffff;
int k;
if (buf == Z_NULL) return 1L;
while (len > 0) {
k = len < NMAX ? (int)len : NMAX;
len -= k;
while (k >= 16) {
DO16(buf);
buf += 16;
k -= 16;
}
if (k != 0) do {
s1 += *buf++;
s2 += s1;
} while (--k);
MOD(s1);
MOD(s2);
}
return (s2 << 16) | s1;
}

79
zlib/compress.c Normal file
View file

@ -0,0 +1,79 @@
/* compress.c -- compress a memory buffer
* Copyright (C) 1995-2002 Jean-loup Gailly.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
#define ZLIB_INTERNAL
#include "zlib.h"
/* ===========================================================================
Compresses the source buffer into the destination buffer. The level
parameter has the same meaning as in deflateInit. sourceLen is the byte
length of the source buffer. Upon entry, destLen is the total size of the
destination buffer, which must be at least 0.1% larger than sourceLen plus
12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
memory, Z_BUF_ERROR if there was not enough room in the output buffer,
Z_STREAM_ERROR if the level parameter is invalid.
*/
int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
Bytef *dest;
uLongf *destLen;
const Bytef *source;
uLong sourceLen;
int level;
{
z_stream stream;
int err;
stream.next_in = (Bytef*)source;
stream.avail_in = (uInt)sourceLen;
#ifdef MAXSEG_64K
/* Check for source > 64K on 16-bit machine: */
if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
#endif
stream.next_out = dest;
stream.avail_out = (uInt)*destLen;
if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
stream.zalloc = (alloc_func)0;
stream.zfree = (free_func)0;
stream.opaque = (voidpf)0;
err = deflateInit(&stream, level);
if (err != Z_OK) return err;
err = deflate(&stream, Z_FINISH);
if (err != Z_STREAM_END) {
deflateEnd(&stream);
return err == Z_OK ? Z_BUF_ERROR : err;
}
*destLen = stream.total_out;
err = deflateEnd(&stream);
return err;
}
/* ===========================================================================
*/
int ZEXPORT compress (dest, destLen, source, sourceLen)
Bytef *dest;
uLongf *destLen;
const Bytef *source;
uLong sourceLen;
{
return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
}
/* ===========================================================================
If the default memLevel or windowBits for deflateInit() is changed, then
this function needs to be updated.
*/
uLong ZEXPORT compressBound (sourceLen)
uLong sourceLen;
{
return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11;
}

311
zlib/crc32.c Normal file
View file

@ -0,0 +1,311 @@
/* crc32.c -- compute the CRC-32 of a data stream
* Copyright (C) 1995-2003 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*
* Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
* CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
* tables for updating the shift register in one step with three exclusive-ors
* instead of four steps with four exclusive-ors. This results about a factor
* of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
*/
/* @(#) $Id$ */
#ifdef MAKECRCH
# include <stdio.h>
# ifndef DYNAMIC_CRC_TABLE
# define DYNAMIC_CRC_TABLE
# endif /* !DYNAMIC_CRC_TABLE */
#endif /* MAKECRCH */
#include "zutil.h" /* for STDC and FAR definitions */
#define local static
/* Find a four-byte integer type for crc32_little() and crc32_big(). */
#ifndef NOBYFOUR
# ifdef STDC /* need ANSI C limits.h to determine sizes */
# include <limits.h>
# define BYFOUR
# if (UINT_MAX == 0xffffffffUL)
typedef unsigned int u4;
# else
# if (ULONG_MAX == 0xffffffffUL)
typedef unsigned long u4;
# else
# if (USHRT_MAX == 0xffffffffUL)
typedef unsigned short u4;
# else
# undef BYFOUR /* can't find a four-byte integer type! */
# endif
# endif
# endif
# endif /* STDC */
#endif /* !NOBYFOUR */
/* Definitions for doing the crc four data bytes at a time. */
#ifdef BYFOUR
# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \
(((w)&0xff00)<<8)+(((w)&0xff)<<24))
local unsigned long crc32_little OF((unsigned long,
const unsigned char FAR *, unsigned));
local unsigned long crc32_big OF((unsigned long,
const unsigned char FAR *, unsigned));
# define TBLS 8
#else
# define TBLS 1
#endif /* BYFOUR */
#ifdef DYNAMIC_CRC_TABLE
local int crc_table_empty = 1;
local unsigned long FAR crc_table[TBLS][256];
local void make_crc_table OF((void));
#ifdef MAKECRCH
local void write_table OF((FILE *, const unsigned long FAR *));
#endif /* MAKECRCH */
/*
Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
Polynomials over GF(2) are represented in binary, one bit per coefficient,
with the lowest powers in the most significant bit. Then adding polynomials
is just exclusive-or, and multiplying a polynomial by x is a right shift by
one. If we call the above polynomial p, and represent a byte as the
polynomial q, also with the lowest power in the most significant bit (so the
byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
where a mod b means the remainder after dividing a by b.
This calculation is done using the shift-register method of multiplying and
taking the remainder. The register is initialized to zero, and for each
incoming bit, x^32 is added mod p to the register if the bit is a one (where
x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
x (which is shifting right by one and adding x^32 mod p if the bit shifted
out is a one). We start with the highest power (least significant bit) of
q and repeat for all eight bits of q.
The first table is simply the CRC of all possible eight bit values. This is
all the information needed to generate CRCs on data a byte at a time for all
combinations of CRC register values and incoming bytes. The remaining tables
allow for word-at-a-time CRC calculation for both big-endian and little-
endian machines, where a word is four bytes.
*/
local void make_crc_table()
{
unsigned long c;
int n, k;
unsigned long poly; /* polynomial exclusive-or pattern */
/* terms of polynomial defining this crc (except x^32): */
static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
/* make exclusive-or pattern from polynomial (0xedb88320UL) */
poly = 0UL;
for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++)
poly |= 1UL << (31 - p[n]);
/* generate a crc for every 8-bit value */
for (n = 0; n < 256; n++) {
c = (unsigned long)n;
for (k = 0; k < 8; k++)
c = c & 1 ? poly ^ (c >> 1) : c >> 1;
crc_table[0][n] = c;
}
#ifdef BYFOUR
/* generate crc for each value followed by one, two, and three zeros, and
then the byte reversal of those as well as the first table */
for (n = 0; n < 256; n++) {
c = crc_table[0][n];
crc_table[4][n] = REV(c);
for (k = 1; k < 4; k++) {
c = crc_table[0][c & 0xff] ^ (c >> 8);
crc_table[k][n] = c;
crc_table[k + 4][n] = REV(c);
}
}
#endif /* BYFOUR */
crc_table_empty = 0;
#ifdef MAKECRCH
/* write out CRC tables to crc32.h */
{
FILE *out;
out = fopen("crc32.h", "w");
if (out == NULL) return;
fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
fprintf(out, "local const unsigned long FAR ");
fprintf(out, "crc_table[TBLS][256] =\n{\n {\n");
write_table(out, crc_table[0]);
# ifdef BYFOUR
fprintf(out, "#ifdef BYFOUR\n");
for (k = 1; k < 8; k++) {
fprintf(out, " },\n {\n");
write_table(out, crc_table[k]);
}
fprintf(out, "#endif\n");
# endif /* BYFOUR */
fprintf(out, " }\n};\n");
fclose(out);
}
#endif /* MAKECRCH */
}
#ifdef MAKECRCH
local void write_table(out, table)
FILE *out;
const unsigned long FAR *table;
{
int n;
for (n = 0; n < 256; n++)
fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n],
n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
}
#endif /* MAKECRCH */
#else /* !DYNAMIC_CRC_TABLE */
/* ========================================================================
* Tables of CRC-32s of all single-byte values, made by make_crc_table().
*/
#include "crc32.h"
#endif /* DYNAMIC_CRC_TABLE */
/* =========================================================================
* This function can be used by asm versions of crc32()
*/
const unsigned long FAR * ZEXPORT get_crc_table()
{
#ifdef DYNAMIC_CRC_TABLE
if (crc_table_empty) make_crc_table();
#endif /* DYNAMIC_CRC_TABLE */
return (const unsigned long FAR *)crc_table;
}
/* ========================================================================= */
#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
/* ========================================================================= */
unsigned long ZEXPORT crc32(crc, buf, len)
unsigned long crc;
const unsigned char FAR *buf;
unsigned len;
{
if (buf == Z_NULL) return 0UL;
#ifdef DYNAMIC_CRC_TABLE
if (crc_table_empty)
make_crc_table();
#endif /* DYNAMIC_CRC_TABLE */
#ifdef BYFOUR
if (sizeof(void *) == sizeof(ptrdiff_t)) {
u4 endian;
endian = 1;
if (*((unsigned char *)(&endian)))
return crc32_little(crc, buf, len);
else
return crc32_big(crc, buf, len);
}
#endif /* BYFOUR */
crc = crc ^ 0xffffffffUL;
while (len >= 8) {
DO8;
len -= 8;
}
if (len) do {
DO1;
} while (--len);
return crc ^ 0xffffffffUL;
}
#ifdef BYFOUR
/* ========================================================================= */
#define DOLIT4 c ^= *buf4++; \
c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
/* ========================================================================= */
local unsigned long crc32_little(crc, buf, len)
unsigned long crc;
const unsigned char FAR *buf;
unsigned len;
{
register u4 c;
register const u4 FAR *buf4;
c = (u4)crc;
c = ~c;
while (len && ((ptrdiff_t)buf & 3)) {
c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
len--;
}
buf4 = (const u4 FAR *)buf;
while (len >= 32) {
DOLIT32;
len -= 32;
}
while (len >= 4) {
DOLIT4;
len -= 4;
}
buf = (const unsigned char FAR *)buf4;
if (len) do {
c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
} while (--len);
c = ~c;
return (unsigned long)c;
}
/* ========================================================================= */
#define DOBIG4 c ^= *++buf4; \
c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
/* ========================================================================= */
local unsigned long crc32_big(crc, buf, len)
unsigned long crc;
const unsigned char FAR *buf;
unsigned len;
{
register u4 c;
register const u4 FAR *buf4;
c = REV((u4)crc);
c = ~c;
while (len && ((ptrdiff_t)buf & 3)) {
c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
len--;
}
buf4 = (const u4 FAR *)buf;
buf4--;
while (len >= 32) {
DOBIG32;
len -= 32;
}
while (len >= 4) {
DOBIG4;
len -= 4;
}
buf4++;
buf = (const unsigned char FAR *)buf4;
if (len) do {
c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
} while (--len);
c = ~c;
return (unsigned long)(REV(c));
}
#endif /* BYFOUR */

441
zlib/crc32.h Normal file
View file

@ -0,0 +1,441 @@
/* crc32.h -- tables for rapid CRC calculation
* Generated automatically by crc32.c
*/
local const unsigned long FAR crc_table[TBLS][256] =
{
{
0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
0x2d02ef8dUL
#ifdef BYFOUR
},
{
0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
0x9324fd72UL
},
{
0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
0xbe9834edUL
},
{
0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
0xde0506f1UL
},
{
0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
0x8def022dUL
},
{
0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
0x72fd2493UL
},
{
0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
0xed3498beUL
},
{
0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
0xf10605deUL
#endif
}
};

1502
zlib/deflate.c Normal file

File diff suppressed because it is too large Load diff

326
zlib/deflate.h Normal file
View file

@ -0,0 +1,326 @@
/* deflate.h -- internal compression state
* Copyright (C) 1995-2002 Jean-loup Gailly
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* WARNING: this file should *not* be used by applications. It is
part of the implementation of the compression library and is
subject to change. Applications should only use zlib.h.
*/
/* @(#) $Id$ */
#ifndef DEFLATE_H
#define DEFLATE_H
#include "zutil.h"
/* define NO_GZIP when compiling if you want to disable gzip header and
trailer creation by deflate(). NO_GZIP would be used to avoid linking in
the crc code when it is not needed. For shared libraries, gzip encoding
should be left enabled. */
#ifndef NO_GZIP
# define GZIP
#endif
/* ===========================================================================
* Internal compression state.
*/
#define LENGTH_CODES 29
/* number of length codes, not counting the special END_BLOCK code */
#define LITERALS 256
/* number of literal bytes 0..255 */
#define L_CODES (LITERALS+1+LENGTH_CODES)
/* number of Literal or Length codes, including the END_BLOCK code */
#define D_CODES 30
/* number of distance codes */
#define BL_CODES 19
/* number of codes used to transfer the bit lengths */
#define HEAP_SIZE (2*L_CODES+1)
/* maximum heap size */
#define MAX_BITS 15
/* All codes must not exceed MAX_BITS bits */
#define INIT_STATE 42
#define BUSY_STATE 113
#define FINISH_STATE 666
/* Stream status */
/* Data structure describing a single value and its code string. */
typedef struct ct_data_s {
union {
ush freq; /* frequency count */
ush code; /* bit string */
} fc;
union {
ush dad; /* father node in Huffman tree */
ush len; /* length of bit string */
} dl;
} FAR ct_data;
#define Freq fc.freq
#define Code fc.code
#define Dad dl.dad
#define Len dl.len
typedef struct static_tree_desc_s static_tree_desc;
typedef struct tree_desc_s {
ct_data *dyn_tree; /* the dynamic tree */
int max_code; /* largest code with non zero frequency */
static_tree_desc *stat_desc; /* the corresponding static tree */
} FAR tree_desc;
typedef ush Pos;
typedef Pos FAR Posf;
typedef unsigned IPos;
/* A Pos is an index in the character window. We use short instead of int to
* save space in the various tables. IPos is used only for parameter passing.
*/
typedef struct internal_state {
z_streamp strm; /* pointer back to this zlib stream */
int status; /* as the name implies */
Bytef *pending_buf; /* output still pending */
ulg pending_buf_size; /* size of pending_buf */
Bytef *pending_out; /* next pending byte to output to the stream */
int pending; /* nb of bytes in the pending buffer */
int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
Byte data_type; /* UNKNOWN, BINARY or ASCII */
Byte method; /* STORED (for zip only) or DEFLATED */
int last_flush; /* value of flush param for previous deflate call */
/* used by deflate.c: */
uInt w_size; /* LZ77 window size (32K by default) */
uInt w_bits; /* log2(w_size) (8..16) */
uInt w_mask; /* w_size - 1 */
Bytef *window;
/* Sliding window. Input bytes are read into the second half of the window,
* and move to the first half later to keep a dictionary of at least wSize
* bytes. With this organization, matches are limited to a distance of
* wSize-MAX_MATCH bytes, but this ensures that IO is always
* performed with a length multiple of the block size. Also, it limits
* the window size to 64K, which is quite useful on MSDOS.
* To do: use the user input buffer as sliding window.
*/
ulg window_size;
/* Actual size of window: 2*wSize, except when the user input buffer
* is directly used as sliding window.
*/
Posf *prev;
/* Link to older string with same hash index. To limit the size of this
* array to 64K, this link is maintained only for the last 32K strings.
* An index in this array is thus a window index modulo 32K.
*/
Posf *head; /* Heads of the hash chains or NIL. */
uInt ins_h; /* hash index of string to be inserted */
uInt hash_size; /* number of elements in hash table */
uInt hash_bits; /* log2(hash_size) */
uInt hash_mask; /* hash_size-1 */
uInt hash_shift;
/* Number of bits by which ins_h must be shifted at each input
* step. It must be such that after MIN_MATCH steps, the oldest
* byte no longer takes part in the hash key, that is:
* hash_shift * MIN_MATCH >= hash_bits
*/
long block_start;
/* Window position at the beginning of the current output block. Gets
* negative when the window is moved backwards.
*/
uInt match_length; /* length of best match */
IPos prev_match; /* previous match */
int match_available; /* set if previous match exists */
uInt strstart; /* start of string to insert */
uInt match_start; /* start of matching string */
uInt lookahead; /* number of valid bytes ahead in window */
uInt prev_length;
/* Length of the best match at previous step. Matches not greater than this
* are discarded. This is used in the lazy match evaluation.
*/
uInt max_chain_length;
/* To speed up deflation, hash chains are never searched beyond this
* length. A higher limit improves compression ratio but degrades the
* speed.
*/
uInt max_lazy_match;
/* Attempt to find a better match only when the current match is strictly
* smaller than this value. This mechanism is used only for compression
* levels >= 4.
*/
# define max_insert_length max_lazy_match
/* Insert new strings in the hash table only if the match length is not
* greater than this length. This saves time but degrades compression.
* max_insert_length is used only for compression levels <= 3.
*/
int level; /* compression level (1..9) */
int strategy; /* favor or force Huffman coding*/
uInt good_match;
/* Use a faster search when the previous match is longer than this */
int nice_match; /* Stop searching when current match exceeds this */
/* used by trees.c: */
/* Didn't use ct_data typedef below to supress compiler warning */
struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
struct tree_desc_s l_desc; /* desc. for literal tree */
struct tree_desc_s d_desc; /* desc. for distance tree */
struct tree_desc_s bl_desc; /* desc. for bit length tree */
ush bl_count[MAX_BITS+1];
/* number of codes at each bit length for an optimal tree */
int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
int heap_len; /* number of elements in the heap */
int heap_max; /* element of largest frequency */
/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
* The same heap array is used to build all trees.
*/
uch depth[2*L_CODES+1];
/* Depth of each subtree used as tie breaker for trees of equal frequency
*/
uchf *l_buf; /* buffer for literals or lengths */
uInt lit_bufsize;
/* Size of match buffer for literals/lengths. There are 4 reasons for
* limiting lit_bufsize to 64K:
* - frequencies can be kept in 16 bit counters
* - if compression is not successful for the first block, all input
* data is still in the window so we can still emit a stored block even
* when input comes from standard input. (This can also be done for
* all blocks if lit_bufsize is not greater than 32K.)
* - if compression is not successful for a file smaller than 64K, we can
* even emit a stored file instead of a stored block (saving 5 bytes).
* This is applicable only for zip (not gzip or zlib).
* - creating new Huffman trees less frequently may not provide fast
* adaptation to changes in the input data statistics. (Take for
* example a binary file with poorly compressible code followed by
* a highly compressible string table.) Smaller buffer sizes give
* fast adaptation but have of course the overhead of transmitting
* trees more frequently.
* - I can't count above 4
*/
uInt last_lit; /* running index in l_buf */
ushf *d_buf;
/* Buffer for distances. To simplify the code, d_buf and l_buf have
* the same number of elements. To use different lengths, an extra flag
* array would be necessary.
*/
ulg opt_len; /* bit length of current block with optimal trees */
ulg static_len; /* bit length of current block with static trees */
uInt matches; /* number of string matches in current block */
int last_eob_len; /* bit length of EOB code for last block */
#ifdef DEBUG
ulg compressed_len; /* total bit length of compressed file mod 2^32 */
ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
#endif
ush bi_buf;
/* Output buffer. bits are inserted starting at the bottom (least
* significant bits).
*/
int bi_valid;
/* Number of valid bits in bi_buf. All bits above the last valid bit
* are always zero.
*/
} FAR deflate_state;
/* Output a byte on the stream.
* IN assertion: there is enough room in pending_buf.
*/
#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
/* Minimum amount of lookahead, except at the end of the input file.
* See deflate.c for comments about the MIN_MATCH+1.
*/
#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)
/* In order to simplify the code, particularly on 16 bit machines, match
* distances are limited to MAX_DIST instead of WSIZE.
*/
/* in trees.c */
void _tr_init OF((deflate_state *s));
int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len,
int eof));
void _tr_align OF((deflate_state *s));
void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
int eof));
#define d_code(dist) \
((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
/* Mapping from a distance to a distance code. dist is the distance - 1 and
* must not have side effects. _dist_code[256] and _dist_code[257] are never
* used.
*/
#ifndef DEBUG
/* Inline versions of _tr_tally for speed: */
#if defined(GEN_TREES_H) || !defined(STDC)
extern uch _length_code[];
extern uch _dist_code[];
#else
extern const uch _length_code[];
extern const uch _dist_code[];
#endif
# define _tr_tally_lit(s, c, flush) \
{ uch cc = (c); \
s->d_buf[s->last_lit] = 0; \
s->l_buf[s->last_lit++] = cc; \
s->dyn_ltree[cc].Freq++; \
flush = (s->last_lit == s->lit_bufsize-1); \
}
# define _tr_tally_dist(s, distance, length, flush) \
{ uch len = (length); \
ush dist = (distance); \
s->d_buf[s->last_lit] = dist; \
s->l_buf[s->last_lit++] = len; \
dist--; \
s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
s->dyn_dtree[d_code(dist)].Freq++; \
flush = (s->last_lit == s->lit_bufsize-1); \
}
#else
# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
# define _tr_tally_dist(s, distance, length, flush) \
flush = _tr_tally(s, distance, length)
#endif
#endif /* DEFLATE_H */

1215
zlib/trees.c Normal file

File diff suppressed because it is too large Load diff

128
zlib/trees.h Normal file
View file

@ -0,0 +1,128 @@
/* header created automatically with -DGEN_TREES_H */
local const ct_data static_ltree[L_CODES+2] = {
{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}},
{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}},
{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}},
{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}},
{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}},
{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}},
{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}},
{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}},
{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}},
{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}},
{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}},
{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}},
{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}},
{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}},
{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}},
{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}},
{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}},
{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}},
{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}},
{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}},
{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}},
{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}},
{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}},
{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}},
{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}},
{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}},
{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}},
{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}},
{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}},
{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}},
{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}},
{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}},
{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}},
{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}},
{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}},
{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}},
{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}},
{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}},
{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}},
{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}},
{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}},
{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}},
{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}},
{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}},
{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}},
{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}},
{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}},
{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}},
{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}},
{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}},
{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}},
{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}},
{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}},
{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}},
{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}},
{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}},
{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}},
{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}}
};
local const ct_data static_dtree[D_CODES] = {
{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
};
const uch _dist_code[DIST_CODE_LEN] = {
0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,
18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
};
const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {
0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
};
local const int base_length[LENGTH_CODES] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
64, 80, 96, 112, 128, 160, 192, 224, 0
};
local const int base_dist[D_CODES] = {
0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
};

323
zlib/zconf.h Normal file
View file

@ -0,0 +1,323 @@
/* zconf.h -- configuration of the zlib compression library
* Copyright (C) 1995-2003 Jean-loup Gailly.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
#ifndef ZCONF_H
#define ZCONF_H
/*
* If you *really* need a unique prefix for all types and library functions,
* compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
*/
#ifdef Z_PREFIX
# define deflateInit_ z_deflateInit_
# define deflate z_deflate
# define deflateEnd z_deflateEnd
# define inflateInit_ z_inflateInit_
# define inflate z_inflate
# define inflateEnd z_inflateEnd
# define deflateInit2_ z_deflateInit2_
# define deflateSetDictionary z_deflateSetDictionary
# define deflateCopy z_deflateCopy
# define deflateReset z_deflateReset
# define deflatePrime z_deflatePrime
# define deflateParams z_deflateParams
# define deflateBound z_deflateBound
# define inflateInit2_ z_inflateInit2_
# define inflateSetDictionary z_inflateSetDictionary
# define inflateSync z_inflateSync
# define inflateSyncPoint z_inflateSyncPoint
# define inflateCopy z_inflateCopy
# define inflateReset z_inflateReset
# define compress z_compress
# define compress2 z_compress2
# define compressBound z_compressBound
# define uncompress z_uncompress
# define adler32 z_adler32
# define crc32 z_crc32
# define get_crc_table z_get_crc_table
# define Byte z_Byte
# define uInt z_uInt
# define uLong z_uLong
# define Bytef z_Bytef
# define charf z_charf
# define intf z_intf
# define uIntf z_uIntf
# define uLongf z_uLongf
# define voidpf z_voidpf
# define voidp z_voidp
#endif
#if defined(__MSDOS__) && !defined(MSDOS)
# define MSDOS
#endif
#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
# define OS2
#endif
#if defined(_WINDOWS) && !defined(WINDOWS)
# define WINDOWS
#endif
#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
# define WIN32
#endif
#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
# ifndef SYS16BIT
# define SYS16BIT
# endif
# endif
#endif
/*
* Compile with -DMAXSEG_64K if the alloc function cannot allocate more
* than 64k bytes at a time (needed on systems with 16-bit int).
*/
#ifdef SYS16BIT
# define MAXSEG_64K
#endif
#ifdef MSDOS
# define UNALIGNED_OK
#endif
#ifdef __STDC_VERSION__
# ifndef STDC
# define STDC
# endif
# if __STDC_VERSION__ >= 199901L
# ifndef STDC99
# define STDC99
# endif
# endif
#endif
#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
# define STDC
#endif
#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
# define STDC
#endif
#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
# define STDC
#endif
#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
# define STDC
#endif
#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
# define STDC
#endif
#ifndef STDC
# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
# define const /* note: need a more gentle solution here */
# endif
#endif
/* Some Mac compilers merge all .h files incorrectly: */
#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
# define NO_DUMMY_DECL
#endif
/* Maximum value for memLevel in deflateInit2 */
#ifndef MAX_MEM_LEVEL
# ifdef MAXSEG_64K
# define MAX_MEM_LEVEL 8
# else
# define MAX_MEM_LEVEL 9
# endif
#endif
/* Maximum value for windowBits in deflateInit2 and inflateInit2.
* WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
* created by gzip. (Files created by minigzip can still be extracted by
* gzip.)
*/
#ifndef MAX_WBITS
# define MAX_WBITS 15 /* 32K LZ77 window */
#endif
/* The memory requirements for deflate are (in bytes):
(1 << (windowBits+2)) + (1 << (memLevel+9))
that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
plus a few kilobytes for small objects. For example, if you want to reduce
the default memory requirements from 256K to 128K, compile with
make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
Of course this will generally degrade compression (there's no free lunch).
The memory requirements for inflate are (in bytes) 1 << windowBits
that is, 32K for windowBits=15 (default value) plus a few kilobytes
for small objects.
*/
/* Type declarations */
#ifndef OF /* function prototypes */
# ifdef STDC
# define OF(args) args
# else
# define OF(args) ()
# endif
#endif
/* The following definitions for FAR are needed only for MSDOS mixed
* model programming (small or medium model with some far allocations).
* This was tested only with MSC; for other MSDOS compilers you may have
* to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
* just define FAR to be empty.
*/
#ifdef SYS16BIT
# if defined(M_I86SM) || defined(M_I86MM)
/* MSC small or medium model */
# define SMALL_MEDIUM
# ifdef _MSC_VER
# define FAR _far
# else
# define FAR far
# endif
# endif
# if (defined(__SMALL__) || defined(__MEDIUM__))
/* Turbo C small or medium model */
# define SMALL_MEDIUM
# ifdef __BORLANDC__
# define FAR _far
# else
# define FAR far
# endif
# endif
#endif
#if defined(WINDOWS) || defined(WIN32)
/* If building or using zlib as a DLL, define ZLIB_DLL.
* This is not mandatory, but it offers a little performance increase.
*/
# ifdef ZLIB_DLL
# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
# ifdef ZLIB_INTERNAL
# define ZEXTERN extern __declspec(dllexport)
# else
# define ZEXTERN extern __declspec(dllimport)
# endif
# endif
# endif /* ZLIB_DLL */
/* If building or using zlib with the WINAPI/WINAPIV calling convention,
* define ZLIB_WINAPI.
* Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
*/
# ifdef ZLIB_WINAPI
# ifdef FAR
# undef FAR
# endif
# include <windows.h>
/* No need for _export, use ZLIB.DEF instead. */
/* For complete Windows compatibility, use WINAPI, not __stdcall. */
# define ZEXPORT WINAPI
# ifdef WIN32
# define ZEXPORTVA WINAPIV
# else
# define ZEXPORTVA FAR CDECL
# endif
# endif
#endif
#if defined (__BEOS__)
# ifdef ZLIB_DLL
# ifdef ZLIB_INTERNAL
# define ZEXPORT __declspec(dllexport)
# define ZEXPORTVA __declspec(dllexport)
# else
# define ZEXPORT __declspec(dllimport)
# define ZEXPORTVA __declspec(dllimport)
# endif
# endif
#endif
#ifndef ZEXTERN
# define ZEXTERN extern
#endif
#ifndef ZEXPORT
# define ZEXPORT
#endif
#ifndef ZEXPORTVA
# define ZEXPORTVA
#endif
#ifndef FAR
# define FAR
#endif
#if !defined(__MACTYPES__)
typedef unsigned char Byte; /* 8 bits */
#endif
typedef unsigned int uInt; /* 16 bits or more */
typedef unsigned long uLong; /* 32 bits or more */
#ifdef SMALL_MEDIUM
/* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
# define Bytef Byte FAR
#else
typedef Byte FAR Bytef;
#endif
typedef char FAR charf;
typedef int FAR intf;
typedef uInt FAR uIntf;
typedef uLong FAR uLongf;
#ifdef STDC
typedef void const *voidpc;
typedef void FAR *voidpf;
typedef void *voidp;
#else
typedef Byte const *voidpc;
typedef Byte FAR *voidpf;
typedef Byte *voidp;
#endif
#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */
# include <sys/types.h> /* for off_t */
# include <unistd.h> /* for SEEK_* and off_t */
# ifdef VMS
# include <unixio.h> /* for off_t */
# endif
# define z_off_t off_t
#endif
#ifndef SEEK_SET
# define SEEK_SET 0 /* Seek from beginning of file. */
# define SEEK_CUR 1 /* Seek from current position. */
# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
#endif
#ifndef z_off_t
# define z_off_t long
#endif
#if defined(__OS400__)
#define NO_vsnprintf
#endif
#if defined(__MVS__)
# define NO_vsnprintf
# ifdef FAR
# undef FAR
# endif
#endif
/* MVS linker does not support external names larger than 8 bytes */
#if defined(__MVS__)
# pragma map(deflateInit_,"DEIN")
# pragma map(deflateInit2_,"DEIN2")
# pragma map(deflateEnd,"DEEND")
# pragma map(deflateBound,"DEBND")
# pragma map(inflateInit_,"ININ")
# pragma map(inflateInit2_,"ININ2")
# pragma map(inflateEnd,"INEND")
# pragma map(inflateSync,"INSY")
# pragma map(inflateSetDictionary,"INSEDI")
# pragma map(compressBound,"CMBND")
# pragma map(inflate_table,"INTABL")
# pragma map(inflate_fast,"INFA")
# pragma map(inflate_copyright,"INCOPY")
#endif
#endif /* ZCONF_H */

1200
zlib/zlib.h Normal file

File diff suppressed because it is too large Load diff

319
zlib/zutil.c Normal file
View file

@ -0,0 +1,319 @@
/* zutil.c -- target dependent utility functions for the compression library
* Copyright (C) 1995-2003 Jean-loup Gailly.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
#include "zutil.h"
#ifndef NO_DUMMY_DECL
struct internal_state {int dummy;}; /* for buggy compilers */
#endif
#ifndef STDC
extern void exit OF((int));
#endif
const char * const z_errmsg[10] = {
"need dictionary", /* Z_NEED_DICT 2 */
"stream end", /* Z_STREAM_END 1 */
"", /* Z_OK 0 */
"file error", /* Z_ERRNO (-1) */
"stream error", /* Z_STREAM_ERROR (-2) */
"data error", /* Z_DATA_ERROR (-3) */
"insufficient memory", /* Z_MEM_ERROR (-4) */
"buffer error", /* Z_BUF_ERROR (-5) */
"incompatible version",/* Z_VERSION_ERROR (-6) */
""};
const char * ZEXPORT zlibVersion()
{
return ZLIB_VERSION;
}
uLong ZEXPORT zlibCompileFlags()
{
uLong flags;
flags = 0;
switch (sizeof(uInt)) {
case 2: break;
case 4: flags += 1; break;
case 8: flags += 2; break;
default: flags += 3;
}
switch (sizeof(uLong)) {
case 2: break;
case 4: flags += 1 << 2; break;
case 8: flags += 2 << 2; break;
default: flags += 3 << 2;
}
switch (sizeof(voidpf)) {
case 2: break;
case 4: flags += 1 << 4; break;
case 8: flags += 2 << 4; break;
default: flags += 3 << 4;
}
switch (sizeof(z_off_t)) {
case 2: break;
case 4: flags += 1 << 6; break;
case 8: flags += 2 << 6; break;
default: flags += 3 << 6;
}
#ifdef DEBUG
flags += 1 << 8;
#endif
#if defined(ASMV) || defined(ASMINF)
flags += 1 << 9;
#endif
#ifdef ZLIB_WINAPI
flags += 1 << 10;
#endif
#ifdef BUILDFIXED
flags += 1 << 12;
#endif
#ifdef DYNAMIC_CRC_TABLE
flags += 1 << 13;
#endif
#ifdef NO_GZCOMPRESS
flags += 1 << 16;
#endif
#ifdef NO_GZIP
flags += 1 << 17;
#endif
#ifdef PKZIP_BUG_WORKAROUND
flags += 1 << 20;
#endif
#ifdef FASTEST
flags += 1 << 21;
#endif
#ifdef STDC
# ifdef NO_vsnprintf
flags += 1 << 25;
# ifdef HAS_vsprintf_void
flags += 1 << 26;
# endif
# else
# ifdef HAS_vsnprintf_void
flags += 1 << 26;
# endif
# endif
#else
flags += 1 << 24;
# ifdef NO_snprintf
flags += 1 << 25;
# ifdef HAS_sprintf_void
flags += 1 << 26;
# endif
# else
# ifdef HAS_snprintf_void
flags += 1 << 26;
# endif
# endif
#endif
return flags;
}
#ifdef DEBUG
# ifndef verbose
# define verbose 0
# endif
int z_verbose = verbose;
void z_error (m)
char *m;
{
fprintf(stderr, "%s\n", m);
exit(1);
}
#endif
/* exported to allow conversion of error code to string for compress() and
* uncompress()
*/
const char * ZEXPORT zError(err)
int err;
{
return ERR_MSG(err);
}
#if defined(_WIN32_WCE)
/* does not exist on WCE */
int errno = 0;
#endif
#ifndef HAVE_MEMCPY
void zmemcpy(dest, source, len)
Bytef* dest;
const Bytef* source;
uInt len;
{
if (len == 0) return;
do {
*dest++ = *source++; /* ??? to be unrolled */
} while (--len != 0);
}
int zmemcmp(s1, s2, len)
const Bytef* s1;
const Bytef* s2;
uInt len;
{
uInt j;
for (j = 0; j < len; j++) {
if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
}
return 0;
}
void zmemzero(dest, len)
Bytef* dest;
uInt len;
{
if (len == 0) return;
do {
*dest++ = 0; /* ??? to be unrolled */
} while (--len != 0);
}
#endif
#ifdef SYS16BIT
#ifdef __TURBOC__
/* Turbo C in 16-bit mode */
# define MY_ZCALLOC
/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
* and farmalloc(64K) returns a pointer with an offset of 8, so we
* must fix the pointer. Warning: the pointer must be put back to its
* original form in order to free it, use zcfree().
*/
#define MAX_PTR 10
/* 10*64K = 640K */
local int next_ptr = 0;
typedef struct ptr_table_s {
voidpf org_ptr;
voidpf new_ptr;
} ptr_table;
local ptr_table table[MAX_PTR];
/* This table is used to remember the original form of pointers
* to large buffers (64K). Such pointers are normalized with a zero offset.
* Since MSDOS is not a preemptive multitasking OS, this table is not
* protected from concurrent access. This hack doesn't work anyway on
* a protected system like OS/2. Use Microsoft C instead.
*/
voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
{
voidpf buf = opaque; /* just to make some compilers happy */
ulg bsize = (ulg)items*size;
/* If we allocate less than 65520 bytes, we assume that farmalloc
* will return a usable pointer which doesn't have to be normalized.
*/
if (bsize < 65520L) {
buf = farmalloc(bsize);
if (*(ush*)&buf != 0) return buf;
} else {
buf = farmalloc(bsize + 16L);
}
if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
table[next_ptr].org_ptr = buf;
/* Normalize the pointer to seg:0 */
*((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
*(ush*)&buf = 0;
table[next_ptr++].new_ptr = buf;
return buf;
}
void zcfree (voidpf opaque, voidpf ptr)
{
int n;
if (*(ush*)&ptr != 0) { /* object < 64K */
farfree(ptr);
return;
}
/* Find the original pointer */
for (n = 0; n < next_ptr; n++) {
if (ptr != table[n].new_ptr) continue;
farfree(table[n].org_ptr);
while (++n < next_ptr) {
table[n-1] = table[n];
}
next_ptr--;
return;
}
ptr = opaque; /* just to make some compilers happy */
Assert(0, "zcfree: ptr not found");
}
#endif /* __TURBOC__ */
#ifdef M_I86
/* Microsoft C in 16-bit mode */
# define MY_ZCALLOC
#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
# define _halloc halloc
# define _hfree hfree
#endif
voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
{
if (opaque) opaque = 0; /* to make compiler happy */
return _halloc((long)items, size);
}
void zcfree (voidpf opaque, voidpf ptr)
{
if (opaque) opaque = 0; /* to make compiler happy */
_hfree(ptr);
}
#endif /* M_I86 */
#endif /* SYS16BIT */
#ifndef MY_ZCALLOC /* Any system without a special alloc function */
#ifndef STDC
extern voidp malloc OF((uInt size));
extern voidp calloc OF((uInt items, uInt size));
extern void free OF((voidpf ptr));
#endif
voidpf zcalloc (opaque, items, size)
voidpf opaque;
unsigned items;
unsigned size;
{
if (opaque) items += size - size; /* make compiler happy */
return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
(voidpf)calloc(items, size);
}
void zcfree (opaque, ptr)
voidpf opaque;
voidpf ptr;
{
free(ptr);
if (opaque) return; /* make compiler happy */
}
#endif /* MY_ZCALLOC */

258
zlib/zutil.h Normal file
View file

@ -0,0 +1,258 @@
/* zutil.h -- internal interface and configuration of the compression library
* Copyright (C) 1995-2003 Jean-loup Gailly.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* WARNING: this file should *not* be used by applications. It is
part of the implementation of the compression library and is
subject to change. Applications should only use zlib.h.
*/
/* @(#) $Id$ */
#ifndef ZUTIL_H
#define ZUTIL_H
#define ZLIB_INTERNAL
#include "zlib.h"
#ifdef STDC
# include <stddef.h>
# include <string.h>
# include <stdlib.h>
#endif
#ifdef NO_ERRNO_H
extern int errno;
#else
# include <errno.h>
#endif
#ifndef local
# define local static
#endif
/* compile with -Dlocal if your debugger can't find static symbols */
typedef unsigned char uch;
typedef uch FAR uchf;
typedef unsigned short ush;
typedef ush FAR ushf;
typedef unsigned long ulg;
extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
/* (size given to avoid silly warnings with Visual C++) */
#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
#define ERR_RETURN(strm,err) \
return (strm->msg = (char*)ERR_MSG(err), (err))
/* To be used only when the state is known to be valid */
/* common constants */
#ifndef DEF_WBITS
# define DEF_WBITS MAX_WBITS
#endif
/* default windowBits for decompression. MAX_WBITS is for compression only */
#if MAX_MEM_LEVEL >= 8
# define DEF_MEM_LEVEL 8
#else
# define DEF_MEM_LEVEL MAX_MEM_LEVEL
#endif
/* default memLevel */
#define STORED_BLOCK 0
#define STATIC_TREES 1
#define DYN_TREES 2
/* The three kinds of block type */
#define MIN_MATCH 3
#define MAX_MATCH 258
/* The minimum and maximum match lengths */
#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
/* target dependencies */
#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
# define OS_CODE 0x00
# if defined(__TURBOC__) || defined(__BORLANDC__)
# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
/* Allow compilation with ANSI keywords only enabled */
void _Cdecl farfree( void *block );
void *_Cdecl farmalloc( unsigned long nbytes );
# else
# include <alloc.h>
# endif
# else /* MSC or DJGPP */
# include <malloc.h>
# endif
#endif
#ifdef AMIGA
# define OS_CODE 0x01
#endif
#if defined(VAXC) || defined(VMS)
# define OS_CODE 0x02
# define F_OPEN(name, mode) \
fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
#endif
#if defined(ATARI) || defined(atarist)
# define OS_CODE 0x05
#endif
#ifdef OS2
# define OS_CODE 0x06
#endif
#if defined(MACOS) || defined(TARGET_OS_MAC)
# define OS_CODE 0x07
# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
# include <unix.h> /* for fdopen */
# else
# ifndef fdopen
# define fdopen(fd,mode) NULL /* No fdopen() */
# endif
# endif
#endif
#ifdef TOPS20
# define OS_CODE 0x0a
#endif
#ifdef WIN32
# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */
# define OS_CODE 0x0b
# endif
#endif
#ifdef __50SERIES /* Prime/PRIMOS */
# define OS_CODE 0x0f
#endif
#if defined(_BEOS_) || defined(RISCOS)
# define fdopen(fd,mode) NULL /* No fdopen() */
#endif
#if (defined(_MSC_VER) && (_MSC_VER > 600))
# if defined(_WIN32_WCE)
# define fdopen(fd,mode) NULL /* No fdopen() */
# ifndef _PTRDIFF_T_DEFINED
typedef int ptrdiff_t;
# define _PTRDIFF_T_DEFINED
# endif
# else
# define fdopen(fd,type) _fdopen(fd,type)
# endif
#endif
/* common defaults */
#ifndef OS_CODE
# define OS_CODE 0x03 /* assume Unix */
#endif
#ifndef F_OPEN
# define F_OPEN(name, mode) fopen((name), (mode))
#endif
/* functions */
#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
# ifndef HAVE_VSNPRINTF
# define HAVE_VSNPRINTF
# endif
#endif
#if defined(__CYGWIN__)
# ifndef HAVE_VSNPRINTF
# define HAVE_VSNPRINTF
# endif
#endif
#ifndef HAVE_VSNPRINTF
# ifdef MSDOS
/* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
but for now we just assume it doesn't. */
# define NO_vsnprintf
# endif
# ifdef __TURBOC__
# define NO_vsnprintf
# endif
# ifdef WIN32
/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
# if !defined(vsnprintf) && !defined(NO_vsnprintf)
# define vsnprintf _vsnprintf
# endif
# endif
# ifdef __SASC
# define NO_vsnprintf
# endif
#endif
#ifdef HAVE_STRERROR
extern char *strerror OF((int));
# define zstrerror(errnum) strerror(errnum)
#else
# define zstrerror(errnum) ""
#endif
#if defined(pyr)
# define NO_MEMCPY
#endif
#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
/* Use our own functions for small and medium model with MSC <= 5.0.
* You may have to use the same strategy for Borland C (untested).
* The __SC__ check is for Symantec.
*/
# define NO_MEMCPY
#endif
#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
# define HAVE_MEMCPY
#endif
#ifdef HAVE_MEMCPY
# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
# define zmemcpy _fmemcpy
# define zmemcmp _fmemcmp
# define zmemzero(dest, len) _fmemset(dest, 0, len)
# else
# define zmemcpy memcpy
# define zmemcmp memcmp
# define zmemzero(dest, len) memset(dest, 0, len)
# endif
#else
extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
extern void zmemzero OF((Bytef* dest, uInt len));
#endif
/* Diagnostic functions */
#ifdef DEBUG
# include <stdio.h>
extern int z_verbose;
extern void z_error OF((char *m));
# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
# define Trace(x) {if (z_verbose>=0) fprintf x ;}
# define Tracev(x) {if (z_verbose>0) fprintf x ;}
# define Tracevv(x) {if (z_verbose>1) fprintf x ;}
# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
#else
# define Assert(cond,msg)
# define Trace(x)
# define Tracev(x)
# define Tracevv(x)
# define Tracec(c,x)
# define Tracecv(c,x)
#endif
voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
void zcfree OF((voidpf opaque, voidpf ptr));
#define ZALLOC(strm, items, size) \
(*((strm)->zalloc))((strm)->opaque, (items), (size))
#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
#endif /* ZUTIL_H */