Initial commit

This commit is contained in:
SteelT 2020-12-23 02:45:27 -05:00
commit 2e174e655d
24 changed files with 12891 additions and 0 deletions

339
COPYING Normal file
View file

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, 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
Appendix: 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) 19yy <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., 675 Mass Ave, Cambridge, MA 02139, 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) 19yy 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.

1210
DOOM/level.cpp Normal file

File diff suppressed because it is too large Load diff

341
DOOM/level.hpp Normal file
View file

@ -0,0 +1,341 @@
//----------------------------------------------------------------------------
//
// File: level.hpp
// Date: 26-Oct-1994
// Programmer: Marc Rousseau
//
// Description: Object classes for manipulating Doom Maps
//
// Copyright (c) 1994-2004 Marc Rousseau, All Rights Reserved.
//
// 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.
//
// Revision History:
//
//----------------------------------------------------------------------------
#ifndef LEVEL_HPP_
#define LEVEL_HPP_
#if ! defined ( COMMON_HPP_ )
#include "common.hpp"
#endif
#if ! defined ( WAD_HPP_ )
#include "wad.hpp"
#endif
#include "thing.hpp"
#include "lineDef.hpp"
struct wThing1 {
INT16 xPos; // x position
INT16 yPos; // y position
UINT16 angle; // direction
UINT16 type; // thing type
UINT16 attr; // attributes of thing
};
struct wThing2 { // HEXEN
UINT16 tid; // Thing ID - for scripts & specials
INT16 xPos; // x position
INT16 yPos; // y position
UINT16 altitude; // starting altitude
UINT16 angle; // direction
UINT16 type; // thing type
UINT16 attr; // attributes of thing
UINT8 special; // special type
UINT8 arg [5]; // special arguments
};
struct wThing {
INT16 xPos; // x position
INT16 yPos; // y position
UINT16 angle; // in degrees not BAM
UINT16 type; // thing type
UINT16 attr; // attributes of thing
UINT16 tid; // Thing ID - for scripts & specials
UINT16 altitude; // starting altitude
UINT8 special; // special type
UINT8 arg [5]; // special arguments
};
struct wLineDef1 {
UINT16 start; // from this vertex ...
UINT16 end; // ... to this vertex
UINT16 flags;
UINT16 type;
UINT16 tag; // crossing this linedef activates the sector with the same tag
UINT16 sideDef[2]; // sidedef
};
struct wLineDef2 { // HEXEN
UINT16 start; // from this vertex ...
UINT16 end; // ... to this vertex
UINT16 flags;
UINT8 special; // special type
UINT8 arg [5]; // special arguments
UINT16 sideDef[2]; // sidedef
};
struct wLineDef {
UINT16 start; // from this vertex ...
UINT16 end; // ... to this vertex
UINT16 flags;
UINT16 type;
UINT16 tag; // crossing this linedef activates the sector with the same tag
UINT16 sideDef[2]; // sidedef
UINT8 special; // special type
UINT8 arg [5]; // special arguments
};
#define NO_SIDEDEF (( UINT16 ) -1 )
#define RIGHT_SIDEDEF (( UINT16 ) 0 )
#define LEFT_SIDEDEF (( UINT16 ) 1 )
#define EMPTY_TEXTURE 0x002D // UINT16 version of ASCII "-"
struct wSideDef {
INT16 xOff; // X offset for texture
INT16 yOff; // Y offset for texture
char text1[MAX_LUMP_NAME]; // texture name for the part above
char text2[MAX_LUMP_NAME]; // texture name for the part below
char text3[MAX_LUMP_NAME]; // texture name for the regular part
UINT16 sector; // adjacent sector
};
struct wVertex {
INT16 x; // X coordinate
INT16 y; // Y coordinate
};
struct wSector {
INT16 floorh; // floor height
INT16 ceilh; // ceiling height
char floorTexture[MAX_LUMP_NAME]; // floor texture
char ceilTexture[MAX_LUMP_NAME]; // ceiling texture
UINT16 light; // light level (0-255)
UINT16 special; // special behaviour (0 = normal, 9 = secret, ...)
UINT16 trigger; // sector activated by a linedef with the same tag
};
struct wSegs {
UINT16 start; // from this vertex ...
UINT16 end; // ... to this vertex
UINT16 angle; // angle (0 = east, 16384 = north, ...)
UINT16 lineDef; // linedef that this seg goes along*/
UINT16 flip; // true if not the same direction as linedef
UINT16 offset; // distance from starting point
};
struct wSSector {
UINT16 num; // number of Segs in this Sub-Sector
UINT16 first; // first Seg
};
struct wBound {
INT16 maxy, miny;
INT16 minx, maxx; // bounding rectangle
};
struct wNode {
INT16 x, y; // starting point
INT16 dx, dy; // offset to ending point
wBound side[2];
UINT16 child[2]; // Node or SSector (if high bit is set)
};
struct wReject {
UINT16 dummy;
};
struct wBlockMap {
INT16 xOrigin;
INT16 yOrigin;
UINT16 noColumns;
UINT16 noRows;
// UINT16 data [];
};
class DoomLevel {
struct sLevelLump {
bool changed;
int byteOrder;
int elementSize;
int elementCount;
UINT32 dataSize;
void *rawData;
sLevelLump ();
};
WAD *m_Wad;
wLumpName m_Name;
bool m_IsHexen;
const char *m_Title;
const char *m_Music;
int m_Cluster;
wThing *m_ThingData;
wLineDef *m_LineDefData;
sLevelLump m_Map;
sLevelLump m_Thing;
sLevelLump m_LineDef;
sLevelLump m_SideDef;
sLevelLump m_Vertex;
sLevelLump m_Sector;
sLevelLump m_Segs;
sLevelLump m_SubSector;
sLevelLump m_Node;
sLevelLump m_Reject;
sLevelLump m_BlockMap;
sLevelLump m_Behavior;
static void ConvertRaw1ToThing ( int, wThing1 *, wThing * );
static void ConvertRaw2ToThing ( int, wThing2 *, wThing * );
static void ConvertThingToRaw1 ( int, wThing *, wThing1 * );
static void ConvertThingToRaw2 ( int, wThing *, wThing2 * );
static void ConvertRaw1ToLineDef ( int, wLineDef1 *, wLineDef * );
static void ConvertRaw2ToLineDef ( int, wLineDef2 *, wLineDef * );
static void ConvertLineDefToRaw1 ( int, wLineDef *, wLineDef1 * );
static void ConvertLineDefToRaw2 ( int, wLineDef *, wLineDef2 * );
void ReplaceVertices ( int *, wVertex *, int );
void DetermineType ();
bool Load ();
bool LoadHexenInfo ();
bool LoadThings ( bool );
bool LoadLineDefs ( bool );
void StoreThings ();
void StoreLineDefs ();
void NewEntry ( sLevelLump *, int, void * );
bool ReadEntry ( sLevelLump *, const char *, const wadDirEntry *, const wadDirEntry *, bool );
bool UpdateEntry ( sLevelLump *, const char *, const char *, bool );
void AdjustByteOrderMap ( int );
void AdjustByteOrderThing ( int );
void AdjustByteOrderLineDef ( int );
void AdjustByteOrderSideDef ( int );
void AdjustByteOrderVertex ( int );
void AdjustByteOrderSector ( int );
void AdjustByteOrderSegs ( int );
void AdjustByteOrderSubSector ( int );
void AdjustByteOrderNode ( int );
void AdjustByteOrderReject ( int );
void AdjustByteOrderBlockMap ( int );
void AdjustByteOrderBehavior ( int );
void AdjustByteOrder ( int );
void CleanUpEntry ( sLevelLump * );
void CleanUp ();
public:
DoomLevel ( const char *, WAD *, bool = true );
~DoomLevel ();
const WAD *GetWAD () const { return m_Wad; }
const char *Name () const { return m_Name; }
const char *Title () const { return m_Title ? m_Title : m_Name; }
const char *Music () const { return m_Music ? m_Music : NULL; }
int MapCluster () const { return m_Cluster; }
int ThingCount () const { return m_Thing.elementCount; }
int LineDefCount () const { return m_LineDef.elementCount; }
int SideDefCount () const { return m_SideDef.elementCount; }
int VertexCount () const { return m_Vertex.elementCount; }
int SectorCount () const { return m_Sector.elementCount; }
int SegCount () const { return m_Segs.elementCount; }
int SubSectorCount () const { return m_SubSector.elementCount; }
int NodeCount () const { return m_Node.elementCount; }
int RejectSize () const { return m_Reject.dataSize; }
int BlockMapSize () const { return m_BlockMap.dataSize; }
int BehaviorSize () const { return m_Behavior.dataSize; }
const wThing *GetThings () const { return m_ThingData; }
const wLineDef *GetLineDefs () const { return m_LineDefData; }
const wSideDef *GetSideDefs () const { return ( wSideDef * ) m_SideDef.rawData; }
const wVertex *GetVertices () const { return ( wVertex * ) m_Vertex.rawData; }
const wSector *GetSectors () const { return ( wSector * ) m_Sector.rawData; }
const wSegs *GetSegs () const { return ( wSegs * ) m_Segs.rawData; }
const wSSector *GetSubSectors () const { return ( wSSector * ) m_SubSector.rawData; }
const wNode *GetNodes () const { return ( wNode * ) m_Node.rawData; }
const wReject *GetReject () const { return ( wReject * ) m_Reject.rawData; }
const wBlockMap *GetBlockMap () const { return ( wBlockMap * ) m_BlockMap.rawData; }
const UINT8 *GetBehavior () const { return ( UINT8 * ) m_Behavior.rawData; }
void NewThings ( int, wThing * );
void NewLineDefs ( int, wLineDef * );
void NewSideDefs ( int, wSideDef * );
void NewVertices ( int, wVertex * );
void NewSectors ( int, wSector * );
void NewSegs ( int, wSegs * );
void NewSubSectors ( int, wSSector * );
void NewNodes ( int, wNode * );
void NewReject ( int, UINT8 * );
void NewBlockMap ( int, wBlockMap * );
void NewBehavior ( int, char * );
bool IsValid ( bool, bool = true ) const;
bool IsDirty () const;
void TrimVertices ();
void PackVertices ();
void PackSideDefs ();
void UnPackSideDefs ();
bool UpdateWAD ();
void AddToWAD ( WAD *wad );
sThingDesc *FindThing ( int type );
static sLineDefDesc *FindLineDef ( int type );
sThingDesc *GetThing ( int index );
static sLineDefDesc *GetLineDef ( int index );
};
#if ( BYTE_ORDER == LITTLE_ENDIAN )
inline void DoomLevel::AdjustByteOrderMap ( int ) {}
inline void DoomLevel::AdjustByteOrderThing ( int ) {}
inline void DoomLevel::AdjustByteOrderLineDef ( int ) {}
inline void DoomLevel::AdjustByteOrderSideDef ( int ) {}
inline void DoomLevel::AdjustByteOrderVertex ( int ) {}
inline void DoomLevel::AdjustByteOrderSector ( int ) {}
inline void DoomLevel::AdjustByteOrderSegs ( int ) {}
inline void DoomLevel::AdjustByteOrderSubSector ( int ) {}
inline void DoomLevel::AdjustByteOrderNode ( int ) {}
inline void DoomLevel::AdjustByteOrderReject ( int ) {}
inline void DoomLevel::AdjustByteOrderBlockMap ( int ) {}
inline void DoomLevel::AdjustByteOrderBehavior ( int ) {}
inline void DoomLevel::AdjustByteOrder ( int ) {}
#endif
#endif

159
DOOM/lineDef.hpp Normal file
View file

@ -0,0 +1,159 @@
//----------------------------------------------------------------------------
//
// File: lineDef.hpp
// Date: 23-August-1995
// Programmer: Marc Rousseau
//
// Description: Object classes for manipulating Doom Map LineDefs
//
// Copyright (c) 1994-2004 Marc Rousseau, All Rights Reserved.
//
// 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.
//
// Revision History:
//
//----------------------------------------------------------------------------
#ifndef LINEDEF_HPP_
#define LINEDEF_HPP_
#if ! defined ( LEVEL_HPP_ )
#include "level.hpp"
#endif
// WAD LINEDEF Flags
#define LDF_IMPASSABLE 0x0001
#define LDF_BLOCK_MONSTERS 0x0002
#define LDF_TWO_SIDED 0x0004
#define LDF_UPPER_UNPEGGED 0x0008
#define LDF_LOWER_UNPEGGED 0x0010
#define LDF_SECRET 0x0020
#define LDF_BLOCK_SOUND 0x0040
#define LDF_NOT_ON_MAP 0x0080
#define LDF_ALREADY_ON_MAP 0x0100
enum LD_LINE_CLASS {
LDC_NONE, // "--"
LDC_SPECIAL, // "Special"
LDC_DOOR, // "Door"
LDC_REMOTE, // "Remote Door"
LDC_CEILING, // "Ceiling"
LDC_LIFT, // "Lift"
LDC_FLOOR, // "Floor"
LDC_STAIRS, // "Stairs"
LDC_MOVE, // "Moving Floor"
LDC_CRUSH, // "Crushing Ceiling"
LDC_EXIT, // "Exit"
LDC_TELEPORT, // "Teleporter"
LDC_LIGHT, // "Light"
LDC_UNKNOWN, // "???"
};
enum LD_LINE_SPEED {
LDS_NONE,
LDS_SLOW,
LDS_MED,
LDS_FAST,
LDS_TURBO
};
enum LD_LINE_ACTION {
LDA_NONE,
LDA_SCROLL,
LDA_OPEN,
LDA_CLOSE,
LDA_RAISE,
LDA_LOWER,
LDA_START,
LDA_STOP,
LDA_CHANGE,
LDA_TELEPORT,
LDA_END,
LDA_END_SECRET
};
enum LD_LINE_EFFECTS {
LDE_NONE = 0x00000000,
LDE_NEEDTAG = 0x80000000,
LDE_LOCK = 0x40000000,
LDE_MONSTER = 0x20000000,
LDE_MONSTER_ONLY = 0x10000000,
LDE_TRIGGER_MODEL = 0x08000000,
LDE_NUMERIC_MODEL = 0x04000000,
LDE_MODEL_MASK = 0x0C000000,
LDE_TX_TEXTURE = 0x02000000,
LDE_TX_SPECIAL = 0x01000000,
LDE_TX_MASK = 0x03000000,
LDE_MAX = 0x00800000,
LDE_MIN = 0x00400000,
LDE_MV_HIGHEST = 0x00C00000,
LDE_MV_NEXT_HIGHEST = 0x00800000,
LDE_MV_LOWEST = 0x00400000,
LDE_MV_SHORTEST = 0x00300000,
LDE_MV_FLOOR = 0x00200000,
LDE_MV_CEILING = 0x00100000,
LDE_MV_EXCLUSIVE = 0x00080000,
LDE_MV_INCLUSIVE = 0x00040000,
LDE_SLOW_HURT = 0x00020000,
LDE_FAST_HURT = 0x00010000,
LDE_CRUSH = 0x00008000,
LDE_SILENT = 0x00004000,
LDE_BLINKING = 0x00002000,
LDE_KEY_BLUE = 0x00000C00,
LDE_KEY_YELLOW = 0x00000800,
LDE_KEY_RED = 0x00000400,
LDE_KEY_MASK = 0x00000C00,
LDE_MODIFIER_MASK = 0x000003FF
};
#define LDE_TX ( LDE_TRIGGER_MODEL | LDE_TX_TEXTURE )
#define LDE_TXP ( LDE_TRIGGER_MODEL | LDE_TX_TEXTURE | LDE_TX_SPECIAL )
#define LDE_NXP ( LDE_NUMERIC_MODEL | LDE_TX_TEXTURE | LDE_TX_SPECIAL )
#define LDE_HE ( LDE_MV_HIGHEST | LDE_MV_EXCLUSIVE )
#define LDE_HEF ( LDE_MV_HIGHEST | LDE_MV_EXCLUSIVE | LDE_MV_FLOOR )
#define LDE_HEC ( LDE_MV_HIGHEST | LDE_MV_EXCLUSIVE | LDE_MV_CEILING )
#define LDE_LE ( LDE_MV_LOWEST | LDE_MV_EXCLUSIVE )
#define LDE_LEF ( LDE_MV_LOWEST | LDE_MV_EXCLUSIVE | LDE_MV_FLOOR )
#define LDE_LIC ( LDE_MV_LOWEST | LDE_MV_INCLUSIVE | LDE_MV_CEILING )
#define LDE_nhEF ( LDE_MV_NEXT_HIGHEST | LDE_MV_EXCLUSIVE | LDE_MV_FLOOR )
#define LDE_F ( LDE_MV_FLOOR )
#define LDE_NUM(x) ((x) & LDE_MODIFIER_MASK )
struct sLineDefDesc {
INT16 Type;
UINT8 Class;
const char *Trigger;
UINT8 Speed;
UINT8 Duration;
UINT8 Action;
UINT32 Effects;
const char *GetClass ();
const char *GetDescription ();
};
#endif

100
DOOM/thing.hpp Normal file
View file

@ -0,0 +1,100 @@
//----------------------------------------------------------------------------
//
// File: thing.hpp
// Date: 23-August-1995
// Programmer: Marc Rousseau
//
// Description: Object classes for manipulating Doom Map Things
//
// Copyright (c) 1994-2004 Marc Rousseau, All Rights Reserved.
//
// 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.
//
// Revision History:
//
//----------------------------------------------------------------------------
#ifndef THING_HPP_
#define THING_HPP_
#if ! defined ( LEVEL_HPP_ )
#include "level.hpp"
#endif
#ifndef SHORT
typedef short SHORT;
#endif
#define THING_SKILL_1_2 0x0001
#define THING_SKILL_3 0x0002
#define THING_SKILL_4_5 0x0004
#define THING_DEAF 0x0008
#define THING_MULTIPLAYER 0x0010
#define THING_a 0x0020
#define THING_b 0x0040
#define THING_c 0x0080
#define THING_d 0x0100
#define THING_e 0x0200
#define THING_f 0x0400
#define TP_NONE 0x00000
#define TP_BLOCK 0x00001 // Blocks the player
#define TP_PICK 0x00002 // Can be picked up
#define TP_SOUND 0x00004 // Sound only: invisible, can be outside of map
#define TP_INVIS 0x00008 // Invisible or blurred
#define TP_FLOAT 0x00010 // Floats or hangs from the ceiling
#define TP_LIGHT 0x00020 // Can be seen in a dark room
#define TP_ITEM 0x00040 // Counts towards the item ratio at the end
#define TP_KILL 0x00080 // Counts towards the kill ratio at the end
#define TP_PLAYER 0x00100 // Player starting point
#define TP_HEALTH ( 0x00200 | TP_PICK )
#define TP_ARTIFACT ( 0x00400 | TP_PICK | TP_ITEM ) // Artifact
#define TP_ARMOR ( 0x00800 | TP_PICK
#define TP_WEAPON ( 0x01000 | TP_PICK | TP_ITEM ) // Weapon
#define TP_AMMO 0x02000 // Ammunition
#define TP_KEY ( 0x04000 | TP_PICK | TP_ITEM )
#define TP_MONSTER ( 0x08000 | TP_BLOCK | TP_KILL )
#define TP_BAD -1 // Invalid Thing - should not be used
#define TP_POLYOBJ 0x10000
#define TP_BONUS ( TP_PICK | TP_ITEM )
#define TP_DECORATE TP_BLOCK
#define TP_CORPSE TP_DECORATE
struct sThingDesc {
SHORT Type;
const char *Name;
const char *Sprite;
const char *Sequence;
SHORT Radius;
SHORT Height;
SHORT Mass;
SHORT Health;
SHORT Speed;
SHORT Damage;
int Properties;
};
/*
Bullets 10
Shotgun 70 ( 7 pellets * 10 )
Plasma 20
Rockets 100
BFG 1000
*/
#endif

1223
DOOM/wad.cpp Normal file

File diff suppressed because it is too large Load diff

322
DOOM/wad.hpp Normal file
View file

@ -0,0 +1,322 @@
//----------------------------------------------------------------------------
//
// File: wad.hpp
// Date: 26-Oct-1994
// Programmer: Marc Rousseau
//
// Description: Object classes for manipulating Doom WAD files
//
// Copyright (c) 1994-2004 Marc Rousseau, All Rights Reserved.
//
// 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.
//
// Revision History:
//
// 04-25-01 Added little/big endian conversions
//
//----------------------------------------------------------------------------
#ifndef WAD_HPP_
#define WAD_HPP_
#if ! defined ( COMMON_HPP_ )
#include "common.hpp"
#endif
#if ! defined ( __STDIO_H )
#include <stdio.h>
#endif
#if ( BYTE_ORDER == LITTLE_ENDIAN )
const UINT32 IWAD_ID = 0x44415749; // ASCII - 'IWAD'
const UINT32 PWAD_ID = 0x44415750; // ASCII - 'PWAD'
#else
const UINT32 IWAD_ID = 0x49574144; // ASCII - 'IWAD'
const UINT32 PWAD_ID = 0x50574144; // ASCII - 'PWAD'
extern UINT32 swap_uint32 ( const unsigned char *ptr );
extern UINT16 swap_uint16 ( const unsigned char *ptr );
#endif
#define IS_TYPE(x,y) (( * ( UINT32 * ) ( x )) == (( UINT32 ) y ))
#define MAX_LUMP_NAME 8
enum eLumpType {
wl_UNCHECKED,
wl_UNKNOWN,
wl_PALETTE,
wl_COLORMAP,
wl_DEMO,
wl_TEXTURE_LIST,
wl_PATCH_NAMES,
wl_MIDI_MAPPING,
wl_GRAVIS_PATCH,
wl_MAP_NAME,
wl_MAP_DATA,
wl_PC_SPEAKER,
wl_SOUND_EFFECT,
wl_MUSIC,
wl_FLAT,
wl_PATCH,
wl_SPRITE,
wl_GRAPHIC,
wl_SCREEN_SHOT,
wl_TEXT_SCREEN,
wl_SOUND_INFO,
wl_SCRIPT,
wl_SPECIAL
};
enum eWadType {
wt_UNKNOWN,
wt_DOOM,
wt_DOOM2,
wt_HERETIC,
wt_HEXEN
};
enum eWadStyle {
wst_UNKNOWN,
wst_FORMAT_1, // DOOM / Heretic
wst_FORMAT_2, // DOOM ][
wst_FORMAT_3 // Hexen
};
enum eWadStatus {
ws_UNKNOWN,
ws_OK,
ws_CANT_READ,
ws_CANT_WRITE,
ws_INVALID_WAD,
ws_INVALID_FILE,
ws_SEEK_ERROR,
ws_READ_ERROR,
ws_WRITE_ERROR
};
struct wadHeader {
char type [4];
UINT32 dirSize; // number of Lumps in WAD
UINT32 dirStart; // offset to start of directory
};
typedef char wLumpName [ MAX_LUMP_NAME ];
struct wadDirEntry {
UINT32 offset; // offset to start of data
UINT32 size; // byte size of data
wLumpName name; // name of data block
};
struct wadDirInfo {
UINT8 *cacheData;
UINT8 *newData;
eLumpType type;
};
class wadList;
class wadFilter {
public:
virtual const char *getFileSpec () const = 0;
virtual bool isRecognized ( UINT32, void * ) const = 0;
virtual bool isRecognized ( const char * ) const = 0;
virtual bool readData ( FILE *, UINT32 *, void ** ) const = 0;
virtual bool writeData ( FILE *, UINT32, void * ) const = 0;
};
class WAD {
char *m_Name;
FILE *m_File;
wadList *m_List;
bool m_bValid;
bool m_bRegistered;
bool m_bDirChanged; // wadDirEntry added/deleted
wadHeader m_Header;
wadDirEntry *m_Directory;
wadDirInfo *m_DirInfo;
eWadStatus m_Status;
eWadType m_Type;
eWadStyle m_Style;
const wadDirEntry *m_MapStart;
const wadDirEntry *m_MapEnd;
const wadDirEntry *m_SpriteStart;
const wadDirEntry *m_SpriteEnd;
const wadDirEntry *m_PatchStart;
const wadDirEntry *m_PatchEnd;
const wadDirEntry *m_FlatStart;
const wadDirEntry *m_FlatEnd;
void **m_NewData;
static int sm_NoFilters;
static wadFilter **sm_Filter;
bool EnlargeDirectory ( int holePos, int entries );
bool ReduceDirectory ( int holePos, int entries );
void FindMarkers ();
bool ReadHeader ( wadHeader * );
bool WriteHeader ( FILE *, wadHeader * );
bool ReadDirEntry ( wadDirEntry * );
bool WriteDirEntry ( FILE *, wadDirEntry * );
bool ReadDirectory ();
bool WriteDirectory ( FILE * );
UINT32 IndexOf ( const wadDirEntry * ) const;
public:
WAD ( const char * );
~WAD ();
void SetList ( wadList * );
static bool IsMap ( const char * );
static bool AddFilter ( wadFilter * );
// Called by wadList::Save
void OpenFile ();
void CloseFile ();
bool SaveFile ( const char * = NULL );
void Type ( eWadType );
void Style ( eWadStyle );
void Format ( UINT32 );
const char *Name () const;
eWadStatus Status () const;
eWadType Type () const;
eWadStyle Style () const;
UINT32 Format () const;
UINT32 FileSize () const;
bool IsValid () const;
bool IsRegistered () const;
bool HasChanged () const;
bool HasChanged ( const wadDirEntry * ) const;
eLumpType GetLumpType ( const wadDirEntry * );
const char *GetLumpDescription ( eLumpType ) const;
const char *GetLumpDescription ( const wadDirEntry * );
void Seek ( UINT32 );
void ReadBytes ( void *, UINT32, UINT32 = 1 );
void WriteBytes ( void *, UINT32, UINT32 = 1 );
void CopyBytes ( WAD *, UINT32, UINT32 = 1 );
UINT32 DirSize () const;
const wadDirEntry *GetDir ( UINT32 ) const;
const wadDirEntry *FindDir ( const char *, const wadDirEntry * = NULL, const wadDirEntry * = NULL ) const;
void *ReadEntry ( const char *, UINT32 *, const wadDirEntry * = NULL, const wadDirEntry * = NULL, bool = false );
void *ReadEntry ( const wadDirEntry *, UINT32 *, bool = false );
bool WriteEntry ( const char *, UINT32, void *, bool, const wadDirEntry * = NULL, const wadDirEntry * = NULL );
bool WriteEntry ( const wadDirEntry *, UINT32, void *, bool );
bool Extract ( const wLumpName *, const char * = NULL ) const;
bool InsertBefore ( const wLumpName *, const char *, bool, const wadDirEntry * = NULL );
bool InsertAfter ( const wLumpName *, const char *, bool, const wadDirEntry * = NULL );
bool InsertBefore ( const wLumpName *, UINT32, void *, bool, const wadDirEntry * = NULL );
bool InsertAfter ( const wLumpName *, UINT32, void *, bool, const wadDirEntry * = NULL );
bool Remove ( const wLumpName *, const wadDirEntry * = NULL, const wadDirEntry * = NULL );
};
inline void WAD::Format ( UINT32 newFormat ) { * ( UINT32 * ) m_Header.type = newFormat; }
inline void WAD::Type ( eWadType newType ) { m_Type = newType; }
inline void WAD::Style ( eWadStyle newStyle ) { m_Style = newStyle; }
inline const char *WAD::Name () const { return m_Name; }
inline UINT32 WAD::DirSize () const { return m_Header.dirSize; }
inline UINT32 WAD::Format () const { return * ( UINT32 * ) m_Header.type; }
inline eWadStatus WAD::Status () const { return m_Status; }
inline eWadType WAD::Type () const { return m_Type; }
inline eWadStyle WAD::Style () const { return m_Style; }
inline bool WAD::IsValid () const { return m_bValid; }
inline bool WAD::IsRegistered () const { return m_bRegistered; }
struct wadListDirEntry {
WAD *wad;
const wadDirEntry *entry;
};
class wadList {
struct wadListEntry {
WAD *wad;
wadListEntry *Next;
};
UINT32 m_DirSize;
UINT32 m_MaxSize;
wadListDirEntry *m_Directory;
eWadType m_Type;
eWadStyle m_Style;
wadListEntry *m_List;
UINT32 IndexOf ( const wadListDirEntry * ) const;
int AddLevel ( UINT32, const wadDirEntry *&, WAD * );
void AddDirectory ( WAD *, bool = true );
public:
wadList ();
~wadList ();
bool Add ( WAD * );
bool Remove ( WAD * );
void Clear ();
void UpdateDirectory ();
int wadCount () const;
UINT32 FileSize () const;
WAD *GetWAD ( int ) const;
eWadType Type () const;
eWadStyle Style () const;
bool Save ( const char * = NULL );
bool Extract ( const wLumpName *, const char *file = NULL );
UINT32 DirSize () const;
const wadListDirEntry *GetDir ( UINT32 ) const;
const wadListDirEntry *FindWAD ( const char *, const wadListDirEntry * = NULL, const wadListDirEntry * = NULL ) const;
bool Contains ( WAD * ) const;
bool IsEmpty () const;
bool HasChanged () const;
};
inline UINT32 wadList::DirSize () const { return m_DirSize; }
inline bool wadList::IsEmpty () const { return ( m_List == NULL ) ? true : false; }
inline eWadType wadList::Type () const { return m_Type; }
inline eWadStyle wadList::Style () const { return m_Style; }
#endif

22
README Normal file
View file

@ -0,0 +1,22 @@
ZenNode v1.2.0
==============
This is directory tree includes the source code necessary to build ZenNode.
Since I don't have a lot of time to spend maintaining the code and there
haven't been too many changes in the past few years, I've decided to release
the source under the GPL license. See the file COPYING for details.
Several of the files (i.e. those in the DOOM directory) evolved from earlier
projects. They contain functionality that is not used in ZenNode and may not
have been kept up to date. I think it all works, but I won't make any
guarantees.
There is a makefile included in the ZenNode directory that can be used as is
under Linux. To build ZenNode in any other environment, you can use the
makefile as a guide. I've built and tested it under Windows using Borland
and Microsoft compilers. Older versions have been compiled under OS/2 using
Borland. The code should be portable to other compilers, but it has never
been tested.
Enjoy,
Marc

1030
ZenNode/ZenMain.cpp Normal file

File diff suppressed because it is too large Load diff

1890
ZenNode/ZenNode.cpp Normal file

File diff suppressed because it is too large Load diff

235
ZenNode/ZenNode.hpp Normal file
View file

@ -0,0 +1,235 @@
//----------------------------------------------------------------------------
//
// File: ZenNode.hpp
// Date: 26-Oct-1994
// Programmer: Marc Rousseau
//
// Description: Definitions of structures used by the ZenNode routines
//
// Copyright (c) 1994-2004 Marc Rousseau, All Rights Reserved.
//
// 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.
//
// Revision History:
//
// 06-??-95 Added LineDef alias list to speed up the process
//
//----------------------------------------------------------------------------
#ifndef ZENNODE_HPP_
#define ZENNODE_HPP_
#if ! defined ( LEVEL_HPP_ )
#include "level.hpp"
#endif
struct sBlockMapOptions {
bool Rebuild;
bool Compress;
};
struct sNodeOptions {
bool Rebuild;
int Method;
bool Quiet;
bool Unique;
bool ReduceLineDefs;
};
struct sBlockList {
int firstIndex; // Index of 1st blockList element matching this one
int offset;
int count;
int *line;
};
struct sBlockMap {
int xOrigin;
int yOrigin;
int noColumns;
int noRows;
sBlockList *data;
};
typedef unsigned short BAM;
typedef long double REAL; // Must have at least 50 significant bits
struct sVertex {
double x;
double y;
double l;
};
struct SEG {
wSegs Data;
const wLineDef *LineDef;
int Sector;
int Side;
int AliasFlip;
bool Split;
bool DontSplit;
bool final;
sVertex start;
sVertex end;
};
struct sBSPOptions {
int algorithm;
bool showProgress;
bool reduceLineDefs; // global flag for invisible linedefs
bool *ignoreLineDef; // linedefs that can be left out
bool *dontSplit; // linedefs that can't be split
bool *keepUnique; // unique sector requirements
};
struct sScoreInfo {
int index;
long metric1;
long metric2;
int invalid;
int total;
};
#define sgn(a) ((0<(a))-((a)<0))
#define BAM90 (( BAM ) 0x4000 ) // BAM: 90ø ( «ã)
#define BAM180 (( BAM ) 0x8000 ) // BAM: 180ø ( ñã)
#define BAM270 (( BAM ) 0xC000 ) // BAM: 270ø (-«ã)
#define M_PI 3.14159265358979323846
#define SIDE_UNKNOWN -2
#define SIDE_LEFT -1
#define SIDE_SPLIT 0
#define SIDE_RIGHT 1
#define SIDE_FLIPPED 0xFFFFFFFE
#define SIDE_NORMAL 0
#define LEFT 0
#define SPLIT 1
#define RIGHT 2
#define IS_LEFT_RIGHT(s) ( s & 1 )
#define FLIP(c,s) ( c ^ s )
// ---- ZenReject structures to support RMB options ----
enum REJECT_OPTION_E {
OPTION_UNKNOWN,
OPTION_MAP_1,
OPTION_MAP_2,
OPTION_BAND,
OPTION_BLIND,
OPTION_BLOCK,
OPTION_DISTANCE,
OPTION_DOOR,
OPTION_EXCLUDE,
OPTION_GROUP,
OPTION_INCLUDE,
OPTION_LEFT,
OPTION_LENGTH,
OPTION_LINE,
OPTION_NODOOR,
OPTION_NOMAP,
OPTION_NOPROCESS,
OPTION_ONE,
OPTION_PERFECT,
OPTION_PREPROCESS,
OPTION_PROCESS,
OPTION_REPORT,
OPTION_RIGHT,
OPTION_SAFE,
OPTION_TRACE
};
struct sRejectOptionRMB;
struct sOptionTableInfo;
typedef bool (*PARSE_FUNCTION) ( char *, const sOptionTableInfo &, sRejectOptionRMB * );
struct sOptionTableInfo {
const char *Name;
const char *Syntax;
REJECT_OPTION_E Type;
PARSE_FUNCTION ParseFunction;
};
struct sRejectOptionRMB {
const sOptionTableInfo *Info;
bool Inverted;
bool Banded;
int Data [2];
int *List [2];
};
struct sRejectOptions {
bool Rebuild;
bool Empty;
bool Force;
bool FindChildren;
bool UseGraphs;
bool UseRMB;
const sRejectOptionRMB *rmb;
};
bool ParseOptionRMB ( int, const char *, sRejectOptionRMB * );
// ----- C99 routines from <math.h> Required by ZenNode -----
#if ( defined ( __GNUC__ ) && ( __GNUC__ < 3 )) || defined ( __INTEL_COMPILER ) || defined ( __BORLANDC__ )
#if defined ( X86 )
__inline long lrint ( double flt )
{
int intgr;
__asm__ __volatile__ ("fistpl %0" : "=m" (intgr) : "t" (flt) : "st");
return intgr;
}
#else
__inline long lrint ( double flt )
{
// return ( long ) ( flt + 0.5 * sgn ( flt ));
return ( long ) ( flt + 0.5 );
}
#endif
#elif defined ( _MSC_VER )
__inline long lrint ( double flt )
{
int intgr;
_asm
{
fld flt
fistp intgr
};
return intgr;
}
#endif
extern sBlockMap *GenerateBLOCKMAP ( DoomLevel *level );
extern int CreateBLOCKMAP ( DoomLevel *level, const sBlockMapOptions &options );
extern void CreateNODES ( DoomLevel *level, sBSPOptions *options );
extern bool CreateREJECT ( DoomLevel *level, const sRejectOptions &options );
#endif

407
ZenNode/ZenRMB.cpp Normal file
View file

@ -0,0 +1,407 @@
//----------------------------------------------------------------------------
//
// File: ZenRMB.cpp
// Date: 30-Oct-2000
// Programmer: Marc Rousseau
//
// Description: RMB configuration file support for ZenNode
//
// Copyright (c) 2000-2004 Marc Rousseau, All Rights Reserved.
//
// 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.
//
// Revision History:
//
//----------------------------------------------------------------------------
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common.hpp"
#include "logger.hpp"
#include "ZenNode.hpp"
DBG_REGISTER ( __FILE__ );
bool ParseGeneric ( char *, const sOptionTableInfo &, sRejectOptionRMB * );
bool ParseMap ( char *, const sOptionTableInfo &, sRejectOptionRMB * );
bool ParseBAND ( char *, const sOptionTableInfo &, sRejectOptionRMB * );
bool ParseINVERT ( char *, const sOptionTableInfo &, sRejectOptionRMB * );
bool ParseNOPROCESS ( char *, const sOptionTableInfo &, sRejectOptionRMB * );
sOptionTableInfo ParseTable [] = {
{ "BAND", "NNL", OPTION_BAND, ParseBAND },
{ "BLIND", "NL", OPTION_BLIND, ParseGeneric },
{ "BLOCK", "NN", OPTION_BLOCK, ParseGeneric },
{ "DISTANCE", "N", OPTION_DISTANCE, ParseGeneric },
{ "DOOR", "N", OPTION_DOOR, ParseGeneric },
{ "E*M*", NULL, OPTION_MAP_1, ParseMap },
{ "EXCLUDE", "LL", OPTION_EXCLUDE, ParseGeneric },
{ "GROUP", "NL", OPTION_GROUP, ParseGeneric },
{ "INCLUDE", "LL", OPTION_INCLUDE, ParseGeneric },
{ "INVERT", NULL, OPTION_UNKNOWN, ParseINVERT },
{ "LEFT", "N", OPTION_LEFT, ParseGeneric },
{ "LENGTH", "N", OPTION_LENGTH, ParseGeneric },
{ "LINE", "N", OPTION_LINE, ParseGeneric },
{ "MAP**", NULL, OPTION_MAP_2, ParseMap },
{ "NODOOR", "L", OPTION_NODOOR, ParseGeneric },
{ "NOMAP", NULL, OPTION_NOMAP, ParseGeneric },
{ "NOPROCESS", NULL, OPTION_NOPROCESS, ParseNOPROCESS },
{ "ONE", "NN", OPTION_ONE, ParseGeneric },
{ "PERFECT", NULL, OPTION_PERFECT, ParseGeneric },
{ "PREPROCESS", "N", OPTION_PREPROCESS, ParseGeneric },
{ "PROCESS", "L", OPTION_PROCESS, ParseGeneric },
{ "REPORT", "N", OPTION_REPORT, ParseGeneric },
{ "RIGHT", "N", OPTION_RIGHT, ParseGeneric },
{ "SAFE", "NL", OPTION_SAFE, ParseGeneric },
{ "TRACE", "L", OPTION_TRACE, ParseGeneric }
};
static const char *parseText;
static int parseLine;
static int lastLine;
const sOptionTableInfo *FindByType ( REJECT_OPTION_E type )
{
for ( unsigned i = 0; i < SIZE ( ParseTable ); i++ ) {
if ( ParseTable [i].Type == type ) return &ParseTable [i];
}
return NULL;
}
void ParseError ( const char *fmt, ... )
{
FUNCTION_ENTRY ( NULL, "ParseError", true );
va_list args;
va_start ( args, fmt );
fprintf ( stderr, ( lastLine == parseLine ) ? " " : "Line %3d: ", parseLine );
vfprintf ( stderr, fmt, args );
fprintf ( stderr, "\n" );
lastLine = parseLine;
}
int ParseNumber ( char *&text )
{
FUNCTION_ENTRY ( NULL, "ParseNumber", true );
if ( ! isdigit ( *text )) throw "expected a number";
int number = 0;
while ( isdigit ( *text )) {
number *= 10;
number += *text++ - '0';
}
return number;
}
int *ParseList ( char *&text, bool strict )
{
FUNCTION_ENTRY ( NULL, "ParseList", true );
if (( strict == true ) && ( *text != '(' )) {
int *list = new int [ 2 ];
list [0] = ParseNumber ( text );
list [1] = -1;
return list;
}
bool close = false;
if ( *text == '(' ) {
close = true;
text++;
}
while ( isspace ( *text )) text++;
if ( *text == '\0' ) throw "Invalid list";
int count = 0;
char *ptr = text;
if ( isdigit ( *ptr )) {
while (( *ptr != '\0' ) && ( *ptr != ')' )) {
if ( ! isdigit ( *ptr )) throw "Invalid list";
while ( isdigit ( *ptr )) ptr++;
if ( *ptr == ',' ) ptr++;
while ( isspace ( *ptr )) ptr++;
count++;
}
/* Is this valid???
} else {
if ( strncmp ( ptr, "ALL", 3 ) != 0 ) throw "Invalid list";
ptr += 3;
while ( isspace ( *ptr )) ptr++;
*/
}
if (( close == true ) && ( *ptr != ')' )) throw "List must end with a ')'";
int *list = new int [ count + 1 ];
for ( int i = 0; i < count; i++ ) {
list [i] = atoi ( text );
while ( isdigit ( *text )) text++;
if ( *text == ',' ) text++;
while ( isspace ( *text )) text++;
}
if ( close == true ) text++;
list [count] = -1;
return list;
}
bool ParseGeneric ( char *text, const sOptionTableInfo &info, sRejectOptionRMB *option )
{
FUNCTION_ENTRY ( NULL, "ParseGeneric", true );
int dataIndex = 0;
int listIndex = 0;
const char *syntax = info.Syntax;
try {
if ( syntax != NULL ) while ( *syntax ) {
while ( isspace ( *text )) text++;
switch ( *syntax++ ) {
case 'N' :
option->Data [dataIndex++] = ParseNumber ( text );
break;
case 'L' :
option->List [listIndex++] = ParseList ( text, ( *syntax != '\0' ) ? true : false );
break;
}
}
while ( isspace ( *text )) text++;
if (( *text != '\0' ) && ( *text != '#' )) throw "unexpected characters after command";
option->Info = &info;
}
catch ( const char *message ) {
ParseError ( "Syntax error - %s.", message );
return false;
}
return true;
}
bool ParseMap ( char *text, const sOptionTableInfo &info, sRejectOptionRMB *option )
{
option->Info = &info;
while ( ! isdigit ( *text )) text--;
switch ( info.Type ) {
case OPTION_MAP_1 :
option->Data [0] = text [-2] - '0';
option->Data [1] = text [0] - '0';
break;
case OPTION_MAP_2 :
option->Data [0] = ( text [-1] - '0' ) * 10 + ( text [0] - '0' );
break;
default :
ParseError ( "Unable to parse map name" );
break;
}
return true;
}
bool ParseBAND ( char *text, const sOptionTableInfo &info, sRejectOptionRMB *option )
{
FUNCTION_ENTRY ( NULL, "ParseBAND", true );
REJECT_OPTION_E type = OPTION_UNKNOWN;
while ( isspace ( *text )) text++;
if ( strncmp ( text, "BLIND", 5 ) == 0 ) {
type = OPTION_BLIND;
text += 5;
} else if ( strncmp ( text, "SAFE", 5 ) == 0 ) {
type = OPTION_SAFE;
text += 4;
} else {
goto bad_option;
}
if ( isspace ( *text )) {
bool retVal = ParseGeneric ( text, info, option );
option->Banded = true;
option->Info = FindByType ( type );
return retVal;
}
bad_option:
ParseError ( "Invalid BAND option." );
return false;
}
bool ParseINVERT ( char *text, const sOptionTableInfo &info, sRejectOptionRMB *option )
{
FUNCTION_ENTRY ( NULL, "ParseINVERT", true );
if ( ParseOptionRMB ( -1, text, option ) == true ) {
switch ( option->Info->Type ) {
case OPTION_BAND :
case OPTION_BLIND :
case OPTION_SAFE :
option->Inverted = true;
break;
default :
ParseError ( "Invalid %s option '%s'.", info.Name, text );
return false;
}
return true;
} else {
ParseError ( "Unable to process %s effect.", info.Name );
}
return false;
}
bool ParseNOPROCESS ( char *text, const sOptionTableInfo &info, sRejectOptionRMB *option )
{
FUNCTION_ENTRY ( NULL, "ParseNOPROCESS", true );
return false;
}
bool ParseOptionRMB ( int lineNumber, const char *lineText, sRejectOptionRMB *option )
{
FUNCTION_ENTRY ( NULL, "ParseOptionRMB", true );
ASSERT ( lineText != NULL );
ASSERT ( option != NULL );
if ( lineNumber > 0 ) {
parseLine = lineNumber;
parseText = lineText;
}
memset ( option, 0, sizeof ( sRejectOptionRMB ));
const char *srcText = lineText;
while (( *srcText != '\0' ) && ( isspace ( *srcText ))) srcText++;
if (( *srcText == '#' ) || ( *srcText == '\0' )) return false;
size_t length = strlen ( srcText );
char *buffer = new char [ length + 1 ];
for ( size_t i = 0; i < length; i++ ) {
buffer [i] = toupper ( srcText [i] );
if (( buffer [i] == '\r' ) || ( buffer [i] == '\n' )) length = i;
}
buffer [length] = '\0';
char *start = buffer;
char *end = buffer;
while (( *end != '\0' ) && ( ! isspace ( *end ))) end++;
bool retVal = false;
if ( start != end ) {
for ( unsigned i = 0; i < SIZE ( ParseTable ); i++ ) {
char *src = start;
const char *tgt = ParseTable [i].Name;
while (( src != end ) && ( *tgt != '\0' )) {
if ( *src != *tgt ) {
if ( *tgt != '*' ) goto next;
if ( ! isdigit ( *src )) goto next;
}
src++;
tgt++;
}
if (( i + 1 < SIZE ( ParseTable )) && ( strncmp ( buffer, ParseTable [i+1].Name, src - buffer ) == 0 )) {
ParseError ( "'%*.*s' is not a unique identifier.", end - buffer, end - buffer, buffer );
goto done;
}
while ( isspace ( *end )) end++;
retVal = ParseTable [i].ParseFunction ( end, ParseTable [i], option );
goto done;
next:
;
}
ParseError ( "Unrecognized effect '%*.*s'.", end - buffer, end - buffer, buffer );
}
done:
delete [] buffer;
return retVal;
}
void PrintOption ( FILE *file, sRejectOptionRMB *option )
{
const sOptionTableInfo *info = option->Info;
const char *syntax = info->Syntax;
if ( option->Inverted ) fprintf ( file, "INVERT " );
if ( option->Banded ) {
syntax = "NNL";
fprintf ( file, "BAND " );
}
switch ( info->Type ) {
case OPTION_MAP_1 :
fprintf ( file, "E%dM%d", option->Data [0], option->Data [1] );
break;
case OPTION_MAP_2 :
fprintf ( file, "MAP%02d", option->Data [0] );
break;
default :
fprintf ( file, "%s", info->Name );
break;
}
int dataIndex = 0;
int listIndex = 0;
if ( syntax != NULL ) while ( *syntax ) {
switch ( *syntax++ ) {
case 'N' :
fprintf ( file, " %d", option->Data [dataIndex++] );
break;
case 'L' :
int *list;
fprintf ( file, " (" );
list = option->List [listIndex++];
while ( *list != -1 ) fprintf ( file, " %d", *list++ );
fprintf ( file, " )" );
break;
default :
fprintf ( stderr, "Internal error: Invalid syntax\n" );
break;
}
}
fprintf ( file, "\n" );
}

198
ZenNode/ZenReject-util.cpp Normal file
View file

@ -0,0 +1,198 @@
void DotGraph ( sGraph *graph )
{
int maxMetric = 0;
for ( int x = 0; x < graph->noSectors; x++ ) {
if ( graph->sector [x]->metric > maxMetric ) maxMetric = graph->sector [x]->metric;
}
fprintf ( stderr, "digraph g {\n" );
fprintf ( stderr, "\tsize = \"12,12\";\n" );
fprintf ( stderr, "\tnode [shape=record];\n" );
for ( int x = 0; x < graph->noSectors; x++ ) {
sSector *sec1 = graph->sector [x];
if ( sec1->graphParent != NULL ) fprintf ( stderr, "\t%d -> %d%s;\n", sec1->graphParent->index, sec1->index, ( sec1->loDFS < sec1->indexDFS ) ? " [color=green]" : "" );
for ( int i = 0; i < sec1->noNeighbors; i++ ) {
sSector *sec2 = sec1->neighbor [i];
if ( sec1->graphParent == sec2 ) continue;
if (( sec2->graphParent != sec1 ) && ( sec1->index > sec2->index )) fprintf ( stderr, "\t%d -> %d [color=red];\n", sec1->index, sec2->index );
}
}
for ( int x = 0; x < graph->noSectors; x++ ) {
sSector *sec = graph->sector [x];
fprintf ( stderr, "\t%d [label=\"%d | { %d | %d | %d } | %d\"];\n", sec->index, sec->loDFS, sec->index, sec->indexDFS, sec->metric, sec->hiDFS );
}
fprintf ( stderr, "}\n" );
}
void NeatoGraph ( sGraph *graph )
{
int maxMetric = 0;
for ( int x = 0; x < graph->noSectors; x++ ) {
if ( graph->sector [x]->metric > maxMetric ) maxMetric = graph->sector [x]->metric;
}
fprintf ( stderr, "graph g {\n" );
fprintf ( stderr, "\tsize = \"12,12\";\n" );
fprintf ( stderr, "\tnode [style=filled,fontcolor=white];\n" );
for ( int x = 0; x < graph->noSectors; x++ ) {
sSector *sec1 = graph->sector [x];
for ( int i = 0; i < sec1->noNeighbors; i++ ) {
sSector *sec2 = sec1->neighbor [i];
if ( sec1->index < sec2->index ) fprintf ( stderr, "\t%d -- %d;\n", sec1->index, sec2->index );
}
}
for ( int x = 0; x < graph->noSectors; x++ ) {
sSector *sec = graph->sector [x];
int color = ( maxMetric != 0 ) ? ( int ) ( 0xFF * sqrt (( double ) sec->metric / ( double ) maxMetric )) : 0;
fprintf ( stderr, "\t%d [color=\"#%02X%02X%02X\"%s];\n", sec->index, color, 0, 0, ( color > 0x80 ) ? ",fontcolor=black" : "" );
}
fprintf ( stderr, "}\n" );
}
void DumpGraph ( sGraph *graph )
{
fprintf ( stderr, "%08X:", graph );
for ( int x = 0; x < graph->noSectors; x++ ) fprintf ( stderr, " %d", graph->sector [x]->index );
fprintf ( stderr, "\n" );
}
void PrintGraph ( sGraph *graph )
{
fprintf ( stderr, "%08X:\n", graph );
int artCount = 0, childCount = 0;
for ( int i = 0; i < graph->noSectors; i++ ) {
sSector *sec = graph->sector [i];
if ( sec->isArticulation == true ) artCount++;
if ( sec->noChildren > 0 ) childCount++;
fprintf ( stderr, " %4d(%4d-%4d,%4d,%7d)%s %4d %3d/%3d", sec->index, sec->loDFS, sec->indexDFS, sec->hiDFS, sec->metric, sec->isArticulation ? "*" : " ", sec->noChildren, sec->noActiveNeighbors, sec->noNeighbors );
if ( sec->noActiveNeighbors == 2 ) {
sSector *sec1 = sec->neighbor [0];
sSector *sec2 = sec->neighbor [1];
if (( sec1->isArticulation == true ) && ( sec2->isArticulation == true )) {
fprintf ( stderr, " -step-" );
}
}
while ( sec->parent != NULL ) {
sec = sec->parent;
fprintf ( stderr, " %4d%s", sec->index, sec->isArticulation ? "*" : "" );
}
fprintf ( stderr, "\n" );
}
fprintf ( stderr, " %4d %3d\n", artCount, childCount );
fprintf ( stderr, "\n" );
}
int CompareREJECT ( UCHAR *srcPtr, UCHAR *tgtPtr, int noSectors )
{
FUNCTION_ENTRY ( NULL, "CompareREJECT", true );
bool match = true;
int **vis2hid = new int * [ noSectors ];
int **hid2vis = new int * [ noSectors ];
int *v2hCount = new int [ noSectors ];
int *h2vCount = new int [ noSectors ];
int bits = 8;
int srcVal = *srcPtr++;
int tgtVal = *tgtPtr++;
int dif = srcVal ^ tgtVal;
for ( int i = 0; i < noSectors; i++ ) {
vis2hid [i] = new int [ noSectors ];
hid2vis [i] = new int [ noSectors ];
memset ( vis2hid [i], 0, noSectors * sizeof ( int ));
memset ( hid2vis [i], 0, noSectors * sizeof ( int ));
v2hCount [i] = 0;
h2vCount [i] = 0;
for ( int j = 0; j < noSectors; j++ ) {
if ( dif & 1 ) {
if ( srcVal & 1 ) {
hid2vis [i][h2vCount [i]++] = j;
} else {
vis2hid [i][v2hCount [i]++] = j;
}
match = false;
}
if ( --bits == 0 ) {
bits = 8;
srcVal = *srcPtr++;
tgtVal = *tgtPtr++;
dif = srcVal ^ tgtVal;
} else {
srcVal >>= 1;
tgtVal >>= 1;
dif >>= 1;
}
}
}
bool first = true;
for ( int i = 0; i < noSectors; i++ ) {
if (( v2hCount [i] == 0 ) && ( h2vCount [i] == 0 )) continue;
bool v2h = false;
for ( int j = 0; j < v2hCount [i]; j++ ) {
int index = vis2hid [i][j];
if (( v2hCount [i] > v2hCount [index] ) ||
(( v2hCount [i] == v2hCount [index] ) && ( i > index ))) {
v2h = true;
break;
}
}
bool h2v = false;
for ( int j = 0; j < h2vCount [i]; j++ ) {
int index = hid2vis [i][j];
if (( h2vCount [i] > h2vCount [index] ) ||
(( h2vCount [i] == h2vCount [index] ) && ( i > index ))) {
h2v = true;
break;
}
}
if ( v2h == true ) {
if ( first == false ) printf ( " " );
printf ( "vis->hid %5d:", i );
for ( int j = 0; j < v2hCount [i]; j++ ) {
printf ( " %d", vis2hid [i][j] );
}
printf ( "\n" );
first = false;
}
if ( h2v == true ) {
if ( first == false ) printf ( " " );
printf ( "hid->vis %5d:", i );
for ( int j = 0; j < h2vCount [i]; j++ ) {
printf ( " %d", hid2vis [i][j] );
}
printf ( "\n" );
first = false;
}
}
if ( match == true ) printf ( "Perfect Match\n" );
for ( int i = 0; i < noSectors; i++ ) {
delete [] vis2hid [i];
delete [] hid2vis [i];
}
delete [] vis2hid;
delete [] hid2vis;
delete [] v2hCount;
delete [] h2vCount;
return match ? 0 : 1;
}

2437
ZenNode/ZenReject.cpp Normal file

File diff suppressed because it is too large Load diff

258
ZenNode/blockmap.cpp Normal file
View file

@ -0,0 +1,258 @@
//----------------------------------------------------------------------------
//
// File: blockmap.cpp
// Date: 14-Jul-1995
// Programmer: Marc Rousseau
//
// Description: This module contains the logic for the BLOCKMAP builder.
//
// Copyright (c) 1994-2004 Marc Rousseau, All Rights Reserved.
//
// 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.
//
// Revision History:
//
//----------------------------------------------------------------------------
#include <math.h>
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include "common.hpp"
#include "level.hpp"
#include "ZenNode.hpp"
#include "console.hpp"
void AddLineDef ( sBlockList *block, int line )
{
if (( block->count % 16 ) == 0 ) {
int size = ( block->count + 16 ) * sizeof ( int );
block->line = ( int * ) realloc ( block->line, size );
}
block->line [ block->count++ ] = line;
}
sBlockMap *GenerateBLOCKMAP ( DoomLevel *level )
{
Status ( "Creating BLOCKMAP ... " );
const wVertex *vertex = level->GetVertices ();
const wLineDef *lineDef = level->GetLineDefs ();
int xLeft, xRight, yTop, yBottom;
xRight = xLeft = vertex [0].x;
yTop = yBottom = vertex [0].y;
for ( int i = 1; i < level->VertexCount (); i++ ) {
if ( vertex [i].x < xLeft ) xLeft = vertex [i].x;
if ( vertex [i].x > xRight ) xRight = vertex [i].x;
if ( vertex [i].y < yBottom ) yBottom = vertex [i].y;
if ( vertex [i].y > yTop ) yTop = vertex [i].y;
}
xLeft -= 8; xRight += 8;
yBottom -= 8; yTop += 8;
int noCols = ( xRight - xLeft ) / 128 + 1;
int noRows = ( yTop - yBottom ) / 128 + 1;
int totalSize = noCols * noRows;
sBlockList *blockList = new sBlockList [ totalSize ];
for ( int i = 0; i < totalSize; i++ ) {
blockList [i].firstIndex = i;
blockList [i].offset = 0;
blockList [i].count = 0;
blockList [i].line = NULL;
}
for ( int i = 0; i < level->LineDefCount (); i++ ) {
const wVertex *vertS = &vertex [ lineDef [i].start ];
const wVertex *vertE = &vertex [ lineDef [i].end ];
long x0 = vertS->x - xLeft;
long y0 = vertS->y - yBottom;
long x1 = vertE->x - xLeft;
long y1 = vertE->y - yBottom;
int startX = x0 / 128, startY = y0 / 128;
int endX = x1 / 128, endY = y1 / 128;
int index = startX + startY * noCols;
if ( startX == endX ) {
AddLineDef ( &blockList [ index ], i );
if ( startY != endY ) { // vertical line
int dy = (( endY - startY ) > 0 ) ? 1 : -1;
do {
startY += dy;
index += dy * noCols;
AddLineDef ( &blockList [ index ], i );
} while ( startY != endY );
}
} else {
if ( startY == endY ) { // horizontal line
AddLineDef ( &blockList [ index ], i );
int dx = (( endX - startX ) > 0 ) ? 1 : -1;
do {
startX += dx;
index += dx;
AddLineDef ( &blockList [ index ], i );
} while ( startX != endX );
} else { // diagonal line
int dx = ( x1 - x0 );
int dy = ( y1 - y0 );
int sx = ( dx < 0 ) ? -1 : 1;
int sy = ( dy < 0 ) ? -1 : 1;
x1 *= dy;
int nextX = x0 * dy;
int deltaX = ( startY * 128 + 64 * ( 1 + sy ) - y0 ) * dx;
bool done = false;
do {
int thisX = nextX;
nextX += deltaX;
if (( sx * sy * nextX ) >= ( sx * sy * x1 )) nextX = x1, done = true;
int lastIndex = index + nextX / dy / 128 - thisX / dy / 128;
AddLineDef ( &blockList [ index ], i );
while ( index != lastIndex ) {
index += sx;
AddLineDef ( &blockList [ index ], i );
}
index += sy * noCols;
deltaX = ( 128 * dx ) * sy;
} while ( ! done );
int lastIndex = endX + endY * noCols;
if ( index != lastIndex + sy * noCols ) {
AddLineDef ( &blockList [ lastIndex ], i );
}
}
}
}
sBlockMap *blockMap = new sBlockMap;
blockMap->xOrigin = xLeft;
blockMap->yOrigin = yBottom;
blockMap->noColumns = noCols;
blockMap->noRows = noRows;
blockMap->data = blockList;
return blockMap;
}
int CreateBLOCKMAP ( DoomLevel *level, const sBlockMapOptions &options )
{
// Generate the data
sBlockMap *blockMap = GenerateBLOCKMAP ( level );
Status ( "Packing BLOCKMAP ... " );
sBlockList *blockList = blockMap->data;
// Count unique blockList elements
int totalSize = blockMap->noColumns * blockMap->noRows;
int blockListSize = 0, savings = 0;
int zeroIndex = -1;
for ( int i = 0; i < totalSize; i++ ) {
if ( options.Compress ) {
if ( blockList [i].count == 0 ) {
if ( zeroIndex != -1 ) {
blockList [i].firstIndex = zeroIndex;
savings += 0 + 2;
continue;
}
zeroIndex = i;
} else {
// Only go back to the beginning of the previous row
int rowStart = ( i / blockMap->noColumns ) * blockMap->noColumns;
int lastStart = rowStart ? rowStart - blockMap->noColumns : 0;
int index = i - 1;
while ( index >= lastStart ) {
int count = blockList[i].count;
if (( blockList[index].count == count ) &&
( memcmp ( blockList[i].line, blockList[index].line, count * sizeof ( int )) == 0 )) {
blockList [i].firstIndex = index;
savings += count + 2;
break;
}
index--;
}
if ( index >= lastStart ) continue;
}
}
blockList [i].firstIndex = i;
blockListSize += 2 + blockList [i].count;
}
Status ( "Saving BLOCKMAP ... " );
int blockSize = sizeof ( wBlockMap ) +
totalSize * sizeof ( INT16 ) +
blockListSize * sizeof ( INT16 );
char *start = new char [ blockSize ];
wBlockMap *map = ( wBlockMap * ) start;
map->xOrigin = ( INT16 ) blockMap->xOrigin;
map->yOrigin = ( INT16 ) blockMap->yOrigin;
map->noColumns = ( UINT16 ) blockMap->noColumns;
map->noRows = ( UINT16 ) blockMap->noRows;
// Fill in data & offsets
UINT16 *offset = ( UINT16 * ) ( map + 1 );
UINT16 *data = offset + totalSize;
for ( int i = 0; i < totalSize; i++ ) {
sBlockList *block = &blockList [i];
if ( block->firstIndex == i ) {
block->offset = data - ( UINT16 * ) start;
*data++ = 0;
for ( int x = 0; x < block->count; x++ ) {
*data++ = ( UINT16 ) block->line [x];
}
*data++ = ( UINT16 ) -1;
} else {
block->offset = blockList [ block->firstIndex ].offset;
}
}
bool errors = false;
for ( int i = 0; i < totalSize; i++ ) {
if ( blockList [i].offset > 0xFFFF ) {
errors = true;
}
offset [i] = ( UINT16 ) blockList [i].offset;
if ( blockList [i].line ) free ( blockList [i].line );
}
delete [] blockList;
delete blockMap;
if ( errors == true ) {
delete [] start;
return -1;
}
level->NewBlockMap ( blockSize, map );
return savings * sizeof ( INT16 );
}

462
ZenNode/bspdiff.cpp Normal file
View file

@ -0,0 +1,462 @@
//----------------------------------------------------------------------------
//
// File: bspdiff.cpp
// Date: 27-Oct-2000
// Programmer: Marc Rousseau
//
// Description: Compares two BSP structures and report any differences
//
// Copyright (c) 2000-2004 Marc Rousseau, All Rights Reserved.
//
// 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.
//
// Revision History:
//
//----------------------------------------------------------------------------
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined ( __OS2__ )
#define INCL_DOS
#define INCL_SUB
#include <conio.h>
#include <dos.h>
#include <os2.h>
#elif defined ( __WIN32__ )
#include <conio.h>
#include <dos.h>
#include <windows.h>
#include <wincon.h>
#elif defined ( __GNUC__ )
#else
#error This program must be compiled as a 32-bit app.
#endif
#include "common.hpp"
#include "wad.hpp"
#include "level.hpp"
#include "console.hpp"
#define VERSION "1.0"
#define MAX_LEVELS 50
#define UNSUPPORTED_FEATURE -1
#define UNRECOGNIZED_PARAMETER -2
#if defined ( __GNUC__ )
#define stricmp strcasecmp
#define cprintf printf
extern char *strupr ( char *ptr );
extern int getch ();
extern bool kbhit ();
#endif
int GCD ( int A, int B )
{
if ( A < 0 ) A = -A; else if ( A == 0 ) return 1;
if ( B < 0 ) B = -B; else if ( B == 0 ) return 1;
unsigned twos = 0;
while ((( A | B ) & 1 ) == 0 ) {
twos++;
A >>= 1;
B >>= 1;
}
while (( A & 1 ) == 0 ) A >>= 1; // remove other powers of 2
while (( B & 1 ) == 0 ) B >>= 1; // remove other powers of 2
// A and B both odd at this point!
while ( A != B ) {
while ( A > B ) {
A -= B; // subtractracting smaller odd number
// from larger odd number. ( A now even )
while (( A & 1 ) == 0 ) A >>= 1; // remove powers of 2
}
while ( B > A ) {
B -= A; // subtractracting smaller odd number
// from larger odd number. ( B now even )
while (( B & 1 ) == 0 ) B >>= 1; // remove powers of 2
}
}
return ( A << twos ); // reapply original powers of two
}
void printHelp ()
{
fprintf ( stderr, "Usage: nodediff {-options} filename1[.wad] filename2[.wad] [level{+level}]\n" );
fprintf ( stderr, "\n" );
fprintf ( stderr, " -x+ turn on option -x- turn off option %c = default\n", DEFAULT_CHAR );
fprintf ( stderr, "\n" );
fprintf ( stderr, " level - ExMy for DOOM / Heretic\n" );
fprintf ( stderr, " MAPxx for DOOM II / HEXEN\n" );
}
int parseArgs ( int index, const char *argv[] )
{
bool errors = false;
while ( argv [ index ] ) {
if ( argv [index][0] != '/' ) break;
index++;
}
if ( errors ) fprintf ( stderr, "\n" );
return index;
}
int getLevels ( int argIndex, const char *argv[], char names [][MAX_LUMP_NAME], wadList *list )
{
int index = 0, errors = 0;
char buffer [128];
buffer [0] = '\0';
if ( argv [argIndex] ) {
strcpy ( buffer, argv [argIndex] );
strupr ( buffer );
}
char *ptr = strtok ( buffer, "+" );
// See if the user requested specific levels
if ( WAD::IsMap ( ptr )) {
argIndex++;
while ( ptr ) {
if ( WAD::IsMap ( ptr ))
if ( list->FindWAD ( ptr ))
strcpy ( names [index++], ptr );
else
fprintf ( stderr, " Could not find %s\n", ptr, errors++ );
else
fprintf ( stderr, " %s is not a valid name for a level\n", ptr, errors++ );
ptr = strtok ( NULL, "+" );
}
} else {
int size = list->DirSize ();
const wadListDirEntry *dir = list->GetDir ( 0 );
for ( int i = 0; i < size; i++ ) {
if ( dir->wad->IsMap ( dir->entry->name )) {
if ( index == MAX_LEVELS )
fprintf ( stderr, "ERROR: Too many levels in WAD - ignoring %s!\n", dir->entry->name, errors++ );
else
memcpy ( names [index++], dir->entry->name, MAX_LUMP_NAME );
}
dir++;
}
}
memset ( names [index], 0, MAX_LUMP_NAME );
if ( errors ) fprintf ( stderr, "\n" );
return argIndex;
}
void EnsureExtension ( char *fileName, const char *ext )
{
size_t length = strlen ( fileName );
char *ptr = strrchr ( fileName, '.' );
if (( ptr && strchr ( ptr, '\\' )) ||
( ! ptr && stricmp ( &fileName[length-4], ext )))
strcat ( fileName, ext );
}
const char *TypeName ( eWadType type )
{
switch ( type ) {
case wt_DOOM : return "DOOM";
case wt_DOOM2 : return "DOOM2";
case wt_HERETIC : return "Heretic";
case wt_HEXEN : return "Hexen";
default : break;
}
return "<Unknown>";
}
wadList *getInputFiles ( const char *cmdLine, char *wadFileName )
{
char *listNames = wadFileName;
wadList *myList = new wadList;
if ( cmdLine == NULL ) return myList;
char temp [ 256 ];
strcpy ( temp, cmdLine );
char *ptr = strtok ( temp, "+" );
int errors = 0;
while ( ptr && *ptr ) {
char wadName [ 256 ];
strcpy ( wadName, ptr );
EnsureExtension ( wadName, ".wad" );
WAD *wad = new WAD ( wadName );
if ( wad->Status () != ws_OK ) {
const char *msg;
switch ( wad->Status ()) {
case ws_INVALID_FILE : msg = "The file %s does not exist\n"; break;
case ws_CANT_READ : msg = "Can't open the file %s for read access\n"; break;
case ws_INVALID_WAD : msg = "%s is not a valid WAD file\n"; break;
default : msg = "** Unexpected Error opening %s **\n"; break;
}
fprintf ( stderr, msg, wadName );
delete wad;
} else {
if ( ! myList->IsEmpty ()) {
cprintf ( "Merging: %s with %s\r\n", wadName, listNames );
*wadFileName++ = '+';
}
if ( myList->Add ( wad ) == false ) {
errors++;
if ( myList->Type () != wt_UNKNOWN )
fprintf ( stderr, "ERROR: %s is not a %s PWAD.\n", wadName, TypeName ( myList->Type ()));
else
fprintf ( stderr, "ERROR: %s is not the same type.\n", wadName );
delete wad;
} else {
char *end = wadName + strlen ( wadName ) - 1;
while (( end > wadName ) && ( *end != '\\' )) end--;
if ( *end == '\\' ) end++;
wadFileName += sprintf ( wadFileName, "%s", end );
}
}
ptr = strtok ( NULL, "+" );
}
if ( wadFileName [-1] == '+' ) wadFileName [-1] = '\0';
if ( myList->wadCount () > 1 ) cprintf ( "\r\n" );
if ( errors ) fprintf ( stderr, "\n" );
return myList;
}
template <class T> inline T sgn ( T val ) { return ( val > 0 ) ? 1 : ( val < 0 ) ? -1 : 0; }
void NormalizeNODES ( wNode *node, int noNodes )
{
for ( int i = 0; i < noNodes; i++ ) {
int gcd = GCD ( node [i].dx, node [i].dy );
node [i].dx /= gcd;
node [i].dy /= gcd;
if ( node [i].dx == 0 ) node [i].dy = sgn ( node [i].dy );
if ( node [i].dy == 0 ) node [i].dx = sgn ( node [i].dx );
if (( node [i].dx < 0 ) || (( node [i].dx == 0 ) && ( node [i].dy < 0 ))) {
node [i].dx = -node [i].dx;
node [i].dy = -node [i].dy;
swap ( node [i].side [0], node [i].side [1] );
swap ( node [i].child [0], node [i].child [1] );
}
}
}
static int SortSegs ( const void *ptr1, const void *ptr2 )
{
int dif = (( wSegs * ) ptr1)->lineDef - (( wSegs * ) ptr2)->lineDef;
if ( dif ) return dif;
return (( wSegs * ) ptr1)->flip - (( wSegs * ) ptr2)->flip ?
(( wSegs * ) ptr1)->flip - (( wSegs * ) ptr2)->flip :
(( wSegs * ) ptr1)->offset - (( wSegs * ) ptr2)->offset;
}
bool LinesMatch ( const wNode &node1, const wNode &node2 )
{
if (( node1.dx != node2.dx ) || ( node1.dy != node2.dy )) return false;
if ( node1.dx == 0 ) return ( node1.x == node2.x ) ? true : false;
if ( node1.dy == 0 ) return ( node1.y == node2.y ) ? true : false;
double tx = ( double ) ( node2.x - node1.x ) / ( double ) node1.dx;
double ty = ( double ) ( node2.y - node1.y ) / ( double ) node1.dy;
double delta = fabs ( tx - ty );
if ( delta < 0.001 ) return true;
if ( delta < 1.000 ) printf ( "tx = %g ty = %g\n", tx, ty );
return false;
}
char *locationString;
void printNode ( const wNode &node, int index )
{
printf ( "\n%5d - (%5d,%5d) (%5d,%5d) L: %c %5d R: %c %5d",
index, node.x, node.y, node.dx, node.dy,
( node.child [0] & 0x8000 ) ? 'S' : 'N', node.child [0] & 0x7FFF, ( node.child [1] & 0x8000 ) ? 'S' : 'N', node.child [1] & 0x7FFF );
}
static DoomLevel *srcLevel;
static DoomLevel *tgtLevel;
int CompareSSECTOR ( int srcIndex, int tgtIndex )
{
srcIndex &= 0x7FFF;
tgtIndex &= 0x7FFF;
// qsort ( segs, noSegs, sizeof ( SEG ), SortSegs );
return 0;
}
int CompareNODE ( int srcIndex, int tgtIndex, char *location )
{
int length = location - locationString;
if (( srcIndex & 0x8000 ) != ( tgtIndex & 0x8000 )) {
printf ( "\n%*.*s: Leaf != Node", length, length, locationString );
return 1;
}
if ( srcIndex & 0x8000 ) {
return CompareSSECTOR ( srcIndex, tgtIndex );
}
const wNode &src = srcLevel->GetNodes () [srcIndex];
const wNode &tgt = tgtLevel->GetNodes () [tgtIndex];
if ( LinesMatch ( src, tgt ) == false ) {
int length = location - locationString;
printf ( "\n%*.*s:", length, length, locationString );
printNode ( src, srcIndex );
printNode ( tgt, tgtIndex );
return 1;
}
int count = 0;
*location = 'R';
count += CompareNODE ( src.child [0], tgt.child [0], location + 1 );
*location = 'L';
count += CompareNODE ( src.child [1], tgt.child [1], location + 1 );
return count;
}
int ProcessLevel ( char *name, wadList *myList1, wadList *myList2 )
{
cprintf ( "\r %-*.*s: ", MAX_LUMP_NAME, MAX_LUMP_NAME, name );
GetXY ( &startX, &startY );
int mismatches = 0;
srcLevel = NULL;
tgtLevel = NULL;
const wadListDirEntry *dir = myList1->FindWAD ( name );
srcLevel = new DoomLevel ( name, dir->wad );
if ( srcLevel->IsValid ( true ) == false ) {
Status ( "This level is not valid... " );
mismatches = -1;
goto done;
}
dir = myList2->FindWAD ( name );
tgtLevel = new DoomLevel ( name, dir->wad );
if ( tgtLevel->IsValid ( true ) == false ) {
Status ( "This level is not valid... " );
mismatches = -1;
goto done;
}
{
NormalizeNODES (( wNode * ) srcLevel->GetNodes (), srcLevel->NodeCount ());
NormalizeNODES (( wNode * ) tgtLevel->GetNodes (), tgtLevel->NodeCount ());
int noNodes = max ( srcLevel->NodeCount (), tgtLevel->NodeCount ());
locationString = new char [ noNodes ];
mismatches = CompareNODE ( srcLevel->NodeCount () - 1, tgtLevel->NodeCount () - 1, locationString );
delete [] locationString;
if ( mismatches == 0 ) Status ( "NODES Match" );
}
done:
cprintf ( "\r\n" );
delete tgtLevel;
delete srcLevel;
return mismatches;
}
int main ( int argc, const char *argv[] )
{
fprintf ( stderr, "Compare Version %s (c) 2003-2004 Marc Rousseau\n\n", VERSION );
if ( argc == 1 ) {
printHelp ();
return -1;
}
SaveConsoleSettings ();
int argIndex = 1, changes = 0;
while ( KeyPressed ()) GetKey ();
do {
argIndex = parseArgs ( argIndex, argv );
if ( argIndex < 0 ) break;
char wadFileName1 [ 256 ];
wadList *myList1 = getInputFiles ( argv [argIndex++], wadFileName1 );
if ( myList1->IsEmpty ()) { changes = -1000; break; }
char wadFileName2 [ 256 ];
wadList *myList2 = getInputFiles ( argv [argIndex++], wadFileName2 );
if ( myList2->IsEmpty ()) { changes = -1000; break; }
cprintf ( "Comparing: %s and %s\r\n\n", wadFileName1, wadFileName2 );
char levelNames [MAX_LEVELS+1][MAX_LUMP_NAME];
argIndex = getLevels ( argIndex, argv, levelNames, myList1 );
if ( levelNames [0][0] == '\0' ) {
fprintf ( stderr, "Unable to find any valid levels in %s\n", wadFileName1 );
break;
}
int noLevels = 0;
do {
changes += ProcessLevel ( levelNames [noLevels++], myList1, myList2 );
if ( KeyPressed () && ( GetKey () == 0x1B )) break;
} while ( levelNames [noLevels][0] );
cprintf ( "\r\n" );
delete myList1;
delete myList2;
} while ( argv [argIndex] );
RestoreConsoleSettings ();
return changes;
}

439
ZenNode/bspinfo.cpp Normal file
View file

@ -0,0 +1,439 @@
//----------------------------------------------------------------------------
//
// File: bspinfo.cpp
// Date: 11-Oct-1995
// Programmer: Marc Rousseau
//
// Description: An application to analyze the contents of a BSP tree
//
// Copyright (c) 1995-2004 Marc Rousseau, All Rights Reserved.
//
// 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.
//
// Revision History:
//
//----------------------------------------------------------------------------
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common.hpp"
#include "logger.hpp"
#include "wad.hpp"
#include "level.hpp"
#include "console.hpp"
#if defined ( __OS2__ )
#include <conio.h>
#include <io.h>
#elif defined ( __WIN32__ )
#include <conio.h>
#include <io.h>
#elif defined ( __GNUC__ ) || defined ( __INTEL_COMPILER )
#include <unistd.h>
#else
#error This program must be compiled as a 32-bit app.
#endif
DBG_REGISTER ( __FILE__ );
#define VERSION "1.3"
#define BANNER "BSPInfo Version " VERSION " (c) 1995-2004 Marc Rousseau"
#define MAX_LEVELS 99
#if defined ( __GNUC__ ) || defined ( __INTEL_COMPILER )
#define stricmp strcasecmp
extern char *strupr ( char *ptr );
#endif
struct {
bool Tree;
} flags;
void printHelp ()
{
fprintf ( stderr, "Usage: bspInfo [-options] filename[.wad] [level[+level]]\n" );
fprintf ( stderr, "\n" );
fprintf ( stderr, " -x+ turn on option -x- turn off option %c = default\n", DEFAULT_CHAR );
fprintf ( stderr, "\n" );
fprintf ( stderr, " -t - Display NODE tree\n" );
fprintf ( stderr, "\n" );
fprintf ( stderr, " level - ExMy for DOOM / Heretic\n" );
fprintf ( stderr, " MAPxx for DOOM II / HEXEN\n" );
}
int parseArgs ( int index, const char *argv [] )
{
FUNCTION_ENTRY ( NULL, "parseArgs", true );
bool errors = false;
while ( argv [ index ] ) {
if ( argv [index][0] != '-' ) break;
char *localCopy = strdup ( argv [ index ]);
char *ptr = localCopy + 1;
strupr ( localCopy );
bool localError = false;
while ( *ptr && ( localError == false )) {
int option = *ptr++;
bool setting = true;
if (( *ptr == '+' ) || ( *ptr == '-' )) {
setting = ( *ptr == '-' ) ? false : true;
ptr++;
}
switch ( option ) {
case 'T' : flags.Tree = setting; break;
default : localError = true;
}
}
if ( localError ) {
errors = true;
int offset = ptr - localCopy - 1;
size_t width = strlen ( ptr ) + 1;
fprintf ( stderr, "Unrecognized parameter '%*.*s'\n", width, width, argv [index] + offset );
}
free ( localCopy );
index++;
}
if ( errors ) fprintf ( stderr, "\n" );
return index;
}
int getLevels ( int argIndex, const char *argv [], char names [][MAX_LUMP_NAME], wadList *list )
{
FUNCTION_ENTRY ( NULL, "getLevels", true );
int index = 0, errors = 0;
char buffer [128];
buffer [0] = '\0';
if ( argv [argIndex] ) {
strcpy ( buffer, argv [argIndex] );
strupr ( buffer );
}
char *ptr = strtok ( buffer, "+" );
// See if the user requested specific levels
if ( WAD::IsMap ( ptr )) {
argIndex++;
while ( ptr ) {
if ( WAD::IsMap ( ptr )) {
if ( list->FindWAD ( ptr )) {
strcpy ( names [index++], ptr );
} else {
fprintf ( stderr, " Could not find %s\n", ptr, errors++ );
}
} else {
fprintf ( stderr, " %s is not a valid name for a level\n", ptr, errors++ );
}
ptr = strtok ( NULL, "+" );
}
} else {
int size = list->DirSize ();
const wadListDirEntry *dir = list->GetDir ( 0 );
for ( int i = 0; i < size; i++ ) {
if ( dir->wad->IsMap ( dir->entry->name )) {
// Make sure it's really a level
if ( strcmp ( dir[1].entry->name, "THINGS" ) == 0 ) {
if ( index == MAX_LEVELS ) {
fprintf ( stderr, "ERROR: Too many levels in WAD - ignoring %s!\n", dir->entry->name, errors++ );
} else {
memcpy ( names [index++], dir->entry->name, MAX_LUMP_NAME );
}
}
}
dir++;
}
}
memset ( names [index], 0, MAX_LUMP_NAME );
if ( errors ) fprintf ( stderr, "\n" );
return argIndex;
}
void EnsureExtension ( char *fileName, const char *ext )
{
FUNCTION_ENTRY ( NULL, "EnsureExtension", true );
// See if the file exists first
FILE *file = fopen ( fileName, "rb" );
if ( file != NULL ) {
fclose ( file );
return;
}
size_t length = strlen ( fileName );
if ( stricmp ( &fileName [length-4], ext ) != 0 ) {
strcat ( fileName, ext );
}
}
const char *TypeName ( eWadType type )
{
FUNCTION_ENTRY ( NULL, "TypeName", true );
const char *name = NULL;
switch ( type ) {
case wt_DOOM : name = "DOOM"; break;
case wt_DOOM2 : name = "DOOM2"; break;
case wt_HERETIC : name = "Heretic"; break;
case wt_HEXEN : name = "Hexen"; break;
default : name = "<Unknown>"; break;
}
return name;
}
wadList *getInputFiles ( const char *cmdLine, char *wadFileName )
{
FUNCTION_ENTRY ( NULL, "getInputFiles", true );
char *listNames = wadFileName;
wadList *myList = new wadList;
if ( cmdLine == NULL ) return myList;
char temp [ 256 ];
strcpy ( temp, cmdLine );
char *ptr = strtok ( temp, "+" );
int errors = 0;
while ( ptr && *ptr ) {
char wadName [ 256 ];
strcpy ( wadName, ptr );
EnsureExtension ( wadName, ".wad" );
WAD *wad = new WAD ( wadName );
if ( wad->Status () != ws_OK ) {
const char *msg;
switch ( wad->Status ()) {
case ws_INVALID_FILE : msg = "The file %s does not exist\n"; break;
case ws_CANT_READ : msg = "Can't open the file %s for read access\n"; break;
case ws_INVALID_WAD : msg = "%s is not a valid WAD file\n"; break;
default : msg = "** Unexpected Error opening %s **\n"; break;
}
fprintf ( stderr, msg, wadName );
delete wad;
} else {
if ( ! myList->IsEmpty ()) {
cprintf ( "Merging: %s with %s\r\n", wadName, listNames );
*wadFileName++ = '+';
}
if ( myList->Add ( wad ) == false ) {
errors++;
if ( myList->Type () != wt_UNKNOWN ) {
fprintf ( stderr, "ERROR: %s is not a %s PWAD.\n", wadName, TypeName ( myList->Type ()));
} else {
fprintf ( stderr, "ERROR: %s is not the same type.\n", wadName );
}
delete wad;
} else {
char *end = wadName + strlen ( wadName ) - 1;
while (( end > wadName ) && ( *end != SEPERATOR )) end--;
if ( *end == SEPERATOR ) end++;
wadFileName += sprintf ( wadFileName, "%s", end );
}
}
ptr = strtok ( NULL, "+" );
}
if ( wadFileName [-1] == '+' ) wadFileName [-1] = '\0';
if ( myList->wadCount () > 1 ) cprintf ( "\r\n" );
if ( errors ) fprintf ( stderr, "\n" );
return myList;
}
const wNode *nodes;
int totalDepth;
int Traverse ( int index, int depth, int &diagonals, int &balance, int &lChildren, int &rChildren )
{
FUNCTION_ENTRY ( NULL, "Traverse", false );
const wNode *node = &nodes [ index ];
if ( flags.Tree ) printf ( "(%5d,%5d) [%5d,%5d]\n", node->x, node->y, node->dx, node->dy );
if (( node->dx != 0 ) && ( node->dy != 0 )) diagonals++;
int lIndex = node->child [0];
int rIndex = node->child [1];
if (( lIndex & 0x8000 ) == ( rIndex & 0x8000 )) balance++;
int lDepth = 0, rDepth = 0;
depth++;
if ( flags.Tree ) printf ( "%5d %*.*sLeft - ", depth, depth*2, depth*2, "" );
if (( lIndex & 0x8000 ) == 0 ) {
int left = 0, right = 0;
lDepth = Traverse ( lIndex, depth, diagonals, balance, left, right );
lChildren = 1 + left + right;
} else {
if ( flags.Tree ) printf ( "** NONE **\n" );
lDepth = depth;
totalDepth += depth + 1;
}
if ( flags.Tree ) printf ( "%5d %*.*sRight - ", depth, depth*2, depth*2, "" );
if (( rIndex & 0x8000 ) == 0 ) {
int left = 0, right = 0;
rDepth = Traverse ( rIndex, depth, diagonals, balance, left, right );
rChildren = 1 + left + right;
} else {
if ( flags.Tree ) printf ( "** NONE **\n" );
rDepth = depth;
totalDepth += depth + 1;
}
return (( lDepth > rDepth ) ? lDepth : rDepth );
}
void AnalyzeBSP ( DoomLevel *curLevel )
{
FUNCTION_ENTRY ( NULL, "AnalyzeBSP", true );
if ( curLevel->IsValid ( true, true ) == false ) {
printf ( "******** Invalid level ********" );
return;
}
totalDepth = 0;
nodes = curLevel->GetNodes ();
int balance = 0, diagonals = 0;
if ( flags.Tree ) printf ( "\n\nROOT: " );
int left = 0;
int right = 0;
int depth = Traverse ( curLevel->NodeCount () - 1, 0, diagonals, balance, left, right );
const wSegs *seg = curLevel->GetSegs ();
const wLineDef *lineDef = curLevel->GetLineDefs ();
bool *lineUsed = new bool [ curLevel->LineDefCount ()];
memset ( lineUsed, false, sizeof ( bool ) * curLevel->LineDefCount ());
for ( int i = 0; i < curLevel->SegCount (); i++, seg++ ) {
lineUsed [ seg->lineDef ] = true;
}
int sideDefs = 0;
for ( int i = 0; i < curLevel->LineDefCount (); i++ ) {
if ( lineUsed [i] == false ) continue;
if ( lineDef[i].sideDef[0] != NO_SIDEDEF ) sideDefs++;
if ( lineDef[i].sideDef[1] != NO_SIDEDEF ) sideDefs++;
}
int splits = curLevel->SegCount () - sideDefs;
int noLeafs = curLevel->SubSectorCount ();
int optDepth = ( int ) ceil ( log (( float ) noLeafs ) / log ( 2.0 ));
int maxLeafs = ( int ) pow ( 2, optDepth );
int minDepth = noLeafs * ( optDepth + 1 ) - maxLeafs;
int maxDepth = noLeafs * (( noLeafs - 1 ) / 2 + 1 ) - 1;
double minScore = ( double ) minDepth / ( double ) maxDepth;
double score = ( double ) minDepth / ( double ) totalDepth;
score = ( score - minScore ) / ( 1 - minScore );
if ( ! flags.Tree ) {
float avgDepth = noLeafs ? ( float ) totalDepth / ( float ) noLeafs : 0;
printf ( "%2d ", depth );
printf ( "%4.1f ", avgDepth );
printf ( "%5.3f ", score );
printf ( "%5.3f ", ( left < right ) ? ( double ) left / ( double ) right : ( double ) right / ( double ) left );
printf ( "%5d - %4.1f%% ", splits, 100.0 * splits / sideDefs );
printf ( "%5d - %4.1f%% ", diagonals, 100.0 * diagonals / curLevel->NodeCount ());
printf ( "%5d ", curLevel->NodeCount ());
printf ( "%5d", curLevel->SegCount ());
}
}
int main ( int argc, const char *argv[] )
{
FUNCTION_ENTRY ( NULL, "main", true );
SaveConsoleSettings ();
cprintf ( "%s\r\n\r\n", BANNER );
if ( ! isatty ( fileno ( stdout ))) fprintf ( stdout, "%s\n\n", BANNER );
if ( ! isatty ( fileno ( stderr ))) fprintf ( stderr, "%s\n\n", BANNER );
if ( argc == 1 ) {
printHelp ();
return -1;
}
flags.Tree = false;
int argIndex = 1;
do {
argIndex = parseArgs ( argIndex, argv );
if ( argIndex < 0 ) break;
char wadFileName [ 256 ];
wadList *myList = getInputFiles ( argv [argIndex++], wadFileName );
if ( myList->IsEmpty ()) break;
printf ( "Analyzing: %s\n\n", wadFileName );
char levelNames [MAX_LEVELS+1][MAX_LUMP_NAME];
argIndex = getLevels ( argIndex, argv, levelNames, myList );
if ( levelNames [0][0] == '\0' ) {
fprintf ( stderr, "Unable to find any valid levels in %s\n", wadFileName );
break;
}
if ( ! flags.Tree ) {
printf ( " Max Avg\n" );
printf ( " Depth Depth FOM Balance Splits Diagonals Nodes Segs\n" );
}
int noLevels = 0;
do {
const wadListDirEntry *dir = myList->FindWAD ( levelNames [ noLevels ]);
DoomLevel *curLevel = new DoomLevel ( levelNames [ noLevels ], dir->wad );
printf ( "%8.8s: ", levelNames [ noLevels++ ]);
AnalyzeBSP ( curLevel );
printf ( "\n" );
delete curLevel;
} while ( levelNames [noLevels][0] );
printf ( "\n" );
delete myList;
} while ( argv [argIndex] );
return 0;
}

494
ZenNode/compare.cpp Normal file
View file

@ -0,0 +1,494 @@
//----------------------------------------------------------------------------
//
// File: compare.cpp
// Date: 16-Jan-1996
// Programmer: Marc Rousseau
//
// Description: Compares two REJECT structures and report any differences
//
// Copyright (c) 1996-2004 Marc Rousseau, All Rights Reserved.
//
// 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.
//
// Revision History:
//
//----------------------------------------------------------------------------
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined ( __OS2__ )
#define INCL_DOS
#define INCL_SUB
#include <conio.h>
#include <dos.h>
#include <io.h>
#include <os2.h>
#elif defined ( __WIN32__ )
#include <conio.h>
#include <dos.h>
#include <io.h>
#include <windows.h>
#include <wincon.h>
#elif defined ( __GNUC__ ) || defined ( __INTEL_COMPILER )
#include <unistd.h>
#else
#error This program must be compiled as a 32-bit app.
#endif
#include "common.hpp"
#include "logger.hpp"
#include "wad.hpp"
#include "level.hpp"
#include "console.hpp"
DBG_REGISTER ( __FILE__ );
#define VERSION "1.3"
#define BANNER "compare Version " VERSION " (c) 1996-2004 Marc Rousseau"
#define MAX_LEVELS 99
#define UNSUPPORTED_FEATURE -1
#define UNRECOGNIZED_PARAMETER -2
#if defined ( __BORLANDC__ )
#pragma option -x -xf
#endif
#if defined ( __GNUC__ ) || defined ( __INTEL_COMPILER )
#define stricmp strcasecmp
extern char *strupr ( char *ptr );
#endif
void printHelp ()
{
FUNCTION_ENTRY ( NULL, "printHelp", true );
fprintf ( stderr, "Usage: compare {-options} filename1[.wad] filename2[.wad] [level{+level}]\n" );
fprintf ( stderr, "\n" );
fprintf ( stderr, " -x+ turn on option -x- turn off option %c = default\n", DEFAULT_CHAR );
fprintf ( stderr, "\n" );
fprintf ( stderr, " level - ExMy for DOOM / Heretic\n" );
fprintf ( stderr, " MAPxx for DOOM II / HEXEN\n" );
}
int parseArgs ( int index, const char *argv[] )
{
FUNCTION_ENTRY ( NULL, "parseArgs", true );
bool errors = false;
while ( argv [ index ] ) {
if ( argv [index][0] != '-' ) break;
char *localCopy = strdup ( argv [ index ]);
char *ptr = localCopy + 1;
strupr ( localCopy );
bool localError = false;
while ( *ptr && ( localError == false )) {
int option = *ptr++;
bool setting = true;
if (( *ptr == '+' ) || ( *ptr == '-' )) {
setting = ( *ptr == '-' ) ? false : true;
ptr++;
}
switch ( option ) {
case -1 :
default : localError = true;
}
}
if ( localError ) {
errors = true;
int offset = ptr - localCopy - 1;
size_t width = strlen ( ptr ) + 1;
fprintf ( stderr, "Unrecognized parameter '%*.*s'\n", width, width, argv [index] + offset );
}
free ( localCopy );
index++;
}
if ( errors ) fprintf ( stderr, "\n" );
return index;
}
int getLevels ( int argIndex, const char *argv[], char names [][MAX_LUMP_NAME], wadList *list1, wadList *list2 )
{
FUNCTION_ENTRY ( NULL, "getLevels", true );
int index = 0, errors = 0;
char buffer [128];
buffer [0] = '\0';
if ( argv [argIndex] ) {
strcpy ( buffer, argv [argIndex] );
strupr ( buffer );
}
char *ptr = strtok ( buffer, "+" );
// See if the user requested specific levels
if ( WAD::IsMap ( ptr )) {
argIndex++;
while ( ptr ) {
if ( WAD::IsMap ( ptr )) {
if ( list1->FindWAD ( ptr )) {
strcpy ( names [index++], ptr );
} else {
fprintf ( stderr, " Could not find %s\n", ptr, errors++ );
}
} else {
fprintf ( stderr, " %s is not a valid name for a level\n", ptr, errors++ );
}
ptr = strtok ( NULL, "+" );
}
} else {
int size = list1->DirSize ();
const wadListDirEntry *dir = list1->GetDir ( 0 );
for ( int i = 0; i < size; i++ ) {
if ( dir->wad->IsMap ( dir->entry->name )) {
if ( index == MAX_LEVELS ) {
fprintf ( stderr, "ERROR: Too many levels in WAD - ignoring %s!\n", dir->entry->name, errors++ );
} else {
memcpy ( names [index++], dir->entry->name, MAX_LUMP_NAME );
}
}
dir++;
}
}
memset ( names [index], 0, MAX_LUMP_NAME );
// Remove any maps that aren't in both files
for ( int i = 0; names [i][0]; i++ ) {
if ( list2->FindWAD ( names [i] ) == NULL ) {
memcpy ( names + i, names + i + 1, ( index - i ) * MAX_LUMP_NAME );
i--;
}
}
if ( errors ) fprintf ( stderr, "\n" );
return argIndex;
}
void EnsureExtension ( char *fileName, const char *ext )
{
FUNCTION_ENTRY ( NULL, "EnsureExtension", true );
// See if the file exists first
FILE *file = fopen ( fileName, "rb" );
if ( file != NULL ) {
fclose ( file );
return;
}
size_t length = strlen ( fileName );
if ( stricmp ( &fileName [length-4], ext ) != 0 ) {
strcat ( fileName, ext );
}
}
const char *TypeName ( eWadType type )
{
FUNCTION_ENTRY ( NULL, "TypeName", true );
const char *name = NULL;
switch ( type ) {
case wt_DOOM : name = "DOOM"; break;
case wt_DOOM2 : name = "DOOM2"; break;
case wt_HERETIC : name = "Heretic"; break;
case wt_HEXEN : name = "Hexen"; break;
default : name = "<Unknown>"; break;
}
return name;
}
wadList *getInputFiles ( const char *cmdLine, char *wadFileName )
{
FUNCTION_ENTRY ( NULL, "getInputFiles", true );
char *listNames = wadFileName;
wadList *myList = new wadList;
if ( cmdLine == NULL ) return myList;
char temp [ 256 ];
strcpy ( temp, cmdLine );
char *ptr = strtok ( temp, "+" );
int errors = 0;
while ( ptr && *ptr ) {
char wadName [ 256 ];
strcpy ( wadName, ptr );
EnsureExtension ( wadName, ".wad" );
WAD *wad = new WAD ( wadName );
if ( wad->Status () != ws_OK ) {
const char *msg;
switch ( wad->Status ()) {
case ws_INVALID_FILE : msg = "The file %s does not exist\n"; break;
case ws_CANT_READ : msg = "Can't open the file %s for read access\n"; break;
case ws_INVALID_WAD : msg = "%s is not a valid WAD file\n"; break;
default : msg = "** Unexpected Error opening %s **\n"; break;
}
fprintf ( stderr, msg, wadName );
delete wad;
} else {
if ( ! myList->IsEmpty ()) {
cprintf ( "Merging: %s with %s\r\n", wadName, listNames );
*wadFileName++ = '+';
}
if ( myList->Add ( wad ) == false ) {
errors++;
if ( myList->Type () != wt_UNKNOWN ) {
fprintf ( stderr, "ERROR: %s is not a %s PWAD.\n", wadName, TypeName ( myList->Type ()));
} else {
fprintf ( stderr, "ERROR: %s is not the same type.\n", wadName );
}
delete wad;
} else {
char *end = wadName + strlen ( wadName ) - 1;
while (( end > wadName ) && ( *end != SEPERATOR )) end--;
if ( *end == SEPERATOR ) end++;
wadFileName += sprintf ( wadFileName, "%s", end );
}
}
ptr = strtok ( NULL, "+" );
}
if ( wadFileName [-1] == '+' ) wadFileName [-1] = '\0';
if ( myList->wadCount () > 1 ) cprintf ( "\r\n" );
if ( errors ) fprintf ( stderr, "\n" );
return myList;
}
int CompareREJECT ( DoomLevel *srcLevel, DoomLevel *tgtLevel )
{
FUNCTION_ENTRY ( NULL, "CompareREJECT", true );
bool match = true;
int noSectors = srcLevel->SectorCount ();
char *srcPtr = ( char * ) srcLevel->GetReject ();
char *tgtPtr = ( char * ) tgtLevel->GetReject ();
int **vis2hid = new int * [ noSectors ];
int **hid2vis = new int * [ noSectors ];
int *v2hCount = new int [ noSectors ];
int *h2vCount = new int [ noSectors ];
int bits = 8;
int srcVal = *srcPtr++;
int tgtVal = *tgtPtr++;
int dif = srcVal ^ tgtVal;
for ( int i = 0; i < noSectors; i++ ) {
vis2hid [i] = new int [ noSectors ];
hid2vis [i] = new int [ noSectors ];
memset ( vis2hid [i], 0, noSectors * sizeof ( int ));
memset ( hid2vis [i], 0, noSectors * sizeof ( int ));
v2hCount [i] = 0;
h2vCount [i] = 0;
for ( int j = 0; j < noSectors; j++ ) {
if ( dif & 1 ) {
if ( srcVal & 1 ) {
hid2vis [i][h2vCount [i]++] = j;
} else {
vis2hid [i][v2hCount [i]++] = j;
}
match = false;
}
if ( --bits == 0 ) {
bits = 8;
srcVal = *srcPtr++;
tgtVal = *tgtPtr++;
dif = srcVal ^ tgtVal;
} else {
srcVal >>= 1;
tgtVal >>= 1;
dif >>= 1;
}
}
}
bool first = true;
for ( int i = 0; i < noSectors; i++ ) {
if (( v2hCount [i] == 0 ) && ( h2vCount [i] == 0 )) continue;
bool v2h = false;
for ( int j = 0; j < v2hCount [i]; j++ ) {
int index = vis2hid [i][j];
if (( v2hCount [i] > v2hCount [index] ) ||
(( v2hCount [i] == v2hCount [index] ) && ( i > index ))) {
v2h = true;
break;
}
}
bool h2v = false;
for ( int j = 0; j < h2vCount [i]; j++ ) {
int index = hid2vis [i][j];
if (( h2vCount [i] > h2vCount [index] ) ||
(( h2vCount [i] == h2vCount [index] ) && ( i > index ))) {
h2v = true;
break;
}
}
if ( v2h == true ) {
if ( first == false ) printf ( " " );
printf ( "vis->hid %5d:", i );
for ( int j = 0; j < v2hCount [i]; j++ ) {
printf ( " %d", vis2hid [i][j] );
}
printf ( "\n" );
first = false;
}
if ( h2v == true ) {
if ( first == false ) printf ( " " );
printf ( "hid->vis %5d:", i );
for ( int j = 0; j < h2vCount [i]; j++ ) {
printf ( " %d", hid2vis [i][j] );
}
printf ( "\n" );
first = false;
}
}
if ( match == true ) printf ( "Perfect Match\n" );
for ( int i = 0; i < noSectors; i++ ) {
delete [] vis2hid [i];
delete [] hid2vis [i];
}
delete [] vis2hid;
delete [] hid2vis;
delete [] v2hCount;
delete [] h2vCount;
return match ? 0 : 1;
}
int ProcessLevel ( char *name, wadList *myList1, wadList *myList2 )
{
FUNCTION_ENTRY ( NULL, "ProcessLevel", true );
int change;
cprintf ( " %-*.*s: ", MAX_LUMP_NAME, MAX_LUMP_NAME, name );
GetXY ( &startX, &startY );
DoomLevel *tgtLevel = NULL;
const wadListDirEntry *dir = myList1->FindWAD ( name );
DoomLevel *srcLevel = new DoomLevel ( name, dir->wad );
if ( srcLevel->IsValid ( true ) == false ) {
change = -1000;
cprintf ( "The source level is not valid... \r\n" );
goto done;
}
dir = myList2->FindWAD ( name );
tgtLevel = new DoomLevel ( name, dir->wad );
if ( tgtLevel->IsValid ( true ) == false ) {
change = -1000;
cprintf ( "The target level is not valid... \r\n" );
goto done;
}
if ( srcLevel->RejectSize () != tgtLevel->RejectSize ()) {
change = -1000;
cprintf ( "The reject maps aren't the same size\r\n" );
goto done;
}
change = CompareREJECT ( srcLevel, tgtLevel );
done:
delete tgtLevel;
delete srcLevel;
return change;
}
#if defined ( __BORLANDC__ )
#include <dir.h>
#endif
int main ( int argc, const char *argv[] )
{
FUNCTION_ENTRY ( NULL, "main", true );
SaveConsoleSettings ();
HideCursor ();
cprintf ( "%s\r\n\r\n", BANNER );
if ( ! isatty ( fileno ( stdout ))) fprintf ( stdout, "%s\n\n", BANNER );
if ( ! isatty ( fileno ( stderr ))) fprintf ( stderr, "%s\n\n", BANNER );
if ( argc == 1 ) {
printHelp ();
return -1;
}
int argIndex = 1, changes = 0;
while ( KeyPressed ()) GetKey ();
do {
argIndex = parseArgs ( argIndex, argv );
if ( argIndex < 0 ) break;
char wadFileName1 [ 256 ];
wadList *myList1 = getInputFiles ( argv [argIndex++], wadFileName1 );
if ( myList1->IsEmpty ()) { changes = -1000; break; }
char wadFileName2 [ 256 ];
wadList *myList2 = getInputFiles ( argv [argIndex++], wadFileName2 );
if ( myList2->IsEmpty ()) { changes = -1000; break; }
cprintf ( "Comparing: %s and %s\r\n\n", wadFileName1, wadFileName2 );
char levelNames [MAX_LEVELS+1][MAX_LUMP_NAME];
argIndex = getLevels ( argIndex, argv, levelNames, myList1, myList2 );
if ( levelNames [0][0] == '\0' ) {
fprintf ( stderr, "Unable to find any valid levels in %s\n", wadFileName1 );
break;
}
int noLevels = 0;
do {
changes += ProcessLevel ( levelNames [noLevels++], myList1, myList2 );
if ( KeyPressed () && ( GetKey () == 0x1B )) break;
} while ( levelNames [noLevels][0] );
delete myList1;
delete myList2;
} while ( argv [argIndex] );
cprintf ( "\r\n" );
RestoreConsoleSettings ();
return changes;
}

574
ZenNode/console.cpp Normal file
View file

@ -0,0 +1,574 @@
//----------------------------------------------------------------------------
//
// File: console.cpp
// Date: 13-Aug-2000
// Programmer: Marc Rousseau
//
// Description: Screen I/O routines for ZenNode
//
// Copyright (c) 2000-2004 Marc Rousseau, All Rights Reserved.
//
// 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.
//
// Revision History:
//
// 06-??-95 Added Win32 support
// 07-19-95 Updated command line & screen logic
// 11-19-95 Updated command line again
// 12-06-95 Add config & customization file support
// 11-??-98 Added Linux support
// 04-21-01 Modified Linux code to match Win32 console I/O behavior
// 04-26-01 Added SIGABRT to list of 'handled' signals
//
//----------------------------------------------------------------------------
#if defined ( __OS2__ )
#include <conio.h>
#include <dos.h>
#include <io.h>
#define INCL_DOS
#define INCL_SUB
#include <os2.h>
#elif defined ( __WIN32__ )
#include <conio.h>
#include <signal.h>
#include <windows.h>
#elif defined ( __GNUC__ ) || defined ( __INTEL_COMPILER )
#include <memory.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/time.h>
#include <termios.h>
#include <unistd.h>
#include "level.hpp"
#else
#error This program must be compiled as a 32-bit app.
#endif
#include "common.hpp"
#include "console.hpp"
static UINT32 curX = 0;
static UINT32 curY = 0;
UINT32 startX, startY;
char progress [4] = { 0x7C, 0x2F, 0x2D, 0x5C };
int progressIndex;
#if defined ( __OS2__ )
static HVIO hVio = 0;
static VIOCURSORINFO vioco;
static int oldAttr;
void SaveConsoleSettings ()
{
VioGetCurType ( &vioco, hVio );
oldAttr = vioco.attr;
vioco.attr = 0xFFFF;
VioSetCurType ( &vioco, hVio );
}
void RestoreConsoleSettings ()
{
vioco.attr = oldAttr;
VioSetCurType ( &vioco, hVio );
}
void GetXY ( UINT32 *x, UINT32 *y )
{
VioGetCurPos ( y, x, hVio );
}
void GotoXY ( UINT32 x, UINT32 y )
{
curX = x;
curY = y;
VioSetCurPos ( y, x, hVio );
}
UINT32 CurrentTime ()
{
UINT32 time;
DosQuerySysInfo ( QSV_MS_COUNT, QSV_MS_COUNT, &time, 4 );
return time;
}
void Status ( char *message )
{
int len = strlen ( message );
VioWrtCharStr (( BYTE * ) message, len, startY, startX, hVio );
VioWrtNChar (( BYTE * ) " ", 80 - ( startX + len ), startY, startX + len, hVio );
curY = startY;
curX = startX + len;
}
void GoRight ()
{
VioWrtNChar (( BYTE * ) "R", 1, curY, curX++, hVio );
}
void GoLeft ()
{
VioWrtNChar (( BYTE * ) "L", 1, curY, curX - 1 , hVio );
}
void Backup ()
{
curX--;
}
void ShowDone ()
{
VioWrtNChar (( BYTE * ) "*", 1, curY, curX, hVio );
}
void ShowProgress ()
{
VioWrtNChar (( BYTE * ) &progress [ progressIndex++ % SIZE ( progress )], 1, curY, curX, hVio );
}
void MoveUp ( int delta )
{
curY -= delta;
VioSetCurPos ( curY, 0, hVio );
}
void MoveDown ( int delta )
{
curY += delta;
VioSetCurPos ( curY, 0, hVio );
}
#elif defined ( __WIN32__ )
#if defined ( __GNUC__ ) || defined ( __INTEL_COMPILER )
#define cprintf _cprintf
#endif
static CONSOLE_SCREEN_BUFFER_INFO screenInfo;
static CONSOLE_CURSOR_INFO cursorInfo;
static BOOL oldVisible;
static HANDLE hOutput;
static COORD currentPos;
static LARGE_INTEGER timerFrequency;
long WINAPI myHandler ( PEXCEPTION_POINTERS )
{
RestoreConsoleSettings ();
return EXCEPTION_CONTINUE_SEARCH;
}
void SignalHandler ( int )
{
RestoreConsoleSettings ();
cprintf ( "\r\n" );
exit ( -1 );
}
void SaveConsoleSettings ()
{
hOutput = GetStdHandle ( STD_OUTPUT_HANDLE );
GetConsoleCursorInfo ( hOutput, &cursorInfo );
GetConsoleScreenBufferInfo ( hOutput, &screenInfo );
oldVisible = cursorInfo.bVisible;
SetUnhandledExceptionFilter ( myHandler );
signal ( SIGBREAK, SignalHandler );
signal ( SIGINT, SignalHandler );
atexit ( RestoreConsoleSettings );
QueryPerformanceFrequency ( &timerFrequency );
}
void RestoreConsoleSettings ()
{
cursorInfo.bVisible = oldVisible;
SetConsoleCursorInfo ( hOutput, &cursorInfo );
}
void HideCursor ()
{
CONSOLE_CURSOR_INFO info = cursorInfo;
info.bVisible = FALSE;
SetConsoleCursorInfo ( hOutput, &info );
}
void ShowCursor ()
{
CONSOLE_CURSOR_INFO info = cursorInfo;
info.bVisible = TRUE;
SetConsoleCursorInfo ( hOutput, &info );
}
int GetKey ()
{
int key = 0;
UCHAR *ptr = ( UCHAR * ) &key;
int ch = getch ();
if ( ch == 0xE0 ) {
*ptr++ = 0x1B;
*ptr++ = 0x5B;
ch = getch ();
switch ( ch ) {
case 0x48 : ch = 0x41; break;
case 0x50 : ch = 0x42; break;
case 0x4D : ch = 0x43; break;
case 0x4B : ch = 0x44; break;
}
}
*ptr++ = ( UCHAR ) ch;
return key;
}
bool KeyPressed ()
{
return ( kbhit () != 0 ) ? true : false;
}
UINT32 CurrentTime ()
{
LARGE_INTEGER time;
QueryPerformanceCounter ( &time );
return ( UINT32 ) ( 1000 * time.QuadPart / timerFrequency.QuadPart );
}
void ClearScreen ()
{
DWORD dwActual;
COORD origin;
origin.X = 0;
origin.Y = 0;
FillConsoleOutputCharacter ( hOutput, ' ', screenInfo.dwSize.X * screenInfo.dwSize.Y, origin, &dwActual );
screenInfo.dwCursorPosition.X = 0;
screenInfo.dwCursorPosition.Y = 0;
}
void GetXY ( UINT32 *x, UINT32 *y )
{
GetConsoleScreenBufferInfo ( hOutput, &screenInfo );
*x = screenInfo.dwCursorPosition.X;
*y = screenInfo.dwCursorPosition.Y;
}
void GotoXY ( UINT32 x, UINT32 y )
{
curX = x;
curY = y;
COORD cursor;
cursor.X = ( SHORT ) curX;
cursor.Y = ( SHORT ) curY;
SetConsoleCursorPosition ( hOutput, cursor );
}
void MoveUp ( int delta )
{
GetConsoleScreenBufferInfo ( hOutput, &screenInfo );
COORD pos;
pos.X = ( SHORT ) 0;
pos.Y = ( SHORT ) ( screenInfo.dwCursorPosition.Y - delta );
SetConsoleCursorPosition ( hOutput, pos );
}
void MoveDown ( int delta )
{
GetConsoleScreenBufferInfo ( hOutput, &screenInfo );
COORD pos;
pos.X = ( SHORT ) 0;
pos.Y = ( SHORT ) ( screenInfo.dwCursorPosition.Y + delta );
SetConsoleCursorPosition ( hOutput, pos );
}
void Status ( char *message )
{
DWORD count;
DWORD len = ( DWORD ) strlen ( message );
currentPos.X = ( SHORT ) startX;
currentPos.Y = ( SHORT ) startY;
if ( len != 0 ) {
WriteConsoleOutputCharacter ( hOutput, message, len, currentPos, &count );
currentPos.X = ( SHORT ) ( currentPos.X + len );
}
FillConsoleOutputCharacter ( hOutput, ' ', screenInfo.dwSize.X - currentPos.X, currentPos, &count );
}
void GoRight ()
{
DWORD count;
WriteConsoleOutputCharacter ( hOutput, "R", 1, currentPos, &count );
currentPos.X++;
}
void GoLeft ()
{
DWORD count;
currentPos.X--;
WriteConsoleOutputCharacter ( hOutput, "L", 1, currentPos, &count );
currentPos.X++;
}
void Backup ()
{
currentPos.X--;
}
void ShowDone ()
{
DWORD count;
WriteConsoleOutputCharacter ( hOutput, "*", 1, currentPos, &count );
}
void ShowProgress ()
{
DWORD count;
WriteConsoleOutputCharacter ( hOutput, &progress [ progressIndex++ % SIZE ( progress )], 1, currentPos, &count );
}
#elif defined ( __GNUC__ ) || defined ( __INTEL_COMPILER )
static FILE *console;
static termios stored;
static termios term_getch;
static termios term_kbhit;
static int lastChar;
static int keyhit;
static bool cursor_visible = true;
int cprintf ( const char *fmt, ... )
{
va_list args;
va_start ( args, fmt );
int ret = vfprintf ( console, fmt, args );
fflush ( console );
va_end ( args );
return ret;
}
void SignalHandler ( int signal )
{
struct sigaction sa;
memset ( &sa, 0, sizeof ( sa ));
sa.sa_handler = SIG_DFL;
switch ( signal ) {
case SIGABRT :
RestoreConsoleSettings ();
break;
case SIGSEGV :
fprintf ( stderr, "Segmentation fault" );
case SIGINT :
RestoreConsoleSettings ();
printf ( "\r\n" );
exit ( -1 );
break;
case SIGTSTP :
RestoreConsoleSettings ();
printf ( "\r\n" );
sigaction ( SIGTSTP, &sa, NULL );
kill ( getpid (), SIGTSTP );
break;
case SIGCONT :
SaveConsoleSettings ();
break;
}
}
void SaveConsoleSettings ()
{
tcgetattr ( 0, &stored );
memcpy ( &term_getch, &stored, sizeof ( struct termios ));
// Disable echo
term_getch.c_lflag &= ~ECHO;
// Disable canonical mode, and set buffer size to 1 byte
term_getch.c_lflag &= ~ICANON;
term_getch.c_cc[VMIN] = 1;
memcpy ( &term_kbhit, &term_getch, sizeof ( struct termios ));
term_kbhit.c_cc[VTIME] = 0;
term_kbhit.c_cc[VMIN] = 0;
// Create a 'console' device
console = fopen ( "/dev/tty", "w" );
if ( console == NULL ) {
console = stdout;
}
HideCursor ();
struct sigaction sa;
memset ( &sa, 0, sizeof ( sa ));
sa.sa_handler = SignalHandler;
sigaction ( SIGINT, &sa, NULL );
sigaction ( SIGABRT, &sa, NULL );
sigaction ( SIGSEGV, &sa, NULL );
sigaction ( SIGTSTP, &sa, NULL );
sigaction ( SIGCONT, &sa, NULL );
atexit ( RestoreConsoleSettings );
}
void RestoreConsoleSettings ()
{
if ( console != stdout ) {
fclose ( console );
console = stdout;
}
struct sigaction sa;
memset ( &sa, 0, sizeof ( sa ));
sa.sa_handler = SIG_DFL;
sigaction ( SIGINT, &sa, NULL );
sigaction ( SIGABRT, &sa, NULL );
sigaction ( SIGSEGV, &sa, NULL );
sigaction ( SIGTSTP, &sa, NULL );
sigaction ( SIGCONT, &sa, NULL );
tcsetattr ( 0, TCSANOW, &stored );
ShowCursor ();
}
void HideCursor ()
{
if ( cursor_visible == true ) {
printf ( "\033[?25l" );
fflush ( stdout );
cursor_visible = false;
}
}
void ShowCursor ()
{
if ( cursor_visible == false ) {
printf ( "\033[?25h" );
fflush ( stdout );
cursor_visible = true;
}
}
int GetKey ()
{
int retVal = lastChar;
lastChar = 0;
if ( keyhit == 0 ) {
tcsetattr ( 0, TCSANOW, &term_getch );
keyhit = read ( STDIN_FILENO, &retVal, sizeof ( retVal ));
}
keyhit = 0;
return retVal;
}
bool KeyPressed ()
{
if ( keyhit == 0 ) {
tcsetattr ( 0, TCSANOW, &term_kbhit );
keyhit = read ( STDIN_FILENO, &lastChar, sizeof ( lastChar ));
}
return ( keyhit != 0 ) ? true : false;
}
UINT32 CurrentTime ()
{
timeval time;
gettimeofday ( &time, NULL );
return ( UINT32 ) (( time.tv_sec * 1000 ) + ( time.tv_usec / 1000 ));
}
void ClearScreen ()
{
printf ( "\033[2J" );
fflush ( stdout );
}
void GetXY ( UINT32 *x, UINT32 *y )
{
*x = MAX_LUMP_NAME + 5;
*y = 0;
}
void GotoXY ( UINT32 x, UINT32 y )
{
// fprintf ( console, "\033[%d;%dH", y, x );
fprintf ( console, "\033[%dG", x );
fflush ( console );
curX = x;
curY = y;
}
void Status ( char *message )
{
fprintf ( console, "\033[%dG%s\033[K", startX, message );
fflush ( console );
}
void GoRight ()
{
fprintf ( console, "R" );
fflush ( console );
}
void GoLeft ()
{
fprintf ( console, "\033[DL" );
fflush ( console );
}
void Backup ()
{
fprintf ( console, "\033[D" );
fflush ( console );
}
void ShowDone ()
{
fprintf ( console, "*\033[D" );
fflush ( console );
}
void ShowProgress ()
{
fprintf ( console, "%c\033[D", progress [ progressIndex++ % SIZE ( progress )] );
fflush ( console );
}
void MoveUp ( int delta )
{
fprintf ( console, "\033[%dA", delta );
fflush ( console );
}
void MoveDown ( int delta )
{
fprintf ( console, "\033[%dB", delta );
fflush ( console );
}
#endif

78
ZenNode/console.hpp Normal file
View file

@ -0,0 +1,78 @@
//----------------------------------------------------------------------------
//
// File: console.hpp
// Date: 01-Jun-2002
// Programmer: Marc Rousseau
//
// Description:
//
// Copyright (c) 1998-2004 Marc Rousseau, All Rights Reserved.
//
// 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.
//
// Revision History:
//
//----------------------------------------------------------------------------
#ifndef CONSOLE_HPP_
#define CONSOLE_HPP_
#if defined ( __OS2__ ) || defined ( __WIN32__ )
#if defined ( __GNUC__ ) || defined ( __INTEL_COMPILER )
#define cprintf _cprintf
#endif
#elif defined ( __GNUC__ ) || defined ( __INTEL_COMPILER )
#define stricmp strcasecmp
extern int cprintf ( const char *, ... );
#endif
void SaveConsoleSettings ();
void RestoreConsoleSettings ();
void HideCursor ();
void ShowCursor ();
int GetKey ();
bool KeyPressed ();
UINT32 CurrentTime ();
void ClearScreen ();
extern UINT32 startX, startY;
void GetXY ( UINT32 *x, UINT32 *y );
void GotoXY ( UINT32 x, UINT32 y );
void MoveUp ( int delta );
void MoveDown ( int delta );
void PutXY ( UINT32 x, UINT32 y, char *ptr, int length );
void Put ( char *ptr, int length );
// ----- External Functions Required by ZenNode -----
void Status ( char *message );
void GoRight ();
void GoLeft ();
void Backup ();
void ShowDone ();
void ShowProgress ();
#endif

91
ZenNode/geometry.hpp Normal file
View file

@ -0,0 +1,91 @@
//----------------------------------------------------------------------------
//
// File: geometry.hpp
// Date: 26-October-1994
// Programmer: Marc Rousseau
//
// Description:
//
// Copyright (c) 1994-2004 Marc Rousseau, All Rights Reserved.
//
// 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.
//
// Revision History:
//
//----------------------------------------------------------------------------
#ifndef GEOMETRY_HPP_
#define GEOMETRY_HPP_
#if ! defined ( COMMON_HPP_ )
#include "common.hpp"
#endif
struct sPoint;
struct sRectangle;
struct sPoint {
long x;
long y;
sPoint () { x = 0; y = 0; }
sPoint ( long _x, long _y ) { x = _x; y = _y; }
bool isInside ( const sRectangle & ) const;
bool operator == ( const sPoint &o ) const { return ( x == o.x ) && ( y == o.y ); }
bool operator != ( const sPoint &o ) const { return ( x != o.x ) || ( y != o.y ); }
};
struct sLine {
sPoint start;
sPoint end;
sLine () : start (), end () {}
sLine ( const sPoint &s, const sPoint &e ) { start = s; end = e; }
int rise () const { return end.y - start.y; }
int run () const { return end.x - start.x; }
float slope () const { return rise () / ( float ) run (); }
bool endMatches ( const sLine & ) const;
bool isInside ( const sRectangle & ) const;
bool intersects ( const sRectangle & ) const;
bool intersects ( const sLine & ) const;
};
struct sRectangle {
int xLeft, xRight;
int yTop, yBottom;
sRectangle ();
sRectangle ( long, long, long, long );
sRectangle ( const sPoint &, const sPoint & );
void include ( const sPoint & );
void include ( const sRectangle & );
long left () const { return xLeft; }
long right () const { return xRight; }
long top () const { return yTop; }
long bottom () const { return yBottom; }
long width () const { return xRight - xLeft; }
long height () const { return yTop - yBottom; }
sPoint center () const { return sPoint (( xLeft + xRight ) / 2, ( yTop + yBottom ) / 2 ); }
sPoint tl () const { return sPoint ( xLeft, yTop ); }
sPoint bl () const { return sPoint ( xLeft, yBottom ); }
sPoint tr () const { return sPoint ( xRight, yTop ); }
sPoint br () const { return sPoint ( xRight, yBottom ); }
bool isInside ( const sRectangle & ) const;
bool intersects ( const sRectangle & ) const;
};
inline sRectangle::sRectangle ()
{
xLeft = yTop = xRight = yBottom = 0;
}
#endif

139
ZenNode/makefile Normal file
View file

@ -0,0 +1,139 @@
# ZenNode makefile for Linux
CC = g++
CFLAGS += -g -O -fstrength-reduce -fno-rtti
CFLAGS += -fomit-frame-pointer -foptimize-sibling-calls
#CFLAGS += -fbranch-probabilities
#CFLAGS += -fprofile-arcs
WARNINGS = -Wall -Wno-format -Wstrict-prototypes -Wmissing-prototypes -Winline
#CC = /opt/intel/compiler60/ia32/bin/icc
#CFLAGS = -g -O3
INCLUDES = -I../DOOM -I../common
TARGETS = ZenNode bspdiff bspinfo compare
CFLAGS += -D__LINUX__
ifdef WIN32
CFLAGS += -D__WIN32__
endif
ifdef DEBUG
CFLAGS += -DDEBUG
LOGGER = ../common/logger/logger.o ../common/logger/string.o
CFLAGS += -fexceptions
LOGGER += ../common/logger/linux-logger.o
LIBS += -lpthread -lrt
endif
.cpp.o:
$(CC) -c $(CFLAGS) $(WARNINGS) $(INCLUDES) -o $@ $<
.SUFFIXES: .cpp .o
all: $(TARGETS)
depend: clean
clean:
rm -rf {.,../DOOM/,../common/logger}/{*.o,*~} $(TARGETS)
ZenNode: ZenMain.o ZenNode.o ZenReject.o ZenRMB.o blockmap.o console.o ../DOOM/wad.o ../DOOM/level.o $(LOGGER)
$(CC) $(LIBS) -o $@ $^
bspdiff: bspdiff.o console.o ../DOOM/wad.o ../DOOM/level.o $(LOGGER)
$(CC) $(LIBS) -o $@ $^
bspinfo: bspinfo.o console.o ../DOOM/wad.o ../DOOM/level.o $(LOGGER)
$(CC) $(LIBS) -o $@ $^
compare: compare.o console.o ../DOOM/wad.o ../DOOM/level.o $(LOGGER)
$(CC) $(LIBS) -o $@ $^
ZenReject.o: \
ZenReject.cpp \
ZenReject-util.cpp \
../common/common.hpp \
../DOOM/level.hpp \
ZenNode.hpp \
console.hpp \
geometry.hpp
ZenNode.o: \
ZenNode.cpp \
../common/common.hpp \
../common/logger.hpp \
../DOOM/level.hpp \
ZenNode.hpp \
console.hpp
ZenMain.o: \
ZenMain.cpp \
../common/common.hpp \
../common/logger.hpp \
../DOOM/wad.hpp \
../DOOM/level.hpp \
console.hpp \
ZenNode.hpp
ZenReject.o: \
ZenReject.cpp \
../common/common.hpp \
../DOOM/level.hpp \
ZenNode.hpp \
console.hpp \
geometry.hpp
ZenRMB.o: \
ZenRMB.cpp \
../common/common.hpp \
../DOOM/level.hpp \
ZenNode.hpp
blockmap.o: \
blockmap.cpp \
../common/common.hpp \
../DOOM/level.hpp \
ZenNode.hpp
console.o: \
console.cpp \
../DOOM/level.hpp \
../common/common.hpp \
console.hpp \
../DOOM/wad.o: \
../DOOM/wad.cpp \
../common/common.hpp \
../DOOM/wad.hpp \
../DOOM/level.hpp
../DOOM/level.o: \
../DOOM/level.cpp \
../common/common.hpp \
../common/logger.hpp \
../DOOM/wad.hpp \
../DOOM/level.hpp
bspdiff.o: \
bspdiff.cpp \
../common/common.hpp \
../common/logger.hpp \
../DOOM/wad.hpp \
../DOOM/level.hpp \
console.hpp
bspinfo.o: \
bspinfo.cpp \
../common/common.hpp \
../common/logger.hpp \
../DOOM/wad.hpp \
../DOOM/level.hpp \
console.hpp
compare.o: \
compare.cpp \
../common/common.hpp \
../common/logger.hpp \
../DOOM/wad.hpp \
../DOOM/level.hpp \
console.hpp

258
common/common.hpp Normal file
View file

@ -0,0 +1,258 @@
//----------------------------------------------------------------------------
//
// File: common.hpp
// Date:
// Programmer: Marc Rousseau
//
// Description:
//
// Copyright (c) 1994-2004 Marc Rousseau, All Rights Reserved.
//
// 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.
//
// Revision History:
//
//----------------------------------------------------------------------------
#ifndef COMMON_HPP_
#define COMMON_HPP_
//----------------------------------------------------------------------------
// Generic definitions
//----------------------------------------------------------------------------
#ifdef UNREFERENCED_PARAMETER
#undef UNREFERENCED_PARAMETER
#endif
#if defined ( _MSC_VER )
#define UNREFERENCED_PARAMETER(x) x
#else
#define UNREFERENCED_PARAMETER(x)
#endif
#define OFFSET_OF(t,x) (( size_t ) & (( t * ) 0 )->( x ))
#define SIZE(x) ( sizeof ( x ) / sizeof (( x )[0] ))
#define EVER ;;
typedef signed char INT8;
typedef signed short INT16;
typedef signed int INT32;
typedef unsigned char UINT8, UCHAR;
typedef unsigned short UINT16;
typedef unsigned int UINT32;
#if defined ( __GNUC__ )
typedef long long INT64;
typedef unsigned long long UINT64;
#else
typedef __int64 INT64;
typedef unsigned __int64 UINT64;
#endif
#if defined ( __WIN32__ ) || defined ( __AMIGAOS__ )
// Undo any previos definitions
#define BIG_ENDIAN 1234
#define LITTLE_ENDIAN 4321
#define BYTE_ORDER LITTLE_ENDIAN
#else
// Use the environments endian definitions
#undef __USE_BSD
#define __USE_BSD
#include <endian.h>
#endif
typedef int (*QSORT_FUNC) ( const void *, const void * );
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
template < class T > inline void swap ( T &item1, T &item2 )
{
T temp = item1;
item1 = item2;
item2 = temp;
}
//----------------------------------------------------------------------------
// Platform specific definitions
//----------------------------------------------------------------------------
#if defined ( __OS2__ ) || defined ( __WIN32__ )
#define SEPERATOR '\\'
#define DEFAULT_CHAR 'û'
#elif defined ( __GNUC__ ) || defined ( __INTEL_COMPILER )
#define SEPERATOR '/'
#define DEFAULT_CHAR '*'
#endif
//----------------------------------------------------------------------------
// Compiler specific definitions
//----------------------------------------------------------------------------
#if defined ( __BORLANDC__ )
#if defined ( __BCPLUSPLUS__ ) || defined ( __TCPLUSPLUS__ )
#undef NULL
#define NULL ( void * ) 0
#endif
#if (( __BORLANDC__ < 0x0500 ) || defined ( __OS2__ ))
// Fake out ANSI definitions for deficient compilers
#define for if (0); else for
enum { false, true };
class bool {
int value;
public:
operator = ( int x ) { value = x ? true : false; }
bool operator ! () { return value; }
};
#endif
template <class T> inline const T &min ( const T &t1, const T &t2 )
{
return ( t1 > t2 ) ? t2 : t1;
}
template <class T> inline const T &max ( const T &t1, const T &t2 )
{
return ( t1 > t2 ) ? t1 : t2;
}
#elif defined ( _MSC_VER )
#undef NULL
#define NULL 0L
#define MAXPATH _MAX_PATH
#define MAXDRIVE _MAX_DRIVE
#define MAXDIR _MAX_DIR
#define MAXFNAME _MAX_FNAME
#define MAXEXT _MAX_EXT
#if ( _MSC_VER < 1300 )
// Fake out ANSI definitions for deficient compilers
#define for if (0); else for
#pragma warning ( disable: 4127 ) // C4127: conditional expression is constant
#endif
#pragma warning ( disable: 4244 ) // C4244: 'xyz' conversion from 'xxx' to 'yyy', possible loss of data
#pragma warning( disable : 4290 ) // C4290: C++ exception specification ignored...
#pragma warning ( disable: 4514 ) // C4514: 'xyz' unreferenced inline function has been removed
template <class T> inline const T &min ( const T &t1, const T &t2 )
{
return ( t1 > t2 ) ? t2 : t1;
}
template <class T> inline const T &max ( const T &t1, const T &t2 )
{
return ( t1 > t2 ) ? t1 : t2;
}
#if ( _MSC_VER >= 1300 )
extern char *strndup ( const char *string, size_t max );
#endif
#elif defined ( __WATCOMC__ )
#define M_PI 3.14159265358979323846
template <class T> inline const T &min ( const T &t1, const T &t2 )
{
return ( t1 > t2 ) ? t2 : t1;
}
template <class T> inline const T &max ( const T &t1, const T &t2 )
{
return ( t1 > t2 ) ? t1 : t2;
}
#elif defined ( __GNUC__ ) || defined ( __INTEL_COMPILER )
#define MAXPATH FILENAME_MAX
#define MAXDRIVE FILENAME_MAX
#define MAXDIR FILENAME_MAX
#define MAXFNAME FILENAME_MAX
#define MAXEXT FILENAME_MAX
#define O_BINARY 0
#define stricmp strcasecmp
#define strnicmp strncasecmp
template <class T> inline const T &min ( const T &t1, const T &t2 )
{
return ( t1 > t2 ) ? t2 : t1;
}
template <class T> inline const T &max ( const T &t1, const T &t2 )
{
return ( t1 > t2 ) ? t1 : t2;
}
#elif defined ( __AMIGAOS__ )
// Fake out ANSI definitions for deficient compilers
#define for if (0); else for
enum { false, true };
class bool {
int value;
public:
operator = ( int x ) { value = x ? true : false; }
bool operator ! () { return value; }
};
template <class T> inline const T &min ( const T &t1, const T &t2 )
{
return ( t1 > t2 ) ? t2 : t1;
}
template <class T> inline const T &max ( const T &t1, const T &t2 )
{
return ( t1 > t2 ) ? t1 : t2;
}
extern char *strdup ( const char *string );
extern char *strndup ( const char *string, size_t max );
#endif
#endif

185
common/logger.hpp Normal file
View file

@ -0,0 +1,185 @@
//----------------------------------------------------------------------------
//
// File: logger.hpp
// Date: 15-Apr-1998
// Programmer: Marc Rousseau
//
// Description: Error Logger object header
//
// Copyright (c) 1998-2004 Marc Rousseau, All Rights Reserved.
//
// 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.
//
// Revision History:
//
//----------------------------------------------------------------------------
#ifndef LOGGER_HPP_
#define LOGGER_HPP_
#ifdef ERROR
#undef ERROR
#endif
#ifdef ASSERT
#undef ASSERT
#endif
#if defined ( DEBUG )
struct LOG_FLAGS {
bool FunctionEntry;
};
extern LOG_FLAGS g_LogFlags;
#define FUNCTION_ENTRY(t,f,l) \
void *l_pThis = ( void * ) t; \
char *l_FnName = f; \
bool l_log = ( g_LogFlags.FunctionEntry == l ) ? true : false; \
if ( l_log && g_LogFlags.FunctionEntry ) { \
DBG_MINOR_TRACE2 ( l_FnName, l_pThis, "Function entered" ); \
}
#define ASSERT(x) (( ! ( x )) ? dbg_Assert ( dbg_FileName, __LINE__, l_FnName, l_pThis, #x ), 1 : 0 )
#define ASSERT_BOOL(x) ASSERT ( x )
#else
#if defined ( _MSC_VER )
#pragma warning ( disable: 4127 ) // C4127: conditional expression is constant
#endif
#define FUNCTION_ENTRY(t,f,l)
#define ASSERT(x)
#define ASSERT_BOOL(x) 0
#endif
#define TRACE(x) DBG_MAJOR_TRACE2 ( l_FnName, l_pThis, ( const char * ) x )
#define EVENT(x) DBG_MINOR_EVENT2 ( l_FnName, l_pThis, ( const char * ) x )
#define MINOR_EVENT(x) DBG_MINOR_EVENT2 ( l_FnName, l_pThis, ( const char * ) x )
#define MAJOR_EVENT(x) DBG_MAJOR_EVENT2 ( l_FnName, l_pThis, ( const char * ) x )
#define STATUS(x) DBG_STATUS2 ( l_FnName, l_pThis, ( const char * ) x )
#define WARNING(x) DBG_WARNING2 ( l_FnName, l_pThis, ( const char * ) x )
#define ERROR(x) DBG_ERROR2 ( l_FnName, l_pThis, ( const char * ) x )
#define FATAL(x) DBG_FATAL2 ( l_FnName, l_pThis, ( const char * ) x )
#if ! defined ( DEBUG )
#define DBG_REGISTER(x)
#define DBG_STRING(x) ""
#define DBG_MINOR_TRACE(f,t,x)
#define DBG_MINOR_TRACE2(f,t,x)
#define DBG_MAJOR_TRACE(f,t,x)
#define DBG_MAJOR_TRACE2(f,t,x)
#define DBG_MINOR_EVENT(f,t,x)
#define DBG_MINOR_EVENT2(f,t,x)
#define DBG_MAJOR_EVENT(f,t,x)
#define DBG_MAJOR_EVENT2(f,t,x)
#define DBG_STATUS(f,t,x)
#define DBG_STATUS2(f,t,x)
#define DBG_WARNING(f,t,x)
#define DBG_WARNING2(f,t,x)
#define DBG_ERROR(f,t,x)
#define DBG_ERROR2(f,t,x)
#define DBG_FATAL(f,t,x)
#define DBG_FATAL2(f,t,x)
#define DBG_ASSERT(f,t,x) 0
#else
#define DBG_REGISTER(x) static int dbg_FileName = dbg_RegisterFile ( x );
#define DBG_STRING(x) x
#define DBG_MINOR_TRACE(f,t,x) dbg_Record ( _MINOR_TRACE_, dbg_FileName, __LINE__, f, t, x )
#define DBG_MINOR_TRACE2(f,t,x) dbg_Record ( _MINOR_TRACE_, dbg_FileName, __LINE__, f, t, dbg_Stream () << x ), dbg_Stream ().flush ()
#define DBG_MAJOR_TRACE(f,t,x) dbg_Record ( _MAJOR_TRACE_, dbg_FileName, __LINE__, f, t, x )
#define DBG_MAJOR_TRACE2(f,t,x) dbg_Record ( _MAJOR_TRACE_, dbg_FileName, __LINE__, f, t, dbg_Stream () << x ), dbg_Stream ().flush ()
#define DBG_MINOR_EVENT(f,t,x) dbg_Record ( _MINOR_EVENT_, dbg_FileName, __LINE__, f, t, x )
#define DBG_MINOR_EVENT2(f,t,x) dbg_Record ( _MINOR_EVENT_, dbg_FileName, __LINE__, f, t, dbg_Stream () << x ), dbg_Stream ().flush ()
#define DBG_MAJOR_EVENT(f,t,x) dbg_Record ( _MAJOR_EVENT_, dbg_FileName, __LINE__, f, t, x )
#define DBG_MAJOR_EVENT2(f,t,x) dbg_Record ( _MAJOR_EVENT_, dbg_FileName, __LINE__, f, t, dbg_Stream () << x ), dbg_Stream ().flush ()
#define DBG_STATUS(f,t,x) dbg_Record ( _STATUS_, dbg_FileName, __LINE__, f, t, x )
#define DBG_STATUS2(f,t,x) dbg_Record ( _STATUS_, dbg_FileName, __LINE__, f, t, dbg_Stream () << x ), dbg_Stream ().flush ()
#define DBG_WARNING(f,t,x) dbg_Record ( _WARNING_, dbg_FileName, __LINE__, f, t, x )
#define DBG_WARNING2(f,t,x) dbg_Record ( _WARNING_, dbg_FileName, __LINE__, f, t, dbg_Stream () << x ), dbg_Stream ().flush ()
#define DBG_ERROR(f,t,x) dbg_Record ( _ERROR_, dbg_FileName, __LINE__, f, t, x )
#define DBG_ERROR2(f,t,x) dbg_Record ( _ERROR_, dbg_FileName, __LINE__, f, t, dbg_Stream () << x ), dbg_Stream ().flush ()
#define DBG_FATAL(f,t,x) dbg_Record ( _FATAL_, dbg_FileName, __LINE__, f, t, x )
#define DBG_FATAL2(f,t,x) dbg_Record ( _FATAL_, dbg_FileName, __LINE__, f, t, dbg_Stream () << x ), dbg_Stream ().flush ()
#define DBG_ASSERT(f,t,x) (( ! ( x )) ? dbg_Assert ( dbg_FileName, __LINE__, f, t, #x ), 1 : 0 )
enum eLOG_TYPE {
_MINOR_TRACE_,
_MAJOR_TRACE_,
_MINOR_EVENT_,
_MAJOR_EVENT_,
_STATUS_,
_WARNING_,
_ERROR_,
_FATAL_,
LOG_TYPE_MAX
};
class dbgString {
friend dbgString &hex ( dbgString & );
friend dbgString &dec ( dbgString & );
int m_Base;
bool m_OwnBuffer;
char *m_Ptr;
char *m_Buffer;
public:
dbgString ( char * );
operator const char * ();
void flush ();
dbgString &operator << ( const char * );
dbgString &operator << ( char );
dbgString &operator << ( unsigned char );
dbgString &operator << ( short );
dbgString &operator << ( unsigned short );
dbgString &operator << ( int );
dbgString &operator << ( unsigned int );
dbgString &operator << ( long );
dbgString &operator << ( unsigned long );
/*
dbgString &operator << ( __int64 );
dbgString &operator << ( unsigned __int64 );
*/
dbgString &operator << ( double );
dbgString &operator << ( void * );
dbgString &operator << ( dbgString &(*f) ( dbgString & ));
};
dbgString &hex ( dbgString & );
dbgString &dec ( dbgString & );
extern "C" {
dbgString &dbg_Stream ();
int dbg_RegisterFile ( const char * );
void dbg_Assert ( int, int, const char * , void *, const char * );
void dbg_Record ( int, int, int, const char *, void *, const char * );
};
#endif
#endif