Initial import

This commit is contained in:
Magnus Norddahl 2017-08-03 20:25:54 +02:00
parent ddd769c695
commit e9356ea255
49 changed files with 21219 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
/Debug
/*.ncb
/*.suo
/debug_vs2005
/Release_vs2005
/build

235
CMakeLists.txt Normal file
View File

@ -0,0 +1,235 @@
cmake_minimum_required( VERSION 2.4 )
if( COMMAND cmake_policy )
cmake_policy( SET CMP0003 NEW )
endif( COMMAND cmake_policy )
include( CheckFunctionExists )
include( CheckCXXCompilerFlag )
project( ZDRay )
IF( NOT CMAKE_BUILD_TYPE )
SET( CMAKE_BUILD_TYPE Debug CACHE STRING
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
FORCE )
ENDIF( NOT CMAKE_BUILD_TYPE )
set( SSE_MATTERS NO )
# SSE only matters on 32-bit targets. We check compiler flags to know if we can do it.
if( CMAKE_SIZEOF_VOID_P MATCHES "4" )
CHECK_CXX_COMPILER_FLAG( "-msse2 -mfpmath=sse" CAN_DO_MFPMATH )
CHECK_CXX_COMPILER_FLAG( -arch:SSE2 CAN_DO_ARCHSSE2 )
if( CAN_DO_MFPMATH )
set( SSE1_ENABLE "-msse -mfpmath=sse" )
set( SSE2_ENABLE "-msse2 -mfpmath=sse" )
set( SSE_MATTERS YES )
elseif( CAN_DO_ARCHSSE2 )
set( SSE1_ENABLE -arch:SSE )
set( SSE2_ENABLE -arch:SSE2 )
set( SSE_MATTERS YES )
endif( CAN_DO_MFPMATH )
endif( CMAKE_SIZEOF_VOID_P MATCHES "4" )
if( SSE_MATTERS )
if( WIN32 )
set( BACKPATCH 1 CACHE BOOL "Enable backpatching." )
else( WIN32 )
CHECK_FUNCTION_EXISTS(mprotect HAVE_MPROTECT)
if( HAVE_MPROTECT )
set( BACKPATCH 1 CACHE BOOL "Enable backpatching." )
else( HAVE_MPROTECT )
set( BACKPATCH 0 )
endif( HAVE_MPROTECT )
endif( WIN32 )
set( FULL_SSE2 0 CACHE BOOL "Use SSE2 math everywhere." )
set( SSE 1 CACHE BOOL "Build SSE and SSE2 versions of key code." )
else( SSE_MATTERS )
set( BACKPATCH 0 )
endif( SSE_MATTERS )
if( CMAKE_COMPILER_IS_GNUCXX )
set( GPROF 0 CACHE BOOL "Enable profiling with gprof for Debug and RelWithDebInfo build types." )
set( PROFILE 0 CACHE INT "1=Generate profile coverage info, 2=Use it" )
endif( CMAKE_COMPILER_IS_GNUCXX )
find_package( ZLIB )
if( MSVC )
# Eliminate unreferenced functions and data
# Perform identical COMDAT folding
set( REL_LINKER_FLAGS "/opt:ref /opt:icf /nodefaultlib:msvcrt" )
# String pooling
# Function-level linking
# Disable run-time type information
set( ALL_C_FLAGS "/GF /Gy /GR-" )
# Avoid CRT DLL dependancies in release builds
set( REL_C_FLAGS "/MT" )
# Disable warnings for unsecure CRT functions from VC8+
if( MSVC_VERSION GREATER 1399 )
set( ALL_C_FLAGS "${ALL_C_FLAGS} /wd4996" )
endif( MSVC_VERSION GREATER 1399 )
# The CMake configurations set /GR and /MD by default, which conflict with our settings.
string(REPLACE "/MD " " " CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} )
string(REPLACE "/MD " " " CMAKE_CXX_FLAGS_MINSIZEREL ${CMAKE_CXX_FLAGS_MINSIZEREL} )
string(REPLACE "/MD " " " CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO} )
string(REPLACE "/MD " " " CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE} )
string(REPLACE "/MD " " " CMAKE_C_FLAGS_MINSIZEREL ${CMAKE_C_FLAGS_MINSIZEREL} )
string(REPLACE "/MD " " " CMAKE_C_FLAGS_RELWITHDEBINFO ${CMAKE_C_FLAGS_RELWITHDEBINFO} )
string(REPLACE " /GR" " " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} )
endif( MSVC )
if( CMAKE_COMPILER_IS_GNUCXX )
set( ALL_C_FLAGS "${ALL_C_FLAGS} -ffast-math -pipe" )
if( GPROF )
set( ALL_C_FLAGS "${ALL_C_FLAGS} -pg -g" )
else( GPROF )
set( REL_C_FLAGS "${REL_C_FLAGS} -fomit-frame-pointer" )
endif( GPROF )
if( PROFILE EQUAL 1 )
message( STATUS "Generating profile coverage information" )
set( ALL_C_FLAGS "${ALL_C_FLAGS} -fprofile-generate" )
set( PROF_LIB "gcov" )
elseif( PROFILE EQUAL 2 )
message( STATUS "Using profile coverage information" )
set( ALL_C_FLAGS "${ALL_C_FLAGS} -fprofile-use" )
endif( PROFILE EQUAL 1 )
endif( CMAKE_COMPILER_IS_GNUCXX )
#if( WIN32 AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
# set( ALL_C_FLAGS "${ALL_C_FLAGS} -Wno-deprecated-declarations -Wno-format" )
#endif( WIN32 AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
if( ZLIB_FOUND )
message( STATUS "Using system zlib" )
else( ZLIB_FOUND )
message( STATUS "Using internal zlib" )
add_subdirectory( zlib )
set( ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/zlib )
set( ZLIB_LIBRARIES z )
set( ZLIB_LIBRARY z )
endif( ZLIB_FOUND )
if( BACKPATCH )
add_definitions( -DBACKPATCH )
endif( BACKPATCH )
CHECK_FUNCTION_EXISTS( stricmp STRICMP_EXISTS )
if( NOT STRICMP_EXISTS )
add_definitions( -Dstricmp=strcasecmp )
endif( NOT STRICMP_EXISTS )
CHECK_FUNCTION_EXISTS( strnicmp STRNICMP_EXISTS )
if( NOT STRNICMP_EXISTS )
add_definitions( -Dstrnicmp=strncasecmp )
endif( NOT STRNICMP_EXISTS )
set( ZDRAY_LIBS "${ZLIB_LIBRARIES}" )
set( SOURCES
src/commandline/main.cpp
src/commandline/getopt.c
src/commandline/getopt1.c
src/blockmapbuilder/blockmapbuilder.cpp
src/level/level.cpp
src/level/level_udmf.cpp
src/parse/sc_man.cpp
src/wad/wad.cpp
src/nodebuilder/nodebuild.cpp
src/nodebuilder/nodebuild_events.cpp
src/nodebuilder/nodebuild_extract.cpp
src/nodebuilder/nodebuild_gl.cpp
src/nodebuilder/nodebuild_utility.cpp
src/nodebuilder/nodebuild_classify_nosse2.cpp
)
if( WIN32 )
set( SOURCES "${SOURCES}" src/viewer/view.cpp )
else( WIN32 )
add_definitions( -DNO_MAP_VIEWER )
endif( WIN32 )
set( HEADERS
src/commandline/getopt.h
src/blockmapbuilder/blockmapbuilder.h
src/nodebuilder/nodebuild.h
src/level/doomdata.h
src/level/level.h
src/level/workdata.h
src/parse/sc_man.h
src/wad/wad.h
src/platform/windows/resource.h
src/framework/tarray.h
src/framework/templates.h
src/framework/zdray.h
src/framework/xs_Float.h )
if( SSE_MATTERS )
if( FULL_SSE2 )
message( STATUS "Using SSE2 math everywhere." )
# Building everything with SSE2 is much like disabling it, in that we
# need not check for its existance while running.
set( ALL_C_FLAGS "${ALL_C_FLAGS} -DDISABLE_SSE ${SSE2_ENABLE}" )
else( FULL_SSE2 )
if( SSE )
message( STATUS "Using SSE math for ClassifyLine only." )
set( SOURCES ${SOURCES} src/nodebuilder/nodebuild_classify_sse1.cpp src/nodebuilder/nodebuild_classify_sse2.cpp )
set_source_files_properties( src/nodebuilder/nodebuild_classify_sse1.cpp PROPERTIES COMPILE_FLAGS "${SSE1_ENABLE}" )
set_source_files_properties( src/nodebuilder/nodebuild_classify_sse2.cpp PROPERTIES COMPILE_FLAGS "${SSE2_ENABLE}" )
else( SSE )
message( STATUS "SSE math is completely disabled." )
set( ALL_C_FLAGS "${ALL_C_FLAGS} -DDISABLE_SSE" )
endif( SSE )
endif( FULL_SSE2 )
else( SSE_MATTERS )
set( ALL_C_FLAGS "${ALL_C_FLAGS} -DDISABLE_SSE" )
endif( SSE_MATTERS )
if( WIN32 )
set( ZDRAY_LIBS ${ZDRAY_LIBS} user32 gdi32 )
if( CMAKE_COMPILER_IS_GNUCXX )
# CMake is not set up to compile and link rc files with GCC. :(
add_custom_command( OUTPUT zdray-rc.o
COMMAND windres -o zdray-rc.o -i ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/windows/resource.rc
DEPENDS resource.rc )
set( SOURCES ${SOURCES} zdray-rc.o )
else( CMAKE_COMPILER_IS_GNUCXX )
set( SOURCES ${SOURCES} src/platform/windows/resource.rc )
endif( CMAKE_COMPILER_IS_GNUCXX )
endif( WIN32 )
set( CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${REL_LINKER_FLAGS}" )
set( CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL} ${REL_LINKER_FLAGS}" )
set( CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} ${REL_LINKER_FLAGS}" )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ALL_C_FLAGS}" )
set( CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${REL_C_FLAGS}" )
set( CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} ${REL_C_FLAGS}" )
set( CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} ${REL_C_FLAGS}" )
set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${DEB_C_FLAGS} -D_DEBUG" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ALL_C_FLAGS}" )
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${REL_C_FLAGS}" )
set( CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} ${REL_C_FLAGS}" )
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${REL_C_FLAGS}" )
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEB_C_FLAGS} -D_DEBUG" )
add_executable( zdray ${SOURCES} ${HEADERS} )
target_link_libraries( zdray ${ZDRAY_LIBS} ${PROF_LIB} )
include_directories( src "${ZLIB_INCLUDE_DIR}" )
source_group("Sources" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/src/.+")
source_group("Sources\\BlockmapBuilder" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/src/blockmapbuilder/.+")
source_group("Sources\\Commandline" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/src/commandline/.+")
source_group("Sources\\Framework" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/src/framework/.+")
source_group("Sources\\Level" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/src/level/.+")
source_group("Sources\\NodeBuilder" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/src/nodebuilder/.+")
source_group("Sources\\Parse" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/src/parse/.+")
source_group("Sources\\Platform" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/src/platform/.+")
source_group("Sources\\Platform\\Windows" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/src/platform/windows/.+")
source_group("Sources\\Viewer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/src/viewer/.+")
source_group("Sources\\Wad" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/src/wad/.+")

340
COPYING Normal file
View File

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

View File

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

View File

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

1064
src/commandline/getopt.c Normal file

File diff suppressed because it is too large Load Diff

131
src/commandline/getopt.h Normal file
View File

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

189
src/commandline/getopt1.c Normal file
View File

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

713
src/commandline/main.cpp Normal file
View File

@ -0,0 +1,713 @@
/*
The main glue for ZDRay.
Copyright (C) 2002-2006 Randy Heit
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
// HEADER FILES ------------------------------------------------------------
#ifdef _WIN32
// Need windows.h for QueryPerformanceCounter
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define HAVE_TIMING 1
#define START_COUNTER(s,e,f) \
LARGE_INTEGER s, e, f; QueryPerformanceCounter (&s);
#define END_COUNTER(s,e,f,l) \
QueryPerformanceCounter (&e); QueryPerformanceFrequency (&f); \
if (!NoTiming) printf (l, double(e.QuadPart - s.QuadPart) / double(f.QuadPart));
#else
#include <time.h>
#define HAVE_TIMING 1
#define START_COUNTER(s,e,f) \
clock_t s, e; s = clock();
#define END_COUNTER(s,e,f,l) \
e = clock(); \
if (!NoTiming) printf (l, double(e - s) / CLOCKS_PER_SEC);
// Need these to check if input/output are the same file
#include <sys/types.h>
#include <sys/stat.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "framework/zdray.h"
#include "wad/wad.h"
#include "level/level.h"
#include "commandline/getopt.h"
// MACROS ------------------------------------------------------------------
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
// TYPES -------------------------------------------------------------------
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
static void ParseArgs (int argc, char **argv);
static void ShowUsage ();
static void ShowVersion ();
static bool CheckInOutNames ();
#ifndef DISABLE_SSE
static void CheckSSE ();
#endif
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
extern "C" int optind;
extern "C" char *optarg;
// PUBLIC DATA DEFINITIONS -------------------------------------------------
const char *Map = NULL;
const char *InName;
const char *OutName = "tmp.wad";
bool BuildNodes = true;
bool BuildGLNodes = false;
bool ConformNodes = false;
bool NoPrune = false;
EBlockmapMode BlockmapMode = EBM_Rebuild;
ERejectMode RejectMode = ERM_DontTouch;
bool WriteComments = false;
int MaxSegs = 64;
int SplitCost = 8;
int AAPreference = 16;
bool CheckPolyobjs = true;
bool ShowMap = false;
bool ShowWarnings = false;
bool NoTiming = false;
bool CompressNodes = false;
bool CompressGLNodes = false;
bool ForceCompression = false;
bool GLOnly = false;
bool V5GLNodes = false;
bool HaveSSE1, HaveSSE2;
int SSELevel;
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static option long_opts[] =
{
{"help", no_argument, 0, 1000},
{"version", no_argument, 0, 'V'},
{"view", no_argument, 0, 'v'},
{"warn", no_argument, 0, 'w'},
{"map", required_argument, 0, 'm'},
{"output", required_argument, 0, 'o'},
{"output-file", required_argument, 0, 'o'},
{"file", required_argument, 0, 'f'},
{"no-nodes", no_argument, 0, 'N'},
{"gl", no_argument, 0, 'g'},
{"gl-matching", no_argument, 0, 'G'},
{"empty-blockmap", no_argument, 0, 'b'},
{"empty-reject", no_argument, 0, 'r'},
{"zero-reject", no_argument, 0, 'R'},
{"full-reject", no_argument, 0, 'e'},
{"no-reject", no_argument, 0, 'E'},
{"partition", required_argument, 0, 'p'},
{"split-cost", required_argument, 0, 's'},
{"diagonal-cost", required_argument, 0, 'd'},
{"no-polyobjs", no_argument, 0, 'P'},
{"no-prune", no_argument, 0, 'q'},
{"no-timing", no_argument, 0, 't'},
{"compress", no_argument, 0, 'z'},
{"compress-normal", no_argument, 0, 'Z'},
{"extended", no_argument, 0, 'X'},
{"gl-only", no_argument, 0, 'x'},
{"gl-v5", no_argument, 0, '5'},
{"no-sse", no_argument, 0, 1002},
{"no-sse2", no_argument, 0, 1003},
{"comments", no_argument, 0, 'c'},
{0,0,0,0}
};
static const char short_opts[] = "wVgGvbNrReEm:o:f:p:s:d:PqtzZXx5c";
// CODE --------------------------------------------------------------------
int main (int argc, char **argv)
{
bool fixSame = false;
#ifdef DISABLE_SSE
HaveSSE1 = HaveSSE2 = false;
#else
HaveSSE1 = HaveSSE2 = true;
#endif
ParseArgs (argc, argv);
if (InName == NULL)
{
if (optind >= argc || optind < argc-1)
{ // Source file is unspecified or followed by junk
ShowUsage ();
return 0;
}
InName = argv[optind];
}
#ifndef DISABLE_SSE
CheckSSE ();
#endif
try
{
START_COUNTER(t1a, t1b, t1c)
if (CheckInOutNames ())
{
// When the input and output files are the same, output will go to
// a temporary file. After everything is done, the input file is
// deleted and the output file is renamed to match the input file.
char *out = new char[strlen(OutName)+3], *dot;
if (out == NULL)
{
throw std::runtime_error("Could not create temporary file name.");
}
strcpy (out, OutName);
dot = strrchr (out, '.');
if (dot && (dot[1] == 'w' || dot[1] == 'W')
&& (dot[2] == 'a' || dot[2] == 'A')
&& (dot[3] == 'd' || dot[3] == 'D')
&& dot[4] == 0)
{
// *.wad becomes *.daw
dot[1] = 'd';
dot[3] = 'w';
}
else
{
// * becomes *.x
strcat (out, ".x");
}
OutName = out;
fixSame = true;
}
{
FWadReader inwad (InName);
FWadWriter outwad (OutName, inwad.IsIWAD());
int lump = 0;
int max = inwad.NumLumps ();
while (lump < max)
{
if (inwad.IsMap (lump) &&
(!Map || stricmp (inwad.LumpName (lump), Map) == 0))
{
START_COUNTER(t2a, t2b, t2c)
FProcessor builder (inwad, lump);
builder.Write (outwad);
END_COUNTER(t2a, t2b, t2c, " %.3f seconds.\n")
lump = inwad.LumpAfterMap (lump);
}
else if (inwad.IsGLNodes (lump))
{
// Ignore GL nodes from the input for any maps we process.
if (BuildNodes && (Map == NULL || stricmp (inwad.LumpName (lump)+3, Map) == 0))
{
lump = inwad.SkipGLNodes (lump);
}
else
{
outwad.CopyLump (inwad, lump);
++lump;
}
}
else
{
//printf ("copy %s\n", inwad.LumpName (lump));
outwad.CopyLump (inwad, lump);
++lump;
}
}
outwad.Close ();
}
if (fixSame)
{
remove (InName);
if (0 != rename (OutName, InName))
{
printf ("The output file could not be renamed to %s.\nYou can find it as %s.\n",
InName, OutName);
}
}
END_COUNTER(t1a, t1b, t1c, "\nTotal time: %.3f seconds.\n")
}
catch (std::runtime_error msg)
{
printf ("%s\n", msg.what());
return 20;
}
catch (std::bad_alloc)
{
printf ("Out of memory\n");
return 20;
}
catch (std::exception msg)
{
printf ("%s\n", msg.what());
return 20;
}
#ifndef _DEBUG
catch (...)
{
printf ("Unhandled exception. ZDRay cannot continue.\n");
return 20;
}
#endif
return 0;
}
//==========================================================================
//
// ParseArgs
//
//==========================================================================
static void ParseArgs (int argc, char **argv)
{
int ch;
while ((ch = getopt_long (argc, argv, short_opts, long_opts, NULL)) != EOF)
{
switch (ch)
{
case 0:
break;
case 'v':
ShowMap = true;
break;
case 'w':
ShowWarnings = true;
break;
case 'm':
Map = optarg;
break;
case 'o':
OutName = optarg;
break;
case 'f':
InName = optarg;
break;
case 'N':
BuildNodes = false;
break;
case 'b':
BlockmapMode = EBM_Create0;
break;
case 'r':
RejectMode = ERM_Create0;
break;
case 'R':
RejectMode = ERM_CreateZeroes;
break;
case 'e':
RejectMode = ERM_Rebuild;
break;
case 'E':
RejectMode = ERM_DontTouch;
break;
case 'p':
MaxSegs = atoi (optarg);
if (MaxSegs < 3)
{ // Don't be too unreasonable
MaxSegs = 3;
}
break;
case 's':
SplitCost = atoi (optarg);
if (SplitCost < 1)
{ // 1 means to add no extra weight at all
SplitCost = 1;
}
break;
case 'd':
AAPreference = atoi (optarg);
if (AAPreference < 1)
{
AAPreference = 1;
}
break;
case 'P':
CheckPolyobjs = false;
break;
case 'g':
BuildGLNodes = true;
ConformNodes = false;
break;
case 'G':
BuildGLNodes = true;
ConformNodes = true;
break;
case 'X':
CompressNodes = true;
CompressGLNodes = true;
ForceCompression = false;
break;
case 'z':
CompressNodes = true;
CompressGLNodes = true;
ForceCompression = true;
break;
case 'Z':
CompressNodes = true;
CompressGLNodes = false;
ForceCompression = true;
break;
case 'x':
GLOnly = true;
BuildGLNodes = true;
ConformNodes = false;
break;
case '5':
V5GLNodes = true;
break;
case 'q':
NoPrune = true;
break;
case 't':
NoTiming = true;
break;
case 'c':
WriteComments = true;
break;
case 'V':
ShowVersion ();
exit (0);
break;
case 1002: // Disable SSE/SSE2 ClassifyLine routine
HaveSSE1 = false;
HaveSSE2 = false;
break;
case 1003: // Disable only SSE2 ClassifyLine routine
HaveSSE2 = false;
break;
case 1000:
ShowUsage ();
exit (0);
default:
printf ("Try `zdray --help' for more information.\n");
exit (0);
}
}
}
//==========================================================================
//
// ShowUsage
//
//==========================================================================
static void ShowUsage ()
{
printf (
"Usage: zdray [options] sourcefile.wad\n"
" -m, --map=MAP Only affect the specified map\n"
" -o, --output=FILE Write output to FILE instead of tmp.wad\n"
" -q, --no-prune Keep unused sidedefs and sectors\n"
" -N, --no-nodes Do not rebuild nodes\n"
" -g, --gl Build GL-friendly nodes\n"
" -G, --gl-matching Build GL-friendly nodes that match normal nodes\n"
" -x, --gl-only Only build GL-friendly nodes\n"
" -5, --gl-v5 Create v5 GL-friendly nodes (overriden by -z and -X)\n"
" -X, --extended Create extended nodes (including GL nodes, if built)\n"
" -z, --compress Compress the nodes (including GL nodes, if built)\n"
" -Z, --compress-normal Compress normal nodes but not GL nodes\n"
" -b, --empty-blockmap Create an empty blockmap\n"
" -r, --empty-reject Create an empty reject table\n"
" -R, --zero-reject Create a reject table of all zeroes\n"
//" -e, --full-reject Rebuild reject table (unsupported)\n"
" -E, --no-reject Leave reject table untouched\n"
" -p, --partition=NNN Maximum segs to consider at each node (default %d)\n"
" -s, --split-cost=NNN Cost for splitting segs (default %d)\n"
" -d, --diagonal-cost=NNN Cost for avoiding diagonal splitters (default %d)\n"
" -P, --no-polyobjs Do not check for polyobject subsector splits\n"
#ifdef _WIN32
" -v, --view View the nodes\n"
#endif
" -w, --warn Show warning messages\n"
#if HAVE_TIMING
" -t, --no-timing Suppress timing information\n"
#endif
" -V, --version Display version information\n"
" --help Display this usage information"
#ifndef _WIN32
"\n"
#endif
, MaxSegs /* Partition size */
, SplitCost
, AAPreference
);
}
//==========================================================================
//
// ShowVersion
//
//==========================================================================
static void ShowVersion ()
{
printf ("ZDRay " ZDRAY_VERSION " ("
#if defined(__GNUC__)
"GCC"
#if defined(__i386__)
"-x86"
#elif defined(__amd64__)
"-amd64"
#elif defined(__ppc__)
"-ppc"
#endif
#elif defined(_MSC_VER)
"VC"
#if defined(_M_IX86)
"-x86"
#if _M_IX86_FP > 1
"-SSE2"
#endif
#elif defined(_M_X64)
"-x64"
#endif
#endif
" : " __DATE__ ")\n");
}
//==========================================================================
//
// CheckInOutNames
//
// Returns true if InName and OutName refer to the same file. This needs
// to be implemented different under Windows than Unix because the inode
// information returned by stat is always 0, so it cannot be used to
// determine duplicate files.
//
//==========================================================================
static bool CheckInOutNames ()
{
#ifndef _WIN32
struct stat info;
dev_t outdev;
ino_t outinode;
if (0 != stat (OutName, &info))
{ // If out doesn't exist, it can't be duplicated
return false;
}
outdev = info.st_dev;
outinode = info.st_ino;
if (0 != stat (InName, &info))
{
return false;
}
return outinode == info.st_ino && outdev == info.st_dev;
#else
HANDLE inFile, outFile;
outFile = CreateFile (OutName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if (outFile == INVALID_HANDLE_VALUE)
{
return false;
}
inFile = CreateFile (InName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if (inFile == INVALID_HANDLE_VALUE)
{
CloseHandle (outFile);
return false;
}
BY_HANDLE_FILE_INFORMATION inInfo, outInfo;
bool same = false;
if (GetFileInformationByHandle (inFile, &inInfo) &&
GetFileInformationByHandle (outFile, &outInfo))
{
same = inInfo.dwVolumeSerialNumber == outInfo.dwVolumeSerialNumber &&
inInfo.nFileIndexLow == outInfo.nFileIndexLow &&
inInfo.nFileIndexHigh == outInfo.nFileIndexHigh;
}
CloseHandle (inFile);
CloseHandle (outFile);
return same;
#endif
}
//==========================================================================
//
// CheckSSE
//
// Checks if the processor supports SSE or SSE2.
//
//==========================================================================
#ifndef DISABLE_SSE
static void CheckSSE ()
{
#ifdef __SSE2__
// If we compiled with SSE2 support enabled for everything, then
// obviously it's available, or the program won't get very far.
return;
#endif
if (!HaveSSE2 && !HaveSSE1)
{
return;
}
bool forcenosse1 = !HaveSSE1;
bool forcenosse2 = !HaveSSE2;
HaveSSE1 = false;
HaveSSE2 = false;
#if defined(_MSC_VER) && !defined(__clang__)
#ifdef _M_X64
// Processors implementing AMD64 are required to support SSE2.
return;
#else
__asm
{
pushfd // save EFLAGS
pop eax // store EFLAGS in EAX
mov edx,eax // save in EDX for later testing
xor eax,0x00200000 // toggle bit 21
push eax // put to stack
popfd // save changed EAX to EFLAGS
pushfd // push EFLAGS to TOS
pop eax // store EFLAGS in EAX
cmp eax,edx // see if bit 21 has changed
jz noid // if no change, then no CPUID
// Check the feature flag for SSE/SSE2
mov eax,1
cpuid
test edx,(1<<25) // Check for SSE
setnz HaveSSE1
test edx,(1<<26) // Check for SSE2
setnz HaveSSE2
noid:
}
#endif
#elif defined(__GNUC__) || defined(__clang__)
// Same as above, but for GCC
asm volatile
("pushfl\n\t"
"popl %%eax\n\t"
"movl %%eax,%%edx\n\t"
"xorl $0x200000,%%eax\n\t"
"pushl %%eax\n\t"
"popfl\n\t"
"pushfl\n\t"
"popl %%eax\n\t"
"cmp %%edx,%%eax\n\t"
"jz noid\n\t"
"mov $1,%%eax\n\t"
"cpuid\n\t"
"test $(1<<25),%%edx\n\t"
"setneb %0\n"
"test $(1<<26),%%edx\n\t"
"setneb %1\n"
"noid:"
:"=m" (HaveSSE1),"=m" (HaveSSE2)::"eax","ebx","ecx","edx");
#endif
if (forcenosse1)
{
HaveSSE1 = false;
}
if (forcenosse2)
{
HaveSSE2 = false;
}
}
#endif
//==========================================================================
//
// PointToAngle
//
//==========================================================================
angle_t PointToAngle (fixed_t x, fixed_t y)
{
double ang = atan2 (double(y), double(x));
const double rad2bam = double(1<<30) / M_PI;
double dbam = ang * rad2bam;
// Convert to signed first since negative double to unsigned is undefined.
return angle_t(int(dbam)) << 1;
}
//==========================================================================
//
// Warn
//
//==========================================================================
void Warn (const char *format, ...)
{
va_list marker;
if (!ShowWarnings)
{
return;
}
va_start (marker, format);
vprintf (format, marker);
va_end (marker);
}

333
src/framework/tarray.h Normal file
View File

@ -0,0 +1,333 @@
/*
** tarray.h
** Templated, automatically resizing array
**
**---------------------------------------------------------------------------
** Copyright 1998-2007 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#pragma once
#include <stdlib.h>
#include <assert.h>
#ifndef __APPLE__
#include <malloc.h>
#endif
#include <new>
// TArray -------------------------------------------------------------------
// T is the type stored in the array.
// TT is the type returned by operator().
template <class T, class TT=T>
class TArray
{
public:
////////
// This is a dummy constructor that does nothing. The purpose of this
// is so you can create a global TArray in the data segment that gets
// used by code before startup without worrying about the constructor
// resetting it after it's already been used. You MUST NOT use it for
// heap- or stack-allocated TArrays.
enum ENoInit
{
NoInit
};
TArray (ENoInit dummy)
{
}
////////
TArray ()
{
Most = 0;
Count = 0;
Array = NULL;
}
TArray (int max)
{
Most = max;
Count = 0;
Array = (T *)malloc (sizeof(T)*max);
if (Array == NULL)
{
throw std::bad_alloc();
}
}
TArray (const TArray<T> &other)
{
DoCopy (other);
}
TArray<T> &operator= (const TArray<T> &other)
{
if (&other != this)
{
if (Array != NULL)
{
if (Count > 0)
{
DoDelete (0, Count-1);
}
free (Array);
}
DoCopy (other);
}
return *this;
}
~TArray ()
{
if (Array)
{
if (Count > 0)
{
DoDelete (0, Count-1);
}
free (Array);
Array = NULL;
Count = 0;
Most = 0;
}
}
// Return a reference to an element
T &operator[] (unsigned int index) const
{
return Array[index];
}
// Returns the value of an element
TT operator() (unsigned int index) const
{
return Array[index];
}
unsigned int Push (const T &item)
{
Grow (1);
::new((void*)&Array[Count]) T(item);
return Count++;
}
bool Pop (T &item)
{
if (Count > 0)
{
item = Array[--Count];
Array[Count].~T();
return true;
}
return false;
}
void Delete (unsigned int index)
{
if (index < Count)
{
Array[index].~T();
if (index < --Count)
{
memmove (&Array[index], &Array[index+1], sizeof(T)*(Count - index));
}
}
}
void Delete (unsigned int index, int deletecount)
{
if (index + deletecount > Count) deletecount = Count - index;
if (deletecount > 0)
{
for(int i = 0; i < deletecount; i++)
{
Array[index + i].~T();
}
Count -= deletecount;
if (index < Count)
{
memmove (&Array[index], &Array[index+deletecount], sizeof(T)*(Count - index));
}
}
}
// Inserts an item into the array, shifting elements as needed
void Insert (unsigned int index, const T &item)
{
if (index >= Count)
{
// Inserting somewhere past the end of the array, so we can
// just add it without moving things.
Resize (index + 1);
::new ((void *)&Array[index]) T(item);
}
else
{
// Inserting somewhere in the middle of the array,
// so make room for it
Resize (Count + 1);
// Now move items from the index and onward out of the way
memmove (&Array[index+1], &Array[index], sizeof(T)*(Count - index - 1));
// And put the new element in
::new ((void *)&Array[index]) T(item);
}
}
void ShrinkToFit ()
{
if (Most > Count)
{
Most = Count;
if (Most == 0)
{
if (Array != NULL)
{
free (Array);
Array = NULL;
}
}
else
{
DoResize ();
}
}
}
// Grow Array to be large enough to hold amount more entries without
// further growing.
void Grow (unsigned int amount)
{
if (Count + amount > Most)
{
const unsigned int choicea = Count + amount;
const unsigned int choiceb = Most = (Most >= 16) ? Most + Most / 2 : 16;
Most = (choicea > choiceb ? choicea : choiceb);
DoResize ();
}
}
// Resize Array so that it has exactly amount entries in use.
void Resize (unsigned int amount)
{
if (Count < amount)
{
// Adding new entries
Grow (amount - Count);
for (unsigned int i = Count; i < amount; ++i)
{
::new((void *)&Array[i]) T;
}
}
else if (Count != amount)
{
// Deleting old entries
DoDelete (amount, Count - 1);
}
Count = amount;
}
// Reserves amount entries at the end of the array, but does nothing
// with them.
unsigned int Reserve (unsigned int amount)
{
Grow (amount);
unsigned int place = Count;
Count += amount;
for (unsigned int i = place; i < Count; ++i)
{
::new((void *)&Array[i]) T;
}
return place;
}
unsigned int Size () const
{
return Count;
}
unsigned int Max () const
{
return Most;
}
void Clear ()
{
if (Count > 0)
{
DoDelete (0, Count-1);
Count = 0;
}
}
private:
T *Array;
unsigned int Most;
unsigned int Count;
void DoCopy (const TArray<T> &other)
{
Most = Count = other.Count;
if (Count != 0)
{
Array = (T *)malloc (sizeof(T)*Most);
if (Array == NULL)
{
throw std::bad_alloc();
}
for (unsigned int i = 0; i < Count; ++i)
{
::new(&Array[i]) T(other.Array[i]);
}
}
else
{
Array = NULL;
}
}
void DoResize ()
{
size_t allocsize = sizeof(T)*Most;
Array = (T *)realloc (Array, allocsize);
if (Array == NULL)
{
throw std::bad_alloc();
}
}
void DoDelete (unsigned int first, unsigned int last)
{
assert (last != ~0u);
for (unsigned int i = first; i <= last; ++i)
{
Array[i].~T();
}
}
};
// TDeletingArray -----------------------------------------------------------
// An array that deletes its elements when it gets deleted.
template<class T, class TT=T>
class TDeletingArray : public TArray<T, TT>
{
public:
~TDeletingArray<T, TT> ()
{
for (unsigned int i = 0; i < TArray<T,TT>::Size(); ++i)
{
if ((*this)[i] != NULL)
delete (*this)[i];
}
}
};

195
src/framework/templates.h Normal file
View File

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

218
src/framework/xs_Float.h Normal file
View File

@ -0,0 +1,218 @@
// ====================================================================================================================
// ====================================================================================================================
// xs_Float.h
//
// Source: "Know Your FPU: Fixing Floating Fast"
// http://www.stereopsis.com/sree/fpu2006.html
//
// xs_CRoundToInt: Round toward nearest, but ties round toward even (just like FISTP)
// xs_ToInt: Round toward zero, just like the C (int) cast
// xs_FloorToInt: Round down
// xs_CeilToInt: Round up
// xs_RoundToInt: Round toward nearest, but ties round up
// ====================================================================================================================
// ====================================================================================================================
#pragma once
// ====================================================================================================================
// Defines
// ====================================================================================================================
#ifndef _xs_DEFAULT_CONVERSION
#define _xs_DEFAULT_CONVERSION 0
#endif //_xs_DEFAULT_CONVERSION
#if __BIG_ENDIAN__
#define _xs_iexp_ 0
#define _xs_iman_ 1
#else
#define _xs_iexp_ 1 //intel is little endian
#define _xs_iman_ 0
#endif //BigEndian_
#ifdef __GNUC__
#define finline inline
#else
#define finline __forceinline
#endif
union _xs_doubleints
{
real64 val;
uint32 ival[2];
};
#if 0
#define _xs_doublecopysgn(a,b) ((int32*)&a)[_xs_iexp_]&=~(((int32*)&b)[_xs_iexp_]&0x80000000)
#define _xs_doubleisnegative(a) ((((int32*)&a)[_xs_iexp_])|0x80000000)
#endif
// ====================================================================================================================
// Constants
// ====================================================================================================================
const real64 _xs_doublemagic = real64 (6755399441055744.0); //2^52 * 1.5, uses limited precisicion to floor
const real64 _xs_doublemagicdelta = (1.5e-8); //almost .5f = .5f + 1e^(number of exp bit)
const real64 _xs_doublemagicroundeps = (.5f-_xs_doublemagicdelta); //almost .5f = .5f - 1e^(number of exp bit)
// ====================================================================================================================
// Prototypes
// ====================================================================================================================
static int32 xs_CRoundToInt (real64 val, real64 dmr = _xs_doublemagic);
static int32 xs_ToInt (real64 val, real64 dme = -_xs_doublemagicroundeps);
static int32 xs_FloorToInt (real64 val, real64 dme = _xs_doublemagicroundeps);
static int32 xs_CeilToInt (real64 val, real64 dme = _xs_doublemagicroundeps);
static int32 xs_RoundToInt (real64 val);
//int32 versions
finline static int32 xs_CRoundToInt (int32 val) {return val;}
finline static int32 xs_ToInt (int32 val) {return val;}
// ====================================================================================================================
// Fix Class
// ====================================================================================================================
template <int32 N> class xs_Fix
{
public:
typedef int32 Fix;
// ====================================================================================================================
// Basic Conversion from Numbers
// ====================================================================================================================
finline static Fix ToFix (int32 val) {return val<<N;}
finline static Fix ToFix (real64 val) {return xs_ConvertToFixed(val);}
// ====================================================================================================================
// Basic Conversion to Numbers
// ====================================================================================================================
finline static real64 ToReal (Fix f) {return real64(f)/real64(1<<N);}
finline static int32 ToInt (Fix f) {return f>>N;}
protected:
// ====================================================================================================================
// Helper function - mainly to preserve _xs_DEFAULT_CONVERSION
// ====================================================================================================================
finline static int32 xs_ConvertToFixed (real64 val)
{
#if _xs_DEFAULT_CONVERSION==0
return xs_CRoundToInt(val, _xs_doublemagic/(1<<N));
#else
return (long)((val)*(1<<N));
#endif
}
};
// ====================================================================================================================
// ====================================================================================================================
// Inline implementation
// ====================================================================================================================
// ====================================================================================================================
finline static int32 xs_CRoundToInt(real64 val, real64 dmr)
{
#if _xs_DEFAULT_CONVERSION==0
_xs_doubleints uval;
uval.val = val + dmr;
return uval.ival[_xs_iman_];
#else
return int32(floor(val+.5));
#endif
}
// ====================================================================================================================
finline static int32 xs_ToInt(real64 val, real64 dme)
{
/* unused - something else I tried...
_xs_doublecopysgn(dme,val);
return xs_CRoundToInt(val+dme);
return 0;
*/
#if _MSC_VER >= 1400
// VC++ 2005's standard cast is a little bit faster than this
// magic number code. (Which is pretty amazing!) SSE has the
// fastest C-style float->int conversion, but unfortunately,
// checking for SSE support every time you need to do a
// conversion completely negates its performance advantage.
return int32(val);
#else
#if _xs_DEFAULT_CONVERSION==0
return (val<0) ? xs_CRoundToInt(val-dme) :
xs_CRoundToInt(val+dme);
#else
return int32(val);
#endif
#endif
}
// ====================================================================================================================
finline static int32 xs_FloorToInt(real64 val, real64 dme)
{
#if _xs_DEFAULT_CONVERSION==0
return xs_CRoundToInt (val - dme);
#else
return floor(val);
#endif
}
// ====================================================================================================================
finline static int32 xs_CeilToInt(real64 val, real64 dme)
{
#if _xs_DEFAULT_CONVERSION==0
return xs_CRoundToInt (val + dme);
#else
return ceil(val);
#endif
}
// ====================================================================================================================
finline static int32 xs_RoundToInt(real64 val)
{
#if _xs_DEFAULT_CONVERSION==0
// Yes, it is important that two fadds be generated, so you cannot override the dmr
// passed to xs_CRoundToInt with _xs_doublemagic + _xs_doublemagicdelta. If you do,
// you'll end up with Banker's Rounding again.
return xs_CRoundToInt (val + _xs_doublemagicdelta);
#else
return floor(val+.5);
#endif
}
// ====================================================================================================================
// ====================================================================================================================
// Unsigned variants
// ====================================================================================================================
// ====================================================================================================================
finline static uint32 xs_CRoundToUInt(real64 val)
{
return (uint32)xs_CRoundToInt(val);
}
finline static uint32 xs_FloorToUInt(real64 val)
{
return (uint32)xs_FloorToInt(val);
}
finline static uint32 xs_CeilToUInt(real64 val)
{
return (uint32)xs_CeilToUInt(val);
}
finline static uint32 xs_RoundToUInt(real64 val)
{
return (uint32)xs_RoundToInt(val);
}

269
src/framework/zdray.h Normal file
View File

@ -0,0 +1,269 @@
#pragma once
#include <limits.h>
#include <exception>
#include <stdexcept>
#include <stdint.h>
#define ZDRAY_VERSION "1.0"
enum EBlockmapMode
{
EBM_Rebuild,
EBM_Create0
};
enum ERejectMode
{
ERM_DontTouch,
ERM_CreateZeroes,
ERM_Create0,
ERM_Rebuild
};
extern const char *Map;
extern const char *InName;
extern const char *OutName;
extern bool BuildNodes, BuildGLNodes, ConformNodes, GLOnly, WriteComments;
extern bool NoPrune;
extern EBlockmapMode BlockmapMode;
extern ERejectMode RejectMode;
extern int MaxSegs;
extern int SplitCost;
extern int AAPreference;
extern bool CheckPolyobjs;
extern bool ShowMap;
extern bool CompressNodes, CompressGLNodes, ForceCompression, V5GLNodes;
extern bool HaveSSE1, HaveSSE2;
extern int SSELevel;
#define FIXED_MAX INT_MAX
#define FIXED_MIN INT_MIN
#define FRACBITS 16
typedef int fixed_t;
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef signed short SWORD;
#ifdef _WIN32
typedef unsigned long DWORD;
#else
typedef uint32_t DWORD;
#endif
typedef uint32_t angle_t;
angle_t PointToAngle (fixed_t x, fixed_t y);
static const WORD NO_MAP_INDEX = 0xffff;
static const DWORD NO_INDEX = 0xffffffff;
static const angle_t ANGLE_MAX = 0xffffffff;
static const DWORD DWORD_MAX = 0xffffffff;
static const angle_t ANGLE_180 = (1u<<31);
static const angle_t ANGLE_EPSILON = 5000;
void Warn (const char *format, ...);
#if defined(_MSC_VER) && !defined(__clang__) && defined(_M_IX86)
#pragma warning (disable: 4035)
inline fixed_t Scale (fixed_t a, fixed_t b, fixed_t c)
{
__asm mov eax,a
__asm mov ecx,c
__asm imul b
__asm idiv ecx
}
inline fixed_t DivScale30 (fixed_t a, fixed_t b)
{
__asm mov edx,a
__asm sar edx,2
__asm mov eax,a
__asm shl eax,30
__asm idiv b
}
inline fixed_t MulScale30 (fixed_t a, fixed_t b)
{
__asm mov eax,a
__asm imul b
__asm shrd eax,edx,30
}
inline fixed_t DMulScale32 (fixed_t a, fixed_t b, fixed_t c, fixed_t d)
{
__asm mov eax,a
__asm imul b
__asm mov ebx,eax
__asm mov eax,c
__asm mov esi,edx
__asm imul d
__asm add eax,ebx
__asm adc edx,esi
__asm mov eax,edx
}
#pragma warning (default: 4035)
#elif defined(__GNUC__) && defined(__i386__)
#ifdef __clang__
inline fixed_t Scale (fixed_t a, fixed_t b, fixed_t c)
{
fixed_t result, dummy;
asm volatile
("imull %3\n\t"
"idivl %4"
: "=a" (result),
"=&d" (dummy)
: "a" (a),
"r" (b),
"r" (c)
: "%cc"
);
return result;
}
inline fixed_t DivScale30 (fixed_t a, fixed_t b)
{
fixed_t result, dummy;
asm volatile
("idivl %4"
: "=a" (result),
"=d" (dummy)
: "a" (a<<30),
"d" (a>>2),
"r" (b) \
: "%cc");
return result;
}
#else
inline fixed_t Scale (fixed_t a, fixed_t b, fixed_t c)
{
fixed_t result, dummy;
asm volatile
("imull %3\n\t"
"idivl %4"
: "=a,a,a,a,a,a" (result),
"=&d,&d,&d,&d,d,d" (dummy)
: "a,a,a,a,a,a" (a),
"m,r,m,r,d,d" (b),
"r,r,m,m,r,m" (c)
: "%cc"
);
return result;
}
inline fixed_t DivScale30 (fixed_t a, fixed_t b)
{
fixed_t result, dummy;
asm volatile
("idivl %4"
: "=a,a" (result),
"=d,d" (dummy)
: "a,a" (a<<30),
"d,d" (a>>2),
"r,m" (b) \
: "%cc");
return result;
}
#endif
inline fixed_t MulScale30 (fixed_t a, fixed_t b)
{
return ((int64_t)a * b) >> 30;
}
inline fixed_t DMulScale30 (fixed_t a, fixed_t b, fixed_t c, fixed_t d)
{
return (((int64_t)a * b) + ((int64_t)c * d)) >> 30;
}
inline fixed_t DMulScale32 (fixed_t a, fixed_t b, fixed_t c, fixed_t d)
{
return (((int64_t)a * b) + ((int64_t)c * d)) >> 32;
}
#else
inline fixed_t Scale (fixed_t a, fixed_t b, fixed_t c)
{
return (fixed_t)(double(a)*double(b)/double(c));
}
inline fixed_t DivScale30 (fixed_t a, fixed_t b)
{
return (fixed_t)(double(a)/double(b)*double(1<<30));
}
inline fixed_t MulScale30 (fixed_t a, fixed_t b)
{
return (fixed_t)(double(a)*double(b)/double(1<<30));
}
inline fixed_t DMulScale30 (fixed_t a, fixed_t b, fixed_t c, fixed_t d)
{
return (fixed_t)((double(a)*double(b)+double(c)*double(d))/double(1<<30));
}
inline fixed_t DMulScale32 (fixed_t a, fixed_t b, fixed_t c, fixed_t d)
{
return (fixed_t)((double(a)*double(b)+double(c)*double(d))/4294967296.0);
}
#endif
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#define LittleShort(x) CFSwapInt16LittleToHost(x)
#define LittleLong(x) CFSwapInt32LittleToHost(x)
#else
#ifdef __BIG_ENDIAN__
// Swap 16bit, that is, MSB and LSB byte.
// No masking with 0xFF should be necessary.
inline short LittleShort (short x)
{
return (short)((((unsigned short)x)>>8) | (((unsigned short)x)<<8));
}
inline unsigned short LittleShort (unsigned short x)
{
return (unsigned short)((x>>8) | (x<<8));
}
// Swapping 32bit.
inline unsigned int LittleLong (unsigned int x)
{
return (unsigned int)(
(x>>24)
| ((x>>8) & 0xff00)
| ((x<<8) & 0xff0000)
| (x<<24));
}
inline int LittleLong (int x)
{
return (int)(
(((unsigned int)x)>>24)
| ((((unsigned int)x)>>8) & 0xff00)
| ((((unsigned int)x)<<8) & 0xff0000)
| (((unsigned int)x)<<24));
}
#else
#define LittleShort(x) (x)
#define LittleLong(x) (x)
#endif // __BIG_ENDIAN__
#endif // __APPLE__

268
src/level/doomdata.h Normal file
View File

@ -0,0 +1,268 @@
#pragma once
#include "framework/tarray.h"
enum
{
BOXTOP, BOXBOTTOM, BOXLEFT, BOXRIGHT
};
struct UDMFKey
{
const char *key;
const char *value;
};
struct MapVertex
{
short x, y;
};
struct WideVertex
{
fixed_t x, y;
int index;
};
struct MapSideDef
{
short textureoffset;
short rowoffset;
char toptexture[8];
char bottomtexture[8];
char midtexture[8];
WORD sector;
};
struct IntSideDef
{
// the first 5 values are only used for binary format maps
short textureoffset;
short rowoffset;
char toptexture[8];
char bottomtexture[8];
char midtexture[8];
int sector;
TArray<UDMFKey> props;
};
struct MapLineDef
{
WORD v1;
WORD v2;
short flags;
short special;
short tag;
WORD sidenum[2];
};
struct MapLineDef2
{
WORD v1;
WORD v2;
short flags;
unsigned char special;
unsigned char args[5];
WORD sidenum[2];
};
struct IntLineDef
{
DWORD v1;
DWORD v2;
int flags;
int special;
int args[5];
DWORD sidenum[2];
TArray<UDMFKey> props;
};
struct MapSector
{
short floorheight;
short ceilingheight;
char floorpic[8];
char ceilingpic[8];
short lightlevel;
short special;
short tag;
};
struct IntSector
{
// none of the sector properties are used by the node builder
// so there's no need to store them in their expanded form for
// UDMF. Just storing the UDMF keys and leaving the binary fields
// empty is enough
MapSector data;
TArray<UDMFKey> props;
};
struct MapSubsector
{
WORD numlines;
WORD firstline;
};
struct MapSubsectorEx
{
DWORD numlines;
DWORD firstline;
};
struct MapSeg
{
WORD v1;
WORD v2;
WORD angle;
WORD linedef;
short side;
short offset;
};
struct MapSegEx
{
DWORD v1;
DWORD v2;
WORD angle;
WORD linedef;
short side;
short offset;
};
struct MapSegGL
{
WORD v1;
WORD v2;
WORD linedef;
WORD side;
WORD partner;
};
struct MapSegGLEx
{
DWORD v1;
DWORD v2;
DWORD linedef;
WORD side;
DWORD partner;
};
#define NF_SUBSECTOR 0x8000
#define NFX_SUBSECTOR 0x80000000
struct MapNode
{
short x,y,dx,dy;
short bbox[2][4];
WORD children[2];
};
struct MapNodeExO
{
short x,y,dx,dy;
short bbox[2][4];
DWORD children[2];
};
struct MapNodeEx
{
int x,y,dx,dy;
short bbox[2][4];
DWORD children[2];
};
struct MapThing
{
short x;
short y;
short angle;
short type;
short flags;
};
struct MapThing2
{
unsigned short thingid;
short x;
short y;
short z;
short angle;
short type;
short flags;
char special;
char args[5];
};
struct IntThing
{
unsigned short thingid;
fixed_t x; // full precision coordinates for UDMF support
fixed_t y;
// everything else is not needed or has no extended form in UDMF
short z;
short angle;
short type;
short flags;
char special;
char args[5];
TArray<UDMFKey> props;
};
struct IntVertex
{
TArray<UDMFKey> props;
};
struct FLevel
{
FLevel ();
~FLevel ();
WideVertex *Vertices; int NumVertices;
TArray<IntVertex> VertexProps;
TArray<IntSideDef> Sides;
TArray<IntLineDef> Lines;
TArray<IntSector> Sectors;
TArray<IntThing> Things;
MapSubsectorEx *Subsectors; int NumSubsectors;
MapSegEx *Segs; int NumSegs;
MapNodeEx *Nodes; int NumNodes;
WORD *Blockmap; int BlockmapSize;
BYTE *Reject; int RejectSize;
MapSubsectorEx *GLSubsectors; int NumGLSubsectors;
MapSegGLEx *GLSegs; int NumGLSegs;
MapNodeEx *GLNodes; int NumGLNodes;
WideVertex *GLVertices; int NumGLVertices;
BYTE *GLPVS; int GLPVSSize;
int NumOrgVerts;
DWORD *OrgSectorMap; int NumOrgSectors;
fixed_t MinX, MinY, MaxX, MaxY;
TArray<UDMFKey> props;
void FindMapBounds ();
void RemoveExtraLines ();
void RemoveExtraSides ();
void RemoveExtraSectors ();
int NumSides() const { return Sides.Size(); }
int NumLines() const { return Lines.Size(); }
int NumSectors() const { return Sectors.Size(); }
int NumThings() const { return Things.Size(); }
};
const int BLOCKSIZE = 128;
const int BLOCKFRACSIZE = BLOCKSIZE<<FRACBITS;
const int BLOCKBITS = 7;
const int BLOCKFRACBITS = FRACBITS+7;

1762
src/level/level.cpp Normal file

File diff suppressed because it is too large Load Diff

126
src/level/level.h Normal file
View File

@ -0,0 +1,126 @@
#pragma once
#include "wad/wad.h"
#include "level/doomdata.h"
#include "level/workdata.h"
#include "framework/tarray.h"
#include "nodebuilder/nodebuild.h"
#include "blockmapbuilder/blockmapbuilder.h"
#include <zlib.h>
class ZLibOut
{
public:
ZLibOut (FWadWriter &out);
~ZLibOut ();
ZLibOut &operator << (BYTE);
ZLibOut &operator << (WORD);
ZLibOut &operator << (SWORD);
ZLibOut &operator << (DWORD);
ZLibOut &operator << (fixed_t);
void Write (BYTE *data, int len);
private:
enum { BUFFER_SIZE = 8192 };
z_stream Stream;
BYTE Buffer[BUFFER_SIZE];
FWadWriter &Out;
};
class FProcessor
{
public:
FProcessor (FWadReader &inwad, int lump);
void Write (FWadWriter &out);
private:
void LoadUDMF();
void LoadThings ();
void LoadLines ();
void LoadVertices ();
void LoadSides ();
void LoadSectors ();
void GetPolySpots ();
MapNodeEx *NodesToEx (const MapNode *nodes, int count);
MapSubsectorEx *SubsectorsToEx (const MapSubsector *ssec, int count);
MapSegGLEx *SegGLsToEx (const MapSegGL *segs, int count);
BYTE *FixReject (const BYTE *oldreject);
bool CheckForFracSplitters(const MapNodeEx *nodes, int count);
void WriteLines (FWadWriter &out);
void WriteVertices (FWadWriter &out, int count);
void WriteSectors (FWadWriter &out);
void WriteSides (FWadWriter &out);
void WriteSegs (FWadWriter &out);
void WriteSSectors (FWadWriter &out) const;
void WriteNodes (FWadWriter &out) const;
void WriteBlockmap (FWadWriter &out);
void WriteReject (FWadWriter &out);
void WriteGLVertices (FWadWriter &out, bool v5);
void WriteGLSegs (FWadWriter &out, bool v5);
void WriteGLSegs5 (FWadWriter &out);
void WriteGLSSect (FWadWriter &out, bool v5);
void WriteGLNodes (FWadWriter &out, bool v5);
void WriteBSPZ (FWadWriter &out, const char *label);
void WriteGLBSPZ (FWadWriter &out, const char *label);
void WriteVerticesZ (ZLibOut &out, const WideVertex *verts, int orgverts, int newverts);
void WriteSubsectorsZ (ZLibOut &out, const MapSubsectorEx *subs, int numsubs);
void WriteSegsZ (ZLibOut &out, const MapSegEx *segs, int numsegs);
void WriteGLSegsZ (ZLibOut &out, const MapSegGLEx *segs, int numsegs, int nodever);
void WriteNodesZ (ZLibOut &out, const MapNodeEx *nodes, int numnodes, int nodever);
void WriteBSPX (FWadWriter &out, const char *label);
void WriteGLBSPX (FWadWriter &out, const char *label);
void WriteVerticesX (FWadWriter &out, const WideVertex *verts, int orgverts, int newverts);
void WriteSubsectorsX (FWadWriter &out, const MapSubsectorEx *subs, int numsubs);
void WriteSegsX (FWadWriter &out, const MapSegEx *segs, int numsegs);
void WriteGLSegsX (FWadWriter &out, const MapSegGLEx *segs, int numsegs, int nodever);
void WriteNodesX (FWadWriter &out, const MapNodeEx *nodes, int numnodes, int nodever);
void WriteNodes2 (FWadWriter &out, const char *name, const MapNodeEx *zaNodes, int count) const;
void WriteSSectors2 (FWadWriter &out, const char *name, const MapSubsectorEx *zaSubs, int count) const;
void WriteNodes5 (FWadWriter &out, const char *name, const MapNodeEx *zaNodes, int count) const;
void WriteSSectors5 (FWadWriter &out, const char *name, const MapSubsectorEx *zaSubs, int count) const;
const char *ParseKey(const char *&value);
bool CheckKey(const char *&key, const char *&value);
void ParseThing(IntThing *th);
void ParseLinedef(IntLineDef *ld);
void ParseSidedef(IntSideDef *sd);
void ParseSector(IntSector *sec);
void ParseVertex(WideVertex *vt, IntVertex *vtp);
void ParseMapProperties();
void ParseTextMap(int lump);
void WriteProps(FWadWriter &out, TArray<UDMFKey> &props);
void WriteIntProp(FWadWriter &out, const char *key, int value);
void WriteThingUDMF(FWadWriter &out, IntThing *th, int num);
void WriteLinedefUDMF(FWadWriter &out, IntLineDef *ld, int num);
void WriteSidedefUDMF(FWadWriter &out, IntSideDef *sd, int num);
void WriteSectorUDMF(FWadWriter &out, IntSector *sec, int num);
void WriteVertexUDMF(FWadWriter &out, IntVertex *vt, int num);
void WriteTextMap(FWadWriter &out);
void WriteUDMF(FWadWriter &out);
FLevel Level;
TArray<FNodeBuilder::FPolyStart> PolyStarts;
TArray<FNodeBuilder::FPolyStart> PolyAnchors;
bool Extended;
bool isUDMF;
FWadReader &Wad;
int Lump;
};

606
src/level/level_udmf.cpp Normal file
View File

@ -0,0 +1,606 @@
/*
Reads and writes UDMF maps
Copyright (C) 2009 Christoph Oelckers
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <float.h>
#include "level/level.h"
#include "parse/sc_man.h"
typedef double real64;
typedef unsigned int uint32;
typedef signed int int32;
#include "framework/xs_Float.h"
class StringBuffer
{
const static size_t BLOCK_SIZE = 100000;
const static size_t BLOCK_ALIGN = sizeof(size_t);
TDeletingArray<char *> blocks;
size_t currentindex;
char *Alloc(size_t size)
{
if (currentindex + size >= BLOCK_SIZE)
{
// Block is full - get a new one!
char *newblock = new char[BLOCK_SIZE];
blocks.Push(newblock);
currentindex = 0;
}
size = (size + BLOCK_ALIGN-1) &~ (BLOCK_ALIGN-1);
char *p = blocks[blocks.Size()-1] + currentindex;
currentindex += size;
return p;
}
public:
StringBuffer()
{
currentindex = BLOCK_SIZE;
}
char * Copy(const char * p)
{
return p != NULL? strcpy(Alloc(strlen(p)+1) , p) : NULL;
}
};
StringBuffer stbuf;
//===========================================================================
//
// Parses a 'key = value;' line of the map
//
//===========================================================================
const char *FProcessor::ParseKey(const char *&value)
{
SC_MustGetString();
const char *key = stbuf.Copy(sc_String);
SC_MustGetStringName("=");
sc_Number = INT_MIN;
sc_Float = DBL_MIN;
if (!SC_CheckFloat())
{
SC_MustGetString();
}
value = stbuf.Copy(sc_String);
SC_MustGetStringName(";");
return key;
}
bool FProcessor::CheckKey(const char *&key, const char *&value)
{
SC_SavePos();
SC_MustGetString();
if (SC_CheckString("="))
{
SC_RestorePos();
key = ParseKey(value);
return true;
}
SC_RestorePos();
return false;
}
int CheckInt(const char *key)
{
if (sc_Number == INT_MIN)
{
SC_ScriptError("Integer value expected for key '%s'", key);
}
return sc_Number;
}
double CheckFloat(const char *key)
{
if (sc_Float == DBL_MIN)
{
SC_ScriptError("Floating point value expected for key '%s'", key);
}
return sc_Float;
}
fixed_t CheckFixed(const char *key)
{
double val = CheckFloat(key);
if (val < -32768 || val > 32767)
{
SC_ScriptError("Fixed point value is out of range for key '%s'\n\t%.2f should be within [-32768,32767]", key, val / 65536);
}
return xs_Fix<16>::ToFix(val);
}
//===========================================================================
//
// Parse a thing block
//
//===========================================================================
void FProcessor::ParseThing(IntThing *th)
{
SC_MustGetStringName("{");
while (!SC_CheckString("}"))
{
const char *value;
const char *key = ParseKey(value);
// The only properties we need from a thing are
// x, y, angle and type.
if (!stricmp(key, "x"))
{
th->x = CheckFixed(key);
}
else if (!stricmp(key, "y"))
{
th->y = CheckFixed(key);
}
if (!stricmp(key, "angle"))
{
th->angle = (short)CheckInt(key);
}
if (!stricmp(key, "type"))
{
th->type = (short)CheckInt(key);
}
// now store the key in its unprocessed form
UDMFKey k = {key, value};
th->props.Push(k);
}
}
//===========================================================================
//
// Parse a linedef block
//
//===========================================================================
void FProcessor::ParseLinedef(IntLineDef *ld)
{
SC_MustGetStringName("{");
ld->v1 = ld->v2 = ld->sidenum[0] = ld->sidenum[1] = NO_INDEX;
ld->special = 0;
while (!SC_CheckString("}"))
{
const char *value;
const char *key = ParseKey(value);
if (!stricmp(key, "v1"))
{
ld->v1 = CheckInt(key);
continue; // do not store in props
}
else if (!stricmp(key, "v2"))
{
ld->v2 = CheckInt(key);
continue; // do not store in props
}
else if (Extended && !stricmp(key, "special"))
{
ld->special = CheckInt(key);
}
else if (Extended && !stricmp(key, "arg0"))
{
ld->args[0] = CheckInt(key);
}
if (!stricmp(key, "sidefront"))
{
ld->sidenum[0] = CheckInt(key);
continue; // do not store in props
}
else if (!stricmp(key, "sideback"))
{
ld->sidenum[1] = CheckInt(key);
continue; // do not store in props
}
// now store the key in its unprocessed form
UDMFKey k = {key, value};
ld->props.Push(k);
}
}
//===========================================================================
//
// Parse a sidedef block
//
//===========================================================================
void FProcessor::ParseSidedef(IntSideDef *sd)
{
SC_MustGetStringName("{");
sd->sector = NO_INDEX;
while (!SC_CheckString("}"))
{
const char *value;
const char *key = ParseKey(value);
if (!stricmp(key, "sector"))
{
sd->sector = CheckInt(key);
continue; // do not store in props
}
// now store the key in its unprocessed form
UDMFKey k = {key, value};
sd->props.Push(k);
}
}
//===========================================================================
//
// Parse a sidedef block
//
//===========================================================================
void FProcessor::ParseSector(IntSector *sec)
{
SC_MustGetStringName("{");
while (!SC_CheckString("}"))
{
const char *value;
const char *key = ParseKey(value);
// No specific sector properties are ever used by the node builder
// so everything can go directly to the props array.
// now store the key in its unprocessed form
UDMFKey k = {key, value};
sec->props.Push(k);
}
}
//===========================================================================
//
// parse a vertex block
//
//===========================================================================
void FProcessor::ParseVertex(WideVertex *vt, IntVertex *vtp)
{
vt->x = vt->y = 0;
SC_MustGetStringName("{");
while (!SC_CheckString("}"))
{
const char *value;
const char *key = ParseKey(value);
if (!stricmp(key, "x"))
{
vt->x = CheckFixed(key);
}
else if (!stricmp(key, "y"))
{
vt->y = CheckFixed(key);
}
// now store the key in its unprocessed form
UDMFKey k = {key, value};
vtp->props.Push(k);
}
}
//===========================================================================
//
// parses global map properties
//
//===========================================================================
void FProcessor::ParseMapProperties()
{
const char *key, *value;
// all global keys must come before the first map element.
while (CheckKey(key, value))
{
if (!stricmp(key, "namespace"))
{
// all unknown namespaces are assumed to be standard.
Extended = !stricmp(value, "\"ZDoom\"") || !stricmp(value, "\"Hexen\"") || !stricmp(value, "\"Vavoom\"");
}
// now store the key in its unprocessed form
UDMFKey k = {key, value};
Level.props.Push(k);
}
}
//===========================================================================
//
// Main parsing function
//
//===========================================================================
void FProcessor::ParseTextMap(int lump)
{
char *buffer;
int buffersize;
TArray<WideVertex> Vertices;
ReadLump<char> (Wad, lump, buffer, buffersize);
SC_OpenMem("TEXTMAP", buffer, buffersize);
SC_SetCMode(true);
ParseMapProperties();
while (SC_GetString())
{
if (SC_Compare("thing"))
{
IntThing *th = &Level.Things[Level.Things.Reserve(1)];
ParseThing(th);
}
else if (SC_Compare("linedef"))
{
IntLineDef *ld = &Level.Lines[Level.Lines.Reserve(1)];
ParseLinedef(ld);
}
else if (SC_Compare("sidedef"))
{
IntSideDef *sd = &Level.Sides[Level.Sides.Reserve(1)];
ParseSidedef(sd);
}
else if (SC_Compare("sector"))
{
IntSector *sec = &Level.Sectors[Level.Sectors.Reserve(1)];
ParseSector(sec);
}
else if (SC_Compare("vertex"))
{
WideVertex *vt = &Vertices[Vertices.Reserve(1)];
IntVertex *vtp = &Level.VertexProps[Level.VertexProps.Reserve(1)];
vt->index = Vertices.Size();
ParseVertex(vt, vtp);
}
}
Level.Vertices = new WideVertex[Vertices.Size()];
Level.NumVertices = Vertices.Size();
memcpy(Level.Vertices, &Vertices[0], Vertices.Size() * sizeof(WideVertex));
SC_Close();
delete[] buffer;
}
//===========================================================================
//
// parse an UDMF map
//
//===========================================================================
void FProcessor::LoadUDMF()
{
ParseTextMap(Lump+1);
}
//===========================================================================
//
// writes a property list
//
//===========================================================================
void FProcessor::WriteProps(FWadWriter &out, TArray<UDMFKey> &props)
{
for(unsigned i=0; i< props.Size(); i++)
{
out.AddToLump(props[i].key, (int)strlen(props[i].key));
out.AddToLump(" = ", 3);
out.AddToLump(props[i].value, (int)strlen(props[i].value));
out.AddToLump(";\n", 2);
}
}
//===========================================================================
//
// writes an integer property
//
//===========================================================================
void FProcessor::WriteIntProp(FWadWriter &out, const char *key, int value)
{
char buffer[20];
out.AddToLump(key, (int)strlen(key));
out.AddToLump(" = ", 3);
sprintf(buffer, "%d;\n", value);
out.AddToLump(buffer, (int)strlen(buffer));
}
//===========================================================================
//
// writes a UDMF thing
//
//===========================================================================
void FProcessor::WriteThingUDMF(FWadWriter &out, IntThing *th, int num)
{
out.AddToLump("thing", 5);
if (WriteComments)
{
char buffer[32];
int len = sprintf(buffer, " // %d", num);
out.AddToLump(buffer, len);
}
out.AddToLump("\n{\n", 3);
WriteProps(out, th->props);
out.AddToLump("}\n\n", 3);
}
//===========================================================================
//
// writes a UDMF linedef
//
//===========================================================================
void FProcessor::WriteLinedefUDMF(FWadWriter &out, IntLineDef *ld, int num)
{
out.AddToLump("linedef", 7);
if (WriteComments)
{
char buffer[32];
int len = sprintf(buffer, " // %d", num);
out.AddToLump(buffer, len);
}
out.AddToLump("\n{\n", 3);
WriteIntProp(out, "v1", ld->v1);
WriteIntProp(out, "v2", ld->v2);
if (ld->sidenum[0] != NO_INDEX) WriteIntProp(out, "sidefront", ld->sidenum[0]);
if (ld->sidenum[1] != NO_INDEX) WriteIntProp(out, "sideback", ld->sidenum[1]);
WriteProps(out, ld->props);
out.AddToLump("}\n\n", 3);
}
//===========================================================================
//
// writes a UDMF sidedef
//
//===========================================================================
void FProcessor::WriteSidedefUDMF(FWadWriter &out, IntSideDef *sd, int num)
{
out.AddToLump("sidedef", 7);
if (WriteComments)
{
char buffer[32];
int len = sprintf(buffer, " // %d", num);
out.AddToLump(buffer, len);
}
out.AddToLump("\n{\n", 3);
WriteIntProp(out, "sector", sd->sector);
WriteProps(out, sd->props);
out.AddToLump("}\n\n", 3);
}
//===========================================================================
//
// writes a UDMF sector
//
//===========================================================================
void FProcessor::WriteSectorUDMF(FWadWriter &out, IntSector *sec, int num)
{
out.AddToLump("sector", 6);
if (WriteComments)
{
char buffer[32];
int len = sprintf(buffer, " // %d", num);
out.AddToLump(buffer, len);
}
out.AddToLump("\n{\n", 3);
WriteProps(out, sec->props);
out.AddToLump("}\n\n", 3);
}
//===========================================================================
//
// writes a UDMF vertex
//
//===========================================================================
void FProcessor::WriteVertexUDMF(FWadWriter &out, IntVertex *vt, int num)
{
out.AddToLump("vertex", 6);
if (WriteComments)
{
char buffer[32];
int len = sprintf(buffer, " // %d", num);
out.AddToLump(buffer, len);
}
out.AddToLump("\n{\n", 3);
WriteProps(out, vt->props);
out.AddToLump("}\n\n", 3);
}
//===========================================================================
//
// writes a UDMF text map
//
//===========================================================================
void FProcessor::WriteTextMap(FWadWriter &out)
{
out.StartWritingLump("TEXTMAP");
WriteProps(out, Level.props);
for(int i = 0; i < Level.NumThings(); i++)
{
WriteThingUDMF(out, &Level.Things[i], i);
}
for(int i = 0; i < Level.NumOrgVerts; i++)
{
WideVertex *vt = &Level.Vertices[i];
if (vt->index <= 0)
{
// not valid!
throw std::runtime_error("Invalid vertex data.");
}
WriteVertexUDMF(out, &Level.VertexProps[vt->index-1], i);
}
for(int i = 0; i < Level.NumLines(); i++)
{
WriteLinedefUDMF(out, &Level.Lines[i], i);
}
for(int i = 0; i < Level.NumSides(); i++)
{
WriteSidedefUDMF(out, &Level.Sides[i], i);
}
for(int i = 0; i < Level.NumSectors(); i++)
{
WriteSectorUDMF(out, &Level.Sectors[i], i);
}
}
//===========================================================================
//
// writes an UDMF map
//
//===========================================================================
void FProcessor::WriteUDMF(FWadWriter &out)
{
out.CopyLump (Wad, Lump);
WriteTextMap(out);
if (ForceCompression) WriteGLBSPZ (out, "ZNODES");
else WriteGLBSPX (out, "ZNODES");
// copy everything except existing nodes, blockmap and reject
for(int i=Lump+2; stricmp(Wad.LumpName(i), "ENDMAP") && i < Wad.NumLumps(); i++)
{
const char *lumpname = Wad.LumpName(i);
if (stricmp(lumpname, "ZNODES") &&
stricmp(lumpname, "BLOCKMAP") &&
stricmp(lumpname, "REJECT"))
{
out.CopyLump(Wad, i);
}
}
out.CreateLabel("ENDMAP");
}

22
src/level/workdata.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include "framework/zdray.h"
struct vertex_t
{
fixed_t x, y;
};
struct node_t
{
fixed_t x, y, dx, dy;
fixed_t bbox[2][4];
unsigned int intchildren[2];
};
struct subsector_t
{
DWORD numlines;
DWORD firstline;
};

File diff suppressed because it is too large Load Diff

322
src/nodebuilder/nodebuild.h Normal file
View File

@ -0,0 +1,322 @@
#pragma once
#include <math.h>
#include "level/doomdata.h"
#include "level/workdata.h"
#include "framework/tarray.h"
struct FEventInfo
{
int Vertex;
DWORD FrontSeg;
};
struct FEvent
{
FEvent *Parent, *Left, *Right;
double Distance;
FEventInfo Info;
};
class FEventTree
{
public:
FEventTree ();
~FEventTree ();
FEvent *GetMinimum ();
FEvent *GetSuccessor (FEvent *event) const { FEvent *node = Successor(event); return node == &Nil ? NULL : node; }
FEvent *GetPredecessor (FEvent *event) const { FEvent *node = Predecessor(event); return node == &Nil ? NULL : node; }
FEvent *GetNewNode ();
void Insert (FEvent *event);
FEvent *FindEvent (double distance) const;
void DeleteAll ();
void PrintTree () const { PrintTree (Root); }
private:
FEvent Nil;
FEvent *Root;
FEvent *Spare;
void DeletionTraverser (FEvent *event);
FEvent *Successor (FEvent *event) const;
FEvent *Predecessor (FEvent *event) const;
void PrintTree (const FEvent *event) const;
};
struct FSimpleVert
{
fixed_t x, y;
};
extern "C"
{
int ClassifyLine2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]);
#ifndef DISABLE_SSE
int ClassifyLineSSE1 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]);
int ClassifyLineSSE2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]);
#ifdef BACKPATCH
#ifdef __GNUC__
int ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]) __attribute__((noinline));
#else
int __declspec(noinline) ClassifyLineBackpatch (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2]);
#endif
#endif
#endif
}
class FNodeBuilder
{
struct FPrivSeg
{
int v1, v2;
DWORD sidedef;
int linedef;
int frontsector;
int backsector;
DWORD next;
DWORD nextforvert;
DWORD nextforvert2;
int loopnum; // loop number for split avoidance (0 means splitting is okay)
DWORD partner; // seg on back side
DWORD storedseg; // seg # in the GL_SEGS lump
angle_t angle;
fixed_t offset;
int planenum;
bool planefront;
FPrivSeg *hashnext;
};
struct FPrivVert : FSimpleVert
{
DWORD segs; // segs that use this vertex as v1
DWORD segs2; // segs that use this vertex as v2
int index;
int pad; // This structure must be 8-byte aligned.
bool operator== (const FPrivVert &other)
{
return x == other.x && y == other.y;
}
};
struct FSimpleLine
{
fixed_t x, y, dx, dy;
};
union USegPtr
{
DWORD SegNum;
FPrivSeg *SegPtr;
};
struct FSplitSharer
{
double Distance;
DWORD Seg;
bool Forward;
};
// Like a blockmap, but for vertices instead of lines
class FVertexMap
{
public:
FVertexMap (FNodeBuilder &builder, fixed_t minx, fixed_t miny, fixed_t maxx, fixed_t maxy);
~FVertexMap ();
int SelectVertexExact (FPrivVert &vert);
int SelectVertexClose (FPrivVert &vert);
private:
FNodeBuilder &MyBuilder;
TArray<int> *VertexGrid;
fixed_t MinX, MinY, MaxX, MaxY;
int BlocksWide, BlocksTall;
enum { BLOCK_SHIFT = 8 + FRACBITS };
enum { BLOCK_SIZE = 1 << BLOCK_SHIFT };
int InsertVertex (FPrivVert &vert);
inline int GetBlock (fixed_t x, fixed_t y)
{
assert (x >= MinX);
assert (y >= MinY);
assert (x <= MaxX);
assert (y <= MaxY);
return (unsigned(x - MinX) >> BLOCK_SHIFT) + (unsigned(y - MinY) >> BLOCK_SHIFT) * BlocksWide;
}
};
friend class FVertexMap;
public:
struct FPolyStart
{
int polynum;
fixed_t x, y;
};
FNodeBuilder (FLevel &level,
TArray<FPolyStart> &polyspots, TArray<FPolyStart> &anchors,
const char *name, bool makeGLnodes);
~FNodeBuilder ();
void GetVertices (WideVertex *&verts, int &count);
void GetNodes (MapNodeEx *&nodes, int &nodeCount,
MapSegEx *&segs, int &segCount,
MapSubsectorEx *&ssecs, int &subCount);
void GetGLNodes (MapNodeEx *&nodes, int &nodeCount,
MapSegGLEx *&segs, int &segCount,
MapSubsectorEx *&ssecs, int &subCount);
// < 0 : in front of line
// == 0 : on line
// > 0 : behind line
static inline int PointOnSide (int x, int y, int x1, int y1, int dx, int dy);
private:
FVertexMap *VertexMap;
TArray<node_t> Nodes;
TArray<subsector_t> Subsectors;
TArray<DWORD> SubsectorSets;
TArray<FPrivSeg> Segs;
TArray<FPrivVert> Vertices;
TArray<USegPtr> SegList;
TArray<BYTE> PlaneChecked;
TArray<FSimpleLine> Planes;
size_t InitialVertices; // Number of vertices in a map that are connected to linedefs
TArray<int> Touched; // Loops a splitter touches on a vertex
TArray<int> Colinear; // Loops with edges colinear to a splitter
FEventTree Events; // Vertices intersected by the current splitter
TArray<FSplitSharer> SplitSharers; // Segs collinear with the current splitter
DWORD HackSeg; // Seg to force to back of splitter
DWORD HackMate; // Seg to use in front of hack seg
FLevel &Level;
bool GLNodes;
// Progress meter stuff
int SegsStuffed;
const char *MapName;
void FindUsedVertices (WideVertex *vertices, int max);
void BuildTree ();
void MakeSegsFromSides ();
int CreateSeg (int linenum, int sidenum);
void GroupSegPlanes ();
void FindPolyContainers (TArray<FPolyStart> &spots, TArray<FPolyStart> &anchors);
bool GetPolyExtents (int polynum, fixed_t bbox[4]);
int MarkLoop (DWORD firstseg, int loopnum);
void AddSegToBBox (fixed_t bbox[4], const FPrivSeg *seg);
DWORD CreateNode (DWORD set, unsigned int count, fixed_t bbox[4]);
DWORD CreateSubsector (DWORD set, fixed_t bbox[4]);
void CreateSubsectorsForReal ();
bool CheckSubsector (DWORD set, node_t &node, DWORD &splitseg);
bool CheckSubsectorOverlappingSegs (DWORD set, node_t &node, DWORD &splitseg);
bool ShoveSegBehind (DWORD set, node_t &node, DWORD seg, DWORD mate);
int SelectSplitter (DWORD set, node_t &node, DWORD &splitseg, int step, bool nosplit);
void SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &outset0, DWORD &outset1, unsigned int &count0, unsigned int &count1);
DWORD SplitSeg (DWORD segnum, int splitvert, int v1InFront);
int Heuristic (node_t &node, DWORD set, bool honorNoSplit);
// Returns:
// 0 = seg is in front
// 1 = seg is in back
// -1 = seg cuts the node
inline int ClassifyLine (node_t &node, const FPrivVert *v1, const FPrivVert *v2, int sidev[2]);
void FixSplitSharers ();
double AddIntersection (const node_t &node, int vertex);
void AddMinisegs (const node_t &node, DWORD splitseg, DWORD &fset, DWORD &rset);
DWORD CheckLoopStart (fixed_t dx, fixed_t dy, int vertex1, int vertex2);
DWORD CheckLoopEnd (fixed_t dx, fixed_t dy, int vertex2);
void RemoveSegFromVert1 (DWORD segnum, int vertnum);
void RemoveSegFromVert2 (DWORD segnum, int vertnum);
DWORD AddMiniseg (int v1, int v2, DWORD partner, DWORD seg1, DWORD splitseg);
void SetNodeFromSeg (node_t &node, const FPrivSeg *pseg) const;
int RemoveMinisegs (MapNodeEx *nodes, TArray<MapSegEx> &segs, MapSubsectorEx *subs, int node, short bbox[4]);
int StripMinisegs (TArray<MapSegEx> &segs, int subsector, short bbox[4]);
void AddSegToShortBBox (short bbox[4], const FPrivSeg *seg);
int CloseSubsector (TArray<MapSegGLEx> &segs, int subsector);
DWORD PushGLSeg (TArray<MapSegGLEx> &segs, const FPrivSeg *seg);
void PushConnectingGLSeg (int subsector, TArray<MapSegGLEx> &segs, int v1, int v2);
int OutputDegenerateSubsector (TArray<MapSegGLEx> &segs, int subsector, bool bForward, double lastdot, FPrivSeg *&prev);
static int SortSegs (const void *a, const void *b);
double InterceptVector (const node_t &splitter, const FPrivSeg &seg);
void PrintSet (int l, DWORD set);
void DumpNodes(MapNodeEx *outNodes, int nodeCount);
};
// Points within this distance of a line will be considered on the line.
// Units are in fixed_ts.
const double SIDE_EPSILON = 6.5536;
// Vertices within this distance of each other will be considered as the same vertex.
#define VERTEX_EPSILON 6 // This is a fixed_t value
inline int FNodeBuilder::PointOnSide (int x, int y, int x1, int y1, int dx, int dy)
{
// For most cases, a simple dot product is enough.
double d_dx = double(dx);
double d_dy = double(dy);
double d_x = double(x);
double d_y = double(y);
double d_x1 = double(x1);
double d_y1 = double(y1);
double s_num = (d_y1-d_y)*d_dx - (d_x1-d_x)*d_dy;
if (fabs(s_num) < 17179869184.f) // 4<<32
{
// Either the point is very near the line, or the segment defining
// the line is very short: Do a more expensive test to determine
// just how far from the line the point is.
double l = d_dx*d_dx + d_dy*d_dy; // double l = sqrt(d_dx*d_dx+d_dy*d_dy);
double dist = s_num * s_num / l; // double dist = fabs(s_num)/l;
if (dist < SIDE_EPSILON*SIDE_EPSILON) // if (dist < SIDE_EPSILON)
{
return 0;
}
}
return s_num > 0.0 ? -1 : 1;
}
inline int FNodeBuilder::ClassifyLine (node_t &node, const FPrivVert *v1, const FPrivVert *v2, int sidev[2])
{
#ifdef DISABLE_SSE
return ClassifyLine2 (node, v1, v2, sidev);
#else
#if defined(__SSE2__) || defined(_M_X64)
// If compiling with SSE2 support everywhere, just use the SSE2 version.
return ClassifyLineSSE2 (node, v1, v2, sidev);
#elif defined(_MSC_VER) && _MSC_VER < 1300
// VC 6 does not support SSE optimizations.
return ClassifyLine2 (node, v1, v2, sidev);
#else
// Select the routine based on our flag.
#ifdef BACKPATCH
return ClassifyLineBackpatch (node, v1, v2, sidev);
#else
if (SSELevel == 2)
return ClassifyLineSSE2 (node, v1, v2, sidev);
else if (SSELevel == 1)
return ClassifyLineSSE1 (node, v1, v2, sidev);
else
return ClassifyLine2 (node, v1, v2, sidev);
#endif
#endif
#endif
}

View File

@ -0,0 +1,156 @@
/*
Determine what side of a splitter a seg lies on.
Copyright (C) 2002-2006 Randy Heit
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "framework/zdray.h"
#include "nodebuilder/nodebuild.h"
#define FAR_ENOUGH 17179869184.f // 4<<32
extern "C" int ClassifyLine2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2])
{
double d_x1 = double(node.x);
double d_y1 = double(node.y);
double d_dx = double(node.dx);
double d_dy = double(node.dy);
double d_xv1 = double(v1->x);
double d_xv2 = double(v2->x);
double d_yv1 = double(v1->y);
double d_yv2 = double(v2->y);
double s_num1 = (d_y1 - d_yv1) * d_dx - (d_x1 - d_xv1) * d_dy;
double s_num2 = (d_y1 - d_yv2) * d_dx - (d_x1 - d_xv2) * d_dy;
int nears = 0;
if (s_num1 <= -FAR_ENOUGH)
{
if (s_num2 <= -FAR_ENOUGH)
{
sidev[0] = sidev[1] = 1;
return 1;
}
if (s_num2 >= FAR_ENOUGH)
{
sidev[0] = 1;
sidev[1] = -1;
return -1;
}
nears = 1;
}
else if (s_num1 >= FAR_ENOUGH)
{
if (s_num2 >= FAR_ENOUGH)
{
sidev[0] = sidev[1] = -1;
return 0;
}
if (s_num2 <= -FAR_ENOUGH)
{
sidev[0] = -1;
sidev[1] = 1;
return -1;
}
nears = 1;
}
else
{
nears = 2 | int(fabs(s_num2) < FAR_ENOUGH);
}
if (nears)
{
double l = 1.f / (d_dx*d_dx + d_dy*d_dy);
if (nears & 2)
{
double dist = s_num1 * s_num1 * l;
if (dist < SIDE_EPSILON*SIDE_EPSILON)
{
sidev[0] = 0;
}
else
{
sidev[0] = s_num1 > 0.0 ? -1 : 1;
}
}
else
{
sidev[0] = s_num1 > 0.0 ? -1 : 1;
}
if (nears & 1)
{
double dist = s_num2 * s_num2 * l;
if (dist < SIDE_EPSILON*SIDE_EPSILON)
{
sidev[1] = 0;
}
else
{
sidev[1] = s_num2 > 0.0 ? -1 : 1;
}
}
else
{
sidev[1] = s_num2 > 0.0 ? -1 : 1;
}
}
else
{
sidev[0] = s_num1 > 0.0 ? -1 : 1;
sidev[1] = s_num2 > 0.0 ? -1 : 1;
}
if ((sidev[0] | sidev[1]) == 0)
{ // seg is coplanar with the splitter, so use its orientation to determine
// which child it ends up in. If it faces the same direction as the splitter,
// it goes in front. Otherwise, it goes in back.
if (node.dx != 0)
{
if ((node.dx > 0 && v2->x > v1->x) || (node.dx < 0 && v2->x < v1->x))
{
return 0;
}
else
{
return 1;
}
}
else
{
if ((node.dy > 0 && v2->y > v1->y) || (node.dy < 0 && v2->y < v1->y))
{
return 0;
}
else
{
return 1;
}
}
}
else if (sidev[0] <= 0 && sidev[1] <= 0)
{
return 0;
}
else if (sidev[0] >= 0 && sidev[1] >= 0)
{
return 1;
}
return -1;
}

View File

@ -0,0 +1,164 @@
/*
Determine what side of a splitter a seg lies on. (SSE2 version)
Copyright (C) 2002-2006 Randy Heit
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef DISABLE_SSE
#include "zdbsp.h"
#include "nodebuild.h"
#define FAR_ENOUGH 17179869184.f // 4<<32
// You may notice that this function is identical to ClassifyLine2.
// The reason it is SSE is because this file is explicitly compiled
// with SSE math enabled, but the other files are not.
extern "C" int ClassifyLineSSE1 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2])
{
double d_x1 = double(node.x);
double d_y1 = double(node.y);
double d_dx = double(node.dx);
double d_dy = double(node.dy);
double d_xv1 = double(v1->x);
double d_xv2 = double(v2->x);
double d_yv1 = double(v1->y);
double d_yv2 = double(v2->y);
double s_num1 = (d_y1 - d_yv1) * d_dx - (d_x1 - d_xv1) * d_dy;
double s_num2 = (d_y1 - d_yv2) * d_dx - (d_x1 - d_xv2) * d_dy;
int nears = 0;
if (s_num1 <= -FAR_ENOUGH)
{
if (s_num2 <= -FAR_ENOUGH)
{
sidev[0] = sidev[1] = 1;
return 1;
}
if (s_num2 >= FAR_ENOUGH)
{
sidev[0] = 1;
sidev[1] = -1;
return -1;
}
nears = 1;
}
else if (s_num1 >= FAR_ENOUGH)
{
if (s_num2 >= FAR_ENOUGH)
{
sidev[0] = sidev[1] = -1;
return 0;
}
if (s_num2 <= -FAR_ENOUGH)
{
sidev[0] = -1;
sidev[1] = 1;
return -1;
}
nears = 1;
}
else
{
nears = 2 | int(fabs(s_num2) < FAR_ENOUGH);
}
if (nears)
{
double l = 1.f / (d_dx*d_dx + d_dy*d_dy);
if (nears & 2)
{
double dist = s_num1 * s_num1 * l;
if (dist < SIDE_EPSILON*SIDE_EPSILON)
{
sidev[0] = 0;
}
else
{
sidev[0] = s_num1 > 0.0 ? -1 : 1;
}
}
else
{
sidev[0] = s_num1 > 0.0 ? -1 : 1;
}
if (nears & 1)
{
double dist = s_num2 * s_num2 * l;
if (dist < SIDE_EPSILON*SIDE_EPSILON)
{
sidev[1] = 0;
}
else
{
sidev[1] = s_num2 > 0.0 ? -1 : 1;
}
}
else
{
sidev[1] = s_num2 > 0.0 ? -1 : 1;
}
}
else
{
sidev[0] = s_num1 > 0.0 ? -1 : 1;
sidev[1] = s_num2 > 0.0 ? -1 : 1;
}
if ((sidev[0] | sidev[1]) == 0)
{ // seg is coplanar with the splitter, so use its orientation to determine
// which child it ends up in. If it faces the same direction as the splitter,
// it goes in front. Otherwise, it goes in back.
if (node.dx != 0)
{
if ((node.dx > 0 && v2->x > v1->x) || (node.dx < 0 && v2->x < v1->x))
{
return 0;
}
else
{
return 1;
}
}
else
{
if ((node.dy > 0 && v2->y > v1->y) || (node.dy < 0 && v2->y < v1->y))
{
return 0;
}
else
{
return 1;
}
}
}
else if (sidev[0] <= 0 && sidev[1] <= 0)
{
return 0;
}
else if (sidev[0] >= 0 && sidev[1] >= 0)
{
return 1;
}
return -1;
}
#endif

View File

@ -0,0 +1,164 @@
/*
Determine what side of a splitter a seg lies on. (SSE2 version)
Copyright (C) 2002-2006 Randy Heit
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef DISABLE_SSE
#include "zdbsp.h"
#include "nodebuild.h"
#define FAR_ENOUGH 17179869184.f // 4<<32
// You may notice that this function is identical to ClassifyLine2.
// The reason it is SSE2 is because this file is explicitly compiled
// with SSE2 math enabled, but the other files are not.
extern "C" int ClassifyLineSSE2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2])
{
double d_x1 = double(node.x);
double d_y1 = double(node.y);
double d_dx = double(node.dx);
double d_dy = double(node.dy);
double d_xv1 = double(v1->x);
double d_xv2 = double(v2->x);
double d_yv1 = double(v1->y);
double d_yv2 = double(v2->y);
double s_num1 = (d_y1 - d_yv1) * d_dx - (d_x1 - d_xv1) * d_dy;
double s_num2 = (d_y1 - d_yv2) * d_dx - (d_x1 - d_xv2) * d_dy;
int nears = 0;
if (s_num1 <= -FAR_ENOUGH)
{
if (s_num2 <= -FAR_ENOUGH)
{
sidev[0] = sidev[1] = 1;
return 1;
}
if (s_num2 >= FAR_ENOUGH)
{
sidev[0] = 1;
sidev[1] = -1;
return -1;
}
nears = 1;
}
else if (s_num1 >= FAR_ENOUGH)
{
if (s_num2 >= FAR_ENOUGH)
{
sidev[0] = sidev[1] = -1;
return 0;
}
if (s_num2 <= -FAR_ENOUGH)
{
sidev[0] = -1;
sidev[1] = 1;
return -1;
}
nears = 1;
}
else
{
nears = 2 | int(fabs(s_num2) < FAR_ENOUGH);
}
if (nears)
{
double l = 1.f / (d_dx*d_dx + d_dy*d_dy);
if (nears & 2)
{
double dist = s_num1 * s_num1 * l;
if (dist < SIDE_EPSILON*SIDE_EPSILON)
{
sidev[0] = 0;
}
else
{
sidev[0] = s_num1 > 0.0 ? -1 : 1;
}
}
else
{
sidev[0] = s_num1 > 0.0 ? -1 : 1;
}
if (nears & 1)
{
double dist = s_num2 * s_num2 * l;
if (dist < SIDE_EPSILON*SIDE_EPSILON)
{
sidev[1] = 0;
}
else
{
sidev[1] = s_num2 > 0.0 ? -1 : 1;
}
}
else
{
sidev[1] = s_num2 > 0.0 ? -1 : 1;
}
}
else
{
sidev[0] = s_num1 > 0.0 ? -1 : 1;
sidev[1] = s_num2 > 0.0 ? -1 : 1;
}
if ((sidev[0] | sidev[1]) == 0)
{ // seg is coplanar with the splitter, so use its orientation to determine
// which child it ends up in. If it faces the same direction as the splitter,
// it goes in front. Otherwise, it goes in back.
if (node.dx != 0)
{
if ((node.dx > 0 && v2->x > v1->x) || (node.dx < 0 && v2->x < v1->x))
{
return 0;
}
else
{
return 1;
}
}
else
{
if ((node.dy > 0 && v2->y > v1->y) || (node.dy < 0 && v2->y < v1->y))
{
return 0;
}
else
{
return 1;
}
}
}
else if (sidev[0] <= 0 && sidev[1] <= 0)
{
return 0;
}
else if (sidev[0] >= 0 && sidev[1] >= 0)
{
return 1;
}
return -1;
}
#endif

View File

@ -0,0 +1,187 @@
/*
Determine what side of a splitter a seg lies on. (SSE2 version)
Copyright (C) 2002-2006 Randy Heit
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef DISABLE_SSE
#include "zdbsp.h"
#include "nodebuild.h"
#include <emmintrin.h>
#define FAR_ENOUGH 17179869184.f // 4<<32
// You may notice that this function is identical to ClassifyLine2.
// The reason it is SSE2 is because this file is explicitly compiled
// with SSE2 math enabled, but the other files are not.
extern "C" int ClassifyLineSSE2 (node_t &node, const FSimpleVert *v1, const FSimpleVert *v2, int sidev[2])
{
__m128d xy, dxy, xyv1, xyv2;
// Why does this intrinsic go through an MMX register, when it can just go through memory?
// That would let it work with x64, too. (This only applies to VC++. GCC
// is smarter and can load directly from memory without touching the MMX registers.)
xy = _mm_cvtpi32_pd(*(__m64*)&node.x); // d_y1 d_x1
dxy = _mm_cvtpi32_pd(*(__m64*)&node.dx); // d_dy d_dx
xyv1 = _mm_cvtpi32_pd(*(__m64*)&v1->x); // d_yv1 d_xv1
xyv2 = _mm_cvtpi32_pd(*(__m64*)&v2->x); // d_yv2 d_xv2
__m128d num1, num2, dyx;
dyx = _mm_shuffle_pd(dxy, dxy, _MM_SHUFFLE2(0,1));
num1 = _mm_mul_pd(_mm_sub_pd(xy, xyv1), dyx);
num2 = _mm_mul_pd(_mm_sub_pd(xy, xyv2), dyx);
__m128d pnuma, pnumb, num;
pnuma = _mm_shuffle_pd(num1, num2, _MM_SHUFFLE2(1,1));
pnumb = _mm_shuffle_pd(num1, num2, _MM_SHUFFLE2(0,0));
num = _mm_sub_pd(pnuma, pnumb);
// s_num1 is at num[0]; s_num2 is at num[1]
__m128d neg_enough, pos_enough;
__m128d neg_check, pos_check;
neg_enough = _mm_set1_pd(-FAR_ENOUGH);
pos_enough = _mm_set1_pd( FAR_ENOUGH);
// Why do the comparison instructions return __m128d and not __m128i?
neg_check = _mm_cmple_pd(num, neg_enough);
pos_check = _mm_cmpge_pd(num, pos_enough);
union
{
struct
{
double n[2], p[2];
};
struct
{
int ni[4], pi[4];
};
} _;
_mm_storeu_pd(_.n, neg_check);
_mm_storeu_pd(_.p, pos_check);
int nears = 0;
if (_.ni[0])
{
if (_.ni[2])
{
sidev[0] = sidev[1] = 1;
return 1;
}
if (_.pi[2])
{
sidev[0] = 1;
sidev[1] = -1;
return -1;
}
nears = 1;
}
else if (_.pi[0])
{
if (_.pi[2])
{
sidev[0] = sidev[1] = -1;
return 0;
}
if (_.ni[2])
{
sidev[0] = -1;
sidev[1] = 1;
return -1;
}
nears = 1;
}
else
{
nears = 2 | (((_.ni[2] | _.pi[2]) & 1) ^ 1);
}
__m128d zero = _mm_setzero_pd();
__m128d posi = _mm_cmpgt_pd(num, zero);
_mm_storeu_pd(_.p, posi);
int sv1 = _.pi[0] ? _.pi[0] : 1;
int sv2 = _.pi[2] ? _.pi[2] : 1;
if (nears)
{
__m128d sqnum = _mm_mul_pd(num, num);
__m128d sqdyx = _mm_mul_pd(dyx, dyx);
__m128d sqdxy = _mm_mul_pd(dxy, dxy);
__m128d l = _mm_add_pd(sqdyx, sqdxy);
__m128d dist = _mm_div_pd(sqnum, l);
__m128d epsilon = _mm_set1_pd(SIDE_EPSILON);
__m128d close = _mm_cmplt_pd(dist, epsilon);
_mm_storeu_pd(_.n, close);
if (nears & _.ni[0] & 2)
{
sv1 = 0;
}
if (nears & _.ni[2] & 1)
{
sv2 = 0;
}
}
sidev[0] = sv1;
sidev[1] = sv2;
if ((sv1 | sv2) == 0)
{ // seg is coplanar with the splitter, so use its orientation to determine
// which child it ends up in. If it faces the same direction as the splitter,
// it goes in front. Otherwise, it goes in back.
if (node.dx != 0)
{
if ((node.dx > 0 && v2->x > v1->x) || (node.dx < 0 && v2->x < v1->x))
{
return 0;
}
else
{
return 1;
}
}
else
{
if ((node.dy > 0 && v2->y > v1->y) || (node.dy < 0 && v2->y < v1->y))
{
return 0;
}
else
{
return 1;
}
}
}
else if (sv1 <= 0 && sv2 <= 0)
{
return 0;
}
else if (sv1 >= 0 && sv2 >= 0)
{
return 1;
}
return -1;
}
#endif

View File

@ -0,0 +1,207 @@
/*
A red-black tree implementation for building minisegs.
Copyright (C) 2002-2006 Randy Heit
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <string.h>
#include <stdio.h>
#include "framework/zdray.h"
#include "nodebuilder/nodebuild.h"
FEventTree::FEventTree ()
: Root (&Nil), Spare (NULL)
{
memset (&Nil, 0, sizeof(Nil));
}
FEventTree::~FEventTree ()
{
FEvent *probe;
DeleteAll ();
probe = Spare;
while (probe != NULL)
{
FEvent *next = probe->Left;
delete probe;
probe = next;
}
}
void FEventTree::DeleteAll ()
{
DeletionTraverser (Root);
Root = &Nil;
}
void FEventTree::DeletionTraverser (FEvent *node)
{
if (node != &Nil && node != NULL)
{
DeletionTraverser (node->Left);
DeletionTraverser (node->Right);
node->Left = Spare;
Spare = node;
}
}
FEvent *FEventTree::GetNewNode ()
{
FEvent *node;
if (Spare != NULL)
{
node = Spare;
Spare = node->Left;
}
else
{
node = new FEvent;
}
return node;
}
void FEventTree::Insert (FEvent *z)
{
FEvent *y = &Nil;
FEvent *x = Root;
while (x != &Nil)
{
y = x;
if (z->Distance < x->Distance)
{
x = x->Left;
}
else
{
x = x->Right;
}
}
z->Parent = y;
if (y == &Nil)
{
Root = z;
}
else if (z->Distance < y->Distance)
{
y->Left = z;
}
else
{
y->Right = z;
}
z->Left = &Nil;
z->Right = &Nil;
}
FEvent *FEventTree::Successor (FEvent *event) const
{
if (event->Right != &Nil)
{
event = event->Right;
while (event->Left != &Nil)
{
event = event->Left;
}
return event;
}
else
{
FEvent *y = event->Parent;
while (y != &Nil && event == y->Right)
{
event = y;
y = y->Parent;
}
return y;
}
}
FEvent *FEventTree::Predecessor (FEvent *event) const
{
if (event->Left != &Nil)
{
event = event->Left;
while (event->Right != &Nil)
{
event = event->Right;
}
return event;
}
else
{
FEvent *y = event->Parent;
while (y != &Nil && event == y->Left)
{
event = y;
y = y->Parent;
}
return y;
}
}
FEvent *FEventTree::FindEvent (double key) const
{
FEvent *node = Root;
while (node != &Nil)
{
if (node->Distance == key)
{
return node;
}
else if (node->Distance > key)
{
node = node->Left;
}
else
{
node = node->Right;
}
}
return NULL;
}
FEvent *FEventTree::GetMinimum ()
{
FEvent *node = Root;
if (node == &Nil)
{
return NULL;
}
while (node->Left != &Nil)
{
node = node->Left;
}
return node;
}
void FEventTree::PrintTree (const FEvent *event) const
{
if (event->Left != &Nil)
{
PrintTree (event->Left);
}
printf (" Distance %g, vertex %d, seg %u\n",
sqrt(event->Distance/4294967296.0), event->Info.Vertex, (unsigned)event->Info.FrontSeg);
if (event->Right != &Nil)
{
PrintTree (event->Right);
}
}

View File

@ -0,0 +1,572 @@
/*
Routines for extracting usable data from the new BSP tree.
Copyright (C) 2002-2006 Randy Heit
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <string.h>
#include <stdio.h>
#include <float.h>
#include "framework/zdray.h"
#include "nodebuilder/nodebuild.h"
#include "framework/templates.h"
#if 0
#define D(x) x
#define DD 1
#else
#define D(x) do{}while(0)
#undef DD
#endif
void FNodeBuilder::GetGLNodes (MapNodeEx *&outNodes, int &nodeCount,
MapSegGLEx *&outSegs, int &segCount,
MapSubsectorEx *&outSubs, int &subCount)
{
TArray<MapSegGLEx> segs (Segs.Size()*5/4);
int i, j, k;
nodeCount = Nodes.Size ();
outNodes = new MapNodeEx[nodeCount];
for (i = 0; i < nodeCount; ++i)
{
const node_t *orgnode = &Nodes[i];
MapNodeEx *newnode = &outNodes[i];
newnode->x = orgnode->x;
newnode->y = orgnode->y;
newnode->dx = orgnode->dx;
newnode->dy = orgnode->dy;
for (j = 0; j < 2; ++j)
{
for (k = 0; k < 4; ++k)
{
newnode->bbox[j][k] = orgnode->bbox[j][k] >> FRACBITS;
}
newnode->children[j] = orgnode->intchildren[j];
}
}
subCount = Subsectors.Size();
outSubs = new MapSubsectorEx[subCount];
for (i = 0; i < subCount; ++i)
{
int numsegs = CloseSubsector (segs, i);
outSubs[i].numlines = numsegs;
outSubs[i].firstline = segs.Size() - numsegs;
}
segCount = segs.Size ();
outSegs = new MapSegGLEx[segCount];
memcpy (outSegs, &segs[0], segCount*sizeof(MapSegGLEx));
for (i = 0; i < segCount; ++i)
{
if (outSegs[i].partner != DWORD_MAX)
{
outSegs[i].partner = Segs[outSegs[i].partner].storedseg;
}
}
D(DumpNodes(outNodes, nodeCount));
}
int FNodeBuilder::CloseSubsector (TArray<MapSegGLEx> &segs, int subsector)
{
FPrivSeg *seg, *prev;
angle_t prevAngle;
double accumx, accumy;
fixed_t midx, midy;
int i, j, first, max, count, firstVert;
bool diffplanes;
int firstplane;
first = Subsectors[subsector].firstline;
max = first + Subsectors[subsector].numlines;
count = 0;
accumx = accumy = 0.0;
diffplanes = false;
firstplane = Segs[SegList[first].SegNum].planenum;
// Calculate the midpoint of the subsector and also check for degenerate subsectors.
// A subsector is degenerate if it exists in only one dimension, which can be
// detected when all the segs lie in the same plane. This can happen if you have
// outward-facing lines in the void that don't point toward any sector. (Some of the
// polyobjects in Hexen are constructed like this.)
for (i = first; i < max; ++i)
{
seg = &Segs[SegList[i].SegNum];
accumx += double(Vertices[seg->v1].x) + double(Vertices[seg->v2].x);
accumy += double(Vertices[seg->v1].y) + double(Vertices[seg->v2].y);
if (firstplane != seg->planenum)
{
diffplanes = true;
}
}
midx = fixed_t(accumx / (max - first) / 2);
midy = fixed_t(accumy / (max - first) / 2);
seg = &Segs[SegList[first].SegNum];
prevAngle = PointToAngle (Vertices[seg->v1].x - midx, Vertices[seg->v1].y - midy);
seg->storedseg = PushGLSeg (segs, seg);
count = 1;
prev = seg;
firstVert = seg->v1;
#ifdef DD
printf("--%d--\n", subsector);
for (j = first; j < max; ++j)
{
seg = &Segs[SegList[j].SegNum];
angle_t ang = PointToAngle (Vertices[seg->v1].x - midx, Vertices[seg->v1].y - midy);
printf ("%d%c %5d(%5d,%5d)->%5d(%5d,%5d) - %3.5f %d,%d [%08x,%08x]-[%08x,%08x]\n", j,
seg->linedef == -1 ? '+' : ':',
seg->v1, Vertices[seg->v1].x>>16, Vertices[seg->v1].y>>16,
seg->v2, Vertices[seg->v2].x>>16, Vertices[seg->v2].y>>16,
double(ang/2)*180/(1<<30),
seg->planenum, seg->planefront,
Vertices[seg->v1].x, Vertices[seg->v1].y,
Vertices[seg->v2].x, Vertices[seg->v2].y);
}
#endif
if (diffplanes)
{ // A well-behaved subsector. Output the segs sorted by the angle formed by connecting
// the subsector's center to their first vertex.
D(printf("Well behaved subsector\n"));
for (i = first + 1; i < max; ++i)
{
angle_t bestdiff = ANGLE_MAX;
FPrivSeg *bestseg = NULL;
int bestj = -1;
for (j = first; j < max; ++j)
{
seg = &Segs[SegList[j].SegNum];
angle_t ang = PointToAngle (Vertices[seg->v1].x - midx, Vertices[seg->v1].y - midy);
angle_t diff = prevAngle - ang;
if (seg->v1 == prev->v2)
{
bestdiff = diff;
bestseg = seg;
bestj = j;
break;
}
if (diff < bestdiff && diff > 0)
{
bestdiff = diff;
bestseg = seg;
bestj = j;
}
}
if (bestseg != NULL)
{
seg = bestseg;
}
if (prev->v2 != seg->v1)
{
// Add a new miniseg to connect the two segs
PushConnectingGLSeg (subsector, segs, prev->v2, seg->v1);
count++;
}
#ifdef DD
printf ("+%d\n", bestj);
#endif
prevAngle -= bestdiff;
seg->storedseg = PushGLSeg (segs, seg);
count++;
prev = seg;
if (seg->v2 == firstVert)
{
prev = seg;
break;
}
}
#ifdef DD
printf ("\n");
#endif
}
else
{ // A degenerate subsector. These are handled in three stages:
// Stage 1. Proceed in the same direction as the start seg until we
// hit the seg furthest from it.
// Stage 2. Reverse direction and proceed until we hit the seg
// furthest from the start seg.
// Stage 3. Reverse direction again and insert segs until we get
// to the start seg.
// A dot product serves to determine distance from the start seg.
D(printf("degenerate subsector\n"));
// Stage 1. Go forward.
count += OutputDegenerateSubsector (segs, subsector, true, 0, prev);
// Stage 2. Go backward.
count += OutputDegenerateSubsector (segs, subsector, false, DBL_MAX, prev);
// Stage 3. Go forward again.
count += OutputDegenerateSubsector (segs, subsector, true, -DBL_MAX, prev);
}
if (prev->v2 != firstVert)
{
PushConnectingGLSeg (subsector, segs, prev->v2, firstVert);
count++;
}
#ifdef DD
printf ("Output GL subsector %d:\n", subsector);
for (i = segs.Size() - count; i < (int)segs.Size(); ++i)
{
printf (" Seg %5d%c(%5d,%5d)-(%5d,%5d) [%08x,%08x]-[%08x,%08x]\n", i,
segs[i].linedef == NO_INDEX ? '+' : ' ',
Vertices[segs[i].v1].x>>16,
Vertices[segs[i].v1].y>>16,
Vertices[segs[i].v2].x>>16,
Vertices[segs[i].v2].y>>16,
Vertices[segs[i].v1].x,
Vertices[segs[i].v1].y,
Vertices[segs[i].v2].x,
Vertices[segs[i].v2].y);
}
#endif
return count;
}
int FNodeBuilder::OutputDegenerateSubsector (TArray<MapSegGLEx> &segs, int subsector, bool bForward, double lastdot, FPrivSeg *&prev)
{
static const double bestinit[2] = { -DBL_MAX, DBL_MAX };
FPrivSeg *seg;
int i, j, first, max, count;
double dot, x1, y1, dx, dy, dx2, dy2;
bool wantside;
first = Subsectors[subsector].firstline;
max = first + Subsectors[subsector].numlines;
count = 0;
seg = &Segs[SegList[first].SegNum];
x1 = Vertices[seg->v1].x;
y1 = Vertices[seg->v1].y;
dx = Vertices[seg->v2].x - x1;
dy = Vertices[seg->v2].y - y1;
wantside = seg->planefront ^ !bForward;
for (i = first + 1; i < max; ++i)
{
double bestdot = bestinit[bForward];
FPrivSeg *bestseg = NULL;
for (j = first + 1; j < max; ++j)
{
seg = &Segs[SegList[j].SegNum];
if (seg->planefront != wantside)
{
continue;
}
dx2 = Vertices[seg->v1].x - x1;
dy2 = Vertices[seg->v1].y - y1;
dot = dx*dx2 + dy*dy2;
if (bForward)
{
if (dot < bestdot && dot > lastdot)
{
bestdot = dot;
bestseg = seg;
}
}
else
{
if (dot > bestdot && dot < lastdot)
{
bestdot = dot;
bestseg = seg;
}
}
}
if (bestseg != NULL)
{
if (prev->v2 != bestseg->v1)
{
PushConnectingGLSeg (subsector, segs, prev->v2, bestseg->v1);
count++;
}
seg->storedseg = PushGLSeg (segs, bestseg);
count++;
prev = bestseg;
lastdot = bestdot;
}
}
return count;
}
DWORD FNodeBuilder::PushGLSeg (TArray<MapSegGLEx> &segs, const FPrivSeg *seg)
{
MapSegGLEx newseg;
newseg.v1 = seg->v1;
newseg.v2 = seg->v2;
newseg.linedef = seg->linedef;
// Just checking the sidedef to determine the side is insufficient.
// When a level is sidedef compressed both sides may well have the same sidedef.
if (newseg.linedef != NO_INDEX)
{
IntLineDef *ld = &Level.Lines[newseg.linedef];
if (ld->sidenum[0] == ld->sidenum[1])
{
// When both sidedefs are the same a quick check doesn't work so this
// has to be done by comparing the distances of the seg's end point to
// the line's start.
WideVertex *lv1 = &Level.Vertices[ld->v1];
WideVertex *sv1 = &Level.Vertices[seg->v1];
WideVertex *sv2 = &Level.Vertices[seg->v2];
double dist1sq = double(sv1->x-lv1->x)*(sv1->x-lv1->x) + double(sv1->y-lv1->y)*(sv1->y-lv1->y);
double dist2sq = double(sv2->x-lv1->x)*(sv2->x-lv1->x) + double(sv2->y-lv1->y)*(sv2->y-lv1->y);
newseg.side = dist1sq < dist2sq ? 0 : 1;
}
else
{
newseg.side = ld->sidenum[1] == seg->sidedef ? 1 : 0;
}
}
else
{
newseg.side = 0;
}
newseg.partner = seg->partner;
return segs.Push (newseg);
}
void FNodeBuilder::PushConnectingGLSeg (int subsector, TArray<MapSegGLEx> &segs, int v1, int v2)
{
MapSegGLEx newseg;
Warn ("Unclosed subsector %d, from (%d,%d) to (%d,%d)\n", subsector,
Vertices[v1].x >> FRACBITS, Vertices[v1].y >> FRACBITS,
Vertices[v2].x >> FRACBITS, Vertices[v2].y >> FRACBITS);
newseg.v1 = v1;
newseg.v2 = v2;
newseg.linedef = NO_INDEX;
newseg.side = 0;
newseg.partner = DWORD_MAX;
segs.Push (newseg);
}
void FNodeBuilder::GetVertices (WideVertex *&verts, int &count)
{
count = Vertices.Size ();
verts = new WideVertex[count];
for (int i = 0; i < count; ++i)
{
verts[i].x = Vertices[i].x;
verts[i].y = Vertices[i].y;
verts[i].index = Vertices[i].index;
}
}
void FNodeBuilder::GetNodes (MapNodeEx *&outNodes, int &nodeCount,
MapSegEx *&outSegs, int &segCount,
MapSubsectorEx *&outSubs, int &subCount)
{
short bbox[4];
TArray<MapSegEx> segs (Segs.Size());
// Walk the BSP and create a new BSP with only the information
// suitable for a standard tree. At a minimum, this means removing
// all minisegs. As an optional step, I also recompute all the
// nodes' bounding boxes so that they only bound the real segs and
// not the minisegs.
nodeCount = Nodes.Size ();
outNodes = new MapNodeEx[nodeCount];
subCount = Subsectors.Size ();
outSubs = new MapSubsectorEx[subCount];
RemoveMinisegs (outNodes, segs, outSubs, Nodes.Size() - 1, bbox);
segCount = segs.Size ();
outSegs = new MapSegEx[segCount];
memcpy (outSegs, &segs[0], segCount*sizeof(MapSegEx));
D(DumpNodes(outNodes, nodeCount));
#ifdef DD
for (int i = 0; i < segCount; ++i)
{
printf("Seg %d: v1(%d) -> v2(%d)\n", i, outSegs[i].v1, outSegs[i].v2);
}
#endif
}
int FNodeBuilder::RemoveMinisegs (MapNodeEx *nodes,
TArray<MapSegEx> &segs, MapSubsectorEx *subs, int node, short bbox[4])
{
if (node & NFX_SUBSECTOR)
{
int subnum = node == -1 ? 0 : node & ~NFX_SUBSECTOR;
int numsegs = StripMinisegs (segs, subnum, bbox);
subs[subnum].numlines = numsegs;
subs[subnum].firstline = segs.Size() - numsegs;
return NFX_SUBSECTOR | subnum;
}
else
{
const node_t *orgnode = &Nodes[node];
MapNodeEx *newnode = &nodes[node];
int child0 = RemoveMinisegs (nodes, segs, subs, orgnode->intchildren[0], newnode->bbox[0]);
int child1 = RemoveMinisegs (nodes, segs, subs, orgnode->intchildren[1], newnode->bbox[1]);
newnode->x = orgnode->x;
newnode->y = orgnode->y;
newnode->dx = orgnode->dx;
newnode->dy = orgnode->dy;
newnode->children[0] = child0;
newnode->children[1] = child1;
bbox[BOXTOP] = MAX(newnode->bbox[0][BOXTOP], newnode->bbox[1][BOXTOP]);
bbox[BOXBOTTOM] = MIN(newnode->bbox[0][BOXBOTTOM], newnode->bbox[1][BOXBOTTOM]);
bbox[BOXLEFT] = MIN(newnode->bbox[0][BOXLEFT], newnode->bbox[1][BOXLEFT]);
bbox[BOXRIGHT] = MAX(newnode->bbox[0][BOXRIGHT], newnode->bbox[1][BOXRIGHT]);
return node;
}
}
int FNodeBuilder::StripMinisegs (TArray<MapSegEx> &segs, int subsector, short bbox[4])
{
int count, i, max;
// The bounding box is recomputed to only cover the real segs and not the
// minisegs in the subsector.
bbox[BOXTOP] = -32768;
bbox[BOXBOTTOM] = 32767;
bbox[BOXLEFT] = 32767;
bbox[BOXRIGHT] = -32768;
i = Subsectors[subsector].firstline;
max = Subsectors[subsector].numlines + i;
for (count = 0; i < max; ++i)
{
const FPrivSeg *org = &Segs[SegList[i].SegNum];
// Because of the ordering guaranteed by SortSegs(), all mini segs will
// be at the end of the subsector, so once one is encountered, we can
// stop right away.
if (org->linedef == -1)
{
break;
}
else
{
MapSegEx newseg;
AddSegToShortBBox (bbox, org);
newseg.v1 = org->v1;
newseg.v2 = org->v2;
newseg.angle = org->angle >> 16;
newseg.offset = org->offset >> FRACBITS;
newseg.linedef = org->linedef;
// Just checking the sidedef to determine the side is insufficient.
// When a level is sidedef compressed both sides may well have the same sidedef.
IntLineDef * ld = &Level.Lines[newseg.linedef];
if (ld->sidenum[0]==ld->sidenum[1])
{
// When both sidedefs are the same a quick check doesn't work so this
// has to be done by comparing the distances of the seg's end point to
// the line's start.
WideVertex * lv1 = &Level.Vertices[ld->v1];
WideVertex * sv1 = &Level.Vertices[org->v1];
WideVertex * sv2 = &Level.Vertices[org->v2];
double dist1sq = double(sv1->x-lv1->x)*(sv1->x-lv1->x) + double(sv1->y-lv1->y)*(sv1->y-lv1->y);
double dist2sq = double(sv2->x-lv1->x)*(sv2->x-lv1->x) + double(sv2->y-lv1->y)*(sv2->y-lv1->y);
newseg.side = dist1sq<dist2sq? 0:1;
}
else
{
newseg.side = ld->sidenum[1] == org->sidedef ? 1 : 0;
}
newseg.side = Level.Lines[org->linedef].sidenum[1] == org->sidedef ? 1 : 0;
segs.Push (newseg);
++count;
}
}
return count;
}
void FNodeBuilder::AddSegToShortBBox (short bbox[4], const FPrivSeg *seg)
{
const FPrivVert *v1 = &Vertices[seg->v1];
const FPrivVert *v2 = &Vertices[seg->v2];
short v1x = v1->x >> FRACBITS;
short v1y = v1->y >> FRACBITS;
short v2x = v2->x >> FRACBITS;
short v2y = v2->y >> FRACBITS;
if (v1x < bbox[BOXLEFT]) bbox[BOXLEFT] = v1x;
if (v1x > bbox[BOXRIGHT]) bbox[BOXRIGHT] = v1x;
if (v1y < bbox[BOXBOTTOM]) bbox[BOXBOTTOM] = v1y;
if (v1y > bbox[BOXTOP]) bbox[BOXTOP] = v1y;
if (v2x < bbox[BOXLEFT]) bbox[BOXLEFT] = v2x;
if (v2x > bbox[BOXRIGHT]) bbox[BOXRIGHT] = v2x;
if (v2y < bbox[BOXBOTTOM]) bbox[BOXBOTTOM] = v2y;
if (v2y > bbox[BOXTOP]) bbox[BOXTOP] = v2y;
}
void FNodeBuilder::DumpNodes(MapNodeEx *outNodes, int nodeCount)
{
for (unsigned int i = 0; i < Nodes.Size(); ++i)
{
printf("Node %d: Splitter[%08x,%08x] [%08x,%08x]\n", i,
outNodes[i].x, outNodes[i].y, outNodes[i].dx, outNodes[i].dy);
for (int j = 1; j >= 0; --j)
{
if (outNodes[i].children[j] & NFX_SUBSECTOR)
{
printf(" subsector %d\n", outNodes[i].children[j] & ~NFX_SUBSECTOR);
}
else
{
printf(" node %d\n", outNodes[i].children[j]);
}
}
}
}

View File

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

View File

@ -0,0 +1,556 @@
/*
Various utility functions.
Copyright (C) 2002-2006 Randy Heit
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <string.h>
#include <stdio.h>
#include "framework/zdray.h"
#include "nodebuilder/nodebuild.h"
#include "framework/templates.h"
static const int PO_LINE_START = 1;
static const int PO_LINE_EXPLICIT = 5;
#if 0
#define D(x) x
#else
#define D(x) do{}while(0)
#endif
#if 0
#define P(x) x
#define Printf printf
#else
#define P(x) do{}while(0)
#endif
void FNodeBuilder::FindUsedVertices (WideVertex *oldverts, int max)
{
int *map = new int[max];
int i;
FPrivVert newvert;
memset (&map[0], -1, sizeof(int)*max);
for (i = 0; i < Level.NumLines(); ++i)
{
int v1 = Level.Lines[i].v1;
int v2 = Level.Lines[i].v2;
if (map[v1] == -1)
{
newvert.x = oldverts[v1].x;
newvert.y = oldverts[v1].y;
newvert.index = oldverts[v1].index;
map[v1] = VertexMap->SelectVertexExact (newvert);
}
if (map[v2] == -1)
{
newvert.x = oldverts[v2].x;
newvert.y = oldverts[v2].y;
newvert.index = oldverts[v2].index;
map[v2] = VertexMap->SelectVertexExact (newvert);
}
Level.Lines[i].v1 = map[v1];
Level.Lines[i].v2 = map[v2];
}
InitialVertices = Vertices.Size ();
Level.NumOrgVerts = (int)InitialVertices;
delete[] map;
}
// For every sidedef in the map, create a corresponding seg.
void FNodeBuilder::MakeSegsFromSides ()
{
int i, j;
for (i = 0; i < Level.NumLines(); ++i)
{
if (Level.Lines[i].sidenum[0] != NO_INDEX)
{
CreateSeg (i, 0);
}
else
{
printf ("Linedef %d does not have a front side.\n", i);
}
if (Level.Lines[i].sidenum[1] != NO_INDEX)
{
j = CreateSeg (i, 1);
if (Level.Lines[i].sidenum[0] != NO_INDEX)
{
Segs[j-1].partner = j;
Segs[j].partner = j-1;
}
}
}
}
int FNodeBuilder::CreateSeg (int linenum, int sidenum)
{
FPrivSeg seg;
DWORD backside;
int segnum;
seg.next = DWORD_MAX;
seg.loopnum = 0;
seg.offset = 0;
seg.partner = DWORD_MAX;
seg.hashnext = NULL;
seg.planefront = false;
seg.planenum = DWORD_MAX;
seg.storedseg = DWORD_MAX;
if (sidenum == 0)
{ // front
seg.v1 = Level.Lines[linenum].v1;
seg.v2 = Level.Lines[linenum].v2;
}
else
{ // back
seg.v2 = Level.Lines[linenum].v1;
seg.v1 = Level.Lines[linenum].v2;
}
seg.linedef = linenum;
seg.sidedef = Level.Lines[linenum].sidenum[sidenum];
backside = Level.Lines[linenum].sidenum[!sidenum];
seg.frontsector = Level.Sides[seg.sidedef].sector;
seg.backsector = backside != NO_INDEX ? Level.Sides[backside].sector : -1;
seg.nextforvert = Vertices[seg.v1].segs;
seg.nextforvert2 = Vertices[seg.v2].segs2;
seg.angle = PointToAngle (Vertices[seg.v2].x-Vertices[seg.v1].x,
Vertices[seg.v2].y-Vertices[seg.v1].y);
segnum = (int)Segs.Push (seg);
Vertices[seg.v1].segs = segnum;
Vertices[seg.v2].segs2 = segnum;
D(printf("Seg %4d: From line %d, side %s (%5d,%5d)-(%5d,%5d) [%08x,%08x]-[%08x,%08x]\n", segnum, linenum, sidenum ? "back " : "front",
Vertices[seg.v1].x>>16, Vertices[seg.v1].y>>16, Vertices[seg.v2].x>>16, Vertices[seg.v2].y>>16,
Vertices[seg.v1].x, Vertices[seg.v1].y, Vertices[seg.v2].x, Vertices[seg.v2].y));
return segnum;
}
// Group colinear segs together so that only one seg per line needs to be checked
// by SelectSplitter().
void FNodeBuilder::GroupSegPlanes ()
{
const int bucketbits = 12;
FPrivSeg *buckets[1<<bucketbits] = { 0 };
int i, planenum;
for (i = 0; i < (int)Segs.Size(); ++i)
{
FPrivSeg *seg = &Segs[i];
seg->next = i+1;
seg->hashnext = NULL;
}
Segs[Segs.Size()-1].next = DWORD_MAX;
for (i = planenum = 0; i < (int)Segs.Size(); ++i)
{
FPrivSeg *seg = &Segs[i];
fixed_t x1 = Vertices[seg->v1].x;
fixed_t y1 = Vertices[seg->v1].y;
fixed_t x2 = Vertices[seg->v2].x;
fixed_t y2 = Vertices[seg->v2].y;
angle_t ang = PointToAngle (x2 - x1, y2 - y1);
if (ang >= 1u<<31)
ang += 1u<<31;
FPrivSeg *check = buckets[ang >>= 31-bucketbits];
while (check != NULL)
{
fixed_t cx1 = Vertices[check->v1].x;
fixed_t cy1 = Vertices[check->v1].y;
fixed_t cdx = Vertices[check->v2].x - cx1;
fixed_t cdy = Vertices[check->v2].y - cy1;
if (PointOnSide (x1, y1, cx1, cy1, cdx, cdy) == 0 &&
PointOnSide (x2, y2, cx1, cy1, cdx, cdy) == 0)
{
break;
}
check = check->hashnext;
}
if (check != NULL)
{
seg->planenum = check->planenum;
const FSimpleLine *line = &Planes[seg->planenum];
if (line->dx != 0)
{
if ((line->dx > 0 && x2 > x1) || (line->dx < 0 && x2 < x1))
{
seg->planefront = true;
}
else
{
seg->planefront = false;
}
}
else
{
if ((line->dy > 0 && y2 > y1) || (line->dy < 0 && y2 < y1))
{
seg->planefront = true;
}
else
{
seg->planefront = false;
}
}
}
else
{
seg->hashnext = buckets[ang];
buckets[ang] = seg;
seg->planenum = planenum++;
seg->planefront = true;
FSimpleLine pline = { Vertices[seg->v1].x,
Vertices[seg->v1].y,
Vertices[seg->v2].x - Vertices[seg->v1].x,
Vertices[seg->v2].y - Vertices[seg->v1].y };
Planes.Push (pline);
}
}
D(printf ("%d planes from %d segs\n", planenum, Segs.Size()));
PlaneChecked.Reserve ((planenum + 7) / 8);
}
// Find "loops" of segs surrounding polyobject's origin. Note that a polyobject's origin
// is not solely defined by the polyobject's anchor, but also by the polyobject itself.
// For the split avoidance to work properly, you must have a convex, complete loop of
// segs surrounding the polyobject origin. All the maps in hexen.wad have complete loops of
// segs around their polyobjects, but they are not all convex: The doors at the start of MAP01
// and some of the pillars in MAP02 that surround the entrance to MAP06 are not convex.
// Heuristic() uses some special weighting to make these cases work properly.
void FNodeBuilder::FindPolyContainers (TArray<FPolyStart> &spots, TArray<FPolyStart> &anchors)
{
int loop = 1;
for (unsigned int i = 0; i < spots.Size(); ++i)
{
FPolyStart *spot = &spots[i];
fixed_t bbox[4];
if (GetPolyExtents (spot->polynum, bbox))
{
FPolyStart *anchor;
unsigned int j;
for (j = 0; j < anchors.Size(); ++j)
{
anchor = &anchors[j];
if (anchor->polynum == spot->polynum)
{
break;
}
}
if (j < anchors.Size())
{
vertex_t mid;
vertex_t center;
mid.x = bbox[BOXLEFT] + (bbox[BOXRIGHT]-bbox[BOXLEFT])/2;
mid.y = bbox[BOXBOTTOM] + (bbox[BOXTOP]-bbox[BOXBOTTOM])/2;
center.x = mid.x - anchor->x + spot->x;
center.y = mid.y - anchor->y + spot->y;
// Scan right for the seg closest to the polyobject's center after it
// gets moved to its start spot.
fixed_t closestdist = FIXED_MAX;
DWORD closestseg = 0;
P(Printf ("start %d,%d -- center %d, %d\n", spot->x>>16, spot->y>>16, center.x>>16, center.y>>16));
for (unsigned int j = 0; j < Segs.Size(); ++j)
{
FPrivSeg *seg = &Segs[j];
FPrivVert *v1 = &Vertices[seg->v1];
FPrivVert *v2 = &Vertices[seg->v2];
fixed_t dy = v2->y - v1->y;
if (dy == 0)
{ // Horizontal, so skip it
continue;
}
if ((v1->y < center.y && v2->y < center.y) || (v1->y > center.y && v2->y > center.y))
{ // Not crossed
continue;
}
fixed_t dx = v2->x - v1->x;
if (PointOnSide (center.x, center.y, v1->x, v1->y, dx, dy) <= 0)
{
fixed_t t = DivScale30 (center.y - v1->y, dy);
fixed_t sx = v1->x + MulScale30 (dx, t);
fixed_t dist = sx - spot->x;
if (dist < closestdist && dist >= 0)
{
closestdist = dist;
closestseg = (long)j;
}
}
}
if (closestdist != FIXED_MAX)
{
loop = MarkLoop (closestseg, loop);
P(Printf ("Found polyobj in sector %d (loop %d)\n", Segs[closestseg].frontsector,
Segs[closestseg].loopnum));
}
}
}
}
}
int FNodeBuilder::MarkLoop (DWORD firstseg, int loopnum)
{
int seg;
int sec = Segs[firstseg].frontsector;
if (Segs[firstseg].loopnum != 0)
{ // already marked
return loopnum;
}
seg = firstseg;
do
{
FPrivSeg *s1 = &Segs[seg];
s1->loopnum = loopnum;
P(Printf ("Mark seg %d (%d,%d)-(%d,%d)\n", seg,
Vertices[s1->v1].x>>16, Vertices[s1->v1].y>>16,
Vertices[s1->v2].x>>16, Vertices[s1->v2].y>>16));
DWORD bestseg = DWORD_MAX;
DWORD tryseg = Vertices[s1->v2].segs;
angle_t bestang = ANGLE_MAX;
angle_t ang1 = s1->angle;
while (tryseg != DWORD_MAX)
{
FPrivSeg *s2 = &Segs[tryseg];
if (s2->frontsector == sec)
{
angle_t ang2 = s2->angle + ANGLE_180;
angle_t angdiff = ang2 - ang1;
if (angdiff < bestang && angdiff > 0)
{
bestang = angdiff;
bestseg = tryseg;
}
}
tryseg = s2->nextforvert;
}
seg = bestseg;
} while (seg != (int)DWORD_MAX && Segs[seg].loopnum == 0);
return loopnum + 1;
}
// Find the bounding box for a specific polyobject.
bool FNodeBuilder::GetPolyExtents (int polynum, fixed_t bbox[4])
{
unsigned int i;
bbox[BOXLEFT] = bbox[BOXBOTTOM] = FIXED_MAX;
bbox[BOXRIGHT] = bbox[BOXTOP] = FIXED_MIN;
// Try to find a polyobj marked with a start line
for (i = 0; i < Segs.Size(); ++i)
{
if (Level.Lines[Segs[i].linedef].special == PO_LINE_START &&
Level.Lines[Segs[i].linedef].args[0] == polynum)
{
break;
}
}
if (i < Segs.Size())
{
vertex_t start;
unsigned int vert;
unsigned int count = Segs.Size(); // to prevent endless loops. Stop when this reaches the number of segs.
vert = Segs[i].v1;
start.x = Vertices[vert].x;
start.y = Vertices[vert].y;
do
{
AddSegToBBox (bbox, &Segs[i]);
vert = Segs[i].v2;
i = Vertices[vert].segs;
} while (--count && i != DWORD_MAX && (Vertices[vert].x != start.x || Vertices[vert].y != start.y));
return true;
}
// Try to find a polyobj marked with explicit lines
bool found = false;
for (i = 0; i < Segs.Size(); ++i)
{
if (Level.Lines[Segs[i].linedef].special == PO_LINE_EXPLICIT &&
Level.Lines[Segs[i].linedef].args[0] == polynum)
{
AddSegToBBox (bbox, &Segs[i]);
found = true;
}
}
return found;
}
void FNodeBuilder::AddSegToBBox (fixed_t bbox[4], const FPrivSeg *seg)
{
FPrivVert *v1 = &Vertices[seg->v1];
FPrivVert *v2 = &Vertices[seg->v2];
if (v1->x < bbox[BOXLEFT]) bbox[BOXLEFT] = v1->x;
if (v1->x > bbox[BOXRIGHT]) bbox[BOXRIGHT] = v1->x;
if (v1->y < bbox[BOXBOTTOM]) bbox[BOXBOTTOM] = v1->y;
if (v1->y > bbox[BOXTOP]) bbox[BOXTOP] = v1->y;
if (v2->x < bbox[BOXLEFT]) bbox[BOXLEFT] = v2->x;
if (v2->x > bbox[BOXRIGHT]) bbox[BOXRIGHT] = v2->x;
if (v2->y < bbox[BOXBOTTOM]) bbox[BOXBOTTOM] = v2->y;
if (v2->y > bbox[BOXTOP]) bbox[BOXTOP] = v2->y;
}
FNodeBuilder::FVertexMap::FVertexMap (FNodeBuilder &builder,
fixed_t minx, fixed_t miny, fixed_t maxx, fixed_t maxy)
: MyBuilder(builder)
{
MinX = minx;
MinY = miny;
BlocksWide = int(((double(maxx) - minx + 1) + (BLOCK_SIZE - 1)) / BLOCK_SIZE);
BlocksTall = int(((double(maxy) - miny + 1) + (BLOCK_SIZE - 1)) / BLOCK_SIZE);
MaxX = MinX + BlocksWide * BLOCK_SIZE - 1;
MaxY = MinY + BlocksTall * BLOCK_SIZE - 1;
VertexGrid = new TArray<int>[BlocksWide * BlocksTall];
}
FNodeBuilder::FVertexMap::~FVertexMap ()
{
delete[] VertexGrid;
}
int FNodeBuilder::FVertexMap::SelectVertexExact (FNodeBuilder::FPrivVert &vert)
{
TArray<int> &block = VertexGrid[GetBlock (vert.x, vert.y)];
FPrivVert *vertices = &MyBuilder.Vertices[0];
unsigned int i;
for (i = 0; i < block.Size(); ++i)
{
if (vertices[block[i]].x == vert.x && vertices[block[i]].y == vert.y)
{
return block[i];
}
}
// Not present: add it!
return InsertVertex (vert);
}
int FNodeBuilder::FVertexMap::SelectVertexClose (FNodeBuilder::FPrivVert &vert)
{
TArray<int> &block = VertexGrid[GetBlock (vert.x, vert.y)];
FPrivVert *vertices = &MyBuilder.Vertices[0];
unsigned int i;
for (i = 0; i < block.Size(); ++i)
{
#if VERTEX_EPSILON <= 1
if (vertices[block[i]].x == vert.x && vertices[block[i]].y == vert.y)
#else
if (abs(vertices[block[i]].x - vert.x) < VERTEX_EPSILON &&
abs(vertices[block[i]].y - vert.y) < VERTEX_EPSILON)
#endif
{
return block[i];
}
}
// Not present: add it!
return InsertVertex (vert);
}
int FNodeBuilder::FVertexMap::InsertVertex (FNodeBuilder::FPrivVert &vert)
{
int vertnum;
vert.segs = DWORD_MAX;
vert.segs2 = DWORD_MAX;
vertnum = (int)MyBuilder.Vertices.Push (vert);
// If a vertex is near a block boundary, then it will be inserted on
// both sides of the boundary so that SelectVertexClose can find
// it by checking in only one block.
fixed_t minx = MAX (MinX, vert.x - VERTEX_EPSILON);
fixed_t maxx = MIN (MaxX, vert.x + VERTEX_EPSILON);
fixed_t miny = MAX (MinY, vert.y - VERTEX_EPSILON);
fixed_t maxy = MIN (MaxY, vert.y + VERTEX_EPSILON);
int blk[4] =
{
GetBlock (minx, miny),
GetBlock (maxx, miny),
GetBlock (minx, maxy),
GetBlock (maxx, maxy)
};
unsigned int blkcount[4] =
{
VertexGrid[blk[0]].Size(),
VertexGrid[blk[1]].Size(),
VertexGrid[blk[2]].Size(),
VertexGrid[blk[3]].Size()
};
for (int i = 0; i < 4; ++i)
{
if (VertexGrid[blk[i]].Size() == blkcount[i])
{
VertexGrid[blk[i]].Push (vertnum);
}
}
return vertnum;
}

714
src/parse/sc_man.cpp Normal file
View File

@ -0,0 +1,714 @@
/*
Reads wad files, builds nodes, and saves new wad files.
Copyright (C) 1996 Raven Software
Copyright (C) 2002-2006 Randy Heit
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
// HEADER FILES ------------------------------------------------------------
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <limits.h>
#include "sc_man.h"
#ifdef _MSC_VER
#pragma warning(disable:4996)
#endif
// MACROS ------------------------------------------------------------------
#define MAX_STRING_SIZE 4096
#define ASCII_COMMENT (';')
#define CPP_COMMENT ('/')
#define C_COMMENT ('*')
#define ASCII_QUOTE (34)
#define LUMP_SCRIPT 1
#define FILE_ZONE_SCRIPT 2
// TYPES -------------------------------------------------------------------
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
static void SC_PrepareScript (void);
static void CheckOpen (void);
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
// PUBLIC DATA DEFINITIONS -------------------------------------------------
char *sc_String;
int sc_StringLen;
int sc_Number;
double sc_Float;
int sc_Line;
bool sc_End;
bool sc_Crossed;
bool sc_StringQuoted;
bool sc_FileScripts = false;
//FILE *sc_Out;
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static char *ScriptBuffer;
static char *ScriptPtr;
static char *ScriptEndPtr;
static char StringBuffer[MAX_STRING_SIZE];
static bool ScriptOpen = false;
static int ScriptSize;
static bool AlreadyGot = false;
static char *SavedScriptPtr;
static int SavedScriptLine;
static bool CMode;
// CODE --------------------------------------------------------------------
//==========================================================================
//
// SC_OpenFile
//
// Loads a script
//
//==========================================================================
void SC_OpenMem (const char *name, char *buffer, int len)
{
SC_Close ();
ScriptSize = len;
ScriptBuffer = buffer;
SC_PrepareScript ();
}
//==========================================================================
//
// SC_PrepareScript
//
// Prepares a script for parsing.
//
//==========================================================================
static void SC_PrepareScript (void)
{
ScriptPtr = ScriptBuffer;
ScriptEndPtr = ScriptPtr + ScriptSize;
sc_Line = 1;
sc_End = false;
ScriptOpen = true;
sc_String = StringBuffer;
AlreadyGot = false;
SavedScriptPtr = NULL;
CMode = false;
}
//==========================================================================
//
// SC_Close
//
//==========================================================================
void SC_Close (void)
{
if (ScriptOpen)
{
ScriptBuffer = NULL;
ScriptOpen = false;
}
}
//==========================================================================
//
// SC_SavePos
//
// Saves the current script location for restoration later
//
//==========================================================================
void SC_SavePos (void)
{
CheckOpen ();
if (sc_End)
{
SavedScriptPtr = NULL;
}
else
{
SavedScriptPtr = ScriptPtr;
SavedScriptLine = sc_Line;
}
}
//==========================================================================
//
// SC_RestorePos
//
// Restores the previously saved script location
//
//==========================================================================
void SC_RestorePos (void)
{
if (SavedScriptPtr)
{
ScriptPtr = SavedScriptPtr;
sc_Line = SavedScriptLine;
sc_End = false;
AlreadyGot = false;
}
}
//==========================================================================
//
// SC_SetCMode
//
// Enables/disables C mode. In C mode, more characters are considered to
// be whole words than in non-C mode.
//
//==========================================================================
void SC_SetCMode (bool cmode)
{
CMode = cmode;
}
//==========================================================================
//
// SC_GetString
//
//==========================================================================
bool SC_GetString ()
{
char *text;
bool foundToken;
CheckOpen();
if (AlreadyGot)
{
AlreadyGot = false;
return true;
}
foundToken = false;
sc_Crossed = false;
sc_StringQuoted = false;
if (ScriptPtr >= ScriptEndPtr)
{
sc_End = true;
return false;
}
while (foundToken == false)
{
while (ScriptPtr < ScriptEndPtr && *ScriptPtr <= ' ')
{
if (*ScriptPtr++ == '\n')
{
sc_Line++;
sc_Crossed = true;
}
}
if (ScriptPtr >= ScriptEndPtr)
{
sc_End = true;
return false;
}
if ((CMode || *ScriptPtr != ASCII_COMMENT) &&
!(ScriptPtr[0] == CPP_COMMENT && ScriptPtr < ScriptEndPtr - 1 &&
(ScriptPtr[1] == CPP_COMMENT || ScriptPtr[1] == C_COMMENT)))
{ // Found a token
foundToken = true;
}
else
{ // Skip comment
if (ScriptPtr[0] == CPP_COMMENT && ScriptPtr[1] == C_COMMENT)
{ // C comment
while (ScriptPtr[0] != C_COMMENT || ScriptPtr[1] != CPP_COMMENT)
{
if (ScriptPtr[0] == '\n')
{
sc_Line++;
sc_Crossed = true;
}
// fputc(ScriptPtr[0], sc_Out);
ScriptPtr++;
if (ScriptPtr >= ScriptEndPtr - 1)
{
sc_End = true;
return false;
}
// fputs("*/", sc_Out);
}
ScriptPtr += 2;
}
else
{ // C++ comment
while (*ScriptPtr++ != '\n')
{
// fputc(ScriptPtr[-1], sc_Out);
if (ScriptPtr >= ScriptEndPtr)
{
sc_End = true;
return false;
}
}
sc_Line++;
sc_Crossed = true;
// fputc('\n', sc_Out);
}
}
}
text = sc_String;
if (*ScriptPtr == ASCII_QUOTE)
{ // Quoted string - return string including the quotes
*text++ = *ScriptPtr++;
sc_StringQuoted = true;
while (*ScriptPtr != ASCII_QUOTE)
{
if (*ScriptPtr >= 0 && *ScriptPtr < ' ')
{
ScriptPtr++;
}
else if (*ScriptPtr == '\\')
{
// Add the backslash character and the following chararcter to the text.
// We do not translate the escape sequence in any way, since the only
// thing that will happen to this string is that it will be written back
// out to disk. Basically, we just need this special case here so that
// string reading won't terminate prematurely when a \" sequence is
// used to embed a quote mark in the string.
*text++ = *ScriptPtr++;
*text++ = *ScriptPtr++;
}
else
{
*text++ = *ScriptPtr++;
}
if (ScriptPtr == ScriptEndPtr
|| text == &sc_String[MAX_STRING_SIZE-1])
{
break;
}
}
*text++ = '"';
ScriptPtr++;
}
else
{ // Normal string
static const char *stopchars;
if (CMode)
{
stopchars = "`~!@#$%^&*(){}[]/=\?+|;:<>,";
// '-' can be its own token, or it can be part of a negative number
if (*ScriptPtr == '-')
{
*text++ = '-';
ScriptPtr++;
if (ScriptPtr < ScriptEndPtr || (*ScriptPtr >= '0' && *ScriptPtr <= '9'))
{
goto grabtoken;
}
goto gottoken;
}
}
else
{
stopchars = "{}|=";
}
if (strchr (stopchars, *ScriptPtr))
{
*text++ = *ScriptPtr++;
}
else
{
grabtoken:
while ((*ScriptPtr > ' ') && (strchr (stopchars, *ScriptPtr) == NULL)
&& (CMode || *ScriptPtr != ASCII_COMMENT)
&& !(ScriptPtr[0] == CPP_COMMENT && (ScriptPtr < ScriptEndPtr - 1) &&
(ScriptPtr[1] == CPP_COMMENT || ScriptPtr[1] == C_COMMENT)))
{
*text++ = *ScriptPtr++;
if (ScriptPtr == ScriptEndPtr
|| text == &sc_String[MAX_STRING_SIZE-1])
{
break;
}
}
}
}
gottoken:
*text = 0;
sc_StringLen = int(text - sc_String);
return true;
}
//==========================================================================
//
// SC_MustGetString
//
//==========================================================================
void SC_MustGetString (void)
{
if (SC_GetString () == false)
{
SC_ScriptError ("Missing string (unexpected end of file).");
}
}
//==========================================================================
//
// SC_MustGetStringName
//
//==========================================================================
void SC_MustGetStringName (const char *name)
{
SC_MustGetString ();
if (SC_Compare (name) == false)
{
SC_ScriptError ("Expected '%s', got '%s'.", name, sc_String);
}
}
//==========================================================================
//
// SC_CheckString
//
// Checks if the next token matches the specified string. Returns true if
// it does. If it doesn't, it ungets it and returns false.
//==========================================================================
bool SC_CheckString (const char *name)
{
if (SC_GetString ())
{
if (SC_Compare (name))
{
return true;
}
SC_UnGet ();
}
return false;
}
//==========================================================================
//
// SC_GetNumber
//
//==========================================================================
bool SC_GetNumber (void)
{
char *stopper;
CheckOpen ();
if (SC_GetString())
{
if (strcmp (sc_String, "MAXINT") == 0)
{
sc_Number = INT_MAX;
}
else
{
sc_Number = strtol (sc_String, &stopper, 0);
if (*stopper != 0)
{
SC_ScriptError ("SC_GetNumber: Bad numeric constant \"%s\".", sc_String);
}
}
sc_Float = sc_Number;
return true;
}
else
{
return false;
}
}
//==========================================================================
//
// SC_MustGetNumber
//
//==========================================================================
void SC_MustGetNumber (void)
{
if (SC_GetNumber() == false)
{
SC_ScriptError ("Missing integer (unexpected end of file).");
}
}
//==========================================================================
//
// SC_CheckNumber
// similar to SC_GetNumber but ungets the token if it isn't a number
// and does not print an error
//
//==========================================================================
bool SC_CheckNumber (void)
{
char *stopper;
//CheckOpen ();
if (SC_GetString())
{
if (strcmp (sc_String, "MAXINT") == 0)
{
sc_Number = INT_MAX;
}
else
{
sc_Number = strtol (sc_String, &stopper, 0);
if (*stopper != 0)
{
SC_UnGet();
return false;
}
}
sc_Float = sc_Number;
return true;
}
else
{
return false;
}
}
//==========================================================================
//
// SC_CheckFloat
// [GRB] Same as SC_CheckNumber, only for floats
//
//==========================================================================
bool SC_CheckFloat (void)
{
char *stopper;
//CheckOpen ();
if (SC_GetString())
{
sc_Float = strtod (sc_String, &stopper);
sc_Number = (int)sc_Float;
if (*stopper != 0)
{
SC_UnGet();
return false;
}
return true;
}
else
{
return false;
}
}
//==========================================================================
//
// SC_GetFloat
//
//==========================================================================
bool SC_GetFloat (void)
{
char *stopper;
CheckOpen ();
if (SC_GetString())
{
sc_Float = strtod (sc_String, &stopper);
if (*stopper != 0)
{
SC_ScriptError("SC_GetFloat: Bad numeric constant \"%s\".\n",sc_String);
}
sc_Number = (int)sc_Float;
return true;
}
else
{
return false;
}
}
//==========================================================================
//
// SC_MustGetFloat
//
//==========================================================================
void SC_MustGetFloat (void)
{
if (SC_GetFloat() == false)
{
SC_ScriptError ("Missing floating-point number (unexpected end of file).");
}
}
//==========================================================================
//
// SC_UnGet
//
// Assumes there is a valid string in sc_String.
//
//==========================================================================
void SC_UnGet (void)
{
AlreadyGot = true;
}
//==========================================================================
//
// SC_Check
//
// Returns true if another token is on the current line.
//
//==========================================================================
/*
bool SC_Check(void)
{
char *text;
CheckOpen();
text = ScriptPtr;
if(text >= ScriptEndPtr)
{
return false;
}
while(*text <= 32)
{
if(*text == '\n')
{
return false;
}
text++;
if(text == ScriptEndPtr)
{
return false;
}
}
if(*text == ASCII_COMMENT)
{
return false;
}
return true;
}
*/
//==========================================================================
//
// SC_MatchString
//
// Returns the index of the first match to sc_String from the passed
// array of strings, or -1 if not found.
//
//==========================================================================
int SC_MatchString (const char **strings)
{
int i;
for (i = 0; *strings != NULL; i++)
{
if (SC_Compare (*strings++))
{
return i;
}
}
return -1;
}
//==========================================================================
//
// SC_MustMatchString
//
//==========================================================================
int SC_MustMatchString (const char **strings)
{
int i;
i = SC_MatchString (strings);
if (i == -1)
{
SC_ScriptError (NULL);
}
return i;
}
//==========================================================================
//
// SC_Compare
//
//==========================================================================
bool SC_Compare (const char *text)
{
#ifdef _MSC_VER
return (_stricmp (text, sc_String) == 0);
#else
return (strcasecmp (text, sc_String) == 0);
#endif
}
//==========================================================================
//
// SC_ScriptError
//
//==========================================================================
void SC_ScriptError (const char *message, ...)
{
char composed[2048];
if (message == NULL)
{
message = "Bad syntax.";
}
va_list arglist;
va_start (arglist, message);
vsprintf (composed, message, arglist);
va_end (arglist);
printf ("Script error, line %d:\n%s\n", sc_Line, composed);
exit(1);
}
//==========================================================================
//
// CheckOpen
//
//==========================================================================
static void CheckOpen(void)
{
if (ScriptOpen == false)
{
printf ("SC_ call before SC_Open().\n");
exit(1);
}
}

42
src/parse/sc_man.h Normal file
View File

@ -0,0 +1,42 @@
#pragma once
void SC_Open (const char *name);
void SC_OpenFile (const char *name);
void SC_OpenMem (const char *name, char *buffer, int size);
void SC_OpenLumpNum (int lump, const char *name);
void SC_Close (void);
void SC_SetCMode (bool cmode);
void SC_SetEscape (bool esc);
void SC_SavePos (void);
void SC_RestorePos (void);
bool SC_GetString (void);
void SC_MustGetString (void);
void SC_MustGetStringName (const char *name);
bool SC_CheckString (const char *name);
bool SC_GetNumber (void);
void SC_MustGetNumber (void);
bool SC_CheckNumber (void);
bool SC_CheckFloat (void);
bool SC_GetFloat (void);
void SC_MustGetFloat (void);
void SC_UnGet (void);
//boolean SC_Check(void);
bool SC_Compare (const char *text);
int SC_MatchString (const char **strings);
int SC_MustMatchString (const char **strings);
void SC_ScriptError (const char *message, ...);
void SC_SaveScriptState();
void SC_RestoreScriptState();
extern char *sc_String;
extern int sc_StringLen;
extern int sc_Number;
extern double sc_Float;
extern int sc_Line;
extern bool sc_End;
extern bool sc_Crossed;
extern bool sc_FileScripts;
extern bool sc_StringQuoted;
extern char *sc_ScriptsDir;
//extern FILE *sc_Out;

View File

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

View File

@ -0,0 +1,138 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winresrc.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_MAPVIEW DIALOGEX 0, 0, 510, 446
STYLE DS_SETFONT | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
EXSTYLE WS_EX_APPWINDOW
CAPTION "ZDRay Map Viewer"
FONT 8, "MS Sans Serif", 0, 0, 0x0
BEGIN
CONTROL "Custom2",IDC_MAPVIEW,"MapViewer",WS_VSCROLL | WS_HSCROLL,7,7,496,411,WS_EX_CLIENTEDGE
PUSHBUTTON "OK",IDOK,7,423,53,16
LTEXT "Static",IDC_STATICNUMBER,68,425,60,14
COMBOBOX IDC_COMBO1,142,427,123,250,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_MAPVIEW, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 503
TOPMARGIN, 7
BOTTOMMARGIN, 439
END
END
#endif // APSTUDIO_INVOKED
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winresrc.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "FileDescription", "ZDRay Raytracer"
VALUE "FileVersion", "1.0"
VALUE "InternalName", "zdray"
VALUE "LegalCopyright", "Copyright (C) 2017 Magnus Norddahl, 2002-2016 Randy Heit, 2009 Christoph Oelckers"
VALUE "OriginalFilename", "zdray.exe"
VALUE "ProductName", "ZDRay"
VALUE "ProductVersion", "1.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

1074
src/viewer/view.cpp Normal file

File diff suppressed because it is too large Load Diff

485
src/wad/wad.cpp Normal file
View File

@ -0,0 +1,485 @@
/*
WAD-handling routines.
Copyright (C) 2002-2006 Randy Heit
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "wad.h"
static const char MapLumpNames[12][9] =
{
"THINGS",
"LINEDEFS",
"SIDEDEFS",
"VERTEXES",
"SEGS",
"SSECTORS",
"NODES",
"SECTORS",
"REJECT",
"BLOCKMAP",
"BEHAVIOR",
"SCRIPTS"
};
static const bool MapLumpRequired[12] =
{
true, // THINGS
true, // LINEDEFS
true, // SIDEDEFS
true, // VERTEXES
false, // SEGS
false, // SSECTORS
false, // NODES
true, // SECTORS
false, // REJECT
false, // BLOCKMAP
false, // BEHAVIOR
false // SCRIPTS
};
static const char GLLumpNames[5][9] =
{
"GL_VERT",
"GL_SEGS",
"GL_SSECT",
"GL_NODES",
"GL_PVS"
};
FWadReader::FWadReader (const char *filename)
: Lumps (NULL), File (NULL)
{
File = fopen (filename, "rb");
if (File == NULL)
{
throw std::runtime_error("Could not open input file");
}
SafeRead (&Header, sizeof(Header));
if (Header.Magic[0] != 'P' && Header.Magic[0] != 'I' &&
Header.Magic[1] != 'W' &&
Header.Magic[2] != 'A' &&
Header.Magic[3] != 'D')
{
fclose (File);
File = NULL;
throw std::runtime_error("Input file is not a wad");
}
Header.NumLumps = LittleLong(Header.NumLumps);
Header.Directory = LittleLong(Header.Directory);
if (fseek (File, Header.Directory, SEEK_SET))
{
throw std::runtime_error("Could not read wad directory");
}
Lumps = new WadLump[Header.NumLumps];
SafeRead (Lumps, Header.NumLumps * sizeof(*Lumps));
for (int i = 0; i < Header.NumLumps; ++i)
{
Lumps[i].FilePos = LittleLong(Lumps[i].FilePos);
Lumps[i].Size = LittleLong(Lumps[i].Size);
}
}
FWadReader::~FWadReader ()
{
if (File) fclose (File);
if (Lumps) delete[] Lumps;
}
bool FWadReader::IsIWAD () const
{
return Header.Magic[0] == 'I';
}
int FWadReader::NumLumps () const
{
return Header.NumLumps;
}
int FWadReader::FindLump (const char *name, int index) const
{
if (index < 0)
{
index = 0;
}
for (; index < Header.NumLumps; ++index)
{
if (strnicmp (Lumps[index].Name, name, 8) == 0)
{
return index;
}
}
return -1;
}
int FWadReader::FindMapLump (const char *name, int map) const
{
int i, j, k;
++map;
for (i = 0; i < 12; ++i)
{
if (strnicmp (MapLumpNames[i], name, 8) == 0)
{
break;
}
}
if (i == 12)
{
return -1;
}
for (j = k = 0; j < 12; ++j)
{
if (strnicmp (Lumps[map+k].Name, MapLumpNames[j], 8) == 0)
{
if (i == j)
{
return map+k;
}
k++;
}
}
return -1;
}
bool FWadReader::isUDMF (int index) const
{
index++;
if (strnicmp(Lumps[index].Name, "TEXTMAP", 8) == 0)
{
// UDMF map
return true;
}
return false;
}
bool FWadReader::IsMap (int index) const
{
int i, j;
if (isUDMF(index)) return true;
index++;
for (i = j = 0; i < 12; ++i)
{
if (strnicmp (Lumps[index+j].Name, MapLumpNames[i], 8) != 0)
{
if (MapLumpRequired[i])
{
return false;
}
}
else
{
j++;
}
}
return true;
}
int FWadReader::FindGLLump (const char *name, int glheader) const
{
int i, j, k;
++glheader;
for (i = 0; i < 5; ++i)
{
if (strnicmp (Lumps[glheader+i].Name, name, 8) == 0)
{
break;
}
}
if (i == 5)
{
return -1;
}
for (j = k = 0; j < 5; ++j)
{
if (strnicmp (Lumps[glheader+k].Name, GLLumpNames[j], 8) == 0)
{
if (i == j)
{
return glheader+k;
}
k++;
}
}
return -1;
}
bool FWadReader::IsGLNodes (int index) const
{
if (index + 4 >= Header.NumLumps)
{
return false;
}
if (Lumps[index].Name[0] != 'G' ||
Lumps[index].Name[1] != 'L' ||
Lumps[index].Name[2] != '_')
{
return false;
}
index++;
for (int i = 0; i < 4; ++i)
{
if (strnicmp (Lumps[i+index].Name, GLLumpNames[i], 8) != 0)
{
return false;
}
}
return true;
}
int FWadReader::SkipGLNodes (int index) const
{
index++;
for (int i = 0; i < 5 && index < Header.NumLumps; ++i, ++index)
{
if (strnicmp (Lumps[index].Name, GLLumpNames[i], 8) != 0)
{
break;
}
}
return index;
}
bool FWadReader::MapHasBehavior (int map) const
{
return FindMapLump ("BEHAVIOR", map) != -1;
}
int FWadReader::NextMap (int index) const
{
if (index < 0)
{
index = 0;
}
else
{
index++;
}
for (; index < Header.NumLumps; ++index)
{
if (IsMap (index))
{
return index;
}
}
return -1;
}
int FWadReader::LumpAfterMap (int i) const
{
int j, k;
if (isUDMF(i))
{
// UDMF map
i += 2;
while (strnicmp(Lumps[i].Name, "ENDMAP", 8) != 0 && i < Header.NumLumps)
{
i++;
}
return i+1; // one lump after ENDMAP
}
i++;
for (j = k = 0; j < 12; ++j)
{
if (strnicmp (Lumps[i+k].Name, MapLumpNames[j], 8) != 0)
{
if (MapLumpRequired[j])
{
break;
}
}
else
{
k++;
}
}
return i+k;
}
void FWadReader::SafeRead (void *buffer, size_t size)
{
if (fread (buffer, 1, size, File) != size)
{
throw std::runtime_error("Failed to read");
}
}
const char *FWadReader::LumpName (int lump)
{
static char name[9];
strncpy (name, Lumps[lump].Name, 8);
name[8] = 0;
return name;
}
FWadWriter::FWadWriter (const char *filename, bool iwad)
: File (NULL)
{
File = fopen (filename, "wb");
if (File == NULL)
{
throw std::runtime_error("Could not open output file");
}
WadHeader head;
if (iwad)
{
head.Magic[0] = 'I';
}
else
{
head.Magic[0] = 'P';
}
head.Magic[1] = 'W';
head.Magic[2] = 'A';
head.Magic[3] = 'D';
SafeWrite (&head, sizeof(head));
}
FWadWriter::~FWadWriter ()
{
if (File)
{
Close ();
}
}
void FWadWriter::Close ()
{
if (File)
{
int32_t head[2];
head[0] = LittleLong(Lumps.Size());
head[1] = LittleLong(ftell (File));
SafeWrite (&Lumps[0], sizeof(WadLump)*Lumps.Size());
fseek (File, 4, SEEK_SET);
SafeWrite (head, 8);
fclose (File);
File = NULL;
}
}
void FWadWriter::CreateLabel (const char *name)
{
WadLump lump;
strncpy (lump.Name, name, 8);
lump.FilePos = LittleLong(ftell (File));
lump.Size = 0;
Lumps.Push (lump);
}
void FWadWriter::WriteLump (const char *name, const void *data, int len)
{
WadLump lump;
strncpy (lump.Name, name, 8);
lump.FilePos = LittleLong(ftell (File));
lump.Size = LittleLong(len);
Lumps.Push (lump);
SafeWrite (data, len);
}
void FWadWriter::CopyLump (FWadReader &wad, int lump)
{
BYTE *data;
int size;
ReadLump<BYTE> (wad, lump, data, size);
if (data != NULL)
{
WriteLump (wad.LumpName (lump), data, size);
delete[] data;
}
}
void FWadWriter::StartWritingLump (const char *name)
{
CreateLabel (name);
}
void FWadWriter::AddToLump (const void *data, int len)
{
SafeWrite (data, len);
Lumps[Lumps.Size()-1].Size += len;
}
void FWadWriter::SafeWrite (const void *buffer, size_t size)
{
if (fwrite (buffer, 1, size, File) != size)
{
fclose (File);
File = NULL;
throw std::runtime_error(
"Failed to write. Check that this directory is writable and\n"
"that you have enough free disk space.");
}
}
FWadWriter &FWadWriter::operator << (BYTE val)
{
AddToLump (&val, 1);
return *this;
}
FWadWriter &FWadWriter::operator << (WORD val)
{
val = LittleShort(val);
AddToLump ((BYTE *)&val, 2);
return *this;
}
FWadWriter &FWadWriter::operator << (SWORD val)
{
val = LittleShort(val);
AddToLump ((BYTE *)&val, 2);
return *this;
}
FWadWriter &FWadWriter::operator << (DWORD val)
{
val = LittleLong(val);
AddToLump ((BYTE *)&val, 4);
return *this;
}
FWadWriter &FWadWriter::operator << (fixed_t val)
{
val = LittleLong(val);
AddToLump ((BYTE *)&val, 4);
return *this;
}

108
src/wad/wad.h Normal file
View File

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

21
zlib/CMakeLists.txt Normal file
View File

@ -0,0 +1,21 @@
cmake_minimum_required( VERSION 2.4 )
if( CMAKE_COMPILER_IS_GNUC )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fomit-frame-pointer" )
endif( CMAKE_COMPILER_IS_GNUC )
add_library( z
adler32.c
compress.c
crc32.c
deflate.c
trees.c
zutil.c
crc32.h
deflate.h
gzguts.h
trees.h
zconf.h
zlib.h
zutil.h )
target_link_libraries( z )

179
zlib/adler32.c Normal file
View File

@ -0,0 +1,179 @@
/* adler32.c -- compute the Adler-32 checksum of a data stream
* Copyright (C) 1995-2011 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
#include "zutil.h"
#define local static
local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));
#define BASE 65521 /* largest prime smaller than 65536 */
#define NMAX 5552
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
#define DO16(buf) DO8(buf,0); DO8(buf,8);
/* use NO_DIVIDE if your processor does not do division in hardware --
try it both ways to see which is faster */
#ifdef NO_DIVIDE
/* note that this assumes BASE is 65521, where 65536 % 65521 == 15
(thank you to John Reiser for pointing this out) */
# define CHOP(a) \
do { \
unsigned long tmp = a >> 16; \
a &= 0xffffUL; \
a += (tmp << 4) - tmp; \
} while (0)
# define MOD28(a) \
do { \
CHOP(a); \
if (a >= BASE) a -= BASE; \
} while (0)
# define MOD(a) \
do { \
CHOP(a); \
MOD28(a); \
} while (0)
# define MOD63(a) \
do { /* this assumes a is not negative */ \
z_off64_t tmp = a >> 32; \
a &= 0xffffffffL; \
a += (tmp << 8) - (tmp << 5) + tmp; \
tmp = a >> 16; \
a &= 0xffffL; \
a += (tmp << 4) - tmp; \
tmp = a >> 16; \
a &= 0xffffL; \
a += (tmp << 4) - tmp; \
if (a >= BASE) a -= BASE; \
} while (0)
#else
# define MOD(a) a %= BASE
# define MOD28(a) a %= BASE
# define MOD63(a) a %= BASE
#endif
/* ========================================================================= */
uLong ZEXPORT adler32(adler, buf, len)
uLong adler;
const Bytef *buf;
uInt len;
{
unsigned long sum2;
unsigned n;
/* split Adler-32 into component sums */
sum2 = (adler >> 16) & 0xffff;
adler &= 0xffff;
/* in case user likes doing a byte at a time, keep it fast */
if (len == 1) {
adler += buf[0];
if (adler >= BASE)
adler -= BASE;
sum2 += adler;
if (sum2 >= BASE)
sum2 -= BASE;
return adler | (sum2 << 16);
}
/* initial Adler-32 value (deferred check for len == 1 speed) */
if (buf == Z_NULL)
return 1L;
/* in case short lengths are provided, keep it somewhat fast */
if (len < 16) {
while (len--) {
adler += *buf++;
sum2 += adler;
}
if (adler >= BASE)
adler -= BASE;
MOD28(sum2); /* only added so many BASE's */
return adler | (sum2 << 16);
}
/* do length NMAX blocks -- requires just one modulo operation */
while (len >= NMAX) {
len -= NMAX;
n = NMAX / 16; /* NMAX is divisible by 16 */
do {
DO16(buf); /* 16 sums unrolled */
buf += 16;
} while (--n);
MOD(adler);
MOD(sum2);
}
/* do remaining bytes (less than NMAX, still just one modulo) */
if (len) { /* avoid modulos if none remaining */
while (len >= 16) {
len -= 16;
DO16(buf);
buf += 16;
}
while (len--) {
adler += *buf++;
sum2 += adler;
}
MOD(adler);
MOD(sum2);
}
/* return recombined sums */
return adler | (sum2 << 16);
}
/* ========================================================================= */
local uLong adler32_combine_(adler1, adler2, len2)
uLong adler1;
uLong adler2;
z_off64_t len2;
{
unsigned long sum1;
unsigned long sum2;
unsigned rem;
/* for negative len, return invalid adler32 as a clue for debugging */
if (len2 < 0)
return 0xffffffffUL;
/* the derivation of this formula is left as an exercise for the reader */
MOD63(len2); /* assumes len2 >= 0 */
rem = (unsigned)len2;
sum1 = adler1 & 0xffff;
sum2 = rem * sum1;
MOD(sum2);
sum1 += (adler2 & 0xffff) + BASE - 1;
sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
if (sum1 >= BASE) sum1 -= BASE;
if (sum1 >= BASE) sum1 -= BASE;
if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1);
if (sum2 >= BASE) sum2 -= BASE;
return sum1 | (sum2 << 16);
}
/* ========================================================================= */
uLong ZEXPORT adler32_combine(adler1, adler2, len2)
uLong adler1;
uLong adler2;
z_off_t len2;
{
return adler32_combine_(adler1, adler2, len2);
}
uLong ZEXPORT adler32_combine64(adler1, adler2, len2)
uLong adler1;
uLong adler2;
z_off64_t len2;
{
return adler32_combine_(adler1, adler2, len2);
}

80
zlib/compress.c Normal file
View File

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

425
zlib/crc32.c Normal file
View File

@ -0,0 +1,425 @@
/* crc32.c -- compute the CRC-32 of a data stream
* Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*
* Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
* CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
* tables for updating the shift register in one step with three exclusive-ors
* instead of four steps with four exclusive-ors. This results in about a
* factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
*/
/* @(#) $Id$ */
/*
Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore
protection on the static variables used to control the first-use generation
of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should
first call get_crc_table() to initialize the tables before allowing more than
one thread to use crc32().
DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h.
*/
#ifdef MAKECRCH
# include <stdio.h>
# ifndef DYNAMIC_CRC_TABLE
# define DYNAMIC_CRC_TABLE
# endif /* !DYNAMIC_CRC_TABLE */
#endif /* MAKECRCH */
#include "zutil.h" /* for STDC and FAR definitions */
#define local static
/* Definitions for doing the crc four data bytes at a time. */
#if !defined(NOBYFOUR) && defined(Z_U4)
# define BYFOUR
#endif
#ifdef BYFOUR
local unsigned long crc32_little OF((unsigned long,
const unsigned char FAR *, unsigned));
local unsigned long crc32_big OF((unsigned long,
const unsigned char FAR *, unsigned));
# define TBLS 8
#else
# define TBLS 1
#endif /* BYFOUR */
/* Local functions for crc concatenation */
local unsigned long gf2_matrix_times OF((unsigned long *mat,
unsigned long vec));
local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));
local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2));
#ifdef DYNAMIC_CRC_TABLE
local volatile int crc_table_empty = 1;
local z_crc_t FAR crc_table[TBLS][256];
local void make_crc_table OF((void));
#ifdef MAKECRCH
local void write_table OF((FILE *, const z_crc_t FAR *));
#endif /* MAKECRCH */
/*
Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
Polynomials over GF(2) are represented in binary, one bit per coefficient,
with the lowest powers in the most significant bit. Then adding polynomials
is just exclusive-or, and multiplying a polynomial by x is a right shift by
one. If we call the above polynomial p, and represent a byte as the
polynomial q, also with the lowest power in the most significant bit (so the
byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
where a mod b means the remainder after dividing a by b.
This calculation is done using the shift-register method of multiplying and
taking the remainder. The register is initialized to zero, and for each
incoming bit, x^32 is added mod p to the register if the bit is a one (where
x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
x (which is shifting right by one and adding x^32 mod p if the bit shifted
out is a one). We start with the highest power (least significant bit) of
q and repeat for all eight bits of q.
The first table is simply the CRC of all possible eight bit values. This is
all the information needed to generate CRCs on data a byte at a time for all
combinations of CRC register values and incoming bytes. The remaining tables
allow for word-at-a-time CRC calculation for both big-endian and little-
endian machines, where a word is four bytes.
*/
local void make_crc_table()
{
z_crc_t c;
int n, k;
z_crc_t poly; /* polynomial exclusive-or pattern */
/* terms of polynomial defining this crc (except x^32): */
static volatile int first = 1; /* flag to limit concurrent making */
static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
/* See if another task is already doing this (not thread-safe, but better
than nothing -- significantly reduces duration of vulnerability in
case the advice about DYNAMIC_CRC_TABLE is ignored) */
if (first) {
first = 0;
/* make exclusive-or pattern from polynomial (0xedb88320UL) */
poly = 0;
for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++)
poly |= (z_crc_t)1 << (31 - p[n]);
/* generate a crc for every 8-bit value */
for (n = 0; n < 256; n++) {
c = (z_crc_t)n;
for (k = 0; k < 8; k++)
c = c & 1 ? poly ^ (c >> 1) : c >> 1;
crc_table[0][n] = c;
}
#ifdef BYFOUR
/* generate crc for each value followed by one, two, and three zeros,
and then the byte reversal of those as well as the first table */
for (n = 0; n < 256; n++) {
c = crc_table[0][n];
crc_table[4][n] = ZSWAP32(c);
for (k = 1; k < 4; k++) {
c = crc_table[0][c & 0xff] ^ (c >> 8);
crc_table[k][n] = c;
crc_table[k + 4][n] = ZSWAP32(c);
}
}
#endif /* BYFOUR */
crc_table_empty = 0;
}
else { /* not first */
/* wait for the other guy to finish (not efficient, but rare) */
while (crc_table_empty)
;
}
#ifdef MAKECRCH
/* write out CRC tables to crc32.h */
{
FILE *out;
out = fopen("crc32.h", "w");
if (out == NULL) return;
fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
fprintf(out, "local const z_crc_t FAR ");
fprintf(out, "crc_table[TBLS][256] =\n{\n {\n");
write_table(out, crc_table[0]);
# ifdef BYFOUR
fprintf(out, "#ifdef BYFOUR\n");
for (k = 1; k < 8; k++) {
fprintf(out, " },\n {\n");
write_table(out, crc_table[k]);
}
fprintf(out, "#endif\n");
# endif /* BYFOUR */
fprintf(out, " }\n};\n");
fclose(out);
}
#endif /* MAKECRCH */
}
#ifdef MAKECRCH
local void write_table(out, table)
FILE *out;
const z_crc_t FAR *table;
{
int n;
for (n = 0; n < 256; n++)
fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ",
(unsigned long)(table[n]),
n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
}
#endif /* MAKECRCH */
#else /* !DYNAMIC_CRC_TABLE */
/* ========================================================================
* Tables of CRC-32s of all single-byte values, made by make_crc_table().
*/
#include "crc32.h"
#endif /* DYNAMIC_CRC_TABLE */
/* =========================================================================
* This function can be used by asm versions of crc32()
*/
const z_crc_t FAR * ZEXPORT get_crc_table()
{
#ifdef DYNAMIC_CRC_TABLE
if (crc_table_empty)
make_crc_table();
#endif /* DYNAMIC_CRC_TABLE */
return (const z_crc_t FAR *)crc_table;
}
/* ========================================================================= */
#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
/* ========================================================================= */
unsigned long ZEXPORT crc32(crc, buf, len)
unsigned long crc;
const unsigned char FAR *buf;
uInt len;
{
if (buf == Z_NULL) return 0UL;
#ifdef DYNAMIC_CRC_TABLE
if (crc_table_empty)
make_crc_table();
#endif /* DYNAMIC_CRC_TABLE */
#ifdef BYFOUR
if (sizeof(void *) == sizeof(ptrdiff_t)) {
z_crc_t endian;
endian = 1;
if (*((unsigned char *)(&endian)))
return crc32_little(crc, buf, len);
else
return crc32_big(crc, buf, len);
}
#endif /* BYFOUR */
crc = crc ^ 0xffffffffUL;
while (len >= 8) {
DO8;
len -= 8;
}
if (len) do {
DO1;
} while (--len);
return crc ^ 0xffffffffUL;
}
#ifdef BYFOUR
/* ========================================================================= */
#define DOLIT4 c ^= *buf4++; \
c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
/* ========================================================================= */
local unsigned long crc32_little(crc, buf, len)
unsigned long crc;
const unsigned char FAR *buf;
unsigned len;
{
register z_crc_t c;
register const z_crc_t FAR *buf4;
c = (z_crc_t)crc;
c = ~c;
while (len && ((ptrdiff_t)buf & 3)) {
c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
len--;
}
buf4 = (const z_crc_t FAR *)(const void FAR *)buf;
while (len >= 32) {
DOLIT32;
len -= 32;
}
while (len >= 4) {
DOLIT4;
len -= 4;
}
buf = (const unsigned char FAR *)buf4;
if (len) do {
c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
} while (--len);
c = ~c;
return (unsigned long)c;
}
/* ========================================================================= */
#define DOBIG4 c ^= *++buf4; \
c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
/* ========================================================================= */
local unsigned long crc32_big(crc, buf, len)
unsigned long crc;
const unsigned char FAR *buf;
unsigned len;
{
register z_crc_t c;
register const z_crc_t FAR *buf4;
c = ZSWAP32((z_crc_t)crc);
c = ~c;
while (len && ((ptrdiff_t)buf & 3)) {
c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
len--;
}
buf4 = (const z_crc_t FAR *)(const void FAR *)buf;
buf4--;
while (len >= 32) {
DOBIG32;
len -= 32;
}
while (len >= 4) {
DOBIG4;
len -= 4;
}
buf4++;
buf = (const unsigned char FAR *)buf4;
if (len) do {
c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
} while (--len);
c = ~c;
return (unsigned long)(ZSWAP32(c));
}
#endif /* BYFOUR */
#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */
/* ========================================================================= */
local unsigned long gf2_matrix_times(mat, vec)
unsigned long *mat;
unsigned long vec;
{
unsigned long sum;
sum = 0;
while (vec) {
if (vec & 1)
sum ^= *mat;
vec >>= 1;
mat++;
}
return sum;
}
/* ========================================================================= */
local void gf2_matrix_square(square, mat)
unsigned long *square;
unsigned long *mat;
{
int n;
for (n = 0; n < GF2_DIM; n++)
square[n] = gf2_matrix_times(mat, mat[n]);
}
/* ========================================================================= */
local uLong crc32_combine_(crc1, crc2, len2)
uLong crc1;
uLong crc2;
z_off64_t len2;
{
int n;
unsigned long row;
unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */
unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */
/* degenerate case (also disallow negative lengths) */
if (len2 <= 0)
return crc1;
/* put operator for one zero bit in odd */
odd[0] = 0xedb88320UL; /* CRC-32 polynomial */
row = 1;
for (n = 1; n < GF2_DIM; n++) {
odd[n] = row;
row <<= 1;
}
/* put operator for two zero bits in even */
gf2_matrix_square(even, odd);
/* put operator for four zero bits in odd */
gf2_matrix_square(odd, even);
/* apply len2 zeros to crc1 (first square will put the operator for one
zero byte, eight zero bits, in even) */
do {
/* apply zeros operator for this bit of len2 */
gf2_matrix_square(even, odd);
if (len2 & 1)
crc1 = gf2_matrix_times(even, crc1);
len2 >>= 1;
/* if no more bits set, then done */
if (len2 == 0)
break;
/* another iteration of the loop with odd and even swapped */
gf2_matrix_square(odd, even);
if (len2 & 1)
crc1 = gf2_matrix_times(odd, crc1);
len2 >>= 1;
/* if no more bits set, then done */
} while (len2 != 0);
/* return combined crc */
crc1 ^= crc2;
return crc1;
}
/* ========================================================================= */
uLong ZEXPORT crc32_combine(crc1, crc2, len2)
uLong crc1;
uLong crc2;
z_off_t len2;
{
return crc32_combine_(crc1, crc2, len2);
}
uLong ZEXPORT crc32_combine64(crc1, crc2, len2)
uLong crc1;
uLong crc2;
z_off64_t len2;
{
return crc32_combine_(crc1, crc2, len2);
}

441
zlib/crc32.h Normal file
View File

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

1965
zlib/deflate.c Normal file

File diff suppressed because it is too large Load Diff

346
zlib/deflate.h Normal file
View File

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

193
zlib/gzguts.h Normal file
View File

@ -0,0 +1,193 @@
/* gzguts.h -- zlib internal header definitions for gz* operations
* Copyright (C) 2004, 2005, 2010, 2011, 2012 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
#ifdef _LARGEFILE64_SOURCE
# ifndef _LARGEFILE_SOURCE
# define _LARGEFILE_SOURCE 1
# endif
# ifdef _FILE_OFFSET_BITS
# undef _FILE_OFFSET_BITS
# endif
#endif
#ifdef HAVE_HIDDEN
# define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
#else
# define ZLIB_INTERNAL
#endif
#include <stdio.h>
#include "zlib.h"
#ifdef STDC
# include <string.h>
# include <stdlib.h>
# include <limits.h>
#endif
#include <fcntl.h>
#ifdef _WIN32
# include <stddef.h>
#endif
#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32)
# include <io.h>
#endif
#ifdef NO_DEFLATE /* for compatibility with old definition */
# define NO_GZCOMPRESS
#endif
#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
# ifndef HAVE_VSNPRINTF
# define HAVE_VSNPRINTF
# endif
#endif
#if defined(__CYGWIN__)
# ifndef HAVE_VSNPRINTF
# define HAVE_VSNPRINTF
# endif
#endif
#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410)
# ifndef HAVE_VSNPRINTF
# define HAVE_VSNPRINTF
# endif
#endif
#ifndef HAVE_VSNPRINTF
# ifdef MSDOS
/* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
but for now we just assume it doesn't. */
# define NO_vsnprintf
# endif
# ifdef __TURBOC__
# define NO_vsnprintf
# endif
# ifdef WIN32
/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
# if !defined(vsnprintf) && !defined(NO_vsnprintf)
# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 )
# define vsnprintf _vsnprintf
# endif
# endif
# endif
# ifdef __SASC
# define NO_vsnprintf
# endif
# ifdef VMS
# define NO_vsnprintf
# endif
# ifdef __OS400__
# define NO_vsnprintf
# endif
# ifdef __MVS__
# define NO_vsnprintf
# endif
#endif
#ifndef local
# define local static
#endif
/* compile with -Dlocal if your debugger can't find static symbols */
/* gz* functions always use library allocation functions */
#ifndef STDC
extern voidp malloc OF((uInt size));
extern void free OF((voidpf ptr));
#endif
/* get errno and strerror definition */
#if defined UNDER_CE
# include <windows.h>
# define zstrerror() gz_strwinerror((DWORD)GetLastError())
#else
# ifndef NO_STRERROR
# include <errno.h>
# define zstrerror() strerror(errno)
# else
# define zstrerror() "stdio error (consult errno)"
# endif
#endif
/* provide prototypes for these when building zlib without LFS */
#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0
ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
#endif
/* default memLevel */
#if MAX_MEM_LEVEL >= 8
# define DEF_MEM_LEVEL 8
#else
# define DEF_MEM_LEVEL MAX_MEM_LEVEL
#endif
/* default i/o buffer size -- double this for output when reading */
#define GZBUFSIZE 8192
/* gzip modes, also provide a little integrity check on the passed structure */
#define GZ_NONE 0
#define GZ_READ 7247
#define GZ_WRITE 31153
#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */
/* values for gz_state how */
#define LOOK 0 /* look for a gzip header */
#define COPY 1 /* copy input directly */
#define GZIP 2 /* decompress a gzip stream */
/* internal gzip file state data structure */
typedef struct {
/* exposed contents for gzgetc() macro */
struct gzFile_s x; /* "x" for exposed */
/* x.have: number of bytes available at x.next */
/* x.next: next output data to deliver or write */
/* x.pos: current position in uncompressed data */
/* used for both reading and writing */
int mode; /* see gzip modes above */
int fd; /* file descriptor */
char *path; /* path or fd for error messages */
unsigned size; /* buffer size, zero if not allocated yet */
unsigned want; /* requested buffer size, default is GZBUFSIZE */
unsigned char *in; /* input buffer */
unsigned char *out; /* output buffer (double-sized when reading) */
int direct; /* 0 if processing gzip, 1 if transparent */
/* just for reading */
int how; /* 0: get header, 1: copy, 2: decompress */
z_off64_t start; /* where the gzip data started, for rewinding */
int eof; /* true if end of input file reached */
int past; /* true if read requested past end */
/* just for writing */
int level; /* compression level */
int strategy; /* compression strategy */
/* seek request */
z_off64_t skip; /* amount to skip (already rewound if backwards) */
int seek; /* true if seek request pending */
/* error information */
int err; /* error code */
char *msg; /* error message */
/* zlib inflate or deflate stream */
z_stream strm; /* stream structure in-place (not a pointer) */
} gz_state;
typedef gz_state FAR *gz_statep;
/* shared functions */
void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *));
#if defined UNDER_CE
char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error));
#endif
/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t
value -- needed when comparing unsigned to z_off64_t, which is signed
(possible z_off64_t types off_t, off64_t, and long are all signed) */
#ifdef INT_MAX
# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX)
#else
unsigned ZLIB_INTERNAL gz_intmax OF((void));
# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax())
#endif

1224
zlib/trees.c Normal file

File diff suppressed because it is too large Load Diff

128
zlib/trees.h Normal file
View File

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

506
zlib/zconf.h Normal file
View File

@ -0,0 +1,506 @@
/* zconf.h -- configuration of the zlib compression library
* Copyright (C) 1995-2012 Jean-loup Gailly.
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
#ifndef ZCONF_H
#define ZCONF_H
/*
* If you *really* need a unique prefix for all types and library functions,
* compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
* Even better than compiling with -DZ_PREFIX would be to use configure to set
* this permanently in zconf.h using "./configure --zprefix".
*/
#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */
# define Z_PREFIX_SET
/* all linked symbols */
# define _dist_code z__dist_code
# define _length_code z__length_code
# define _tr_align z__tr_align
# define _tr_flush_block z__tr_flush_block
# define _tr_init z__tr_init
# define _tr_stored_block z__tr_stored_block
# define _tr_tally z__tr_tally
# define adler32 z_adler32
# define adler32_combine z_adler32_combine
# define adler32_combine64 z_adler32_combine64
# ifndef Z_SOLO
# define compress z_compress
# define compress2 z_compress2
# define compressBound z_compressBound
# endif
# define crc32 z_crc32
# define crc32_combine z_crc32_combine
# define crc32_combine64 z_crc32_combine64
# define deflate z_deflate
# define deflateBound z_deflateBound
# define deflateCopy z_deflateCopy
# define deflateEnd z_deflateEnd
# define deflateInit2_ z_deflateInit2_
# define deflateInit_ z_deflateInit_
# define deflateParams z_deflateParams
# define deflatePending z_deflatePending
# define deflatePrime z_deflatePrime
# define deflateReset z_deflateReset
# define deflateResetKeep z_deflateResetKeep
# define deflateSetDictionary z_deflateSetDictionary
# define deflateSetHeader z_deflateSetHeader
# define deflateTune z_deflateTune
# define deflate_copyright z_deflate_copyright
# define get_crc_table z_get_crc_table
# ifndef Z_SOLO
# define gz_error z_gz_error
# define gz_intmax z_gz_intmax
# define gz_strwinerror z_gz_strwinerror
# define gzbuffer z_gzbuffer
# define gzclearerr z_gzclearerr
# define gzclose z_gzclose
# define gzclose_r z_gzclose_r
# define gzclose_w z_gzclose_w
# define gzdirect z_gzdirect
# define gzdopen z_gzdopen
# define gzeof z_gzeof
# define gzerror z_gzerror
# define gzflush z_gzflush
# define gzgetc z_gzgetc
# define gzgetc_ z_gzgetc_
# define gzgets z_gzgets
# define gzoffset z_gzoffset
# define gzoffset64 z_gzoffset64
# define gzopen z_gzopen
# define gzopen64 z_gzopen64
# ifdef _WIN32
# define gzopen_w z_gzopen_w
# endif
# define gzprintf z_gzprintf
# define gzputc z_gzputc
# define gzputs z_gzputs
# define gzread z_gzread
# define gzrewind z_gzrewind
# define gzseek z_gzseek
# define gzseek64 z_gzseek64
# define gzsetparams z_gzsetparams
# define gztell z_gztell
# define gztell64 z_gztell64
# define gzungetc z_gzungetc
# define gzwrite z_gzwrite
# endif
# define inflate z_inflate
# define inflateBack z_inflateBack
# define inflateBackEnd z_inflateBackEnd
# define inflateBackInit_ z_inflateBackInit_
# define inflateCopy z_inflateCopy
# define inflateEnd z_inflateEnd
# define inflateGetHeader z_inflateGetHeader
# define inflateInit2_ z_inflateInit2_
# define inflateInit_ z_inflateInit_
# define inflateMark z_inflateMark
# define inflatePrime z_inflatePrime
# define inflateReset z_inflateReset
# define inflateReset2 z_inflateReset2
# define inflateSetDictionary z_inflateSetDictionary
# define inflateSync z_inflateSync
# define inflateSyncPoint z_inflateSyncPoint
# define inflateUndermine z_inflateUndermine
# define inflateResetKeep z_inflateResetKeep
# define inflate_copyright z_inflate_copyright
# define inflate_fast z_inflate_fast
# define inflate_table z_inflate_table
# ifndef Z_SOLO
# define uncompress z_uncompress
# endif
# define zError z_zError
# ifndef Z_SOLO
# define zcalloc z_zcalloc
# define zcfree z_zcfree
# endif
# define zlibCompileFlags z_zlibCompileFlags
# define zlibVersion z_zlibVersion
/* all zlib typedefs in zlib.h and zconf.h */
# define Byte z_Byte
# define Bytef z_Bytef
# define alloc_func z_alloc_func
# define charf z_charf
# define free_func z_free_func
# ifndef Z_SOLO
# define gzFile z_gzFile
# endif
# define gz_header z_gz_header
# define gz_headerp z_gz_headerp
# define in_func z_in_func
# define intf z_intf
# define out_func z_out_func
# define uInt z_uInt
# define uIntf z_uIntf
# define uLong z_uLong
# define uLongf z_uLongf
# define voidp z_voidp
# define voidpc z_voidpc
# define voidpf z_voidpf
/* all zlib structs in zlib.h and zconf.h */
# define gz_header_s z_gz_header_s
# define internal_state z_internal_state
#endif
#if defined(__MSDOS__) && !defined(MSDOS)
# define MSDOS
#endif
#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
# define OS2
#endif
#if defined(_WINDOWS) && !defined(WINDOWS)
# define WINDOWS
#endif
#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
# ifndef WIN32
# define WIN32
# endif
#endif
#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
# ifndef SYS16BIT
# define SYS16BIT
# endif
# endif
#endif
/*
* Compile with -DMAXSEG_64K if the alloc function cannot allocate more
* than 64k bytes at a time (needed on systems with 16-bit int).
*/
#ifdef SYS16BIT
# define MAXSEG_64K
#endif
#ifdef MSDOS
# define UNALIGNED_OK
#endif
#ifdef __STDC_VERSION__
# ifndef STDC
# define STDC
# endif
# if __STDC_VERSION__ >= 199901L
# ifndef STDC99
# define STDC99
# endif
# endif
#endif
#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
# define STDC
#endif
#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
# define STDC
#endif
#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
# define STDC
#endif
#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
# define STDC
#endif
#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
# define STDC
#endif
#ifndef STDC
# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
# define const /* note: need a more gentle solution here */
# endif
#endif
#if defined(ZLIB_CONST) && !defined(z_const)
# define z_const const
#else
# define z_const
#endif
/* Some Mac compilers merge all .h files incorrectly: */
#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
# define NO_DUMMY_DECL
#endif
/* Maximum value for memLevel in deflateInit2 */
#ifndef MAX_MEM_LEVEL
# ifdef MAXSEG_64K
# define MAX_MEM_LEVEL 8
# else
# define MAX_MEM_LEVEL 9
# endif
#endif
/* Maximum value for windowBits in deflateInit2 and inflateInit2.
* WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
* created by gzip. (Files created by minigzip can still be extracted by
* gzip.)
*/
#ifndef MAX_WBITS
# define MAX_WBITS 15 /* 32K LZ77 window */
#endif
/* The memory requirements for deflate are (in bytes):
(1 << (windowBits+2)) + (1 << (memLevel+9))
that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
plus a few kilobytes for small objects. For example, if you want to reduce
the default memory requirements from 256K to 128K, compile with
make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
Of course this will generally degrade compression (there's no free lunch).
The memory requirements for inflate are (in bytes) 1 << windowBits
that is, 32K for windowBits=15 (default value) plus a few kilobytes
for small objects.
*/
/* Type declarations */
#ifndef OF /* function prototypes */
# ifdef STDC
# define OF(args) args
# else
# define OF(args) ()
# endif
#endif
#ifndef Z_ARG /* function prototypes for stdarg */
# if defined(STDC) || defined(Z_HAVE_STDARG_H)
# define Z_ARG(args) args
# else
# define Z_ARG(args) ()
# endif
#endif
/* The following definitions for FAR are needed only for MSDOS mixed
* model programming (small or medium model with some far allocations).
* This was tested only with MSC; for other MSDOS compilers you may have
* to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
* just define FAR to be empty.
*/
#ifdef SYS16BIT
# if defined(M_I86SM) || defined(M_I86MM)
/* MSC small or medium model */
# define SMALL_MEDIUM
# ifdef _MSC_VER
# define FAR _far
# else
# define FAR far
# endif
# endif
# if (defined(__SMALL__) || defined(__MEDIUM__))
/* Turbo C small or medium model */
# define SMALL_MEDIUM
# ifdef __BORLANDC__
# define FAR _far
# else
# define FAR far
# endif
# endif
#endif
#if defined(WINDOWS) || defined(WIN32)
/* If building or using zlib as a DLL, define ZLIB_DLL.
* This is not mandatory, but it offers a little performance increase.
*/
# ifdef ZLIB_DLL
# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
# ifdef ZLIB_INTERNAL
# define ZEXTERN extern __declspec(dllexport)
# else
# define ZEXTERN extern __declspec(dllimport)
# endif
# endif
# endif /* ZLIB_DLL */
/* If building or using zlib with the WINAPI/WINAPIV calling convention,
* define ZLIB_WINAPI.
* Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
*/
# ifdef ZLIB_WINAPI
# ifdef FAR
# undef FAR
# endif
# include <windows.h>
/* No need for _export, use ZLIB.DEF instead. */
/* For complete Windows compatibility, use WINAPI, not __stdcall. */
# define ZEXPORT WINAPI
# ifdef WIN32
# define ZEXPORTVA WINAPIV
# else
# define ZEXPORTVA FAR CDECL
# endif
# endif
#endif
#if defined (__BEOS__)
# ifdef ZLIB_DLL
# ifdef ZLIB_INTERNAL
# define ZEXPORT __declspec(dllexport)
# define ZEXPORTVA __declspec(dllexport)
# else
# define ZEXPORT __declspec(dllimport)
# define ZEXPORTVA __declspec(dllimport)
# endif
# endif
#endif
#ifndef ZEXTERN
# define ZEXTERN extern
#endif
#ifndef ZEXPORT
# define ZEXPORT
#endif
#ifndef ZEXPORTVA
# define ZEXPORTVA
#endif
#ifndef FAR
# define FAR
#endif
#if !defined(__MACTYPES__)
typedef unsigned char Byte; /* 8 bits */
#endif
typedef unsigned int uInt; /* 16 bits or more */
typedef unsigned long uLong; /* 32 bits or more */
#ifdef SMALL_MEDIUM
/* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
# define Bytef Byte FAR
#else
typedef Byte FAR Bytef;
#endif
typedef char FAR charf;
typedef int FAR intf;
typedef uInt FAR uIntf;
typedef uLong FAR uLongf;
#ifdef STDC
typedef void const *voidpc;
typedef void FAR *voidpf;
typedef void *voidp;
#else
typedef Byte const *voidpc;
typedef Byte FAR *voidpf;
typedef Byte *voidp;
#endif
/* ./configure may #define Z_U4 here */
#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
# include <limits.h>
# if (UINT_MAX == 0xffffffffUL)
# define Z_U4 unsigned
# else
# if (ULONG_MAX == 0xffffffffUL)
# define Z_U4 unsigned long
# else
# if (USHRT_MAX == 0xffffffffUL)
# define Z_U4 unsigned short
# endif
# endif
# endif
#endif
#ifdef Z_U4
typedef Z_U4 z_crc_t;
#else
typedef unsigned long z_crc_t;
#endif
#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */
# define Z_HAVE_UNISTD_H
#endif
#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */
# define Z_HAVE_STDARG_H
#endif
#ifdef STDC
# ifndef Z_SOLO
# include <sys/types.h> /* for off_t */
# endif
#endif
#ifdef _WIN32
# include <stddef.h> /* for wchar_t */
#endif
/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
* "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
* though the former does not conform to the LFS document), but considering
* both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
* equivalently requesting no 64-bit operations
*/
#if defined(LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
# undef _LARGEFILE64_SOURCE
#endif
#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
# define Z_HAVE_UNISTD_H
#endif
#ifndef Z_SOLO
# if defined(Z_HAVE_UNISTD_H) || defined(LARGEFILE64_SOURCE)
# include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
# ifdef VMS
# include <unixio.h> /* for off_t */
# endif
# ifndef z_off_t
# define z_off_t off_t
# endif
# endif
#endif
#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0
# define Z_LFS64
#endif
#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
# define Z_LARGE64
#endif
#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)
# define Z_WANT64
#endif
#if !defined(SEEK_SET) && !defined(Z_SOLO)
# define SEEK_SET 0 /* Seek from beginning of file. */
# define SEEK_CUR 1 /* Seek from current position. */
# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
#endif
#ifndef z_off_t
# define z_off_t long
#endif
#if !defined(_WIN32) && defined(Z_LARGE64)
# define z_off64_t off64_t
#else
# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
# define z_off64_t __int64
# else
# define z_off64_t z_off_t
# endif
#endif
/* MVS linker does not support external names larger than 8 bytes */
#if defined(__MVS__)
#pragma map(deflateInit_,"DEIN")
#pragma map(deflateInit2_,"DEIN2")
#pragma map(deflateEnd,"DEEND")
#pragma map(deflateBound,"DEBND")
#pragma map(inflateInit_,"ININ")
#pragma map(inflateInit2_,"ININ2")
#pragma map(inflateEnd,"INEND")
#pragma map(inflateSync,"INSY")
#pragma map(inflateSetDictionary,"INSEDI")
#pragma map(compressBound,"CMBND")
#pragma map(inflate_table,"INTABL")
#pragma map(inflate_fast,"INFA")
#pragma map(inflate_copyright,"INCOPY")
#endif
#endif /* ZCONF_H */

1744
zlib/zlib.h Normal file

File diff suppressed because it is too large Load Diff

324
zlib/zutil.c Normal file
View File

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

252
zlib/zutil.h Normal file
View File

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