From 14c4952d8db858b81977154342894de90487aaae Mon Sep 17 00:00:00 2001 From: Paolo Cignoni cignoni Date: Fri, 9 Sep 2011 14:39:03 +0000 Subject: [PATCH] Added OpenCTM to the external libraries --- src/external/OpenCTM-1.0.3/COMPILING.txt | 100 + src/external/OpenCTM-1.0.3/LICENSE.txt | 20 + src/external/OpenCTM-1.0.3/Makefile.linux | 65 + src/external/OpenCTM-1.0.3/Makefile.macosx | 64 + src/external/OpenCTM-1.0.3/Makefile.mingw | 45 + src/external/OpenCTM-1.0.3/Makefile.msvc | 45 + src/external/OpenCTM-1.0.3/README.txt | 152 ++ .../doc/APIReference/annotated.html | 38 + .../classCTMexporter-members.html | 51 + .../doc/APIReference/classCTMexporter.html | 508 ++++ .../classCTMimporter-members.html | 51 + .../doc/APIReference/classCTMimporter.html | 476 ++++ .../APIReference/classctm__error-members.html | 37 + .../doc/APIReference/classctm__error.html | 106 + .../doc/APIReference/classes.html | 37 + .../doc/APIReference/doxygen.css | 498 ++++ .../doc/APIReference/doxygen.png | Bin 0 -> 1281 bytes .../OpenCTM-1.0.3/doc/APIReference/files.html | 37 + .../doc/APIReference/functions.html | 216 ++ .../doc/APIReference/functions_func.html | 216 ++ .../doc/APIReference/globals.html | 313 +++ .../doc/APIReference/globals_defs.html | 54 + .../doc/APIReference/globals_enum.html | 48 + .../doc/APIReference/globals_eval.html | 193 ++ .../doc/APIReference/globals_func.html | 135 + .../doc/APIReference/globals_type.html | 63 + .../OpenCTM-1.0.3/doc/APIReference/index.html | 93 + .../doc/APIReference/openctm_8h.html | 1738 +++++++++++++ .../doc/APIReference/openctm_8h_source.html | 287 +++ .../doc/APIReference/openctmpp_8h.html | 46 + .../doc/APIReference/openctmpp_8h_source.html | 333 +++ .../OpenCTM-1.0.3/doc/APIReference/tab_b.gif | Bin 0 -> 35 bytes .../OpenCTM-1.0.3/doc/APIReference/tab_l.gif | Bin 0 -> 706 bytes .../OpenCTM-1.0.3/doc/APIReference/tab_r.gif | Bin 0 -> 2585 bytes .../OpenCTM-1.0.3/doc/APIReference/tabs.css | 105 + .../OpenCTM-1.0.3/doc/DevelopersManual.pdf | Bin 0 -> 174834 bytes .../OpenCTM-1.0.3/doc/FormatSpecification.pdf | Bin 0 -> 126994 bytes src/external/OpenCTM-1.0.3/doc/ctmconv.1 | 92 + src/external/OpenCTM-1.0.3/doc/ctmviewer.1 | 86 + src/external/OpenCTM-1.0.3/lib/Makefile.linux | 81 + .../OpenCTM-1.0.3/lib/Makefile.macosx | 86 + src/external/OpenCTM-1.0.3/lib/Makefile.mingw | 87 + src/external/OpenCTM-1.0.3/lib/Makefile.msvc | 103 + src/external/OpenCTM-1.0.3/lib/compressMG1.c | 324 +++ src/external/OpenCTM-1.0.3/lib/compressMG2.c | 1319 ++++++++++ src/external/OpenCTM-1.0.3/lib/compressRAW.c | 181 ++ src/external/OpenCTM-1.0.3/lib/internal.h | 147 ++ .../OpenCTM-1.0.3/lib/liblzma/Alloc.c | 127 + .../OpenCTM-1.0.3/lib/liblzma/Alloc.h | 34 + .../OpenCTM-1.0.3/lib/liblzma/LzFind.c | 751 ++++++ .../OpenCTM-1.0.3/lib/liblzma/LzFind.h | 107 + .../OpenCTM-1.0.3/lib/liblzma/LzHash.h | 54 + .../OpenCTM-1.0.3/lib/liblzma/LzmaDec.c | 1007 ++++++++ .../OpenCTM-1.0.3/lib/liblzma/LzmaDec.h | 223 ++ .../OpenCTM-1.0.3/lib/liblzma/LzmaEnc.c | 2281 +++++++++++++++++ .../OpenCTM-1.0.3/lib/liblzma/LzmaEnc.h | 72 + .../OpenCTM-1.0.3/lib/liblzma/LzmaLib.c | 48 + .../OpenCTM-1.0.3/lib/liblzma/LzmaLib.h | 136 + .../OpenCTM-1.0.3/lib/liblzma/NameMangle.h | 84 + .../OpenCTM-1.0.3/lib/liblzma/Types.h | 210 ++ .../OpenCTM-1.0.3/lib/liblzma/readme.txt | 7 + .../OpenCTM-1.0.3/lib/openctm-mingw1.def | 32 + .../OpenCTM-1.0.3/lib/openctm-mingw2.def | 32 + .../OpenCTM-1.0.3/lib/openctm-msvc.def | 32 + src/external/OpenCTM-1.0.3/lib/openctm.c | 1423 ++++++++++ src/external/OpenCTM-1.0.3/lib/openctm.h | 655 +++++ src/external/OpenCTM-1.0.3/lib/openctm.rc | 26 + src/external/OpenCTM-1.0.3/lib/openctmpp.h | 377 +++ src/external/OpenCTM-1.0.3/lib/stream.c | 512 ++++ src/external/lib/macx/libopenctm.a | Bin 0 -> 104656 bytes 70 files changed, 16906 insertions(+) create mode 100644 src/external/OpenCTM-1.0.3/COMPILING.txt create mode 100644 src/external/OpenCTM-1.0.3/LICENSE.txt create mode 100644 src/external/OpenCTM-1.0.3/Makefile.linux create mode 100644 src/external/OpenCTM-1.0.3/Makefile.macosx create mode 100644 src/external/OpenCTM-1.0.3/Makefile.mingw create mode 100644 src/external/OpenCTM-1.0.3/Makefile.msvc create mode 100644 src/external/OpenCTM-1.0.3/README.txt create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/annotated.html create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/classCTMexporter-members.html create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/classCTMexporter.html create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/classCTMimporter-members.html create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/classCTMimporter.html create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/classctm__error-members.html create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/classctm__error.html create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/classes.html create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/doxygen.css create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/doxygen.png create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/files.html create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/functions.html create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/functions_func.html create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/globals.html create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/globals_defs.html create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/globals_enum.html create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/globals_eval.html create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/globals_func.html create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/globals_type.html create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/index.html create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/openctm_8h.html create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/openctm_8h_source.html create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/openctmpp_8h.html create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/openctmpp_8h_source.html create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/tab_b.gif create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/tab_l.gif create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/tab_r.gif create mode 100644 src/external/OpenCTM-1.0.3/doc/APIReference/tabs.css create mode 100644 src/external/OpenCTM-1.0.3/doc/DevelopersManual.pdf create mode 100644 src/external/OpenCTM-1.0.3/doc/FormatSpecification.pdf create mode 100644 src/external/OpenCTM-1.0.3/doc/ctmconv.1 create mode 100644 src/external/OpenCTM-1.0.3/doc/ctmviewer.1 create mode 100644 src/external/OpenCTM-1.0.3/lib/Makefile.linux create mode 100644 src/external/OpenCTM-1.0.3/lib/Makefile.macosx create mode 100644 src/external/OpenCTM-1.0.3/lib/Makefile.mingw create mode 100644 src/external/OpenCTM-1.0.3/lib/Makefile.msvc create mode 100644 src/external/OpenCTM-1.0.3/lib/compressMG1.c create mode 100644 src/external/OpenCTM-1.0.3/lib/compressMG2.c create mode 100644 src/external/OpenCTM-1.0.3/lib/compressRAW.c create mode 100644 src/external/OpenCTM-1.0.3/lib/internal.h create mode 100644 src/external/OpenCTM-1.0.3/lib/liblzma/Alloc.c create mode 100644 src/external/OpenCTM-1.0.3/lib/liblzma/Alloc.h create mode 100644 src/external/OpenCTM-1.0.3/lib/liblzma/LzFind.c create mode 100644 src/external/OpenCTM-1.0.3/lib/liblzma/LzFind.h create mode 100644 src/external/OpenCTM-1.0.3/lib/liblzma/LzHash.h create mode 100644 src/external/OpenCTM-1.0.3/lib/liblzma/LzmaDec.c create mode 100644 src/external/OpenCTM-1.0.3/lib/liblzma/LzmaDec.h create mode 100644 src/external/OpenCTM-1.0.3/lib/liblzma/LzmaEnc.c create mode 100644 src/external/OpenCTM-1.0.3/lib/liblzma/LzmaEnc.h create mode 100644 src/external/OpenCTM-1.0.3/lib/liblzma/LzmaLib.c create mode 100644 src/external/OpenCTM-1.0.3/lib/liblzma/LzmaLib.h create mode 100644 src/external/OpenCTM-1.0.3/lib/liblzma/NameMangle.h create mode 100644 src/external/OpenCTM-1.0.3/lib/liblzma/Types.h create mode 100644 src/external/OpenCTM-1.0.3/lib/liblzma/readme.txt create mode 100644 src/external/OpenCTM-1.0.3/lib/openctm-mingw1.def create mode 100644 src/external/OpenCTM-1.0.3/lib/openctm-mingw2.def create mode 100644 src/external/OpenCTM-1.0.3/lib/openctm-msvc.def create mode 100644 src/external/OpenCTM-1.0.3/lib/openctm.c create mode 100644 src/external/OpenCTM-1.0.3/lib/openctm.h create mode 100644 src/external/OpenCTM-1.0.3/lib/openctm.rc create mode 100644 src/external/OpenCTM-1.0.3/lib/openctmpp.h create mode 100644 src/external/OpenCTM-1.0.3/lib/stream.c create mode 100644 src/external/lib/macx/libopenctm.a diff --git a/src/external/OpenCTM-1.0.3/COMPILING.txt b/src/external/OpenCTM-1.0.3/COMPILING.txt new file mode 100644 index 000000000..065e932fc --- /dev/null +++ b/src/external/OpenCTM-1.0.3/COMPILING.txt @@ -0,0 +1,100 @@ +1. PREREQUISITES +================ + +In order to compile the OpenCTM shared library, all you need is a supported +compiler and it should compile right out of the box. + +In order to compile the entire OpenCTM package, including documentation and the +tools, there are some extra dependencies: + +- To build all the tools, you need GLUT, and for Un*x/X11 you also need + GTK+ 2.0 (Ubuntu: sudo apt-get install libgtk2.0-dev). + +- To build the documentation you need Doxygen (www.doxygen.org), a full + LaTeX installation (see TeX Live - http://www.tug.org/texlive/), and Groff + (Windows: http://gnuwin32.sourceforge.net/packages/groff.htm, + Mac OS X: preinstalled, Ubuntu: sudo apt-get install groff). + + +2. COMPILING +============ + +There are a few makefiles for different systems and compilers. Just pick the +one that fits your system, and run "make" on the corresponding file. Here are +a few specific instructions: + + +2.1 Windows, MinGW32 +-------------------- + +mingw32-make -f Makefile.mingw + + +2.2 Windows, MS Visual Studio (Express) 2008 +-------------------------------------------- + +nmake /f Makefile.msvc + + +2.3 Mac OS X +------------ + +make -f Makefile.macosx + + +2.4 Linux +--------- + +make -f Makefile.linux + + +2.5 OpenSolaris +--------------- + +gmake -f Makefile.linux + + +3. BUILD TARGETS +================ + +By default, the OpenCTM shared library and the OpenCTM tools are compiled when +make is run. To select what is built, use one of the following build targets +(just append it to the end of the make command line): + + openctm (the shared library) + toolset (the tools) + documentation (the HTML and PDF documentation) + all (openctm + toolset + documentation) + clean (clean all the built files - start from scratch) + +For instance, to just build the OpenCTM shared library under Windows with +MS Visual Studio, type: + + nmake /f Makefile.msvc openctm + + +4. INSTALLATION +=============== + +For Linux and Mac OS X, it is possible to make a system wide installation by +using the "install" build target. The installation process will install the +following: + + - OpenCTM shared library + - OpenCTM C/C++ headers (inlcude files) + - ctmconv and ctmviewer tools + - Man pages + +Just make sure that the Makefile contains the correct (and desired) +installation paths. Also, you need to have root privileges to make a system +wide installation. + +For instance, to compile and install OpenCTM under Ubuntu, do: + +make -f Makefile.linux +sudo make -f Makefile.linux install + +...and to compile and install OpenCTM under Mac OS X, do: + +make -f Makefile.macosx +sudo make -f Makefile.macosx install diff --git a/src/external/OpenCTM-1.0.3/LICENSE.txt b/src/external/OpenCTM-1.0.3/LICENSE.txt new file mode 100644 index 000000000..0e66fa76e --- /dev/null +++ b/src/external/OpenCTM-1.0.3/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright (c) 2009-2010 Marcus Geelnard + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not + be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. diff --git a/src/external/OpenCTM-1.0.3/Makefile.linux b/src/external/OpenCTM-1.0.3/Makefile.linux new file mode 100644 index 000000000..24ca13753 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/Makefile.linux @@ -0,0 +1,65 @@ +############################################################################### +# Product: OpenCTM +# File: Makefile.linux +# Description: Top level makefile for Linux systems (should work on most +# Un*x-like systems with gcc, e.g. OpenSolaris). +############################################################################### +# Copyright (c) 2009 Marcus Geelnard +# +# This software is provided 'as-is', without any express or implied +# warranty. In no event will the authors be held liable for any damages +# arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment in the product documentation would be +# appreciated but is not required. +# +# 2. Altered source versions must be plainly marked as such, and must not +# be misrepresented as being the original software. +# +# 3. This notice may not be removed or altered from any source +# distribution. +############################################################################### + +.phony: default all openctm toolset documentation install clean + +default: openctm toolset +all: openctm toolset documentation + +clean: + cd lib && $(MAKE) -f Makefile.linux clean && cd .. + cd tools && $(MAKE) -f Makefile.linux clean && cd .. + cd doc && $(MAKE) -f Makefile.linux clean && cd .. + +openctm: + cd lib && $(MAKE) -f Makefile.linux -j2 && cd .. + +toolset: + cd tools && $(MAKE) -f Makefile.linux -j2 && cd .. + +documentation: + cd doc && $(MAKE) -f Makefile.linux -j2 && cd .. + + +# Installation settings +LIBDIR = /usr/lib/ +INCDIR = /usr/local/include/ +BINDIR = /usr/local/bin/ +MAN1DIR = /usr/local/share/man/man1/ +CP = cp +MKDIR = mkdir -p + +install: + $(CP) lib/libopenctm.so $(LIBDIR) + $(CP) lib/openctm.h $(INCDIR) + $(CP) lib/openctmpp.h $(INCDIR) + $(CP) tools/ctmconv $(BINDIR) + $(CP) tools/ctmviewer $(BINDIR) + $(MKDIR) $(MAN1DIR) + $(CP) doc/ctmconv.1 $(MAN1DIR) + $(CP) doc/ctmviewer.1 $(MAN1DIR) diff --git a/src/external/OpenCTM-1.0.3/Makefile.macosx b/src/external/OpenCTM-1.0.3/Makefile.macosx new file mode 100644 index 000000000..16c804b99 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/Makefile.macosx @@ -0,0 +1,64 @@ +############################################################################### +# Product: OpenCTM +# File: Makefile.macosx +# Description: Top level makefile for Mac OS X. +############################################################################### +# Copyright (c) 2009 Marcus Geelnard +# +# This software is provided 'as-is', without any express or implied +# warranty. In no event will the authors be held liable for any damages +# arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment in the product documentation would be +# appreciated but is not required. +# +# 2. Altered source versions must be plainly marked as such, and must not +# be misrepresented as being the original software. +# +# 3. This notice may not be removed or altered from any source +# distribution. +############################################################################### + +.phony: default all openctm toolset documentation clean + +default: openctm toolset +all: openctm toolset documentation + +clean: + cd lib && $(MAKE) -f Makefile.macosx clean && cd .. + cd tools && $(MAKE) -f Makefile.macosx clean && cd .. + cd doc && $(MAKE) -f Makefile.macosx clean && cd .. + +openctm: + cd lib && $(MAKE) -f Makefile.macosx -j2 && cd .. + +toolset: + cd tools && $(MAKE) -f Makefile.macosx -j2 && cd .. + +documentation: + cd doc && $(MAKE) -f Makefile.macosx -j2 && cd .. + + +# Installation settings +LIBDIR = /usr/local/lib/ +INCDIR = /usr/local/include/ +BINDIR = /usr/local/bin/ +MAN1DIR = /usr/local/share/man/man1/ +CP = cp +MKDIR = mkdir -p + +install: + $(CP) lib/libopenctm.dylib $(LIBDIR) + $(CP) lib/openctm.h $(INCDIR) + $(CP) lib/openctmpp.h $(INCDIR) + $(CP) tools/ctmconv $(BINDIR) + $(CP) tools/ctmviewer $(BINDIR) + $(MKDIR) $(MAN1DIR) + $(CP) doc/ctmconv.1 $(MAN1DIR) + $(CP) doc/ctmviewer.1 $(MAN1DIR) diff --git a/src/external/OpenCTM-1.0.3/Makefile.mingw b/src/external/OpenCTM-1.0.3/Makefile.mingw new file mode 100644 index 000000000..bf67cdced --- /dev/null +++ b/src/external/OpenCTM-1.0.3/Makefile.mingw @@ -0,0 +1,45 @@ +############################################################################### +# Product: OpenCTM +# File: Makefile.mingw +# Description: Top level makefile for Windows / MinGW32. +############################################################################### +# Copyright (c) 2009 Marcus Geelnard +# +# This software is provided 'as-is', without any express or implied +# warranty. In no event will the authors be held liable for any damages +# arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment in the product documentation would be +# appreciated but is not required. +# +# 2. Altered source versions must be plainly marked as such, and must not +# be misrepresented as being the original software. +# +# 3. This notice may not be removed or altered from any source +# distribution. +############################################################################### + +.phony: default all openctm toolset documentation clean + +default: openctm toolset +all: openctm toolset documentation + +clean: + cd lib && $(MAKE) -f Makefile.mingw clean && cd .. + cd tools && $(MAKE) -f Makefile.mingw clean && cd .. + cd doc && $(MAKE) -f Makefile.win clean && cd .. + +openctm: + cd lib && $(MAKE) -f Makefile.mingw -j2 && cd .. + +toolset: + cd tools && $(MAKE) -f Makefile.mingw -j2 && cd .. + +documentation: + cd doc && $(MAKE) -f Makefile.win -j2 && cd .. diff --git a/src/external/OpenCTM-1.0.3/Makefile.msvc b/src/external/OpenCTM-1.0.3/Makefile.msvc new file mode 100644 index 000000000..ad3cbfae7 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/Makefile.msvc @@ -0,0 +1,45 @@ +############################################################################### +# Product: OpenCTM +# File: Makefile.msvc +# Description: Top level makefile for Windows / MS Visual Studio 2008. +############################################################################### +# Copyright (c) 2009 Marcus Geelnard +# +# This software is provided 'as-is', without any express or implied +# warranty. In no event will the authors be held liable for any damages +# arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment in the product documentation would be +# appreciated but is not required. +# +# 2. Altered source versions must be plainly marked as such, and must not +# be misrepresented as being the original software. +# +# 3. This notice may not be removed or altered from any source +# distribution. +############################################################################### + +.PHONY: default all openctm toolset documentation clean + +default: openctm toolset +all: openctm toolset documentation + +clean: + cd lib && $(MAKE) /nologo /f Makefile.msvc clean && cd .. + cd tools && $(MAKE) /nologo /f Makefile.msvc clean && cd .. + cd doc && $(MAKE) /nologo /f Makefile.win clean && cd .. + +openctm: + cd lib && $(MAKE) /nologo /f Makefile.msvc && cd .. + +toolset: + cd tools && $(MAKE) /nologo /f Makefile.msvc && cd .. + +documentation: + cd doc && $(MAKE) /nologo /f Makefile.win && cd .. diff --git a/src/external/OpenCTM-1.0.3/README.txt b/src/external/OpenCTM-1.0.3/README.txt new file mode 100644 index 000000000..f7d1429c4 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/README.txt @@ -0,0 +1,152 @@ +1. INTRODUCTION +=============== + +Welcome to OpenCTM! + +OpenCTM is a file format, a software library and a tool set for compression of +3D triangle meshes. The geometry is compressed to a fraction of comparable file +formats (3DS, STL, COLLADA, VRML...), and the format is easily accessible +through a simple, portable API. + +The library is written in portable C (C99), and should compile nicely on any +32/64-bit system regardless of endianity (big endian or little endian). + + +2. LICENSE +========== + +The OpenCTM API and the OpenCTM tools are released under the zlib/libpng +license (see LICENSE.txt). + +3. CREDITS +========== + +Many people have helped out in the development process of OpenCTM, with +valuable feedback, programming efforts, test models and conceptual ideas. +Also, OpenCTM relies heavily on many other open source projects. + +Here is an incomplete list of persons that deserve credit: + +- Igor Pavlov (LZMA library) +- Jonas Innala (COLLADA importer, Maya exporter plugin) +- Ilian Dinev (help with the OpenCTM file format design and the LWO loader) +- Lee Thomason (TinyXML) +- Diego Nehab (RPly - for loading PLY files) +- Lev Povalahev, Marcelo E. Magallon, Milan Ikits (GLEW) +- Thomas G. Lane, Guido Vollbeding (libjpeg) +- Jean-loup Gailly, Mark Adler (zlib) +- Daniel Karling (pnglite) + +During the development of OpenCTM, the following software has been used +extensively: + +- Ubuntu (www.ubuntu.com) +- Blender (www.blender.org) +- GCC (gcc.gnu.org) +- SciTE (www.scintilla.org/SciTE.html) +- Notepad++ (notepad-plus.sourceforge.net) +- Smultron (smultron.sourceforge.net) + +Legal notices: + +- This software is based in part on the work of the Independent JPEG Group. + + +4. CHANGES +========== + +v1.0.3 - 2010.01.15 +------------------- +- Added support for PNG format textures (ctmviewer). + +- Added support for LightWave LWO files (ctmconv and ctmviewer). + +- Added support for Geomview OFF files, e.g. as used by the Princeton Shape + Benchmark (ctmconv and ctmviewer). + +- Improved the OBJ file loader (ctmviewer and ctmconv). + +- Experimental support for VRML 2.0 files - export only (ctmconv and ctmviewer). + +- Made it possible to run ctmviewer without command line arguments. + +- Improved the normal calculation algorithm (ctmviewer and ctmconv). + +- Normals are no longer exported if no normals were present in the input file + (ctmviewer). + + +v1.0.2 - 2009.12.13 +------------------- +- Added an OpenCTM exporter plugin for Maya [Jonas Innala]. + +- Added the possiblity to save and load files from ctmviewer, effectively + turning it into a quick and simple converter tool (without all the options + in the ctmconv program, though). + +- Added a function to load texture files from ctmviewer. + +- Improved the camera control in ctmviewer (panning with the right mouse + button, zooming with the middle mouse button and the mouse wheel, feature + focusing by double clicking, Y/Z up axis selection and "fit to screen" + function). + +- Added a GUI dialog for showing errors in ctmviewer (this is especially useful + under Windows, where console output is disabeled). + +- Added an option for calculating the normals in ctmconv (if the input file + does not have normals). + +- Added options for turning off normals, texture coordinates and/or vertex + colors for the output file in ctmconv. + +- Added manuals for ctmviewer and ctmconv (man pages). + +- Added a "make install" build target for Mac OS X and Linux for simple system + wide installation (see COMPILING.txt). + +- NOTE: The Linux/X11 version of ctmviewer now reqires GTK+ 2.0. + + +v1.0.1 - 2009.11.15 +------------------- +- Notable reduction of the memory footprint by tuning of the LZMA compression + parameters. + +- Added a Wavefront OBJ file importer/exporter. + +- Some improvements to ctmviewer and ctmconv. + +- Some directory structure and build system cleanups. + + +v1.0 - 2009.11.09 +----------------- +- Added a COLLADA converter module to the ctmconv program [Jonas Innala]. + +- Added Python bindings and a demo Python program. + +- Improved the internal mesh integrity checking, to minimize the risk of invalid + data processing. + +- Improved the file format specification document. + + +v0.8 (beta) - 2009.09.14 +------------------------ +- Introduced a new API function for controlling the compression level + (ctmCompressionLevel), and set the default compression level to 5 (rather + than 9, which would eat a lot of memory, usally without much difference). + +- Changed the name "texture map" in the API to "UV map" (and all + corresponding constant and function names). This is more in line with + the nomenclature of most 3D authoring software, and avoids the confusion + with the term texture mapping in 3D hardware (which is not limited to + 2D UV mapping coordinates). + +- A few updates to the documentation. + + +v0.7 (beta) - 2009.08.29 +------------------------ +- This was the first public release of OpenCTM. diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/annotated.html b/src/external/OpenCTM-1.0.3/doc/APIReference/annotated.html new file mode 100644 index 000000000..3658d4522 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/annotated.html @@ -0,0 +1,38 @@ + + + + +OpenCTM: Class List + + + + + + +
+

Class List

Here are the classes, structs, unions and interfaces with brief descriptions: + + + +
ctm_errorOpenCTM exception
CTMexporterOpenCTM exporter class
CTMimporterOpenCTM importer class
+
+
+

Copyright © 2009-2010 Marcus Geelnard — + openctm.sourceforge.net

+
+ + diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/classCTMexporter-members.html b/src/external/OpenCTM-1.0.3/doc/APIReference/classCTMexporter-members.html new file mode 100644 index 000000000..dacb9434c --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/classCTMexporter-members.html @@ -0,0 +1,51 @@ + + + + +OpenCTM: Member List + + + + + + +
+

CTMexporter Member List

This is the complete list of members for CTMexporter, including all inherited members. + + + + + + + + + + + + + + + + + +
AddAttribMap(const CTMfloat *aAttribValues, const char *aName)CTMexporter [inline]
AddUVMap(const CTMfloat *aUVCoords, const char *aName, const char *aFileName)CTMexporter [inline]
AttribPrecision(CTMenum aAttribMap, CTMfloat aPrecision)CTMexporter [inline]
CompressionLevel(CTMuint aLevel)CTMexporter [inline]
CompressionMethod(CTMenum aMethod)CTMexporter [inline]
CTMexporter()CTMexporter [inline]
CTMexporter(const CTMexporter &v)CTMexporter
DefineMesh(const CTMfloat *aVertices, CTMuint aVertexCount, const CTMuint *aIndices, CTMuint aTriangleCount, const CTMfloat *aNormals)CTMexporter [inline]
FileComment(const char *aFileComment)CTMexporter [inline]
NormalPrecision(CTMfloat aPrecision)CTMexporter [inline]
operator=(const CTMexporter &v)CTMexporter
Save(const char *aFileName)CTMexporter [inline]
SaveCustom(CTMwritefn aWriteFn, void *aUserData)CTMexporter [inline]
UVCoordPrecision(CTMenum aUVMap, CTMfloat aPrecision)CTMexporter [inline]
VertexPrecision(CTMfloat aPrecision)CTMexporter [inline]
VertexPrecisionRel(CTMfloat aRelPrecision)CTMexporter [inline]
~CTMexporter()CTMexporter [inline]
+
+

Copyright © 2009-2010 Marcus Geelnard — + openctm.sourceforge.net

+
+ + diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/classCTMexporter.html b/src/external/OpenCTM-1.0.3/doc/APIReference/classCTMexporter.html new file mode 100644 index 000000000..f97cfa5a2 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/classCTMexporter.html @@ -0,0 +1,508 @@ + + + + +OpenCTM: CTMexporter Class Reference + + + + + + +
+

CTMexporter Class Reference

+

OpenCTM exporter class. +More...

+ +

#include <openctmpp.h>

+ +

List of all members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Member Functions

 CTMexporter ()
 Constructor.
 ~CTMexporter ()
 Destructor.
void CompressionMethod (CTMenum aMethod)
 Wrapper for ctmCompressionMethod().
void CompressionLevel (CTMuint aLevel)
 Wrapper for ctmCompressionLevel().
void VertexPrecision (CTMfloat aPrecision)
 Wrapper for ctmVertexPrecision().
void VertexPrecisionRel (CTMfloat aRelPrecision)
 Wrapper for ctmVertexPrecisionRel().
void NormalPrecision (CTMfloat aPrecision)
 Wrapper for ctmNormalPrecision().
void UVCoordPrecision (CTMenum aUVMap, CTMfloat aPrecision)
 Wrapper for ctmUVCoordPrecision().
void AttribPrecision (CTMenum aAttribMap, CTMfloat aPrecision)
 Wrapper for ctmAttribPrecision().
void FileComment (const char *aFileComment)
 Wrapper for ctmFileComment().
void DefineMesh (const CTMfloat *aVertices, CTMuint aVertexCount, const CTMuint *aIndices, CTMuint aTriangleCount, const CTMfloat *aNormals)
 Wrapper for ctmDefineMesh().
CTMenum AddUVMap (const CTMfloat *aUVCoords, const char *aName, const char *aFileName)
 Wrapper for ctmAddUVMap().
CTMenum AddAttribMap (const CTMfloat *aAttribValues, const char *aName)
 Wrapper for ctmAddAttribMap().
void Save (const char *aFileName)
 Wrapper for ctmSave().
void SaveCustom (CTMwritefn aWriteFn, void *aUserData)
 Wrapper for ctmSaveCustom().
 CTMexporter (const CTMexporter &v)
CTMexporteroperator= (const CTMexporter &v)
+

Detailed Description

+

OpenCTM exporter class.

+

This is a C++ wrapper class for an OpenCTM export context. Usage example:

+
 void MySaveFile(CTMuint aVertCount, CTMuint aTriCount, CTMfloat * aVertices,
+   CTMuint * aIndices, const char * aFileName)
+ {
+   // Create a new OpenCTM exporter object
+   CTMexporter ctm;
+
+   // Define our mesh representation to OpenCTM (store references to it in
+   // the context)
+   ctm.DefineMesh(aVertices, aVertCount, aIndices, aTriCount, NULL);
+
+   // Save the OpenCTM file
+   ctm.Save(aFileName);
+ }
+

Constructor & Destructor Documentation

+ +
+
+ + + + + + + + +
CTMexporter::CTMexporter ( )  [inline]
+
+
+ +

Constructor.

+ +
+
+ +
+
+ + + + + + + + +
CTMexporter::~CTMexporter ( )  [inline]
+
+
+ +

Destructor.

+ +
+
+ +
+
+ + + + + + + + + +
CTMexporter::CTMexporter (const CTMexporter v ) 
+
+
+ +
+
+

Member Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
CTMenum CTMexporter::AddAttribMap (const CTMfloat aAttribValues,
const char *  aName 
) [inline]
+
+
+ +

Wrapper for ctmAddAttribMap().

+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
CTMenum CTMexporter::AddUVMap (const CTMfloat aUVCoords,
const char *  aName,
const char *  aFileName 
) [inline]
+
+
+ +

Wrapper for ctmAddUVMap().

+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void CTMexporter::AttribPrecision (CTMenum  aAttribMap,
CTMfloat  aPrecision 
) [inline]
+
+
+ +

Wrapper for ctmAttribPrecision().

+ +
+
+ +
+
+ + + + + + + + + +
void CTMexporter::CompressionLevel (CTMuint  aLevel )  [inline]
+
+
+ +

Wrapper for ctmCompressionLevel().

+ +
+
+ +
+
+ + + + + + + + + +
void CTMexporter::CompressionMethod (CTMenum  aMethod )  [inline]
+
+
+ +

Wrapper for ctmCompressionMethod().

+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void CTMexporter::DefineMesh (const CTMfloat aVertices,
CTMuint  aVertexCount,
const CTMuint aIndices,
CTMuint  aTriangleCount,
const CTMfloat aNormals 
) [inline]
+
+
+ +

Wrapper for ctmDefineMesh().

+ +
+
+ +
+
+ + + + + + + + + +
void CTMexporter::FileComment (const char *  aFileComment )  [inline]
+
+
+ +

Wrapper for ctmFileComment().

+ +
+
+ +
+
+ + + + + + + + + +
void CTMexporter::NormalPrecision (CTMfloat  aPrecision )  [inline]
+
+
+ +

Wrapper for ctmNormalPrecision().

+ +
+
+ +
+
+ + + + + + + + + +
CTMexporter& CTMexporter::operator= (const CTMexporter v ) 
+
+
+ +
+
+ +
+
+ + + + + + + + + +
void CTMexporter::Save (const char *  aFileName )  [inline]
+
+
+ +

Wrapper for ctmSave().

+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void CTMexporter::SaveCustom (CTMwritefn  aWriteFn,
void *  aUserData 
) [inline]
+
+
+ +

Wrapper for ctmSaveCustom().

+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void CTMexporter::UVCoordPrecision (CTMenum  aUVMap,
CTMfloat  aPrecision 
) [inline]
+
+
+ +

Wrapper for ctmUVCoordPrecision().

+ +
+
+ +
+
+ + + + + + + + + +
void CTMexporter::VertexPrecision (CTMfloat  aPrecision )  [inline]
+
+
+ +

Wrapper for ctmVertexPrecision().

+ +
+
+ +
+
+ + + + + + + + + +
void CTMexporter::VertexPrecisionRel (CTMfloat  aRelPrecision )  [inline]
+
+
+ +

Wrapper for ctmVertexPrecisionRel().

+ +
+
+
The documentation for this class was generated from the following file: +
+
+

Copyright © 2009-2010 Marcus Geelnard — + openctm.sourceforge.net

+
+ + diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/classCTMimporter-members.html b/src/external/OpenCTM-1.0.3/doc/APIReference/classCTMimporter-members.html new file mode 100644 index 000000000..2b2b0769e --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/classCTMimporter-members.html @@ -0,0 +1,51 @@ + + + + +OpenCTM: Member List + + + + + + +
+

CTMimporter Member List

This is the complete list of members for CTMimporter, including all inherited members. + + + + + + + + + + + + + + + + + +
CTMimporter()CTMimporter [inline]
CTMimporter(const CTMimporter &v)CTMimporter
GetAttribMapFloat(CTMenum aAttribMap, CTMenum aProperty)CTMimporter [inline]
GetAttribMapString(CTMenum aAttribMap, CTMenum aProperty)CTMimporter [inline]
GetFloat(CTMenum aProperty)CTMimporter [inline]
GetFloatArray(CTMenum aProperty)CTMimporter [inline]
GetInteger(CTMenum aProperty)CTMimporter [inline]
GetIntegerArray(CTMenum aProperty)CTMimporter [inline]
GetNamedAttribMap(const char *aName)CTMimporter [inline]
GetNamedUVMap(const char *aName)CTMimporter [inline]
GetString(CTMenum aProperty)CTMimporter [inline]
GetUVMapFloat(CTMenum aUVMap, CTMenum aProperty)CTMimporter [inline]
GetUVMapString(CTMenum aUVMap, CTMenum aProperty)CTMimporter [inline]
Load(const char *aFileName)CTMimporter [inline]
LoadCustom(CTMreadfn aReadFn, void *aUserData)CTMimporter [inline]
operator=(const CTMimporter &v)CTMimporter
~CTMimporter()CTMimporter [inline]
+
+

Copyright © 2009-2010 Marcus Geelnard — + openctm.sourceforge.net

+
+ + diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/classCTMimporter.html b/src/external/OpenCTM-1.0.3/doc/APIReference/classCTMimporter.html new file mode 100644 index 000000000..19bfa2aba --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/classCTMimporter.html @@ -0,0 +1,476 @@ + + + + +OpenCTM: CTMimporter Class Reference + + + + + + +
+

CTMimporter Class Reference

+

OpenCTM importer class. +More...

+ +

#include <openctmpp.h>

+ +

List of all members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Member Functions

 CTMimporter ()
 Constructor.
 ~CTMimporter ()
 Destructor.
CTMuint GetInteger (CTMenum aProperty)
 Wrapper for ctmGetInteger().
CTMfloat GetFloat (CTMenum aProperty)
 Wrapper for ctmGetFloat().
const CTMuintGetIntegerArray (CTMenum aProperty)
 Wrapper for ctmGetIntegerArray().
const CTMfloatGetFloatArray (CTMenum aProperty)
 Wrapper for ctmGetFloatArray().
CTMenum GetNamedUVMap (const char *aName)
 Wrapper for ctmGetNamedUVMap().
const char * GetUVMapString (CTMenum aUVMap, CTMenum aProperty)
 Wrapper for ctmGetUVMapString().
CTMfloat GetUVMapFloat (CTMenum aUVMap, CTMenum aProperty)
 Wrapper for ctmGetUVMapFloat().
CTMenum GetNamedAttribMap (const char *aName)
 Wrapper for ctmGetNamedAttribMap().
const char * GetAttribMapString (CTMenum aAttribMap, CTMenum aProperty)
 Wrapper for ctmGetAttribMapString().
CTMfloat GetAttribMapFloat (CTMenum aAttribMap, CTMenum aProperty)
 Wrapper for ctmGetAttribMapFloat().
const char * GetString (CTMenum aProperty)
 Wrapper for ctmGetString().
void Load (const char *aFileName)
 Wrapper for ctmLoad().
void LoadCustom (CTMreadfn aReadFn, void *aUserData)
 Wrapper for ctmLoadCustom().
 CTMimporter (const CTMimporter &v)
CTMimporteroperator= (const CTMimporter &v)
+

Detailed Description

+

OpenCTM importer class.

+

This is a C++ wrapper class for an OpenCTM import context. Usage example:

+
   // Create a new OpenCTM importer object
+   CTMimporter ctm;
+
+   // Load the OpenCTM file
+   ctm.Load("mymesh.ctm");
+
+   // Access the mesh data
+   vertCount = ctm.GetInteger(CTM_VERTEX_COUNT);
+   vertices = ctm.GetFloatArray(CTM_VERTICES);
+   triCount = ctm.GetInteger(CTM_TRIANGLE_COUNT);
+   indices = ctm.GetIntegerArray(CTM_INDICES);
+
+   // Deal with the mesh (e.g. transcode it to our internal representation)
+   // ...
+

Constructor & Destructor Documentation

+ +
+
+ + + + + + + + +
CTMimporter::CTMimporter ( )  [inline]
+
+
+ +

Constructor.

+ +
+
+ +
+
+ + + + + + + + +
CTMimporter::~CTMimporter ( )  [inline]
+
+
+ +

Destructor.

+ +
+
+ +
+
+ + + + + + + + + +
CTMimporter::CTMimporter (const CTMimporter v ) 
+
+
+ +
+
+

Member Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + +
CTMfloat CTMimporter::GetAttribMapFloat (CTMenum  aAttribMap,
CTMenum  aProperty 
) [inline]
+
+
+ +

Wrapper for ctmGetAttribMapFloat().

+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
const char* CTMimporter::GetAttribMapString (CTMenum  aAttribMap,
CTMenum  aProperty 
) [inline]
+
+
+ +

Wrapper for ctmGetAttribMapString().

+ +
+
+ +
+
+ + + + + + + + + +
CTMfloat CTMimporter::GetFloat (CTMenum  aProperty )  [inline]
+
+
+ +

Wrapper for ctmGetFloat().

+ +
+
+ +
+
+ + + + + + + + + +
const CTMfloat* CTMimporter::GetFloatArray (CTMenum  aProperty )  [inline]
+
+
+ +

Wrapper for ctmGetFloatArray().

+ +
+
+ +
+
+ + + + + + + + + +
CTMuint CTMimporter::GetInteger (CTMenum  aProperty )  [inline]
+
+
+ +

Wrapper for ctmGetInteger().

+ +
+
+ +
+
+ + + + + + + + + +
const CTMuint* CTMimporter::GetIntegerArray (CTMenum  aProperty )  [inline]
+
+
+ +

Wrapper for ctmGetIntegerArray().

+ +
+
+ +
+
+ + + + + + + + + +
CTMenum CTMimporter::GetNamedAttribMap (const char *  aName )  [inline]
+
+
+ +

Wrapper for ctmGetNamedAttribMap().

+ +
+
+ +
+
+ + + + + + + + + +
CTMenum CTMimporter::GetNamedUVMap (const char *  aName )  [inline]
+
+
+ +

Wrapper for ctmGetNamedUVMap().

+ +
+
+ +
+
+ + + + + + + + + +
const char* CTMimporter::GetString (CTMenum  aProperty )  [inline]
+
+
+ +

Wrapper for ctmGetString().

+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
CTMfloat CTMimporter::GetUVMapFloat (CTMenum  aUVMap,
CTMenum  aProperty 
) [inline]
+
+
+ +

Wrapper for ctmGetUVMapFloat().

+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
const char* CTMimporter::GetUVMapString (CTMenum  aUVMap,
CTMenum  aProperty 
) [inline]
+
+
+ +

Wrapper for ctmGetUVMapString().

+ +
+
+ +
+
+ + + + + + + + + +
void CTMimporter::Load (const char *  aFileName )  [inline]
+
+
+ +

Wrapper for ctmLoad().

+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
void CTMimporter::LoadCustom (CTMreadfn  aReadFn,
void *  aUserData 
) [inline]
+
+
+ +

Wrapper for ctmLoadCustom().

+ +
+
+ +
+
+ + + + + + + + + +
CTMimporter& CTMimporter::operator= (const CTMimporter v ) 
+
+
+ +
+
+
The documentation for this class was generated from the following file: +
+
+

Copyright © 2009-2010 Marcus Geelnard — + openctm.sourceforge.net

+
+ + diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/classctm__error-members.html b/src/external/OpenCTM-1.0.3/doc/APIReference/classctm__error-members.html new file mode 100644 index 000000000..808972cb9 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/classctm__error-members.html @@ -0,0 +1,37 @@ + + + + +OpenCTM: Member List + + + + + + +
+

ctm_error Member List

This is the complete list of members for ctm_error, including all inherited members. + + + +
ctm_error(CTMenum aError)ctm_error [inline, explicit]
error_code() const ctm_error [inline]
what() const ctm_error [inline, virtual]
+
+

Copyright © 2009-2010 Marcus Geelnard — + openctm.sourceforge.net

+
+ + diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/classctm__error.html b/src/external/OpenCTM-1.0.3/doc/APIReference/classctm__error.html new file mode 100644 index 000000000..c75b0790a --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/classctm__error.html @@ -0,0 +1,106 @@ + + + + +OpenCTM: ctm_error Class Reference + + + + + + +
+

ctm_error Class Reference

+

OpenCTM exception. +More...

+ +

#include <openctmpp.h>

+ +

List of all members.

+ + + + + +

Public Member Functions

 ctm_error (CTMenum aError)
virtual const char * what () const throw ()
CTMenum error_code () const throw ()
+

Detailed Description

+

OpenCTM exception.

+

When an error occurs, a ctm_error exception is thrown. Its what() function returns the name of the OpenCTM error code (for instance "CTM_INVALID_OPERATION").

+

Constructor & Destructor Documentation

+ +
+
+ + + + + + + + + +
ctm_error::ctm_error (CTMenum  aError )  [inline, explicit]
+
+
+ +
+
+

Member Function Documentation

+ +
+
+ + + + + + + + +
CTMenum ctm_error::error_code ( )  const throw () [inline]
+
+
+ +
+
+ +
+
+ + + + + + + + +
virtual const char* ctm_error::what ( )  const throw () [inline, virtual]
+
+
+ +
+
+
The documentation for this class was generated from the following file: +
+
+

Copyright © 2009-2010 Marcus Geelnard — + openctm.sourceforge.net

+
+ + diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/classes.html b/src/external/OpenCTM-1.0.3/doc/APIReference/classes.html new file mode 100644 index 000000000..866996cc7 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/classes.html @@ -0,0 +1,37 @@ + + + + +OpenCTM: Alphabetical List + + + + + + +
+

Class Index

+ +
  C  
+
ctm_error   CTMexporter   CTMimporter   
+
+
+

Copyright © 2009-2010 Marcus Geelnard — + openctm.sourceforge.net

+
+ + diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/doxygen.css b/src/external/OpenCTM-1.0.3/doc/APIReference/doxygen.css new file mode 100644 index 000000000..9ca3cafbc --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/doxygen.css @@ -0,0 +1,498 @@ +/* The standard CSS for doxygen */ + +body, table, div, p, dl { + font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif; + font-size: 12px; +} + +/* @group Heading Levels */ + +h1 { + text-align: center; + font-size: 150%; +} + +h2 { + font-size: 120%; +} + +h3 { + font-size: 100%; +} + +dt { + font-weight: bold; +} + +div.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; +} + +p.startli, p.startdd { + margin-top: 2px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + padding: 2px; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #153788; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #1b77c5; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #6666cc; + color: #ffffff; + border: 1px double #9295C2; +} + +.contents a.qindexHL:visited { + color: #ffffff; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code { +} + +a.codeRef { +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +.fragment { + font-family: monospace, fixed; + font-size: 105%; +} + +pre.fragment { + border: 1px solid #CCCCCC; + background-color: #f5f5f5; + padding: 4px 6px; + margin: 4px 8px 4px 2px; +} + +div.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + margin-bottom: 6px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background: white; + color: black; + margin-right: 20px; + margin-left: 20px; +} + +td.indexkey { + background-color: #e8eef2; + font-weight: bold; + border: 1px solid #CCCCCC; + margin: 2px 0px 2px 0; + padding: 2px 10px; +} + +td.indexvalue { + background-color: #e8eef2; + border: 1px solid #CCCCCC; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #f0f0f0; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +/* @end */ + +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #84b0c7; +} + +th.dirtab { + background: #e8eef2; + font-weight: bold; +} + +hr { + height: 0; + border: none; + border-top: 1px solid #666; +} + +/* @group Member Descriptions */ + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #FAFAFA; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memItemLeft, .memItemRight, .memTemplParams { + border-top: 1px solid #ccc; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memTemplParams { + color: #606060; + white-space: nowrap; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtemplate { + font-size: 80%; + color: #606060; + font-weight: normal; + margin-left: 3px; +} + +.memnav { + background-color: #e8eef2; + border: 1px solid #84b0c7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.memitem { + padding: 0; + margin-bottom: 10px; +} + +.memname { + white-space: nowrap; + font-weight: bold; +} + +.memproto, .memdoc { + border: 1px solid #84b0c7; +} + +.memproto { + padding: 0; + background-color: #d5e1e8; + font-weight: bold; + -webkit-border-top-left-radius: 8px; + -webkit-border-top-right-radius: 8px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -moz-border-radius-topleft: 8px; + -moz-border-radius-topright: 8px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + +} + +.memdoc { + padding: 2px 5px; + background-color: #eef3f5; + border-top-width: 0; + -webkit-border-bottom-left-radius: 8px; + -webkit-border-bottom-right-radius: 8px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -moz-border-radius-bottomleft: 8px; + -moz-border-radius-bottomright: 8px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} + +/* @end */ + +/* @group Directory (tree) */ + +/* for the tree view */ + +.ftvtree { + font-family: sans-serif; + margin: 0.5em; +} + +/* these are for tree view when used as main index */ + +.directory { + font-size: 9pt; + font-weight: bold; +} + +.directory h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +/* +The following two styles can be used to replace the root node title +with an image of your choice. Simply uncomment the next two styles, +specify the name of your image and be sure to set 'height' to the +proper pixel height of your image. +*/ + +/* +.directory h3.swap { + height: 61px; + background-repeat: no-repeat; + background-image: url("yourimage.gif"); +} +.directory h3.swap span { + display: none; +} +*/ + +.directory > h3 { + margin-top: 0; +} + +.directory p { + margin: 0px; + white-space: nowrap; +} + +.directory div { + display: none; + margin: 0px; +} + +.directory img { + vertical-align: -30%; +} + +/* these are for tree view when not used as main index */ + +.directory-alt { + font-size: 100%; + font-weight: bold; +} + +.directory-alt h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +.directory-alt > h3 { + margin-top: 0; +} + +.directory-alt p { + margin: 0px; + white-space: nowrap; +} + +.directory-alt div { + display: none; + margin: 0px; +} + +.directory-alt img { + vertical-align: -30%; +} + +/* @end */ + +address { + font-style: normal; + color: #333; +} diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/doxygen.png b/src/external/OpenCTM-1.0.3/doc/APIReference/doxygen.png new file mode 100644 index 0000000000000000000000000000000000000000..f0a274bbaffdd67f6d784c894d9cf28729db0e14 GIT binary patch literal 1281 zcmaJ>ZA?>F7(Vx-ms?uoS`b@hdRtpo6o^%HU>M$hfGrBvQnk$LE?p^P!kn&ikhyq! zX~V@&tPF5Qt@V?oTL96Bi%aRiwbe1)9DWQI#?)=HxS7QSw`J`5fAJ*eJbB;uNuKA& zdERDo*{Y<(If(#(B$Lr#;nB(8Y#ia=ZCeW?JfPLuQY`=@cW$k}Rivq|vbxGrRq1Tl9;+(gNt?}UtVKM2`T5t1jLzuL@0UIs`S#vlhl4)^ zLgSYrPj@$+`|j?eSbXTmiHGkWxV8V}BzNR?pl9k_s4pDu9vd5a_UzZEPk)}Ad{AV_ zzddrjrh4=Imr`E06;LY{)YYt?o}L~H@7C}F^WB!Ra=v`Q0bj{>5&$66CWF>mf6vjP z2N>RRY6ZYa=K`76>+|_)Xdwko+7wv}7cN|btOhWb(*{sta~6b?S8Omrxw}!4`NhGr zZVpNqpu1@BE`QGWNTpEpcJVW5izu~2B^GlM?1(OPg)zwW;QcP@Ltcclm>XbJL9C|j z=9!2?ua=uIlf0%AndzHsRC}IyTL$EhAee(fdKB`?27KeS^2M8M_7b~PiCFO&r5LC7 z7gl1*a<8;SjNaw#h=843_AV9iZbWQOAp5YOC^&_F*9K0> zB|6%IDb?aM#3viTxkLU4aXg&@+CkNTOnQ1iMP*^?b|^lJy$4C)Zk4isV!|RZ*XhXh zw8q3$=*0LeGC!XI_Wc?dkT~3+*Gu%%yIqP+Wr3H$=&ROMQU6q}Ag^P~>c5vAEO;a- z_dK-3PPeKar%)6$j~vI2#*-YH!1h6HYVtwCX5_wM`iF#UKz&&@9Oo5w3%XGYrX zW>dY~)SG-((Yim%`InwgTvyRC?e=Wh^8KCao!R6Eg&TpVWUY1sN~4G}V?nFnEGo-; zHZ_$eW9-GnC%^WS9b z@p;-$oH#MtC0v>Q$HX%4^JdFdO$0cbv-W)Q TtK}Eh@>>I#ipmV1>S*>q-hkC} literal 0 HcmV?d00001 diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/files.html b/src/external/OpenCTM-1.0.3/doc/APIReference/files.html new file mode 100644 index 000000000..3d4691c98 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/files.html @@ -0,0 +1,37 @@ + + + + +OpenCTM: File Index + + + + + + +
+

File List

Here is a list of all files with brief descriptions: + + +
openctm.h [code]
openctmpp.h [code]
+
+
+

Copyright © 2009-2010 Marcus Geelnard — + openctm.sourceforge.net

+
+ + diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/functions.html b/src/external/OpenCTM-1.0.3/doc/APIReference/functions.html new file mode 100644 index 000000000..2dd69a021 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/functions.html @@ -0,0 +1,216 @@ + + + + +OpenCTM: Class Members + + + + + + +
+Here is a list of all class members with links to the classes they belong to: + +

- a -

+ + +

- c -

+ + +

- d -

+ + +

- e -

+ + +

- f -

+ + +

- g -

+ + +

- l -

+ + +

- n -

+ + +

- o -

+ + +

- s -

+ + +

- u -

+ + +

- v -

+ + +

- w -

+ + +

- ~ -

+
+
+

Copyright © 2009-2010 Marcus Geelnard — + openctm.sourceforge.net

+
+ + diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/functions_func.html b/src/external/OpenCTM-1.0.3/doc/APIReference/functions_func.html new file mode 100644 index 000000000..df20fa4f7 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/functions_func.html @@ -0,0 +1,216 @@ + + + + +OpenCTM: Class Members - Functions + + + + + + +
+  + +

- a -

+ + +

- c -

+ + +

- d -

+ + +

- e -

+ + +

- f -

+ + +

- g -

+ + +

- l -

+ + +

- n -

+ + +

- o -

+ + +

- s -

+ + +

- u -

+ + +

- v -

+ + +

- w -

+ + +

- ~ -

+
+
+

Copyright © 2009-2010 Marcus Geelnard — + openctm.sourceforge.net

+
+ + diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/globals.html b/src/external/OpenCTM-1.0.3/doc/APIReference/globals.html new file mode 100644 index 000000000..e0bc7b0b6 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/globals.html @@ -0,0 +1,313 @@ + + + + +OpenCTM: Class Members + + + + + + +
+Here is a list of all file members with links to the files they belong to: + +

- c -

+
+
+

Copyright © 2009-2010 Marcus Geelnard — + openctm.sourceforge.net

+
+ + diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/globals_defs.html b/src/external/OpenCTM-1.0.3/doc/APIReference/globals_defs.html new file mode 100644 index 000000000..3c5815d65 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/globals_defs.html @@ -0,0 +1,54 @@ + + + + +OpenCTM: Class Members + + + + + + +
+
+
+

Copyright © 2009-2010 Marcus Geelnard — + openctm.sourceforge.net

+
+ + diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/globals_enum.html b/src/external/OpenCTM-1.0.3/doc/APIReference/globals_enum.html new file mode 100644 index 000000000..bf3d826bd --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/globals_enum.html @@ -0,0 +1,48 @@ + + + + +OpenCTM: Class Members + + + + + + +
+
+
+

Copyright © 2009-2010 Marcus Geelnard — + openctm.sourceforge.net

+
+ + diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/globals_eval.html b/src/external/OpenCTM-1.0.3/doc/APIReference/globals_eval.html new file mode 100644 index 000000000..9f23a4d95 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/globals_eval.html @@ -0,0 +1,193 @@ + + + + +OpenCTM: Class Members + + + + + + +
+  + +

- c -

+
+
+

Copyright © 2009-2010 Marcus Geelnard — + openctm.sourceforge.net

+
+ + diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/globals_func.html b/src/external/OpenCTM-1.0.3/doc/APIReference/globals_func.html new file mode 100644 index 000000000..da41c09e8 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/globals_func.html @@ -0,0 +1,135 @@ + + + + +OpenCTM: Class Members + + + + + + +
+
+
+

Copyright © 2009-2010 Marcus Geelnard — + openctm.sourceforge.net

+
+ + diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/globals_type.html b/src/external/OpenCTM-1.0.3/doc/APIReference/globals_type.html new file mode 100644 index 000000000..1986f7f44 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/globals_type.html @@ -0,0 +1,63 @@ + + + + +OpenCTM: Class Members + + + + + + +
+
+
+

Copyright © 2009-2010 Marcus Geelnard — + openctm.sourceforge.net

+
+ + diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/index.html b/src/external/OpenCTM-1.0.3/doc/APIReference/index.html new file mode 100644 index 000000000..72eba302c --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/index.html @@ -0,0 +1,93 @@ + + + + +OpenCTM: OpenCTM API Reference + + + + + + +
+

OpenCTM API Reference

1.0.3

+Introduction

+

OpenCTM is an open file format for storing compressed triangle meshes. In order to easily read and write OpenCTM files (usually suffixed .ctm) an API (Application Program Interface) is provided that can easily be used from most modern programming languages.

+

The OpenCTM functionality itself is written in highly portable standard C (C99).

+

+Usage

+

For information about how to use the OpenCTM API, see openctm.h.

+

For information about the C++ wrapper classes, see CTMimporter and CTMexporter.

+

+Example usage

+

+Loading a CTM file

+

Here is a simple example of loading a CTM file:

+
   CTMcontext context;
+   CTMuint    vertCount, triCount, * indices;
+   CTMfloat   * vertices;
+
+   // Create a new context
+   context = ctmNewContext(CTM_IMPORT);
+
+   // Load the OpenCTM file
+   ctmLoad(context, "mymesh.ctm");
+   if(ctmGetError(context) == CTM_NONE)
+   {
+     // Access the mesh data
+     vertCount = ctmGetInteger(context, CTM_VERTEX_COUNT);
+     vertices = ctmGetFloatArray(context, CTM_VERTICES);
+     triCount = ctmGetInteger(context, CTM_TRIANGLE_COUNT);
+     indices = ctmGetIntegerArray(context, CTM_INDICES);
+
+     // Deal with the mesh (e.g. transcode it to our internal representation)
+     // ...
+   }
+
+   // Free the context
+   ctmFreeContext(context);
+

+Creating a CTM file

+

Here is a simple example of creating a CTM file:

+
   CTMcontext context;
+   CTMuint    vertCount, triCount, * indices;
+   CTMfloat   * vertices;
+
+   // Create our mesh in memory
+   vertCount = 100;
+   triCount = 120;
+   vertices = (CTMfloat *) malloc(3 * sizeof(CTMfloat) * vertCount);
+   indices = (CTMuint *) malloc(3 * sizeof(CTMuint) * triCount);
+   // ...
+
+   // Create a new context
+   context = ctmNewContext(CTM_EXPORT);
+
+   // Define our mesh representation to OpenCTM (store references to it in
+   // the context)
+   ctmDefineMesh(context, vertices, vertCount, indices, triCount, NULL);
+
+   // Save the OpenCTM file
+   ctmSave(context, "mymesh.ctm");
+
+   // Free the context
+   ctmFreeContext(context);
+
+   // Free our mesh
+   free(indices);
+   free(vertices);
+
+
+

Copyright © 2009-2010 Marcus Geelnard — + openctm.sourceforge.net

+
+ + diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/openctm_8h.html b/src/external/OpenCTM-1.0.3/doc/APIReference/openctm_8h.html new file mode 100644 index 000000000..d6711fceb --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/openctm_8h.html @@ -0,0 +1,1738 @@ + + + + +OpenCTM: openctm.h File Reference + + + + + + +
+

openctm.h File Reference

#include <stdint.h>
+ +

Go to the source code of this file.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Defines

#define CTM_API_VERSION   0x00000100
 OpenCTM API version (1.0).
#define CTM_TRUE   1
 Boolean TRUE.
#define CTM_FALSE   0
 Boolean FALSE.

Typedefs

typedef float CTMfloat
 Single precision floating point type (IEEE 754 32 bits wide).
typedef int32_t CTMint
 Signed integer (32 bits wide).
typedef uint32_t CTMuint
 Unsigned integer (32 bits wide).
typedef void * CTMcontext
 OpenCTM context handle.
typedef CTMuint(CTMCALL * CTMreadfn )(void *aBuf, CTMuint aCount, void *aUserData)
 Stream read() function pointer.
typedef CTMuint(CTMCALL * CTMwritefn )(const void *aBuf, CTMuint aCount, void *aUserData)
 Stream write() function pointer.

Enumerations

enum  CTMenum {
+  CTM_NONE = 0x0000, +
+  CTM_INVALID_CONTEXT = 0x0001, +
+  CTM_INVALID_ARGUMENT = 0x0002, +
+  CTM_INVALID_OPERATION = 0x0003, +
+  CTM_INVALID_MESH = 0x0004, +
+  CTM_OUT_OF_MEMORY = 0x0005, +
+  CTM_FILE_ERROR = 0x0006, +
+  CTM_BAD_FORMAT = 0x0007, +
+  CTM_LZMA_ERROR = 0x0008, +
+  CTM_INTERNAL_ERROR = 0x0009, +
+  CTM_UNSUPPORTED_FORMAT_VERSION = 0x000A, +
+  CTM_IMPORT = 0x0101, +
+  CTM_EXPORT = 0x0102, +
+  CTM_METHOD_RAW = 0x0201, +
+  CTM_METHOD_MG1 = 0x0202, +
+  CTM_METHOD_MG2 = 0x0203, +
+  CTM_VERTEX_COUNT = 0x0301, +
+  CTM_TRIANGLE_COUNT = 0x0302, +
+  CTM_HAS_NORMALS = 0x0303, +
+  CTM_UV_MAP_COUNT = 0x0304, +
+  CTM_ATTRIB_MAP_COUNT = 0x0305, +
+  CTM_VERTEX_PRECISION = 0x0306, +
+  CTM_NORMAL_PRECISION = 0x0307, +
+  CTM_COMPRESSION_METHOD = 0x0308, +
+  CTM_FILE_COMMENT = 0x0309, +
+  CTM_NAME = 0x0501, +
+  CTM_FILE_NAME = 0x0502, +
+  CTM_PRECISION = 0x0503, +
+  CTM_INDICES = 0x0601, +
+  CTM_VERTICES = 0x0602, +
+  CTM_NORMALS = 0x0603, +
+  CTM_UV_MAP_1 = 0x0700, +
+  CTM_UV_MAP_2 = 0x0701, +
+  CTM_UV_MAP_3 = 0x0702, +
+  CTM_UV_MAP_4 = 0x0703, +
+  CTM_UV_MAP_5 = 0x0704, +
+  CTM_UV_MAP_6 = 0x0705, +
+  CTM_UV_MAP_7 = 0x0706, +
+  CTM_UV_MAP_8 = 0x0707, +
+  CTM_ATTRIB_MAP_1 = 0x0800, +
+  CTM_ATTRIB_MAP_2 = 0x0801, +
+  CTM_ATTRIB_MAP_3 = 0x0802, +
+  CTM_ATTRIB_MAP_4 = 0x0803, +
+  CTM_ATTRIB_MAP_5 = 0x0804, +
+  CTM_ATTRIB_MAP_6 = 0x0805, +
+  CTM_ATTRIB_MAP_7 = 0x0806, +
+  CTM_ATTRIB_MAP_8 = 0x0807 +
+ }
 

OpenCTM specific enumerators.

+ More...

Functions

CTMEXPORT CTMcontext CTMCALL ctmNewContext (CTMenum aMode)
 Create a new OpenCTM context.
CTMEXPORT void CTMCALL ctmFreeContext (CTMcontext aContext)
 Free an OpenCTM context.
CTMEXPORT CTMenum CTMCALL ctmGetError (CTMcontext aContext)
 Returns the latest error.
CTMEXPORT const char *CTMCALL ctmErrorString (CTMenum aError)
 Converts an OpenCTM error code to a zero-terminated string.
CTMEXPORT CTMuint CTMCALL ctmGetInteger (CTMcontext aContext, CTMenum aProperty)
 Get information about an OpenCTM context.
CTMEXPORT CTMfloat CTMCALL ctmGetFloat (CTMcontext aContext, CTMenum aProperty)
 Get information about an OpenCTM context.
CTMEXPORT const CTMuint *CTMCALL ctmGetIntegerArray (CTMcontext aContext, CTMenum aProperty)
 Get an integer array from an OpenCTM context.
CTMEXPORT const CTMfloat *CTMCALL ctmGetFloatArray (CTMcontext aContext, CTMenum aProperty)
 Get a floating point array from an OpenCTM context.
CTMEXPORT CTMenum CTMCALL ctmGetNamedUVMap (CTMcontext aContext, const char *aName)
 Get a reference to the named UV map.
CTMEXPORT const char *CTMCALL ctmGetUVMapString (CTMcontext aContext, CTMenum aUVMap, CTMenum aProperty)
 Get information about a UV map.
CTMEXPORT CTMfloat CTMCALL ctmGetUVMapFloat (CTMcontext aContext, CTMenum aUVMap, CTMenum aProperty)
 Get information about a UV map.
CTMEXPORT CTMenum CTMCALL ctmGetNamedAttribMap (CTMcontext aContext, const char *aName)
 Get a reference to the named vertex attribute map.
CTMEXPORT const char *CTMCALL ctmGetAttribMapString (CTMcontext aContext, CTMenum aAttribMap, CTMenum aProperty)
 Get information about a vertex attribute map.
CTMEXPORT CTMfloat CTMCALL ctmGetAttribMapFloat (CTMcontext aContext, CTMenum aAttribMap, CTMenum aProperty)
 Get information about a vertex attribute map.
CTMEXPORT const char *CTMCALL ctmGetString (CTMcontext aContext, CTMenum aProperty)
 Get information about an OpenCTM context.
CTMEXPORT void CTMCALL ctmCompressionMethod (CTMcontext aContext, CTMenum aMethod)
 Set which compression method to use for the given OpenCTM context.
CTMEXPORT void CTMCALL ctmCompressionLevel (CTMcontext aContext, CTMuint aLevel)
 Set which LZMA compression level to use for the given OpenCTM context.
CTMEXPORT void CTMCALL ctmVertexPrecision (CTMcontext aContext, CTMfloat aPrecision)
 Set the vertex coordinate precision (only used by the MG2 compression method).
CTMEXPORT void CTMCALL ctmVertexPrecisionRel (CTMcontext aContext, CTMfloat aRelPrecision)
 Set the vertex coordinate precision, relative to the mesh dimensions (only used by the MG2 compression method).
CTMEXPORT void CTMCALL ctmNormalPrecision (CTMcontext aContext, CTMfloat aPrecision)
 Set the normal precision (only used by the MG2 compression method).
CTMEXPORT void CTMCALL ctmUVCoordPrecision (CTMcontext aContext, CTMenum aUVMap, CTMfloat aPrecision)
 Set the coordinate precision for the specified UV map (only used by the MG2 compression method).
CTMEXPORT void CTMCALL ctmAttribPrecision (CTMcontext aContext, CTMenum aAttribMap, CTMfloat aPrecision)
 Set the attribute value precision for the specified attribute map (only used by the MG2 compression method).
CTMEXPORT void CTMCALL ctmFileComment (CTMcontext aContext, const char *aFileComment)
 Set the file comment for the given OpenCTM context.
CTMEXPORT void CTMCALL ctmDefineMesh (CTMcontext aContext, const CTMfloat *aVertices, CTMuint aVertexCount, const CTMuint *aIndices, CTMuint aTriangleCount, const CTMfloat *aNormals)
 Define a triangle mesh.
CTMEXPORT CTMenum CTMCALL ctmAddUVMap (CTMcontext aContext, const CTMfloat *aUVCoords, const char *aName, const char *aFileName)
 Define a UV map.
CTMEXPORT CTMenum CTMCALL ctmAddAttribMap (CTMcontext aContext, const CTMfloat *aAttribValues, const char *aName)
 Define a custom vertex attribute map.
CTMEXPORT void CTMCALL ctmLoad (CTMcontext aContext, const char *aFileName)
 Load an OpenCTM format file into the context.
CTMEXPORT void CTMCALL ctmLoadCustom (CTMcontext aContext, CTMreadfn aReadFn, void *aUserData)
 Load an OpenCTM format file using a custom stream read function.
CTMEXPORT void CTMCALL ctmSave (CTMcontext aContext, const char *aFileName)
 Save an OpenCTM format file.
CTMEXPORT void CTMCALL ctmSaveCustom (CTMcontext aContext, CTMwritefn aWriteFn, void *aUserData)
 Save an OpenCTM format file using a custom stream write function.
+

Define Documentation

+ +
+
+ + + + +
#define CTM_API_VERSION   0x00000100
+
+
+ +

OpenCTM API version (1.0).

+ +
+
+ +
+
+ + + + +
#define CTM_FALSE   0
+
+
+ +

Boolean FALSE.

+ +
+
+ +
+
+ + + + +
#define CTM_TRUE   1
+
+
+ +

Boolean TRUE.

+ +
+
+

Typedef Documentation

+ +
+
+ + + + +
typedef void* CTMcontext
+
+
+ +

OpenCTM context handle.

+ +
+
+ +
+
+ + + + +
typedef float CTMfloat
+
+
+ +

Single precision floating point type (IEEE 754 32 bits wide).

+ +
+
+ +
+
+ + + + +
typedef int32_t CTMint
+
+
+ +

Signed integer (32 bits wide).

+ +
+
+ +
+
+ + + + +
typedef CTMuint(CTMCALL * CTMreadfn)(void *aBuf, CTMuint aCount, void *aUserData)
+
+
+ +

Stream read() function pointer.

+
Parameters:
+ + + + +
[in] aBuf Pointer to the memory buffer to which data should be read.
[in] aCount The number of bytes to read.
[in] aUserData The custom user data that was passed to the ctmLoadCustom() function.
+
+
+
Returns:
The number of bytes actually read (if this is less than aCount, it indicates that an error occured or the end of file was reached before all bytes were read).
+ +
+
+ +
+
+ + + + +
typedef uint32_t CTMuint
+
+
+ +

Unsigned integer (32 bits wide).

+ +
+
+ +
+
+ + + + +
typedef CTMuint(CTMCALL * CTMwritefn)(const void *aBuf, CTMuint aCount, void *aUserData)
+
+
+ +

Stream write() function pointer.

+
Parameters:
+ + + + +
[in] aBuf Pointer to the memory buffer from which data should be written.
[in] aCount The number of bytes to write.
[in] aUserData The custom user data that was passed to the ctmSaveCustom() function.
+
+
+
Returns:
The number of bytes actually written (if this is less than aCount, it indicates that an error occured).
+ +
+
+

Enumeration Type Documentation

+ +
+
+ + + + +
enum CTMenum
+
+
+ +

OpenCTM specific enumerators.

+
Note:
For the information query functions, it is an error to query a value of the wrong type (e.g. to query a string value with the ctmGetInteger() function).
+
Enumerator:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CTM_NONE  +

No error has occured (everything is OK).

+

Also used as an error return value for functions that should return a CTMenum value.

+
CTM_INVALID_CONTEXT  +

The OpenCTM context was invalid (e.g. NULL).

+
CTM_INVALID_ARGUMENT  +

A function argument was invalid.

+
CTM_INVALID_OPERATION  +

The operation is not allowed.

+
CTM_INVALID_MESH  +

The mesh was invalid (e.g. no vertices).

+
CTM_OUT_OF_MEMORY  +

Not enough memory to proceed.

+
CTM_FILE_ERROR  +

File I/O error.

+
CTM_BAD_FORMAT  +

File format error (e.g. unrecognized format or corrupted file).

+
CTM_LZMA_ERROR  +

An error occured within the LZMA library.

+
CTM_INTERNAL_ERROR  +

An internal error occured (indicates a bug).

+
CTM_UNSUPPORTED_FORMAT_VERSION  +

Unsupported file format version.

+
CTM_IMPORT  +

The OpenCTM context will be used for importing data.

+
CTM_EXPORT  +

The OpenCTM context will be used for exporting data.

+
CTM_METHOD_RAW  +

Just store the raw data.

+
CTM_METHOD_MG1  +

Lossless compression (floating point).

+
CTM_METHOD_MG2  +

Lossless compression (fixed point).

+
CTM_VERTEX_COUNT  +

Number of vertices in the mesh (integer).

+
CTM_TRIANGLE_COUNT  +

Number of triangles in the mesh (integer).

+
CTM_HAS_NORMALS  +

CTM_TRUE if the mesh has normals (integer).

+
CTM_UV_MAP_COUNT  +

Number of UV coordinate sets (integer).

+
CTM_ATTRIB_MAP_COUNT  +

Number of custom attribute sets (integer).

+
CTM_VERTEX_PRECISION  +

Vertex precision - for MG2 (float).

+
CTM_NORMAL_PRECISION  +

Normal precision - for MG2 (float).

+
CTM_COMPRESSION_METHOD  +

Compression method (integer).

+
CTM_FILE_COMMENT  +

File comment (string).

+
CTM_NAME  +

Unique name (UV/attrib map string).

+
CTM_FILE_NAME  +

File name reference (UV map string).

+
CTM_PRECISION  +

Value precision (UV/attrib map float).

+
CTM_INDICES  +

Triangle indices (integer array).

+
CTM_VERTICES  +

Vertex point coordinates (float array).

+
CTM_NORMALS  +

Per vertex normals (float array).

+
CTM_UV_MAP_1  +

Per vertex UV map 1 (float array).

+
CTM_UV_MAP_2  +

Per vertex UV map 2 (float array).

+
CTM_UV_MAP_3  +

Per vertex UV map 3 (float array).

+
CTM_UV_MAP_4  +

Per vertex UV map 4 (float array).

+
CTM_UV_MAP_5  +

Per vertex UV map 5 (float array).

+
CTM_UV_MAP_6  +

Per vertex UV map 6 (float array).

+
CTM_UV_MAP_7  +

Per vertex UV map 7 (float array).

+
CTM_UV_MAP_8  +

Per vertex UV map 8 (float array).

+
CTM_ATTRIB_MAP_1  +

Per vertex attribute map 1 (float array).

+
CTM_ATTRIB_MAP_2  +

Per vertex attribute map 2 (float array).

+
CTM_ATTRIB_MAP_3  +

Per vertex attribute map 3 (float array).

+
CTM_ATTRIB_MAP_4  +

Per vertex attribute map 4 (float array).

+
CTM_ATTRIB_MAP_5  +

Per vertex attribute map 5 (float array).

+
CTM_ATTRIB_MAP_6  +

Per vertex attribute map 6 (float array).

+
CTM_ATTRIB_MAP_7  +

Per vertex attribute map 7 (float array).

+
CTM_ATTRIB_MAP_8  +

Per vertex attribute map 8 (float array).

+
+
+
+ +
+
+

Function Documentation

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
CTMEXPORT CTMenum CTMCALL ctmAddAttribMap (CTMcontext  aContext,
const CTMfloat aAttribValues,
const char *  aName 
)
+
+
+ +

Define a custom vertex attribute map.

+

Custom vertex attributes can be used for defining special per-vertex attributes, such as color, weight, ambient occlusion factor, etc.

+
Parameters:
+ + + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aAttribValues An array of attribute values. Each attribute value is made up by four consecutive floats, and there must be as many values as there are vertices in the mesh.
[in] aName A unique name for this attribute map (zero terminated UTF-8 string).
+
+
+
Returns:
A attribute map index (CTM_ATTRIB_MAP_1 and higher). If the function failed, it will return the zero valued CTM_NONE (use ctmGetError() to determine the cause of the error).
+
Note:
A triangle mesh must have been defined before calling this function, since the number of vertices is defined by the triangle mesh.
+
See also:
ctmDefineMesh().
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CTMEXPORT CTMenum CTMCALL ctmAddUVMap (CTMcontext  aContext,
const CTMfloat aUVCoords,
const char *  aName,
const char *  aFileName 
)
+
+
+ +

Define a UV map.

+

There can be several UV maps in a mesh. A UV map is typically used for 2D texture mapping.

+
Parameters:
+ + + + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aUVCoords An array of UV coordinates. Each UV coordinate is made up by two consecutive floats, and there must be as many coordinates as there are vertices in the mesh.
[in] aName A unique name for this UV map (zero terminated UTF-8 string).
[in] aFileName A reference to a image file (zero terminated UTF-8 string). If no file name reference exists, pass NULL.
+
+
+
Returns:
A UV map index (CTM_UV_MAP_1 and higher). If the function failed, it will return the zero valued CTM_NONE (use ctmGetError() to determine the cause of the error).
+
Note:
A triangle mesh must have been defined before calling this function, since the number of vertices is defined by the triangle mesh.
+
See also:
ctmDefineMesh().
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
CTMEXPORT void CTMCALL ctmAttribPrecision (CTMcontext  aContext,
CTMenum  aAttribMap,
CTMfloat  aPrecision 
)
+
+
+ +

Set the attribute value precision for the specified attribute map (only used by the MG2 compression method).

+
Parameters:
+ + + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aAttribMap An attribute map specifier for a defined attribute map (CTM_ATTRIB_MAP_1, ...).
[in] aPrecision Fixed point precision. For instance, if this value is 0.001, all attribute values will be rounded to three decimals. If the attributes represent integer values, set the precision to 1.0. The default attribute precision is 2^-8 ~= 0.0039.
+
+
+
See also:
ctmAddAttribMap().
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
CTMEXPORT void CTMCALL ctmCompressionLevel (CTMcontext  aContext,
CTMuint  aLevel 
)
+
+
+ +

Set which LZMA compression level to use for the given OpenCTM context.

+

The compression level can be between 0 (fastest) and 9 (best). The higher the compression level, the more memory is required for compression and decompression. The default compression level is 1.

+
Parameters:
+ + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aLevel Which compression level to use (0 to 9).
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
CTMEXPORT void CTMCALL ctmCompressionMethod (CTMcontext  aContext,
CTMenum  aMethod 
)
+
+
+ +

Set which compression method to use for the given OpenCTM context.

+

The selected compression method will be used when calling the ctmSave() function.

+
Parameters:
+ + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aMethod Which compression method to use: CTM_METHOD_RAW, CTM_METHOD_MG1 or CTM_METHOD_MG2 (the default method is CTM_METHOD_MG1).
+
+
+
See also:
CTM_METHOD_RAW, CTM_METHOD_MG1, CTM_METHOD_MG2
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CTMEXPORT void CTMCALL ctmDefineMesh (CTMcontext  aContext,
const CTMfloat aVertices,
CTMuint  aVertexCount,
const CTMuint aIndices,
CTMuint  aTriangleCount,
const CTMfloat aNormals 
)
+
+
+ +

Define a triangle mesh.

+
Parameters:
+ + + + + + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aVertices An array of vertices (three consecutive floats make one vertex).
[in] aVertexCount The number of vertices in aVertices (and optionally aTexCoords).
[in] aIndices An array of vertex indices (three consecutive integers make one triangle).
[in] aTriangleCount The number of triangles in aIndices (there must be exactly 3 x aTriangleCount indices in aIndices).
[in] aNormals An array of per-vertex normals (or NULL if there are no normals). Each normal is made up by three consecutive floats, and there must be aVertexCount normals.
+
+
+
See also:
ctmAddUVMap(), ctmAddAttribMap(), ctmSave(), ctmSaveCustom().
+ +
+
+ +
+
+ + + + + + + + + +
CTMEXPORT const char* CTMCALL ctmErrorString (CTMenum  aError ) 
+
+
+ +

Converts an OpenCTM error code to a zero-terminated string.

+
Parameters:
+ + +
[in] aError An OpenCTM error code, as returned by ctmGetError().
+
+
+
Returns:
A zero terminated string that describes the error. For instance, if aError is CTM_INVALID_OPERATION, then the return value will be "CTM_INVALID_OPERATION".
+
See also:
CTMenum
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
CTMEXPORT void CTMCALL ctmFileComment (CTMcontext  aContext,
const char *  aFileComment 
)
+
+
+ +

Set the file comment for the given OpenCTM context.

+
Parameters:
+ + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aFileComment The file comment (zero terminated UTF-8 string).
+
+
+ +
+
+ +
+
+ + + + + + + + + +
CTMEXPORT void CTMCALL ctmFreeContext (CTMcontext  aContext ) 
+
+
+ +

Free an OpenCTM context.

+
Parameters:
+ + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
+
+
+
See also:
ctmNewContext()
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
CTMEXPORT CTMfloat CTMCALL ctmGetAttribMapFloat (CTMcontext  aContext,
CTMenum  aAttribMap,
CTMenum  aProperty 
)
+
+
+ +

Get information about a vertex attribute map.

+
Parameters:
+ + + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aAttribMap Which vertex attribute map to query (CTM_ATTRIB_MAP_1 or higher).
[in] aProperty Which vertex attribute map property to return.
+
+
+
Returns:
A floating point value, representing the vertex attribute map property given by aProperty.
+
See also:
CTMenum
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
CTMEXPORT const char* CTMCALL ctmGetAttribMapString (CTMcontext  aContext,
CTMenum  aAttribMap,
CTMenum  aProperty 
)
+
+
+ +

Get information about a vertex attribute map.

+
Parameters:
+ + + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aAttribMap Which vertex attribute map to query (CTM_ATTRIB_MAP_1 or higher).
[in] aProperty Which vertex attribute map property to return.
+
+
+
Returns:
A string value, representing the vertex attribute map property given by aProperty.
+
Note:
The string is only valid as long as the vertex attribute map within the OpenCTM context is valid. Trying to access an invalid string will result in undefined behaviour. Therefor it is recommended that the string is copied to a new variable if it is to be used other than directly after the call to ctmGetAttribMapString().
+
See also:
CTMenum
+ +
+
+ +
+
+ + + + + + + + + +
CTMEXPORT CTMenum CTMCALL ctmGetError (CTMcontext  aContext ) 
+
+
+ +

Returns the latest error.

+

Calling this function will return the last produced error code, or CTM_NO_ERROR (zero) if no error has occured since the last call to ctmGetError(). When this function is called, the internal error varibale will be reset to CTM_NONE.

+
Parameters:
+ + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
+
+
+
Returns:
An OpenCTM error code.
+
See also:
CTMenum
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
CTMEXPORT CTMfloat CTMCALL ctmGetFloat (CTMcontext  aContext,
CTMenum  aProperty 
)
+
+
+ +

Get information about an OpenCTM context.

+
Parameters:
+ + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aProperty Which property to return.
+
+
+
Returns:
A floating point value, representing the OpenCTM context property given by aProperty.
+
See also:
CTMenum
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
CTMEXPORT const CTMfloat* CTMCALL ctmGetFloatArray (CTMcontext  aContext,
CTMenum  aProperty 
)
+
+
+ +

Get a floating point array from an OpenCTM context.

+
Parameters:
+ + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aProperty Which array to return.
+
+
+
Returns:
A floating point array. If the requested array does not exist, or if aProperty does not indicate a float array, the function returns NULL.
+
Note:
The array is only valid as long as the OpenCTM context is valid, or until the corresponding array changes within the OpenCTM context. Trying to access an invalid array will result in undefined behaviour. Therefor it is recommended that the array is copied to a new variable if it is to be used other than directly after the call to ctmGetFloatArray().
+
See also:
CTMenum
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
CTMEXPORT CTMuint CTMCALL ctmGetInteger (CTMcontext  aContext,
CTMenum  aProperty 
)
+
+
+ +

Get information about an OpenCTM context.

+
Parameters:
+ + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aProperty Which property to return.
+
+
+
Returns:
An integer value, representing the OpenCTM context property given by aProperty.
+
See also:
CTMenum
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
CTMEXPORT const CTMuint* CTMCALL ctmGetIntegerArray (CTMcontext  aContext,
CTMenum  aProperty 
)
+
+
+ +

Get an integer array from an OpenCTM context.

+
Parameters:
+ + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aProperty Which array to return.
+
+
+
Returns:
An integer array. If the requested array does not exist, or if aProperty does not indicate an integer array, the function returns NULL.
+
Note:
The array is only valid as long as the OpenCTM context is valid, or until the corresponding array changes within the OpenCTM context. Trying to access an invalid array will result in undefined behaviour. Therefor it is recommended that the array is copied to a new variable if it is to be used other than directly after the call to ctmGetIntegerArray().
+
See also:
CTMenum
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
CTMEXPORT CTMenum CTMCALL ctmGetNamedAttribMap (CTMcontext  aContext,
const char *  aName 
)
+
+
+ +

Get a reference to the named vertex attribute map.

+
Parameters:
+ + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aName The name of the attribute map that should be returned.
+
+
+
Returns:
A reference to an attribute map. If the attribute map was found, a value of CTM_ATTRIB_MAP_1 or higher is returned, otherwise CTM_NONE is returned.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
CTMEXPORT CTMenum CTMCALL ctmGetNamedUVMap (CTMcontext  aContext,
const char *  aName 
)
+
+
+ +

Get a reference to the named UV map.

+
Parameters:
+ + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aName The name of the UV map that should be returned.
+
+
+
Returns:
A reference to a UV map. If the UV map was found, a value of CTM_UV_MAP_1 or higher is returned, otherwise CTM_NONE is returned.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
CTMEXPORT const char* CTMCALL ctmGetString (CTMcontext  aContext,
CTMenum  aProperty 
)
+
+
+ +

Get information about an OpenCTM context.

+
Parameters:
+ + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aProperty Which property to return.
+
+
+
Returns:
A string value, representing the OpenCTM context property given by aProperty.
+
Note:
The string is only valid as long as the OpenCTM context is valid, or until the corresponding string changes within the OpenCTM context (e.g. calling ctmFileComment() invalidates the CTM_FILE_COMMENT string). Trying to access an invalid string will result in undefined behaviour. Therefor it is recommended that the string is copied to a new variable if it is to be used other than directly after the call to ctmGetString().
+
See also:
CTMenum
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
CTMEXPORT CTMfloat CTMCALL ctmGetUVMapFloat (CTMcontext  aContext,
CTMenum  aUVMap,
CTMenum  aProperty 
)
+
+
+ +

Get information about a UV map.

+
Parameters:
+ + + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aUVMap Which UV map to query (CTM_UV_MAP_1 or higher).
[in] aProperty Which UV map property to return.
+
+
+
Returns:
A floating point value, representing the UV map property given by aProperty.
+
See also:
CTMenum
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
CTMEXPORT const char* CTMCALL ctmGetUVMapString (CTMcontext  aContext,
CTMenum  aUVMap,
CTMenum  aProperty 
)
+
+
+ +

Get information about a UV map.

+
Parameters:
+ + + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aUVMap Which UV map to query (CTM_UV_MAP_1 or higher).
[in] aProperty Which UV map property to return.
+
+
+
Returns:
A string value, representing the UV map property given by aProperty.
+
Note:
The string is only valid as long as the UV map within the OpenCTM context is valid. Trying to access an invalid string will result in undefined behaviour. Therefor it is recommended that the string is copied to a new variable if it is to be used other than directly after the call to ctmGetUVMapString().
+
See also:
CTMenum
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
CTMEXPORT void CTMCALL ctmLoad (CTMcontext  aContext,
const char *  aFileName 
)
+
+
+ +

Load an OpenCTM format file into the context.

+

The mesh data can be retrieved with the various ctmGet functions.

+
Parameters:
+ + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aFileName The name of the file to be loaded.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
CTMEXPORT void CTMCALL ctmLoadCustom (CTMcontext  aContext,
CTMreadfn  aReadFn,
void *  aUserData 
)
+
+
+ +

Load an OpenCTM format file using a custom stream read function.

+

The mesh data can be retrieved with the various ctmGet functions.

+
Parameters:
+ + + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aReadFn Pointer to a custom stream read function.
[in] aUserData Custom user data, which can be a C language FILE handle, C++ istream object, or a custom object pointer of any type. The user data pointer will be passed to the custom stream read function.
+
+
+
See also:
CTMreadfn.
+ +
+
+ +
+
+ + + + + + + + + +
CTMEXPORT CTMcontext CTMCALL ctmNewContext (CTMenum  aMode ) 
+
+
+ +

Create a new OpenCTM context.

+

The context is used for all subsequent OpenCTM function calls. Several contexts can coexist at the same time.

+
Parameters:
+ + +
[in] aMode An OpenCTM context mode. Set this to CTM_IMPORT if the context will be used for importing data, or set it to CTM_EXPORT if it will be used for exporting data.
+
+
+
Returns:
An OpenCTM context handle (or NULL if no context could be created).
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
CTMEXPORT void CTMCALL ctmNormalPrecision (CTMcontext  aContext,
CTMfloat  aPrecision 
)
+
+
+ +

Set the normal precision (only used by the MG2 compression method).

+

The normal is represented in spherical coordinates in the MG2 compression method, and the normal precision controls the angular and radial resolution.

+
Parameters:
+ + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aPrecision Fixed point precision. For the angular information, this value represents the angular precision. For the radial information, this value is the linear resolution. For instance, 0.01 means that the circle is divided into 100 steps, and the normal magnitude is rounded to 2 decimals. The default normal precision is 2^-8 ~= 0.0039.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
CTMEXPORT void CTMCALL ctmSave (CTMcontext  aContext,
const char *  aFileName 
)
+
+
+ +

Save an OpenCTM format file.

+

The mesh must have been defined by ctmDefineMesh().

+
Parameters:
+ + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aFileName The name of the file to be saved.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
CTMEXPORT void CTMCALL ctmSaveCustom (CTMcontext  aContext,
CTMwritefn  aWriteFn,
void *  aUserData 
)
+
+
+ +

Save an OpenCTM format file using a custom stream write function.

+

The mesh must have been defined by ctmDefineMesh().

+
Parameters:
+ + + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aWriteFn Pointer to a custom stream write function.
[in] aUserData Custom user data, which can be a C language FILE handle, C++ ostream object, or a custom object pointer of any type. The user data pointer will be passed to the custom stream write function.
+
+
+
See also:
CTMwritefn.
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
CTMEXPORT void CTMCALL ctmUVCoordPrecision (CTMcontext  aContext,
CTMenum  aUVMap,
CTMfloat  aPrecision 
)
+
+
+ +

Set the coordinate precision for the specified UV map (only used by the MG2 compression method).

+
Parameters:
+ + + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aUVMap A UV map specifier for a defined UV map (CTM_UV_MAP_1, ...).
[in] aPrecision Fixed point precision. For instance, if this value is 0.001, all UV coordinates will be rounded to three decimals. The default UV coordinate precision is 2^-12 ~= 0.00024.
+
+
+
See also:
ctmAddUVMap().
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
CTMEXPORT void CTMCALL ctmVertexPrecision (CTMcontext  aContext,
CTMfloat  aPrecision 
)
+
+
+ +

Set the vertex coordinate precision (only used by the MG2 compression method).

+
Parameters:
+ + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aPrecision Fixed point precision. For instance, if this value is 0.001, all vertex coordinates will be rounded to three decimals. The default vertex coordinate precision is 2^-10 ~= 0.00098.
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
CTMEXPORT void CTMCALL ctmVertexPrecisionRel (CTMcontext  aContext,
CTMfloat  aRelPrecision 
)
+
+
+ +

Set the vertex coordinate precision, relative to the mesh dimensions (only used by the MG2 compression method).

+
Parameters:
+ + + +
[in] aContext An OpenCTM context that has been created by ctmNewContext().
[in] aRelPrecision Relative precision. This factor is multiplied by the average triangle edge length in the mesh in order to obtain the final, fixed point precision. For instance, if aRelPrecision is 0.01, and the average edge length is 3.7, then the fixed point precision is set to 0.037.
+
+
+
Note:
The mesh must have been defined using the ctmDefineMesh() function before calling this function.
+
See also:
ctmVertexPrecision().
+ +
+
+
+
+

Copyright © 2009-2010 Marcus Geelnard — + openctm.sourceforge.net

+
+ + diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/openctm_8h_source.html b/src/external/OpenCTM-1.0.3/doc/APIReference/openctm_8h_source.html new file mode 100644 index 000000000..740225adf --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/openctm_8h_source.html @@ -0,0 +1,287 @@ + + + + +OpenCTM: openctm.h Source File + + + + + + +
+

Copyright © 2009-2010 Marcus Geelnard — + openctm.sourceforge.net

+
+ + diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/openctmpp_8h.html b/src/external/OpenCTM-1.0.3/doc/APIReference/openctmpp_8h.html new file mode 100644 index 000000000..fc52a74d6 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/openctmpp_8h.html @@ -0,0 +1,46 @@ + + + + +OpenCTM: openctmpp.h File Reference + + + + + + +
+

openctmpp.h File Reference

#include "openctm.h"
+#include <exception>
+ +

Go to the source code of this file.

+ + + + + + + + +

Classes

class  ctm_error
 OpenCTM exception. More...
class  CTMimporter
 OpenCTM importer class. More...
class  CTMexporter
 OpenCTM exporter class. More...
+
+
+

Copyright © 2009-2010 Marcus Geelnard — + openctm.sourceforge.net

+
+ + diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/openctmpp_8h_source.html b/src/external/OpenCTM-1.0.3/doc/APIReference/openctmpp_8h_source.html new file mode 100644 index 000000000..24c8c2703 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/openctmpp_8h_source.html @@ -0,0 +1,333 @@ + + + + +OpenCTM: openctmpp.h Source File + + + + + + +
+

Copyright © 2009-2010 Marcus Geelnard — + openctm.sourceforge.net

+
+ + diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/tab_b.gif b/src/external/OpenCTM-1.0.3/doc/APIReference/tab_b.gif new file mode 100644 index 0000000000000000000000000000000000000000..0d623483ffdf5f9f96900108042a7ab0643fe2a3 GIT binary patch literal 35 ncmZ?wbhEHbWMp7uXkcJy*>IeJfk6j|fqX^=1|}vKMh0sDa2W*H literal 0 HcmV?d00001 diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/tab_l.gif b/src/external/OpenCTM-1.0.3/doc/APIReference/tab_l.gif new file mode 100644 index 0000000000000000000000000000000000000000..9b1e6337c9299a700401a2a78a2c6ffced475216 GIT binary patch literal 706 zcmZ?wbhEHbZT`}F1e&(Gg}Y(8=I;HA5#Z$3JI=gGB)FQ#odI(O&E^@q;x zK6mr*m3xOS-#u~t!I@i+u0DKm^U160k6t`|^WpV}&n+8{U%dD9&a>B#U%!9-@yol< zU%&tQ{rk_K|NsC0`}dE5ET99@1@a36+kb~?0UJ*yc&I3X_m z!ND^5$O7$#8OFRuDhG}!?8z?cdZK&!`PWjdR;Aj^wZ` zeK{IEYHBJ)6K8VIp1`BVt++swf6j+=L{p1*nO(VhE`pFexG@5$|>uaCcd z`0m=9m+yak{QmXN#Sc$^{$X9h9&q2jiKAI|&T)a;PPx2K9p`YIdw8HtR5k2Q$2-O2 z*;3y{MQ-RnJTgJfI&R5|O)AHxDf_00XbPvDZPy4t=hHd)nfLPvms&O`Ok(sD()5v$ z5U@&h;a=#xbxVbo2~X&Xj0Ie(f{v>vERH+qC+nTG=B8Nca=wU-O$?1&vUgV~9=!H; zx>3p9Yn%*<>t~sk+&0xfyS8RsPfYBd<~wWK%j-LmpU>O7yX^h#UCp1x-p#i7@bE;py8XI6 zmY<)m>~)W~yIWcMVoiPg{duuf<*)9qZ9l$m*Ph&W&$jlv*Vpa+{pH@n=IQ$L?0$ax ec60Ul|8o2P|NVbd{6P)#weSbE3}s?04AuZvx_~SI literal 0 HcmV?d00001 diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/tab_r.gif b/src/external/OpenCTM-1.0.3/doc/APIReference/tab_r.gif new file mode 100644 index 0000000000000000000000000000000000000000..ce9dd9f533cb5486d6941844f442b59d4a9e9175 GIT binary patch literal 2585 zcmbV}`9Bkk1ILFF--w5zJc=ZZT(zjE=;2|_S)Qm~rCWz1Pc)KPl;jv%A#&v2*x}yc zmf2~Jm~&=xjJY?PqwIN}f8qQ2{r$uH{c*nJbmr{cR5??*egHrs-B=MzCF`3%e{FAW z{oL5xTHn~5TM{jaB;@|_Ue5F&Zb@p(kMyG{*;gWDg zyeL|eZf7Qd8=#bXzSiR{yzRgLSj-fJS8>lBjVHN z^o-0eS=nE6a`W;LChBs=`+QAJP~{b93>H^eRb5kCSC1zUNezun%`L5M?RDzv#%jk7 zYVRX=vATPD`+oEfum^{RM@GjuP?-r=yh0!p;Vx^T9G7~`7%5ydH%70=jyJ;;`d;hv92x3R=z{xp+Lg2!*@OK*K15-t&okoPtSED)h&$RLxdbA zseWm^C3d%-yRNi-ryk^!ek+C`n&~cd$#ZWct_cUL{l~i+Nzx^5d!n94(>bW-iL~Rl z&8r)?q|1DIo=0=judQ{FaGcfLERz8gfn3-Qt<2lksh{mzpT}DXxUuR^z=^key&q4! z+wWI45vL0k$R^(F#{qfqhUsN@WA+w-V?LPH33!Q?WFSB3)WBojE@hK41Nb?KfS+Qo zXgrzfsP$wr4Qzy*{OD>uJBjdgGM@VMml5)2f~_}lD*YyOb}Hjeobhz#4c`w(l^>KK zr?Ud;W~Z}*w;%hZ|2^p^+f06gJDJQD zeIhGADbDmm&6arh(q>EZ<7mjzg7l|z$hRL8=1>)Nv=S7CY$B}iYJ&*T_-T_OG*L1q ztZ3Lana33?y3AKnyq^YCF|4x%Rb5WU&2qcl{TFKey%QJeMxn^SdT!hZ5+0i1zeusiYVp-phBl7b5+Px-X&LhByq z0F&<;K0l2+v>qiHlXb#$jXMv$uK-dEGE9L~qtdU(XeRXmvu*K2Q&6!fD**JxYP4b4BR7FdJ$Qx9G9`J%-_X!a#LGpp3g9)VWytGCa;7`S1_e8F~!R+aSJ zOF17p2`H?2kPs8Q`_;U}+D%3p zs2-0BTqFwpUoBk`?P;iPQ(IbEA|JmMx!P&YYG|R@S=5Mnw;-?A6rEEVyV%d7{iU4a zNk`i!%F(Ykpm`}#oH;BjY->@b8vQedv;pza2FL&*6ufjd+*3Ute&>kes~TU?^KkojsTh(o~(3tk1Y6>4(yn( z#U*ID9@eg-beKo1B;HXe+}{Z%n@7m0+yxivuqk9~;!1LGQlah)xYK4>wgL}l6dsaN zIxlRlq`*`j9PG4*0hD6YV_b_2w5b#)o7J?`q#{GjvvKlD`T*dWcZx<-s(ZvLB44E# z=!|sw!?)@%y$oRNL#25WS3lzdii}TuQ3?CLnvQ1_n};2sT_;Y;#d3=+-(O% zMN$>O!3;ke(UuLR%h_&)N zs^!-@A>QR}4yB1bPp`9S19ikTbZ~O{&FF-yHK{En;mmShDUIEw03`j(DBIsM}Rjki2J#SQa3gFZTKBPDeIiLt9Z z%bL3(B@Qw%(B`wSMS~dPh$=R`(}lBoFXKy(s|*{#ru$wjsBc_O#zxNk9w+UUHmx(U zmJ8+M+ndtnZ<7|VU9Mbt61zpo9T&3%Wx&XII=#QJxjR`CZf22ac3d51Z?GD%LEe_&*t46Qf;4`bZ7p2K(Ab5>GfT^}4! zBT&HZD`^PEgWoI&{~o-ID0F?O`75sm(87x%A{(}Ch1)QlzdJ)1B-eqe5a(weg0`4lQIf1evjvbBY50DVbzO7CLf|vP z2#0(U-|jZ`H{y5N^o7%iK6H>_HEGN->U6^!)1{XpJV!!4(Ig7wzZQ*9WYF4X1rG0x z=1uA@i`rIAciubDC{;~b(|&|A@xkjRP5aRcvRU9tvIm}jDB6J eQ0-6-y)mpwdT=ayS0tBxKDA*~;EWmo literal 0 HcmV?d00001 diff --git a/src/external/OpenCTM-1.0.3/doc/APIReference/tabs.css b/src/external/OpenCTM-1.0.3/doc/APIReference/tabs.css new file mode 100644 index 000000000..a44416341 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/APIReference/tabs.css @@ -0,0 +1,105 @@ +/* tabs styles, based on http://www.alistapart.com/articles/slidingdoors */ + +DIV.tabs +{ + float : left; + width : 100%; + background : url("tab_b.gif") repeat-x bottom; + margin-bottom : 4px; +} + +DIV.tabs UL +{ + margin : 0px; + padding-left : 10px; + list-style : none; +} + +DIV.tabs LI, DIV.tabs FORM +{ + display : inline; + margin : 0px; + padding : 0px; +} + +DIV.tabs FORM +{ + float : right; +} + +DIV.tabs A +{ + float : left; + background : url("tab_r.gif") no-repeat right top; + border-bottom : 1px solid #84B0C7; + font-size : 80%; + font-weight : bold; + text-decoration : none; +} + +DIV.tabs A:hover +{ + background-position: 100% -150px; +} + +DIV.tabs A:link, DIV.tabs A:visited, +DIV.tabs A:active, DIV.tabs A:hover +{ + color: #1A419D; +} + +DIV.tabs SPAN +{ + float : left; + display : block; + background : url("tab_l.gif") no-repeat left top; + padding : 5px 9px; + white-space : nowrap; +} + +DIV.tabs #MSearchBox +{ + float : right; + display : inline; + font-size : 1em; +} + +DIV.tabs TD +{ + font-size : 80%; + font-weight : bold; + text-decoration : none; +} + + + +/* Commented Backslash Hack hides rule from IE5-Mac \*/ +DIV.tabs SPAN {float : none;} +/* End IE5-Mac hack */ + +DIV.tabs A:hover SPAN +{ + background-position: 0% -150px; +} + +DIV.tabs LI.current A +{ + background-position: 100% -150px; + border-width : 0px; +} + +DIV.tabs LI.current SPAN +{ + background-position: 0% -150px; + padding-bottom : 6px; +} + +DIV.navpath +{ + background : none; + border : none; + border-bottom : 1px solid #84B0C7; + text-align : center; + margin : 2px; + padding : 2px; +} diff --git a/src/external/OpenCTM-1.0.3/doc/DevelopersManual.pdf b/src/external/OpenCTM-1.0.3/doc/DevelopersManual.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d280b66f6743b4a42feb5109dcaf25fb70526c20 GIT binary patch literal 174834 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

11bjKfsrfv%7iSDN4sJJFt%}E)QuhHyV?Q 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 V;2yq@16D;RlEhS1O>CEn{Xf}Oo5%nF literal 0 HcmV?d00001 diff --git a/src/external/OpenCTM-1.0.3/doc/FormatSpecification.pdf b/src/external/OpenCTM-1.0.3/doc/FormatSpecification.pdf new file mode 100644 index 0000000000000000000000000000000000000000..fa8ce84c87c8822ad13cb66cb92895452588dcfc GIT binary patch literal 126994 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 TX9wT}L?V_$Qc~MkhvWYPrO%{o literal 0 HcmV?d00001 diff --git a/src/external/OpenCTM-1.0.3/doc/ctmconv.1 b/src/external/OpenCTM-1.0.3/doc/ctmconv.1 new file mode 100644 index 000000000..ad76f0745 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/ctmconv.1 @@ -0,0 +1,92 @@ +.TH ctmconv 1 +.SH NAME +.B ctmconv +- file format converter for 3D models +.SH SYNOPSIS +.B ctmconv +.I infile outfile [options] +.SH DESCRIPTION +.B ctmconv +is a 3D file converter that can convert 3D model files to and from several +different formats. +.PP +The file +.I infile +is loaded, and then saved as +.I outfile +in the target file format. +.PP +The input and output file formats are determined from the file endings. +.SH OPTIONS +The following options are available: +.TP 16 +.B --scale arg +Scale the mesh by a scalar factor. +.TP +.B --upaxis arg +Set up axis (X, Y, Z, -X, -Y, -Z). If != Z, the mesh will be flipped. +.TP +.B --flip +Flip triangle orientation. +.TP +.B --calc-normals +If the source file does not contain any normals, calculate them. +.TP +.B --no-normals +Do not export normals. +.TP +.B --no-texcoords +Do not export texture coordinates. +.TP +.B --no-colors +Do not export vertex colors. +.TP +.B --comment arg +Set the file comment (default is to use the comment from the input file, if +any). +.TP +.B --texfile arg +Set the texture file name reference for the texture (default is to use the +texture file name reference from the input file, if any). +.PP +When exporting an OpenCTM file, the following options are also +available: +.TP 16 +.B --method arg +Select compression method (RAW, MG1, MG2). +.TP +.B --level arg +Set the compression level (0 - 9). +.TP +.B --vprec arg +Set vertex precision (only for MG2). +.TP +.B --vprecrel arg +Set vertex precision, relative method (only for MG2). +.TP +.B --nprec arg +Set normal precision (only for MG2). +.TP +.B --tprec arg +Set texture map precision (only for MG2). +.TP +.B --cprec arg +Set color precision (only for MG2). +.SH FILE FORMATS +The following 3D model file formats are supported: +OpenCTM (.ctm), +Stanford triangle format (.ply), +Stereolitography (.stl), +3D Studio (.3ds), +COLLADA 1.4/1.5 (.dae), +Wavefront geometry file (.obj), +LightWave object (.lwo), +Geomview object file format (.off), +VRML 2.0 - export only (.wrl). +.SH AVAILABILITY +.B ctmconv +is designed to be portable, and is available for several different systems, +including (but not limited to): Windows, Mac OS X (10.3+), Linux and +OpenSolaris. +.SH SEE ALSO +ctmviewer(1) diff --git a/src/external/OpenCTM-1.0.3/doc/ctmviewer.1 b/src/external/OpenCTM-1.0.3/doc/ctmviewer.1 new file mode 100644 index 000000000..d06dce48d --- /dev/null +++ b/src/external/OpenCTM-1.0.3/doc/ctmviewer.1 @@ -0,0 +1,86 @@ +.TH ctmviewer 1 +.SH NAME +.B ctmviewer +- 3D viewer for models of various file formats +.SH SYNOPSIS +.B ctmviewer +.I [modelfile [texturefile]] +.SH DESCRIPTION +.B ctmviewer +is a 3D file viewer that can load, show and save 3D model files in several +different formats. +.PP +The program displays an interactive 3D view of the model, which can be operated +with the mouse (e.g. for rotating and zooming). +.PP +If the selected model file contains texture coordinate information, it is +possible to specify which 2D image file to use as a texture with the additional +.I texturefile +argument. If no texture file is given (either by the 3D model file, or by the +.I texturefile +argument), a standard 2D grid is used as a texture. +.SH GUI OPERATIONS +In addition to the command line arguments, +.B ctmviewer +offers several operations that can be performed from the 3D GUI display. For +help, press the F1 key. +.SS Loading and Saving +It is possible to load and save 3D model files from the program by either +using the buttons in the upper left corner of the 3D display, or by using the +keyboard shortcuts CTRL+O (open) and CTRL+S (save). +.PP +It is also possible to load a texture file from the program by using the +Open Texture button. +.SS Rendering +To toggle between a normal filled surface view (default) and a wire frame view, +press the 'w' key. +.SS Camera Control +By holding down the left mouse button and moving the mouse, the camera is +rotated around the 3D model. +.PP +By holding down the right mouse button and moving the mouse, the camera will +pan left/right and up/down. +.PP +By holding down the middle mouse button and moving the mouse, the camera will +zoom in and out. It is also possible to use the mouse wheel (not supported on +all systems) or the +/- keys to zoom in and out. +.PP +Double click the left mouse button on a point on the model to focus the camera +on that point. +.PP +Press the 'f' key to fit the model into the screen view (re-center and re-zoom). +.PP +Press the 'y' key to change the camera up direction to the Y axis (may be +necessary if the model was designed in or for an environment where the Y axis +is considered the up direction). +.PP +Press the 'z' key to change the camera up direction to the Z axis (default). +.SH FILE FORMATS +The following 3D model file formats are supported: +OpenCTM (.ctm), +Stanford triangle format (.ply), +Stereolitography (.stl), +3D Studio (.3ds), +COLLADA 1.4/1.5 (.dae), +Wavefront geometry file (.obj), +LightWave object (.lwo), +Geomview object file format (.off), +VRML 2.0 - export only (.wrl). +.PP +The following 2D image file formats are supported (texture): +JPEG (.jpg), PNG (.png). +.SH AVAILABILITY +.B ctmviewer +is designed to be portable, and is available for several different systems, +including (but not limited to): Windows, Mac OS X (10.3+), Linux and +OpenSolaris. +.PP +.B ctmviewer +uses OpenGL for its accelerated 3D display. When the OpenGL implementation +supports it, +.B ctmviewer +will use per pixel Phong shading for improved visual appearance. Otherwise +.B ctmviewer +will fall back to classic per vertex shading. +.SH SEE ALSO +ctmconv(1) diff --git a/src/external/OpenCTM-1.0.3/lib/Makefile.linux b/src/external/OpenCTM-1.0.3/lib/Makefile.linux new file mode 100644 index 000000000..9e270e517 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/Makefile.linux @@ -0,0 +1,81 @@ +############################################################################### +# Product: OpenCTM +# File: Makefile.linux +# Description: Makefile for Linux systems (should work on most Un*x-like +# systems with gcc, e.g. OpenSolaris). +############################################################################### +# Copyright (c) 2009-2010 Marcus Geelnard +# +# This software is provided 'as-is', without any express or implied +# warranty. In no event will the authors be held liable for any damages +# arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment in the product documentation would be +# appreciated but is not required. +# +# 2. Altered source versions must be plainly marked as such, and must not +# be misrepresented as being the original software. +# +# 3. This notice may not be removed or altered from any source +# distribution. +############################################################################### + +LZMADIR = liblzma +CC = gcc +CFLAGS = -O3 -W -Wall -c -fPIC -DOPENCTM_BUILD -I$(LZMADIR) -DLZMA_PREFIX_CTM -std=c99 -pedantic +CFLAGS_LZMA = -O3 -W -Wall -c -fPIC -DLZMA_PREFIX_CTM -std=c99 -pedantic +RM = rm -f +DEPEND = $(CPP) -MM + +DYNAMICLIB = libopenctm.so + +OBJS = openctm.o \ + stream.o \ + compressRAW.o \ + compressMG1.o \ + compressMG2.o + +LZMA_OBJS = Alloc.o \ + LzFind.o \ + LzmaDec.o \ + LzmaEnc.o \ + LzmaLib.o + +SRCS = openctm.c \ + stream.c \ + compressRAW.c \ + compressMG1.c \ + compressMG2.c + +LZMA_SRCS = $(LZMADIR)/Alloc.c \ + $(LZMADIR)/LzFind.c \ + $(LZMADIR)/LzmaDec.c \ + $(LZMADIR)/LzmaEnc.c \ + $(LZMADIR)/LzmaLib.c + +.phony: all clean depend + +all: $(DYNAMICLIB) + +clean: + $(RM) $(DYNAMICLIB) $(OBJS) $(LZMA_OBJS) + +$(DYNAMICLIB): $(OBJS) $(LZMA_OBJS) + gcc -shared -s -Wl,-soname,$@ -o $@ $(OBJS) $(LZMA_OBJS) -lm + +%.o: %.c + $(CC) $(CFLAGS) $< + +%.o: $(LZMADIR)/%.c + $(CC) $(CFLAGS_LZMA) $< + +depend: + $(DEPEND) $(SRCS) $(LZMA_SRCS) > make.depend + +-include make.depend diff --git a/src/external/OpenCTM-1.0.3/lib/Makefile.macosx b/src/external/OpenCTM-1.0.3/lib/Makefile.macosx new file mode 100644 index 000000000..d1685a0c6 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/Makefile.macosx @@ -0,0 +1,86 @@ +############################################################################### +# Product: OpenCTM +# File: Makefile.macosx +# Description: Makefile for Mac OS X. +############################################################################### +# Copyright (c) 2009-2010 Marcus Geelnard +# +# This software is provided 'as-is', without any express or implied +# warranty. In no event will the authors be held liable for any damages +# arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment in the product documentation would be +# appreciated but is not required. +# +# 2. Altered source versions must be plainly marked as such, and must not +# be misrepresented as being the original software. +# +# 3. This notice may not be removed or altered from any source +# distribution. +############################################################################### + +LZMADIR = liblzma +CC = gcc +CFLAGS = -arch i386 -O3 -W -Wall -c -fvisibility=hidden -DOPENCTM_BUILD -I$(LZMADIR) -DLZMA_PREFIX_CTM -std=c99 -pedantic +CFLAGS_LZMA = -arch i386 -O3 -W -Wall -c -fvisibility=hidden -DLZMA_PREFIX_CTM -std=c99 -pedantic +RM = rm -f +DEPEND = $(CPP) -MM + +DYNAMICLIB = libopenctm.dylib +STATICLIB = libopenctm.a + + +OBJS = openctm.o \ + stream.o \ + compressRAW.o \ + compressMG1.o \ + compressMG2.o + +LZMA_OBJS = Alloc.o \ + LzFind.o \ + LzmaDec.o \ + LzmaEnc.o \ + LzmaLib.o + +SRCS = openctm.c \ + stream.c \ + compressRAW.c \ + compressMG1.c \ + compressMG2.c + +LZMA_SRCS = $(LZMADIR)/Alloc.c \ + $(LZMADIR)/LzFind.c \ + $(LZMADIR)/LzmaDec.c \ + $(LZMADIR)/LzmaEnc.c \ + $(LZMADIR)/LzmaLib.c + +.phony: all clean depend + +#all: $(DYNAMICLIB) +all: $(STATICLIB) + +clean: + $(RM) $(DYNAMICLIB) $(OBJS) $(LZMA_OBJS) + +$(DYNAMICLIB): $(OBJS) $(LZMA_OBJS) + gcc -dynamiclib -o $@ $(OBJS) $(LZMA_OBJS) + +$(STATICLIB): $(OBJS) $(LZMA_OBJS) + ar rcs $@ $(OBJS) $(LZMA_OBJS) + +%.o: %.c + $(CC) $(CFLAGS) $< + +%.o: $(LZMADIR)/%.c + $(CC) $(CFLAGS_LZMA) $< + +depend: + $(DEPEND) $(SRCS) $(LZMA_SRCS) > make.depend + +-include make.depend diff --git a/src/external/OpenCTM-1.0.3/lib/Makefile.mingw b/src/external/OpenCTM-1.0.3/lib/Makefile.mingw new file mode 100644 index 000000000..8606be77e --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/Makefile.mingw @@ -0,0 +1,87 @@ +############################################################################### +# Product: OpenCTM +# File: Makefile.mingw +# Description: Makefile for MinGW32 for Windows. +############################################################################### +# Copyright (c) 2009-2010 Marcus Geelnard +# +# This software is provided 'as-is', without any express or implied +# warranty. In no event will the authors be held liable for any damages +# arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment in the product documentation would be +# appreciated but is not required. +# +# 2. Altered source versions must be plainly marked as such, and must not +# be misrepresented as being the original software. +# +# 3. This notice may not be removed or altered from any source +# distribution. +############################################################################### + +LZMADIR = liblzma +CC = gcc +CFLAGS = -O3 -W -Wall -c -DOPENCTM_BUILD -I$(LZMADIR) -DLZMA_PREFIX_CTM -std=c99 -pedantic +CFLAGS_LZMA = -O3 -W -Wall -c -DLZMA_PREFIX_CTM -std=c99 -pedantic +RM = del /Q +DEPEND = $(CC) -MM +RC = windres + +DYNAMICLIB = openctm.dll +LINKLIB = libopenctm.a + +OBJS = openctm.o \ + stream.o \ + compressRAW.o \ + compressMG1.o \ + compressMG2.o + +LZMA_OBJS = Alloc.o \ + LzFind.o \ + LzmaDec.o \ + LzmaEnc.o \ + LzmaLib.o + +SRCS = openctm.c \ + stream.c \ + compressRAW.c \ + compressMG1.c \ + compressMG2.c + +LZMA_SRCS = $(LZMADIR)/Alloc.c \ + $(LZMADIR)/LzFind.c \ + $(LZMADIR)/LzmaDec.c \ + $(LZMADIR)/LzmaEnc.c \ + $(LZMADIR)/LzmaLib.c + +.phony: all clean depend + +all: $(DYNAMICLIB) + +clean: + $(RM) $(DYNAMICLIB) $(LINKLIB) $(OBJS) $(LZMA_OBJS) openctm-res.o + +$(DYNAMICLIB): $(OBJS) $(LZMA_OBJS) openctm-mingw1.def openctm-mingw2.def openctm-res.o + dllwrap --def openctm-mingw1.def -o $@ $(OBJS) $(LZMA_OBJS) openctm-res.o + strip $@ + dlltool --kill-at --output-lib $(LINKLIB) --def openctm-mingw2.def + +openctm-res.o: openctm.rc + $(RC) $< $@ + +%.o: %.c + $(CC) $(CFLAGS) $< + +%.o: $(LZMADIR)/%.c + $(CC) $(CFLAGS_LZMA) $< + +depend: + $(DEPEND) $(SRCS) $(LZMA_SRCS) > make.depend + +-include make.depend diff --git a/src/external/OpenCTM-1.0.3/lib/Makefile.msvc b/src/external/OpenCTM-1.0.3/lib/Makefile.msvc new file mode 100644 index 000000000..70818d553 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/Makefile.msvc @@ -0,0 +1,103 @@ +############################################################################### +# Product: OpenCTM +# File: Makefile.msvc +# Description: Makefile for MS Visual Studio 2008 for Windows. +############################################################################### +# Copyright (c) 2009-2010 Marcus Geelnard +# +# This software is provided 'as-is', without any express or implied +# warranty. In no event will the authors be held liable for any damages +# arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment in the product documentation would be +# appreciated but is not required. +# +# 2. Altered source versions must be plainly marked as such, and must not +# be misrepresented as being the original software. +# +# 3. This notice may not be removed or altered from any source +# distribution. +############################################################################### + +LZMADIR = liblzma +CC = cl +CFLAGS = /nologo /Ox /W3 /c /DOPENCTM_BUILD /I$(LZMADIR) /DLZMA_PREFIX_CTM /D_CRT_SECURE_NO_WARNINGS +CFLAGS_LZMA = /nologo /Ox /W3 /c /DLZMA_PREFIX_CTM +RM = del /Q +RC = rc + +DYNAMICLIB = openctm.dll +LINKLIB = openctm.lib + +OBJS = openctm.obj \ + stream.obj \ + compressRAW.obj \ + compressMG1.obj \ + compressMG2.obj + +LZMA_OBJS = Alloc.obj \ + LzFind.obj \ + LzmaDec.obj \ + LzmaEnc.obj \ + LzmaLib.obj + +SRCS = openctm.c \ + stream.c \ + compressRAW.c \ + compressMG1.c \ + compressMG2.c + +LZMA_SRCS = $(LZMADIR)\Alloc.c \ + $(LZMADIR)\LzFind.c \ + $(LZMADIR)\LzmaDec.c \ + $(LZMADIR)\LzmaEnc.c \ + $(LZMADIR)\LzmaLib.c + +all: $(DYNAMICLIB) + +.PHONY: clean + +clean: + $(RM) $(DYNAMICLIB) $(LINKLIB) $(OBJS) $(LZMA_OBJS) openctm.res + +$(DYNAMICLIB): $(OBJS) $(LZMA_OBJS) openctm-msvc.def openctm.res + link /nologo /out:$@ /dll /implib:$(LINKLIB) /def:openctm-msvc.def $(OBJS) $(LZMA_OBJS) openctm.res + +openctm.res: openctm.rc + $(RC) openctm.rc + +openctm.obj: openctm.c openctm.h internal.h + $(CC) $(CFLAGS) openctm.c + +stream.obj: stream.c openctm.h internal.h + $(CC) $(CFLAGS) stream.c + +compressRAW.obj: compressRAW.c openctm.h internal.h + $(CC) $(CFLAGS) compressRAW.c + +compressMG1.obj: compressMG1.c openctm.h internal.h + $(CC) $(CFLAGS) compressMG1.c + +compressMG2.obj: compressMG2.c openctm.h internal.h + $(CC) $(CFLAGS) compressMG2.c + +Alloc.obj: $(LZMADIR)\Alloc.c $(LZMADIR)\Alloc.h + $(CC) $(CFLAGS_LZMA) $(LZMADIR)\Alloc.c + +LzFind.obj: $(LZMADIR)\LzFind.c $(LZMADIR)\LzFind.h $(LZMADIR)\Types.h $(LZMADIR)\LzHash.h $(LZMADIR)\NameMangle.h + $(CC) $(CFLAGS_LZMA) $(LZMADIR)\LzFind.c + +LzmaDec.obj: $(LZMADIR)\LzmaDec.c $(LZMADIR)\LzmaDec.h $(LZMADIR)\Types.h $(LZMADIR)\NameMangle.h + $(CC) $(CFLAGS_LZMA) $(LZMADIR)\LzmaDec.c + +LzmaEnc.obj: $(LZMADIR)\LzmaEnc.c $(LZMADIR)\LzmaEnc.h $(LZMADIR)\Types.h $(LZMADIR)\LzFind.h $(LZMADIR)\NameMangle.h + $(CC) $(CFLAGS_LZMA) $(LZMADIR)\LzmaEnc.c + +LzmaLib.obj: $(LZMADIR)\LzmaLib.c $(LZMADIR)\LzmaEnc.h $(LZMADIR)\Types.h $(LZMADIR)\LzmaDec.h $(LZMADIR)\Alloc.h $(LZMADIR)\LzmaLib.h $(LZMADIR)\NameMangle.h + $(CC) $(CFLAGS_LZMA) $(LZMADIR)\LzmaLib.c diff --git a/src/external/OpenCTM-1.0.3/lib/compressMG1.c b/src/external/OpenCTM-1.0.3/lib/compressMG1.c new file mode 100644 index 000000000..e4ca1b747 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/compressMG1.c @@ -0,0 +1,324 @@ +//----------------------------------------------------------------------------- +// Product: OpenCTM +// File: compressMG1.c +// Description: Implementation of the MG1 compression method. +//----------------------------------------------------------------------------- +// Copyright (c) 2009-2010 Marcus Geelnard +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +//----------------------------------------------------------------------------- + +#include +#include +#include "openctm.h" +#include "internal.h" + +#ifdef __DEBUG_ +#include +#endif + + +//----------------------------------------------------------------------------- +// _compareTriangle() - Comparator for the triangle sorting. +//----------------------------------------------------------------------------- +static int _compareTriangle(const void * elem1, const void * elem2) +{ + CTMuint * tri1 = (CTMuint *) elem1; + CTMuint * tri2 = (CTMuint *) elem2; + if(tri1[0] != tri2[0]) + return tri1[0] - tri2[0]; + else + return tri1[1] - tri2[1]; +} + +//----------------------------------------------------------------------------- +// _ctmReArrangeTriangles() - Re-arrange all triangles for optimal +// compression. +//----------------------------------------------------------------------------- +static void _ctmReArrangeTriangles(_CTMcontext * self, CTMuint * aIndices) +{ + CTMuint * tri, tmp, i; + + // Step 1: Make sure that the first index of each triangle is the smallest + // one (rotate triangle nodes if necessary) + for(i = 0; i < self->mTriangleCount; ++ i) + { + tri = &aIndices[i * 3]; + if((tri[1] < tri[0]) && (tri[1] < tri[2])) + { + tmp = tri[0]; + tri[0] = tri[1]; + tri[1] = tri[2]; + tri[2] = tmp; + } + else if((tri[2] < tri[0]) && (tri[2] < tri[1])) + { + tmp = tri[0]; + tri[0] = tri[2]; + tri[2] = tri[1]; + tri[1] = tmp; + } + } + + // Step 2: Sort the triangles based on the first triangle index + qsort((void *) aIndices, self->mTriangleCount, sizeof(CTMuint) * 3, _compareTriangle); +} + +//----------------------------------------------------------------------------- +// _ctmMakeIndexDeltas() - Calculate various forms of derivatives in order to +// reduce data entropy. +//----------------------------------------------------------------------------- +static void _ctmMakeIndexDeltas(_CTMcontext * self, CTMuint * aIndices) +{ + CTMint i; + for(i = self->mTriangleCount - 1; i >= 0; -- i) + { + // Step 1: Calculate delta from second triangle index to the previous + // second triangle index, if the previous triangle shares the same first + // index, otherwise calculate the delta to the first triangle index + if((i >= 1) && (aIndices[i * 3] == aIndices[(i - 1) * 3])) + aIndices[i * 3 + 1] -= aIndices[(i - 1) * 3 + 1]; + else + aIndices[i * 3 + 1] -= aIndices[i * 3]; + + // Step 2: Calculate delta from third triangle index to the first triangle + // index + aIndices[i * 3 + 2] -= aIndices[i * 3]; + + // Step 3: Calculate derivative of the first triangle index + if(i >= 1) + aIndices[i * 3] -= aIndices[(i - 1) * 3]; + } +} + +//----------------------------------------------------------------------------- +// _ctmRestoreIndices() - Restore original indices (inverse derivative +// operation). +//----------------------------------------------------------------------------- +static void _ctmRestoreIndices(_CTMcontext * self, CTMuint * aIndices) +{ + CTMuint i; + + for(i = 0; i < self->mTriangleCount; ++ i) + { + // Step 1: Reverse derivative of the first triangle index + if(i >= 1) + aIndices[i * 3] += aIndices[(i - 1) * 3]; + + // Step 2: Reverse delta from third triangle index to the first triangle + // index + aIndices[i * 3 + 2] += aIndices[i * 3]; + + // Step 3: Reverse delta from second triangle index to the previous + // second triangle index, if the previous triangle shares the same first + // index, otherwise reverse the delta to the first triangle index + if((i >= 1) && (aIndices[i * 3] == aIndices[(i - 1) * 3])) + aIndices[i * 3 + 1] += aIndices[(i - 1) * 3 + 1]; + else + aIndices[i * 3 + 1] += aIndices[i * 3]; + } +} + +//----------------------------------------------------------------------------- +// _ctmCompressMesh_MG1() - Compress the mesh that is stored in the CTM +// context, and write it the the output stream in the CTM context. +//----------------------------------------------------------------------------- +int _ctmCompressMesh_MG1(_CTMcontext * self) +{ + CTMuint * indices; + _CTMfloatmap * map; + CTMuint i; + +#ifdef __DEBUG_ + printf("COMPRESSION METHOD: MG1\n"); +#endif + + // Perpare (sort) indices + indices = (CTMuint *) malloc(sizeof(CTMuint) * self->mTriangleCount * 3); + if(!indices) + { + self->mError = CTM_OUT_OF_MEMORY; + return CTM_FALSE; + } + for(i = 0; i < self->mTriangleCount * 3; ++ i) + indices[i] = self->mIndices[i]; + _ctmReArrangeTriangles(self, indices); + + // Calculate index deltas (entropy-reduction) + _ctmMakeIndexDeltas(self, indices); + + // Write triangle indices +#ifdef __DEBUG_ + printf("Inidices: "); +#endif + _ctmStreamWrite(self, (void *) "INDX", 4); + if(!_ctmStreamWritePackedInts(self, (CTMint *) indices, self->mTriangleCount, 3, CTM_FALSE)) + { + free((void *) indices); + return CTM_FALSE; + } + + // Free temporary resources + free((void *) indices); + + // Write vertices +#ifdef __DEBUG_ + printf("Vertices: "); +#endif + _ctmStreamWrite(self, (void *) "VERT", 4); + if(!_ctmStreamWritePackedFloats(self, self->mVertices, self->mVertexCount * 3, 1)) + { + free((void *) indices); + return CTM_FALSE; + } + + // Write normals + if(self->mNormals) + { +#ifdef __DEBUG_ + printf("Normals: "); +#endif + _ctmStreamWrite(self, (void *) "NORM", 4); + if(!_ctmStreamWritePackedFloats(self, self->mNormals, self->mVertexCount, 3)) + return CTM_FALSE; + } + + // Write UV maps + map = self->mUVMaps; + while(map) + { +#ifdef __DEBUG_ + printf("UV coordinates (%s): ", map->mName ? map->mName : "no name"); +#endif + _ctmStreamWrite(self, (void *) "TEXC", 4); + _ctmStreamWriteSTRING(self, map->mName); + _ctmStreamWriteSTRING(self, map->mFileName); + if(!_ctmStreamWritePackedFloats(self, map->mValues, self->mVertexCount, 2)) + return CTM_FALSE; + map = map->mNext; + } + + // Write attribute maps + map = self->mAttribMaps; + while(map) + { +#ifdef __DEBUG_ + printf("Vertex attributes (%s): ", map->mName ? map->mName : "no name"); +#endif + _ctmStreamWrite(self, (void *) "ATTR", 4); + _ctmStreamWriteSTRING(self, map->mName); + if(!_ctmStreamWritePackedFloats(self, map->mValues, self->mVertexCount, 4)) + return CTM_FALSE; + map = map->mNext; + } + + return CTM_TRUE; +} + +//----------------------------------------------------------------------------- +// _ctmUncompressMesh_MG1() - Uncmpress the mesh from the input stream in the +// CTM context, and store the resulting mesh in the CTM context. +//----------------------------------------------------------------------------- +int _ctmUncompressMesh_MG1(_CTMcontext * self) +{ + CTMuint * indices; + _CTMfloatmap * map; + CTMuint i; + + // Allocate memory for the indices + indices = (CTMuint *) malloc(sizeof(CTMuint) * self->mTriangleCount * 3); + if(!indices) + { + self->mError = CTM_OUT_OF_MEMORY; + return CTM_FALSE; + } + + // Read triangle indices + if(_ctmStreamReadUINT(self) != FOURCC("INDX")) + { + self->mError = CTM_BAD_FORMAT; + free(indices); + return CTM_FALSE; + } + if(!_ctmStreamReadPackedInts(self, (CTMint *) indices, self->mTriangleCount, 3, CTM_FALSE)) + return CTM_FALSE; + + // Restore indices + _ctmRestoreIndices(self, indices); + for(i = 0; i < self->mTriangleCount * 3; ++ i) + self->mIndices[i] = indices[i]; + + // Free temporary resources + free(indices); + + // Read vertices + if(_ctmStreamReadUINT(self) != FOURCC("VERT")) + { + self->mError = CTM_BAD_FORMAT; + return CTM_FALSE; + } + if(!_ctmStreamReadPackedFloats(self, self->mVertices, self->mVertexCount * 3, 1)) + return CTM_FALSE; + + // Read normals + if(self->mNormals) + { + if(_ctmStreamReadUINT(self) != FOURCC("NORM")) + { + self->mError = CTM_BAD_FORMAT; + return CTM_FALSE; + } + if(!_ctmStreamReadPackedFloats(self, self->mNormals, self->mVertexCount, 3)) + return CTM_FALSE; + } + + // Read UV maps + map = self->mUVMaps; + while(map) + { + if(_ctmStreamReadUINT(self) != FOURCC("TEXC")) + { + self->mError = CTM_BAD_FORMAT; + return 0; + } + _ctmStreamReadSTRING(self, &map->mName); + _ctmStreamReadSTRING(self, &map->mFileName); + if(!_ctmStreamReadPackedFloats(self, map->mValues, self->mVertexCount, 2)) + return CTM_FALSE; + map = map->mNext; + } + + // Read vertex attribute maps + map = self->mAttribMaps; + while(map) + { + if(_ctmStreamReadUINT(self) != FOURCC("ATTR")) + { + self->mError = CTM_BAD_FORMAT; + return 0; + } + _ctmStreamReadSTRING(self, &map->mName); + if(!_ctmStreamReadPackedFloats(self, map->mValues, self->mVertexCount, 4)) + return CTM_FALSE; + map = map->mNext; + } + + return CTM_TRUE; +} diff --git a/src/external/OpenCTM-1.0.3/lib/compressMG2.c b/src/external/OpenCTM-1.0.3/lib/compressMG2.c new file mode 100644 index 000000000..d993fef65 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/compressMG2.c @@ -0,0 +1,1319 @@ +//----------------------------------------------------------------------------- +// Product: OpenCTM +// File: compressMG2.c +// Description: Implementation of the MG2 compression method. +//----------------------------------------------------------------------------- +// Copyright (c) 2009-2010 Marcus Geelnard +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +//----------------------------------------------------------------------------- + +#include +#include +#include "openctm.h" +#include "internal.h" + +#ifdef __DEBUG_ +#include +#endif + +// We need PI +#ifndef PI +#define PI 3.141592653589793238462643f +#endif + + +//----------------------------------------------------------------------------- +// _CTMgrid - 3D space subdivision grid. +//----------------------------------------------------------------------------- +typedef struct { + // Axis-aligned boudning box for the grid. + CTMfloat mMin[3]; + CTMfloat mMax[3]; + + // How many divisions per axis (minimum 1). + CTMuint mDivision[3]; + + // Size of each grid box. + CTMfloat mSize[3]; +} _CTMgrid; + +//----------------------------------------------------------------------------- +// _CTMsortvertex - Vertex information. +//----------------------------------------------------------------------------- +typedef struct { + // Vertex X coordinate (used for sorting). + CTMfloat x; + + // Grid index. This is the index into the 3D space subdivision grid. + CTMuint mGridIndex; + + // Original index (before sorting). + CTMuint mOriginalIndex; +} _CTMsortvertex; + +//----------------------------------------------------------------------------- +// _ctmSetupGrid() - Setup the 3D space subdivision grid. +//----------------------------------------------------------------------------- +static void _ctmSetupGrid(_CTMcontext * self, _CTMgrid * aGrid) +{ + CTMuint i; + CTMfloat factor[3], sum, wantedGrids; + + // Calculate the mesh bounding box + aGrid->mMin[0] = aGrid->mMax[0] = self->mVertices[0]; + aGrid->mMin[1] = aGrid->mMax[1] = self->mVertices[1]; + aGrid->mMin[2] = aGrid->mMax[2] = self->mVertices[2]; + for(i = 1; i < self->mVertexCount; ++ i) + { + if(self->mVertices[i * 3] < aGrid->mMin[0]) + aGrid->mMin[0] = self->mVertices[i * 3]; + else if(self->mVertices[i * 3] > aGrid->mMax[0]) + aGrid->mMax[0] = self->mVertices[i * 3]; + if(self->mVertices[i * 3 + 1] < aGrid->mMin[1]) + aGrid->mMin[1] = self->mVertices[i * 3 + 1]; + else if(self->mVertices[i * 3 + 1] > aGrid->mMax[1]) + aGrid->mMax[1] = self->mVertices[i * 3 + 1]; + if(self->mVertices[i * 3 + 2] < aGrid->mMin[2]) + aGrid->mMin[2] = self->mVertices[i * 3 + 2]; + else if(self->mVertices[i * 3 + 2] > aGrid->mMax[2]) + aGrid->mMax[2] = self->mVertices[i * 3 + 2]; + } + + // Determine optimal grid resolution, based on the number of vertices and + // the bounding box. + // NOTE: This algorithm is quite crude, and could very well be optimized for + // better compression levels in the future without affecting the file format + // or backward compatibility at all. + for(i = 0; i < 3; ++ i) + factor[i] = aGrid->mMax[i] - aGrid->mMin[i]; + sum = factor[0] + factor[1] + factor[2]; + if(sum > 1e-30f) + { + sum = 1.0f / sum; + for(i = 0; i < 3; ++ i) + factor[i] *= sum; + wantedGrids = powf(100.0f * self->mVertexCount, 1.0f / 3.0f); + for(i = 0; i < 3; ++ i) + { + aGrid->mDivision[i] = (CTMuint) ceilf(wantedGrids * factor[i]); + if(aGrid->mDivision[i] < 1) + aGrid->mDivision[i] = 1; + } + } + else + { + aGrid->mDivision[0] = 4; + aGrid->mDivision[1] = 4; + aGrid->mDivision[2] = 4; + } +#ifdef __DEBUG_ + printf("Division: (%d %d %d)\n", aGrid->mDivision[0], aGrid->mDivision[1], aGrid->mDivision[2]); +#endif + + // Calculate grid sizes + for(i = 0; i < 3; ++ i) + aGrid->mSize[i] = (aGrid->mMax[i] - aGrid->mMin[i]) / aGrid->mDivision[i]; +} + +//----------------------------------------------------------------------------- +// _ctmPointToGridIdx() - Convert a point to a grid index. +//----------------------------------------------------------------------------- +static CTMuint _ctmPointToGridIdx(_CTMgrid * aGrid, CTMfloat * aPoint) +{ + CTMuint i, idx[3]; + + for(i = 0; i < 3; ++ i) + { + idx[i] = (CTMuint) floorf((aPoint[i] - aGrid->mMin[i]) / aGrid->mSize[i]); + if(idx[i] >= aGrid->mDivision[i]) + idx[i] = aGrid->mDivision[i] - 1; + } + + return idx[0] + aGrid->mDivision[0] * (idx[1] + aGrid->mDivision[1] * idx[2]); +} + +//----------------------------------------------------------------------------- +// _ctmGridIdxToPoint() - Convert a grid index to a point (the min x/y/z for +// the given grid box). +//----------------------------------------------------------------------------- +static void _ctmGridIdxToPoint(_CTMgrid * aGrid, CTMuint aIdx, CTMfloat * aPoint) +{ + CTMuint gridIdx[3], zdiv, ydiv, i; + + zdiv = aGrid->mDivision[0] * aGrid->mDivision[1]; + ydiv = aGrid->mDivision[0]; + + gridIdx[2] = aIdx / zdiv; + aIdx -= gridIdx[2] * zdiv; + gridIdx[1] = aIdx / ydiv; + aIdx -= gridIdx[1] * ydiv; + gridIdx[0] = aIdx; + + for(i = 0; i < 3; ++ i) + aPoint[i] = gridIdx[i] * aGrid->mSize[i] + aGrid->mMin[i]; +} + +//----------------------------------------------------------------------------- +// _compareVertex() - Comparator for the vertex sorting. +//----------------------------------------------------------------------------- +static int _compareVertex(const void * elem1, const void * elem2) +{ + _CTMsortvertex * v1 = (_CTMsortvertex *) elem1; + _CTMsortvertex * v2 = (_CTMsortvertex *) elem2; + if(v1->mGridIndex != v2->mGridIndex) + return v1->mGridIndex - v2->mGridIndex; + else if(v1->x < v2->x) + return -1; + else if(v1->x > v2->x) + return 1; + else + return 0; +} + +//----------------------------------------------------------------------------- +// _ctmSortVertices() - Setup the vertex array. Assign each vertex to a grid +// box, and sort all vertices. +//----------------------------------------------------------------------------- +static void _ctmSortVertices(_CTMcontext * self, _CTMsortvertex * aSortVertices, + _CTMgrid * aGrid) +{ + CTMuint i; + + // Prepare sort vertex array + for(i = 0; i < self->mVertexCount; ++ i) + { + // Store vertex properties in the sort vertex array + aSortVertices[i].x = self->mVertices[i * 3]; + aSortVertices[i].mGridIndex = _ctmPointToGridIdx(aGrid, &self->mVertices[i * 3]); + aSortVertices[i].mOriginalIndex = i; + } + + // Sort vertices. The elements are first sorted by their grid indices, and + // scondly by their x coordinates. + qsort((void *) aSortVertices, self->mVertexCount, sizeof(_CTMsortvertex), _compareVertex); +} + +//----------------------------------------------------------------------------- +// _ctmReIndexIndices() - Re-index all indices, based on the sorted vertices. +//----------------------------------------------------------------------------- +static int _ctmReIndexIndices(_CTMcontext * self, _CTMsortvertex * aSortVertices, + CTMuint * aIndices) +{ + CTMuint i, * indexLUT; + + // Create temporary lookup-array, O(n) + indexLUT = (CTMuint *) malloc(sizeof(CTMuint) * self->mVertexCount); + if(!indexLUT) + { + self->mError = CTM_OUT_OF_MEMORY; + return CTM_FALSE; + } + for(i = 0; i < self->mVertexCount; ++ i) + indexLUT[aSortVertices[i].mOriginalIndex] = i; + + // Convert old indices to new indices, O(n) + for(i = 0; i < self->mTriangleCount * 3; ++ i) + aIndices[i] = indexLUT[self->mIndices[i]]; + + // Free temporary lookup-array + free((void *) indexLUT); + + return CTM_TRUE; +} + +//----------------------------------------------------------------------------- +// _compareTriangle() - Comparator for the triangle sorting. +//----------------------------------------------------------------------------- +static int _compareTriangle(const void * elem1, const void * elem2) +{ + CTMuint * tri1 = (CTMuint *) elem1; + CTMuint * tri2 = (CTMuint *) elem2; + if(tri1[0] != tri2[0]) + return tri1[0] - tri2[0]; + else + return tri1[1] - tri2[1]; +} + +//----------------------------------------------------------------------------- +// _ctmReArrangeTriangles() - Re-arrange all triangles for optimal +// compression. +//----------------------------------------------------------------------------- +static void _ctmReArrangeTriangles(_CTMcontext * self, CTMuint * aIndices) +{ + CTMuint * tri, tmp, i; + + // Step 1: Make sure that the first index of each triangle is the smallest + // one (rotate triangle nodes if necessary) + for(i = 0; i < self->mTriangleCount; ++ i) + { + tri = &aIndices[i * 3]; + if((tri[1] < tri[0]) && (tri[1] < tri[2])) + { + tmp = tri[0]; + tri[0] = tri[1]; + tri[1] = tri[2]; + tri[2] = tmp; + } + else if((tri[2] < tri[0]) && (tri[2] < tri[1])) + { + tmp = tri[0]; + tri[0] = tri[2]; + tri[2] = tri[1]; + tri[1] = tmp; + } + } + + // Step 2: Sort the triangles based on the first triangle index + qsort((void *) aIndices, self->mTriangleCount, sizeof(CTMuint) * 3, _compareTriangle); +} + +//----------------------------------------------------------------------------- +// _ctmMakeIndexDeltas() - Calculate various forms of derivatives in order to +// reduce data entropy. +//----------------------------------------------------------------------------- +static void _ctmMakeIndexDeltas(_CTMcontext * self, CTMuint * aIndices) +{ + CTMint i; + for(i = self->mTriangleCount - 1; i >= 0; -- i) + { + // Step 1: Calculate delta from second triangle index to the previous + // second triangle index, if the previous triangle shares the same first + // index, otherwise calculate the delta to the first triangle index + if((i >= 1) && (aIndices[i * 3] == aIndices[(i - 1) * 3])) + aIndices[i * 3 + 1] -= aIndices[(i - 1) * 3 + 1]; + else + aIndices[i * 3 + 1] -= aIndices[i * 3]; + + // Step 2: Calculate delta from third triangle index to the first triangle + // index + aIndices[i * 3 + 2] -= aIndices[i * 3]; + + // Step 3: Calculate derivative of the first triangle index + if(i >= 1) + aIndices[i * 3] -= aIndices[(i - 1) * 3]; + } +} + +//----------------------------------------------------------------------------- +// _ctmRestoreIndices() - Restore original indices (inverse derivative +// operation). +//----------------------------------------------------------------------------- +static void _ctmRestoreIndices(_CTMcontext * self, CTMuint * aIndices) +{ + CTMuint i; + + for(i = 0; i < self->mTriangleCount; ++ i) + { + // Step 1: Reverse derivative of the first triangle index + if(i >= 1) + aIndices[i * 3] += aIndices[(i - 1) * 3]; + + // Step 2: Reverse delta from third triangle index to the first triangle + // index + aIndices[i * 3 + 2] += aIndices[i * 3]; + + // Step 3: Reverse delta from second triangle index to the previous + // second triangle index, if the previous triangle shares the same first + // index, otherwise reverse the delta to the first triangle index + if((i >= 1) && (aIndices[i * 3] == aIndices[(i - 1) * 3])) + aIndices[i * 3 + 1] += aIndices[(i - 1) * 3 + 1]; + else + aIndices[i * 3 + 1] += aIndices[i * 3]; + } +} + +//----------------------------------------------------------------------------- +// _ctmMakeVertexDeltas() - Calculate various forms of derivatives in order to +// reduce data entropy. +//----------------------------------------------------------------------------- +static void _ctmMakeVertexDeltas(_CTMcontext * self, CTMint * aIntVertices, + _CTMsortvertex * aSortVertices, _CTMgrid * aGrid) +{ + CTMuint i, gridIdx, prevGridIndex, oldIdx; + CTMfloat gridOrigin[3], scale; + CTMint deltaX, prevDeltaX; + + // Vertex scaling factor + scale = 1.0f / self->mVertexPrecision; + + prevGridIndex = 0x7fffffff; + prevDeltaX = 0; + for(i = 0; i < self->mVertexCount; ++ i) + { + // Get grid box origin + gridIdx = aSortVertices[i].mGridIndex; + _ctmGridIdxToPoint(aGrid, gridIdx, gridOrigin); + + // Get old vertex coordinate index (before vertex sorting) + oldIdx = aSortVertices[i].mOriginalIndex; + + // Store delta to the grid box origin in the integer vertex array. For the + // X axis (which is sorted) we also do the delta to the previous coordinate + // in the box. + deltaX = (CTMint) floorf(scale * (self->mVertices[oldIdx * 3] - gridOrigin[0]) + 0.5f); + if(gridIdx == prevGridIndex) + aIntVertices[i * 3] = deltaX - prevDeltaX; + else + aIntVertices[i * 3] = deltaX; + aIntVertices[i * 3 + 1] = (CTMint) floorf(scale * (self->mVertices[oldIdx * 3 + 1] - gridOrigin[1]) + 0.5f); + aIntVertices[i * 3 + 2] = (CTMint) floorf(scale * (self->mVertices[oldIdx * 3 + 2] - gridOrigin[2]) + 0.5f); + + prevGridIndex = gridIdx; + prevDeltaX = deltaX; + } +} + +//----------------------------------------------------------------------------- +// _ctmRestoreVertices() - Calculate inverse derivatives of the vertices. +//----------------------------------------------------------------------------- +static void _ctmRestoreVertices(_CTMcontext * self, CTMint * aIntVertices, + CTMuint * aGridIndices, _CTMgrid * aGrid, CTMfloat * aVertices) +{ + CTMuint i, gridIdx, prevGridIndex; + CTMfloat gridOrigin[3], scale; + CTMint deltaX, prevDeltaX; + + scale = self->mVertexPrecision; + + prevGridIndex = 0x7fffffff; + prevDeltaX = 0; + for(i = 0; i < self->mVertexCount; ++ i) + { + // Get grid box origin + gridIdx = aGridIndices[i]; + _ctmGridIdxToPoint(aGrid, gridIdx, gridOrigin); + + // Restore original point + deltaX = aIntVertices[i * 3]; + if(gridIdx == prevGridIndex) + deltaX += prevDeltaX; + aVertices[i * 3] = scale * deltaX + gridOrigin[0]; + aVertices[i * 3 + 1] = scale * aIntVertices[i * 3 + 1] + gridOrigin[1]; + aVertices[i * 3 + 2] = scale * aIntVertices[i * 3 + 2] + gridOrigin[2]; + + prevGridIndex = gridIdx; + prevDeltaX = deltaX; + } +} + +//----------------------------------------------------------------------------- +// _ctmCalcSmoothNormals() - Calculate the smooth normals for a given mesh. +// These are used as the nominal normals for normal deltas & reconstruction. +//----------------------------------------------------------------------------- +static void _ctmCalcSmoothNormals(_CTMcontext * self, CTMfloat * aVertices, + CTMuint * aIndices, CTMfloat * aSmoothNormals) +{ + CTMuint i, j, k, tri[3]; + CTMfloat len; + CTMfloat v1[3], v2[3], n[3]; + + // Clear smooth normals array + for(i = 0; i < 3 * self->mVertexCount; ++ i) + aSmoothNormals[i] = 0.0f; + + // Calculate sums of all neigbouring triangle normals for each vertex + for(i = 0; i < self->mTriangleCount; ++ i) + { + // Get triangle corner indices + for(j = 0; j < 3; ++ j) + tri[j] = aIndices[i * 3 + j]; + + // Calculate the normalized cross product of two triangle edges (i.e. the + // flat triangle normal) + for(j = 0; j < 3; ++ j) + { + v1[j] = aVertices[tri[1] * 3 + j] - aVertices[tri[0] * 3 + j]; + v2[j] = aVertices[tri[2] * 3 + j] - aVertices[tri[0] * 3 + j]; + } + n[0] = v1[1] * v2[2] - v1[2] * v2[1]; + n[1] = v1[2] * v2[0] - v1[0] * v2[2]; + n[2] = v1[0] * v2[1] - v1[1] * v2[0]; + len = sqrtf(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]); + if(len > 1e-10f) + len = 1.0f / len; + else + len = 1.0f; + for(j = 0; j < 3; ++ j) + n[j] *= len; + + // Add the flat normal to all three triangle vertices + for(k = 0; k < 3; ++ k) + for(j = 0; j < 3; ++ j) + aSmoothNormals[tri[k] * 3 + j] += n[j]; + } + + // Normalize the normal sums, which gives the unit length smooth normals + for(i = 0; i < self->mVertexCount; ++ i) + { + len = sqrtf(aSmoothNormals[i * 3] * aSmoothNormals[i * 3] + + aSmoothNormals[i * 3 + 1] * aSmoothNormals[i * 3 + 1] + + aSmoothNormals[i * 3 + 2] * aSmoothNormals[i * 3 + 2]); + if(len > 1e-10f) + len = 1.0f / len; + else + len = 1.0f; + for(j = 0; j < 3; ++ j) + aSmoothNormals[i * 3 + j] *= len; + } +} + +//----------------------------------------------------------------------------- +// _ctmMakeNormalCoordSys() - Create an ortho-normalized coordinate system +// where the Z-axis is aligned with the given normal. +// Note 1: This function is central to how the compressed normal data is +// interpreted, and it can not be changed (mathematically) without making the +// coder/decoder incompatible with other versions of the library! +// Note 2: Since we do this for every single normal, this routine needs to be +// fast. The current implementation uses: 12 MUL, 1 DIV, 1 SQRT, ~6 ADD. +//----------------------------------------------------------------------------- +static void _ctmMakeNormalCoordSys(CTMfloat * aNormal, CTMfloat * aBasisAxes) +{ + CTMfloat len, * x, * y, * z; + CTMuint i; + + // Pointers to the basis axes (aBasisAxes is a 3x3 matrix) + x = aBasisAxes; + y = &aBasisAxes[3]; + z = &aBasisAxes[6]; + + // Z = normal (must be unit length!) + for(i = 0; i < 3; ++ i) + z[i] = aNormal[i]; + + // Calculate a vector that is guaranteed to be orthogonal to the normal, non- + // zero, and a continuous function of the normal (no discrete jumps): + // X = (0,0,1) x normal + (1,0,0) x normal + x[0] = -aNormal[1]; + x[1] = aNormal[0] - aNormal[2]; + x[2] = aNormal[1]; + + // Normalize the new X axis (note: |x[2]| = |x[0]|) + len = sqrtf(2.0 * x[0] * x[0] + x[1] * x[1]); + if(len > 1.0e-20f) + { + len = 1.0f / len; + x[0] *= len; + x[1] *= len; + x[2] *= len; + } + + // Let Y = Z x X (no normalization needed, since |Z| = |X| = 1) + y[0] = z[1] * x[2] - z[2] * x[1]; + y[1] = z[2] * x[0] - z[0] * x[2]; + y[2] = z[0] * x[1] - z[1] * x[0]; +} + +//----------------------------------------------------------------------------- +// _ctmMakeNormalDeltas() - Convert the normals to a new coordinate system: +// magnitude, phi, theta (relative to predicted smooth normals). +//----------------------------------------------------------------------------- +static CTMint _ctmMakeNormalDeltas(_CTMcontext * self, CTMint * aIntNormals, + CTMfloat * aVertices, CTMuint * aIndices, _CTMsortvertex * aSortVertices) +{ + CTMuint i, j, oldIdx, intPhi; + CTMfloat magn, phi, theta, scale, thetaScale; + CTMfloat * smoothNormals, n[3], n2[3], basisAxes[9]; + + // Allocate temporary memory for the nominal vertex normals + smoothNormals = (CTMfloat *) malloc(3 * sizeof(CTMfloat) * self->mVertexCount); + if(!smoothNormals) + { + self->mError = CTM_OUT_OF_MEMORY; + return CTM_FALSE; + } + + // Calculate smooth normals (Note: aVertices and aIndices use the sorted + // index space, so smoothNormals will too) + _ctmCalcSmoothNormals(self, aVertices, aIndices, smoothNormals); + + // Normal scaling factor + scale = 1.0f / self->mNormalPrecision; + + for(i = 0; i < self->mVertexCount; ++ i) + { + // Get old normal index (before vertex sorting) + oldIdx = aSortVertices[i].mOriginalIndex; + + // Calculate normal magnitude (should always be 1.0 for unit length normals) + magn = sqrtf(self->mNormals[oldIdx * 3] * self->mNormals[oldIdx * 3] + + self->mNormals[oldIdx * 3 + 1] * self->mNormals[oldIdx * 3 + 1] + + self->mNormals[oldIdx * 3 + 2] * self->mNormals[oldIdx * 3 + 2]); + if(magn < 1e-10f) + magn = 1.0f; + + // Invert magnitude if the normal is negative compared to the predicted + // smooth normal + if((smoothNormals[i * 3] * self->mNormals[oldIdx * 3] + + smoothNormals[i * 3 + 1] * self->mNormals[oldIdx * 3 + 1] + + smoothNormals[i * 3 + 2] * self->mNormals[oldIdx * 3 + 2]) < 0.0f) + magn = -magn; + + // Store the magnitude in the first element of the three normal elements + aIntNormals[i * 3] = (CTMint) floorf(scale * magn + 0.5f); + + // Normalize the normal (1 / magn) - and flip it if magn < 0 + magn = 1.0f / magn; + for(j = 0; j < 3; ++ j) + n[j] = self->mNormals[oldIdx * 3 + j] * magn; + + // Convert the normal to angular representation (phi, theta) in a coordinate + // system where the nominal (smooth) normal is the Z-axis + _ctmMakeNormalCoordSys(&smoothNormals[i * 3], basisAxes); + for(j = 0; j < 3; ++ j) + n2[j] = basisAxes[j * 3] * n[0] + + basisAxes[j * 3 + 1] * n[1] + + basisAxes[j * 3 + 2] * n[2]; + if(n2[2] >= 1.0f) + phi = 0.0f; + else + phi = acosf(n2[2]); + theta = atan2f(n2[1], n2[0]); + + // Round phi and theta (spherical coordinates) to integers. Note: We let the + // theta resolution vary with the x/y circumference (roughly phi). + intPhi = (CTMint) floorf(phi * (scale / (0.5f * PI)) + 0.5f); + if(intPhi == 0) + thetaScale = 0.0f; + else if(intPhi <= 4) + thetaScale = 2.0f / PI; + else + thetaScale = ((CTMfloat) intPhi) / (2.0f * PI); + aIntNormals[i * 3 + 1] = intPhi; + aIntNormals[i * 3 + 2] = (CTMint) floorf((theta + PI) * thetaScale + 0.5f); + } + + // Free temporary resources + free(smoothNormals); + + return CTM_TRUE; +} + +//----------------------------------------------------------------------------- +// _ctmRestoreNormals() - Convert the normals back to cartesian coordinates. +//----------------------------------------------------------------------------- +static CTMint _ctmRestoreNormals(_CTMcontext * self, CTMint * aIntNormals) +{ + CTMuint i, j, intPhi; + CTMfloat magn, phi, theta, scale, thetaScale; + CTMfloat * smoothNormals, n[3], n2[3], basisAxes[9]; + + // Allocate temporary memory for the nominal vertex normals + smoothNormals = (CTMfloat *) malloc(3 * sizeof(CTMfloat) * self->mVertexCount); + if(!smoothNormals) + { + self->mError = CTM_OUT_OF_MEMORY; + return CTM_FALSE; + } + + // Calculate smooth normals (nominal normals) + _ctmCalcSmoothNormals(self, self->mVertices, self->mIndices, smoothNormals); + + // Normal scaling factor + scale = self->mNormalPrecision; + + for(i = 0; i < self->mVertexCount; ++ i) + { + // Get the normal magnitude from the first of the three normal elements + magn = aIntNormals[i * 3] * scale; + + // Get phi and theta (spherical coordinates, relative to the smooth normal). + intPhi = aIntNormals[i * 3 + 1]; + phi = intPhi * (0.5f * PI) * scale; + if(intPhi == 0) + thetaScale = 0.0f; + else if(intPhi <= 4) + thetaScale = PI / 2.0f; + else + thetaScale = (2.0f * PI) / ((CTMfloat) intPhi); + theta = aIntNormals[i * 3 + 2] * thetaScale - PI; + + // Convert the normal from the angular representation (phi, theta) back to + // cartesian coordinates + n2[0] = sinf(phi) * cosf(theta); + n2[1] = sinf(phi) * sinf(theta); + n2[2] = cosf(phi); + _ctmMakeNormalCoordSys(&smoothNormals[i * 3], basisAxes); + for(j = 0; j < 3; ++ j) + n[j] = basisAxes[j] * n2[0] + + basisAxes[3 + j] * n2[1] + + basisAxes[6 + j] * n2[2]; + + // Apply normal magnitude, and output to the normals array + for(j = 0; j < 3; ++ j) + self->mNormals[i * 3 + j] = n[j] * magn; + } + + // Free temporary resources + free(smoothNormals); + + return CTM_TRUE; +} + +//----------------------------------------------------------------------------- +// _ctmMakeUVCoordDeltas() - Calculate various forms of derivatives in order +// to reduce data entropy. +//----------------------------------------------------------------------------- +static void _ctmMakeUVCoordDeltas(_CTMcontext * self, _CTMfloatmap * aMap, + CTMint * aIntUVCoords, _CTMsortvertex * aSortVertices) +{ + CTMuint i, oldIdx; + CTMint u, v, prevU, prevV; + CTMfloat scale; + + // UV coordinate scaling factor + scale = 1.0f / aMap->mPrecision; + + prevU = prevV = 0; + for(i = 0; i < self->mVertexCount; ++ i) + { + // Get old UV coordinate index (before vertex sorting) + oldIdx = aSortVertices[i].mOriginalIndex; + + // Convert to fixed point + u = (CTMint) floorf(scale * aMap->mValues[oldIdx * 2] + 0.5f); + v = (CTMint) floorf(scale * aMap->mValues[oldIdx * 2 + 1] + 0.5f); + + // Calculate delta and store it in the converted array. NOTE: Here we rely + // on the fact that vertices are sorted, and usually close to each other, + // which means that UV coordinates should also be close to each other... + aIntUVCoords[i * 2] = u - prevU; + aIntUVCoords[i * 2 + 1] = v - prevV; + + prevU = u; + prevV = v; + } +} + +//----------------------------------------------------------------------------- +// _ctmRestoreUVCoords() - Calculate inverse derivatives of the UV +// coordinates. +//----------------------------------------------------------------------------- +static void _ctmRestoreUVCoords(_CTMcontext * self, _CTMfloatmap * aMap, + CTMint * aIntUVCoords) +{ + CTMuint i; + CTMint u, v, prevU, prevV; + CTMfloat scale; + + // UV coordinate scaling factor + scale = aMap->mPrecision; + + prevU = prevV = 0; + for(i = 0; i < self->mVertexCount; ++ i) + { + // Calculate inverse delta + u = aIntUVCoords[i * 2] + prevU; + v = aIntUVCoords[i * 2 + 1] + prevV; + + // Convert to floating point + aMap->mValues[i * 2] = (CTMfloat) u * scale; + aMap->mValues[i * 2 + 1] = (CTMfloat) v * scale; + + prevU = u; + prevV = v; + } +} + +//----------------------------------------------------------------------------- +// _ctmMakeAttribDeltas() - Calculate various forms of derivatives in order +// to reduce data entropy. +//----------------------------------------------------------------------------- +static void _ctmMakeAttribDeltas(_CTMcontext * self, _CTMfloatmap * aMap, + CTMint * aIntAttribs, _CTMsortvertex * aSortVertices) +{ + CTMuint i, j, oldIdx; + CTMint value[4], prev[4]; + CTMfloat scale; + + // Attribute scaling factor + scale = 1.0f / aMap->mPrecision; + + for(j = 0; j < 4; ++ j) + prev[j] = 0; + + for(i = 0; i < self->mVertexCount; ++ i) + { + // Get old attribute index (before vertex sorting) + oldIdx = aSortVertices[i].mOriginalIndex; + + // Convert to fixed point, and calculate delta and store it in the converted + // array. NOTE: Here we rely on the fact that vertices are sorted, and + // usually close to each other, which means that attributes should also + // be close to each other (and we assume that they somehow vary slowly with + // the geometry)... + for(j = 0; j < 4; ++ j) + { + value[j] = (CTMint) floorf(scale * aMap->mValues[oldIdx * 4 + j] + 0.5f); + aIntAttribs[i * 4 + j] = value[j] - prev[j]; + prev[j] = value[j]; + } + } +} + +//----------------------------------------------------------------------------- +// _ctmRestoreAttribs() - Calculate inverse derivatives of the vertex +// attributes. +//----------------------------------------------------------------------------- +static void _ctmRestoreAttribs(_CTMcontext * self, _CTMfloatmap * aMap, + CTMint * aIntAttribs) +{ + CTMuint i, j; + CTMint value[4], prev[4]; + CTMfloat scale; + + // Attribute scaling factor + scale = aMap->mPrecision; + + for(j = 0; j < 4; ++ j) + prev[j] = 0; + + for(i = 0; i < self->mVertexCount; ++ i) + { + // Calculate inverse delta, and convert to floating point + for(j = 0; j < 4; ++ j) + { + value[j] = aIntAttribs[i * 4 + j] + prev[j]; + aMap->mValues[i * 4 + j] = (CTMfloat) value[j] * scale; + prev[j] = value[j]; + } + } +} + +//----------------------------------------------------------------------------- +// _ctmCompressMesh_MG2() - Compress the mesh that is stored in the CTM +// context, and write it the the output stream in the CTM context. +//----------------------------------------------------------------------------- +int _ctmCompressMesh_MG2(_CTMcontext * self) +{ + _CTMgrid grid; + _CTMsortvertex * sortVertices; + _CTMfloatmap * map; + CTMuint * indices, * deltaIndices, * gridIndices; + CTMint * intVertices, * intNormals, * intUVCoords, * intAttribs; + CTMfloat * restoredVertices; + CTMuint i; + +#ifdef __DEBUG_ + printf("COMPRESSION METHOD: MG2\n"); +#endif + + // Setup 3D space subdivision grid + _ctmSetupGrid(self, &grid); + + // Write MG2-specific header information to the stream + _ctmStreamWrite(self, (void *) "MG2H", 4); + _ctmStreamWriteFLOAT(self, self->mVertexPrecision); + _ctmStreamWriteFLOAT(self, self->mNormalPrecision); + _ctmStreamWriteFLOAT(self, grid.mMin[0]); + _ctmStreamWriteFLOAT(self, grid.mMin[1]); + _ctmStreamWriteFLOAT(self, grid.mMin[2]); + _ctmStreamWriteFLOAT(self, grid.mMax[0]); + _ctmStreamWriteFLOAT(self, grid.mMax[1]); + _ctmStreamWriteFLOAT(self, grid.mMax[2]); + _ctmStreamWriteUINT(self, grid.mDivision[0]); + _ctmStreamWriteUINT(self, grid.mDivision[1]); + _ctmStreamWriteUINT(self, grid.mDivision[2]); + + // Prepare (sort) vertices + sortVertices = (_CTMsortvertex *) malloc(sizeof(_CTMsortvertex) * self->mVertexCount); + if(!sortVertices) + { + self->mError = CTM_OUT_OF_MEMORY; + return CTM_FALSE; + } + _ctmSortVertices(self, sortVertices, &grid); + + // Convert vertices to integers and calculate vertex deltas (entropy-reduction) + intVertices = (CTMint *) malloc(sizeof(CTMint) * 3 * self->mVertexCount); + if(!intVertices) + { + self->mError = CTM_OUT_OF_MEMORY; + free((void *) sortVertices); + return CTM_FALSE; + } + _ctmMakeVertexDeltas(self, intVertices, sortVertices, &grid); + + // Write vertices +#ifdef __DEBUG_ + printf("Vertices: "); +#endif + _ctmStreamWrite(self, (void *) "VERT", 4); + if(!_ctmStreamWritePackedInts(self, intVertices, self->mVertexCount, 3, CTM_FALSE)) + { + free((void *) intVertices); + free((void *) sortVertices); + return CTM_FALSE; + } + + // Prepare grid indices (deltas) + gridIndices = (CTMuint *) malloc(sizeof(CTMuint) * self->mVertexCount); + if(!gridIndices) + { + self->mError = CTM_OUT_OF_MEMORY; + free((void *) intVertices); + free((void *) sortVertices); + return CTM_FALSE; + } + gridIndices[0] = sortVertices[0].mGridIndex; + for(i = 1; i < self->mVertexCount; ++ i) + gridIndices[i] = sortVertices[i].mGridIndex - sortVertices[i - 1].mGridIndex; + + // Write grid indices +#ifdef __DEBUG_ + printf("Grid indices: "); +#endif + _ctmStreamWrite(self, (void *) "GIDX", 4); + if(!_ctmStreamWritePackedInts(self, (CTMint *) gridIndices, self->mVertexCount, 1, CTM_FALSE)) + { + free((void *) gridIndices); + free((void *) intVertices); + free((void *) sortVertices); + return CTM_FALSE; + } + + // Calculate the result of the compressed -> decompressed vertices, in order + // to use the same vertex data for calculating nominal normals as the + // decompression routine (i.e. compensate for the vertex error when + // calculating the normals) + restoredVertices = (CTMfloat *) malloc(sizeof(CTMfloat) * 3 * self->mVertexCount); + if(!restoredVertices) + { + self->mError = CTM_OUT_OF_MEMORY; + free((void *) gridIndices); + free((void *) intVertices); + free((void *) sortVertices); + return CTM_FALSE; + } + for(i = 1; i < self->mVertexCount; ++ i) + gridIndices[i] += gridIndices[i - 1]; + _ctmRestoreVertices(self, intVertices, gridIndices, &grid, restoredVertices); + + // Free temporary resources + free((void *) gridIndices); + free((void *) intVertices); + + // Perpare (sort) indices + indices = (CTMuint *) malloc(sizeof(CTMuint) * self->mTriangleCount * 3); + if(!indices) + { + self->mError = CTM_OUT_OF_MEMORY; + free((void *) restoredVertices); + free((void *) sortVertices); + return CTM_FALSE; + } + if(!_ctmReIndexIndices(self, sortVertices, indices)) + { + free((void *) indices); + free((void *) restoredVertices); + free((void *) sortVertices); + return CTM_FALSE; + } + _ctmReArrangeTriangles(self, indices); + + // Calculate index deltas (entropy-reduction) + deltaIndices = (CTMuint *) malloc(sizeof(CTMuint) * self->mTriangleCount * 3); + if(!indices) + { + self->mError = CTM_OUT_OF_MEMORY; + free((void *) indices); + free((void *) restoredVertices); + free((void *) sortVertices); + return CTM_FALSE; + } + for(i = 0; i < self->mTriangleCount * 3; ++ i) + deltaIndices[i] = indices[i]; + _ctmMakeIndexDeltas(self, deltaIndices); + + // Write triangle indices +#ifdef __DEBUG_ + printf("Indices: "); +#endif + _ctmStreamWrite(self, (void *) "INDX", 4); + if(!_ctmStreamWritePackedInts(self, (CTMint *) deltaIndices, self->mTriangleCount, 3, CTM_FALSE)) + { + free((void *) deltaIndices); + free((void *) indices); + free((void *) restoredVertices); + free((void *) sortVertices); + return CTM_FALSE; + } + + // Free temporary data for the indices + free((void *) deltaIndices); + + if(self->mNormals) + { + // Convert normals to integers and calculate deltas (entropy-reduction) + intNormals = (CTMint *) malloc(sizeof(CTMint) * 3 * self->mVertexCount); + if(!intNormals) + { + self->mError = CTM_OUT_OF_MEMORY; + free((void *) indices); + free((void *) restoredVertices); + free((void *) sortVertices); + return CTM_FALSE; + } + if(!_ctmMakeNormalDeltas(self, intNormals, restoredVertices, indices, sortVertices)) + { + free((void *) indices); + free((void *) intNormals); + free((void *) restoredVertices); + free((void *) sortVertices); + return CTM_FALSE; + } + + // Write normals +#ifdef __DEBUG_ + printf("Normals: "); +#endif + _ctmStreamWrite(self, (void *) "NORM", 4); + if(!_ctmStreamWritePackedInts(self, intNormals, self->mVertexCount, 3, CTM_FALSE)) + { + free((void *) indices); + free((void *) intNormals); + free((void *) restoredVertices); + free((void *) sortVertices); + return CTM_FALSE; + } + + // Free temporary normal data + free((void *) intNormals); + } + + // Free restored indices and vertices + free((void *) indices); + free((void *) restoredVertices); + + // Write UV maps + map = self->mUVMaps; + while(map) + { + // Convert UV coordinates to integers and calculate deltas (entropy-reduction) + intUVCoords = (CTMint *) malloc(sizeof(CTMint) * 2 * self->mVertexCount); + if(!intUVCoords) + { + self->mError = CTM_OUT_OF_MEMORY; + free((void *) sortVertices); + return CTM_FALSE; + } + _ctmMakeUVCoordDeltas(self, map, intUVCoords, sortVertices); + + // Write UV coordinates +#ifdef __DEBUG_ + printf("Texture coordinates (%s): ", map->mName ? map->mName : "no name"); +#endif + _ctmStreamWrite(self, (void *) "TEXC", 4); + _ctmStreamWriteSTRING(self, map->mName); + _ctmStreamWriteSTRING(self, map->mFileName); + _ctmStreamWriteFLOAT(self, map->mPrecision); + if(!_ctmStreamWritePackedInts(self, intUVCoords, self->mVertexCount, 2, CTM_TRUE)) + { + free((void *) intUVCoords); + free((void *) sortVertices); + return CTM_FALSE; + } + + // Free temporary UV coordinate data + free((void *) intUVCoords); + + map = map->mNext; + } + + // Write vertex attribute maps + map = self->mAttribMaps; + while(map) + { + // Convert vertex attributes to integers and calculate deltas (entropy-reduction) + intAttribs = (CTMint *) malloc(sizeof(CTMint) * 4 * self->mVertexCount); + if(!intAttribs) + { + self->mError = CTM_OUT_OF_MEMORY; + free((void *) sortVertices); + return CTM_FALSE; + } + _ctmMakeAttribDeltas(self, map, intAttribs, sortVertices); + + // Write vertex attributes +#ifdef __DEBUG_ + printf("Vertex attributes (%s): ", map->mName ? map->mName : "no name"); +#endif + _ctmStreamWrite(self, (void *) "ATTR", 4); + _ctmStreamWriteSTRING(self, map->mName); + _ctmStreamWriteFLOAT(self, map->mPrecision); + if(!_ctmStreamWritePackedInts(self, intAttribs, self->mVertexCount, 4, CTM_TRUE)) + { + free((void *) intAttribs); + free((void *) sortVertices); + return CTM_FALSE; + } + + // Free temporary vertex attribute data + free((void *) intAttribs); + + map = map->mNext; + } + + // Free temporary data + free((void *) sortVertices); + + return CTM_TRUE; +} + +//----------------------------------------------------------------------------- +// _ctmUncompressMesh_MG2() - Uncmpress the mesh from the input stream in the +// CTM context, and store the resulting mesh in the CTM context. +//----------------------------------------------------------------------------- +int _ctmUncompressMesh_MG2(_CTMcontext * self) +{ + CTMuint * gridIndices, i; + CTMint * intVertices, * intNormals, * intUVCoords, * intAttribs; + _CTMfloatmap * map; + _CTMgrid grid; + + // Read MG2-specific header information from the stream + if(_ctmStreamReadUINT(self) != FOURCC("MG2H")) + { + self->mError = CTM_BAD_FORMAT; + return CTM_FALSE; + } + self->mVertexPrecision = _ctmStreamReadFLOAT(self); + if(self->mVertexPrecision <= 0.0f) + { + self->mError = CTM_BAD_FORMAT; + return CTM_FALSE; + } + self->mNormalPrecision = _ctmStreamReadFLOAT(self); + if(self->mNormalPrecision <= 0.0f) + { + self->mError = CTM_BAD_FORMAT; + return CTM_FALSE; + } + grid.mMin[0] = _ctmStreamReadFLOAT(self); + grid.mMin[1] = _ctmStreamReadFLOAT(self); + grid.mMin[2] = _ctmStreamReadFLOAT(self); + grid.mMax[0] = _ctmStreamReadFLOAT(self); + grid.mMax[1] = _ctmStreamReadFLOAT(self); + grid.mMax[2] = _ctmStreamReadFLOAT(self); + if((grid.mMax[0] < grid.mMin[0]) || + (grid.mMax[1] < grid.mMin[1]) || + (grid.mMax[2] < grid.mMin[2])) + { + self->mError = CTM_BAD_FORMAT; + return CTM_FALSE; + } + grid.mDivision[0] = _ctmStreamReadUINT(self); + grid.mDivision[1] = _ctmStreamReadUINT(self); + grid.mDivision[2] = _ctmStreamReadUINT(self); + if((grid.mDivision[0] < 1) || (grid.mDivision[1] < 1) || (grid.mDivision[2] < 1)) + { + self->mError = CTM_BAD_FORMAT; + return CTM_FALSE; + } + + // Initialize 3D space subdivision grid + for(i = 0; i < 3; ++ i) + grid.mSize[i] = (grid.mMax[i] - grid.mMin[i]) / grid.mDivision[i]; + + // Read vertices + if(_ctmStreamReadUINT(self) != FOURCC("VERT")) + { + self->mError = CTM_BAD_FORMAT; + return CTM_FALSE; + } + intVertices = (CTMint *) malloc(sizeof(CTMint) * self->mVertexCount * 3); + if(!intVertices) + { + self->mError = CTM_OUT_OF_MEMORY; + return CTM_FALSE; + } + if(!_ctmStreamReadPackedInts(self, intVertices, self->mVertexCount, 3, CTM_FALSE)) + { + free((void *) intVertices); + return CTM_FALSE; + } + + // Read grid indices + if(_ctmStreamReadUINT(self) != FOURCC("GIDX")) + { + free((void *) intVertices); + self->mError = CTM_BAD_FORMAT; + return CTM_FALSE; + } + gridIndices = (CTMuint *) malloc(sizeof(CTMuint) * self->mVertexCount); + if(!gridIndices) + { + self->mError = CTM_OUT_OF_MEMORY; + free((void *) intVertices); + return CTM_FALSE; + } + if(!_ctmStreamReadPackedInts(self, (CTMint *) gridIndices, self->mVertexCount, 1, CTM_FALSE)) + { + free((void *) gridIndices); + free((void *) intVertices); + return CTM_FALSE; + } + + // Restore grid indices (deltas) + for(i = 1; i < self->mVertexCount; ++ i) + gridIndices[i] += gridIndices[i - 1]; + + // Restore vertices + _ctmRestoreVertices(self, intVertices, gridIndices, &grid, self->mVertices); + + // Free temporary resources + free((void *) gridIndices); + free((void *) intVertices); + + // Read triangle indices + if(_ctmStreamReadUINT(self) != FOURCC("INDX")) + { + self->mError = CTM_BAD_FORMAT; + return CTM_FALSE; + } + if(!_ctmStreamReadPackedInts(self, (CTMint *) self->mIndices, self->mTriangleCount, 3, CTM_FALSE)) + return CTM_FALSE; + + // Restore indices + _ctmRestoreIndices(self, self->mIndices); + + // Check that all indices are within range + for(i = 0; i < (self->mTriangleCount * 3); ++ i) + { + if(self->mIndices[i] >= self->mVertexCount) + { + self->mError = CTM_INVALID_MESH; + return CTM_FALSE; + } + } + + // Read normals + if(self->mNormals) + { + intNormals = (CTMint *) malloc(sizeof(CTMint) * self->mVertexCount * 3); + if(!intNormals) + { + self->mError = CTM_OUT_OF_MEMORY; + return CTM_FALSE; + } + if(_ctmStreamReadUINT(self) != FOURCC("NORM")) + { + self->mError = CTM_BAD_FORMAT; + free((void *) intNormals); + return CTM_FALSE; + } + if(!_ctmStreamReadPackedInts(self, intNormals, self->mVertexCount, 3, CTM_FALSE)) + { + free((void *) intNormals); + return CTM_FALSE; + } + + // Restore normals + if(!_ctmRestoreNormals(self, intNormals)) + { + free((void *) intNormals); + return CTM_FALSE; + } + + // Free temporary normals data + free((void *) intNormals); + } + + // Read UV maps + map = self->mUVMaps; + while(map) + { + intUVCoords = (CTMint *) malloc(sizeof(CTMint) * self->mVertexCount * 2); + if(!intUVCoords) + { + self->mError = CTM_OUT_OF_MEMORY; + return CTM_FALSE; + } + if(_ctmStreamReadUINT(self) != FOURCC("TEXC")) + { + self->mError = CTM_BAD_FORMAT; + free((void *) intUVCoords); + return CTM_FALSE; + } + _ctmStreamReadSTRING(self, &map->mName); + _ctmStreamReadSTRING(self, &map->mFileName); + map->mPrecision = _ctmStreamReadFLOAT(self); + if(map->mPrecision <= 0.0f) + { + self->mError = CTM_BAD_FORMAT; + free((void *) intUVCoords); + return CTM_FALSE; + } + if(!_ctmStreamReadPackedInts(self, intUVCoords, self->mVertexCount, 2, CTM_TRUE)) + { + free((void *) intUVCoords); + return CTM_FALSE; + } + + // Restore UV coordinates + _ctmRestoreUVCoords(self, map, intUVCoords); + + // Free temporary UV coordinate data + free((void *) intUVCoords); + + map = map->mNext; + } + + // Read vertex attribute maps + map = self->mAttribMaps; + while(map) + { + intAttribs = (CTMint *) malloc(sizeof(CTMint) * self->mVertexCount * 4); + if(!intAttribs) + { + self->mError = CTM_OUT_OF_MEMORY; + return CTM_FALSE; + } + if(_ctmStreamReadUINT(self) != FOURCC("ATTR")) + { + self->mError = CTM_BAD_FORMAT; + free((void *) intAttribs); + return CTM_FALSE; + } + _ctmStreamReadSTRING(self, &map->mName); + map->mPrecision = _ctmStreamReadFLOAT(self); + if(map->mPrecision <= 0.0f) + { + self->mError = CTM_BAD_FORMAT; + free((void *) intAttribs); + return CTM_FALSE; + } + if(!_ctmStreamReadPackedInts(self, intAttribs, self->mVertexCount, 4, CTM_TRUE)) + { + free((void *) intAttribs); + return CTM_FALSE; + } + + // Restore vertex attributes + _ctmRestoreAttribs(self, map, intAttribs); + + // Free temporary vertex attribute data + free((void *) intAttribs); + + map = map->mNext; + } + + return CTM_TRUE; +} diff --git a/src/external/OpenCTM-1.0.3/lib/compressRAW.c b/src/external/OpenCTM-1.0.3/lib/compressRAW.c new file mode 100644 index 000000000..b3c781102 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/compressRAW.c @@ -0,0 +1,181 @@ +//----------------------------------------------------------------------------- +// Product: OpenCTM +// File: compressRAW.c +// Description: Implementation of the RAW compression method. +//----------------------------------------------------------------------------- +// Copyright (c) 2009-2010 Marcus Geelnard +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +//----------------------------------------------------------------------------- + +#include "openctm.h" +#include "internal.h" + +#ifdef __DEBUG_ +#include +#endif + + +//----------------------------------------------------------------------------- +// _ctmCompressMesh_RAW() - Compress the mesh that is stored in the CTM +// context using the RAW method, and write it the the output stream in the CTM +// context. +//----------------------------------------------------------------------------- +int _ctmCompressMesh_RAW(_CTMcontext * self) +{ + CTMuint i; + _CTMfloatmap * map; + +#ifdef __DEBUG_ + printf("COMPRESSION METHOD: RAW\n"); +#endif + + // Write triangle indices +#ifdef __DEBUG_ + printf("Inidices: %d bytes\n", (CTMuint)(self->mTriangleCount * 3 * sizeof(CTMuint))); +#endif + _ctmStreamWrite(self, (void *) "INDX", 4); + for(i = 0; i < self->mTriangleCount * 3; ++ i) + _ctmStreamWriteUINT(self, self->mIndices[i]); + + // Write vertices +#ifdef __DEBUG_ + printf("Vertices: %d bytes\n", (CTMuint)(self->mVertexCount * 3 * sizeof(CTMfloat))); +#endif + _ctmStreamWrite(self, (void *) "VERT", 4); + for(i = 0; i < self->mVertexCount * 3; ++ i) + _ctmStreamWriteFLOAT(self, self->mVertices[i]); + + // Write normals + if(self->mNormals) + { +#ifdef __DEBUG_ + printf("Normals: %d bytes\n", (CTMuint)(self->mVertexCount * 3 * sizeof(CTMfloat))); +#endif + _ctmStreamWrite(self, (void *) "NORM", 4); + for(i = 0; i < self->mVertexCount * 3; ++ i) + _ctmStreamWriteFLOAT(self, self->mNormals[i]); + } + + // Write UV maps + map = self->mUVMaps; + while(map) + { +#ifdef __DEBUG_ + printf("UV coordinates (%s): %d bytes\n", map->mName ? map->mName : "no name", (CTMuint)(self->mVertexCount * 2 * sizeof(CTMfloat))); +#endif + _ctmStreamWrite(self, (void *) "TEXC", 4); + _ctmStreamWriteSTRING(self, map->mName); + _ctmStreamWriteSTRING(self, map->mFileName); + for(i = 0; i < self->mVertexCount * 2; ++ i) + _ctmStreamWriteFLOAT(self, map->mValues[i]); + map = map->mNext; + } + + // Write attribute maps + map = self->mAttribMaps; + while(map) + { +#ifdef __DEBUG_ + printf("Vertex attributes (%s): %d bytes\n", map->mName ? map->mName : "no name", (CTMuint)(self->mVertexCount * 4 * sizeof(CTMfloat))); +#endif + _ctmStreamWrite(self, (void *) "ATTR", 4); + _ctmStreamWriteSTRING(self, map->mName); + for(i = 0; i < self->mVertexCount * 4; ++ i) + _ctmStreamWriteFLOAT(self, map->mValues[i]); + map = map->mNext; + } + + return 1; +} + +//----------------------------------------------------------------------------- +// _ctmUncompressMesh_RAW() - Uncmpress the mesh from the input stream in the +// CTM context using the RAW method, and store the resulting mesh in the CTM +// context. +//----------------------------------------------------------------------------- +int _ctmUncompressMesh_RAW(_CTMcontext * self) +{ + CTMuint i; + _CTMfloatmap * map; + + // Read triangle indices + if(_ctmStreamReadUINT(self) != FOURCC("INDX")) + { + self->mError = CTM_BAD_FORMAT; + return 0; + } + for(i = 0; i < self->mTriangleCount * 3; ++ i) + self->mIndices[i] = _ctmStreamReadUINT(self); + + // Read vertices + if(_ctmStreamReadUINT(self) != FOURCC("VERT")) + { + self->mError = CTM_BAD_FORMAT; + return 0; + } + for(i = 0; i < self->mVertexCount * 3; ++ i) + self->mVertices[i] = _ctmStreamReadFLOAT(self); + + // Read normals + if(self->mNormals) + { + if(_ctmStreamReadUINT(self) != FOURCC("NORM")) + { + self->mError = CTM_BAD_FORMAT; + return 0; + } + for(i = 0; i < self->mVertexCount * 3; ++ i) + self->mNormals[i] = _ctmStreamReadFLOAT(self); + } + + // Read UV maps + map = self->mUVMaps; + while(map) + { + if(_ctmStreamReadUINT(self) != FOURCC("TEXC")) + { + self->mError = CTM_BAD_FORMAT; + return 0; + } + _ctmStreamReadSTRING(self, &map->mName); + _ctmStreamReadSTRING(self, &map->mFileName); + for(i = 0; i < self->mVertexCount * 2; ++ i) + map->mValues[i] = _ctmStreamReadFLOAT(self); + map = map->mNext; + } + + // Read attribute maps + map = self->mAttribMaps; + while(map) + { + if(_ctmStreamReadUINT(self) != FOURCC("ATTR")) + { + self->mError = CTM_BAD_FORMAT; + return 0; + } + _ctmStreamReadSTRING(self, &map->mName); + for(i = 0; i < self->mVertexCount * 4; ++ i) + map->mValues[i] = _ctmStreamReadFLOAT(self); + map = map->mNext; + } + + return 1; +} diff --git a/src/external/OpenCTM-1.0.3/lib/internal.h b/src/external/OpenCTM-1.0.3/lib/internal.h new file mode 100644 index 000000000..2e65c86ba --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/internal.h @@ -0,0 +1,147 @@ +//----------------------------------------------------------------------------- +// Product: OpenCTM +// File: internal.h +// Description: Internal (private) declarations, types and function prototypes. +//----------------------------------------------------------------------------- +// Copyright (c) 2009-2010 Marcus Geelnard +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +//----------------------------------------------------------------------------- + +#ifndef __OPENCTM_INTERNAL_H_ +#define __OPENCTM_INTERNAL_H_ + +//----------------------------------------------------------------------------- +// Constants +//----------------------------------------------------------------------------- +// OpenCTM file format version (v5). +#define _CTM_FORMAT_VERSION 0x00000005 + +// Flags for the Mesh flags field of the file header +#define _CTM_HAS_NORMALS_BIT 0x00000001 + +//----------------------------------------------------------------------------- +// _CTMfloatmap - Internal representation of a floating point based vertex map +// (used for UV maps and attribute maps). +//----------------------------------------------------------------------------- +typedef struct _CTMfloatmap_struct _CTMfloatmap; +struct _CTMfloatmap_struct { + char * mName; // Unique name + char * mFileName; // File name reference (used only for UV maps) + CTMfloat mPrecision; // Precision for this map + CTMfloat * mValues; // Attribute/UV coordinate values (per vertex) + _CTMfloatmap * mNext; // Pointer to the next map in the list (linked list) +}; + +//----------------------------------------------------------------------------- +// _CTMcontext - Internal CTM context structure. +//----------------------------------------------------------------------------- +typedef struct { + // Context mode (import or export) + CTMenum mMode; + + // Vertices + CTMfloat * mVertices; + CTMuint mVertexCount; + + // Indices + CTMuint * mIndices; + CTMuint mTriangleCount; + + // Normals (optional) + CTMfloat * mNormals; + + // Multiple sets of UV coordinate maps (optional) + CTMuint mUVMapCount; + _CTMfloatmap * mUVMaps; + + // Multiple sets of custom vertex attribute maps (optional) + CTMuint mAttribMapCount; + _CTMfloatmap * mAttribMaps; + + // Last error code + CTMenum mError; + + // The selected compression method + CTMenum mMethod; + + // The selected compression level + CTMuint mCompressionLevel; + + // Vertex coordinate precision + CTMfloat mVertexPrecision; + + // Normal precision (angular + magnitude) + CTMfloat mNormalPrecision; + + // File comment + char * mFileComment; + + // Read() function pointer + CTMreadfn mReadFn; + + // Write() function pointer + CTMwritefn mWriteFn; + + // User data (for stream read/write - usually the stream handle) + void * mUserData; +} _CTMcontext; + +//----------------------------------------------------------------------------- +// Macros +//----------------------------------------------------------------------------- +#define FOURCC(str) (((CTMuint) str[0]) | (((CTMuint) str[1]) << 8) | \ + (((CTMuint) str[2]) << 16) | (((CTMuint) str[3]) << 24)) + +//----------------------------------------------------------------------------- +// Funcion prototypes for stream.c +//----------------------------------------------------------------------------- +CTMuint _ctmStreamRead(_CTMcontext * self, void * aBuf, CTMuint aCount); +CTMuint _ctmStreamWrite(_CTMcontext * self, void * aBuf, CTMuint aCount); +CTMuint _ctmStreamReadUINT(_CTMcontext * self); +void _ctmStreamWriteUINT(_CTMcontext * self, CTMuint aValue); +CTMfloat _ctmStreamReadFLOAT(_CTMcontext * self); +void _ctmStreamWriteFLOAT(_CTMcontext * self, CTMfloat aValue); +void _ctmStreamReadSTRING(_CTMcontext * self, char ** aValue); +void _ctmStreamWriteSTRING(_CTMcontext * self, const char * aValue); +int _ctmStreamReadPackedInts(_CTMcontext * self, CTMint * aData, CTMuint aCount, CTMuint aSize, CTMint aSignedInts); +int _ctmStreamWritePackedInts(_CTMcontext * self, CTMint * aData, CTMuint aCount, CTMuint aSize, CTMint aSignedInts); +int _ctmStreamReadPackedFloats(_CTMcontext * self, CTMfloat * aData, CTMuint aCount, CTMuint aSize); +int _ctmStreamWritePackedFloats(_CTMcontext * self, CTMfloat * aData, CTMuint aCount, CTMuint aSize); + +//----------------------------------------------------------------------------- +// Funcion prototypes for compressRAW.c +//----------------------------------------------------------------------------- +int _ctmCompressMesh_RAW(_CTMcontext * self); +int _ctmUncompressMesh_RAW(_CTMcontext * self); + +//----------------------------------------------------------------------------- +// Funcion prototypes for compressMG1.c +//----------------------------------------------------------------------------- +int _ctmCompressMesh_MG1(_CTMcontext * self); +int _ctmUncompressMesh_MG1(_CTMcontext * self); + +//----------------------------------------------------------------------------- +// Funcion prototypes for compressMG2.c +//----------------------------------------------------------------------------- +int _ctmCompressMesh_MG2(_CTMcontext * self); +int _ctmUncompressMesh_MG2(_CTMcontext * self); + +#endif // __OPENCTM_INTERNAL_H_ diff --git a/src/external/OpenCTM-1.0.3/lib/liblzma/Alloc.c b/src/external/OpenCTM-1.0.3/lib/liblzma/Alloc.c new file mode 100644 index 000000000..358a7b526 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/liblzma/Alloc.c @@ -0,0 +1,127 @@ +/* Alloc.c -- Memory allocation functions +2008-09-24 +Igor Pavlov +Public domain */ + +#ifdef _WIN32 +#include +#endif +#include + +#include "Alloc.h" + +/* #define _SZ_ALLOC_DEBUG */ + +/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */ +#ifdef _SZ_ALLOC_DEBUG +#include +int g_allocCount = 0; +int g_allocCountMid = 0; +int g_allocCountBig = 0; +#endif + +void *MyAlloc(size_t size) +{ + if (size == 0) + return 0; + #ifdef _SZ_ALLOC_DEBUG + { + void *p = malloc(size); + fprintf(stderr, "\nAlloc %10d bytes, count = %10d, addr = %8X", size, g_allocCount++, (unsigned)p); + return p; + } + #else + return malloc(size); + #endif +} + +void MyFree(void *address) +{ + #ifdef _SZ_ALLOC_DEBUG + if (address != 0) + fprintf(stderr, "\nFree; count = %10d, addr = %8X", --g_allocCount, (unsigned)address); + #endif + free(address); +} + +#ifdef _WIN32 + +void *MidAlloc(size_t size) +{ + if (size == 0) + return 0; + #ifdef _SZ_ALLOC_DEBUG + fprintf(stderr, "\nAlloc_Mid %10d bytes; count = %10d", size, g_allocCountMid++); + #endif + return VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE); +} + +void MidFree(void *address) +{ + #ifdef _SZ_ALLOC_DEBUG + if (address != 0) + fprintf(stderr, "\nFree_Mid; count = %10d", --g_allocCountMid); + #endif + if (address == 0) + return; + VirtualFree(address, 0, MEM_RELEASE); +} + +#ifndef MEM_LARGE_PAGES +#undef _7ZIP_LARGE_PAGES +#endif + +#ifdef _7ZIP_LARGE_PAGES +SIZE_T g_LargePageSize = 0; +typedef SIZE_T (WINAPI *GetLargePageMinimumP)(); +#endif + +void SetLargePageSize() +{ + #ifdef _7ZIP_LARGE_PAGES + SIZE_T size = 0; + GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP) + GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum"); + if (largePageMinimum == 0) + return; + size = largePageMinimum(); + if (size == 0 || (size & (size - 1)) != 0) + return; + g_LargePageSize = size; + #endif +} + + +void *BigAlloc(size_t size) +{ + if (size == 0) + return 0; + #ifdef _SZ_ALLOC_DEBUG + fprintf(stderr, "\nAlloc_Big %10d bytes; count = %10d", size, g_allocCountBig++); + #endif + + #ifdef _7ZIP_LARGE_PAGES + if (g_LargePageSize != 0 && g_LargePageSize <= (1 << 30) && size >= (1 << 18)) + { + void *res = VirtualAlloc(0, (size + g_LargePageSize - 1) & (~(g_LargePageSize - 1)), + MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE); + if (res != 0) + return res; + } + #endif + return VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE); +} + +void BigFree(void *address) +{ + #ifdef _SZ_ALLOC_DEBUG + if (address != 0) + fprintf(stderr, "\nFree_Big; count = %10d", --g_allocCountBig); + #endif + + if (address == 0) + return; + VirtualFree(address, 0, MEM_RELEASE); +} + +#endif diff --git a/src/external/OpenCTM-1.0.3/lib/liblzma/Alloc.h b/src/external/OpenCTM-1.0.3/lib/liblzma/Alloc.h new file mode 100644 index 000000000..510d18e4d --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/liblzma/Alloc.h @@ -0,0 +1,34 @@ +/* Alloc.h -- Memory allocation functions +2008-03-13 +Igor Pavlov +Public domain */ + +#ifndef __COMMON_ALLOC_H +#define __COMMON_ALLOC_H + +#include + +#include "NameMangle.h" + +void *MyAlloc(size_t size); +void MyFree(void *address); + +#ifdef _WIN32 + +void SetLargePageSize(); + +void *MidAlloc(size_t size); +void MidFree(void *address); +void *BigAlloc(size_t size); +void BigFree(void *address); + +#else + +#define MidAlloc(size) MyAlloc(size) +#define MidFree(address) MyFree(address) +#define BigAlloc(size) MyAlloc(size) +#define BigFree(address) MyFree(address) + +#endif + +#endif diff --git a/src/external/OpenCTM-1.0.3/lib/liblzma/LzFind.c b/src/external/OpenCTM-1.0.3/lib/liblzma/LzFind.c new file mode 100644 index 000000000..34f4f09ea --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/liblzma/LzFind.c @@ -0,0 +1,751 @@ +/* LzFind.c -- Match finder for LZ algorithms +2008-10-04 : Igor Pavlov : Public domain */ + +#include + +#include "LzFind.h" +#include "LzHash.h" + +#define kEmptyHashValue 0 +#define kMaxValForNormalize ((UInt32)0xFFFFFFFF) +#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */ +#define kNormalizeMask (~(kNormalizeStepMin - 1)) +#define kMaxHistorySize ((UInt32)3 << 30) + +#define kStartMaxLen 3 + +static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc) +{ + if (!p->directInput) + { + alloc->Free(alloc, p->bufferBase); + p->bufferBase = 0; + } +} + +/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */ + +static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc) +{ + UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv; + if (p->directInput) + { + p->blockSize = blockSize; + return 1; + } + if (p->bufferBase == 0 || p->blockSize != blockSize) + { + LzInWindow_Free(p, alloc); + p->blockSize = blockSize; + p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize); + } + return (p->bufferBase != 0); +} + +Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } +Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } + +UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } + +void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) +{ + p->posLimit -= subValue; + p->pos -= subValue; + p->streamPos -= subValue; +} + +static void MatchFinder_ReadBlock(CMatchFinder *p) +{ + if (p->streamEndWasReached || p->result != SZ_OK) + return; + for (;;) + { + Byte *dest = p->buffer + (p->streamPos - p->pos); + size_t size = (p->bufferBase + p->blockSize - dest); + if (size == 0) + return; + p->result = p->stream->Read(p->stream, dest, &size); + if (p->result != SZ_OK) + return; + if (size == 0) + { + p->streamEndWasReached = 1; + return; + } + p->streamPos += (UInt32)size; + if (p->streamPos - p->pos > p->keepSizeAfter) + return; + } +} + +void MatchFinder_MoveBlock(CMatchFinder *p) +{ + memmove(p->bufferBase, + p->buffer - p->keepSizeBefore, + (size_t)(p->streamPos - p->pos + p->keepSizeBefore)); + p->buffer = p->bufferBase + p->keepSizeBefore; +} + +int MatchFinder_NeedMove(CMatchFinder *p) +{ + /* if (p->streamEndWasReached) return 0; */ + return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter); +} + +void MatchFinder_ReadIfRequired(CMatchFinder *p) +{ + if (p->streamEndWasReached) + return; + if (p->keepSizeAfter >= p->streamPos - p->pos) + MatchFinder_ReadBlock(p); +} + +static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p) +{ + if (MatchFinder_NeedMove(p)) + MatchFinder_MoveBlock(p); + MatchFinder_ReadBlock(p); +} + +static void MatchFinder_SetDefaultSettings(CMatchFinder *p) +{ + p->cutValue = 32; + p->btMode = 1; + p->numHashBytes = 4; + /* p->skipModeBits = 0; */ + p->directInput = 0; + p->bigHash = 0; +} + +#define kCrcPoly 0xEDB88320 + +void MatchFinder_Construct(CMatchFinder *p) +{ + UInt32 i; + p->bufferBase = 0; + p->directInput = 0; + p->hash = 0; + MatchFinder_SetDefaultSettings(p); + + for (i = 0; i < 256; i++) + { + UInt32 r = i; + int j; + for (j = 0; j < 8; j++) + r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); + p->crc[i] = r; + } +} + +static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->hash); + p->hash = 0; +} + +void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc) +{ + MatchFinder_FreeThisClassMemory(p, alloc); + LzInWindow_Free(p, alloc); +} + +static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc) +{ + size_t sizeInBytes = (size_t)num * sizeof(CLzRef); + if (sizeInBytes / sizeof(CLzRef) != num) + return 0; + return (CLzRef *)alloc->Alloc(alloc, sizeInBytes); +} + +int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, + UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, + ISzAlloc *alloc) +{ + UInt32 sizeReserv; + if (historySize > kMaxHistorySize) + { + MatchFinder_Free(p, alloc); + return 0; + } + sizeReserv = historySize >> 1; + if (historySize > ((UInt32)2 << 30)) + sizeReserv = historySize >> 2; + sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19); + + p->keepSizeBefore = historySize + keepAddBufferBefore + 1; + p->keepSizeAfter = matchMaxLen + keepAddBufferAfter; + /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */ + if (LzInWindow_Create(p, sizeReserv, alloc)) + { + UInt32 newCyclicBufferSize = (historySize /* >> p->skipModeBits */) + 1; + UInt32 hs; + p->matchMaxLen = matchMaxLen; + { + p->fixedHashSize = 0; + if (p->numHashBytes == 2) + hs = (1 << 16) - 1; + else + { + hs = historySize - 1; + hs |= (hs >> 1); + hs |= (hs >> 2); + hs |= (hs >> 4); + hs |= (hs >> 8); + hs >>= 1; + /* hs >>= p->skipModeBits; */ + hs |= 0xFFFF; /* don't change it! It's required for Deflate */ + if (hs > (1 << 24)) + { + if (p->numHashBytes == 3) + hs = (1 << 24) - 1; + else + hs >>= 1; + } + } + p->hashMask = hs; + hs++; + if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size; + if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size; + if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size; + hs += p->fixedHashSize; + } + + { + UInt32 prevSize = p->hashSizeSum + p->numSons; + UInt32 newSize; + p->historySize = historySize; + p->hashSizeSum = hs; + p->cyclicBufferSize = newCyclicBufferSize; + p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize); + newSize = p->hashSizeSum + p->numSons; + if (p->hash != 0 && prevSize == newSize) + return 1; + MatchFinder_FreeThisClassMemory(p, alloc); + p->hash = AllocRefs(newSize, alloc); + if (p->hash != 0) + { + p->son = p->hash + p->hashSizeSum; + return 1; + } + } + } + MatchFinder_Free(p, alloc); + return 0; +} + +static void MatchFinder_SetLimits(CMatchFinder *p) +{ + UInt32 limit = kMaxValForNormalize - p->pos; + UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos; + if (limit2 < limit) + limit = limit2; + limit2 = p->streamPos - p->pos; + if (limit2 <= p->keepSizeAfter) + { + if (limit2 > 0) + limit2 = 1; + } + else + limit2 -= p->keepSizeAfter; + if (limit2 < limit) + limit = limit2; + { + UInt32 lenLimit = p->streamPos - p->pos; + if (lenLimit > p->matchMaxLen) + lenLimit = p->matchMaxLen; + p->lenLimit = lenLimit; + } + p->posLimit = p->pos + limit; +} + +void MatchFinder_Init(CMatchFinder *p) +{ + UInt32 i; + for (i = 0; i < p->hashSizeSum; i++) + p->hash[i] = kEmptyHashValue; + p->cyclicBufferPos = 0; + p->buffer = p->bufferBase; + p->pos = p->streamPos = p->cyclicBufferSize; + p->result = SZ_OK; + p->streamEndWasReached = 0; + MatchFinder_ReadBlock(p); + MatchFinder_SetLimits(p); +} + +static UInt32 MatchFinder_GetSubValue(CMatchFinder *p) +{ + return (p->pos - p->historySize - 1) & kNormalizeMask; +} + +void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) +{ + UInt32 i; + for (i = 0; i < numItems; i++) + { + UInt32 value = items[i]; + if (value <= subValue) + value = kEmptyHashValue; + else + value -= subValue; + items[i] = value; + } +} + +static void MatchFinder_Normalize(CMatchFinder *p) +{ + UInt32 subValue = MatchFinder_GetSubValue(p); + MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons); + MatchFinder_ReduceOffsets(p, subValue); +} + +static void MatchFinder_CheckLimits(CMatchFinder *p) +{ + if (p->pos == kMaxValForNormalize) + MatchFinder_Normalize(p); + if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos) + MatchFinder_CheckAndMoveAndRead(p); + if (p->cyclicBufferPos == p->cyclicBufferSize) + p->cyclicBufferPos = 0; + MatchFinder_SetLimits(p); +} + +static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, + UInt32 *distances, UInt32 maxLen) +{ + son[_cyclicBufferPos] = curMatch; + for (;;) + { + UInt32 delta = pos - curMatch; + if (cutValue-- == 0 || delta >= _cyclicBufferSize) + return distances; + { + const Byte *pb = cur - delta; + curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; + if (pb[maxLen] == cur[maxLen] && *pb == *cur) + { + UInt32 len = 0; + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + if (maxLen < len) + { + *distances++ = maxLen = len; + *distances++ = delta - 1; + if (len == lenLimit) + return distances; + } + } + } + } +} + +UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, + UInt32 *distances, UInt32 maxLen) +{ + CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; + CLzRef *ptr1 = son + (_cyclicBufferPos << 1); + UInt32 len0 = 0, len1 = 0; + for (;;) + { + UInt32 delta = pos - curMatch; + if (cutValue-- == 0 || delta >= _cyclicBufferSize) + { + *ptr0 = *ptr1 = kEmptyHashValue; + return distances; + } + { + CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); + const Byte *pb = cur - delta; + UInt32 len = (len0 < len1 ? len0 : len1); + if (pb[len] == cur[len]) + { + if (++len != lenLimit && pb[len] == cur[len]) + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + if (maxLen < len) + { + *distances++ = maxLen = len; + *distances++ = delta - 1; + if (len == lenLimit) + { + *ptr1 = pair[0]; + *ptr0 = pair[1]; + return distances; + } + } + } + if (pb[len] < cur[len]) + { + *ptr1 = curMatch; + ptr1 = pair + 1; + curMatch = *ptr1; + len1 = len; + } + else + { + *ptr0 = curMatch; + ptr0 = pair; + curMatch = *ptr0; + len0 = len; + } + } + } +} + +static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue) +{ + CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; + CLzRef *ptr1 = son + (_cyclicBufferPos << 1); + UInt32 len0 = 0, len1 = 0; + for (;;) + { + UInt32 delta = pos - curMatch; + if (cutValue-- == 0 || delta >= _cyclicBufferSize) + { + *ptr0 = *ptr1 = kEmptyHashValue; + return; + } + { + CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); + const Byte *pb = cur - delta; + UInt32 len = (len0 < len1 ? len0 : len1); + if (pb[len] == cur[len]) + { + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + { + if (len == lenLimit) + { + *ptr1 = pair[0]; + *ptr0 = pair[1]; + return; + } + } + } + if (pb[len] < cur[len]) + { + *ptr1 = curMatch; + ptr1 = pair + 1; + curMatch = *ptr1; + len1 = len; + } + else + { + *ptr0 = curMatch; + ptr0 = pair; + curMatch = *ptr0; + len0 = len; + } + } + } +} + +#define MOVE_POS \ + ++p->cyclicBufferPos; \ + p->buffer++; \ + if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p); + +#define MOVE_POS_RET MOVE_POS return offset; + +static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } + +#define GET_MATCHES_HEADER2(minLen, ret_op) \ + UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \ + lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ + cur = p->buffer; + +#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0) +#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue) + +#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue + +#define GET_MATCHES_FOOTER(offset, maxLen) \ + offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \ + distances + offset, maxLen) - distances); MOVE_POS_RET; + +#define SKIP_FOOTER \ + SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; + +static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 offset; + GET_MATCHES_HEADER(2) + HASH2_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + offset = 0; + GET_MATCHES_FOOTER(offset, 1) +} + +UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 offset; + GET_MATCHES_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + offset = 0; + GET_MATCHES_FOOTER(offset, 2) +} + +static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 hash2Value, delta2, maxLen, offset; + GET_MATCHES_HEADER(3) + + HASH3_CALC; + + delta2 = p->pos - p->hash[hash2Value]; + curMatch = p->hash[kFix3HashSize + hashValue]; + + p->hash[hash2Value] = + p->hash[kFix3HashSize + hashValue] = p->pos; + + + maxLen = 2; + offset = 0; + if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) + { + for (; maxLen != lenLimit; maxLen++) + if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) + break; + distances[0] = maxLen; + distances[1] = delta2 - 1; + offset = 2; + if (maxLen == lenLimit) + { + SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); + MOVE_POS_RET; + } + } + GET_MATCHES_FOOTER(offset, maxLen) +} + +static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; + GET_MATCHES_HEADER(4) + + HASH4_CALC; + + delta2 = p->pos - p->hash[ hash2Value]; + delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; + curMatch = p->hash[kFix4HashSize + hashValue]; + + p->hash[ hash2Value] = + p->hash[kFix3HashSize + hash3Value] = + p->hash[kFix4HashSize + hashValue] = p->pos; + + maxLen = 1; + offset = 0; + if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) + { + distances[0] = maxLen = 2; + distances[1] = delta2 - 1; + offset = 2; + } + if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) + { + maxLen = 3; + distances[offset + 1] = delta3 - 1; + offset += 2; + delta2 = delta3; + } + if (offset != 0) + { + for (; maxLen != lenLimit; maxLen++) + if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) + break; + distances[offset - 2] = maxLen; + if (maxLen == lenLimit) + { + SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); + MOVE_POS_RET; + } + } + if (maxLen < 3) + maxLen = 3; + GET_MATCHES_FOOTER(offset, maxLen) +} + +static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; + GET_MATCHES_HEADER(4) + + HASH4_CALC; + + delta2 = p->pos - p->hash[ hash2Value]; + delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; + curMatch = p->hash[kFix4HashSize + hashValue]; + + p->hash[ hash2Value] = + p->hash[kFix3HashSize + hash3Value] = + p->hash[kFix4HashSize + hashValue] = p->pos; + + maxLen = 1; + offset = 0; + if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) + { + distances[0] = maxLen = 2; + distances[1] = delta2 - 1; + offset = 2; + } + if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) + { + maxLen = 3; + distances[offset + 1] = delta3 - 1; + offset += 2; + delta2 = delta3; + } + if (offset != 0) + { + for (; maxLen != lenLimit; maxLen++) + if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) + break; + distances[offset - 2] = maxLen; + if (maxLen == lenLimit) + { + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS_RET; + } + } + if (maxLen < 3) + maxLen = 3; + offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), + distances + offset, maxLen) - (distances)); + MOVE_POS_RET +} + +UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 offset; + GET_MATCHES_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), + distances, 2) - (distances)); + MOVE_POS_RET +} + +static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + SKIP_HEADER(2) + HASH2_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + SKIP_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 hash2Value; + SKIP_HEADER(3) + HASH3_CALC; + curMatch = p->hash[kFix3HashSize + hashValue]; + p->hash[hash2Value] = + p->hash[kFix3HashSize + hashValue] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 hash2Value, hash3Value; + SKIP_HEADER(4) + HASH4_CALC; + curMatch = p->hash[kFix4HashSize + hashValue]; + p->hash[ hash2Value] = + p->hash[kFix3HashSize + hash3Value] = p->pos; + p->hash[kFix4HashSize + hashValue] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 hash2Value, hash3Value; + SKIP_HEADER(4) + HASH4_CALC; + curMatch = p->hash[kFix4HashSize + hashValue]; + p->hash[ hash2Value] = + p->hash[kFix3HashSize + hash3Value] = + p->hash[kFix4HashSize + hashValue] = p->pos; + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS + } + while (--num != 0); +} + +void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + SKIP_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS + } + while (--num != 0); +} + +void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) +{ + vTable->Init = (Mf_Init_Func)MatchFinder_Init; + vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte; + vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; + vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; + if (!p->btMode) + { + vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; + } + else if (p->numHashBytes == 2) + { + vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip; + } + else if (p->numHashBytes == 3) + { + vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; + } + else + { + vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; + } +} diff --git a/src/external/OpenCTM-1.0.3/lib/liblzma/LzFind.h b/src/external/OpenCTM-1.0.3/lib/liblzma/LzFind.h new file mode 100644 index 000000000..5b9cebfdf --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/liblzma/LzFind.h @@ -0,0 +1,107 @@ +/* LzFind.h -- Match finder for LZ algorithms +2008-10-04 : Igor Pavlov : Public domain */ + +#ifndef __LZFIND_H +#define __LZFIND_H + +#include "Types.h" + +typedef UInt32 CLzRef; + +typedef struct _CMatchFinder +{ + Byte *buffer; + UInt32 pos; + UInt32 posLimit; + UInt32 streamPos; + UInt32 lenLimit; + + UInt32 cyclicBufferPos; + UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ + + UInt32 matchMaxLen; + CLzRef *hash; + CLzRef *son; + UInt32 hashMask; + UInt32 cutValue; + + Byte *bufferBase; + ISeqInStream *stream; + int streamEndWasReached; + + UInt32 blockSize; + UInt32 keepSizeBefore; + UInt32 keepSizeAfter; + + UInt32 numHashBytes; + int directInput; + int btMode; + /* int skipModeBits; */ + int bigHash; + UInt32 historySize; + UInt32 fixedHashSize; + UInt32 hashSizeSum; + UInt32 numSons; + SRes result; + UInt32 crc[256]; +} CMatchFinder; + +#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer) +#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)]) + +#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) + +int MatchFinder_NeedMove(CMatchFinder *p); +Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); +void MatchFinder_MoveBlock(CMatchFinder *p); +void MatchFinder_ReadIfRequired(CMatchFinder *p); + +void MatchFinder_Construct(CMatchFinder *p); + +/* Conditions: + historySize <= 3 GB + keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB +*/ +int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, + UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, + ISzAlloc *alloc); +void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc); +void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems); +void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); + +UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, + UInt32 *distances, UInt32 maxLen); + +/* +Conditions: + Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func. + Mf_GetPointerToCurrentPos_Func's result must be used only before any other function +*/ + +typedef void (*Mf_Init_Func)(void *object); +typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index); +typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object); +typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object); +typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances); +typedef void (*Mf_Skip_Func)(void *object, UInt32); + +typedef struct _IMatchFinder +{ + Mf_Init_Func Init; + Mf_GetIndexByte_Func GetIndexByte; + Mf_GetNumAvailableBytes_Func GetNumAvailableBytes; + Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos; + Mf_GetMatches_Func GetMatches; + Mf_Skip_Func Skip; +} IMatchFinder; + +void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); + +void MatchFinder_Init(CMatchFinder *p); +UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); +UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); +void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); +void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); + +#endif diff --git a/src/external/OpenCTM-1.0.3/lib/liblzma/LzHash.h b/src/external/OpenCTM-1.0.3/lib/liblzma/LzHash.h new file mode 100644 index 000000000..9f4173e7e --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/liblzma/LzHash.h @@ -0,0 +1,54 @@ +/* LzHash.h -- HASH functions for LZ algorithms +2008-10-04 : Igor Pavlov : Public domain */ + +#ifndef __LZHASH_H +#define __LZHASH_H + +#define kHash2Size (1 << 10) +#define kHash3Size (1 << 16) +#define kHash4Size (1 << 20) + +#define kFix3HashSize (kHash2Size) +#define kFix4HashSize (kHash2Size + kHash3Size) +#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) + +#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8); + +#define HASH3_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + hash2Value = temp & (kHash2Size - 1); \ + hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } + +#define HASH4_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + hash2Value = temp & (kHash2Size - 1); \ + hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ + hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; } + +#define HASH5_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + hash2Value = temp & (kHash2Size - 1); \ + hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ + hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \ + hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \ + hash4Value &= (kHash4Size - 1); } + +/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ +#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; + + +#define MT_HASH2_CALC \ + hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); + +#define MT_HASH3_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + hash2Value = temp & (kHash2Size - 1); \ + hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } + +#define MT_HASH4_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + hash2Value = temp & (kHash2Size - 1); \ + hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ + hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } + +#endif diff --git a/src/external/OpenCTM-1.0.3/lib/liblzma/LzmaDec.c b/src/external/OpenCTM-1.0.3/lib/liblzma/LzmaDec.c new file mode 100644 index 000000000..d87eb1914 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/liblzma/LzmaDec.c @@ -0,0 +1,1007 @@ +/* LzmaDec.c -- LZMA Decoder +2008-11-06 : Igor Pavlov : Public domain */ + +#include "LzmaDec.h" + +#include + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +#define RC_INIT_SIZE 5 + +#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) +#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); +#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); +#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ + { UPDATE_0(p); i = (i + i); A0; } else \ + { UPDATE_1(p); i = (i + i) + 1; A1; } +#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) + +#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); } +#define TREE_DECODE(probs, limit, i) \ + { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } + +/* #define _LZMA_SIZE_OPT */ + +#ifdef _LZMA_SIZE_OPT +#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) +#else +#define TREE_6_DECODE(probs, i) \ + { i = 1; \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + i -= 0x40; } +#endif + +#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) +#define UPDATE_0_CHECK range = bound; +#define UPDATE_1_CHECK range -= bound; code -= bound; +#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ + { UPDATE_0_CHECK; i = (i + i); A0; } else \ + { UPDATE_1_CHECK; i = (i + i) + 1; A1; } +#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) +#define TREE_DECODE_CHECK(probs, limit, i) \ + { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } + + +#define kNumPosBitsMax 4 +#define kNumPosStatesMax (1 << kNumPosBitsMax) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumMidBits 3 +#define kLenNumMidSymbols (1 << kLenNumMidBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define LenChoice 0 +#define LenChoice2 (LenChoice + 1) +#define LenLow (LenChoice2 + 1) +#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) +#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) +#define kNumLenProbs (LenHigh + kLenNumHighSymbols) + + +#define kNumStates 12 +#define kNumLitStates 7 + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#define kNumPosSlotBits 6 +#define kNumLenToPosStates 4 + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) + +#define kMatchMinLen 2 +#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) + +#define IsMatch 0 +#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) +#define IsRepG0 (IsRep + kNumStates) +#define IsRepG1 (IsRepG0 + kNumStates) +#define IsRepG2 (IsRepG1 + kNumStates) +#define IsRep0Long (IsRepG2 + kNumStates) +#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) +#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) +#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) +#define LenCoder (Align + kAlignTableSize) +#define RepLenCoder (LenCoder + kNumLenProbs) +#define Literal (RepLenCoder + kNumLenProbs) + +#define LZMA_BASE_SIZE 1846 +#define LZMA_LIT_SIZE 768 + +#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) + +#if Literal != LZMA_BASE_SIZE +StopCompilingDueBUG +#endif + +static const Byte kLiteralNextStates[kNumStates * 2] = +{ + 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5, + 7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10 +}; + +#define LZMA_DIC_MIN (1 << 12) + +/* First LZMA-symbol is always decoded. +And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization +Out: + Result: + SZ_OK - OK + SZ_ERROR_DATA - Error + p->remainLen: + < kMatchSpecLenStart : normal remain + = kMatchSpecLenStart : finished + = kMatchSpecLenStart + 1 : Flush marker + = kMatchSpecLenStart + 2 : State Init Marker +*/ + +static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + CLzmaProb *probs = p->probs; + + unsigned state = p->state; + UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; + unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; + unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; + unsigned lc = p->prop.lc; + + Byte *dic = p->dic; + SizeT dicBufSize = p->dicBufSize; + SizeT dicPos = p->dicPos; + + UInt32 processedPos = p->processedPos; + UInt32 checkDicSize = p->checkDicSize; + unsigned len = 0; + + const Byte *buf = p->buf; + UInt32 range = p->range; + UInt32 code = p->code; + + do + { + CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = processedPos & pbMask; + + prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; + IF_BIT_0(prob) + { + unsigned symbol; + UPDATE_0(prob); + prob = probs + Literal; + if (checkDicSize != 0 || processedPos != 0) + prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + + (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); + + if (state < kNumLitStates) + { + symbol = 1; + do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100); + } + else + { + unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + unsigned offs = 0x100; + symbol = 1; + do + { + unsigned bit; + CLzmaProb *probLit; + matchByte <<= 1; + bit = (matchByte & offs); + probLit = prob + offs + bit + symbol; + GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) + } + while (symbol < 0x100); + } + dic[dicPos++] = (Byte)symbol; + processedPos++; + + state = kLiteralNextStates[state]; + /* if (state < 4) state = 0; else if (state < 10) state -= 3; else state -= 6; */ + continue; + } + else + { + UPDATE_1(prob); + prob = probs + IsRep + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + state += kNumStates; + prob = probs + LenCoder; + } + else + { + UPDATE_1(prob); + if (checkDicSize == 0 && processedPos == 0) + return SZ_ERROR_DATA; + prob = probs + IsRepG0 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; + IF_BIT_0(prob) + { + UPDATE_0(prob); + dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dicPos++; + processedPos++; + state = state < kNumLitStates ? 9 : 11; + continue; + } + UPDATE_1(prob); + } + else + { + UInt32 distance; + UPDATE_1(prob); + prob = probs + IsRepG1 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep1; + } + else + { + UPDATE_1(prob); + prob = probs + IsRepG2 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep2; + } + else + { + UPDATE_1(prob); + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + state = state < kNumLitStates ? 8 : 11; + prob = probs + RepLenCoder; + } + { + unsigned limit, offset; + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + limit = (1 << kLenNumLowBits); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenChoice2; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + limit = (1 << kLenNumMidBits); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + limit = (1 << kLenNumHighBits); + } + } + TREE_DECODE(probLen, limit, len); + len += offset; + } + + if (state >= kNumStates) + { + UInt32 distance; + prob = probs + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); + TREE_6_DECODE(prob, distance); + if (distance >= kStartPosModelIndex) + { + unsigned posSlot = (unsigned)distance; + int numDirectBits = (int)(((distance >> 1) - 1)); + distance = (2 | (distance & 1)); + if (posSlot < kEndPosModelIndex) + { + distance <<= numDirectBits; + prob = probs + SpecPos + distance - posSlot - 1; + { + UInt32 mask = 1; + unsigned i = 1; + do + { + GET_BIT2(prob + i, i, ; , distance |= mask); + mask <<= 1; + } + while (--numDirectBits != 0); + } + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE + range >>= 1; + + { + UInt32 t; + code -= range; + t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ + distance = (distance << 1) + (t + 1); + code += range & t; + } + /* + distance <<= 1; + if (code >= range) + { + code -= range; + distance |= 1; + } + */ + } + while (--numDirectBits != 0); + prob = probs + Align; + distance <<= kNumAlignBits; + { + unsigned i = 1; + GET_BIT2(prob + i, i, ; , distance |= 1); + GET_BIT2(prob + i, i, ; , distance |= 2); + GET_BIT2(prob + i, i, ; , distance |= 4); + GET_BIT2(prob + i, i, ; , distance |= 8); + } + if (distance == (UInt32)0xFFFFFFFF) + { + len += kMatchSpecLenStart; + state -= kNumStates; + break; + } + } + } + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + rep0 = distance + 1; + if (checkDicSize == 0) + { + if (distance >= processedPos) + return SZ_ERROR_DATA; + } + else if (distance >= checkDicSize) + return SZ_ERROR_DATA; + state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; + /* state = kLiteralNextStates[state]; */ + } + + len += kMatchMinLen; + + if (limit == dicPos) + return SZ_ERROR_DATA; + { + SizeT rem = limit - dicPos; + unsigned curLen = ((rem < len) ? (unsigned)rem : len); + SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); + + processedPos += curLen; + + len -= curLen; + if (pos + curLen <= dicBufSize) + { + Byte *dest = dic + dicPos; + ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; + const Byte *lim = dest + curLen; + dicPos += curLen; + do + *(dest) = (Byte)*(dest + src); + while (++dest != lim); + } + else + { + do + { + dic[dicPos++] = dic[pos]; + if (++pos == dicBufSize) + pos = 0; + } + while (--curLen != 0); + } + } + } + } + while (dicPos < limit && buf < bufLimit); + NORMALIZE; + p->buf = buf; + p->range = range; + p->code = code; + p->remainLen = len; + p->dicPos = dicPos; + p->processedPos = processedPos; + p->reps[0] = rep0; + p->reps[1] = rep1; + p->reps[2] = rep2; + p->reps[3] = rep3; + p->state = state; + + return SZ_OK; +} + +static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) +{ + if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) + { + Byte *dic = p->dic; + SizeT dicPos = p->dicPos; + SizeT dicBufSize = p->dicBufSize; + unsigned len = p->remainLen; + UInt32 rep0 = p->reps[0]; + if (limit - dicPos < len) + len = (unsigned)(limit - dicPos); + + if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) + p->checkDicSize = p->prop.dicSize; + + p->processedPos += len; + p->remainLen -= len; + while (len-- != 0) + { + dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dicPos++; + } + p->dicPos = dicPos; + } +} + +static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + do + { + SizeT limit2 = limit; + if (p->checkDicSize == 0) + { + UInt32 rem = p->prop.dicSize - p->processedPos; + if (limit - p->dicPos > rem) + limit2 = p->dicPos + rem; + } + RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); + if (p->processedPos >= p->prop.dicSize) + p->checkDicSize = p->prop.dicSize; + LzmaDec_WriteRem(p, limit); + } + while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); + + if (p->remainLen > kMatchSpecLenStart) + { + p->remainLen = kMatchSpecLenStart; + } + return 0; +} + +typedef enum +{ + DUMMY_ERROR, /* unexpected end of input stream */ + DUMMY_LIT, + DUMMY_MATCH, + DUMMY_REP +} ELzmaDummy; + +static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) +{ + UInt32 range = p->range; + UInt32 code = p->code; + const Byte *bufLimit = buf + inSize; + CLzmaProb *probs = p->probs; + unsigned state = p->state; + ELzmaDummy res; + + { + CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); + + prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK + + /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ + + prob = probs + Literal; + if (p->checkDicSize != 0 || p->processedPos != 0) + prob += (LZMA_LIT_SIZE * + ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + + (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); + + if (state < kNumLitStates) + { + unsigned symbol = 1; + do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); + } + else + { + unsigned matchByte = p->dic[p->dicPos - p->reps[0] + + ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; + unsigned offs = 0x100; + unsigned symbol = 1; + do + { + unsigned bit; + CLzmaProb *probLit; + matchByte <<= 1; + bit = (matchByte & offs); + probLit = prob + offs + bit + symbol; + GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) + } + while (symbol < 0x100); + } + res = DUMMY_LIT; + } + else + { + unsigned len; + UPDATE_1_CHECK; + + prob = probs + IsRep + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + state = 0; + prob = probs + LenCoder; + res = DUMMY_MATCH; + } + else + { + UPDATE_1_CHECK; + res = DUMMY_REP; + prob = probs + IsRepG0 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + NORMALIZE_CHECK; + return DUMMY_REP; + } + else + { + UPDATE_1_CHECK; + } + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG1 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG2 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + } + } + } + state = kNumStates; + prob = probs + RepLenCoder; + } + { + unsigned limit, offset; + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + limit = 1 << kLenNumLowBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenChoice2; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + limit = 1 << kLenNumMidBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + limit = 1 << kLenNumHighBits; + } + } + TREE_DECODE_CHECK(probLen, limit, len); + len += offset; + } + + if (state < 4) + { + unsigned posSlot; + prob = probs + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << + kNumPosSlotBits); + TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); + if (posSlot >= kStartPosModelIndex) + { + int numDirectBits = ((posSlot >> 1) - 1); + + /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ + + if (posSlot < kEndPosModelIndex) + { + prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE_CHECK + range >>= 1; + code -= range & (((code - range) >> 31) - 1); + /* if (code >= range) code -= range; */ + } + while (--numDirectBits != 0); + prob = probs + Align; + numDirectBits = kNumAlignBits; + } + { + unsigned i = 1; + do + { + GET_BIT_CHECK(prob + i, i); + } + while (--numDirectBits != 0); + } + } + } + } + } + NORMALIZE_CHECK; + return res; +} + + +static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) +{ + p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); + p->range = 0xFFFFFFFF; + p->needFlush = 0; +} + +void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) +{ + p->needFlush = 1; + p->remainLen = 0; + p->tempBufSize = 0; + + if (initDic) + { + p->processedPos = 0; + p->checkDicSize = 0; + p->needInitState = 1; + } + if (initState) + p->needInitState = 1; +} + +void LzmaDec_Init(CLzmaDec *p) +{ + p->dicPos = 0; + LzmaDec_InitDicAndState(p, True, True); +} + +static void LzmaDec_InitStateReal(CLzmaDec *p) +{ + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); + UInt32 i; + CLzmaProb *probs = p->probs; + for (i = 0; i < numProbs; i++) + probs[i] = kBitModelTotal >> 1; + p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; + p->state = 0; + p->needInitState = 0; +} + +SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, + ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT inSize = *srcLen; + (*srcLen) = 0; + LzmaDec_WriteRem(p, dicLimit); + + *status = LZMA_STATUS_NOT_SPECIFIED; + + while (p->remainLen != kMatchSpecLenStart) + { + int checkEndMarkNow; + + if (p->needFlush != 0) + { + for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) + p->tempBuf[p->tempBufSize++] = *src++; + if (p->tempBufSize < RC_INIT_SIZE) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (p->tempBuf[0] != 0) + return SZ_ERROR_DATA; + + LzmaDec_InitRc(p, p->tempBuf); + p->tempBufSize = 0; + } + + checkEndMarkNow = 0; + if (p->dicPos >= dicLimit) + { + if (p->remainLen == 0 && p->code == 0) + { + *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; + return SZ_OK; + } + if (finishMode == LZMA_FINISH_ANY) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_OK; + } + if (p->remainLen != 0) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + checkEndMarkNow = 1; + } + + if (p->needInitState) + LzmaDec_InitStateReal(p); + + if (p->tempBufSize == 0) + { + SizeT processed; + const Byte *bufLimit; + if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, src, inSize); + if (dummyRes == DUMMY_ERROR) + { + memcpy(p->tempBuf, src, inSize); + p->tempBufSize = (unsigned)inSize; + (*srcLen) += inSize; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + bufLimit = src; + } + else + bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; + p->buf = src; + if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) + return SZ_ERROR_DATA; + processed = (SizeT)(p->buf - src); + (*srcLen) += processed; + src += processed; + inSize -= processed; + } + else + { + unsigned rem = p->tempBufSize, lookAhead = 0; + while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) + p->tempBuf[rem++] = src[lookAhead++]; + p->tempBufSize = rem; + if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); + if (dummyRes == DUMMY_ERROR) + { + (*srcLen) += lookAhead; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + } + p->buf = p->tempBuf; + if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) + return SZ_ERROR_DATA; + lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); + (*srcLen) += lookAhead; + src += lookAhead; + inSize -= lookAhead; + p->tempBufSize = 0; + } + } + if (p->code == 0) + *status = LZMA_STATUS_FINISHED_WITH_MARK; + return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; +} + +SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT outSize = *destLen; + SizeT inSize = *srcLen; + *srcLen = *destLen = 0; + for (;;) + { + SizeT inSizeCur = inSize, outSizeCur, dicPos; + ELzmaFinishMode curFinishMode; + SRes res; + if (p->dicPos == p->dicBufSize) + p->dicPos = 0; + dicPos = p->dicPos; + if (outSize > p->dicBufSize - dicPos) + { + outSizeCur = p->dicBufSize; + curFinishMode = LZMA_FINISH_ANY; + } + else + { + outSizeCur = dicPos + outSize; + curFinishMode = finishMode; + } + + res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); + src += inSizeCur; + inSize -= inSizeCur; + *srcLen += inSizeCur; + outSizeCur = p->dicPos - dicPos; + memcpy(dest, p->dic + dicPos, outSizeCur); + dest += outSizeCur; + outSize -= outSizeCur; + *destLen += outSizeCur; + if (res != 0) + return res; + if (outSizeCur == 0 || outSize == 0) + return SZ_OK; + } +} + +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->probs); + p->probs = 0; +} + +static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->dic); + p->dic = 0; +} + +void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) +{ + LzmaDec_FreeProbs(p, alloc); + LzmaDec_FreeDict(p, alloc); +} + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) +{ + UInt32 dicSize; + Byte d; + + if (size < LZMA_PROPS_SIZE) + return SZ_ERROR_UNSUPPORTED; + else + dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); + + if (dicSize < LZMA_DIC_MIN) + dicSize = LZMA_DIC_MIN; + p->dicSize = dicSize; + + d = data[0]; + if (d >= (9 * 5 * 5)) + return SZ_ERROR_UNSUPPORTED; + + p->lc = d % 9; + d /= 9; + p->pb = d / 5; + p->lp = d % 5; + + return SZ_OK; +} + +static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) +{ + UInt32 numProbs = LzmaProps_GetNumProbs(propNew); + if (p->probs == 0 || numProbs != p->numProbs) + { + LzmaDec_FreeProbs(p, alloc); + p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); + p->numProbs = numProbs; + if (p->probs == 0) + return SZ_ERROR_MEM; + } + return SZ_OK; +} + +SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +{ + CLzmaProps propNew; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +{ + CLzmaProps propNew; + SizeT dicBufSize; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + dicBufSize = propNew.dicSize; + if (p->dic == 0 || dicBufSize != p->dicBufSize) + { + LzmaDec_FreeDict(p, alloc); + p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); + if (p->dic == 0) + { + LzmaDec_FreeProbs(p, alloc); + return SZ_ERROR_MEM; + } + } + p->dicBufSize = dicBufSize; + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAlloc *alloc) +{ + CLzmaDec p; + SRes res; + SizeT inSize = *srcLen; + SizeT outSize = *destLen; + *srcLen = *destLen = 0; + if (inSize < RC_INIT_SIZE) + return SZ_ERROR_INPUT_EOF; + + LzmaDec_Construct(&p); + res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc); + if (res != 0) + return res; + p.dic = dest; + p.dicBufSize = outSize; + + LzmaDec_Init(&p); + + *srcLen = inSize; + res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); + + if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) + res = SZ_ERROR_INPUT_EOF; + + (*destLen) = p.dicPos; + LzmaDec_FreeProbs(&p, alloc); + return res; +} diff --git a/src/external/OpenCTM-1.0.3/lib/liblzma/LzmaDec.h b/src/external/OpenCTM-1.0.3/lib/liblzma/LzmaDec.h new file mode 100644 index 000000000..98cdbe949 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/liblzma/LzmaDec.h @@ -0,0 +1,223 @@ +/* LzmaDec.h -- LZMA Decoder +2008-10-04 : Igor Pavlov : Public domain */ + +#ifndef __LZMADEC_H +#define __LZMADEC_H + +#include "Types.h" + +/* #define _LZMA_PROB32 */ +/* _LZMA_PROB32 can increase the speed on some CPUs, + but memory usage for CLzmaDec::probs will be doubled in that case */ + +#ifdef _LZMA_PROB32 +#define CLzmaProb UInt32 +#else +#define CLzmaProb UInt16 +#endif + + +/* ---------- LZMA Properties ---------- */ + +#define LZMA_PROPS_SIZE 5 + +typedef struct _CLzmaProps +{ + unsigned lc, lp, pb; + UInt32 dicSize; +} CLzmaProps; + +/* LzmaProps_Decode - decodes properties +Returns: + SZ_OK + SZ_ERROR_UNSUPPORTED - Unsupported properties +*/ + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); + + +/* ---------- LZMA Decoder state ---------- */ + +/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. + Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ + +#define LZMA_REQUIRED_INPUT_MAX 20 + +typedef struct +{ + CLzmaProps prop; + CLzmaProb *probs; + Byte *dic; + const Byte *buf; + UInt32 range, code; + SizeT dicPos; + SizeT dicBufSize; + UInt32 processedPos; + UInt32 checkDicSize; + unsigned state; + UInt32 reps[4]; + unsigned remainLen; + int needFlush; + int needInitState; + UInt32 numProbs; + unsigned tempBufSize; + Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; +} CLzmaDec; + +#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } + +void LzmaDec_Init(CLzmaDec *p); + +/* There are two types of LZMA streams: + 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. + 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ + +typedef enum +{ + LZMA_FINISH_ANY, /* finish at any point */ + LZMA_FINISH_END /* block must be finished at the end */ +} ELzmaFinishMode; + +/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! + + You must use LZMA_FINISH_END, when you know that current output buffer + covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. + + If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, + and output value of destLen will be less than output buffer size limit. + You can check status result also. + + You can use multiple checks to test data integrity after full decompression: + 1) Check Result and "status" variable. + 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. + 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. + You must use correct finish mode in that case. */ + +typedef enum +{ + LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ + LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ + LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ + LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ +} ELzmaStatus; + +/* ELzmaStatus is used only as output value for function call */ + + +/* ---------- Interfaces ---------- */ + +/* There are 3 levels of interfaces: + 1) Dictionary Interface + 2) Buffer Interface + 3) One Call Interface + You can select any of these interfaces, but don't mix functions from different + groups for same object. */ + + +/* There are two variants to allocate state for Dictionary Interface: + 1) LzmaDec_Allocate / LzmaDec_Free + 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs + You can use variant 2, if you set dictionary buffer manually. + For Buffer Interface you must always use variant 1. + +LzmaDec_Allocate* can return: + SZ_OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties +*/ + +SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); + +SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); +void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); + +/* ---------- Dictionary Interface ---------- */ + +/* You can use it, if you want to eliminate the overhead for data copying from + dictionary to some other external buffer. + You must work with CLzmaDec variables directly in this interface. + + STEPS: + LzmaDec_Constr() + LzmaDec_Allocate() + for (each new stream) + { + LzmaDec_Init() + while (it needs more decompression) + { + LzmaDec_DecodeToDic() + use data from CLzmaDec::dic and update CLzmaDec::dicPos + } + } + LzmaDec_Free() +*/ + +/* LzmaDec_DecodeToDic + + The decoding to internal dictionary buffer (CLzmaDec::dic). + You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! + +finishMode: + It has meaning only if the decoding reaches output limit (dicLimit). + LZMA_FINISH_ANY - Decode just dicLimit bytes. + LZMA_FINISH_END - Stream must be finished after dicLimit. + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_NEEDS_MORE_INPUT + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error +*/ + +SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- Buffer Interface ---------- */ + +/* It's zlib-like interface. + See LzmaDec_DecodeToDic description for information about STEPS and return results, + but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need + to work with CLzmaDec variables manually. + +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). +*/ + +SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- One Call Interface ---------- */ + +/* LzmaDecode + +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). +*/ + +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAlloc *alloc); + +#endif diff --git a/src/external/OpenCTM-1.0.3/lib/liblzma/LzmaEnc.c b/src/external/OpenCTM-1.0.3/lib/liblzma/LzmaEnc.c new file mode 100644 index 000000000..492b78510 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/liblzma/LzmaEnc.c @@ -0,0 +1,2281 @@ +/* LzmaEnc.c -- LZMA Encoder +2009-02-02 : Igor Pavlov : Public domain */ + +#include + +/* #define SHOW_STAT */ +/* #define SHOW_STAT2 */ + +#if defined(SHOW_STAT) || defined(SHOW_STAT2) +#include +#endif + +#include "LzmaEnc.h" + +#include "LzFind.h" +#ifdef COMPRESS_MF_MT +#include "LzFindMt.h" +#endif + +#ifdef SHOW_STAT +static int ttt = 0; +#endif + +#define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1) + +#define kBlockSize (9 << 10) +#define kUnpackBlockSize (1 << 18) +#define kMatchArraySize (1 << 21) +#define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX) + +#define kNumMaxDirectBits (31) + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 +#define kProbInitValue (kBitModelTotal >> 1) + +#define kNumMoveReducingBits 4 +#define kNumBitPriceShiftBits 4 +#define kBitPrice (1 << kNumBitPriceShiftBits) + +void LzmaEncProps_Init(CLzmaEncProps *p) +{ + p->level = 5; + p->dictSize = p->mc = 0; + p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1; + p->writeEndMark = 0; +} + +void LzmaEncProps_Normalize(CLzmaEncProps *p) +{ + int level = p->level; + if (level < 0) level = 5; + p->level = level; + if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26))); + if (p->lc < 0) p->lc = 3; + if (p->lp < 0) p->lp = 0; + if (p->pb < 0) p->pb = 2; + if (p->algo < 0) p->algo = (level < 5 ? 0 : 1); + if (p->fb < 0) p->fb = (level < 7 ? 32 : 64); + if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); + if (p->numHashBytes < 0) p->numHashBytes = 4; + if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1); + if (p->numThreads < 0) + p->numThreads = + #ifdef COMPRESS_MF_MT + ((p->btMode && p->algo) ? 2 : 1); + #else + 1; + #endif +} + +UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) +{ + CLzmaEncProps props = *props2; + LzmaEncProps_Normalize(&props); + return props.dictSize; +} + +/* #define LZMA_LOG_BSR */ +/* Define it for Intel's CPU */ + + +#ifdef LZMA_LOG_BSR + +#define kDicLogSizeMaxCompress 30 + +#define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); } + +static UInt32 GetPosSlot1(UInt32 pos) +{ + UInt32 res; + BSR2_RET(pos, res); + return res; +} +#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } +#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); } + +#else + +#define kNumLogBits (9 + (int)sizeof(size_t) / 2) +#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) + +void LzmaEnc_FastPosInit(Byte *g_FastPos) +{ + int c = 2, slotFast; + g_FastPos[0] = 0; + g_FastPos[1] = 1; + + for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++) + { + UInt32 k = (1 << ((slotFast >> 1) - 1)); + UInt32 j; + for (j = 0; j < k; j++, c++) + g_FastPos[c] = (Byte)slotFast; + } +} + +#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \ + (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \ + res = p->g_FastPos[pos >> i] + (i * 2); } +/* +#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \ + p->g_FastPos[pos >> 6] + 12 : \ + p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; } +*/ + +#define GetPosSlot1(pos) p->g_FastPos[pos] +#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } +#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); } + +#endif + + +#define LZMA_NUM_REPS 4 + +typedef unsigned CState; + +typedef struct _COptimal +{ + UInt32 price; + + CState state; + int prev1IsChar; + int prev2; + + UInt32 posPrev2; + UInt32 backPrev2; + + UInt32 posPrev; + UInt32 backPrev; + UInt32 backs[LZMA_NUM_REPS]; +} COptimal; + +#define kNumOpts (1 << 12) + +#define kNumLenToPosStates 4 +#define kNumPosSlotBits 6 +#define kDicLogSizeMin 0 +#define kDicLogSizeMax 32 +#define kDistTableSizeMax (kDicLogSizeMax * 2) + + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) +#define kAlignMask (kAlignTableSize - 1) + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex) + +#define kNumFullDistances (1 << (kEndPosModelIndex / 2)) + +#ifdef _LZMA_PROB32 +#define CLzmaProb UInt32 +#else +#define CLzmaProb UInt16 +#endif + +#define LZMA_PB_MAX 4 +#define LZMA_LC_MAX 8 +#define LZMA_LP_MAX 4 + +#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX) + + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumMidBits 3 +#define kLenNumMidSymbols (1 << kLenNumMidBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) + +#define LZMA_MATCH_LEN_MIN 2 +#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1) + +#define kNumStates 12 + +typedef struct +{ + CLzmaProb choice; + CLzmaProb choice2; + CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits]; + CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits]; + CLzmaProb high[kLenNumHighSymbols]; +} CLenEnc; + +typedef struct +{ + CLenEnc p; + UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; + UInt32 tableSize; + UInt32 counters[LZMA_NUM_PB_STATES_MAX]; +} CLenPriceEnc; + +typedef struct _CRangeEnc +{ + UInt32 range; + Byte cache; + UInt64 low; + UInt64 cacheSize; + Byte *buf; + Byte *bufLim; + Byte *bufBase; + ISeqOutStream *outStream; + UInt64 processed; + SRes res; +} CRangeEnc; + +typedef struct _CSeqInStreamBuf +{ + ISeqInStream funcTable; + const Byte *data; + SizeT rem; +} CSeqInStreamBuf; + +static SRes MyRead(void *pp, void *data, size_t *size) +{ + size_t curSize = *size; + CSeqInStreamBuf *p = (CSeqInStreamBuf *)pp; + if (p->rem < curSize) + curSize = p->rem; + memcpy(data, p->data, curSize); + p->rem -= curSize; + p->data += curSize; + *size = curSize; + return SZ_OK; +} + +typedef struct +{ + CLzmaProb *litProbs; + + CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; + CLzmaProb isRep[kNumStates]; + CLzmaProb isRepG0[kNumStates]; + CLzmaProb isRepG1[kNumStates]; + CLzmaProb isRepG2[kNumStates]; + CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; + + CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; + CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; + CLzmaProb posAlignEncoder[1 << kNumAlignBits]; + + CLenPriceEnc lenEnc; + CLenPriceEnc repLenEnc; + + UInt32 reps[LZMA_NUM_REPS]; + UInt32 state; +} CSaveState; + +typedef struct _CLzmaEnc +{ + IMatchFinder matchFinder; + void *matchFinderObj; + + #ifdef COMPRESS_MF_MT + Bool mtMode; + CMatchFinderMt matchFinderMt; + #endif + + CMatchFinder matchFinderBase; + + #ifdef COMPRESS_MF_MT + Byte pad[128]; + #endif + + UInt32 optimumEndIndex; + UInt32 optimumCurrentIndex; + + UInt32 longestMatchLength; + UInt32 numPairs; + UInt32 numAvail; + COptimal opt[kNumOpts]; + + #ifndef LZMA_LOG_BSR + Byte g_FastPos[1 << kNumLogBits]; + #endif + + UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; + UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1]; + UInt32 numFastBytes; + UInt32 additionalOffset; + UInt32 reps[LZMA_NUM_REPS]; + UInt32 state; + + UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax]; + UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances]; + UInt32 alignPrices[kAlignTableSize]; + UInt32 alignPriceCount; + + UInt32 distTableSize; + + unsigned lc, lp, pb; + unsigned lpMask, pbMask; + + CLzmaProb *litProbs; + + CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; + CLzmaProb isRep[kNumStates]; + CLzmaProb isRepG0[kNumStates]; + CLzmaProb isRepG1[kNumStates]; + CLzmaProb isRepG2[kNumStates]; + CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; + + CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; + CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; + CLzmaProb posAlignEncoder[1 << kNumAlignBits]; + + CLenPriceEnc lenEnc; + CLenPriceEnc repLenEnc; + + unsigned lclp; + + Bool fastMode; + + CRangeEnc rc; + + Bool writeEndMark; + UInt64 nowPos64; + UInt32 matchPriceCount; + Bool finished; + Bool multiThread; + + SRes result; + UInt32 dictSize; + UInt32 matchFinderCycles; + + ISeqInStream *inStream; + CSeqInStreamBuf seqBufInStream; + + CSaveState saveState; +} CLzmaEnc; + +void LzmaEnc_SaveState(CLzmaEncHandle pp) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + CSaveState *dest = &p->saveState; + int i; + dest->lenEnc = p->lenEnc; + dest->repLenEnc = p->repLenEnc; + dest->state = p->state; + + for (i = 0; i < kNumStates; i++) + { + memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); + memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); + } + for (i = 0; i < kNumLenToPosStates; i++) + memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); + memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); + memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); + memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); + memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); + memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); + memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); + memcpy(dest->reps, p->reps, sizeof(p->reps)); + memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb)); +} + +void LzmaEnc_RestoreState(CLzmaEncHandle pp) +{ + CLzmaEnc *dest = (CLzmaEnc *)pp; + const CSaveState *p = &dest->saveState; + int i; + dest->lenEnc = p->lenEnc; + dest->repLenEnc = p->repLenEnc; + dest->state = p->state; + + for (i = 0; i < kNumStates; i++) + { + memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); + memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); + } + for (i = 0; i < kNumLenToPosStates; i++) + memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); + memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); + memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); + memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); + memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); + memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); + memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); + memcpy(dest->reps, p->reps, sizeof(p->reps)); + memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb)); +} + +SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + CLzmaEncProps props = *props2; + LzmaEncProps_Normalize(&props); + + if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX || + props.dictSize > (1U << kDicLogSizeMaxCompress) || props.dictSize > (1U << 30)) + return SZ_ERROR_PARAM; + p->dictSize = props.dictSize; + p->matchFinderCycles = props.mc; + { + unsigned fb = props.fb; + if (fb < 5) + fb = 5; + if (fb > LZMA_MATCH_LEN_MAX) + fb = LZMA_MATCH_LEN_MAX; + p->numFastBytes = fb; + } + p->lc = props.lc; + p->lp = props.lp; + p->pb = props.pb; + p->fastMode = (props.algo == 0); + p->matchFinderBase.btMode = props.btMode; + { + UInt32 numHashBytes = 4; + if (props.btMode) + { + if (props.numHashBytes < 2) + numHashBytes = 2; + else if (props.numHashBytes < 4) + numHashBytes = props.numHashBytes; + } + p->matchFinderBase.numHashBytes = numHashBytes; + } + + p->matchFinderBase.cutValue = props.mc; + + p->writeEndMark = props.writeEndMark; + + #ifdef COMPRESS_MF_MT + /* + if (newMultiThread != _multiThread) + { + ReleaseMatchFinder(); + _multiThread = newMultiThread; + } + */ + p->multiThread = (props.numThreads > 1); + #endif + + return SZ_OK; +} + +static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; +static const int kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; +static const int kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; +static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; + +#define IsCharState(s) ((s) < 7) + +#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1) + +#define kInfinityPrice (1 << 30) + +static void RangeEnc_Construct(CRangeEnc *p) +{ + p->outStream = 0; + p->bufBase = 0; +} + +#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize) + +#define RC_BUF_SIZE (1 << 16) +static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc) +{ + if (p->bufBase == 0) + { + p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE); + if (p->bufBase == 0) + return 0; + p->bufLim = p->bufBase + RC_BUF_SIZE; + } + return 1; +} + +static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->bufBase); + p->bufBase = 0; +} + +static void RangeEnc_Init(CRangeEnc *p) +{ + /* Stream.Init(); */ + p->low = 0; + p->range = 0xFFFFFFFF; + p->cacheSize = 1; + p->cache = 0; + + p->buf = p->bufBase; + + p->processed = 0; + p->res = SZ_OK; +} + +static void RangeEnc_FlushStream(CRangeEnc *p) +{ + size_t num; + if (p->res != SZ_OK) + return; + num = p->buf - p->bufBase; + if (num != p->outStream->Write(p->outStream, p->bufBase, num)) + p->res = SZ_ERROR_WRITE; + p->processed += num; + p->buf = p->bufBase; +} + +static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p) +{ + if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0) + { + Byte temp = p->cache; + do + { + Byte *buf = p->buf; + *buf++ = (Byte)(temp + (Byte)(p->low >> 32)); + p->buf = buf; + if (buf == p->bufLim) + RangeEnc_FlushStream(p); + temp = 0xFF; + } + while (--p->cacheSize != 0); + p->cache = (Byte)((UInt32)p->low >> 24); + } + p->cacheSize++; + p->low = (UInt32)p->low << 8; +} + +static void RangeEnc_FlushData(CRangeEnc *p) +{ + int i; + for (i = 0; i < 5; i++) + RangeEnc_ShiftLow(p); +} + +static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits) +{ + do + { + p->range >>= 1; + p->low += p->range & (0 - ((value >> --numBits) & 1)); + if (p->range < kTopValue) + { + p->range <<= 8; + RangeEnc_ShiftLow(p); + } + } + while (numBits != 0); +} + +static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol) +{ + UInt32 ttt = *prob; + UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt; + if (symbol == 0) + { + p->range = newBound; + ttt += (kBitModelTotal - ttt) >> kNumMoveBits; + } + else + { + p->low += newBound; + p->range -= newBound; + ttt -= ttt >> kNumMoveBits; + } + *prob = (CLzmaProb)ttt; + if (p->range < kTopValue) + { + p->range <<= 8; + RangeEnc_ShiftLow(p); + } +} + +static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol) +{ + symbol |= 0x100; + do + { + RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1); + symbol <<= 1; + } + while (symbol < 0x10000); +} + +static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte) +{ + UInt32 offs = 0x100; + symbol |= 0x100; + do + { + matchByte <<= 1; + RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1); + symbol <<= 1; + offs &= ~(matchByte ^ symbol); + } + while (symbol < 0x10000); +} + +void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) +{ + UInt32 i; + for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits)) + { + const int kCyclesBits = kNumBitPriceShiftBits; + UInt32 w = i; + UInt32 bitCount = 0; + int j; + for (j = 0; j < kCyclesBits; j++) + { + w = w * w; + bitCount <<= 1; + while (w >= ((UInt32)1 << 16)) + { + w >>= 1; + bitCount++; + } + } + ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount); + } +} + + +#define GET_PRICE(prob, symbol) \ + p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; + +#define GET_PRICEa(prob, symbol) \ + ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; + +#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits] +#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] + +#define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits] +#define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] + +static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices) +{ + UInt32 price = 0; + symbol |= 0x100; + do + { + price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1); + symbol <<= 1; + } + while (symbol < 0x10000); + return price; +} + +static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices) +{ + UInt32 price = 0; + UInt32 offs = 0x100; + symbol |= 0x100; + do + { + matchByte <<= 1; + price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1); + symbol <<= 1; + offs &= ~(matchByte ^ symbol); + } + while (symbol < 0x10000); + return price; +} + + +static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) +{ + UInt32 m = 1; + int i; + for (i = numBitLevels; i != 0;) + { + UInt32 bit; + i--; + bit = (symbol >> i) & 1; + RangeEnc_EncodeBit(rc, probs + m, bit); + m = (m << 1) | bit; + } +} + +static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) +{ + UInt32 m = 1; + int i; + for (i = 0; i < numBitLevels; i++) + { + UInt32 bit = symbol & 1; + RangeEnc_EncodeBit(rc, probs + m, bit); + m = (m << 1) | bit; + symbol >>= 1; + } +} + +static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) +{ + UInt32 price = 0; + symbol |= (1 << numBitLevels); + while (symbol != 1) + { + price += GET_PRICEa(probs[symbol >> 1], symbol & 1); + symbol >>= 1; + } + return price; +} + +static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) +{ + UInt32 price = 0; + UInt32 m = 1; + int i; + for (i = numBitLevels; i != 0; i--) + { + UInt32 bit = symbol & 1; + symbol >>= 1; + price += GET_PRICEa(probs[m], bit); + m = (m << 1) | bit; + } + return price; +} + + +static void LenEnc_Init(CLenEnc *p) +{ + unsigned i; + p->choice = p->choice2 = kProbInitValue; + for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++) + p->low[i] = kProbInitValue; + for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++) + p->mid[i] = kProbInitValue; + for (i = 0; i < kLenNumHighSymbols; i++) + p->high[i] = kProbInitValue; +} + +static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState) +{ + if (symbol < kLenNumLowSymbols) + { + RangeEnc_EncodeBit(rc, &p->choice, 0); + RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol); + } + else + { + RangeEnc_EncodeBit(rc, &p->choice, 1); + if (symbol < kLenNumLowSymbols + kLenNumMidSymbols) + { + RangeEnc_EncodeBit(rc, &p->choice2, 0); + RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols); + } + else + { + RangeEnc_EncodeBit(rc, &p->choice2, 1); + RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols); + } + } +} + +static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices) +{ + UInt32 a0 = GET_PRICE_0a(p->choice); + UInt32 a1 = GET_PRICE_1a(p->choice); + UInt32 b0 = a1 + GET_PRICE_0a(p->choice2); + UInt32 b1 = a1 + GET_PRICE_1a(p->choice2); + UInt32 i = 0; + for (i = 0; i < kLenNumLowSymbols; i++) + { + if (i >= numSymbols) + return; + prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices); + } + for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++) + { + if (i >= numSymbols) + return; + prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices); + } + for (; i < numSymbols; i++) + prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices); +} + +static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices) +{ + LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices); + p->counters[posState] = p->tableSize; +} + +static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices) +{ + UInt32 posState; + for (posState = 0; posState < numPosStates; posState++) + LenPriceEnc_UpdateTable(p, posState, ProbPrices); +} + +static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices) +{ + LenEnc_Encode(&p->p, rc, symbol, posState); + if (updatePrice) + if (--p->counters[posState] == 0) + LenPriceEnc_UpdateTable(p, posState, ProbPrices); +} + + + + +static void MovePos(CLzmaEnc *p, UInt32 num) +{ + #ifdef SHOW_STAT + ttt += num; + printf("\n MovePos %d", num); + #endif + if (num != 0) + { + p->additionalOffset += num; + p->matchFinder.Skip(p->matchFinderObj, num); + } +} + +static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes) +{ + UInt32 lenRes = 0, numPairs; + p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); + numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches); + #ifdef SHOW_STAT + printf("\n i = %d numPairs = %d ", ttt, numPairs / 2); + ttt++; + { + UInt32 i; + for (i = 0; i < numPairs; i += 2) + printf("%2d %6d | ", p->matches[i], p->matches[i + 1]); + } + #endif + if (numPairs > 0) + { + lenRes = p->matches[numPairs - 2]; + if (lenRes == p->numFastBytes) + { + const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + UInt32 distance = p->matches[numPairs - 1] + 1; + UInt32 numAvail = p->numAvail; + if (numAvail > LZMA_MATCH_LEN_MAX) + numAvail = LZMA_MATCH_LEN_MAX; + { + const Byte *pby2 = pby - distance; + for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++); + } + } + } + p->additionalOffset++; + *numDistancePairsRes = numPairs; + return lenRes; +} + + +#define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False; +#define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False; +#define IsShortRep(p) ((p)->backPrev == 0) + +static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState) +{ + return + GET_PRICE_0(p->isRepG0[state]) + + GET_PRICE_0(p->isRep0Long[state][posState]); +} + +static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState) +{ + UInt32 price; + if (repIndex == 0) + { + price = GET_PRICE_0(p->isRepG0[state]); + price += GET_PRICE_1(p->isRep0Long[state][posState]); + } + else + { + price = GET_PRICE_1(p->isRepG0[state]); + if (repIndex == 1) + price += GET_PRICE_0(p->isRepG1[state]); + else + { + price += GET_PRICE_1(p->isRepG1[state]); + price += GET_PRICE(p->isRepG2[state], repIndex - 2); + } + } + return price; +} + +static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState) +{ + return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] + + GetPureRepPrice(p, repIndex, state, posState); +} + +static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur) +{ + UInt32 posMem = p->opt[cur].posPrev; + UInt32 backMem = p->opt[cur].backPrev; + p->optimumEndIndex = cur; + do + { + if (p->opt[cur].prev1IsChar) + { + MakeAsChar(&p->opt[posMem]) + p->opt[posMem].posPrev = posMem - 1; + if (p->opt[cur].prev2) + { + p->opt[posMem - 1].prev1IsChar = False; + p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2; + p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2; + } + } + { + UInt32 posPrev = posMem; + UInt32 backCur = backMem; + + backMem = p->opt[posPrev].backPrev; + posMem = p->opt[posPrev].posPrev; + + p->opt[posPrev].backPrev = backCur; + p->opt[posPrev].posPrev = cur; + cur = posPrev; + } + } + while (cur != 0); + *backRes = p->opt[0].backPrev; + p->optimumCurrentIndex = p->opt[0].posPrev; + return p->optimumCurrentIndex; +} + +#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300) + +static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) +{ + UInt32 numAvail, mainLen, numPairs, repMaxIndex, i, posState, lenEnd, len, cur; + UInt32 matchPrice, repMatchPrice, normalMatchPrice; + UInt32 reps[LZMA_NUM_REPS], repLens[LZMA_NUM_REPS]; + UInt32 *matches; + const Byte *data; + Byte curByte, matchByte; + if (p->optimumEndIndex != p->optimumCurrentIndex) + { + const COptimal *opt = &p->opt[p->optimumCurrentIndex]; + UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex; + *backRes = opt->backPrev; + p->optimumCurrentIndex = opt->posPrev; + return lenRes; + } + p->optimumCurrentIndex = p->optimumEndIndex = 0; + + if (p->additionalOffset == 0) + mainLen = ReadMatchDistances(p, &numPairs); + else + { + mainLen = p->longestMatchLength; + numPairs = p->numPairs; + } + + numAvail = p->numAvail; + if (numAvail < 2) + { + *backRes = (UInt32)(-1); + return 1; + } + if (numAvail > LZMA_MATCH_LEN_MAX) + numAvail = LZMA_MATCH_LEN_MAX; + + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + repMaxIndex = 0; + for (i = 0; i < LZMA_NUM_REPS; i++) + { + UInt32 lenTest; + const Byte *data2; + reps[i] = p->reps[i]; + data2 = data - (reps[i] + 1); + if (data[0] != data2[0] || data[1] != data2[1]) + { + repLens[i] = 0; + continue; + } + for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); + repLens[i] = lenTest; + if (lenTest > repLens[repMaxIndex]) + repMaxIndex = i; + } + if (repLens[repMaxIndex] >= p->numFastBytes) + { + UInt32 lenRes; + *backRes = repMaxIndex; + lenRes = repLens[repMaxIndex]; + MovePos(p, lenRes - 1); + return lenRes; + } + + matches = p->matches; + if (mainLen >= p->numFastBytes) + { + *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; + MovePos(p, mainLen - 1); + return mainLen; + } + curByte = *data; + matchByte = *(data - (reps[0] + 1)); + + if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2) + { + *backRes = (UInt32)-1; + return 1; + } + + p->opt[0].state = (CState)p->state; + + posState = (position & p->pbMask); + + { + const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); + p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) + + (!IsCharState(p->state) ? + LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : + LitEnc_GetPrice(probs, curByte, p->ProbPrices)); + } + + MakeAsChar(&p->opt[1]); + + matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]); + repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]); + + if (matchByte == curByte) + { + UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState); + if (shortRepPrice < p->opt[1].price) + { + p->opt[1].price = shortRepPrice; + MakeAsShortRep(&p->opt[1]); + } + } + lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]); + + if (lenEnd < 2) + { + *backRes = p->opt[1].backPrev; + return 1; + } + + p->opt[1].posPrev = 0; + for (i = 0; i < LZMA_NUM_REPS; i++) + p->opt[0].backs[i] = reps[i]; + + len = lenEnd; + do + p->opt[len--].price = kInfinityPrice; + while (len >= 2); + + for (i = 0; i < LZMA_NUM_REPS; i++) + { + UInt32 repLen = repLens[i]; + UInt32 price; + if (repLen < 2) + continue; + price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState); + do + { + UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2]; + COptimal *opt = &p->opt[repLen]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = 0; + opt->backPrev = i; + opt->prev1IsChar = False; + } + } + while (--repLen >= 2); + } + + normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]); + + len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2); + if (len <= mainLen) + { + UInt32 offs = 0; + while (len > matches[offs]) + offs += 2; + for (; ; len++) + { + COptimal *opt; + UInt32 distance = matches[offs + 1]; + + UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN]; + UInt32 lenToPosState = GetLenToPosState(len); + if (distance < kNumFullDistances) + curAndLenPrice += p->distancesPrices[lenToPosState][distance]; + else + { + UInt32 slot; + GetPosSlot2(distance, slot); + curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot]; + } + opt = &p->opt[len]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = 0; + opt->backPrev = distance + LZMA_NUM_REPS; + opt->prev1IsChar = False; + } + if (len == matches[offs]) + { + offs += 2; + if (offs == numPairs) + break; + } + } + } + + cur = 0; + + #ifdef SHOW_STAT2 + if (position >= 0) + { + unsigned i; + printf("\n pos = %4X", position); + for (i = cur; i <= lenEnd; i++) + printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price); + } + #endif + + for (;;) + { + UInt32 numAvailFull, newLen, numPairs, posPrev, state, posState, startLen; + UInt32 curPrice, curAnd1Price, matchPrice, repMatchPrice; + Bool nextIsChar; + Byte curByte, matchByte; + const Byte *data; + COptimal *curOpt; + COptimal *nextOpt; + + cur++; + if (cur == lenEnd) + return Backward(p, backRes, cur); + + newLen = ReadMatchDistances(p, &numPairs); + if (newLen >= p->numFastBytes) + { + p->numPairs = numPairs; + p->longestMatchLength = newLen; + return Backward(p, backRes, cur); + } + position++; + curOpt = &p->opt[cur]; + posPrev = curOpt->posPrev; + if (curOpt->prev1IsChar) + { + posPrev--; + if (curOpt->prev2) + { + state = p->opt[curOpt->posPrev2].state; + if (curOpt->backPrev2 < LZMA_NUM_REPS) + state = kRepNextStates[state]; + else + state = kMatchNextStates[state]; + } + else + state = p->opt[posPrev].state; + state = kLiteralNextStates[state]; + } + else + state = p->opt[posPrev].state; + if (posPrev == cur - 1) + { + if (IsShortRep(curOpt)) + state = kShortRepNextStates[state]; + else + state = kLiteralNextStates[state]; + } + else + { + UInt32 pos; + const COptimal *prevOpt; + if (curOpt->prev1IsChar && curOpt->prev2) + { + posPrev = curOpt->posPrev2; + pos = curOpt->backPrev2; + state = kRepNextStates[state]; + } + else + { + pos = curOpt->backPrev; + if (pos < LZMA_NUM_REPS) + state = kRepNextStates[state]; + else + state = kMatchNextStates[state]; + } + prevOpt = &p->opt[posPrev]; + if (pos < LZMA_NUM_REPS) + { + UInt32 i; + reps[0] = prevOpt->backs[pos]; + for (i = 1; i <= pos; i++) + reps[i] = prevOpt->backs[i - 1]; + for (; i < LZMA_NUM_REPS; i++) + reps[i] = prevOpt->backs[i]; + } + else + { + UInt32 i; + reps[0] = (pos - LZMA_NUM_REPS); + for (i = 1; i < LZMA_NUM_REPS; i++) + reps[i] = prevOpt->backs[i - 1]; + } + } + curOpt->state = (CState)state; + + curOpt->backs[0] = reps[0]; + curOpt->backs[1] = reps[1]; + curOpt->backs[2] = reps[2]; + curOpt->backs[3] = reps[3]; + + curPrice = curOpt->price; + nextIsChar = False; + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + curByte = *data; + matchByte = *(data - (reps[0] + 1)); + + posState = (position & p->pbMask); + + curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]); + { + const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); + curAnd1Price += + (!IsCharState(state) ? + LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : + LitEnc_GetPrice(probs, curByte, p->ProbPrices)); + } + + nextOpt = &p->opt[cur + 1]; + + if (curAnd1Price < nextOpt->price) + { + nextOpt->price = curAnd1Price; + nextOpt->posPrev = cur; + MakeAsChar(nextOpt); + nextIsChar = True; + } + + matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]); + repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]); + + if (matchByte == curByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0)) + { + UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState); + if (shortRepPrice <= nextOpt->price) + { + nextOpt->price = shortRepPrice; + nextOpt->posPrev = cur; + MakeAsShortRep(nextOpt); + nextIsChar = True; + } + } + numAvailFull = p->numAvail; + { + UInt32 temp = kNumOpts - 1 - cur; + if (temp < numAvailFull) + numAvailFull = temp; + } + + if (numAvailFull < 2) + continue; + numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes); + + if (!nextIsChar && matchByte != curByte) /* speed optimization */ + { + /* try Literal + rep0 */ + UInt32 temp; + UInt32 lenTest2; + const Byte *data2 = data - (reps[0] + 1); + UInt32 limit = p->numFastBytes + 1; + if (limit > numAvailFull) + limit = numAvailFull; + + for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++); + lenTest2 = temp - 1; + if (lenTest2 >= 2) + { + UInt32 state2 = kLiteralNextStates[state]; + UInt32 posStateNext = (position + 1) & p->pbMask; + UInt32 nextRepMatchPrice = curAnd1Price + + GET_PRICE_1(p->isMatch[state2][posStateNext]) + + GET_PRICE_1(p->isRep[state2]); + /* for (; lenTest2 >= 2; lenTest2--) */ + { + UInt32 curAndLenPrice; + COptimal *opt; + UInt32 offset = cur + 1 + lenTest2; + while (lenEnd < offset) + p->opt[++lenEnd].price = kInfinityPrice; + curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); + opt = &p->opt[offset]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = cur + 1; + opt->backPrev = 0; + opt->prev1IsChar = True; + opt->prev2 = False; + } + } + } + } + + startLen = 2; /* speed optimization */ + { + UInt32 repIndex; + for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++) + { + UInt32 lenTest; + UInt32 lenTestTemp; + UInt32 price; + const Byte *data2 = data - (reps[repIndex] + 1); + if (data[0] != data2[0] || data[1] != data2[1]) + continue; + for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); + while (lenEnd < cur + lenTest) + p->opt[++lenEnd].price = kInfinityPrice; + lenTestTemp = lenTest; + price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState); + do + { + UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2]; + COptimal *opt = &p->opt[cur + lenTest]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = cur; + opt->backPrev = repIndex; + opt->prev1IsChar = False; + } + } + while (--lenTest >= 2); + lenTest = lenTestTemp; + + if (repIndex == 0) + startLen = lenTest + 1; + + /* if (_maxMode) */ + { + UInt32 lenTest2 = lenTest + 1; + UInt32 limit = lenTest2 + p->numFastBytes; + UInt32 nextRepMatchPrice; + if (limit > numAvailFull) + limit = numAvailFull; + for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); + lenTest2 -= lenTest + 1; + if (lenTest2 >= 2) + { + UInt32 state2 = kRepNextStates[state]; + UInt32 posStateNext = (position + lenTest) & p->pbMask; + UInt32 curAndLenCharPrice = + price + p->repLenEnc.prices[posState][lenTest - 2] + + GET_PRICE_0(p->isMatch[state2][posStateNext]) + + LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), + data[lenTest], data2[lenTest], p->ProbPrices); + state2 = kLiteralNextStates[state2]; + posStateNext = (position + lenTest + 1) & p->pbMask; + nextRepMatchPrice = curAndLenCharPrice + + GET_PRICE_1(p->isMatch[state2][posStateNext]) + + GET_PRICE_1(p->isRep[state2]); + + /* for (; lenTest2 >= 2; lenTest2--) */ + { + UInt32 curAndLenPrice; + COptimal *opt; + UInt32 offset = cur + lenTest + 1 + lenTest2; + while (lenEnd < offset) + p->opt[++lenEnd].price = kInfinityPrice; + curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); + opt = &p->opt[offset]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = cur + lenTest + 1; + opt->backPrev = 0; + opt->prev1IsChar = True; + opt->prev2 = True; + opt->posPrev2 = cur; + opt->backPrev2 = repIndex; + } + } + } + } + } + } + /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */ + if (newLen > numAvail) + { + newLen = numAvail; + for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2); + matches[numPairs] = newLen; + numPairs += 2; + } + if (newLen >= startLen) + { + UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]); + UInt32 offs, curBack, posSlot; + UInt32 lenTest; + while (lenEnd < cur + newLen) + p->opt[++lenEnd].price = kInfinityPrice; + + offs = 0; + while (startLen > matches[offs]) + offs += 2; + curBack = matches[offs + 1]; + GetPosSlot2(curBack, posSlot); + for (lenTest = /*2*/ startLen; ; lenTest++) + { + UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN]; + UInt32 lenToPosState = GetLenToPosState(lenTest); + COptimal *opt; + if (curBack < kNumFullDistances) + curAndLenPrice += p->distancesPrices[lenToPosState][curBack]; + else + curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask]; + + opt = &p->opt[cur + lenTest]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = cur; + opt->backPrev = curBack + LZMA_NUM_REPS; + opt->prev1IsChar = False; + } + + if (/*_maxMode && */lenTest == matches[offs]) + { + /* Try Match + Literal + Rep0 */ + const Byte *data2 = data - (curBack + 1); + UInt32 lenTest2 = lenTest + 1; + UInt32 limit = lenTest2 + p->numFastBytes; + UInt32 nextRepMatchPrice; + if (limit > numAvailFull) + limit = numAvailFull; + for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); + lenTest2 -= lenTest + 1; + if (lenTest2 >= 2) + { + UInt32 state2 = kMatchNextStates[state]; + UInt32 posStateNext = (position + lenTest) & p->pbMask; + UInt32 curAndLenCharPrice = curAndLenPrice + + GET_PRICE_0(p->isMatch[state2][posStateNext]) + + LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), + data[lenTest], data2[lenTest], p->ProbPrices); + state2 = kLiteralNextStates[state2]; + posStateNext = (posStateNext + 1) & p->pbMask; + nextRepMatchPrice = curAndLenCharPrice + + GET_PRICE_1(p->isMatch[state2][posStateNext]) + + GET_PRICE_1(p->isRep[state2]); + + /* for (; lenTest2 >= 2; lenTest2--) */ + { + UInt32 offset = cur + lenTest + 1 + lenTest2; + UInt32 curAndLenPrice; + COptimal *opt; + while (lenEnd < offset) + p->opt[++lenEnd].price = kInfinityPrice; + curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); + opt = &p->opt[offset]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = cur + lenTest + 1; + opt->backPrev = 0; + opt->prev1IsChar = True; + opt->prev2 = True; + opt->posPrev2 = cur; + opt->backPrev2 = curBack + LZMA_NUM_REPS; + } + } + } + offs += 2; + if (offs == numPairs) + break; + curBack = matches[offs + 1]; + if (curBack >= kNumFullDistances) + GetPosSlot2(curBack, posSlot); + } + } + } + } +} + +#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist)) + +static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes) +{ + UInt32 numAvail, mainLen, mainDist, numPairs, repIndex, repLen, i; + const Byte *data; + const UInt32 *matches; + + if (p->additionalOffset == 0) + mainLen = ReadMatchDistances(p, &numPairs); + else + { + mainLen = p->longestMatchLength; + numPairs = p->numPairs; + } + + numAvail = p->numAvail; + *backRes = (UInt32)-1; + if (numAvail < 2) + return 1; + if (numAvail > LZMA_MATCH_LEN_MAX) + numAvail = LZMA_MATCH_LEN_MAX; + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + + repLen = repIndex = 0; + for (i = 0; i < LZMA_NUM_REPS; i++) + { + UInt32 len; + const Byte *data2 = data - (p->reps[i] + 1); + if (data[0] != data2[0] || data[1] != data2[1]) + continue; + for (len = 2; len < numAvail && data[len] == data2[len]; len++); + if (len >= p->numFastBytes) + { + *backRes = i; + MovePos(p, len - 1); + return len; + } + if (len > repLen) + { + repIndex = i; + repLen = len; + } + } + + matches = p->matches; + if (mainLen >= p->numFastBytes) + { + *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; + MovePos(p, mainLen - 1); + return mainLen; + } + + mainDist = 0; /* for GCC */ + if (mainLen >= 2) + { + mainDist = matches[numPairs - 1]; + while (numPairs > 2 && mainLen == matches[numPairs - 4] + 1) + { + if (!ChangePair(matches[numPairs - 3], mainDist)) + break; + numPairs -= 2; + mainLen = matches[numPairs - 2]; + mainDist = matches[numPairs - 1]; + } + if (mainLen == 2 && mainDist >= 0x80) + mainLen = 1; + } + + if (repLen >= 2 && ( + (repLen + 1 >= mainLen) || + (repLen + 2 >= mainLen && mainDist >= (1 << 9)) || + (repLen + 3 >= mainLen && mainDist >= (1 << 15)))) + { + *backRes = repIndex; + MovePos(p, repLen - 1); + return repLen; + } + + if (mainLen < 2 || numAvail <= 2) + return 1; + + p->longestMatchLength = ReadMatchDistances(p, &p->numPairs); + if (p->longestMatchLength >= 2) + { + UInt32 newDistance = matches[p->numPairs - 1]; + if ((p->longestMatchLength >= mainLen && newDistance < mainDist) || + (p->longestMatchLength == mainLen + 1 && !ChangePair(mainDist, newDistance)) || + (p->longestMatchLength > mainLen + 1) || + (p->longestMatchLength + 1 >= mainLen && mainLen >= 3 && ChangePair(newDistance, mainDist))) + return 1; + } + + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + for (i = 0; i < LZMA_NUM_REPS; i++) + { + UInt32 len, limit; + const Byte *data2 = data - (p->reps[i] + 1); + if (data[0] != data2[0] || data[1] != data2[1]) + continue; + limit = mainLen - 1; + for (len = 2; len < limit && data[len] == data2[len]; len++); + if (len >= limit) + return 1; + } + *backRes = mainDist + LZMA_NUM_REPS; + MovePos(p, mainLen - 2); + return mainLen; +} + +static void WriteEndMarker(CLzmaEnc *p, UInt32 posState) +{ + UInt32 len; + RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); + RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); + p->state = kMatchNextStates[p->state]; + len = LZMA_MATCH_LEN_MIN; + LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); + RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1); + RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits); + RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask); +} + +static SRes CheckErrors(CLzmaEnc *p) +{ + if (p->result != SZ_OK) + return p->result; + if (p->rc.res != SZ_OK) + p->result = SZ_ERROR_WRITE; + if (p->matchFinderBase.result != SZ_OK) + p->result = SZ_ERROR_READ; + if (p->result != SZ_OK) + p->finished = True; + return p->result; +} + +static SRes Flush(CLzmaEnc *p, UInt32 nowPos) +{ + /* ReleaseMFStream(); */ + p->finished = True; + if (p->writeEndMark) + WriteEndMarker(p, nowPos & p->pbMask); + RangeEnc_FlushData(&p->rc); + RangeEnc_FlushStream(&p->rc); + return CheckErrors(p); +} + +static void FillAlignPrices(CLzmaEnc *p) +{ + UInt32 i; + for (i = 0; i < kAlignTableSize; i++) + p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices); + p->alignPriceCount = 0; +} + +static void FillDistancesPrices(CLzmaEnc *p) +{ + UInt32 tempPrices[kNumFullDistances]; + UInt32 i, lenToPosState; + for (i = kStartPosModelIndex; i < kNumFullDistances; i++) + { + UInt32 posSlot = GetPosSlot1(i); + UInt32 footerBits = ((posSlot >> 1) - 1); + UInt32 base = ((2 | (posSlot & 1)) << footerBits); + tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices); + } + + for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++) + { + UInt32 posSlot; + const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState]; + UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState]; + for (posSlot = 0; posSlot < p->distTableSize; posSlot++) + posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices); + for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++) + posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits); + + { + UInt32 *distancesPrices = p->distancesPrices[lenToPosState]; + UInt32 i; + for (i = 0; i < kStartPosModelIndex; i++) + distancesPrices[i] = posSlotPrices[i]; + for (; i < kNumFullDistances; i++) + distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i]; + } + } + p->matchPriceCount = 0; +} + +void LzmaEnc_Construct(CLzmaEnc *p) +{ + RangeEnc_Construct(&p->rc); + MatchFinder_Construct(&p->matchFinderBase); + #ifdef COMPRESS_MF_MT + MatchFinderMt_Construct(&p->matchFinderMt); + p->matchFinderMt.MatchFinder = &p->matchFinderBase; + #endif + + { + CLzmaEncProps props; + LzmaEncProps_Init(&props); + LzmaEnc_SetProps(p, &props); + } + + #ifndef LZMA_LOG_BSR + LzmaEnc_FastPosInit(p->g_FastPos); + #endif + + LzmaEnc_InitPriceTables(p->ProbPrices); + p->litProbs = 0; + p->saveState.litProbs = 0; +} + +CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc) +{ + void *p; + p = alloc->Alloc(alloc, sizeof(CLzmaEnc)); + if (p != 0) + LzmaEnc_Construct((CLzmaEnc *)p); + return p; +} + +void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->litProbs); + alloc->Free(alloc, p->saveState.litProbs); + p->litProbs = 0; + p->saveState.litProbs = 0; +} + +void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + #ifdef COMPRESS_MF_MT + MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); + #endif + MatchFinder_Free(&p->matchFinderBase, allocBig); + LzmaEnc_FreeLits(p, alloc); + RangeEnc_Free(&p->rc, alloc); +} + +void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig); + alloc->Free(alloc, p); +} + +static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize) +{ + UInt32 nowPos32, startPos32; + if (p->inStream != 0) + { + p->matchFinderBase.stream = p->inStream; + p->matchFinder.Init(p->matchFinderObj); + p->inStream = 0; + } + + if (p->finished) + return p->result; + RINOK(CheckErrors(p)); + + nowPos32 = (UInt32)p->nowPos64; + startPos32 = nowPos32; + + if (p->nowPos64 == 0) + { + UInt32 numPairs; + Byte curByte; + if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) + return Flush(p, nowPos32); + ReadMatchDistances(p, &numPairs); + RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0); + p->state = kLiteralNextStates[p->state]; + curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset); + LitEnc_Encode(&p->rc, p->litProbs, curByte); + p->additionalOffset--; + nowPos32++; + } + + if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0) + for (;;) + { + UInt32 pos, len, posState; + + if (p->fastMode) + len = GetOptimumFast(p, &pos); + else + len = GetOptimum(p, nowPos32, &pos); + + #ifdef SHOW_STAT2 + printf("\n pos = %4X, len = %d pos = %d", nowPos32, len, pos); + #endif + + posState = nowPos32 & p->pbMask; + if (len == 1 && pos == (UInt32)-1) + { + Byte curByte; + CLzmaProb *probs; + const Byte *data; + + RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0); + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; + curByte = *data; + probs = LIT_PROBS(nowPos32, *(data - 1)); + if (IsCharState(p->state)) + LitEnc_Encode(&p->rc, probs, curByte); + else + LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1)); + p->state = kLiteralNextStates[p->state]; + } + else + { + RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); + if (pos < LZMA_NUM_REPS) + { + RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1); + if (pos == 0) + { + RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0); + RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1)); + } + else + { + UInt32 distance = p->reps[pos]; + RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1); + if (pos == 1) + RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0); + else + { + RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1); + RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2); + if (pos == 3) + p->reps[3] = p->reps[2]; + p->reps[2] = p->reps[1]; + } + p->reps[1] = p->reps[0]; + p->reps[0] = distance; + } + if (len == 1) + p->state = kShortRepNextStates[p->state]; + else + { + LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); + p->state = kRepNextStates[p->state]; + } + } + else + { + UInt32 posSlot; + RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); + p->state = kMatchNextStates[p->state]; + LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); + pos -= LZMA_NUM_REPS; + GetPosSlot(pos, posSlot); + RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot); + + if (posSlot >= kStartPosModelIndex) + { + UInt32 footerBits = ((posSlot >> 1) - 1); + UInt32 base = ((2 | (posSlot & 1)) << footerBits); + UInt32 posReduced = pos - base; + + if (posSlot < kEndPosModelIndex) + RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced); + else + { + RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits); + RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask); + p->alignPriceCount++; + } + } + p->reps[3] = p->reps[2]; + p->reps[2] = p->reps[1]; + p->reps[1] = p->reps[0]; + p->reps[0] = pos; + p->matchPriceCount++; + } + } + p->additionalOffset -= len; + nowPos32 += len; + if (p->additionalOffset == 0) + { + UInt32 processed; + if (!p->fastMode) + { + if (p->matchPriceCount >= (1 << 7)) + FillDistancesPrices(p); + if (p->alignPriceCount >= kAlignTableSize) + FillAlignPrices(p); + } + if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) + break; + processed = nowPos32 - startPos32; + if (useLimits) + { + if (processed + kNumOpts + 300 >= maxUnpackSize || + RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize) + break; + } + else if (processed >= (1 << 15)) + { + p->nowPos64 += nowPos32 - startPos32; + return CheckErrors(p); + } + } + } + p->nowPos64 += nowPos32 - startPos32; + return Flush(p, nowPos32); +} + +#define kBigHashDicLimit ((UInt32)1 << 24) + +static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + UInt32 beforeSize = kNumOpts; + Bool btMode; + if (!RangeEnc_Alloc(&p->rc, alloc)) + return SZ_ERROR_MEM; + btMode = (p->matchFinderBase.btMode != 0); + #ifdef COMPRESS_MF_MT + p->mtMode = (p->multiThread && !p->fastMode && btMode); + #endif + + { + unsigned lclp = p->lc + p->lp; + if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp) + { + LzmaEnc_FreeLits(p, alloc); + p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); + p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); + if (p->litProbs == 0 || p->saveState.litProbs == 0) + { + LzmaEnc_FreeLits(p, alloc); + return SZ_ERROR_MEM; + } + p->lclp = lclp; + } + } + + p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit); + + if (beforeSize + p->dictSize < keepWindowSize) + beforeSize = keepWindowSize - p->dictSize; + + #ifdef COMPRESS_MF_MT + if (p->mtMode) + { + RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)); + p->matchFinderObj = &p->matchFinderMt; + MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder); + } + else + #endif + { + if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)) + return SZ_ERROR_MEM; + p->matchFinderObj = &p->matchFinderBase; + MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder); + } + return SZ_OK; +} + +void LzmaEnc_Init(CLzmaEnc *p) +{ + UInt32 i; + p->state = 0; + for (i = 0 ; i < LZMA_NUM_REPS; i++) + p->reps[i] = 0; + + RangeEnc_Init(&p->rc); + + + for (i = 0; i < kNumStates; i++) + { + UInt32 j; + for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++) + { + p->isMatch[i][j] = kProbInitValue; + p->isRep0Long[i][j] = kProbInitValue; + } + p->isRep[i] = kProbInitValue; + p->isRepG0[i] = kProbInitValue; + p->isRepG1[i] = kProbInitValue; + p->isRepG2[i] = kProbInitValue; + } + + { + UInt32 num = 0x300 << (p->lp + p->lc); + for (i = 0; i < num; i++) + p->litProbs[i] = kProbInitValue; + } + + { + for (i = 0; i < kNumLenToPosStates; i++) + { + CLzmaProb *probs = p->posSlotEncoder[i]; + UInt32 j; + for (j = 0; j < (1 << kNumPosSlotBits); j++) + probs[j] = kProbInitValue; + } + } + { + for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++) + p->posEncoders[i] = kProbInitValue; + } + + LenEnc_Init(&p->lenEnc.p); + LenEnc_Init(&p->repLenEnc.p); + + for (i = 0; i < (1 << kNumAlignBits); i++) + p->posAlignEncoder[i] = kProbInitValue; + + p->optimumEndIndex = 0; + p->optimumCurrentIndex = 0; + p->additionalOffset = 0; + + p->pbMask = (1 << p->pb) - 1; + p->lpMask = (1 << p->lp) - 1; +} + +void LzmaEnc_InitPrices(CLzmaEnc *p) +{ + if (!p->fastMode) + { + FillDistancesPrices(p); + FillAlignPrices(p); + } + + p->lenEnc.tableSize = + p->repLenEnc.tableSize = + p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN; + LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices); + LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices); +} + +static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + UInt32 i; + for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++) + if (p->dictSize <= ((UInt32)1 << i)) + break; + p->distTableSize = i * 2; + + p->finished = False; + p->result = SZ_OK; + RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig)); + LzmaEnc_Init(p); + LzmaEnc_InitPrices(p); + p->nowPos64 = 0; + return SZ_OK; +} + +static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqInStream *inStream, ISeqOutStream *outStream, + ISzAlloc *alloc, ISzAlloc *allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + p->inStream = inStream; + p->rc.outStream = outStream; + return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig); +} + +SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, + ISeqInStream *inStream, UInt32 keepWindowSize, + ISzAlloc *alloc, ISzAlloc *allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + p->inStream = inStream; + return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); +} + +static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen) +{ + p->seqBufInStream.funcTable.Read = MyRead; + p->seqBufInStream.data = src; + p->seqBufInStream.rem = srcLen; +} + +SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, + UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + LzmaEnc_SetInputBuf(p, src, srcLen); + p->inStream = &p->seqBufInStream.funcTable; + return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); +} + +void LzmaEnc_Finish(CLzmaEncHandle pp) +{ + #ifdef COMPRESS_MF_MT + CLzmaEnc *p = (CLzmaEnc *)pp; + if (p->mtMode) + MatchFinderMt_ReleaseStream(&p->matchFinderMt); + #else + pp = pp; + #endif +} + +typedef struct _CSeqOutStreamBuf +{ + ISeqOutStream funcTable; + Byte *data; + SizeT rem; + Bool overflow; +} CSeqOutStreamBuf; + +static size_t MyWrite(void *pp, const void *data, size_t size) +{ + CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp; + if (p->rem < size) + { + size = p->rem; + p->overflow = True; + } + memcpy(p->data, data, size); + p->rem -= size; + p->data += size; + return size; +} + + +UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp) +{ + const CLzmaEnc *p = (CLzmaEnc *)pp; + return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); +} + +const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) +{ + const CLzmaEnc *p = (CLzmaEnc *)pp; + return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; +} + +SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, + Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + UInt64 nowPos64; + SRes res; + CSeqOutStreamBuf outStream; + + outStream.funcTable.Write = MyWrite; + outStream.data = dest; + outStream.rem = *destLen; + outStream.overflow = False; + + p->writeEndMark = False; + p->finished = False; + p->result = SZ_OK; + + if (reInit) + LzmaEnc_Init(p); + LzmaEnc_InitPrices(p); + nowPos64 = p->nowPos64; + RangeEnc_Init(&p->rc); + p->rc.outStream = &outStream.funcTable; + + res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize); + + *unpackSize = (UInt32)(p->nowPos64 - nowPos64); + *destLen -= outStream.rem; + if (outStream.overflow) + return SZ_ERROR_OUTPUT_EOF; + + return res; +} + +SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, + ISzAlloc *alloc, ISzAlloc *allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + SRes res = SZ_OK; + + #ifdef COMPRESS_MF_MT + Byte allocaDummy[0x300]; + int i = 0; + for (i = 0; i < 16; i++) + allocaDummy[i] = (Byte)i; + #endif + + RINOK(LzmaEnc_Prepare(pp, inStream, outStream, alloc, allocBig)); + + for (;;) + { + res = LzmaEnc_CodeOneBlock(p, False, 0, 0); + if (res != SZ_OK || p->finished != 0) + break; + if (progress != 0) + { + res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc)); + if (res != SZ_OK) + { + res = SZ_ERROR_PROGRESS; + break; + } + } + } + LzmaEnc_Finish(pp); + return res; +} + +SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + int i; + UInt32 dictSize = p->dictSize; + if (*size < LZMA_PROPS_SIZE) + return SZ_ERROR_PARAM; + *size = LZMA_PROPS_SIZE; + props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc); + + for (i = 11; i <= 30; i++) + { + if (dictSize <= ((UInt32)2 << i)) + { + dictSize = (2 << i); + break; + } + if (dictSize <= ((UInt32)3 << i)) + { + dictSize = (3 << i); + break; + } + } + + for (i = 0; i < 4; i++) + props[1 + i] = (Byte)(dictSize >> (8 * i)); + return SZ_OK; +} + +SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + SRes res; + CLzmaEnc *p = (CLzmaEnc *)pp; + + CSeqOutStreamBuf outStream; + + LzmaEnc_SetInputBuf(p, src, srcLen); + + outStream.funcTable.Write = MyWrite; + outStream.data = dest; + outStream.rem = *destLen; + outStream.overflow = False; + + p->writeEndMark = writeEndMark; + res = LzmaEnc_Encode(pp, &outStream.funcTable, &p->seqBufInStream.funcTable, + progress, alloc, allocBig); + + *destLen -= outStream.rem; + if (outStream.overflow) + return SZ_ERROR_OUTPUT_EOF; + return res; +} + +SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, + ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); + SRes res; + if (p == 0) + return SZ_ERROR_MEM; + + res = LzmaEnc_SetProps(p, props); + if (res == SZ_OK) + { + res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize); + if (res == SZ_OK) + res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen, + writeEndMark, progress, alloc, allocBig); + } + + LzmaEnc_Destroy(p, alloc, allocBig); + return res; +} diff --git a/src/external/OpenCTM-1.0.3/lib/liblzma/LzmaEnc.h b/src/external/OpenCTM-1.0.3/lib/liblzma/LzmaEnc.h new file mode 100644 index 000000000..bfbc7d2b9 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/liblzma/LzmaEnc.h @@ -0,0 +1,72 @@ +/* LzmaEnc.h -- LZMA Encoder +2008-10-04 : Igor Pavlov : Public domain */ + +#ifndef __LZMAENC_H +#define __LZMAENC_H + +#include "Types.h" + +#define LZMA_PROPS_SIZE 5 + +typedef struct _CLzmaEncProps +{ + int level; /* 0 <= level <= 9 */ + UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version + (1 << 12) <= dictSize <= (1 << 30) for 64-bit version + default = (1 << 24) */ + int lc; /* 0 <= lc <= 8, default = 3 */ + int lp; /* 0 <= lp <= 4, default = 0 */ + int pb; /* 0 <= pb <= 4, default = 2 */ + int algo; /* 0 - fast, 1 - normal, default = 1 */ + int fb; /* 5 <= fb <= 273, default = 32 */ + int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */ + int numHashBytes; /* 2, 3 or 4, default = 4 */ + UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */ + unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */ + int numThreads; /* 1 or 2, default = 2 */ +} CLzmaEncProps; + +void LzmaEncProps_Init(CLzmaEncProps *p); +void LzmaEncProps_Normalize(CLzmaEncProps *p); +UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); + + +/* ---------- CLzmaEncHandle Interface ---------- */ + +/* LzmaEnc_* functions can return the following exit codes: +Returns: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater in props + SZ_ERROR_WRITE - Write callback error. + SZ_ERROR_PROGRESS - some break from progress callback + SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +*/ + +typedef void * CLzmaEncHandle; + +CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc); +void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig); +SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); +SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); +SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, + ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); +SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); + +/* ---------- One Call Interface ---------- */ + +/* LzmaEncode +Return code: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater + SZ_ERROR_OUTPUT_EOF - output buffer overflow + SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +*/ + +SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, + ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); + +#endif diff --git a/src/external/OpenCTM-1.0.3/lib/liblzma/LzmaLib.c b/src/external/OpenCTM-1.0.3/lib/liblzma/LzmaLib.c new file mode 100644 index 000000000..6cc29da23 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/liblzma/LzmaLib.c @@ -0,0 +1,48 @@ +/* LzmaLib.c -- LZMA library wrapper +2008-08-05 +Igor Pavlov +Public domain */ + +#include "LzmaEnc.h" +#include "LzmaDec.h" +#include "Alloc.h" +#include "LzmaLib.h" + +static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); } +static void SzFree(void *p, void *address) { p = p; MyFree(address); } +static ISzAlloc g_Alloc = { SzAlloc, SzFree }; + +MY_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen, + unsigned char *outProps, size_t *outPropsSize, + int level, /* 0 <= level <= 9, default = 5 */ + unsigned dictSize, /* use (1 << N) or (3 << N). 4 KB < dictSize <= 128 MB */ + int lc, /* 0 <= lc <= 8, default = 3 */ + int lp, /* 0 <= lp <= 4, default = 0 */ + int pb, /* 0 <= pb <= 4, default = 2 */ + int fb, /* 5 <= fb <= 273, default = 32 */ + int numThreads, /* 1 or 2, default = 2 */ + int algo /* 0 = fast, 1 = normal */ +) +{ + CLzmaEncProps props; + LzmaEncProps_Init(&props); + props.level = level; + props.dictSize = dictSize; + props.lc = lc; + props.lp = lp; + props.pb = pb; + props.fb = fb; + props.numThreads = numThreads; + props.algo = algo; + + return LzmaEncode(dest, destLen, src, srcLen, &props, outProps, outPropsSize, 0, + NULL, &g_Alloc, &g_Alloc); +} + + +MY_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t *srcLen, + const unsigned char *props, size_t propsSize) +{ + ELzmaStatus status; + return LzmaDecode(dest, destLen, src, srcLen, props, (unsigned)propsSize, LZMA_FINISH_ANY, &status, &g_Alloc); +} diff --git a/src/external/OpenCTM-1.0.3/lib/liblzma/LzmaLib.h b/src/external/OpenCTM-1.0.3/lib/liblzma/LzmaLib.h new file mode 100644 index 000000000..8ace8bd75 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/liblzma/LzmaLib.h @@ -0,0 +1,136 @@ +/* LzmaLib.h -- LZMA library interface +2008-08-05 +Igor Pavlov +Public domain */ + +#ifndef __LZMALIB_H +#define __LZMALIB_H + +#include "Types.h" + +#ifdef __cplusplus + #define MY_EXTERN_C extern "C" +#else + #define MY_EXTERN_C extern +#endif + +#define MY_STDAPI MY_EXTERN_C int MY_STD_CALL + +#define LZMA_PROPS_SIZE 5 + +/* +RAM requirements for LZMA: + for compression: (dictSize * 11.5 + 6 MB) + state_size + for decompression: dictSize + state_size + state_size = (4 + (1.5 << (lc + lp))) KB + by default (lc=3, lp=0), state_size = 16 KB. + +LZMA properties (5 bytes) format + Offset Size Description + 0 1 lc, lp and pb in encoded form. + 1 4 dictSize (little endian). +*/ + +/* +LzmaCompress +------------ + +outPropsSize - + In: the pointer to the size of outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5. + Out: the pointer to the size of written properties in outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5. + + LZMA Encoder will use defult values for any parameter, if it is + -1 for any from: level, loc, lp, pb, fb, numThreads + 0 for dictSize + +level - compression level: 0 <= level <= 9; + + level dictSize algo fb + 0: 16 KB 0 32 + 1: 64 KB 0 32 + 2: 256 KB 0 32 + 3: 1 MB 0 32 + 4: 4 MB 0 32 + 5: 16 MB 1 32 + 6: 32 MB 1 32 + 7+: 64 MB 1 64 + + The default value for "level" is 5. + + algo = 0 means fast method + algo = 1 means normal method + +dictSize - The dictionary size in bytes. The maximum value is + 128 MB = (1 << 27) bytes for 32-bit version + 1 GB = (1 << 30) bytes for 64-bit version + The default value is 16 MB = (1 << 24) bytes. + It's recommended to use the dictionary that is larger than 4 KB and + that can be calculated as (1 << N) or (3 << N) sizes. + +lc - The number of literal context bits (high bits of previous literal). + It can be in the range from 0 to 8. The default value is 3. + Sometimes lc=4 gives the gain for big files. + +lp - The number of literal pos bits (low bits of current position for literals). + It can be in the range from 0 to 4. The default value is 0. + The lp switch is intended for periodical data when the period is equal to 2^lp. + For example, for 32-bit (4 bytes) periodical data you can use lp=2. Often it's + better to set lc=0, if you change lp switch. + +pb - The number of pos bits (low bits of current position). + It can be in the range from 0 to 4. The default value is 2. + The pb switch is intended for periodical data when the period is equal 2^pb. + +fb - Word size (the number of fast bytes). + It can be in the range from 5 to 273. The default value is 32. + Usually, a big number gives a little bit better compression ratio and + slower compression process. + +numThreads - The number of thereads. 1 or 2. The default value is 2. + Fast mode (algo = 0) can use only 1 thread. + +Out: + destLen - processed output size +Returns: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater + SZ_ERROR_OUTPUT_EOF - output buffer overflow + SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +*/ + +MY_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen, + unsigned char *outProps, size_t *outPropsSize, /* *outPropsSize must be = 5 */ + int level, /* 0 <= level <= 9, default = 5 */ + unsigned dictSize, /* default = (1 << 24) */ + int lc, /* 0 <= lc <= 8, default = 3 */ + int lp, /* 0 <= lp <= 4, default = 0 */ + int pb, /* 0 <= pb <= 4, default = 2 */ + int fb, /* 5 <= fb <= 273, default = 32 */ + int numThreads, /* 1 or 2, default = 2 */ + int algo /* 0 = fast, 1 = normal, default = 0 for level < 5, 1 for level >= 5 */ + ); + +/* +LzmaUncompress +-------------- +In: + dest - output data + destLen - output data size + src - input data + srcLen - input data size +Out: + destLen - processed output size + srcLen - processed input size +Returns: + SZ_OK - OK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation arror + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer (src) +*/ + +MY_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, SizeT *srcLen, + const unsigned char *props, size_t propsSize); + +#endif diff --git a/src/external/OpenCTM-1.0.3/lib/liblzma/NameMangle.h b/src/external/OpenCTM-1.0.3/lib/liblzma/NameMangle.h new file mode 100644 index 000000000..669d3c4ac --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/liblzma/NameMangle.h @@ -0,0 +1,84 @@ +/* NameMangle.h -- Name mangling to avoid linking conflicts +2009-04-15 : Marcus Geelnard : Public domain */ + +#ifndef __7Z_NAMEMANGLE_H +#define __7Z_NAMEMANGLE_H + +#ifdef LZMA_PREFIX_CTM + +/* Alloc.c */ +#define MyAlloc _ctm_MyAlloc +#define MyFree _ctm_MyFree +#ifdef _WIN32 +#define MidAlloc _ctm_MidAlloc +#define MidFree _ctm_MidFree +#define SetLargePageSize _ctm_SetLargePageSize +#define BigAlloc _ctm_BigAlloc +#define BigFree _ctm_BigFree +#endif /* _WIN32 */ + +/* LzFind.c */ +#define MatchFinder_GetPointerToCurrentPos _ctm_MatchFinder_GetPointerToCurrentPos +#define MatchFinder_GetIndexByte _ctm_MatchFinder_GetIndexByte +#define MatchFinder_GetNumAvailableBytes _ctm_MatchFinder_GetNumAvailableBytes +#define MatchFinder_ReduceOffsets _ctm_MatchFinder_ReduceOffsets +#define MatchFinder_MoveBlock _ctm_MatchFinder_MoveBlock +#define MatchFinder_NeedMove _ctm_MatchFinder_NeedMove +#define MatchFinder_ReadIfRequired _ctm_MatchFinder_ReadIfRequired +#define MatchFinder_Construct _ctm_MatchFinder_Construct +#define MatchFinder_Free _ctm_MatchFinder_Free +#define MatchFinder_Create _ctm_MatchFinder_Create +#define MatchFinder_Init _ctm_MatchFinder_Init +#define MatchFinder_Normalize3 _ctm_MatchFinder_Normalize3 +#define GetMatchesSpec1 _ctm_GetMatchesSpec1 +#define Bt3Zip_MatchFinder_GetMatches _ctm_Bt3Zip_MatchFinder_GetMatches +#define Hc3Zip_MatchFinder_GetMatches _ctm_Hc3Zip_MatchFinder_GetMatches +#define Bt3Zip_MatchFinder_Skip _ctm_Bt3Zip_MatchFinder_Skip +#define Hc3Zip_MatchFinder_Skip _ctm_Hc3Zip_MatchFinder_Skip +#define MatchFinder_CreateVTable _ctm_MatchFinder_CreateVTable + +/* LzmaDec.c */ +#define LzmaDec_InitDicAndState _ctm_LzmaDec_InitDicAndState +#define LzmaDec_Init _ctm_LzmaDec_Init +#define LzmaDec_DecodeToDic _ctm_LzmaDec_DecodeToDic +#define LzmaDec_DecodeToBuf _ctm_LzmaDec_DecodeToBuf +#define LzmaDec_FreeProbs _ctm_LzmaDec_FreeProbs +#define LzmaDec_Free _ctm_LzmaDec_Free +#define LzmaProps_Decode _ctm_LzmaProps_Decode +#define LzmaDec_AllocateProbs _ctm_LzmaDec_AllocateProbs +#define LzmaDec_Allocate _ctm_LzmaDec_Allocate +#define LzmaDecode _ctm_LzmaDecode + +/* LzmaEnc.c */ +#define LzmaEncProps_Init _ctm_LzmaEncProps_Init +#define LzmaEncProps_Normalize _ctm_LzmaEncProps_Normalize +#define LzmaEncProps_GetDictSize _ctm_LzmaEncProps_GetDictSize +#define LzmaEnc_FastPosInit _ctm_LzmaEnc_FastPosInit +#define LzmaEnc_SaveState _ctm_LzmaEnc_SaveState +#define LzmaEnc_RestoreState _ctm_LzmaEnc_RestoreState +#define LzmaEnc_SetProps _ctm_LzmaEnc_SetProps +#define LzmaEnc_InitPriceTables _ctm_LzmaEnc_InitPriceTables +#define LzmaEnc_Construct _ctm_LzmaEnc_Construct +#define LzmaEnc_Create _ctm_LzmaEnc_Create +#define LzmaEnc_FreeLits _ctm_LzmaEnc_FreeLits +#define LzmaEnc_Destruct _ctm_LzmaEnc_Destruct +#define LzmaEnc_Destroy _ctm_LzmaEnc_Destroy +#define LzmaEnc_Init _ctm_LzmaEnc_Init +#define LzmaEnc_InitPrices _ctm_LzmaEnc_InitPrices +#define LzmaEnc_PrepareForLzma2 _ctm_LzmaEnc_PrepareForLzma2 +#define LzmaEnc_MemPrepare _ctm_LzmaEnc_MemPrepare +#define LzmaEnc_Finish _ctm_LzmaEnc_Finish +#define LzmaEnc_GetNumAvailableBytes _ctm_LzmaEnc_GetNumAvailableBytes +#define LzmaEnc_GetCurBuf _ctm_LzmaEnc_GetCurBuf +#define LzmaEnc_CodeOneMemBlock _ctm_LzmaEnc_CodeOneMemBlock +#define LzmaEnc_Encode _ctm_LzmaEnc_Encode +#define LzmaEnc_WriteProperties _ctm_LzmaEnc_WriteProperties +#define LzmaEnc_MemEncode _ctm_LzmaEnc_MemEncode + +/* LzmaLib.c */ +#define LzmaCompress _ctm_LzmaCompress +#define LzmaUncompress _ctm_LzmaUncompress + +#endif /* LZMA_PREFIX_CTM */ + +#endif /* __7Z_NAMEMANGLE_H */ diff --git a/src/external/OpenCTM-1.0.3/lib/liblzma/Types.h b/src/external/OpenCTM-1.0.3/lib/liblzma/Types.h new file mode 100644 index 000000000..ea00a9f8a --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/liblzma/Types.h @@ -0,0 +1,210 @@ +/* Types.h -- Basic types +2008-11-23 : Igor Pavlov : Public domain */ + +#ifndef __7Z_TYPES_H +#define __7Z_TYPES_H + +#include + +#ifdef _WIN32 +#include +#endif + +#include "NameMangle.h" + +#define SZ_OK 0 + +#define SZ_ERROR_DATA 1 +#define SZ_ERROR_MEM 2 +#define SZ_ERROR_CRC 3 +#define SZ_ERROR_UNSUPPORTED 4 +#define SZ_ERROR_PARAM 5 +#define SZ_ERROR_INPUT_EOF 6 +#define SZ_ERROR_OUTPUT_EOF 7 +#define SZ_ERROR_READ 8 +#define SZ_ERROR_WRITE 9 +#define SZ_ERROR_PROGRESS 10 +#define SZ_ERROR_FAIL 11 +#define SZ_ERROR_THREAD 12 + +#define SZ_ERROR_ARCHIVE 16 +#define SZ_ERROR_NO_ARCHIVE 17 + +typedef int SRes; + +#ifdef _WIN32 +typedef DWORD WRes; +#else +typedef int WRes; +#endif + +#ifndef RINOK +#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } +#endif + +typedef unsigned char Byte; +typedef short Int16; +typedef unsigned short UInt16; + +#ifdef _LZMA_UINT32_IS_ULONG +typedef long Int32; +typedef unsigned long UInt32; +#else +typedef int Int32; +typedef unsigned int UInt32; +#endif + +#ifdef _SZ_NO_INT_64 + +/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. + NOTES: Some code will work incorrectly in that case! */ + +typedef long Int64; +typedef unsigned long UInt64; + +#else + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#else +typedef long long int Int64; +typedef unsigned long long int UInt64; +#endif + +#endif + +#ifdef _LZMA_NO_SYSTEM_SIZE_T +typedef UInt32 SizeT; +#else +typedef size_t SizeT; +#endif + +typedef int Bool; +#define True 1 +#define False 0 + + +#ifdef _MSC_VER + +#if _MSC_VER >= 1300 +#define MY_NO_INLINE __declspec(noinline) +#else +#define MY_NO_INLINE +#endif + +#define MY_CDECL __cdecl +#define MY_STD_CALL __stdcall +#define MY_FAST_CALL MY_NO_INLINE __fastcall + +#else + +#define MY_CDECL +#define MY_STD_CALL +#define MY_FAST_CALL + +#endif + + +/* The following interfaces use first parameter as pointer to structure */ + +typedef struct +{ + SRes (*Read)(void *p, void *buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) < input(*size)) is allowed */ +} ISeqInStream; + +/* it can return SZ_ERROR_INPUT_EOF */ +SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); +SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); +SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); + +typedef struct +{ + size_t (*Write)(void *p, const void *buf, size_t size); + /* Returns: result - the number of actually written bytes. + (result < size) means error */ +} ISeqOutStream; + +typedef enum +{ + SZ_SEEK_SET = 0, + SZ_SEEK_CUR = 1, + SZ_SEEK_END = 2 +} ESzSeek; + +typedef struct +{ + SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ + SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); +} ISeekInStream; + +typedef struct +{ + SRes (*Look)(void *p, void **buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) > input(*size)) is not allowed + (output(*size) < input(*size)) is allowed */ + SRes (*Skip)(void *p, size_t offset); + /* offset must be <= output(*size) of Look */ + + SRes (*Read)(void *p, void *buf, size_t *size); + /* reads directly (without buffer). It's same as ISeqInStream::Read */ + SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); +} ILookInStream; + +SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); +SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); + +/* reads via ILookInStream::Read */ +SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); +SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); + +#define LookToRead_BUF_SIZE (1 << 14) + +typedef struct +{ + ILookInStream s; + ISeekInStream *realStream; + size_t pos; + size_t size; + Byte buf[LookToRead_BUF_SIZE]; +} CLookToRead; + +void LookToRead_CreateVTable(CLookToRead *p, int lookahead); +void LookToRead_Init(CLookToRead *p); + +typedef struct +{ + ISeqInStream s; + ILookInStream *realStream; +} CSecToLook; + +void SecToLook_CreateVTable(CSecToLook *p); + +typedef struct +{ + ISeqInStream s; + ILookInStream *realStream; +} CSecToRead; + +void SecToRead_CreateVTable(CSecToRead *p); + +typedef struct +{ + SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); + /* Returns: result. (result != SZ_OK) means break. + Value (UInt64)(Int64)-1 for size means unknown value. */ +} ICompressProgress; + +typedef struct +{ + void *(*Alloc)(void *p, size_t size); + void (*Free)(void *p, void *address); /* address can be 0 */ +} ISzAlloc; + +#define IAlloc_Alloc(p, size) (p)->Alloc((p), size) +#define IAlloc_Free(p, a) (p)->Free((p), a) + +#endif diff --git a/src/external/OpenCTM-1.0.3/lib/liblzma/readme.txt b/src/external/OpenCTM-1.0.3/lib/liblzma/readme.txt new file mode 100644 index 000000000..8198e6601 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/liblzma/readme.txt @@ -0,0 +1,7 @@ +This is the C library implementation of LZMA compression/decompression by Igor Pavlov. + +Author: Igor Pavlov +License: Public domain +Version: 4.65 (2009-02-03) + +Some administrative adaptations for integration in OpenCTM were made by Marcus Geelnard. diff --git a/src/external/OpenCTM-1.0.3/lib/openctm-mingw1.def b/src/external/OpenCTM-1.0.3/lib/openctm-mingw1.def new file mode 100644 index 000000000..e3b281070 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/openctm-mingw1.def @@ -0,0 +1,32 @@ +LIBRARY openctm.dll +EXPORTS + ctmAddAttribMap = ctmAddAttribMap@12 @1 + ctmAddUVMap = ctmAddUVMap@16 @2 + ctmAttribPrecision = ctmAttribPrecision@12 @3 + ctmCompressionLevel = ctmCompressionLevel@8 @4 + ctmCompressionMethod = ctmCompressionMethod@8 @5 + ctmDefineMesh = ctmDefineMesh@24 @6 + ctmFileComment = ctmFileComment@8 @7 + ctmFreeContext = ctmFreeContext@4 @8 + ctmGetAttribMapFloat = ctmGetAttribMapFloat@12 @9 + ctmGetAttribMapString = ctmGetAttribMapString@12 @10 + ctmGetError = ctmGetError@4 @11 + ctmGetFloat = ctmGetFloat@8 @12 + ctmGetFloatArray = ctmGetFloatArray@8 @13 + ctmGetInteger = ctmGetInteger@8 @14 + ctmGetIntegerArray = ctmGetIntegerArray@8 @15 + ctmGetNamedAttribMap = ctmGetNamedAttribMap@8 @16 + ctmGetNamedUVMap = ctmGetNamedUVMap@8 @17 + ctmGetString = ctmGetString@8 @18 + ctmGetUVMapFloat = ctmGetUVMapFloat@12 @19 + ctmGetUVMapString = ctmGetUVMapString@12 @20 + ctmErrorString = ctmErrorString@4 @21 + ctmLoad = ctmLoad@8 @22 + ctmLoadCustom = ctmLoadCustom@12 @23 + ctmNewContext = ctmNewContext@4 @24 + ctmNormalPrecision = ctmNormalPrecision@8 @25 + ctmSave = ctmSave@8 @26 + ctmSaveCustom = ctmSaveCustom@12 @27 + ctmUVCoordPrecision = ctmUVCoordPrecision@12 @28 + ctmVertexPrecision = ctmVertexPrecision@8 @29 + ctmVertexPrecisionRel = ctmVertexPrecisionRel@8 @30 diff --git a/src/external/OpenCTM-1.0.3/lib/openctm-mingw2.def b/src/external/OpenCTM-1.0.3/lib/openctm-mingw2.def new file mode 100644 index 000000000..8eb12f6fd --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/openctm-mingw2.def @@ -0,0 +1,32 @@ +LIBRARY openctm.dll +EXPORTS + ctmAddAttribMap@12 @1 + ctmAddUVMap@16 @2 + ctmAttribPrecision@12 @3 + ctmCompressionLevel@8 @4 + ctmCompressionMethod@8 @5 + ctmDefineMesh@24 @6 + ctmFileComment@8 @7 + ctmFreeContext@4 @8 + ctmGetAttribMapFloat@12 @9 + ctmGetAttribMapString@12 @10 + ctmGetError@4 @11 + ctmGetFloat@8 @12 + ctmGetFloatArray@8 @13 + ctmGetInteger@8 @14 + ctmGetIntegerArray@8 @15 + ctmGetNamedAttribMap@8 @16 + ctmGetNamedUVMap@8 @17 + ctmGetString@8 @18 + ctmGetUVMapFloat@12 @19 + ctmGetUVMapString@12 @20 + ctmErrorString@4 @21 + ctmLoad@8 @22 + ctmLoadCustom@12 @23 + ctmNewContext@4 @24 + ctmNormalPrecision@8 @25 + ctmSave@8 @26 + ctmSaveCustom@12 @27 + ctmUVCoordPrecision@12 @28 + ctmVertexPrecision@8 @29 + ctmVertexPrecisionRel@8 @30 diff --git a/src/external/OpenCTM-1.0.3/lib/openctm-msvc.def b/src/external/OpenCTM-1.0.3/lib/openctm-msvc.def new file mode 100644 index 000000000..bb66dbdfe --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/openctm-msvc.def @@ -0,0 +1,32 @@ +LIBRARY openctm.dll +EXPORTS + ctmAddAttribMap + ctmAddUVMap + ctmAttribPrecision + ctmCompressionLevel + ctmCompressionMethod + ctmDefineMesh + ctmFileComment + ctmFreeContext + ctmGetAttribMapFloat + ctmGetAttribMapString + ctmGetError + ctmGetFloat + ctmGetFloatArray + ctmGetInteger + ctmGetIntegerArray + ctmGetNamedAttribMap + ctmGetNamedUVMap + ctmGetString + ctmGetUVMapFloat + ctmGetUVMapString + ctmErrorString + ctmLoad + ctmLoadCustom + ctmNewContext + ctmNormalPrecision + ctmSave + ctmSaveCustom + ctmUVCoordPrecision + ctmVertexPrecision + ctmVertexPrecisionRel diff --git a/src/external/OpenCTM-1.0.3/lib/openctm.c b/src/external/OpenCTM-1.0.3/lib/openctm.c new file mode 100644 index 000000000..3c0acd9ef --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/openctm.c @@ -0,0 +1,1423 @@ +//----------------------------------------------------------------------------- +// Product: OpenCTM +// File: openctm.c +// Description: API functions. +//----------------------------------------------------------------------------- +// Copyright (c) 2009-2010 Marcus Geelnard +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +//----------------------------------------------------------------------------- + +#include +#include +#include +#include +#include "openctm.h" +#include "internal.h" + + +// The C99 macro isfinite() is not supported on all platforms (specifically, +// MS Visual Studio does not support C99) +#if !defined(isfinite) && defined(_MSC_VER) + #include + #define isfinite(x) _finite(x) +#endif + + +//----------------------------------------------------------------------------- +// _ctmFreeMapList() - Free a float map list. +//----------------------------------------------------------------------------- +static void _ctmFreeMapList(_CTMcontext * self, _CTMfloatmap * aMapList) +{ + _CTMfloatmap * map, * nextMap; + map = aMapList; + while(map) + { + // Free internally allocated array (if we are in import mode) + if((self->mMode == CTM_IMPORT) && map->mValues) + free(map->mValues); + + // Free map name + if(map->mName) + free(map->mName); + + // Free file name + if(map->mFileName) + free(map->mFileName); + + nextMap = map->mNext; + free(map); + map = nextMap; + } +} + +//----------------------------------------------------------------------------- +// _ctmClearMesh() - Clear the mesh in a CTM context. +//----------------------------------------------------------------------------- +static void _ctmClearMesh(_CTMcontext * self) +{ + // Free internally allocated mesh arrays + if(self->mMode == CTM_IMPORT) + { + if(self->mVertices) + free(self->mVertices); + if(self->mIndices) + free(self->mIndices); + if(self->mNormals) + free(self->mNormals); + } + + // Clear externally assigned mesh arrays + self->mVertices = (CTMfloat *) 0; + self->mVertexCount = 0; + self->mIndices = (CTMuint *) 0; + self->mTriangleCount = 0; + self->mNormals = (CTMfloat *) 0; + + // Free UV coordinate map list + _ctmFreeMapList(self, self->mUVMaps); + self->mUVMaps = (_CTMfloatmap *) 0; + self->mUVMapCount = 0; + + // Free attribute map list + _ctmFreeMapList(self, self->mAttribMaps); + self->mAttribMaps = (_CTMfloatmap *) 0; + self->mAttribMapCount = 0; +} + +//----------------------------------------------------------------------------- +// _ctmCheckMeshIntegrity() - Check if a mesh is valid (i.e. is non-empty, and +// contains valid data). +//----------------------------------------------------------------------------- + +static CTMint _ctmCheckMeshIntegrity(_CTMcontext * self) +{ + CTMuint i; + _CTMfloatmap * map; + + // Check that we have all the mandatory data + if(!self->mVertices || !self->mIndices || (self->mVertexCount < 1) || + (self->mTriangleCount < 1)) + { + return CTM_FALSE; + } + + // Check that all indices are within range + for(i = 0; i < (self->mTriangleCount * 3); ++ i) + { + if(self->mIndices[i] >= self->mVertexCount) + { + return CTM_FALSE; + } + } + + // Check that all vertices are finite (non-NaN, non-inf) + for(i = 0; i < self->mVertexCount * 3; ++ i) + { + if(!isfinite(self->mVertices[i])) + { + return CTM_FALSE; + } + } + + // Check that all normals are finite (non-NaN, non-inf) + if(self->mNormals) + { + for(i = 0; i < self->mVertexCount * 3; ++ i) + { + if(!isfinite(self->mNormals[i])) + { + return CTM_FALSE; + } + } + } + + // Check that all UV maps are finite (non-NaN, non-inf) + map = self->mUVMaps; + while(map) + { + for(i = 0; i < self->mVertexCount * 2; ++ i) + { + if(!isfinite(map->mValues[i])) + { + return CTM_FALSE; + } + } + map = map->mNext; + } + + // Check that all attribute maps are finite (non-NaN, non-inf) + map = self->mAttribMaps; + while(map) + { + for(i = 0; i < self->mVertexCount * 4; ++ i) + { + if(!isfinite(map->mValues[i])) + { + return CTM_FALSE; + } + } + map = map->mNext; + } + + return CTM_TRUE; +} + +//----------------------------------------------------------------------------- +// ctmNewContext() +//----------------------------------------------------------------------------- +CTMEXPORT CTMcontext CTMCALL ctmNewContext(CTMenum aMode) +{ + _CTMcontext * self; + + // Allocate memory for the new structure + self = (_CTMcontext *) malloc(sizeof(_CTMcontext)); + + // Initialize structure (set null pointers and zero array lengths) + memset(self, 0, sizeof(_CTMcontext)); + self->mMode = aMode; + self->mError = CTM_NONE; + self->mMethod = CTM_METHOD_MG1; + self->mCompressionLevel = 1; + self->mVertexPrecision = 1.0f / 1024.0f; + self->mNormalPrecision = 1.0f / 256.0f; + + return (CTMcontext) self; +} + +//----------------------------------------------------------------------------- +// ctmFreeContext() +//----------------------------------------------------------------------------- +CTMEXPORT void CTMCALL ctmFreeContext(CTMcontext aContext) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + if(!self) return; + + // Free all mesh resources + _ctmClearMesh(self); + + // Free the file comment + if(self->mFileComment) + free(self->mFileComment); + + // Free the context + free(self); +} + +//----------------------------------------------------------------------------- +// ctmGetError() +//----------------------------------------------------------------------------- +CTMEXPORT CTMenum CTMCALL ctmGetError(CTMcontext aContext) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + CTMenum err; + + if(!self) return CTM_INVALID_CONTEXT; + + // Get error code and reset error state + err = self->mError; + self->mError = CTM_NONE; + return err; +} + +//----------------------------------------------------------------------------- +// ctmErrorString() +//----------------------------------------------------------------------------- +CTMEXPORT const char * CTMCALL ctmErrorString(CTMenum aError) +{ + switch(aError) + { + case CTM_INVALID_CONTEXT: + return "CTM_INVALID_CONTEXT"; + case CTM_INVALID_ARGUMENT: + return "CTM_INVALID_ARGUMENT"; + case CTM_INVALID_OPERATION: + return "CTM_INVALID_OPERATION"; + case CTM_INVALID_MESH: + return "CTM_INVALID_MESH"; + case CTM_OUT_OF_MEMORY: + return "CTM_OUT_OF_MEMORY"; + case CTM_FILE_ERROR: + return "CTM_FILE_ERROR"; + case CTM_BAD_FORMAT: + return "CTM_BAD_FORMAT"; + case CTM_LZMA_ERROR: + return "CTM_LZMA_ERROR"; + case CTM_INTERNAL_ERROR: + return "CTM_INTERNAL_ERROR"; + case CTM_UNSUPPORTED_FORMAT_VERSION: + return "CTM_UNSUPPORTED_FORMAT_VERSION"; + default: + return "Unknown error code"; + } +} + +//----------------------------------------------------------------------------- +// ctmGetInteger() +//----------------------------------------------------------------------------- +CTMEXPORT CTMuint CTMCALL ctmGetInteger(CTMcontext aContext, CTMenum aProperty) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + if(!self) return 0; + + switch(aProperty) + { + case CTM_VERTEX_COUNT: + return self->mVertexCount; + + case CTM_TRIANGLE_COUNT: + return self->mTriangleCount; + + case CTM_UV_MAP_COUNT: + return self->mUVMapCount; + + case CTM_ATTRIB_MAP_COUNT: + return self->mAttribMapCount; + + case CTM_HAS_NORMALS: + return self->mNormals ? CTM_TRUE : CTM_FALSE; + + case CTM_COMPRESSION_METHOD: + return (CTMuint) self->mMethod; + + default: + self->mError = CTM_INVALID_ARGUMENT; + } + + return 0; +} + +//----------------------------------------------------------------------------- +// ctmGetFloat() +//----------------------------------------------------------------------------- +CTMEXPORT CTMfloat CTMCALL ctmGetFloat(CTMcontext aContext, CTMenum aProperty) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + if(!self) return 0.0f; + + switch(aProperty) + { + case CTM_VERTEX_PRECISION: + return self->mVertexPrecision; + + case CTM_NORMAL_PRECISION: + return self->mNormalPrecision; + + default: + self->mError = CTM_INVALID_ARGUMENT; + } + + return 0.0f; +} + +//----------------------------------------------------------------------------- +// ctmGetIntegerArray() +//----------------------------------------------------------------------------- +CTMEXPORT const CTMuint * CTMCALL ctmGetIntegerArray(CTMcontext aContext, + CTMenum aProperty) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + if(!self) return (CTMuint *) 0; + + switch(aProperty) + { + case CTM_INDICES: + return self->mIndices; + + default: + self->mError = CTM_INVALID_ARGUMENT; + } + + return (CTMuint *) 0; +} + +//----------------------------------------------------------------------------- +// ctmGetFloatArray() +//----------------------------------------------------------------------------- +CTMEXPORT const CTMfloat * CTMCALL ctmGetFloatArray(CTMcontext aContext, + CTMenum aProperty) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + _CTMfloatmap * map; + CTMuint i; + if(!self) return (CTMfloat *) 0; + + // Did the user request a UV map? + if((aProperty >= CTM_UV_MAP_1) && + ((CTMuint)(aProperty - CTM_UV_MAP_1) < self->mUVMapCount)) + { + map = self->mUVMaps; + i = CTM_UV_MAP_1; + while(map && (i != aProperty)) + { + map = map->mNext; + ++ i; + } + if(!map) + { + self->mError = CTM_INTERNAL_ERROR; + return (CTMfloat *) 0; + } + return map->mValues; + } + + // Did the user request an attribute map? + if((aProperty >= CTM_ATTRIB_MAP_1) && + ((CTMuint)(aProperty - CTM_ATTRIB_MAP_1) < self->mAttribMapCount)) + { + map = self->mAttribMaps; + i = CTM_ATTRIB_MAP_1; + while(map && (i != aProperty)) + { + map = map->mNext; + ++ i; + } + if(!map) + { + self->mError = CTM_INTERNAL_ERROR; + return (CTMfloat *) 0; + } + return map->mValues; + } + + switch(aProperty) + { + case CTM_VERTICES: + return self->mVertices; + + case CTM_NORMALS: + return self->mNormals; + + default: + self->mError = CTM_INVALID_ARGUMENT; + } + + return (CTMfloat *) 0; +} + +//----------------------------------------------------------------------------- +// ctmGetNamedUVMap() +//----------------------------------------------------------------------------- +CTMEXPORT CTMenum CTMCALL ctmGetNamedUVMap(CTMcontext aContext, + const char * aName) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + _CTMfloatmap * map; + CTMuint result; + if(!self) return CTM_NONE; + + map = self->mUVMaps; + result = CTM_UV_MAP_1; + while(map && (strcmp(aName, map->mName) != 0)) + { + map = map->mNext; + ++ result; + } + if(!map) + { + return CTM_NONE; + } + return result; +} + +//----------------------------------------------------------------------------- +// ctmGetUVMapString() +//----------------------------------------------------------------------------- +CTMEXPORT const char * CTMCALL ctmGetUVMapString(CTMcontext aContext, + CTMenum aUVMap, CTMenum aProperty) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + _CTMfloatmap * map; + CTMuint i; + if(!self) return (const char *) 0; + + // Find the indicated map + map = self->mUVMaps; + i = CTM_UV_MAP_1; + while(map && (i != aUVMap)) + { + ++ i; + map = map->mNext; + } + if(!map) + { + self->mError = CTM_INVALID_ARGUMENT; + return (const char *) 0; + } + + // Get the requested string + switch(aProperty) + { + case CTM_NAME: + return (const char *) map->mName; + + case CTM_FILE_NAME: + return (const char *) map->mFileName; + + default: + self->mError = CTM_INVALID_ARGUMENT; + } + + return (const char *) 0; +} + +//----------------------------------------------------------------------------- +// ctmGetUVMapFloat() +//----------------------------------------------------------------------------- +CTMEXPORT CTMfloat CTMCALL ctmGetUVMapFloat(CTMcontext aContext, + CTMenum aUVMap, CTMenum aProperty) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + _CTMfloatmap * map; + CTMuint i; + if(!self) return 0.0f; + + // Find the indicated map + map = self->mUVMaps; + i = CTM_UV_MAP_1; + while(map && (i != aUVMap)) + { + ++ i; + map = map->mNext; + } + if(!map) + { + self->mError = CTM_INVALID_ARGUMENT; + return 0.0f; + } + + // Get the requested string + switch(aProperty) + { + case CTM_PRECISION: + return map->mPrecision; + + default: + self->mError = CTM_INVALID_ARGUMENT; + } + + return 0.0f; +} + +//----------------------------------------------------------------------------- +// ctmGetAttribMapString() +//----------------------------------------------------------------------------- +CTMEXPORT const char * CTMCALL ctmGetAttribMapString(CTMcontext aContext, + CTMenum aAttribMap, CTMenum aProperty) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + _CTMfloatmap * map; + CTMuint i; + if(!self) return (const char *) 0; + + // Find the indicated map + map = self->mAttribMaps; + i = CTM_ATTRIB_MAP_1; + while(map && (i != aAttribMap)) + { + ++ i; + map = map->mNext; + } + if(!map) + { + self->mError = CTM_INVALID_ARGUMENT; + return (const char *) 0; + } + + // Get the requested string + switch(aProperty) + { + case CTM_NAME: + return (const char *) map->mName; + + default: + self->mError = CTM_INVALID_ARGUMENT; + } + + return (const char *) 0; +} + +//----------------------------------------------------------------------------- +// ctmGetAttribMapFloat() +//----------------------------------------------------------------------------- +CTMEXPORT CTMfloat CTMCALL ctmGetAttribMapFloat(CTMcontext aContext, + CTMenum aAttribMap, CTMenum aProperty) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + _CTMfloatmap * map; + CTMuint i; + if(!self) return 0.0f; + + // Find the indicated map + map = self->mAttribMaps; + i = CTM_ATTRIB_MAP_1; + while(map && (i != aAttribMap)) + { + ++ i; + map = map->mNext; + } + if(!map) + { + self->mError = CTM_INVALID_ARGUMENT; + return 0.0f; + } + + // Get the requested string + switch(aProperty) + { + case CTM_PRECISION: + return map->mPrecision; + + default: + self->mError = CTM_INVALID_ARGUMENT; + } + + return 0.0f; +} + +//----------------------------------------------------------------------------- +// ctmGetNamedAttribMap() +//----------------------------------------------------------------------------- +CTMEXPORT CTMenum CTMCALL ctmGetNamedAttribMap(CTMcontext aContext, + const char * aName) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + _CTMfloatmap * map; + CTMuint result; + if(!self) return CTM_NONE; + + map = self->mAttribMaps; + result = CTM_ATTRIB_MAP_1; + while(map && (strcmp(aName, map->mName) != 0)) + { + map = map->mNext; + ++ result; + } + if(!map) + { + return CTM_NONE; + } + return result; +} + +//----------------------------------------------------------------------------- +// ctmGetString() +//----------------------------------------------------------------------------- +CTMEXPORT const char * CTMCALL ctmGetString(CTMcontext aContext, + CTMenum aProperty) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + if(!self) return 0; + + switch(aProperty) + { + case CTM_FILE_COMMENT: + return (const char *) self->mFileComment; + + default: + self->mError = CTM_INVALID_ARGUMENT; + } + + return (const char *) 0; +} + +//----------------------------------------------------------------------------- +// ctmCompressionMethod() +//----------------------------------------------------------------------------- +CTMEXPORT void CTMCALL ctmCompressionMethod(CTMcontext aContext, + CTMenum aMethod) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + if(!self) return; + + // You are only allowed to change compression attributes in export mode + if(self->mMode != CTM_EXPORT) + { + self->mError = CTM_INVALID_OPERATION; + return; + } + + // Check arguments + if((aMethod != CTM_METHOD_RAW) && (aMethod != CTM_METHOD_MG1) && + (aMethod != CTM_METHOD_MG2)) + { + self->mError = CTM_INVALID_ARGUMENT; + return; + } + + // Set method + self->mMethod = aMethod; +} + +//----------------------------------------------------------------------------- +// ctmCompressionLevel() +//----------------------------------------------------------------------------- +CTMEXPORT void CTMCALL ctmCompressionLevel(CTMcontext aContext, + CTMuint aLevel) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + if(!self) return; + + // You are only allowed to change compression attributes in export mode + if(self->mMode != CTM_EXPORT) + { + self->mError = CTM_INVALID_OPERATION; + return; + } + + // Check arguments + if(aLevel > 9) + { + self->mError = CTM_INVALID_ARGUMENT; + return; + } + + // Set the compression level + self->mCompressionLevel = aLevel; +} + +//----------------------------------------------------------------------------- +// ctmVertexPrecision() +//----------------------------------------------------------------------------- +CTMEXPORT void CTMCALL ctmVertexPrecision(CTMcontext aContext, + CTMfloat aPrecision) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + if(!self) return; + + // You are only allowed to change compression attributes in export mode + if(self->mMode != CTM_EXPORT) + { + self->mError = CTM_INVALID_OPERATION; + return; + } + + // Check arguments + if(aPrecision <= 0.0f) + { + self->mError = CTM_INVALID_ARGUMENT; + return; + } + + // Set precision + self->mVertexPrecision = aPrecision; +} + +//----------------------------------------------------------------------------- +// ctmVertexPrecisionRel() +//----------------------------------------------------------------------------- +CTMEXPORT void CTMCALL ctmVertexPrecisionRel(CTMcontext aContext, + CTMfloat aRelPrecision) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + CTMfloat avgEdgeLength, * p1, * p2; + CTMuint edgeCount, i, j; + if(!self) return; + + // You are only allowed to change compression attributes in export mode + if(self->mMode != CTM_EXPORT) + { + self->mError = CTM_INVALID_OPERATION; + return; + } + + // Check arguments + if(aRelPrecision <= 0.0f) + { + self->mError = CTM_INVALID_ARGUMENT; + return; + } + + // Calculate the average edge length (Note: we actually sum up all the half- + // edges, so in a proper solid mesh all connected edges are counted twice) + avgEdgeLength = 0.0f; + edgeCount = 0; + for(i = 0; i < self->mTriangleCount; ++ i) + { + p1 = &self->mVertices[self->mIndices[i * 3 + 2] * 3]; + for(j = 0; j < 3; ++ j) + { + p2 = &self->mVertices[self->mIndices[i * 3 + j] * 3]; + avgEdgeLength += sqrtf((p2[0] - p1[0]) * (p2[0] - p1[0]) + + (p2[1] - p1[1]) * (p2[1] - p1[1]) + + (p2[2] - p1[2]) * (p2[2] - p1[2])); + p1 = p2; + ++ edgeCount; + } + } + if(edgeCount == 0) + { + self->mError = CTM_INVALID_MESH; + return; + } + avgEdgeLength /= (CTMfloat) edgeCount; + + // Set precision + self->mVertexPrecision = aRelPrecision * avgEdgeLength; +} + +//----------------------------------------------------------------------------- +// ctmNormalPrecision() +//----------------------------------------------------------------------------- +CTMEXPORT void CTMCALL ctmNormalPrecision(CTMcontext aContext, + CTMfloat aPrecision) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + if(!self) return; + + // You are only allowed to change compression attributes in export mode + if(self->mMode != CTM_EXPORT) + { + self->mError = CTM_INVALID_OPERATION; + return; + } + + // Check arguments + if(aPrecision <= 0.0f) + { + self->mError = CTM_INVALID_ARGUMENT; + return; + } + + // Set precision + self->mNormalPrecision = aPrecision; +} + +//----------------------------------------------------------------------------- +// ctmUVCoordPrecision() +//----------------------------------------------------------------------------- +CTMEXPORT void CTMCALL ctmUVCoordPrecision(CTMcontext aContext, + CTMenum aUVMap, CTMfloat aPrecision) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + _CTMfloatmap * map; + CTMuint i; + if(!self) return; + + // You are only allowed to change compression attributes in export mode + if(self->mMode != CTM_EXPORT) + { + self->mError = CTM_INVALID_OPERATION; + return; + } + + // Check arguments + if(aPrecision <= 0.0f) + { + self->mError = CTM_INVALID_ARGUMENT; + return; + } + + // Find the indicated map + map = self->mUVMaps; + i = CTM_UV_MAP_1; + while(map && (i != aUVMap)) + { + ++ i; + map = map->mNext; + } + if(!map) + { + self->mError = CTM_INVALID_ARGUMENT; + return; + } + + // Update the precision + map->mPrecision = aPrecision; +} + +//----------------------------------------------------------------------------- +// ctmAttribPrecision() +//----------------------------------------------------------------------------- +CTMEXPORT void CTMCALL ctmAttribPrecision(CTMcontext aContext, + CTMenum aAttribMap, CTMfloat aPrecision) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + _CTMfloatmap * map; + CTMuint i; + if(!self) return; + + // You are only allowed to change compression attributes in export mode + if(self->mMode != CTM_EXPORT) + { + self->mError = CTM_INVALID_OPERATION; + return; + } + + // Check arguments + if(aPrecision <= 0.0f) + { + self->mError = CTM_INVALID_ARGUMENT; + return; + } + + // Find the indicated map + map = self->mAttribMaps; + i = CTM_ATTRIB_MAP_1; + while(map && (i != aAttribMap)) + { + ++ i; + map = map->mNext; + } + if(!map) + { + self->mError = CTM_INVALID_ARGUMENT; + return; + } + + // Update the precision + map->mPrecision = aPrecision; +} + +//----------------------------------------------------------------------------- +// ctmFileComment() +//----------------------------------------------------------------------------- +CTMEXPORT void CTMCALL ctmFileComment(CTMcontext aContext, + const char * aFileComment) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + int len; + if(!self) return; + + // You are only allowed to change file attributes in export mode + if(self->mMode != CTM_EXPORT) + { + self->mError = CTM_INVALID_OPERATION; + return; + } + + // Free the old comment string, if necessary + if(self->mFileComment) + { + free(self->mFileComment); + self->mFileComment = (char *) 0; + } + + // Get length of string (if empty, do nothing) + if(!aFileComment) + return; + len = strlen(aFileComment); + if(!len) + return; + + // Copy the string + self->mFileComment = (char *) malloc(len + 1); + if(!self->mFileComment) + { + self->mError = CTM_OUT_OF_MEMORY; + return; + } + strcpy(self->mFileComment, aFileComment); +} + +//----------------------------------------------------------------------------- +// ctmDefineMesh() +//----------------------------------------------------------------------------- +CTMEXPORT void CTMCALL ctmDefineMesh(CTMcontext aContext, + const CTMfloat * aVertices, CTMuint aVertexCount, const CTMuint * aIndices, + CTMuint aTriangleCount, const CTMfloat * aNormals) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + if(!self) return; + + // You are only allowed to (re)define the mesh in export mode + if(self->mMode != CTM_EXPORT) + { + self->mError = CTM_INVALID_OPERATION; + return; + } + + // Check arguments + if(!aVertices || !aIndices || !aVertexCount || !aTriangleCount) + { + self->mError = CTM_INVALID_ARGUMENT; + return; + } + + // Clear the old mesh, if any + _ctmClearMesh(self); + + // Set vertex array pointer + self->mVertices = (CTMfloat *) aVertices; + self->mVertexCount = aVertexCount; + + // Set index array pointer + self->mIndices = (CTMuint *) aIndices; + self->mTriangleCount = aTriangleCount; + + // Set normal array pointer + self->mNormals = (CTMfloat *) aNormals; +} + +//----------------------------------------------------------------------------- +// _ctmAddFloatMap() +//----------------------------------------------------------------------------- +static _CTMfloatmap * _ctmAddFloatMap(_CTMcontext * self, + const CTMfloat * aValues, const char * aName, const char * aFileName, + _CTMfloatmap ** aList) +{ + _CTMfloatmap * map; + CTMuint len; + + // Allocate memory for a new map list item and append it to the list + if(!*aList) + { + *aList = (_CTMfloatmap *) malloc(sizeof(_CTMfloatmap)); + map = *aList; + } + else + { + map = *aList; + while(map->mNext) + map = map->mNext; + map->mNext = (_CTMfloatmap *) malloc(sizeof(_CTMfloatmap)); + map = map->mNext; + } + if(!map) + { + self->mError = CTM_OUT_OF_MEMORY; + return (_CTMfloatmap *) 0; + } + + // Init the map item + memset(map, 0, sizeof(_CTMfloatmap)); + map->mPrecision = 1.0f / 1024.0f; + map->mValues = (CTMfloat *) aValues; + + // Set name of the map + if(aName) + { + // Get length of string (if empty, do nothing) + len = strlen(aName); + if(len) + { + // Copy the string + map->mName = (char *) malloc(len + 1); + if(!map->mName) + { + self->mError = CTM_OUT_OF_MEMORY; + free(map); + return (_CTMfloatmap *) 0; + } + strcpy(map->mName, aName); + } + } + + // Set file name reference for the map + if(aFileName) + { + // Get length of string (if empty, do nothing) + len = strlen(aFileName); + if(len) + { + // Copy the string + map->mFileName = (char *) malloc(len + 1); + if(!map->mFileName) + { + self->mError = CTM_OUT_OF_MEMORY; + if(map->mName) + free(map->mName); + free(map); + return (_CTMfloatmap *) 0; + } + strcpy(map->mFileName, aFileName); + } + } + + return map; +} + +//----------------------------------------------------------------------------- +// ctmAddUVMap() +//----------------------------------------------------------------------------- +CTMEXPORT CTMenum CTMCALL ctmAddUVMap(CTMcontext aContext, + const CTMfloat * aUVCoords, const char * aName, const char * aFileName) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + _CTMfloatmap * map; + if(!self) return CTM_NONE; + + // Add a new UV map to the UV map list + map = _ctmAddFloatMap(self, aUVCoords, aName, aFileName, &self->mUVMaps); + if(!map) + return CTM_NONE; + else + { + // The default UV coordinate precision is 2^-12 + map->mPrecision = 1.0f / 4096.0f; + ++ self->mUVMapCount; + return CTM_UV_MAP_1 + self->mUVMapCount - 1; + } +} + +//----------------------------------------------------------------------------- +// ctmAddAttribMap() +//----------------------------------------------------------------------------- +CTMEXPORT CTMenum CTMCALL ctmAddAttribMap(CTMcontext aContext, + const CTMfloat * aAttribValues, const char * aName) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + _CTMfloatmap * map; + if(!self) return CTM_NONE; + + // Add a new attribute map to the attribute map list + map = _ctmAddFloatMap(self, aAttribValues, aName, (const char *) 0, + &self->mAttribMaps); + if(!map) + return CTM_NONE; + else + { + // The default vertex attribute precision is 2^-8 + map->mPrecision = 1.0f / 256.0f; + ++ self->mAttribMapCount; + return CTM_ATTRIB_MAP_1 + self->mAttribMapCount - 1; + } +} + +//----------------------------------------------------------------------------- +// _ctmDefaultRead() +//----------------------------------------------------------------------------- +static CTMuint CTMCALL _ctmDefaultRead(void * aBuf, CTMuint aCount, + void * aUserData) +{ + return (CTMuint) fread(aBuf, 1, (size_t) aCount, (FILE *) aUserData); +} + +//----------------------------------------------------------------------------- +// ctmLoad() +//----------------------------------------------------------------------------- +CTMEXPORT void CTMCALL ctmLoad(CTMcontext aContext, const char * aFileName) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + FILE * f; + if(!self) return; + + // You are only allowed to load data in import mode + if(self->mMode != CTM_IMPORT) + { + self->mError = CTM_INVALID_OPERATION; + return; + } + + // Open file stream + f = fopen(aFileName, "rb"); + if(!f) + { + self->mError = CTM_FILE_ERROR; + return; + } + + // Load the file + ctmLoadCustom(self, _ctmDefaultRead, (void *) f); + + // Close file stream + fclose(f); +} + +//----------------------------------------------------------------------------- +// _ctmAllocateFloatMaps() +//----------------------------------------------------------------------------- +static CTMuint _ctmAllocateFloatMaps(_CTMcontext * self, + _CTMfloatmap ** aMapListPtr, CTMuint aCount, CTMuint aChannels) +{ + _CTMfloatmap ** mapListPtr; + CTMuint i, size; + + mapListPtr = aMapListPtr; + for(i = 0; i < aCount; ++ i) + { + // Allocate & clear memory for this map + *mapListPtr = (_CTMfloatmap *) malloc(sizeof(_CTMfloatmap)); + if(!*mapListPtr) + { + self->mError = CTM_OUT_OF_MEMORY; + return CTM_FALSE; + } + memset(*mapListPtr, 0, sizeof(_CTMfloatmap)); + + // Allocate & clear memory for the float array + size = aChannels * sizeof(CTMfloat) * self->mVertexCount; + (*mapListPtr)->mValues = (CTMfloat *) malloc(size); + if(!(*mapListPtr)->mValues) + { + self->mError = CTM_OUT_OF_MEMORY; + return CTM_FALSE; + } + memset((*mapListPtr)->mValues, 0, size); + + // Next map... + mapListPtr = &(*mapListPtr)->mNext; + } + + return CTM_TRUE; +} + +//----------------------------------------------------------------------------- +// ctmLoadCustom() +//----------------------------------------------------------------------------- +CTMEXPORT void CTMCALL ctmLoadCustom(CTMcontext aContext, CTMreadfn aReadFn, + void * aUserData) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + CTMuint formatVersion, flags, method; + if(!self) return; + + // You are only allowed to load data in import mode + if(self->mMode != CTM_IMPORT) + { + self->mError = CTM_INVALID_OPERATION; + return; + } + + // Initialize stream + self->mReadFn = aReadFn; + self->mUserData = aUserData; + + // Clear any old mesh arrays + _ctmClearMesh(self); + + // Read header from stream + if(_ctmStreamReadUINT(self) != FOURCC("OCTM")) + { + self->mError = CTM_BAD_FORMAT; + return; + } + formatVersion = _ctmStreamReadUINT(self); + if(formatVersion != _CTM_FORMAT_VERSION) + { + self->mError = CTM_UNSUPPORTED_FORMAT_VERSION; + return; + } + method = _ctmStreamReadUINT(self); + if(method == FOURCC("RAW\0")) + self->mMethod = CTM_METHOD_RAW; + else if(method == FOURCC("MG1\0")) + self->mMethod = CTM_METHOD_MG1; + else if(method == FOURCC("MG2\0")) + self->mMethod = CTM_METHOD_MG2; + else + { + self->mError = CTM_BAD_FORMAT; + return; + } + self->mVertexCount = _ctmStreamReadUINT(self); + if(self->mVertexCount == 0) + { + self->mError = CTM_BAD_FORMAT; + return; + } + self->mTriangleCount = _ctmStreamReadUINT(self); + if(self->mTriangleCount == 0) + { + self->mError = CTM_BAD_FORMAT; + return; + } + self->mUVMapCount = _ctmStreamReadUINT(self); + self->mAttribMapCount = _ctmStreamReadUINT(self); + flags = _ctmStreamReadUINT(self); + _ctmStreamReadSTRING(self, &self->mFileComment); + + // Allocate memory for the mesh arrays + self->mVertices = (CTMfloat *) malloc(self->mVertexCount * sizeof(CTMfloat) * 3); + if(!self->mVertices) + { + self->mError = CTM_OUT_OF_MEMORY; + return; + } + self->mIndices = (CTMuint *) malloc(self->mTriangleCount * sizeof(CTMuint) * 3); + if(!self->mIndices) + { + _ctmClearMesh(self); + self->mError = CTM_OUT_OF_MEMORY; + return; + } + if(flags & _CTM_HAS_NORMALS_BIT) + { + self->mNormals = (CTMfloat *) malloc(self->mVertexCount * sizeof(CTMfloat) * 3); + if(!self->mNormals) + { + _ctmClearMesh(self); + self->mError = CTM_OUT_OF_MEMORY; + return; + } + } + + // Allocate memory for the UV and attribute maps (if any) + if(!_ctmAllocateFloatMaps(self, &self->mUVMaps, self->mUVMapCount, 2)) + { + _ctmClearMesh(self); + self->mError = CTM_OUT_OF_MEMORY; + return; + } + if(!_ctmAllocateFloatMaps(self, &self->mAttribMaps, self->mAttribMapCount, 4)) + { + _ctmClearMesh(self); + self->mError = CTM_OUT_OF_MEMORY; + return; + } + + // Uncompress from stream + switch(self->mMethod) + { + case CTM_METHOD_RAW: + _ctmUncompressMesh_RAW(self); + break; + + case CTM_METHOD_MG1: + _ctmUncompressMesh_MG1(self); + break; + + case CTM_METHOD_MG2: + _ctmUncompressMesh_MG2(self); + break; + + default: + self->mError = CTM_INTERNAL_ERROR; + } + + // Check mesh integrity + if(!_ctmCheckMeshIntegrity(self)) + { + self->mError = CTM_INVALID_MESH; + return; + } +} + +//----------------------------------------------------------------------------- +// _ctmDefaultWrite() +//----------------------------------------------------------------------------- +static CTMuint CTMCALL _ctmDefaultWrite(const void * aBuf, CTMuint aCount, + void * aUserData) +{ + return (CTMuint) fwrite(aBuf, 1, (size_t) aCount, (FILE *) aUserData); +} + +//----------------------------------------------------------------------------- +// ctmSave() +//----------------------------------------------------------------------------- +CTMEXPORT void CTMCALL ctmSave(CTMcontext aContext, const char * aFileName) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + FILE * f; + if(!self) return; + + // You are only allowed to save data in export mode + if(self->mMode != CTM_EXPORT) + { + self->mError = CTM_INVALID_OPERATION; + return; + } + + // Open file stream + f = fopen(aFileName, "wb"); + if(!f) + { + self->mError = CTM_FILE_ERROR; + return; + } + + // Save the file + ctmSaveCustom(self, _ctmDefaultWrite, (void *) f); + + // Close file stream + fclose(f); +} + +//----------------------------------------------------------------------------- +// ctmSaveCustom() +//----------------------------------------------------------------------------- +void CTMCALL ctmSaveCustom(CTMcontext aContext, CTMwritefn aWriteFn, + void * aUserData) +{ + _CTMcontext * self = (_CTMcontext *) aContext; + CTMuint flags; + if(!self) return; + + // You are only allowed to save data in export mode + if(self->mMode != CTM_EXPORT) + { + self->mError = CTM_INVALID_OPERATION; + return; + } + + // Check mesh integrity + if(!_ctmCheckMeshIntegrity(self)) + { + self->mError = CTM_INVALID_MESH; + return; + } + + // Initialize stream + self->mWriteFn = aWriteFn; + self->mUserData = aUserData; + + // Determine flags + flags = 0; + if(self->mNormals) + flags |= _CTM_HAS_NORMALS_BIT; + + // Write header to stream + _ctmStreamWrite(self, (void *) "OCTM", 4); + _ctmStreamWriteUINT(self, _CTM_FORMAT_VERSION); + switch(self->mMethod) + { + case CTM_METHOD_RAW: + _ctmStreamWrite(self, (void *) "RAW\0", 4); + break; + + case CTM_METHOD_MG1: + _ctmStreamWrite(self, (void *) "MG1\0", 4); + break; + + case CTM_METHOD_MG2: + _ctmStreamWrite(self, (void *) "MG2\0", 4); + break; + + default: + self->mError = CTM_INTERNAL_ERROR; + return; + } + _ctmStreamWriteUINT(self, self->mVertexCount); + _ctmStreamWriteUINT(self, self->mTriangleCount); + _ctmStreamWriteUINT(self, self->mUVMapCount); + _ctmStreamWriteUINT(self, self->mAttribMapCount); + _ctmStreamWriteUINT(self, flags); + _ctmStreamWriteSTRING(self, self->mFileComment); + + // Compress to stream + switch(self->mMethod) + { + case CTM_METHOD_RAW: + _ctmCompressMesh_RAW(self); + break; + + case CTM_METHOD_MG1: + _ctmCompressMesh_MG1(self); + break; + + case CTM_METHOD_MG2: + _ctmCompressMesh_MG2(self); + break; + + default: + self->mError = CTM_INTERNAL_ERROR; + return; + } +} diff --git a/src/external/OpenCTM-1.0.3/lib/openctm.h b/src/external/OpenCTM-1.0.3/lib/openctm.h new file mode 100644 index 000000000..c395f93e6 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/openctm.h @@ -0,0 +1,655 @@ +//----------------------------------------------------------------------------- +// Product: OpenCTM +// File: openctm.h +// Description: OpenCTM API definition. +//----------------------------------------------------------------------------- +// Copyright (c) 2009-2010 Marcus Geelnard +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +//----------------------------------------------------------------------------- + +#ifndef __OPENCTM_H_ +#define __OPENCTM_H_ + +/*! @mainpage OpenCTM API Reference + * + * @section intro_sec Introduction + * + * OpenCTM is an open file format for storing compressed triangle meshes. + * In order to easily read and write OpenCTM files (usually suffixed .ctm) an + * API (Application Program Interface) is provided that can easily be used from + * most modern programming languages. + * + * The OpenCTM functionality itself is written in highly portable standard C + * (C99). + * + * @section usage_sec Usage + * + * For information about how to use the OpenCTM API, see openctm.h. + * + * For information about the C++ wrapper classes, see CTMimporter and + * CTMexporter. + * + * @section example_sec Example usage + * + * @subsection example_load_sec Loading a CTM file + * + * Here is a simple example of loading a CTM file: + * + * @code + * CTMcontext context; + * CTMuint vertCount, triCount, * indices; + * CTMfloat * vertices; + * + * // Create a new context + * context = ctmNewContext(CTM_IMPORT); + * + * // Load the OpenCTM file + * ctmLoad(context, "mymesh.ctm"); + * if(ctmGetError(context) == CTM_NONE) + * { + * // Access the mesh data + * vertCount = ctmGetInteger(context, CTM_VERTEX_COUNT); + * vertices = ctmGetFloatArray(context, CTM_VERTICES); + * triCount = ctmGetInteger(context, CTM_TRIANGLE_COUNT); + * indices = ctmGetIntegerArray(context, CTM_INDICES); + * + * // Deal with the mesh (e.g. transcode it to our internal representation) + * // ... + * } + * + * // Free the context + * ctmFreeContext(context); + * @endcode + * + * @subsection example_create_sec Creating a CTM file + * + * Here is a simple example of creating a CTM file: + * + * @code + * CTMcontext context; + * CTMuint vertCount, triCount, * indices; + * CTMfloat * vertices; + * + * // Create our mesh in memory + * vertCount = 100; + * triCount = 120; + * vertices = (CTMfloat *) malloc(3 * sizeof(CTMfloat) * vertCount); + * indices = (CTMuint *) malloc(3 * sizeof(CTMuint) * triCount); + * // ... + * + * // Create a new context + * context = ctmNewContext(CTM_EXPORT); + * + * // Define our mesh representation to OpenCTM (store references to it in + * // the context) + * ctmDefineMesh(context, vertices, vertCount, indices, triCount, NULL); + * + * // Save the OpenCTM file + * ctmSave(context, "mymesh.ctm"); + * + * // Free the context + * ctmFreeContext(context); + * + * // Free our mesh + * free(indices); + * free(vertices); + * @endcode + */ + +#ifdef __cplusplus +extern "C" { +#endif + + +// Declare calling conventions etc. +#if defined(WIN32) || defined(_WIN32) + // Windows + #if defined(OPENCTM_STATIC) + #define CTMEXPORT + #else + #if defined(OPENCTM_BUILD) + #define CTMEXPORT __declspec(dllexport) + #else + #define CTMEXPORT __declspec(dllimport) + #endif + #endif + #if defined(__MINGW32__) + #define CTMCALL __attribute__ ((__stdcall__)) + #elif (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS) + #define CTMCALL __stdcall + #else + #define CTMCALL + #endif +#else + // Unix + #if !defined(OPENCTM_STATIC) && !defined(OPENCTM_BUILD) + #define CTMEXPORT extern + #else + #if defined(OPENCTM_BUILD) && defined(__GNUC__) && (__GNUC__ >= 4) + #define CTMEXPORT __attribute__ ((visibility("default"))) + #else + #define CTMEXPORT + #endif + #endif + #define CTMCALL +#endif + + +// Get system specific type definitions for sized integers. We use the C99 +// standard stdint.h for this. +#ifdef _MSC_VER + // MS Visual Studio does not support C99 + typedef int int32_t; + typedef unsigned int uint32_t; +#else + #include +#endif + + +/// OpenCTM API version (1.0). +#define CTM_API_VERSION 0x00000100 + +/// Boolean TRUE. +#define CTM_TRUE 1 + +/// Boolean FALSE. +#define CTM_FALSE 0 + +/// Single precision floating point type (IEEE 754 32 bits wide). +typedef float CTMfloat; + +/// Signed integer (32 bits wide). +typedef int32_t CTMint; + +/// Unsigned integer (32 bits wide). +typedef uint32_t CTMuint; + +/// OpenCTM context handle. +typedef void * CTMcontext; + +/// OpenCTM specific enumerators. +/// @note For the information query functions, it is an error to query a value +/// of the wrong type (e.g. to query a string value with the +/// ctmGetInteger() function). +typedef enum { + // Error codes (see ctmGetError()) + CTM_NONE = 0x0000, ///< No error has occured (everything is OK). + /// Also used as an error return value for + /// functions that should return a CTMenum + /// value. + CTM_INVALID_CONTEXT = 0x0001, ///< The OpenCTM context was invalid (e.g. NULL). + CTM_INVALID_ARGUMENT = 0x0002, ///< A function argument was invalid. + CTM_INVALID_OPERATION = 0x0003, ///< The operation is not allowed. + CTM_INVALID_MESH = 0x0004, ///< The mesh was invalid (e.g. no vertices). + CTM_OUT_OF_MEMORY = 0x0005, ///< Not enough memory to proceed. + CTM_FILE_ERROR = 0x0006, ///< File I/O error. + CTM_BAD_FORMAT = 0x0007, ///< File format error (e.g. unrecognized format or corrupted file). + CTM_LZMA_ERROR = 0x0008, ///< An error occured within the LZMA library. + CTM_INTERNAL_ERROR = 0x0009, ///< An internal error occured (indicates a bug). + CTM_UNSUPPORTED_FORMAT_VERSION = 0x000A, ///< Unsupported file format version. + + // OpenCTM context modes + CTM_IMPORT = 0x0101, ///< The OpenCTM context will be used for importing data. + CTM_EXPORT = 0x0102, ///< The OpenCTM context will be used for exporting data. + + // Compression methods + CTM_METHOD_RAW = 0x0201, ///< Just store the raw data. + CTM_METHOD_MG1 = 0x0202, ///< Lossless compression (floating point). + CTM_METHOD_MG2 = 0x0203, ///< Lossless compression (fixed point). + + // Context queries + CTM_VERTEX_COUNT = 0x0301, ///< Number of vertices in the mesh (integer). + CTM_TRIANGLE_COUNT = 0x0302, ///< Number of triangles in the mesh (integer). + CTM_HAS_NORMALS = 0x0303, ///< CTM_TRUE if the mesh has normals (integer). + CTM_UV_MAP_COUNT = 0x0304, ///< Number of UV coordinate sets (integer). + CTM_ATTRIB_MAP_COUNT = 0x0305, ///< Number of custom attribute sets (integer). + CTM_VERTEX_PRECISION = 0x0306, ///< Vertex precision - for MG2 (float). + CTM_NORMAL_PRECISION = 0x0307, ///< Normal precision - for MG2 (float). + CTM_COMPRESSION_METHOD = 0x0308, ///< Compression method (integer). + CTM_FILE_COMMENT = 0x0309, ///< File comment (string). + + // UV/attribute map queries + CTM_NAME = 0x0501, ///< Unique name (UV/attrib map string). + CTM_FILE_NAME = 0x0502, ///< File name reference (UV map string). + CTM_PRECISION = 0x0503, ///< Value precision (UV/attrib map float). + + // Array queries + CTM_INDICES = 0x0601, ///< Triangle indices (integer array). + CTM_VERTICES = 0x0602, ///< Vertex point coordinates (float array). + CTM_NORMALS = 0x0603, ///< Per vertex normals (float array). + CTM_UV_MAP_1 = 0x0700, ///< Per vertex UV map 1 (float array). + CTM_UV_MAP_2 = 0x0701, ///< Per vertex UV map 2 (float array). + CTM_UV_MAP_3 = 0x0702, ///< Per vertex UV map 3 (float array). + CTM_UV_MAP_4 = 0x0703, ///< Per vertex UV map 4 (float array). + CTM_UV_MAP_5 = 0x0704, ///< Per vertex UV map 5 (float array). + CTM_UV_MAP_6 = 0x0705, ///< Per vertex UV map 6 (float array). + CTM_UV_MAP_7 = 0x0706, ///< Per vertex UV map 7 (float array). + CTM_UV_MAP_8 = 0x0707, ///< Per vertex UV map 8 (float array). + CTM_ATTRIB_MAP_1 = 0x0800, ///< Per vertex attribute map 1 (float array). + CTM_ATTRIB_MAP_2 = 0x0801, ///< Per vertex attribute map 2 (float array). + CTM_ATTRIB_MAP_3 = 0x0802, ///< Per vertex attribute map 3 (float array). + CTM_ATTRIB_MAP_4 = 0x0803, ///< Per vertex attribute map 4 (float array). + CTM_ATTRIB_MAP_5 = 0x0804, ///< Per vertex attribute map 5 (float array). + CTM_ATTRIB_MAP_6 = 0x0805, ///< Per vertex attribute map 6 (float array). + CTM_ATTRIB_MAP_7 = 0x0806, ///< Per vertex attribute map 7 (float array). + CTM_ATTRIB_MAP_8 = 0x0807 ///< Per vertex attribute map 8 (float array). +} CTMenum; + +/// Stream read() function pointer. +/// @param[in] aBuf Pointer to the memory buffer to which data should be read. +/// @param[in] aCount The number of bytes to read. +/// @param[in] aUserData The custom user data that was passed to the +/// ctmLoadCustom() function. +/// @return The number of bytes actually read (if this is less than aCount, it +/// indicates that an error occured or the end of file was reached +/// before all bytes were read). +typedef CTMuint (CTMCALL * CTMreadfn)(void * aBuf, CTMuint aCount, void * aUserData); + +/// Stream write() function pointer. +/// @param[in] aBuf Pointer to the memory buffer from which data should be written. +/// @param[in] aCount The number of bytes to write. +/// @param[in] aUserData The custom user data that was passed to the +/// ctmSaveCustom() function. +/// @return The number of bytes actually written (if this is less than aCount, it +/// indicates that an error occured). +typedef CTMuint (CTMCALL * CTMwritefn)(const void * aBuf, CTMuint aCount, void * aUserData); + +/// Create a new OpenCTM context. The context is used for all subsequent +/// OpenCTM function calls. Several contexts can coexist at the same time. +/// @param[in] aMode An OpenCTM context mode. Set this to CTM_IMPORT if the +/// context will be used for importing data, or set it to CTM_EXPORT +/// if it will be used for exporting data. +/// @return An OpenCTM context handle (or NULL if no context could be created). +CTMEXPORT CTMcontext CTMCALL ctmNewContext(CTMenum aMode); + +/// Free an OpenCTM context. +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @see ctmNewContext() +CTMEXPORT void CTMCALL ctmFreeContext(CTMcontext aContext); + +/// Returns the latest error. Calling this function will return the last +/// produced error code, or CTM_NO_ERROR (zero) if no error has occured since +/// the last call to ctmGetError(). When this function is called, the internal +/// error varibale will be reset to CTM_NONE. +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @return An OpenCTM error code. +/// @see CTMenum +CTMEXPORT CTMenum CTMCALL ctmGetError(CTMcontext aContext); + +/// Converts an OpenCTM error code to a zero-terminated string. +/// @param[in] aError An OpenCTM error code, as returned by ctmGetError(). +/// @return A zero terminated string that describes the error. For instance, +/// if \c aError is CTM_INVALID_OPERATION, then the return value will +/// be "CTM_INVALID_OPERATION". +/// @see CTMenum +CTMEXPORT const char * CTMCALL ctmErrorString(CTMenum aError); + +/// Get information about an OpenCTM context. +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aProperty Which property to return. +/// @return An integer value, representing the OpenCTM context property given +/// by \c aProperty. +/// @see CTMenum +CTMEXPORT CTMuint CTMCALL ctmGetInteger(CTMcontext aContext, CTMenum aProperty); + +/// Get information about an OpenCTM context. +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aProperty Which property to return. +/// @return A floating point value, representing the OpenCTM context property +/// given by \c aProperty. +/// @see CTMenum +CTMEXPORT CTMfloat CTMCALL ctmGetFloat(CTMcontext aContext, CTMenum aProperty); + +/// Get an integer array from an OpenCTM context. +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aProperty Which array to return. +/// @return An integer array. If the requested array does not exist, or +/// if \c aProperty does not indicate an integer array, the function +/// returns NULL. +/// @note The array is only valid as long as the OpenCTM context is valid, or +/// until the corresponding array changes within the OpenCTM context. +/// Trying to access an invalid array will result in undefined +/// behaviour. Therefor it is recommended that the array is copied to +/// a new variable if it is to be used other than directly after the call +/// to ctmGetIntegerArray(). +/// @see CTMenum +CTMEXPORT const CTMuint * CTMCALL ctmGetIntegerArray(CTMcontext aContext, + CTMenum aProperty); + +/// Get a floating point array from an OpenCTM context. +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aProperty Which array to return. +/// @return A floating point array. If the requested array does not exist, or +/// if \c aProperty does not indicate a float array, the function +/// returns NULL. +/// @note The array is only valid as long as the OpenCTM context is valid, or +/// until the corresponding array changes within the OpenCTM context. +/// Trying to access an invalid array will result in undefined +/// behaviour. Therefor it is recommended that the array is copied to +/// a new variable if it is to be used other than directly after the call +/// to ctmGetFloatArray(). +/// @see CTMenum +CTMEXPORT const CTMfloat * CTMCALL ctmGetFloatArray(CTMcontext aContext, + CTMenum aProperty); + +/// Get a reference to the named UV map. +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aName The name of the UV map that should be returned. +/// @return A reference to a UV map. If the UV map was found, a value of +/// CTM_UV_MAP_1 or higher is returned, otherwise CTM_NONE is +/// returned. +CTMEXPORT CTMenum CTMCALL ctmGetNamedUVMap(CTMcontext aContext, + const char * aName); + +/// Get information about a UV map. +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aUVMap Which UV map to query (CTM_UV_MAP_1 or higher). +/// @param[in] aProperty Which UV map property to return. +/// @return A string value, representing the UV map property given +/// by \c aProperty. +/// @note The string is only valid as long as the UV map within the OpenCTM +/// context is valid. Trying to access an invalid string will result in +/// undefined behaviour. Therefor it is recommended that the string is +/// copied to a new variable if it is to be used other than directly after +/// the call to ctmGetUVMapString(). +/// @see CTMenum +CTMEXPORT const char * CTMCALL ctmGetUVMapString(CTMcontext aContext, + CTMenum aUVMap, CTMenum aProperty); + +/// Get information about a UV map. +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aUVMap Which UV map to query (CTM_UV_MAP_1 or higher). +/// @param[in] aProperty Which UV map property to return. +/// @return A floating point value, representing the UV map property given +/// by \c aProperty. +/// @see CTMenum +CTMEXPORT CTMfloat CTMCALL ctmGetUVMapFloat(CTMcontext aContext, + CTMenum aUVMap, CTMenum aProperty); + +/// Get a reference to the named vertex attribute map. +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aName The name of the attribute map that should be returned. +/// @return A reference to an attribute map. If the attribute map was found, +/// a value of CTM_ATTRIB_MAP_1 or higher is returned, otherwise +/// CTM_NONE is returned. +CTMEXPORT CTMenum CTMCALL ctmGetNamedAttribMap(CTMcontext aContext, + const char * aName); + +/// Get information about a vertex attribute map. +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aAttribMap Which vertex attribute map to query (CTM_ATTRIB_MAP_1 +/// or higher). +/// @param[in] aProperty Which vertex attribute map property to return. +/// @return A string value, representing the vertex attribute map property given +/// by \c aProperty. +/// @note The string is only valid as long as the vertex attribute map within +/// the OpenCTM context is valid. Trying to access an invalid string will +/// result in undefined behaviour. Therefor it is recommended that the +/// string is copied to a new variable if it is to be used other than +/// directly after the call to ctmGetAttribMapString(). +/// @see CTMenum +CTMEXPORT const char * CTMCALL ctmGetAttribMapString(CTMcontext aContext, + CTMenum aAttribMap, CTMenum aProperty); + +/// Get information about a vertex attribute map. +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aAttribMap Which vertex attribute map to query (CTM_ATTRIB_MAP_1 +/// or higher). +/// @param[in] aProperty Which vertex attribute map property to return. +/// @return A floating point value, representing the vertex attribute map +/// property given by \c aProperty. +/// @see CTMenum +CTMEXPORT CTMfloat CTMCALL ctmGetAttribMapFloat(CTMcontext aContext, + CTMenum aAttribMap, CTMenum aProperty); + +/// Get information about an OpenCTM context. +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aProperty Which property to return. +/// @return A string value, representing the OpenCTM context property given +/// by \c aProperty. +/// @note The string is only valid as long as the OpenCTM context is valid, or +/// until the corresponding string changes within the OpenCTM context +/// (e.g. calling ctmFileComment() invalidates the CTM_FILE_COMMENT +/// string). Trying to access an invalid string will result in undefined +/// behaviour. Therefor it is recommended that the string is copied to +/// a new variable if it is to be used other than directly after the call +/// to ctmGetString(). +/// @see CTMenum +CTMEXPORT const char * CTMCALL ctmGetString(CTMcontext aContext, + CTMenum aProperty); + +/// Set which compression method to use for the given OpenCTM context. +/// The selected compression method will be used when calling the ctmSave() +/// function. +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aMethod Which compression method to use: CTM_METHOD_RAW, +/// CTM_METHOD_MG1 or CTM_METHOD_MG2 (the default method is +/// CTM_METHOD_MG1). +/// @see CTM_METHOD_RAW, CTM_METHOD_MG1, CTM_METHOD_MG2 +CTMEXPORT void CTMCALL ctmCompressionMethod(CTMcontext aContext, + CTMenum aMethod); + +/// Set which LZMA compression level to use for the given OpenCTM context. +/// The compression level can be between 0 (fastest) and 9 (best). The higher +/// the compression level, the more memory is required for compression and +/// decompression. The default compression level is 1. +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aLevel Which compression level to use (0 to 9). +CTMEXPORT void CTMCALL ctmCompressionLevel(CTMcontext aContext, + CTMuint aLevel); + +/// Set the vertex coordinate precision (only used by the MG2 compression +/// method). +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aPrecision Fixed point precision. For instance, if this value is +/// 0.001, all vertex coordinates will be rounded to three decimals. +/// The default vertex coordinate precision is 2^-10 ~= 0.00098. +CTMEXPORT void CTMCALL ctmVertexPrecision(CTMcontext aContext, + CTMfloat aPrecision); + +/// Set the vertex coordinate precision, relative to the mesh dimensions (only +/// used by the MG2 compression method). +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aRelPrecision Relative precision. This factor is multiplied by the +/// average triangle edge length in the mesh in order to obtain the +/// final, fixed point precision. For instance, if aRelPrecision is +/// 0.01, and the average edge length is 3.7, then the fixed point +/// precision is set to 0.037. +/// @note The mesh must have been defined using the ctmDefineMesh() function +/// before calling this function. +/// @see ctmVertexPrecision(). +CTMEXPORT void CTMCALL ctmVertexPrecisionRel(CTMcontext aContext, + CTMfloat aRelPrecision); + +/// Set the normal precision (only used by the MG2 compression method). The +/// normal is represented in spherical coordinates in the MG2 compression +/// method, and the normal precision controls the angular and radial resolution. +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aPrecision Fixed point precision. For the angular information, +/// this value represents the angular precision. For the radial +/// information, this value is the linear resolution. For instance, +/// 0.01 means that the circle is divided into 100 steps, and the +/// normal magnitude is rounded to 2 decimals. The default normal +/// precision is 2^-8 ~= 0.0039. +CTMEXPORT void CTMCALL ctmNormalPrecision(CTMcontext aContext, + CTMfloat aPrecision); + +/// Set the coordinate precision for the specified UV map (only used by the +/// MG2 compression method). +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aUVMap A UV map specifier for a defined UV map +/// (CTM_UV_MAP_1, ...). +/// @param[in] aPrecision Fixed point precision. For instance, if this value is +/// 0.001, all UV coordinates will be rounded to three decimals. +/// The default UV coordinate precision is 2^-12 ~= 0.00024. +/// @see ctmAddUVMap(). +CTMEXPORT void CTMCALL ctmUVCoordPrecision(CTMcontext aContext, + CTMenum aUVMap, CTMfloat aPrecision); + +/// Set the attribute value precision for the specified attribute map (only +/// used by the MG2 compression method). +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aAttribMap An attribute map specifier for a defined attribute map +/// (CTM_ATTRIB_MAP_1, ...). +/// @param[in] aPrecision Fixed point precision. For instance, if this value is +/// 0.001, all attribute values will be rounded to three decimals. +/// If the attributes represent integer values, set the precision +/// to 1.0. The default attribute precision is 2^-8 ~= 0.0039. +/// @see ctmAddAttribMap(). +CTMEXPORT void CTMCALL ctmAttribPrecision(CTMcontext aContext, + CTMenum aAttribMap, CTMfloat aPrecision); + +/// Set the file comment for the given OpenCTM context. +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aFileComment The file comment (zero terminated UTF-8 string). +CTMEXPORT void CTMCALL ctmFileComment(CTMcontext aContext, + const char * aFileComment); + +/// Define a triangle mesh. +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aVertices An array of vertices (three consecutive floats make +/// one vertex). +/// @param[in] aVertexCount The number of vertices in \c aVertices (and +/// optionally \c aTexCoords). +/// @param[in] aIndices An array of vertex indices (three consecutive integers +/// make one triangle). +/// @param[in] aTriangleCount The number of triangles in \c aIndices (there +/// must be exactly 3 x \c aTriangleCount indices in \c aIndices). +/// @param[in] aNormals An array of per-vertex normals (or NULL if there are +/// no normals). Each normal is made up by three consecutive floats, +/// and there must be \c aVertexCount normals. +/// @see ctmAddUVMap(), ctmAddAttribMap(), ctmSave(), ctmSaveCustom(). +CTMEXPORT void CTMCALL ctmDefineMesh(CTMcontext aContext, + const CTMfloat * aVertices, CTMuint aVertexCount, const CTMuint * aIndices, + CTMuint aTriangleCount, const CTMfloat * aNormals); + +/// Define a UV map. There can be several UV maps in a mesh. A UV map is +/// typically used for 2D texture mapping. +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aUVCoords An array of UV coordinates. Each UV coordinate is made +/// up by two consecutive floats, and there must be as many +/// coordinates as there are vertices in the mesh. +/// @param[in] aName A unique name for this UV map (zero terminated UTF-8 +/// string). +/// @param[in] aFileName A reference to a image file (zero terminated +/// UTF-8 string). If no file name reference exists, pass NULL. +/// @return A UV map index (CTM_UV_MAP_1 and higher). If the function +/// failed, it will return the zero valued CTM_NONE (use ctmGetError() +/// to determine the cause of the error). +/// @note A triangle mesh must have been defined before calling this function, +/// since the number of vertices is defined by the triangle mesh. +/// @see ctmDefineMesh(). +CTMEXPORT CTMenum CTMCALL ctmAddUVMap(CTMcontext aContext, + const CTMfloat * aUVCoords, const char * aName, const char * aFileName); + +/// Define a custom vertex attribute map. Custom vertex attributes can be used +/// for defining special per-vertex attributes, such as color, weight, ambient +/// occlusion factor, etc. +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aAttribValues An array of attribute values. Each attribute value +/// is made up by four consecutive floats, and there must be as many +/// values as there are vertices in the mesh. +/// @param[in] aName A unique name for this attribute map (zero terminated UTF-8 +/// string). +/// @return A attribute map index (CTM_ATTRIB_MAP_1 and higher). If the function +/// failed, it will return the zero valued CTM_NONE (use ctmGetError() +/// to determine the cause of the error). +/// @note A triangle mesh must have been defined before calling this function, +/// since the number of vertices is defined by the triangle mesh. +/// @see ctmDefineMesh(). +CTMEXPORT CTMenum CTMCALL ctmAddAttribMap(CTMcontext aContext, + const CTMfloat * aAttribValues, const char * aName); + +/// Load an OpenCTM format file into the context. The mesh data can be retrieved +/// with the various ctmGet functions. +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aFileName The name of the file to be loaded. +CTMEXPORT void CTMCALL ctmLoad(CTMcontext aContext, const char * aFileName); + +/// Load an OpenCTM format file using a custom stream read function. The mesh +/// data can be retrieved with the various ctmGet functions. +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aReadFn Pointer to a custom stream read function. +/// @param[in] aUserData Custom user data, which can be a C language FILE +/// handle, C++ istream object, or a custom object pointer +/// of any type. The user data pointer will be passed to the +/// custom stream read function. +/// @see CTMreadfn. +CTMEXPORT void CTMCALL ctmLoadCustom(CTMcontext aContext, CTMreadfn aReadFn, + void * aUserData); + +/// Save an OpenCTM format file. The mesh must have been defined by +/// ctmDefineMesh(). +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aFileName The name of the file to be saved. +CTMEXPORT void CTMCALL ctmSave(CTMcontext aContext, const char * aFileName); + +/// Save an OpenCTM format file using a custom stream write function. The mesh +/// must have been defined by ctmDefineMesh(). +/// @param[in] aContext An OpenCTM context that has been created by +/// ctmNewContext(). +/// @param[in] aWriteFn Pointer to a custom stream write function. +/// @param[in] aUserData Custom user data, which can be a C language FILE +/// handle, C++ ostream object, or a custom object pointer +/// of any type. The user data pointer will be passed to the +/// custom stream write function. +/// @see CTMwritefn. +CTMEXPORT void CTMCALL ctmSaveCustom(CTMcontext aContext, CTMwritefn aWriteFn, + void * aUserData); + +#ifdef __cplusplus +} +#endif + + +// C++ extensions to the API (to disable C++ extensions, define OPENCTM_NO_CPP) +#if defined(__cplusplus) && !defined(OPENCTM_NO_CPP) + #include "openctmpp.h" +#endif + +#endif // __OPENCTM_H_ diff --git a/src/external/OpenCTM-1.0.3/lib/openctm.rc b/src/external/OpenCTM-1.0.3/lib/openctm.rc new file mode 100644 index 000000000..562417e53 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/openctm.rc @@ -0,0 +1,26 @@ + +1 VERSIONINFO + FILEVERSION 1,0,3,0 + PRODUCTVERSION 1,0,3,0 + FILEOS 0x4 + FILETYPE 0x2 + BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "ProductVersion", "1.0.3.0" + VALUE "FileVersion", "1.0.3.0" + VALUE "FileDescription", "OpenCTM API shared library" + VALUE "ProductName", "OpenCTM" + VALUE "OriginalFilename", "openctm.dll" + VALUE "LegalCopyright", "© 2009-2010 Marcus Geelnard" + VALUE "License", "This software is released under the zlib/libpng license." + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1252 + END + END diff --git a/src/external/OpenCTM-1.0.3/lib/openctmpp.h b/src/external/OpenCTM-1.0.3/lib/openctmpp.h new file mode 100644 index 000000000..e2519f202 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/openctmpp.h @@ -0,0 +1,377 @@ +//----------------------------------------------------------------------------- +// Product: OpenCTM +// File: openctmpp.h +// Description: C++ wrapper for the OpenCTM API. +//----------------------------------------------------------------------------- +// Copyright (c) 2009-2010 Marcus Geelnard +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +//----------------------------------------------------------------------------- + +// To disable C++ extensions, define OPENCTM_NO_CPP +#ifndef OPENCTM_NO_CPP + +#ifndef __OPENCTMPP_H_ +#define __OPENCTMPP_H_ + +// Just in case (if this file was included from outside openctm.h)... +#ifndef __OPENCTM_H_ +#include "openctm.h" +#endif + +#include + +/// OpenCTM exception. When an error occurs, a \c ctm_error exception is +/// thrown. Its what() function returns the name of the OpenCTM error code +/// (for instance "CTM_INVALID_OPERATION"). +class ctm_error: public std::exception +{ + private: + CTMenum mErrorCode; + + public: + explicit ctm_error(CTMenum aError) + { + mErrorCode = aError; + } + + virtual const char* what() const throw() + { + return ctmErrorString(mErrorCode); + } + + CTMenum error_code() const throw() + { + return mErrorCode; + } +}; + + +/// OpenCTM importer class. This is a C++ wrapper class for an OpenCTM import +/// context. Usage example: +/// +/// @code +/// // Create a new OpenCTM importer object +/// CTMimporter ctm; +/// +/// // Load the OpenCTM file +/// ctm.Load("mymesh.ctm"); +/// +/// // Access the mesh data +/// vertCount = ctm.GetInteger(CTM_VERTEX_COUNT); +/// vertices = ctm.GetFloatArray(CTM_VERTICES); +/// triCount = ctm.GetInteger(CTM_TRIANGLE_COUNT); +/// indices = ctm.GetIntegerArray(CTM_INDICES); +/// +/// // Deal with the mesh (e.g. transcode it to our internal representation) +/// // ... +/// @endcode + +class CTMimporter { + private: + /// The OpenCTM context handle. + CTMcontext mContext; + + /// Check for OpenCTM errors, and throw an exception if an error has + /// occured. + void CheckError() + { + CTMenum err = ctmGetError(mContext); + if(err != CTM_NONE) + throw ctm_error(err); + } + + public: + /// Constructor + CTMimporter() + { + mContext = ctmNewContext(CTM_IMPORT); + } + + /// Destructor + ~CTMimporter() + { + ctmFreeContext(mContext); + } + + /// Wrapper for ctmGetInteger() + CTMuint GetInteger(CTMenum aProperty) + { + CTMuint res = ctmGetInteger(mContext, aProperty); + CheckError(); + return res; + } + + /// Wrapper for ctmGetFloat() + CTMfloat GetFloat(CTMenum aProperty) + { + CTMfloat res = ctmGetFloat(mContext, aProperty); + CheckError(); + return res; + } + + /// Wrapper for ctmGetIntegerArray() + const CTMuint * GetIntegerArray(CTMenum aProperty) + { + const CTMuint * res = ctmGetIntegerArray(mContext, aProperty); + CheckError(); + return res; + } + + /// Wrapper for ctmGetFloatArray() + const CTMfloat * GetFloatArray(CTMenum aProperty) + { + const CTMfloat * res = ctmGetFloatArray(mContext, aProperty); + CheckError(); + return res; + } + + /// Wrapper for ctmGetNamedUVMap() + CTMenum GetNamedUVMap(const char * aName) + { + CTMenum res = ctmGetNamedUVMap(mContext, aName); + CheckError(); + return res; + } + + /// Wrapper for ctmGetUVMapString() + const char * GetUVMapString(CTMenum aUVMap, CTMenum aProperty) + { + const char * res = ctmGetUVMapString(mContext, aUVMap, aProperty); + CheckError(); + return res; + } + + /// Wrapper for ctmGetUVMapFloat() + CTMfloat GetUVMapFloat(CTMenum aUVMap, CTMenum aProperty) + { + CTMfloat res = ctmGetUVMapFloat(mContext, aUVMap, aProperty); + CheckError(); + return res; + } + + /// Wrapper for ctmGetNamedAttribMap() + CTMenum GetNamedAttribMap(const char * aName) + { + CTMenum res = ctmGetNamedAttribMap(mContext, aName); + CheckError(); + return res; + } + + /// Wrapper for ctmGetAttribMapString() + const char * GetAttribMapString(CTMenum aAttribMap, CTMenum aProperty) + { + const char * res = ctmGetAttribMapString(mContext, aAttribMap, aProperty); + CheckError(); + return res; + } + + /// Wrapper for ctmGetAttribMapFloat() + CTMfloat GetAttribMapFloat(CTMenum aAttribMap, CTMenum aProperty) + { + CTMfloat res = ctmGetAttribMapFloat(mContext, aAttribMap, aProperty); + CheckError(); + return res; + } + + /// Wrapper for ctmGetString() + const char * GetString(CTMenum aProperty) + { + const char * res = ctmGetString(mContext, aProperty); + CheckError(); + return res; + } + + /// Wrapper for ctmLoad() + void Load(const char * aFileName) + { + ctmLoad(mContext, aFileName); + CheckError(); + } + + /// Wrapper for ctmLoadCustom() + void LoadCustom(CTMreadfn aReadFn, void * aUserData) + { + ctmLoadCustom(mContext, aReadFn, aUserData); + CheckError(); + } + + // You can not copy nor assign from one CTMimporter object to another, since + // the object contains hidden state. By declaring these dummy prototypes + // without an implementation, you will at least get linker errors if you try + // to copy or assign a CTMimporter object. + CTMimporter(const CTMimporter& v); + CTMimporter& operator=(const CTMimporter& v); +}; + + +/// OpenCTM exporter class. This is a C++ wrapper class for an OpenCTM export +/// context. Usage example: +/// @code +/// void MySaveFile(CTMuint aVertCount, CTMuint aTriCount, CTMfloat * aVertices, +/// CTMuint * aIndices, const char * aFileName) +/// { +/// // Create a new OpenCTM exporter object +/// CTMexporter ctm; +/// +/// // Define our mesh representation to OpenCTM (store references to it in +/// // the context) +/// ctm.DefineMesh(aVertices, aVertCount, aIndices, aTriCount, NULL); +/// +/// // Save the OpenCTM file +/// ctm.Save(aFileName); +/// } +/// @endcode + +class CTMexporter { + private: + /// The OpenCTM context handle. + CTMcontext mContext; + + /// Check for OpenCTM errors, and throw an exception if an error has + /// occured. + void CheckError() + { + CTMenum err = ctmGetError(mContext); + if(err != CTM_NONE) + throw ctm_error(err); + } + + public: + /// Constructor + CTMexporter() + { + mContext = ctmNewContext(CTM_EXPORT); + } + + /// Destructor + ~CTMexporter() + { + ctmFreeContext(mContext); + } + + /// Wrapper for ctmCompressionMethod() + void CompressionMethod(CTMenum aMethod) + { + ctmCompressionMethod(mContext, aMethod); + CheckError(); + } + + /// Wrapper for ctmCompressionLevel() + void CompressionLevel(CTMuint aLevel) + { + ctmCompressionLevel(mContext, aLevel); + CheckError(); + } + + /// Wrapper for ctmVertexPrecision() + void VertexPrecision(CTMfloat aPrecision) + { + ctmVertexPrecision(mContext, aPrecision); + CheckError(); + } + + /// Wrapper for ctmVertexPrecisionRel() + void VertexPrecisionRel(CTMfloat aRelPrecision) + { + ctmVertexPrecisionRel(mContext, aRelPrecision); + CheckError(); + } + + /// Wrapper for ctmNormalPrecision() + void NormalPrecision(CTMfloat aPrecision) + { + ctmNormalPrecision(mContext, aPrecision); + CheckError(); + } + + /// Wrapper for ctmUVCoordPrecision() + void UVCoordPrecision(CTMenum aUVMap, CTMfloat aPrecision) + { + ctmUVCoordPrecision(mContext, aUVMap, aPrecision); + CheckError(); + } + + /// Wrapper for ctmAttribPrecision() + void AttribPrecision(CTMenum aAttribMap, CTMfloat aPrecision) + { + ctmAttribPrecision(mContext, aAttribMap, aPrecision); + CheckError(); + } + + /// Wrapper for ctmFileComment() + void FileComment(const char * aFileComment) + { + ctmFileComment(mContext, aFileComment); + CheckError(); + } + + /// Wrapper for ctmDefineMesh() + void DefineMesh(const CTMfloat * aVertices, CTMuint aVertexCount, + const CTMuint * aIndices, CTMuint aTriangleCount, + const CTMfloat * aNormals) + { + ctmDefineMesh(mContext, aVertices, aVertexCount, aIndices, aTriangleCount, + aNormals); + CheckError(); + } + + /// Wrapper for ctmAddUVMap() + CTMenum AddUVMap(const CTMfloat * aUVCoords, const char * aName, + const char * aFileName) + { + CTMenum res = ctmAddUVMap(mContext, aUVCoords, aName, aFileName); + CheckError(); + return res; + } + + /// Wrapper for ctmAddAttribMap() + CTMenum AddAttribMap(const CTMfloat * aAttribValues, const char * aName) + { + CTMenum res = ctmAddAttribMap(mContext, aAttribValues, aName); + CheckError(); + return res; + } + + /// Wrapper for ctmSave() + void Save(const char * aFileName) + { + ctmSave(mContext, aFileName); + CheckError(); + } + + /// Wrapper for ctmSaveCustom() + void SaveCustom(CTMwritefn aWriteFn, void * aUserData) + { + ctmSaveCustom(mContext, aWriteFn, aUserData); + CheckError(); + } + + // You can not copy nor assign from one CTMexporter object to another, since + // the object contains hidden state. By declaring these dummy prototypes + // without an implementation, you will at least get linker errors if you try + // to copy or assign a CTMexporter object. + CTMexporter(const CTMexporter& v); + CTMexporter& operator=(const CTMexporter& v); +}; + +#endif // __OPENCTMPP_H_ + +#endif // OPENCTM_NO_CPP diff --git a/src/external/OpenCTM-1.0.3/lib/stream.c b/src/external/OpenCTM-1.0.3/lib/stream.c new file mode 100644 index 000000000..c67f43779 --- /dev/null +++ b/src/external/OpenCTM-1.0.3/lib/stream.c @@ -0,0 +1,512 @@ +//----------------------------------------------------------------------------- +// Product: OpenCTM +// File: stream.c +// Description: Stream I/O functions. +//----------------------------------------------------------------------------- +// Copyright (c) 2009-2010 Marcus Geelnard +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +//----------------------------------------------------------------------------- + +#include +#include +#include +#include "openctm.h" +#include "internal.h" + +#ifdef __DEBUG_ +#include +#endif + +//----------------------------------------------------------------------------- +// _ctmStreamRead() - Read data from a stream. +//----------------------------------------------------------------------------- +CTMuint _ctmStreamRead(_CTMcontext * self, void * aBuf, CTMuint aCount) +{ + if(!self->mUserData || !self->mReadFn) + return 0; + + return self->mReadFn(aBuf, aCount, self->mUserData); +} + +//----------------------------------------------------------------------------- +// _ctmStreamWrite() - Write data to a stream. +//----------------------------------------------------------------------------- +CTMuint _ctmStreamWrite(_CTMcontext * self, void * aBuf, CTMuint aCount) +{ + if(!self->mUserData || !self->mWriteFn) + return 0; + + return self->mWriteFn(aBuf, aCount, self->mUserData); +} + +//----------------------------------------------------------------------------- +// _ctmStreamReadUINT() - Read an unsigned integer from a stream in a machine +// endian independent manner (for portability). +//----------------------------------------------------------------------------- +CTMuint _ctmStreamReadUINT(_CTMcontext * self) +{ + unsigned char buf[4]; + _ctmStreamRead(self, (void *) buf, 4); + return ((CTMuint) buf[0]) | + (((CTMuint) buf[1]) << 8) | + (((CTMuint) buf[2]) << 16) | + (((CTMuint) buf[3]) << 24); +} + +//----------------------------------------------------------------------------- +// _ctmStreamWriteUINT() - Write an unsigned integer to a stream in a machine +// endian independent manner (for portability). +//----------------------------------------------------------------------------- +void _ctmStreamWriteUINT(_CTMcontext * self, CTMuint aValue) +{ + unsigned char buf[4]; + buf[0] = aValue & 0x000000ff; + buf[1] = (aValue >> 8) & 0x000000ff; + buf[2] = (aValue >> 16) & 0x000000ff; + buf[3] = (aValue >> 24) & 0x000000ff; + _ctmStreamWrite(self, (void *) buf, 4); +} + +//----------------------------------------------------------------------------- +// _ctmStreamReadFLOAT() - Read a floating point value from a stream in a +// machine endian independent manner (for portability). +//----------------------------------------------------------------------------- +CTMfloat _ctmStreamReadFLOAT(_CTMcontext * self) +{ + union { + CTMfloat f; + CTMuint i; + } u; + u.i = _ctmStreamReadUINT(self); + return u.f; +} + +//----------------------------------------------------------------------------- +// _ctmStreamWriteFLOAT() - Write a floating point value to a stream in a +// machine endian independent manner (for portability). +//----------------------------------------------------------------------------- +void _ctmStreamWriteFLOAT(_CTMcontext * self, CTMfloat aValue) +{ + union { + CTMfloat f; + CTMuint i; + } u; + u.f = aValue; + _ctmStreamWriteUINT(self, u.i); +} + +//----------------------------------------------------------------------------- +// _ctmStreamReadSTRING() - Read a string value from a stream. The format of +// the string in the stream is: an unsigned integer (string length) followed by +// the string (without null termination). +//----------------------------------------------------------------------------- +void _ctmStreamReadSTRING(_CTMcontext * self, char ** aValue) +{ + CTMuint len; + + // Clear the old string + if(*aValue) + { + free(*aValue); + *aValue = (char *) 0; + } + + // Get string length + len = _ctmStreamReadUINT(self); + + // Read string + if(len > 0) + { + *aValue = (char *) malloc(len + 1); + if(*aValue) + { + _ctmStreamRead(self, (void *) *aValue, len); + (*aValue)[len] = 0; + } + } +} + +//----------------------------------------------------------------------------- +// _ctmStreamWriteSTRING() - Write a string value to a stream. The format of +// the string in the stream is: an unsigned integer (string length) followed by +// the string (without null termination). +//----------------------------------------------------------------------------- +void _ctmStreamWriteSTRING(_CTMcontext * self, const char * aValue) +{ + CTMuint len; + + // Get string length + if(aValue) + len = strlen(aValue); + else + len = 0; + + // Write string length + _ctmStreamWriteUINT(self, len); + + // Write string + if(len > 0) + _ctmStreamWrite(self, (void *) aValue, len); +} + +//----------------------------------------------------------------------------- +// _ctmStreamReadPackedInts() - Read an compressed binary integer data array +// from a stream, and uncompress it. +//----------------------------------------------------------------------------- +int _ctmStreamReadPackedInts(_CTMcontext * self, CTMint * aData, + CTMuint aCount, CTMuint aSize, CTMint aSignedInts) +{ + size_t packedSize, unpackedSize; + CTMuint i, k, x; + CTMint value; + unsigned char * packed, * tmp; + unsigned char props[5]; + int lzmaRes; + + // Read packed data size from the stream + packedSize = (size_t) _ctmStreamReadUINT(self); + + // Read LZMA compression props from the stream + _ctmStreamRead(self, (void *) props, 5); + + // Allocate memory and read the packed data from the stream + packed = (unsigned char *) malloc(packedSize); + if(!packed) + { + self->mError = CTM_OUT_OF_MEMORY; + return CTM_FALSE; + } + _ctmStreamRead(self, (void *) packed, packedSize); + + // Allocate memory for interleaved array + tmp = (unsigned char *) malloc(aCount * aSize * 4); + if(!tmp) + { + free(packed); + self->mError = CTM_OUT_OF_MEMORY; + return CTM_FALSE; + } + + // Uncompress + unpackedSize = aCount * aSize * 4; + lzmaRes = LzmaUncompress(tmp, &unpackedSize, packed, + &packedSize, props, 5); + + // Free the packed array + free(packed); + + // Error? + if((lzmaRes != SZ_OK) || (unpackedSize != aCount * aSize * 4)) + { + self->mError = CTM_LZMA_ERROR; + free(tmp); + return CTM_FALSE; + } + + // Convert interleaved array to integers + for(i = 0; i < aCount; ++ i) + { + for(k = 0; k < aSize; ++ k) + { + value = (CTMint) tmp[i + k * aCount + 3 * aCount * aSize] | + (((CTMint) tmp[i + k * aCount + 2 * aCount * aSize]) << 8) | + (((CTMint) tmp[i + k * aCount + aCount * aSize]) << 16) | + (((CTMint) tmp[i + k * aCount]) << 24); + // Convert signed magnitude to two's complement? + if(aSignedInts) + { + x = (CTMuint) value; + value = (x & 1) ? -(CTMint)((x + 1) >> 1) : (CTMint)(x >> 1); + } + aData[i * aSize + k] = value; + } + } + + // Free the interleaved array + free(tmp); + + return CTM_TRUE; +} + +//----------------------------------------------------------------------------- +// _ctmStreamWritePackedInts() - Compress a binary integer data array, and +// write it to a stream. +//----------------------------------------------------------------------------- +int _ctmStreamWritePackedInts(_CTMcontext * self, CTMint * aData, + CTMuint aCount, CTMuint aSize, CTMint aSignedInts) +{ + int lzmaRes, lzmaAlgo; + CTMuint i, k; + CTMint value; + size_t bufSize, outPropsSize; + unsigned char * packed, outProps[5], *tmp; +#ifdef __DEBUG_ + CTMuint negCount = 0; +#endif + + // Allocate memory for interleaved array + tmp = (unsigned char *) malloc(aCount * aSize * 4); + if(!tmp) + { + self->mError = CTM_OUT_OF_MEMORY; + return CTM_FALSE; + } + + // Convert integers to an interleaved array + for(i = 0; i < aCount; ++ i) + { + for(k = 0; k < aSize; ++ k) + { + value = aData[i * aSize + k]; + // Convert two's complement to signed magnitude? + if(aSignedInts) + value = value < 0 ? -1 - (value << 1) : value << 1; +#ifdef __DEBUG_ + else if(value < 0) + ++ negCount; +#endif + tmp[i + k * aCount + 3 * aCount * aSize] = value & 0x000000ff; + tmp[i + k * aCount + 2 * aCount * aSize] = (value >> 8) & 0x000000ff; + tmp[i + k * aCount + aCount * aSize] = (value >> 16) & 0x000000ff; + tmp[i + k * aCount] = (value >> 24) & 0x000000ff; + } + } + + // Allocate memory for the packed data + bufSize = 1000 + aCount * aSize * 4; + packed = (unsigned char *) malloc(bufSize); + if(!packed) + { + free(tmp); + self->mError = CTM_OUT_OF_MEMORY; + return CTM_FALSE; + } + + // Call LZMA to compress + outPropsSize = 5; + lzmaAlgo = (self->mCompressionLevel < 1 ? 0 : 1); + lzmaRes = LzmaCompress(packed, + &bufSize, + (const unsigned char *) tmp, + aCount * aSize * 4, + outProps, + &outPropsSize, + self->mCompressionLevel, // Level (0-9) + 0, -1, -1, -1, -1, -1, // Default values (set by level) + lzmaAlgo // Algorithm (0 = fast, 1 = normal) + ); + + // Free temporary array + free(tmp); + + // Error? + if(lzmaRes != SZ_OK) + { + self->mError = CTM_LZMA_ERROR; + free(packed); + return CTM_FALSE; + } + +#ifdef __DEBUG_ + printf("%d->%d bytes (%d negative words)\n", aCount * aSize * 4, (int) bufSize, negCount); +#endif + + // Write packed data size to the stream + _ctmStreamWriteUINT(self, (CTMuint) bufSize); + + // Write LZMA compression props to the stream + _ctmStreamWrite(self, (void *) outProps, 5); + + // Write the packed data to the stream + _ctmStreamWrite(self, (void *) packed, (CTMuint) bufSize); + + // Free the packed data + free(packed); + + return CTM_TRUE; +} + +//----------------------------------------------------------------------------- +// _ctmStreamReadPackedFloats() - Read an compressed binary float data array +// from a stream, and uncompress it. +//----------------------------------------------------------------------------- +int _ctmStreamReadPackedFloats(_CTMcontext * self, CTMfloat * aData, + CTMuint aCount, CTMuint aSize) +{ + CTMuint i, k; + size_t packedSize, unpackedSize; + union { + CTMfloat f; + CTMint i; + } value; + unsigned char * packed, * tmp; + unsigned char props[5]; + int lzmaRes; + + // Read packed data size from the stream + packedSize = (size_t) _ctmStreamReadUINT(self); + + // Read LZMA compression props from the stream + _ctmStreamRead(self, (void *) props, 5); + + // Allocate memory and read the packed data from the stream + packed = (unsigned char *) malloc(packedSize); + if(!packed) + { + self->mError = CTM_OUT_OF_MEMORY; + return CTM_FALSE; + } + _ctmStreamRead(self, (void *) packed, packedSize); + + // Allocate memory for interleaved array + tmp = (unsigned char *) malloc(aCount * aSize * 4); + if(!tmp) + { + free(packed); + self->mError = CTM_OUT_OF_MEMORY; + return CTM_FALSE; + } + + // Uncompress + unpackedSize = aCount * aSize * 4; + lzmaRes = LzmaUncompress(tmp, &unpackedSize, packed, + &packedSize, props, 5); + + // Free the packed array + free(packed); + + // Error? + if((lzmaRes != SZ_OK) || (unpackedSize != aCount * aSize * 4)) + { + self->mError = CTM_LZMA_ERROR; + free(tmp); + return CTM_FALSE; + } + + // Convert interleaved array to floats + for(i = 0; i < aCount; ++ i) + { + for(k = 0; k < aSize; ++ k) + { + value.i = (CTMint) tmp[i + k * aCount + 3 * aCount * aSize] | + (((CTMint) tmp[i + k * aCount + 2 * aCount * aSize]) << 8) | + (((CTMint) tmp[i + k * aCount + aCount * aSize]) << 16) | + (((CTMint) tmp[i + k * aCount]) << 24); + aData[i * aSize + k] = value.f; + } + } + + // Free the interleaved array + free(tmp); + + return CTM_TRUE; +} + +//----------------------------------------------------------------------------- +// _ctmStreamWritePackedFloats() - Compress a binary float data array, and +// write it to a stream. +//----------------------------------------------------------------------------- +int _ctmStreamWritePackedFloats(_CTMcontext * self, CTMfloat * aData, + CTMuint aCount, CTMuint aSize) +{ + int lzmaRes, lzmaAlgo; + CTMuint i, k; + union { + CTMfloat f; + CTMint i; + } value; + size_t bufSize, outPropsSize; + unsigned char * packed, outProps[5], *tmp; + + // Allocate memory for interleaved array + tmp = (unsigned char *) malloc(aCount * aSize * 4); + if(!tmp) + { + self->mError = CTM_OUT_OF_MEMORY; + return CTM_FALSE; + } + + // Convert floats to an interleaved array + for(i = 0; i < aCount; ++ i) + { + for(k = 0; k < aSize; ++ k) + { + value.f = aData[i * aSize + k]; + tmp[i + k * aCount + 3 * aCount * aSize] = value.i & 0x000000ff; + tmp[i + k * aCount + 2 * aCount * aSize] = (value.i >> 8) & 0x000000ff; + tmp[i + k * aCount + aCount * aSize] = (value.i >> 16) & 0x000000ff; + tmp[i + k * aCount] = (value.i >> 24) & 0x000000ff; + } + } + + // Allocate memory for the packed data + bufSize = 1000 + aCount * aSize * 4; + packed = (unsigned char *) malloc(bufSize); + if(!packed) + { + free(tmp); + self->mError = CTM_OUT_OF_MEMORY; + return CTM_FALSE; + } + + // Call LZMA to compress + outPropsSize = 5; + lzmaAlgo = (self->mCompressionLevel < 1 ? 0 : 1); + lzmaRes = LzmaCompress(packed, + &bufSize, + (const unsigned char *) tmp, + aCount * aSize * 4, + outProps, + &outPropsSize, + self->mCompressionLevel, // Level (0-9) + 0, -1, -1, -1, -1, -1, // Default values (set by level) + lzmaAlgo // Algorithm (0 = fast, 1 = normal) + ); + + // Free temporary array + free(tmp); + + // Error? + if(lzmaRes != SZ_OK) + { + self->mError = CTM_LZMA_ERROR; + free(packed); + return CTM_FALSE; + } + +#ifdef __DEBUG_ + printf("%d->%d bytes\n", aCount * aSize * 4, (int) bufSize); +#endif + + // Write packed data size to the stream + _ctmStreamWriteUINT(self, (CTMuint) bufSize); + + // Write LZMA compression props to the stream + _ctmStreamWrite(self, (void *) outProps, 5); + + // Write the packed data to the stream + _ctmStreamWrite(self, (void *) packed, (CTMuint) bufSize); + + // Free the packed data + free(packed); + + return CTM_TRUE; +} diff --git a/src/external/lib/macx/libopenctm.a b/src/external/lib/macx/libopenctm.a new file mode 100644 index 0000000000000000000000000000000000000000..c2201c96f3ec9d6529c9ffc30a9e7e2e3458cb0e GIT binary patch literal 104656 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�uz;fc4NdZ7I&Fl3BQquzs(RVPjuYhKLN|a|sxOi=qrrO2VpTLcD zj6f)a#ONJ-6WD=$J|^)(S9C6MB0t$)IOw5pfPlabeRdW7 z5i-G=SA@EkPSSQJ<&V{NN#MOuyausoFcZkY?pv@FT=|IJE6=S$12R=GJ<6p5@B{M& zq!}8b0)9HSsJhd|YBWip$y%myD`e_%K0aYVT6} zZT~5XOs_zPUSuZqo))JdHBnv?X$nS)aC&*XS!TdayZMWl@iCKbTZAOoqDy#_%1J0YRXwnZPt9aOquTCufdP05}`d~>SS^?H> z1-ck~5&QyLFfhN=EH$|1qhbhBhH8O5$?Eorura9?`1^MmELj?v3>#T0NqseC3Rv`H zSA|96m&l85D(2(N2NoJ(`u-EwneM%7+I@4!Yt$b*UL9!epMAV2Wex$gbC1`Jv^k1i zbrOOX3%i_{{4gl|?g65A*9jE>-^)*Qv5|{UYAKu#o;z5pXww0%O15&rD3#4K9-^K; z11=b2xaNMI=(vY9-+aWgq#QKvvP13QAe_DZV)?nG^9MuW}fF( zrzr|4{`HrbrDOdipMBoX7M^y>E;xSeXe0bK#@R}ATv~=akldLy*=ypFeNaA$cW9%AL_CaUKR*eI1sJ$!N-cD|R+xEZ0h0H-ESLXFnN7g_f+UoEO z^uZxrsHpHTPIdTnPEEkWNWc078vcpc4>&oR$$Z*0V?Y|J9eLyUmZUA}bt+{-?`X6E zHmWFS^m5(_OZm=~aH(49i)d1zlG8;T>1g+33U|)s1P&K-BLOZMDAodK2xN~lc8h0+ zepjc1eaxcU!)>bq_;6f^=4wR*HA)|;qMd10!8lAcsrr}{Ts=iA3E~xY1-9wq0^Fa1yUIQ=xY-}|q3>N+zy%i@=uPtZ zhYj}+8=-%+agB`-`9(h~dbF4R2SRjW*ze$%hPt}=eS6VFk7sMY=hG8FCivuKgv|d5 z=lQj(^>c|6-sprsxk{%$j7?+I^V)Is8%i(EML2!Umb3a?4VvR z;S!l47?b>`e8As@=-Rf1R&4|CitsDV?5r`TU0q?_}2r#YOW2f*(r>c<0TIC7$uj$nFFKWm*^NqTO~S{(VsH9 zZd~}({nuMJO+Z~Afvwq&(`GAd>W#&2M@`$|(`xnvYxd-D>xL1L*{lYN!v|lm=U#r9 z=xiT;E4m)tiOe2HXmmg0h;)(JDR^|+q3%bHzOr6qb}ENXH%=`d@E+pb8NczZRy7-@ z{n%=CBl5)8zRlzCH6Zb97D8h_?Ang8X0uD`bIi9H-~U6J2Wxp)gN}YYvG@=^z^Khm zmPHXYf1JHr+Hemf@Ar82XL-GQ*g83FluOQd;q967O1%E+G1<9UnP-aLpKbo(BM*O6 zz25P`4U+xvZ^FI7cBVe`wkw|I$k{834<^fv-sh50_>_Y%I{c$n@4@RhS*^zwP#IF) zy_}A&S(09I3eG?M!B-V__x;V^Mh4in^*?65kgATB{~;L#1$S{g+_gvsRz&JB4sBpV z+h|Hv?bvAb8%?d2zY0d>SCqfkI|8B#QeLsr9;cP+z!9TqK~mp*M+f9P1_AS4wBb#h zh@FUNYxK~+w2Mb!DbQuUm^|g@<{5ABlJ0b;8|p>X(GfM8{PP@3{k`BIQ=n?+_l>PG zKkx>B0dWD6 z1*5Vh-*TIypN-1Jz$uKUJ#`b!;9+;G;5f7gu_k6iQp;ZQYKV;N{=Cq)u0H`5w13bP znn%@$DSO+_04$FaEU#e+%x2(vIGeE-@ZN`$xXk>n;CJ07#PPNK#7umz!UwQMhu38M zB@x=;F2q!LAO6BuB>y%t2ks(F+3xpY!L5~SU)4IcP^x{)vYEjS-ItQ?iyiWWk0C7* z?!;eWX1Es@LH>osrT<n&=8DA_l z8K=Z^uS5^Shgj&do5%amY$F7s_Nd4+SqLKGqfSv%ehy=w?p}=QP%n184Sc=LaRVVu zKLC8ypz&=lXVZz~M=U7WHYTl%(tY))v;Cxp)2F;I;(cwwVXBXnjHQ z0yjSJ8sP`fwXE*_=9$aZf96@vQsT3`YZx>wtVR~@^*@%aL6^Ci<(2%x?f*z;#A>`* zpYVC?ucqh^tl=sfM?HR=q`;f1nvD(R6g3;CGFx_F;GtWDLVfHl^yqm@&tKC)^Jn4F0rN0B^Q%ApAzSSk@REf=F4HoYdo-av!l#h?YJ~`k&QQ z?L-eKuxm5*R#obAiO&&vk4AYS@`f?@+(y>!GCxMlIT&C5BIdMMY-TK$6^rG>V)ah@ zB4$G@wi7Wxzc*qwBSu(6%-zo0{pJ&lS>^!*%525oh}rJEjF?Aav7=5*9mUiTDSHC_ z^Y{_j_-QBdLpNoUn^NzlY<5$ga#OzHrZl)IHEzl-H{~%mrP)o{=B7OBru>tevfEAB z?xyT1tih@0OdHHAcD4MBmBuygqUhFL~zkbZRt_;`{dqa~-z>?gE-;E4+Bgt-Llp9HLBbP}eVpel9!!KfPjK!upRBc(? zi2wkM+I#p-)p3Ke>X4ujhF40>9e9jedImpoByBxkX?fmS0K+{vF-bny`$i1FWvmnL z-Lv!DG2A`HX+g>ED8gIiY$JAjeC0%A z+uxd0PE4*I{tTBVx*<-rf~bc(F=6~&GX}{c(Fs7*tAfYvTyOPlUTiQ`FVKIJB#r}P z_D}8Y{zZImb0+O*n{{XnWZ}@S*ov(gX!eb2>zzncThoA18hFs4Am2M&coZ5}%>4sA zO*v(ooaiVg6GdMWyW8jc5l?7E78 z(d-k@8+A+!8cl+~IG2!?YcS*97AAJcX&qhaMf1fZ_;!Msw6=GW?3tI3j6e{=K^VP1 zaoWE&zrF1PzazdFO*OZYE<|><8U#4L28%F)vP(SEKg2TmbS7`_C8eGCT3(>yw$8D* zXc8BRd<|Q5A;(mMITvV=g;QAbbgCg+sla(8@fV!|Mo4^H1cZbk8)#SJFhsW3?OZyE z=~@bB*H&e0cAYt)cah(!jLoj{9Fg}dFCuRkvnpkRqhKa= zM?2Namc_hSF#fIHsRSLOj4PGQnM9`BFzO%zq?`MY(=v(qJpS2ATA-+WTr+Xt#K)|y zY%LBQU=!+i=GGnf02i3h5D^!2hs=H*k{N)FjmR6u_IR)#4E4L?xM7atAE!kEnD`@$ zv9>Z1=bLln0PKP*a1JjLO#(agi(WMFXu@RMal`gGG6ej*#^YFmuC<=#v#pJ3=Xa*R z`z%#vW&}FnZN&bEu{?U4J0Xou>3P;|nIu{C9p+2*NfsS_Z1^3|k%J%U(+HP-;9rO* zG0b-}^6_*;x6)~!;18U_;bbiZXK%EUykG(ivoFB9s?%D48}i468+KU>VAS)3b$_b0 z0QQ@DthG2+^IJF(ale2(i;#3$K4GG(8bwgajX(#qO0>`7@mT${YWQ@OJ%{~r~+&ju*^1MKo3UrBE7^wx{>;0C%iRfH>?&8ax zfK84q|D_INH$xA`_Kj|bPL&^n2lHG%;304*ny)uIHH4g9URiZ0UhkqL8}fr zS(lA#65QPfX{1c(nu(PL>KrEPS7>VGC+{z3+_S&@Ul0u3uW8_Z&AE4Jex`S6hTM{Y zFOnR0n(ntB^LpZb44W9*LS}ByPQ8wMGR1!NLidvbIx-smB4uPe{JFkc^u!dWPh_VH zh2-!-htdv!L0xKoFzn&Wp$vK1Q(nk9?XKsFXHig+`GLC=*dBkQi|sRh0OQzO;K4y0 zIR@%MKA}9&(%|D-?~LmxG3NT08`nTR=dQb`{*Yf^-X;SJotZ%W{xUtVWq+}OO+cRcF{8_#Fawn*8)@kDZLNU_-yl0gRi>4P)1i%)lOqsSbOqa9W0=kx=;gvw-z zq^imkL~Kb{l^!NOMz%HOVE5<*{DUO;iQ-E{i3Flyd(rP~|43EIJ%LE&370x6PdYK} zn$60G35hh-)Ai-k*noHee0u_x-d#^ZGnpap>_jR%V;>)PVzgsz?1qV{8Mo1n%{=o-!TAxvlc%vk%( zSo?YgZ{LveQC8QVTRu{-?n`AYzZR5w-_Y{et=gu$+Rq!dWn3+g)M&2F+QWOjuzYM) z)-VFA!JD=rf;+U4Br-kj2UQAD20A$_m46^}Qy$z;!M?S-1W^$jphHpBUUU}wg2t}A z-s-@Qor?sK0M816H-a_TL7Y^xi9005uE39{K^uv>4zln)ZtvNC8IiDVMkOab!(4(_ z*pe!(^R8b79Xgr=zjOMBX6eqP^|x3#(|fWq19cFUj<$7;us2@Ak7wjeKUp%qdunVx zvSxK<%|Ncdv2H$LMw2CPX8Zap%+))StXVxUL}7j9Bugy$De6IUdH@wzk@c>h0s3JD zM&*1ogT&ODgp!I~oVJX7bfYmL{i}rJYH*34!PM{=6uPVv9U(F5h9a zPC!-tU0L4g+1Q4ot3W9u)WD&VH%Zg8lZchYdUiR%pZ zWPVdXS$PIuWG=2Z%q=Js7K+v4`e-Gh0IQYr_=m8nYn5(?sgOY393y;?JzHGYrO;yiX^ZFySiuM8W~WGu2}2m zcxC;XSX7#|xV}&2kw6`BNPpcc`J-Rq%4aLK4ydu) z2oX|7)n_DWHxaF98qsL|H5$?Ou1k-O!pr#h>#8C`ZR}D+Dq_rSILspNm?H*?VT1xV z8nAP}1ODrJs|yaJ8S|kV3x8($hbC>@<51DzY2M<6c@Q>(T{gB?0aj=r)Ztqr^d;0i zD0ushZTTO{&;ViL@W@q%af*IG&B6lcfn|HA&+-O$n58vIhTIiGQquHUNkRKr0MFA6 z5fjbJNdnT1GQvTy47lm42}YxrV|=tB-un|qDn&&sa~rWkFhR4EXN9Na!mGit%z`?@ z{5YCzFY3)whtpp`S5W*2s5#b6_s@WOG73|tv+S8kzQuLjR~ozUZ?-p2oS3}HiVEte zDh^abVeP?RMt>rS+tny_bdC|4h^Ijy5=~{XFg!H^o*yeRP=E9mLLkQA0uZ#fSru$~ z`5qDgo9wjvF+OvhQm{J{mrN>uAT_q$2)&am+_h`7`0;M^A{9V_){iZ9Wzi(eUO0O4 zMs&*>_>3e8uw zymthBAN;kdxlff@&3&ulFHnQ;2JGb9HN&?f!Fpg!`pZ@}%sDYDEvk-DmCUbBm+xb# zvMx~jBW1B|uQGSrD?XQe3fmJ_3oEvsml>s{j&W%U=#IsOcQU0`@;pL_$<*>Da3~U} z=`*#|(CfN_!V6DS)cahnK>n(#tA+64zx?d`17 zmZCyWl3sAv7D>wglr~?L4y~v#iw^1~5Xby(KN$zybug5ict0mDAWhz_n`kA&*09nudhj zLNruMauZ4e%@uzl`a>jX1aQz`SI%^jUXb4LYJxphn0-)b^_I<+&sb<5F!Ekf@*vKD z)T`zDg>^U5Y(!?5P2?N@2zNe}UC*~qaRIAq0G`Vo#q@V+lZ`p`2#qi2)~I?nen(N& z5~vO;?4pG0ea}ggI>i{B6fbCnbIWX=b+|{%p$geC46j8YW(ylR+^C%T3Bt6I-7|Ix z_LTj^8xd_T4tqot0J-xGBW^H005vcwx?TOAPhQw*saBYc!cpP^?(C20vv=lz#XU}> zikKG%08@J2Z@*f;=aoMks{gB2AA(lg5rS5Vw%eDC(4|93Gu_7Ut&DXw-Iv1+h--o8v z3>kbQTLRTWG?wAN4BA|p)FV~L-6n$Qs&?an8w*vf66sV``y_H)RUKfYmPOe9TZH$F z5Z)7Jl3Z=dnq$75f%!K0ZY0pkUayqS@|u&fCn6Ws+y%F-sm$7~H1N%{<0&L9$T}NTDHMwbV-krfYx`TX-Or02tp!!5Aw{kk~U}PKz~rd+d!B z-1oKp>)G~DQUki9&iHOVJ!3)Fx{s;_T@kj}L*v?TjGaZ@AkREA>NmSG(A40O-T-!M zTKz`&OBh(E&E;$}+AvE7M-QKR$=6icTdxj1+)*q2!=)LQW!B;!~e zZDUQDkCC3&rN>jO(tR2eP05sGiIK+{yX%>;2mIag^!>b`fkYc zNAd(fDBP+g53(AI@i#N&8Y5JXcJ#u>L!b{$H%pDrO1HDjEAXXDF zvt>21Cve*2yANK1_6^fJezV(gD2xvtHYyk4^)nbqn1W#*=&W1h0oC##pdVLh#s~vu%UntDI4IT*IGP2>&^0tej7}>|TMUHU>B2 zN#-@oQ7~%Wt7kfKQe-_w#%XOLhv%ijBhb9P(W*SkM~r?eY@J(`$M9tPv&i?gU=3E#Yu@A zR~4rjc|=Co?qU};Eb?SLaho-KKN4Z6_cY(h1D4Od)!|couH{SG;j4WRk#xuoWeA}o zUv0n7_l2vmi zMVb%!u_o1+NW(N-+Jbm;50tqfp0Ih~I_!mrCv(sWLiTw|CW-Q&Bc-VKu08`JG$Nj` zunQ7TSZGW5a_7 z_A*D20MzC?H8FCUO#~%SXhnG=p-QRc2aG`LPrz)|#z)v!qhVcp0yT2=)D&9OUyPA= zv5aK05Mv0kX<>n1s0X@B4%e(8#p4PAFH2bYq4fN1Gz^m)*hYVP8@w?7i|;toR{jDV zv9y?vJp&k|$ZLl~KHRno_W<_Bu3D*~R@d-fNWxCQHd=DYJ0L3>dK$1=h>zF@gE=pv z-1J;*=RAoQ+LQH1EeCBNyE_^D*93=UXTBKx^^K~Q@}E^2g0U@W)EP7?$U;duLgxMo znBzjR8i8{);~D=X@z_P*Spy_P5rbeuo8PtYYk+h^e~^ZpT-D4K!18skPnt7BgtztA z;(*m|z&kqyhO#-=wY>p>$RK;})xw;Z5XdrHGcx6qU>EF0Gat!HHx%{G>L++vyQN-l zOW)QF6yv;l#+F|A!qUppW;AOtB=oe%_SUh|EWa1qu)l)WIvnouNZo> z{m!}qiwMfUShb)Lkm%(`(~SEvAPwJ_0kT#bU?`hCp)@>eZe-Rpg2@u=Y+1Nu#m;J5 z_O*nA#^%h8BIFyPP0ZWEOiHZynbHM+uh>#F<)TssY%IuSDiMuW5ft-Io02<0G-eAR z8qY+~_U3S_ks!0-^h$u~+gK&)s?rCiwVj4lQ$?BB+u`;tdKEr`bb;1P5+GG9w zrDY3$26${9c&ykc%RI1tj#aA}BNhu{Fm}5Cvf#C_SKi2J)F;;JeA0Q?cM|wIK2?)) z=@W8fUS>-Msw|04lI~zLv`*Hf2SFmdXCKZY^kz0gJY>sc56mZHrdf}rWUkNOaW(od z4O!G_a)$%41$C~l&3=pN?JU%BATR+R8M|hVaI8(+x;t1Z?vfMw#tF=86C${g?RABM z)4GE3k8y_s^Ez`Ke$(4-Pt9t3YoxPSsOJVp`O9QL5xHGRym*F>3FmDc-{nO%G@CmU zj9&dBOyzsqG2!R3Gw0loxE=Xn^GmF`PdSY}iMDd2U_at}R;>Wc&SCSXZn0VjoIGsp zUJZMqZ;Mn_%fG%_j-juXje`MQJ^#UkaD3eR zO-Q~P*&OlJl89GEWO51AA(eBAPi_V}E8~=m8Czs(nWH4s=1|o$GPRV)rk3*9)Kbo= z1%rzDJfzB>z(brJl-J|Y<%dH4nPQx_c&@_*Q?_8uiYA#KfOb#fj9MLV7Pd@HWQrnT zVx@{r-UOx?ZN)dHUVfQ!?=r(`T*@Jl*_v11{}<&Su&L5&co>ZC#*IhHF(Sd-jNL1^ z0>nYUsZkV#@{*?K;xsCX2UuU>G}Zkv8Z~gGo9j_5=RCOC3|`U;?TEnU%s@jBcM=*f ztp!odsmH@+qX!BUR_V@6!IR*x^~?%2obXJ{pb!sZl11XyPkcM2g_AO{ z@}d62toOh)8u@IBkV?B7k%`@h6U_$M`oZB_!iO@GxH34^H>0m%Oj4j_yn4BqY~Mx1zz3unNoqf^SdCZ@2-56h$)q2A1l?x-aa`;I!eOAHa#8?|nbmGYDdTb4B%A>ZD5Pah zmw7sp>#~EIu>U$_NVfjyTbC&D zy$x-&*s^31uVM7rp_e9!hU26_t7t8wSBrQ@L*L@tsP_%dM8DXDo;x)9B%xD*>cO-@ zOceIji_r>L;~6-2#2aSS2oKXsGqmhJvW10PCg zpgwkaFS-%4se=jrs_66+c#3ap<$zqU;ffWIo*gXFx_F-Fq}TC}k$XC`X$>sW*&kI9B05q$vM_dF~{BJUq}NyMk~Ra0oPnkh7C znOJSEM!b8tf&*>!OMU*Ld6+#m71s&y5?i#39lp}8m-1*OE`RYIfA-B_F;cEc!3)_T zYmnr0o$-v;R&o_5?^bdZwV5r^g*z=2pD~t{r=*>#o@LWE7KLkPk`%EIPJ0NP;g*Pk z>Y0tm7yb86WNJCa7thqNiYGVYFKAY`2`do|gL;915T$xtU@$_xs`5kX^;lj_Blg&7 zF*tn1fy3zwgTrT?I+5K4)&;>ppki%fzm;xhFcb$v0l}a-W0iEmJ$lebb&0_Er(X&` z&@`@D4i=u|rh1H{>wqBO4nY#!eL`?L7m3X!^ITl8!0X!*`Id9=Su-zz*;zG@v1CWE zw;Fd7%dy^-6N4EQhtM0tO#T%rl(;^KB?83{Vx!SFd6FT5Zgd*wu8!z-RPT;D`La9e za>^fV{zY%E9NtIol7S}^juUwVL`?#hCRm~qq4i<*XbOK9KB_Yt>+lVXEx(24QYGfq z^!=7Tv=^-yInbHzzupKhM-E3ZM!xC(c!ES|gmduPl2aq0ZI%ju*ib5YJ(|u}f~}F^ z7(K0_5dHAKu<@<$OHPa#)}c){Tr0ZP%1h4NZ{+n@d43$AB#Xv_HfnXx^Vn%GN%ofb z)wS6Bi5s`k>v`y(^8V%G(<=BO?~I_Z+~mxo>qbU$Q#ie=7wFy@cCx6=3H@MLnCTkB zBEOdG{hD7LwHBYYf?_c<#KGZxD7pVJ8495GR$dFT&HLM+eF_UMbLOBtr;HPy>Dh|cn>+!QMt zn>c2X{_ zq%CcGE3X*aX7L`~-7CcIY))*)6Zd9?id~GOAn+3TkeVWr-yy`#@7f+6PqsxGu(t{g2qh??igUN6FFlY3?5(1pCzPOsDh4UxX}KoXmmWwWiS*FbJdhq% zDctLL4T{g^2P2HC9h9J(QmqkfU2wCxSB=oFJm`4T+YWQ)E1)WIrMB*FRDK^~e_LU) z-wM{_DvVt`91ge|V1JC$6)qUzZGwJxFKnL%VJ|c`NqT{J-qQ|g(r_wvl6F#4UBf$b&FlvlhNXiH^eE@NhB`$4gg6yCG;K>|dMvR*6EX zdmjZg%ugP@C?(yX#`G}tv-G{HJ<20ixEQlWwM8*LFC}E6uOvu79HMJtfZ`>!K>$^O zWC7IYaFK)>V4zq}cS?fi^Y*YB>Mwpg}0K36qHo`1@!Z50i0H1(jM$>Ic zgJI%GxMEf72GGt8K}o~FFTY>voo-H7tszHU>}e8*_(d|D0#?1$#ysl z8XP5$7~z|ce`u6ki%s4^Af4f&J<9^4oGG={sMKB5fsXD^7}i*Frbtp9la2zyU)4jHWn7wg|`&ELKUND}%7 z9K7XDCZ89fLqqb3E2HZ%0}Md#^~v}$RLdESlfpGIfRtfq&ow_7A$nUL0tSCPzZ;@~ zze8iBfuC~@cCR{L`-<-yqHTZt_#}?bnll1x7xki57_Ef&gA>A)(XZ>n8dBhW@dYgHi#T4LsFEaK>CBM@!H6U5h7n=u~Hz; zv^KZm3w74^Pl4!x#;Pq$V2PV(cL8F^x2-)#5rbK}#~q6gFJWefn)lVA}5b#U8*ETLAZ2`|PPVb19** z@y9a3w&R{3$PmV-aDMVAYaRVK8Vh5zdCZi5u$_us9MtP3n1`+jS=`iIt0$u#$!U=w1l6q;20IDOrUP`<6G_0k0bbN zRUKe!tAx6F8Y?_Ppet*UDu=+MyxIy^aUW+h3tGEx;%I!!X|ppLo6kQS!6O`qr5Fh5 zD^UZ^CeC)eqn={CH~$Ehm%Tm=%8|oe7=ZVWUJZ*5gnd;U_QFv;B~QU{w`$^NENdXr zRDGrYh|Gyi-&!8KnDN>CS28|&g4chC8mnR%tE14y1zC1#>O6)A%n)$M0k*rnMD`P^ z2t2HZxN<%KiPI4&g~|rft;oM*$2ZHzG9k)hx?}-mV0j*NB-R&U8oHOSE|hG0Vf>}^ znBNF}Tu9cDiaS;xjZVjyLhKuY5`UQmYB6D-^Ze5PeUibTtv6ENhF(tkXj@Yr50^j-rCGjqvq1T<1?%5Bn!h% z(7*CYS0JV@a76@fXzfhQZi$Q)ew~@zEARa3j!7UNv9p0UFy=sGK7?pBOnO8_C6o>C z&INMc>DDid^Ze72qfsi(y@wg07bc?oS^>ZS!LekAF58tG=O(OAH4ra&ig}*h(A5ks zNXnQvvZMx=D^AwNW*h6`W}6oFYRCy^23|&Fm>?YE!XYz9%83I4@^W_oPh#m7725z( zp7nVD2}-_-(_M?z|l-)!-i2}QsIfQ;~QsPP$nllW}6a1H=IFUT(#9eG{hyxNXhqZ0Uovar`Dx9uvn6+6e}fC-zm#Ibl*F5$~z)IO3!kgjDg zNp@%s^LUKI*a-_(hulS~b&kRZU$aWVLoQn>!ec)lq@}67mh{y1$vrNCMgNH#54y5J zu&KtyCe?uv7-W?yxBZ{%qDVqh1^G?7`c!0_QOrS_$Ii%D8wr1pXS8Z=gIv@^yrLxk|!(c>(K_8nWRX zXlX~`Hn@2o8QccF>Ry=4sAW&FE~z>EwiVoF&s=LXeJQc2a;&gl36F%ucNl|$1srx= zcxnQV)i=;Yzfw2UD^l_3YA!3STJq)e%_LUn{_;2m8@aSqM0>{liF026^^6S81@9{T zOB_~zb+lTBwt?To=Xt%;B)Ac!R;Jm)0f8UmJ>2V&hmPN=7A|4c*?BO1fe6+!bY={r z7ZxV^m$5i#S;b_@4VT9ayyYwSZ-=sZ0;@+k=I?k1kYSUy&qb4#+~Z&nrF8^V!7(~7 z?!q;yyEGaScmEr+K5v4f~uKJYa;L#?DMfVI6e&N0!!g{D6J6^6RYN z4twT2qN^r#X?P;KLdA+uc>`|0cN(Gbi2pf|_O}=$%~E@-HbShz5V#GXy>?YWTkTc_ zt+=ZSrdSm`qErlyeQ7vXQruyqq)VkEktHPS(dKYI&K@ z@OyBsvtx)OEXI7EZ840>cV#?zLWBL_D%!qQ;c3W_xW0iUD6t=WDA9iKp+5G5+hg{F z<;qjsgs{UXn`&<3YFX50)q7ThzWLJdh$!L(+T*5#ABbhsT*cR*Z*9V$a69%%H^`bh zaA=@GVX;AJl^#+J&&);F;G*)7*$achUq)v%gMn>&yx`9nfJ8C)pFf6VkuN9ZAHhv` zd_`HH!w>1Wd@^pQ&j=*1%Xe66y+{Gg+~mdO)%tdXS2S}QseHd@9N_&L7G2y)npAN> zvb3GK%DaE`YmPrJ?37oYhByM7EwAWKddoYJZ}b)}#}efJCuOOHOTkMq2fG<`_& zIf@%HB%gMKeOdo``8~~Hz@|m;JJyr3rUdW5gwviwDDLtjNL$N~#8#aZOqW%so~oV+ zp@D3{cVOAYdQ!eZNnhqyf^?Cp*pjA-Z=)0NiuwgoPh8mg6ZyF~{?TCiE92)wG4ioE zcGN@WE^qVu&|jla{)L{BY>Q*~pT553afuAxg`AiO9twA2Z(xtG?lvWHJ^yeS<2^vV8cCE*IiqR} zh?ldEq`3s#U-CDq-Xw4Ahlm#|^#^J6;;$0(G&(tQ5+w77!R{-=J(%JKWkObL%b}bX z8XT^GohC^an%6k_n9w{tgV&Np$v%{9VF(Z+Wifgez*@pFqMt{RecIz7Sg1-SzVKbb zu_@ML0h`BV92R}Dfb|Z!bd{ANmadCL#Vuj!YE&%(3y&{fHLDtMR;E{e&9I@;mkwuL z0wio2f^{v~iJaRXj2j;vZ<5+a%F!Hh4FjH(id zJLeTOox$c}^G_srYNY*j68ym76JVWJ6p&q|(0Z}xBePDGNTyXHnL1P)mru0~03}kY zGit$cF3HF_Ys(l6IvubH_C&vg8x1ZGriiK{``5zWJ)G(8p^h ztxn;gO-u1Lj$Z`+MJ zvo6=t>}_b?729?bMO!(Ha;C1eWL=oLB+cpEfSqxT&DXR0!gXB{;$m6XGk?Xbt3RF2 z?K^)sd_bh~^B*zG5$2y~mcGEVW;%*!)X^w2Gu1I!W#69?=QXsk4tT) z2cma$*smdfpX2N)QQ5;$w2AG7zK>lV*x(V%0VZ_X15d!SsVb=N&gKfdj!Qtz;x2Rx z4cfrm^DTq`<;YcX$^?}Z348OOfE{&g{63MWkfIseIdxKWE9wU>xE7M_X*7%J3gyTy zwJSgfKR>@#;Qx8+{WaVZY?R%`w+y-H(M-PO-1m^H^n(0N4fk`ui@F2OidVf$6_wHk z^EX}v4Hg;bL1>Z2N?5{RS}M1lp9nYLEI)XW_|qF`HcOkKt770HckFUT$LfaYWHcmp z_&88wC5FaVZeGzM)14>do(ntV0&R7 zJCqi;fIevt6$Xr5BdWtoV#A>gYr_C#uWM@xjECFJ8p-+?O-Z|@?ah&@b}8TLVT&1{ zlr&)nW-}%9;YQW95O87bkX6BJuqr6Sy_|mpB@BM5Ak4y&eR~m*akdEISe{*$C2S^9 z2e$GB6i1fG`#Tqj(jA3m<)vk`^#OuiT>qe(2A9kFNPy48?J38w;OWk%?W$T#2! z;lgzbVuayAIlAetY(KBB{Cjcq@qgm}-~!>8TCCIS$}|Ecwyyjoj&ap%gKEUZ!1z_D zfT;srd%~D{Pa(hch$wZn$JM_gS-?lw-gec$faViXP1ir0$So9Qm1{+?XLw8;J^ls< zW-41EZ*f2|%USu!5xJ%St)!r3rFL#nw!2CSp@*2;RZ;jC$OJqr7o7$NRR@_jA3z)X z&zl!3935vFdS?D>+ah;xShjWR%}u8K54sen zzBUkofxN&*T89(_>L?6>!}yR=5E@^w5tt&J)Sj75W+UB5Jh40#s0N$)B>Fyp&HNF^ z>%Sq536G5*#r$ucf8EO(|C{Guv6QswPVPs+WI8N(P;Gpr>{n`zFx+v;YU$mn(_QLe zz^am8IBF%KJ=~CrK9I0ojzcs~8qTcc9-?JnJL^IY(H8StO$@u-qqLJh1?#Fmjsp6~ z_R-g<+^YGLtM@vU4e6Vdk98t(_oKfVP{84V1^k4^c73aP9+Djkcqn#Ub-|j<(N=tG zmGd~%`bQp(LP>v%s5A9b(uezXa``^0`sdz0`DdbSCA9&s4ji!xj;NllKfDMyEd{WK z5UQecS%sWs@U$Yj7$#YuEyN<^7~K-ZD0QIgDHc=#i!6Vkrn6*?AMRPS9y4t`ULAtoMbV z>`gpI({t1cni+|oqm_J}vevoJ&?XZ?UBp*VwtV%5Nt{@F}nTF%lKb*7(cymBz8@mU(31UyKGQ- z3;$~NzvKv7EzJ}Ys}CaCVey(`2Qqre3|{|PWc_pSda76T=k*sWMEnWstpA_*{LTMw z^*S0#Q0J661R5>%FM~Ml9Kd)|RGamdYRaauX&3 zdxIEqJCnW_R^X<<3fwg?MZolVUhm7^SGzAa=siu_4269-yn)@&VxV#Gt>`>FLI1*;p3`?(|d>wB8J zSXVqpT_MZl%r{BggsZ)dQV{N-rog8lEX{Q?%U0?D$*nbbzedHpC6bB;Tg_1Gf&1La zj%AB7w!pp5V@b`h5BIl#Yv0x_mDUv>i+`CFgZG17EaVQ@TM-wzR$#K!1|N&hgMmYR zEI3M?HupU!RSxDbm)>#%PvE1j*Vm!qzl0;?{AS)uo(sMo*vX1Ge()z*zE|{a3t*69 zXJ2Q?xWEj_$+L$&z>cN&GzRJ2>g4RatQiFjMJM5M?IRD5Rqu9uaD$Wca3O34H=wf} zeD~0Caf!T#asda}_))9(Aa)yI!1{6*|N8mQJ*M8n-fQ!>@kROpw8!>Sj8ZowGw!j7KZhDD}|0MWv{?S*ozCr<+xRy;op{TOFXgZFMPUPS0w9=DO{pxgGB z`O4|9+xE96m5Yhng0a;}&s>5W-J`{73>@a}Uq2cYb5-%BVm6WqCCA~W^<6m1t)Al* zZxMFNPw@$)Ut9srA6uO>%9{uwR>z2+;(K<6Fs z1Dy{Sf+-fP;AEZp^ z>H=$kccMTmicC*}A%^g&;$hE^VAlf~A_o*aLAz~B@00dnZ3Hk#y2fJIPJ`*^3R?1! zR8*S+uR}zm!N&oaMOlv`MxV?~72xnq!DQ;)-{Oz{3ar(|2l6lYJI>JL1oL&aX+BA) zbdj3{PQVc{q0$oxoMb_fD#Am@NVqyi{>-11pF&HI2N0!0`*Ee{UzMcs3om#Px} zTQC-_7Y-`8f+P7$4x&+yvr&@@pi?|njkXGU;L$i8;mPnT&vKZIz+Q7-#vMxzzOb47 zm{x*mXA&Bh!0%^jfZ1kJJ<2PvbiEQCZeuHs1RETfC<>f z4kUM-z?i7LV9Hlnu$`NqnhrNLxU|x&yA5~b=DwNwvYz9=eLcDtNGAKb`5&aGkqQEj zzeoi~l|L&ujt4NUh{ldHLww;$;OMO0j_B%x<#@81*<1?UYXMxG6o@veCEBQ}%_o|w zSBR$Spem`c*+(=`Ezv+Fy?_!i`;0@AIr|u)4JiCs&Op(TGKOVrmy7?PeM@euk$FWS zWA$tBvHcFbUX9WvB0oLnkC;pLO}Ib`5r)Ux5^fyPK0oTC4fUU_u>b!)ALD_%eyIQb zzvXlPAIE*D|Ablp|5@J<Sr&s5SjkcLppqD ztqzYZ)!{FfIO%ulaM7K8%e@KDI}+;oGM+mVp3mOlsT;R7-j1`k>vI1479H-tCH{WT ze2*tB&*PbdemWJ||K17nobWSFczce1Kg|jKPPk^aPA|#U;UXvek`rF(gmY%; z_Y%VD5f936Uxd#eN66>zr$X{UXd;}5a62x) zvECgx#%I2VoN%lY{wm4ixePD3UGU#doFlnxP?DNe|obXug#0jf)PJ9RA)r_P3dX%}viI2mW?{L$B1NCk?@RlaMu0sBH;Cnkl z#+L#H2qcccgKGmi9pMk0{NqS-PX3HycH*hP@32!&E5@4BH`|tqGAVT9pZxL@;wuv3UrdPKj56K) zo+V3`7q4D2_kq>R0{1RoP_$<4x+OQFPG#lTUWeb&ANe~ zNl6QeRxU4Gxa{kz3fJ}juBfnZ?#kl+$%B-WyYk+Z>+bINd0t`hyx{6t>zA!u#nQ7k z6c4BYS!M@|vV$x7eY&VCxDQ%a(VHs0|%~8 z>zr?vRB^2I^=n{b|a1nsb zUAbyi&dPPg%kIUaJJfE2X01YTo+bGkZYf-LmuCsUH-ByM%GJTu#Ph^w&yst9zJ*20 zR?RECzgYT)vhR`c?~`&%;o3gWx8A*`sJLHZ{suux^jEjmZM>ug?!7C2SDN;-GQK!<>bP;4nO}4= zFCE3s&t3WT&#!U#2!of-{PrwZnaG0V7hunxiHwZX{G%1o!G6q>gZ~WqJ^zE{$ZyG# zV!+CIK(J)V!ockdU<_RnT%zZg`9DG5q zr%*mK1d%k6i#ul z#D|BHz*MaAtiUuCIB5lDV&!L>nBCcSZXQfP!^g4V2yx-e?Z6n_fi$da&e;i`cAEQ^ z-to1AFRaDKOY#3B01RM!>5n~-s}RTU+cy5x;y>``(tkjRF}?I2gusVOIlp3Eaw)`> zSbj`}vQEM0L>&*q4G1Zxu*?d^5iUiDsb1o&KO6r=7C?yC5=Y=!?L0G%DO%n!UXT!< znh^g?LOg*R6@ZbgURzYSE|H_>6l(4!94&uC;`Fh>VL&lvH+$gc;0}p%_5U~IGBQ0L Psz102Vrp;|M1TPR%>Xhx literal 0 HcmV?d00001

h`;X{6X9cI2}W3aL@+?Zi(AzH^%X5r2SI|vl=D%?lvl| z5)JZvvDBz6_f;XQNGt^&1B*z>U{zW2y{pc>*g!huU!2$6Cd;K7hMbATfh$njnUFN! zoZp@I%eE?VR4aK?B4XZu*7}EnD_NwJVq(nBoIRU@UGX1Q+cXUMADa>F03uIn<^Y~z z|NOyy*dgrCpqx~{e$qCR&~C9)$Ozb8gUEc!a9hNzvGb!D1~n|D(7q!&Q=yxIF56K6 z>jcnVe*@NiSaG=WLN^}GE$iu5*_?+>Fb?e;uY@XF2uaA1jxTx5V{eUSNCnVMM(KOl zYQKaY^-xxFilhOBIwSYAh1xAhTWqDBJm$VJ?(6X0pEDw*l(R1Tw*dbhS ziw8H^WY&Q8dbTFk_Exsv zUMAn?QaTpj{x0IGic-8PYa8CcrmFtL8$$**HAVqjuq{C&zo4@LdgHh=v``91s{idxiO$J|7Z*V4$` z;QPw=1$lb|3#D(?8j4!we^xQj(|$k1SjSf0z#fN$T9R6aT9;anTF=VDLWf$P+JxGa z+Kk$g+M3$hz}Cb{pW2q%&RoaNnA)D&f!dMUnc9WgmGtlLD`fJ$%U_Nyf3@TNQ-9sR zne_3O#K`&&V*1;TkcElyA7}r}Sbq=P{I9!pDq>wY;>~^!;fojM(F=&&SS#eC)Ayl? z*M?K5_6ExtCxZ7;gv-+BFfitWQu@b+!Vb!jn3@|<|J0qQ$&E!3z#o#khwbP%@?ih! z%sR??bJFa3Ywdcv@?<)8-qvm;U<0(zo=c`7z%T*S-dInc02o2^@it%fHt=>PN|CA? zqUVJMFtN0RIuFhTAkhQxsp0vpo-K*<8-Ri{eF6tOhz8K3yeAhDcv+4YEG4)I(9+ou zLL^}vXO|QpQi{M&f(fI#Kn9>{05irL6%CRO)|-F@Bm_i69}fw~yGQ?5zcIo{3W@+Y z4fkk%@pV=OFb=*P5a=*Ca&40PDvD(Y$X9r_i6;cEFM60vDq&NWlsoe-f z+^72@;B?RgF3~Cd@Hi0CAs|VoI1%^cAq1U-u=w2NesygfJ5fQJr!Lzg428_>7$ERo zX-N#XR+J&ZyoP{o2-YA#q_kq4S>#_@ldDqrv!eQHG~Rq^K+a&mQ-L@Hc{0Wf@DU)x z42Z)(Jc%I75K?*cgz5mIG&MZ%8Gx$piZEa_w(1lgGKStUZ(hiVI#6fq z{*(t(v$S&-`4OAJw@~3cVq4AOe6A=~mSj)8`NTK2$O^l{YC7jBT4){4pMvHH zd3@E;#OMaTl$bXiaK3y~u~vnVXQ&K2ZvrO~wDNzjd6)PyRyKW#xtw8wh z;)n5#WEA3#`|!?Jf`A`q*W0!f>XZtctVAqzGtROGV;UitQ2eS_?2&$WW zFuljwnKGpZv-481Gca>AolBU~F-){E9+pL+c6pq9V>7 zPO;`d<7LXj214vek2m(%?yGAt&_C;yFN#g_K1MZj_VTpaUuYFwnva=|ML6eYmhot3 z=9$8NPxM_Z_SBl!HV{#Ffla?b3D^%sNK!Vr59}|}AV+SOu zXS9BI{`ET#6_))}@8@9TD2}`siBuj>mv(QqG)e)TA%QxNNCBbykfvf-Y=xlOMSM1 zcKqwGw9qTM`q5Yfry;}i5t9kk->0ep$cauBx@V>JH@n(TS2if}L&w7A^OTWrcBWi8 zG4^w8TKQti z=c{^Eus3V!lQlGWpx1rwo8LtTuT2{i}R?$V4i%oxsq#CSLTBfXR#kg52yq!D7j98zgBKeDu+%d*BM#5AiG zqDQfb3LR@b=BzwBnbR0$a@4ldP&c?tYiIZ)08h|09tTERx4at0N`MYt!nRzJ4K4g) zI+aRhlrKs#2MXj2_)b*Bv1g_|wF^e_q16qD5YXYh3N5~%wGxOnwW81^XIBlV%{)3o z0*4IWp6p?MpcL%y>3a z9X0B$nrZSGt*;f1#5-o0EMFO@>bkT<9XBInjxSoL)-|m5h(C1drItCN>JVjjUwFU* zIa`^-)vt?E$zjk>bJ>fkU2sJnP&Jj+0goJp4O5=9-BM__z&SlkG90VB@P5{FJ;?67 zgLIhVuw-Bd+F~dn*3mSJ}9^gX2oLsWlAUA>A+?b z{21?!byEf?!RbU`0CoXlmT4V(Ro%!48A&q1Snq24Yf|g%LaYgKv$eC#%_%->Xe90F zyz0tPexBn`+}`9-gx=KXv7l;(?88D_LI1Di3+(l}x6iZ#$|1;-z?t;VhO{RlX+vxT z4v4EG=^^QK(G=&|jC^_}nk;QZXA0|yiw`Lenq9smk&}dk%E=-!=(l=h10hoNTa{=7B*}E-BH5y7IAf$ zCCSEil^K<)Cp)dwv^;~6T5thap}?ngeRL^>tTafZUCbd(%%lAB;zFrob&+VdUlaRo z(RR`*=0xS04oT9h8V?!H*isW5c9#F^G}O3i$sAr|OQ06dBF>bT{L|oPHu1tT3UyDkpdu?AI{q>5^2hN)utF7?v1>rm>oSo7C$ z?Mtl}*0Q932Y&y#i{bwSe%1JeM5P4&27bQ_7XBUf{Wcu^4UZ=ji|;^`#a*e@mmHDP zg+f=aD*q^a-E6wLczbf;TUa)u9=9L7o81%aoE&+glI-)bXORbbltyB!2lm|{40#BEd<9qT^ z=DAZWoA*6nhzbJ~cyf+NW;UEAaKtTG`L!{H2$UR1^ya4b!4syZH{mfj;sc3S_o%_c7Zn0-+9_|5$s zPixW_oO)N-@7Rux30bbKgD&s~Zi{%hMfPKEkajp937`;fbSz**n=bh&AMTD6A2f=U zqo+z*$b$$$d>gDy9DpxKoe!8AADlrTaXvSoOA;&YYjD_Iny$2L;-@~K^ZJ;|oRH4- zsg%!S)$D4PSO@qW?1ig+Y{p$>N$H^AA0Qap_s$6Rcpoor2ls2LU@Qz+egiH5Vx^`4 zp&|mHyvI#Je@cLGAppYqynO)BM3`aZ`*%d|DFHa+Xu2__{oS#PiGaLY5M+;`aYlaI z6MI;F_9uMxctu`cfqfvOJyQ!rPyxQip4hzy@o$|+K7e}xirE856MX{B1ERr(y$#6B zfM`E|RqgHv1b&2t5FwpNiEw}Zc*T5fa~ztrf`I_@H6A{bs+%FAcZTLqg^*9RhDb%PU z>9)E{7u^5AZayWdJ< zmV3$Wna!o`+PuI?J_es$ejxN-sqXx78OxRNsdM@x;HUj_Wr-gQ6BLYO zPuCR?Eq%y_+b8ypvy47TNv*k(aZPU-#Im{?rS3j@H0AZJZ|Wtp|ZO(alQvB_>=B9?b3yB^jVPBlg~@LR~McitgD z9d>WDOZ>jtF;EiyZeY!Xaj$t67o7LJYnCWfi&9XVK!`@p zlh^>S#;%fvf+p9&vw?O_d#`fuQxe^m=63Dv;D=H4*#gcnLd&!=BhXws;6+5!&*Gm_ zMa|Jf8Ita!nfPjx?K>S_N5+ihQnSAh zon59>Ggt_@@QR6Xb>9h8dAJ8pujfG@#5_FX$^=bw}@5|oQoDq33h~v66o~6$F0pceMp|Y zZyXQwAp;*MwkB?el~-pm7(<$>=yg7$m`Ax*(ub^&r`U>KdLa zOCB8f2xk*3>|>-KA4(GP{`2U;AGKF|*#HxU8g5Ro1In^?kIq{10a*VoVEQF8q#;hx zFrx)I>(-k|E;&zK>d@v|TJflu-#|8HLwb@LfO)Gm&faRn@2w`PuJ~ALC zJ@!)ob*(s^e?3_iNvLaf$rt=W>DHl^yA@;uB1lCIbA%(3U5;xzPYZY6$_r&h>Q;}9 z){Q+CjsdGaim)< z6M)a7+_-nsu%SZC`;r;Q{k2`PzWhE7~`cDC^ct3 zzb?bdJm?i=c7A4PXZ7F}5AFAJPpyi3Fv*YVxU%C-aOhEeqMc=uFziYS8V)m`a2)~o z`2zE+`Bw*)Va@R5qV~A(QP<1P=C1W=tBcFdO0WdCy>y36#Ec#*I9yB@NQ$+GTNhT^ z1>c@H^+*6^o_SK_L#ic}*GPD?tkMFl^iN|=Lh5flX4tXM{YVHaZxpcsy6NMs7U(`I zul?*jCmsc5qRaSqz3Ux~-Fa*{>NezD;$z4R(Aa1))Z~4$HkRYD5qu&o2i(g)D zVg(iF5N;-Vj-7$1E6Hqpg@Q(0Qo1Rd-m#i?>rHDa$gSHzXp7;eOk=6Q6My4IPvv;LlhpoMou{ZJ?t^e@P}`@CdkUT*?ax7@vVe&V=C{zo&p zX%K00NXVame<~_Uo{B6vF)ykph7q3X zj&Z1Bu~T+lnK`;*-sLe{xyMMgsJI{flqL+oWp|RmOTP+mhGDDVoECwsGD|LRhOpcFHpc%=Ev{5o+TIaIVLyvw zP&MXBC^X=3t6Eql_hDT+n}x=aRce*E30vYIX|3#sT>*f?T70`=n8ynV_ouzGxD8pH>#%KIm%s-}LYO8-4 zz0Fj!#6c$M-IpdU=%ntbO{crf<7vGY)thOGZcn%U_w?;D1VgvI8&v0pU2 z7;c(-${ctx6(E|0IHPOU&Ie4<;*_}fg0c;ZwaMhwXxB{rOHB3D_}88Kh-aC$*Iv~M z)l-4r-U`n=UQ?i>jOmh3O7j4ik+VotG+S|1rGb#tW1C_t3`l8r}uL(P{b63ir zZ7fniV`4Ot$uCBX^RAcPI>=JcY}&jNATD%&8~s@;^95I^wWd_sdvVo+U$noNQY|CN zF|N|=$`1+8{+4yt7gHT-ZjbMNBDK{sVxOGG&>lnM&c$(Zj*1~06PBmWdOY$%#}!n} zx=lpd>_IB4v&(ZPS)L?qR-mph&?76dzEAFfV7OOS5|Y@{))a%TjNc6qG7?*By64xd zj5n3aL{n04O`1E18?zTDVV>VWJ=AYupV|{!kTXg0oH8f6Cp|7o+H-TQb_18^ab~5EI!0Z%~|u2b81onKhQ?f+z@|z zG#v$Q!Pesfwdsft_A9791><(%<;k(P;Xj;84X3W#A(t8x`}|2pE7wT~UFJDxIuv{Ui1EIF-+^~14o@X{22Czf(c20?`FFN2I_JU z?(s}V>n{e93p>%h;QJj@dM^&r$)*LqS7K#K%=rk`bJUm#I|udG<11^YRj^k{T5TzP zeJwRuC-%`(%hIt4V6dk|43aeaoq|+rOj>E~6L_id8J)~~*!W0iubl}-;}mbHEkQ#Z zX{&aN>j|o~r4Q3t3$l0Pkv7TB7D#Jh97s!K>F&^T{_y)AFtkZpus!9df&LXBSjhYS z4Ux19>VpKVwHSA~;jkOH0md@SV%X@N?x;#*!7vduyligv1^5ohwgZ+I0cV#@`Wdx7 zqNHa+d@G-Dc8X`r|BgKQXOqGI6L}&b%qJxF7kMK0pM*oYZ|jZ!Q4YU{K(PMh9`S#t z9DWOvf7cC}zG;pBz@6yY>gbsn*qa*|+Ef3}vF%@~B=z64NooTd2OV>2LlZ{>YC|gr zTWU)aO9N`F@1M1ft%2p=R{ibh?`!N#oT=@NZ4C^l?VYTsT@7rl{*{yYi-GwUPUc?* zs{MnLVWImcPKK6+`9DaE-@Z5hEhi)Aq$2Nv@)NKJA{d!g#Ki_A0TEHmcs4BCSAjPa zF%}h3==^d(9oYh`sqaA7k-TaL;%$1;Qp%C z1_M|n0f?ZTrDd2s2m>G|VF?$4!lCo-P0*>~G z{WUwR+zofy_R!;oZ(>kHT1Ox6!`0fm6swM?LZG_JwHAMuN!QYGmzgIM10wXb5Uwl< zgVylZ=lk8q3F&V#*xtC}cf0960F_@qeuM38fp*OT<4psEgo3LA4DY@z@X6tVb%AaR zBZ9)?{5oHwdy!P**4^&ohPU7e1E4kW0&ETRMiBu0LdgcC1d9RtMD^Xp&zauB1oKv6 z5qSfAr$-kT5B`}`;s?mk@RDI1&jmHT#4q>}1wWKO!$Y?BHgj|LQAZU0yavFF672Vb z+sAtF#%H~?zt%WyH`7*!5pc{~{Umb1=`F3P|3?NYj+Te}asDcF=8>3SWqp7Cb-wNK zsg$dje7;@LMO$**$%@}u9Ij_v%gzsWPE=dW-cN|l2U<(Rvx`=r@6TQ!;nzR)Nd}nY zCgjOqOXGw^9gCJ#f|vymvElH?RGf(vsgl)ux*9s2sRIw|>W3di#nL%QP1`wQA zkzueBh!x7%9&n7b1xlfUVRTC#iG{D@9Zg4Yy6z>Ke$pY*B>H%d6l+qN$|;)ZsY}z% zt#S!f28(&}MX8yRm^33({krC-UL$Dk98}n<^6(Mi9!$~Go}>zTx=R*bql@8^cDF zB0WXItUGIG`NB<&navvELZK^vRFUu$%p>pL*_K*Gvp27s#fz!UA5M(L8q#6aW)(+< zTJt}mm5YMf+p&$p&i&<;MsG|~j@Zb-{v8M9FO4j zmP3-q9ul=#*%>UHpHW_AWFFtWTj2bd+3T5=coMdXT9Zq!t7)~+*=g}ksByNQ+$cU& z?$4~Mo6Il7LSo-+H%j=D0a(krt#+OfRKhQc(R+On5UbMti10K5k+9tLOk0xC$pEFC zbK;gs?_gnm;#o{V8m4hJVlpb>wLxBl1Oy|;UM!t5#8xZmZ6^mnGYW9SBcg!aZJs3a zs87JHixwTJ%Az4jK|u{IBI&3Q;B-D{pY3yvy>`oUcuI-5KUij2$sd1>^x!=j%yJNC zt#GLqhj!0#OkBbdOrsrPq98wInF*mF)jbq`vVudT9NaEEYf-3X#>89c^)?@Y3i!KkF=0n1xn zYRh5OSG2oF^7PQlj5i;J&~-Jv?8>?Yf`HtC;rOb#vsJvYPTo8~KA2*!d_AVJ1hTw2 z${YJ?hXu)QDNwY2uv={d!1?V->G@zCf`RbkgA zx2cgQMRa@SGJ`Co-k=QCoH66~aNR4!u4)3cPmwfHtB8_^y$Hs-t@Mc%a!vFqN!t!K ze_FqX^C+ABj@{ymbK7b1$Tx9hDuuRCiVNTY4E$c!1 zUF8-|*<15$cjKa9N_X*wtGw4-DUT-zAM#G4FsJTCz^0N_$Umy7Zon7AiUvCIU7n|jL`D)1vf!Qc{qX1SeD1%hXGOkclwo;|r{xH}i>{`T-T1QM&>F;avd zs`5ALf*MJr=qJE>f8-TSS+#5#9Cid>U{_k12`polfk~tJmWJ+t&u;eXjEKkKpq!p%@#Q~+jDGpv;Vv|I$sYixvOQO7WKKo$c0CE ztl?qLbU@XRM1b0zTwowqhd5~X)q2xt`sHq{W;<@Oh$_=m20gP5u|cYdn^IV z7*Gy^d8D|y-dj(3Gbmiz&6k^d#~VZ2`~pLXX-}bJzh$Sixfh~z&8!UF3X*QNB~NS? z?iM8LJtFL_7?Bi&CGT>B*;UYT$B4}`E^qcJU}{_`y6!pIk$$oK%!1CNv-OLOve~mL zlrTA-&^eU87;IIpC+!J%{bMweuS`C%@jH=K$m4UQ8F4VXLk@c?-DMpu*6LEz>GrU0 zTAauVXn27fVrdXHjidPsYz8gw>fZq8zYPxlZ%gi!1r~%4)3oC{NKNAoyoB)shQgIWhgLDv1!K*)Io7NBnQ_*+6N!oB z(Q5yA4RL?G632~%M5R@m5tOp&&}uPz+~2mU<(xmUvnIOUSijPbUO2DrJh!&)Si)fw zZ350lS}6TqK(uEhra*aOO!E<^rS z<_S}ZLqm#Q;O!kIu@C8=%jFY%hsyvDM}$W4Ygkqg<9vc2@hYl!bqTun2{M^h&og)| zsO2%VhlH1|u7L~!B&*a-Z(n}ARRHN%HBUDZ1bk!k2iIr7Q`>l2KS?@Ho_E>sk8Fkr zQ`U2^niz;X;x=GwUm@V$0Ekf9>rqUm68} zc&bm979zw#wYt2m(jxuJj8au%G)CP#rS-ZxNpd=!2n>hYVA$MLT9+}lU2|?uczoxK%z*`1tc#(m+?SsSuyDirprWw5WG-Z~cNiFab678Qpbj&Jhs5 zEHz-p%Dha&mo7*M@)DwpzwVuK8tAv!g zuY5Mn`Lkf{kaL9FfToO_5vC^Hv7(25@4<2|JJqM8(&sc5HN{}&jQv@OGKzR{Uh8JU zYLPqwY~@@629mo+G%Misot~zn_F%Hrj!gfg=Yw8Z%9;7{fy2zj=`u1KShV^4qqi6D z(h>S=&_e|80@eDnSy1zI=K3il(A=&L9cIL7;0PPVD5d;i*oCE{Vgf?F^bc-ktTnEo zjuYGT31wjtjH-%Jy(v0|S=z$va*9{;q{gr{`(&pplkG~e5p*cDq)UE-;dUm(QC1xuNi&kx=UC0|6>5t8&#T|vNcQsvu zfv(tV9qlqqZ*mp({_+Kb`!Z*j^o2DCDkV2ARq11E#b?}6Wvn{3xAAqKxfd~O4l8re zhvzv*0>|KKUPsL?wu-&;Zh5wF2PaFB@%zXYjn#0?={h-)Xh^^25gSWv_o~?5C=WN( zdy@$wY9C4^WQloT?cb>1AA&c z6I(rV13fEi7hC&(A&Xf5%98(@H~*c53Nyq1rpj*vAeQfU{(DCK=lUI5n(v4Gmw8iO z5e8z>L1IK&%wcSbe1>tJzFyAy@keC649z_Kww$5^m6#;O$oQ0d=JwRAOw#MIm&1LNZ8*c6T2==jvkl%WDR+i0UdYMs8U z0xSjf07Qz3Y6>v+@xEZwF{w~I#D)7u2MT2Q`GqzoZwJ5^VxX=5zasgV*DDx^hp1^$ z^*KnQY4VZm=pklpX(<-%^K69S9))(_KCV^vebsLoVlljBm(lan&z zO0&(3bB(mkp<;$99LLHL?>lL#K%dcK*Nd-3$ock(Ok8Ij)R`r+E`vp`E`F% zphhRBC?m?LMwe=P%fKA|#(VCjAsa2131*t6r=bBM1K~p>N132nYTtj4A8)q@#h0fK z=+DjV7o!5smK7>2gjxuMN^v1A`3Y6>lL!3l?BE~?pn(K{zfcL6vMU%GxdaUAwI#)+ zU;sy!NO^33=H)&iZskk<$|)w8fpshsmef7#NE~2H*<78J4vZ( zF{$GYcWR!s4&saV78c}Z8mL+-1Eo_hcm1nL%qwsL=f!CmDRRHf*{Ee`JM>4&0-_op zF;S*ENp=#(mAc1ICr!Ua9Zu8ofW*OKE4d^M>u%AjeT?g4I!1T6xhi4xRDrdDhOZK!8L2fUQg9-V|2+2=%WIj zxpMW1dSVDBayoz2kvB8pFqy(Cxb3YgDms#6l3_d_?ofPx&37((euEBb4!AhLOTvtb zXo?zf9kbu)HQ$_oUxA%Tb4#as6HyS)U|snArR8Zd&8C&%xEU4@EBtu>da&tnE%)#w zDxMOOB#w4u_1<{tXS7vSFxSBqR5(>VmQ*XziG%OuIhW$rUdA>>8ToZJ-F($Oe*njJ z$Wo@c9B-jpdQ(znxutM&K77P@RrTIwr$?x~{QCkY(7#c2YW*``oN-M;jgJ0i;Y$=S ze9pI44=Y95HTy>Byc}XK;vLhBe(ngB;=VOM)8U(LA_A`1ICJHPVPjte0?^=q<^Ok4 z`=5=<|4#yef+W8HpXA@7_J8`&q4^Hl-!5|B)2Y5a{FwhqANaoy+W%Q0urRT7u>050 z{QuJ`#QM+H!~giCVWDUKM>PI!6{2PNZeIE~v6=bXJ?p=W%@uMc3i3-RC^q4@B00e# zC+s5V_5Lt0xII9)K8WaINHQ?|KSl^OelXJl6VS2b1p5Yi%ae?1WAcAw&4l zQ$nd~Band*h-oTB-#=((&psV*HC?J1ZCG7dWnHbknY*pgFhvfc4)6lv2?XM|!k6GA zPwLP3eT0DU*yF+nqq(`Yg6xiJBlK>M;*jCUkq}&?OM{72dJAO71}iv0iRto+R@-L^ z@R9czvI0R|ehC8E$Ec9{fI`x33vAKYA+5MXihbL*&_soK!&g!OiU}MzYv5{!Inxlx zw*sWfK&a3=$aVYXM-xEqwrK|obO*^|+e8Bh(LATXCX2K~L?89Kw>)c-LB@`&087z)$@Y%UNOZzeW|yi%a`CXouGe z+{efDX$ER|r=x)u6F@$2$2^5RuDh#+mJtD>?E#QuZ01(>- zzAZ+eK?tVFgxunXjOUHOl@AaN#2DekD?nEd5`0k008bsOZHTq-W4pzYK1X#w67R`n z-v=+sML-C_1?8hdhnqVF4>YKg8gM*=z;|su=8;=JQv=Tje&t*&C(kWtPse^5KHu9p z`H~93%8B+&z@;-N0Myd26QKsn4${0!w&i~M1fh57B<_^WdCMWti(3iIvrFigyf8bA zKue&USAlq$I0^a&llo(28@*#_Z%nH7wmSET(a>2L?JrI3Zl%~ z&SHFGW~y&Ja*phCSX#%t99qNE^`q%^;oMy+qmawthM38dgG zW^|VDF@6i9PKZQ#ak}LHq3j)FLz4gOaOq?p6!3{AIVyqeb@e%S`^fg09hyk8mj zhD!%rRPVI&Qd*eTh!j%7K1NXkx`&PMlGwkgz`cT{hmp-HymHs#@yG{7*yu->M0VSQGeK37uZ%4%|~$M;7ZAbAls zwnaOaq&cD1p4x#>;ie>Nrq}0p)>6ydx&Fwl`K!*fd-^sR!aFROEift9uDvs=>Q{J*yP}+&@#6HAztc@xcd$5) zsX}#7-`~8*Ie$>&xLf}B4~k;2x`vxl8hNwIgRJxrmcf8Nfax z?Vevf#YTHJq^GL{QUg{bX^oeveM;1LAi*sGS> zoYK@>?(NazGr=+ujg(uu$?x!8)UqwVa+yT=$;f%FXLv20$f-fk-rd{&!k?%1YM0jo$;Y^%fM1E6*IMBVU6YNpA*U`^U7uDde;cgR$naK_rQp_enwI!4Y6$#04~lR#Ty~a! zuI9jSakag7nAMMDHFi2ah7~%l-IecHOsq99B{p^Y-FF%e6$Llmi$svXYu3)By3Dhj z`{b9Zn1$KYdu(4O;3RKux-aqx7hoy)k-O1d`I;18D!^I>3>!iyaiW&=6{xzf&cU=t zEUQJXX>5J)?z~Q$hSo|-6y@4deTU;klCy59lX0Inv}#8O z$~@mM4&SZ)FRmPhcr&^d9Ukp%WxwlUmnFQsV!p(YV?=A>@WI! z0U8n%)c>dA;QuIkp{yh(Crv3OD6SwVCH()ns{0T1F7>a^@;{`OzkTxm*!-`R-G5ux z{T}>R^!Ru8|Cu}fJ^W94;6EId|Fxj|-ThygV|^xCeP&vH7FvDQ|6U*bZ`lj>|0#Px z&qDY6gY`d4f?pdgBg=0L`hPDF*yvf=|9=+@Bo5jd-mXtpl{lNQHBax(dZYfAXtrOPp!FzXKILOYa*jRYIKPlLkXYcSisDod!fvdhVFeBKI zcxZ5rB0#+eoLoHEZ2L6CeqTSu3^%?qhd+LUKZyQ6g!kV+gI^sYKL-duzB3OydCFW_ zS;RX3)2`g_hO7bp_}9~NXooTryw)JM5VsFMQ>Lc?pzM7Y`WK%3yZBZO2S zyNJk0;9(Ka0E0syK;P2MymUZ68kWF_*K)XiZ`xy@K)z5vHz&H36Fq%o1AKP3H{|qu z0Q$QfeeWfEEtrRA*FGgDISoFlx4g@~B3M9o{(iUJ(tZ5@^kdFy7!j0}+PVfLj&V6b zu3thrl9w_5qJSv(ZU8S3q7sc;S5pqS@5FMoSqsS6v~5?K*;PNg%5gL_l?XiFp8=(^ zaX^dt)cPPCXu$3@PL(Ymu4om!$-@d@E6?JaBdyEJ4!PTlsnR6T& z+hQ$bG_NE))qkmgm+ZT_Qqx3_-S%$9SCw9WSzN6z&OjvCj(Z-HEFr4RC_j%@eu;>f zx}J;_7TtBO${CiRPNdoYLs<$d3=x#q6mltgwrNC+Y1@ub$C+R`p%uGvj)<$`Mvp|e z!NEwhU3|Zv5+80Puk=Pp!b-T0cGV)rFnl&H@ac=y9GqS|FLO&^E2*Ir-RUVaAdsY~ zV(3e84xV9Gy(EFL%4Ms`+441CqFYB0{9NX}**G(iIl1@;Vy&abP=Y=b%jAj%boEs^ zS+5ZBCOo*&&eyxWkV2A#A%+xk0+P8LxhW-GJHgFab^w9ep$hr7OvpgV7UtmmXKJ9SOm{ z7M^%I+O0fb%uLDo2Z+48@&HhQ=qf9IF?;CN=!IWp>0|1#$yrl4J=8Q~Um)j7&=?Z- z5|?YnPx@_V-8hj7JOi@Z@PG?)Y+u`rT#fvvjWsU74*K|Ccvh-4UK355jh-dDaRh~g z>2OqXvgbqhiRoZ$Xt1po^YiZRH=WsR45;u}shCoCrKG0uQL!kJ zwnsO^7d#-t!wKNh^JnTKIb^TjR(9brSS;b2g?fUE1qs zBnXNF7yNLVw6hG8+A7-@yv<_F^U+=1JE4z>w$2$NrXmnkxj5`e&3?t>{zYeUE$Nlg z?v%bL^}&0l68U=MFd`GFYCCdqd$GmQJ7Bgwrbw*bWU_YJVSIdglk!*Hfh&`T#m64X z9D1$2GRT2By6ZPb*5JimZIeiKw`|L)d`Dop7H{_3ki3jO2CSk$dE!AgG`p((=ckPN zxyhiT(0rAE2gBX^P`jzTqe}-c^H6?RA`#P+`m|u;)kk+cV} zti!{>qI$(ClqISHvL2#)-hh!4p@5NLayO3qqzEi7=k~Vhig1FQTteABJ`22`RTjOZ*h_i&i(b zIT4yB!CZ%V7j29;L!fma`JeYRVrLq4s0meHd+~y-sFYYZH>vX7?6igF{uzYy^@`Z< zId8X~Y*=6ZpG9QS-hQ8V9brx%tdmF@bEayiQ@IjXOTJ+N_wVQM=2%Q~oM^VDrvmP; zF~;z^IovUm1iO}hk5{XF<^xw=0-s&XOH5bVNaCSr(-8?E%9m!9K8XYIvJE?U>ncDz zjG_&$d+vwA0uL#5dYvFB&#P2f7rR zrv=$%UrXu9?iO7DSf>I6lVhV=z1h9WXAVYe$Upn*pV{@fL=SD7nDS+4mDmK?eJl8Fou{GVtP55mR3(v9r2x9jMF*3JiZo?t~(( z6ZW>H8WwlD(SyCNPDrVX^Oi*RwLBzD-STbaJWT=}#8M&7`IkZdmjMPlleq z^#4Es$AD$hErXF+v&7goqpe}((WpfZP$$jSpjq*kh*4klhDFQ8NZ$SP$(D2wkPc6>A4g=0}_PLfMP|DAeKwlZF{HiR2CJs}Wlf-EJV@E{psAtQne~c zfMH7~OIe_8Va#I57;`a)hG>|*;YdlQBq{sgb#GK=JU}IDgaaPE(-6wWO7Z+wViTtB zLw&~S8gCb+M$A-V4%u05Y!N;JyeA7F`*EDAL!9cN)8PAT&l|qu>}7vXp3|c-j8-jF znWme-4H$FUfJZ3SJ2kjZisG@9K(E(VFmbE!c{dS(H)LrSz3^)_&{<*23FjL&pOszH z%_SVcG;eN>fuRh##N18YkPhk;Uhfy}2476<+CdX6QaH|X#sxVEBEd@1_FWL^wnwbk zz^|83-T?JVEMw{P*?pD{AK34$V#se>k`C)@0&9pUN*j&}#~^DUFJnKl$e32H3Z#z3s}>_FL-f3w6f2xe zNXWEUSI6N>L&J;+&Xv~utk@EglVXl{)*xCU*#NbRA%W&_&d_}0O)IPCFo9jCwy4Bc6r~?y3O^E%wGrf-|q47ggB>&4~P2cj{vw$ zdA8*)p%mSg^``ISSMtUN7F0DE9MiGPlm|1Y=b_I%#znXtF{{l3m53U+P3ja08g~*#kMk}^EoU@ji;1rfx47g)O~Q;8$?MVn zsQ0?$w8r0b<0BU`iX>%Q6<9~v{xKWl+>!u|_-xp24UfodDh`cCKY z#539l9>vg!op0kYB~DB{!P{;!)orP~aCf&=j}$Gj?vj6%HR~I);?fYGlUEYUuksOa zbcE4&7WNNkhByNx2Iqy@gm!IO`V+Rg8#HWCUVY-Vh?@^L=BrrkEu=bZT*=0vQ#k}S zxAn4)cAkc|(TGq?E<;f8VBNmG1EI@!ZL`f%{^H)$vHrlBsY9A zLW^H>A&+4069Us2gF_d3<+!koRGFn6H&)yt%h}ebq@UO2S=~clq^8E#Kvk?6@S@;@ zguIUW52?KK{C>U)Z%KZJCrPFU;BRrOf|D8_z7){cpMM1;WGmt6Q0dE!m3D*JwS|A@ zk-GEXAirSlv-m7*i(_agFebmEng%JbU1uM^G9f78pN&#Pp8&1-;DsR{3wp7!Eo~YLLrJbjQ=OJ* zk?2e^?l?n-j}jireO>S7=Ut)ud`J0F#^{EGSDnrzB>AZ$&(Zx>{~bq9OKcFqJP2lq zGI1*PwWKDaiDbI^5`wh%XoTq;-l2$DUx_+^4I#j z_3DoVoAyHh$c9gF8OxiZUENA`4o+wS+}#u~bxYJ#sEi8abF)!BXaJ1@`w|h-*c5;( z!&kAYDD&UfJy7YK@M%l6+L>~r+*P)th#IGRy+pG&+|Z1nFXsLvMZ?SXE6PD8LWj|p zbKXp>oVzGI-N|R8M-3J=7{Aai;q9+0ASx&)P=7|SAG}=BKv{Z*zXaXnmy2p5x^I)6 zZ|yXj>3chDp(DzWR`X1R>6iT)KlU2u&$<1V=-tf)t4GUpxolIYFW~Q}hG{_H1Ek() zpKExy8TqqjBFDse#r^HqWbqnaQ+$xf{nHjF-zjyB&Wdk)qOXZqkxL9|md|a+hsf;2 zFYKA5{FCum!>^1LoiqhM44Atf2@F>jtY|F<=xHZTZMj-;c8KXP-3u)R1;O;$s3KLMDFuU1-|^s~7q#Dtw7?p8DeLLNiue^UPuVBjk7S}0*aIzg z!^-W{e!vI1%VAIXG9ePG>lYL2_kI~E5HnBr{VbLF#Xj45=g|e1QzSAWiWPUD?L8SK zBDDTm>s|R(hiY6%a@;%6Dy+T96LSnLkd11lFp>CBC8W^__FEejOLYsm2r8$65JaTGG?@S z-z$|-JZRyXQlxVoHU8%&>7OV98sO=mRm;Sa;zXD|hhxdEIVX^9mHorEc0XJ-FUg=Y zxc+vFw-zNKr8X-5q*Cb6lZ*u3!|^|_gG?o0L-##FAT8M>fDRZz95PWyO@k5MWV&{z zlqlA#{x%~bo5_yEr=_M~kPVfb=!nTEuwC#vN~RGOdsN8 z(?vmSr18B=0x{6IZ+Ic{FnYjc2duL-@Y^B{%a83e z`3-Ksx$04I1~H_0#DEy`(Mjb4^<>TtF-?XHy4IL=_rZ%pW)z@|<8i}ZA9kr3q-kd~ zOEraX-diP=Caj+i_ERW0AvZ0+&f5EAm1zag?68@0=>^=>(WoFQiuagnms7bBtxLrN z2Mc%F-7Bj6R0j>7O6V}C4BxHJ9t3~7w=tWE&Wqcd8gh_6x@X^0gEjV}_N^DkFZ-G9 z@nRwos~Ll-<1dUw&{xEw3um|p^|+*o1E9Ul#|YKegX!<87+!9@`d!$STwaAEqr!(G z;Bylpwvn&;vux1>JE~ za0@PqTweDcd4E@IeZaf0j?HymBDt$Qzyma&tm9JrNJIa z2SxP^>kBgeL7Gae2P$t4lm%*T=fseGGav+l>tBR=4p^>h2O$)Aq$igemB8KKKXX)_ zsOd~l3YIoQ;7xRYn8-?fkGUiah9B6OP5~01d1WSe+8dsrlk&bl895F~!VdWrn0H>p z)2hi;&6E!C95t4F9I)dlm#9a%H8V4BNx*b3KI4l|x}G7_AMWu4&sa=^Z!jmQ21;^W zXOmxs9{gEUi3}DCGuEwhGU_qio7TxpRXel;qrSEN;>4Y0*qhs&emWFT5AzZ9>Kn!! zF~VoD`6UwqquIrE%-#7*0Q>Ije2&HfX3qk;`~C!wCbFZVd027@mgg)Ta*&V*3Bk`e z_+s}LDQF%ClXxtSa(L~$Bu&VKTYx5t-Yw>1f?h*QPI+2){x-8u637UTeh`F{Q5Hci zd{&R3W?@EJBdm(eQh9BJXD4tnb470U=AWo-JoOfGFpVf_*wo?(XWK&cF4^a9Hd0S) zR7KOrLrM&9$6r@629+yA#1Fec7$tCQXmAyKWW6t}3&iSC3&o?(+s;I5RLWuA=r)^3 z+-FoJ)fD??T0bp?Pf5Y&0{$Eeh`2zGS)rU^J}-aPhr;i35kkh6#M9OUfyx2rOGgI9 z9Sk$fAoF&Rl!g_<0tT*G`S=WXklA4Pw0(mHRu6E0ma`s7z%hxd_w`GS)D2|rTo}Q(C{HS7W=&bbE*qsc*eJA9z;o_NEpvrQIU@mQ7$?cfEjPIZ zw^^>apWX*wCs)hduK3O8^{S4mOC7wzcf zRZ&J?3^PhM^1!HV3`;N=TSH4{NNiQLP2R2*c7kBSm0UJF;NFj|*|lfv7-I_1c~}XO zDp^(YLOQG4q2QVpBQ}bG9jHCU2WZ^WSBRX8`>V!muUMCN@QNNC`?Ol&hOz2%)=1OM z+aq4}7_VpnM=FV3^>r{mw@(?T1^Dj1lW0!42U2mqXfGQ&Nzg_(uwI*hp?U`2hE7ps z27V(u)hEoh(bMm_>coq?^06bEHjhDdyM0wNJxbO67#!Nac-}X5Nts9VaAe>d#MPi& ziBYJGaNQRM^fE;ibBaaZE^aydgdbLh1y%RmIAx}FPG1Dk806%b5f?HjMg&id^pS_F z)SD2M9tK5r;L}*YpM$_9*k}NYAONQcm07^-0OOVeR!+r1fj-n$zr!^=q=K;PsJvwW z&G|p_ z1}h%L2ND-WRCjQij(O~k<+hL6ag;gE+mDUmL8)zsS(T}`xcFRUPE%1CDt=d|YHUlt?Qfg=v--c+tT!HcyRxQ=ephevGB zCkk{#xu&IH@53V?;hKQ;&+7S%Y&_k}7BrEivfc&NhwBq0ZJJ(l!boy%rg0z3?8S9h zwXr@|2P+1)T1s$hFL1&9@~zfz!k(< zl`WelA7i*kj9LO`AO^{)P@yM$Psu#py8FWu4|j@|VLzQ%T)H16M@eNzoVKMWA z=KMvLT?g5d;0>V&d95yx4bG3ejXW%|1N+c>L~{KIo*8!j^cyIua10&7GL*1klvE&` zFO3w^~j1t8bv8@|fqZg4^o31#S2r#e#nZECX6;C_`WkVyA&}eF)>$ ziS>rX;Q!%&UjF6NpKw^vQJvju8W*%qVI@#n`-i5d9WF0AQ;H0X>r6AYK%G6u*}h)w8qRi%nfD2t#d0xAAbqHR^nWyrSl>s2iR+{aG*YP(FT6?=mEXF#83>A z!T$w)!0T6(7(pvoZxF&N1YuQM3b<2_W&gHgz^0J1JLF2!xizz?v5)Oj#tOc1&*MGQ ziM{-Ji_X&FWtmW7Lfzx#6|$GmkH&v?x+nIl-y*hLkI{}S6xcqULQ+6; zphAw&#!ep|UN0*lb%HuUjrAo+5=stAs>Lz*mXozU#{J`A6Of1 zP~8NqIipf5KvQ)vPYFnUS02o z$fP*3S50}Bg#$%4Z)=e2>!$#Lf(5Fvqp|Nm3ocSbYc4u99bOdgwB?p2`2Q15@qZ#? z(2$l?6H}#>F}F5wc9gcYk)jr`wKDpjot8|DzevSz0E^{!nk^eE{r}=ASQ!4B&YhY0 z7j*nDrh=ND;g@mvAF&F0x?jz~e{mJR)0+PqS@COfH=_M@F3_6&n%u2^J?=Kn)&|B7 zj^?H|w6_1@a{o_{`+vtS{@;29reFT!f29Tf3(KVcopAkMpv5nj$;?3ie^VI$4Vq`6 zWByNS{`Ya1TR9m!;Qfc{)5%!qm)18j{uRYTIXXEQ>sv#)tyeW0IvwpSlVGS;Mzk4j zG+T3WHd_}MY?Mb(G+V1!ZOGVs&757gjI??8JbLq9()(EMr_E%}Xjxh@5D24i;469> z=C*caL1QCv6SDGc&o8eosZVdqB+HQE8U+#)BH06Bw5hFcgk!V;v;ku9Df*Gk zg7i+p=`|4N(qWD>&l8I?L{^No4~WZxo;uzyZ@0fe*fW#|G^~swncpH5#Ijs-Ty8T z`Pm@;{_)KDLDJY<8W!0eeZB$u{O||-^wz%wtoQTXM#Cg5`B80+uPTZ@`N7}g1!ng9 zA$j}pCpE_U-U`hj2i1|4|RHDxD6C6$Et zoBkaTmiE2$`t$m=B7VcGH+U&^DgCpCf`UrOxzKa*)C2R=Dy@~3`Ca~AgZb04_v8M( zk`L^U!-uq*MC^%_jZpDe36r8R*_j6^pVf^+a+@a?TEA016#Uz>-uga6+|W`Exna(G zgjL+ksmhKlfy4cnUj!%QMq@$VD(js9;?n(7zAcald+!359*76_#Sj$57>#yQ0lG#F zVeKOF6qp4`Z2UFvO7>ai@|X0qg0vjqPfI@l)4V9S5N|@`JKH1NAsE8qdj10Aec?fg zXoUaVUS8id=IFM!R{ACz8Uqe11jzjpmh_)jTl8~l!)7AMstO%Ks1f*mluNq z);yW!nyT6bs-s5j*Kv@>fne+KQv%T&IAzqE>^uu4T26!E|b8v|B=- zcMIckVc&xK&N*ZVPH#2&MD@aja8PBSDkK zE=|Z`Sp2&^ai3`1Z~~qI+Kg#z@P${_Gp@0R)p}mBY8Hq`R!|$99>T!%Bq|^<4SFd( zCA64zkQH+zIQse+hcU@w8U^XGaXsz^@Zh#86MF0lzW5{ z73NS(I6)L!3n$K}#|Y0JQlmj3pty)fFIY?^r36s_vebdkPb^jT&(e8I>ccCxHo`dPOA5!Pyo` z(ZxwHdiCi%Ac{gQ7*=;ZWj(*}6G_?`=)(Y^cZlYHU8o?j=Hj06*SF#W2%8@|HgM!owLpEwLc(;)zWVw} z>L3m`xS?=ANultWLX$sbM~lu_TYEt3NziB`ehoPIYPF5b1EU(O(dAs#ar18? z!3>CGkzJz+^^p6ms*}t+2~&|Rd|V)BK$v61XQJELqxE#|%<`E_$}8{Mz$#_mL&@>q z?EWk5kTOqaN+iX-7TtiFHl1`q7g1#bi7jAIvNZXz&s;2|EKY6zR`tY>pTY*p6>rm8 zqxA^FEjiJ#GzH(VJB@mSJ%Z<)hM2c)!acPlI?~mVy}AnkpczrqV8{YE2}tX<0{IDi z;cBFcy^*O7$(a!Gf7(s%rLwPGU_S!=5I!C+P=un;xptBS?%W5f?$-i4uf{m-vcD>5 z%t&Bjc=*E*Zpjcl96L5v| zPeybrq=FPYrYvm@4qAR<;ygj8qGW!}C=;K6t0xmsWHSGTS1UzV!H@;~YnES|=&UK- z=zvNM6K1WfN_DJ_4L!LZ>A;)bS=~i1q{XnGd!ONo?YpMjswM)87GOUr-@8E*V?$kS zUE#ZbZ!V!Q5Ia0x76^a*e03X!@lS2u=-K*}D{ZDK1$ORpIV{d^x$3@i@7yTA>S=B7 ze zjv~Xz7@inp+*|D!r#?|kOff_2C`ke(A%7sP=J9%##c0 zi%~R#)%C&rf>%$k4g6ziKg&cxW8G4^;VvpGX}H^x2sn1&1PfCdszWTjI5fkC_runM zoy3IKQ>sv*eh7}+Cz;%vj{u!nwIaaVzdq&-V15ib4Zx)iIT;K0;W@v&TjL+oZTh** z!uwqFQ8E1-**skV;|(=C@~RmjWL*YTVK}!W18X!X1ap(Sq$?=2yQ(YOcF*7*+8?W zqy5v5D$|}bkCI43e^uWt`U$klp9WtfgtTQQfy<|Q*|_}J(+u)D3oFzx+u#1JA*r@d zG|_Rh!1JqEGLGD|d}3CAJ!Ht&B=NQOVSPA(p(?7D316*x)MB#wx+@mvJ5z+v9Lfl!vJlDcGo`E8#m4M7 zc9#pga_`Yw1zOq#mKYQGiqJ|3I>aT*ZEg6LOGi^Rtsq!TVgy^9fuU$Y-bC*@mpW5g zw9`Y41MIh0IgSn*LZnAt_}08%uz^`<31h}B@_`3lXXG>eS;Y^7E|x)TdGQYxs$3Lv zpBFQXX-WCv@=;x11F4ec)Cxpy@o9Y2Q$n@54+`ZOb&~T$EV|0LHk4Y+FJjxu?4^!x zfaAiouSOe|qGscr2WWPioS#s>JoHnC9qpQj#f6{%8lntE>ipz^JAEvB358l-RU12whnC$v2J?~}0Y6&l`J3|`{NWrLC~|hr zucbI+zj=IYCTS7>$wKo+rLu-CiBh|j912_`c$X0#F4T5WZY58lR$@PU4-CpKB5 zlAX!Puh9gXoe`bBL`c&sbbY#RwGgnM&_}Y%6O=d(>9}nY$GsXy41cy!km7B$!ND58A{UZ) z)N1XuZ~`xoR|)&zR#=ohi9Of(lG`(?nXZF$4Dq2#kWK{Oj67``uR9WT9){x3 z4HbGYETku)U-_kvMk)CPLaz^f%%W=T?4^8HD_Q_vjTF-O=xlbZr7yiDoGN&qYIH1& z$#Wei>MsI^`cTiFok{(l@XkT;_*Ygk*jv`(0?e8?s$in~Xl)J_1y(6^O#`EP?lA1| z;LeDC=qyl3W&H_{#73}5gfE^4DY!c6qdT?+!3iA4pY4fVxM7H8g=7{E`h}IV+U6RB zSB4XX`yp|UF%Fu5H;SXyLrh&aR?QUxW4A9Ca<|cllFQXqie)IIk<@=SOPwM=u+{`Q z@v|JOg4Cp!?JmM8*Nkr`@Q2i|Xi-f-45Oc*4^MXpQP+%A@M+FQhM zS^6$$hT#CE%vF1*(PhB%#VH(D5M`2=5^<`4Bl+F(oRP3}V^D99@d~ToVP9GZ#=_u{ z0ODPkspL+j+53@zL|1{bD!NCs2_BfZRMr!?sipZzqvXQ~V`J>&!#1hwKBc<>4~0C~ zL!O!x#jnj;i`XKB>w_CCmV|4r+q#nqJK0Y$4Y@)iy^j!WjoL%ojgm+RA%nYQ?wOX^7)a})X_K8h-ntK7 za9@y#7Kgl|i|16K@MCj8j0k?ZyXrgv`v-ac@eD(Wh{^1rW|nRy7weD^WzxEgS>&`8p?%> zk4hh{`ZNEE#QVzt$E-;|=J(}}DuPSvoZ&`(*J9a8*e@`EsW$FOjm-Qoe@#rE$7;$b z-u%6rF|<$VRqrSr0T(=$e`RBcBX3AoVUJlA`$pjNJ7oWa4$J3VOkYlX}dleD2LMR@`+s;zNOF5aZ=)p+76i` z^VwTBj}7rU_7~Va-}1i#$^KftmWo2krK17%UeUG9G>qedq9DjOl{XIFb;+pM`mIZx`-T~3PrnY<0R;jB}nA!Q;;z7~U9F)R+yISbPc?ZtU zTt6|v_Ha-4=Q4=Q#OI;?W_>2PUV+}0S($es>jtyj#ZE>#j_ zTCdw}veDe7y4=)CfqP$UiermNYlS`aak>8%jzTB1T&FlOHfw-pL9;`zbxruT9805pH*nPkvgjS%^qq|AWCI()lIF8S5}H z-+Y=f!>TBhqB|h2=~N1IS1g+L3jXP@5N4u>nWzr+l0#TgUCR<1UCn&jSuhyO;|Tp- ze2KV$GBApMnBn?61btVNG832@aIrWJQ&hI_Z2`*T5dNf3frGd~`kb0E2_PqxoJ@_)4PWnDc!%!Ow#IsZ$^fLD^rr4%8Z?#5N#+S`0gMZlE6Vofz zNdGue3q^UkQF)q{(0u&ic%cJe3Jio&U)M;U)vM8~HHaM7UY)7o&Gdb}gh z6J<>VH8kY3DG=*6nAIy5b`x5>xH!b)-hxJYi!?sYb#nki=3)i`SX7~n@!CHOU8d3# zpx3Rn{K1E=E{dmQ=x9f?6zvOxZ%KNuiBsxs>?t}=C$)=$A(J4Xn>d;I2;2ilw}+xb z-=D6YR{xf}ZFuG=g)JcLeUK`k&6>DWVS>4+sX_A78+`J1{fC+{z?W@!?F8<#0Y_S-xmMa4%AH5YwMY@v(Xq+ThF2Mimk?-6YdRYR-QRGxXnAs5(d z1~gyr&=p}brKM2Ll@!yoS%A@*qm;ZEs~bND2gb{zJWn!zP}qFLi&8S8{&lbUfo9}bIQ|%L z?IS+NLdXUZmEYO(gH(8eir3gJ;n0_|?yfHj9r&jXrV+0aZv=BxHD%`R&wwLwi4az< z7q38g?oXl;)0An{ywFITA~B)CAK40*BvO%ZeEt=U3~$Fn*|v8eEo9)hnc#(*0+pv% z1k7d;LgJwiYB#J!+V}$!1n-%Dib*WfYQZ9X7`)IHBRq#CpLyWF`ZE^uag@U#Gp^VU zn}!}k6*cCHO@33kh|#VaDj67v1CHR%&^&h2`CYu#Xib0m+O)YBbPV1GtBoTR_iAFI$JL%*q`J44KJri)J^t^DSn_rh_}Uj3$pt3OW^w)hFT2bzsYFXq~P>M^jeOs!Hk^yp zva!l%VYj36I!@W-Wbis0>>u37_+V-O`Jk(8$4x*FmezFmNZ>q#HrM_d)f2<*km`A_yU0Zd`Eri@A=Y5@b?)cw}+wv>wU&&Na{<*XSVFxi;5$3H@WT!;X4del#dR>h=rS~(Q?s(L~PG)?* zKf!f(vIRX73xl&obNh{?QUf#50$-#;=UUSzu+7EjBu~d4C{Vh0`YhLpRix)UG@1|j zpG_i$f+@NQ4m2SU!7m;xm}JWdB7{h(#)|+iYSIPNi~OF{zVrxaKQS& zot+%jUsO8os~zsgqm0nu07i(00CKKuV( zX>GYPPD+w3ftyO}YAR7og)d&wSzbr(K{igSHqdMKBr4EU8N_|QOCwqn1@veIT~aa1 zTOt%Vt8K?%ieOiE?fLKfx%(cJqPa+*30ZU$Y9L}ejtdXwB+O*XTX-e%rb$wj9dS-xWX!zDF)rpsX3X(D?~{+#M^z#zYWAa0h2u}$cm?Gm) z`YI+RHjbGb-7eMHEt&qxp!fP&_3ZG$R*;8$dJ0ki{I@eVg6tJA6Ra}z7bT@a34BC5 z+L*E5HzrzG)+T>Zt|=ApF!9`%ekC*U$`MREby{@jVR{9&gm}6LVn|#C=`Dr@WBWskk)cg)><;2b@6Bsn|A4nu^M7!=-dH`P-Wi{(z~~G_ z8+zT=n?9CnWn-Js$Tg=VLXTM*zw{V;b)Q>7!$m+7J8YmIc?LD_6(wPAZUA<)W zR(z>~e1jp%p;*Nz+Pw1h!uZ4ui4hIr%HoJvbh(258v}ik1yi`n;O^RYFj6=NRS{ka zTu!pTm>v&x%+>OxmmXh&G~~G$i)(BN`ow$DfdL#J`)JR&Hj&0?e^vk7lXFXnwECH| zyNqxvlD`vfae2lHoH2Zse>`Yb?^n}OIgw3 znu;lcM}y1JlPNxoEV&chP3Xc}v8i0xHn=WvOKIcx>jA082?Q?}4$d--$td0Q{Ly>( zOa108-7b6FjNm#?_wAi^gO2o{LdJ^@mNf zMgAi=QLgv>3~m0q`Sab~Mc|o;hivnc$c@Dxnm0L{gH|6-P9g69MsMIUN$c&P=vQ#Aqm;;B79e;9r5JtUtq_}ez z2ZMrsH<3Oxv^I^o7B+}RlM|dII6>q-OojR{FMdM{c|lwZX6oCVsEx!YN^D{Iz5ACO zQ>Y+d$&Wf2ytN2+y{!-|`#NSYt5^%9Nr{x7H#bRqQC>l^HGvFD}M#B_Upw6d$hN6j`DcNsblwp^g2qG3E%Y2R{J#(=P-!} zb9Pm+|0dL4NKq@`x3ZII;0i@{OLy?_fbBYoCkP{Q*2P}kj$lCLuk?tnUp#VRE6c_0 z{uYX4LRA$j0H2caA15?~UJ{`@-^Fl~DiW9N*p_gl4H`nC?LSdR)@*m9Qp`#Om%#}+ zwSQ?%w@X4A+qwy`up}Ea9N^{dhnmM~#H=&NkZnnjr`t?GGW>y23y1lf=QT;D2ZYoF zs_bDTRxq}4OS_CnFqt5R>alkTmlf}-E{QmA{XJ4gqh&Ig0m>sG1K@v1N?V`D#O+O- z#KMOfaK49yE;dsO}m{fENq5J6^aK0JCj3YF?o9z`&cAm z`}f9-&vroAvFOgCA*4O!nKN7y6aEw3?u+ZgY8{N}Qr*9=bauKvte4fpQ-n!&}YdHO9azG3An#3;i z{Pk~n>LGzXfOPJ<=V)CL1eAL46flb{Kh`>g>Y5*`a38nMwN@wAfS})!u2FKP-7&+h z5u^H%N~62bWoU!Y{L0g6^`RpWW$==zO1+X~<=ZAXoAyh^Dv$k1pk7f z$udyp>c&QVTts0-(2jX+&WOAwUl!P%MRO>#*6tXNFXwk13i@%a@6>W;z+uQ#%AsL| zDQ|$5|*mb4%#GQ zCiVU+ocb`ChwK-fDA0y8ZqU5PI$DwRLK`hF$bCSMIl+5AIe)>?JYkz!lBjNnceyDY z6KO{?x7%*jUbQs1U0FOmh8fgy7hSUj#20}(GYa0=4w|&u&WHEZZxJ!zP2rZ#7q|H} zjBCaMrpbhj*5N`-1)YIpeB)9fxaCY0c&2`Wr27S9*+Pl5KU)k(b0fWJA>9jy2t5u< z(fNXQ+;rRtjvn>&3K9IyQ1{k-?vDHxGHvSJ5D}OP172!{34MKQihDJePo8-fYA@`W zP^bw_DEX!1DpP|bZo*`rhnOi_p$?N=0@CzH>$il1k!-f6_(!^$q$GVZ0hm2Xzs*CN z^CqrN$T@XsuuWCCVduk*2xq;Qhp}(Zn&@sTcst3`sj+gRgnb=GSBhWX@j7_mzw3b$ zVPuK|hMoz0hi7s>a{}Bw%}QUD?VDT5#)b;%J3W)ic}g+^5&s-)M_$r9CbAhg>q(~D zwXo;PmUoe|?}ZA*yX-{`-hlqWSr@2EIa-SZ3UY29xU28jVinjSKy%-%2;yiGHISKt zbi9#Ogz{mXOY8EV*vVobh$4vRH6L}r=ajtj%dK4q#%ed3L-ZaT zGnBwI8rHn8Nv6)9=mi2oTz?bI{xW{(iGYg3>yJlu^Zyl(YD3XdQRV8(F#k^mUU`?C z2Y=4p^K9=;f6&B1tQolRsX3kLX~Io=luf&?u4n!YZhYNv_#q(H3iIRo3*{th+ls!- zopdXBQ^}A1BH&>o__VH8H6F<;y4l-(PX7xOUmE>>^%xOBL(FoWD=GQB{Vj|LPddlF=;r(M$%c zq21e-8~kSzDPdaCo?#lE<6D^jT2ex>$7uPvYP!k`hi~5)Dmb-zH{_HZ0dr(D4^Ye# zY1@`xM2phwdt+5%iLE2Et;{4^{N?_P32qbx3PP z%GH`wMD;YxumWZ%7_A!Tq4kKGQE+Hdnpnm8qMU(`h5|1r#huGzlvmeZ% zAk(qEDI~m#)Qk9rCT^#}S_8&Q>sSEY+Wxz7bKixCp^f~}tQdT?sY;#IMo#j zeCT%bp1gH4(HOD@$+XKX$pL$tIWx)5sUBq%BiKX&M(_@=5I^$?;#;yfM}IXxp~Il4 zyJk`jVb1FaJC(tyuYQ(zssbxGmt4iak=-xneezMSP&ZAP5-x#LbuLBM0IxpeBU!%I zpy=j&ydc5Wud@y3XOQL-o9UwTtqP$^IjzbC>HvcCs`Dg2^Z9ku`~}8&tPLcDrt`cD z)Z4pHQPa&`z+rLZMcz)YalF#0aBCEnbm0|4fogEuVdrUkeR=Fp{)AYHhd1(l>94>C1*;k^}qFt z^i+oE#smub&|aWS-+Rz3;sk$eMHAcCwAMp~&-z_glN2zvj56LE&svxt80DPRH|8(_ zd6-I8LDpGoICnuxV6tZ1xwh0QIiKhwLQ}C=PLGLsXrm`?2}jj zQONx%=)E^(oXdY)7azu8Lq(lX#LBtApR@$*W_8%aJj+FQDT(qXiTQePFUYOusySuf z2x>9d8hYNEU(BMpWl#|YvhzlZchJ=M2o{}Nkc0+7uPqxL)_nI;wOW|gU{A@jMucTAhJ%oDr@fr zKeW!H%2oC&C@HT!_pO}4Qd}cE>)OE}H?RxY$FN)G4ui=<9viW{Xklz4Op}d_5o}TW z4WFbAd{`FEEOYc4u8yNuL1b-}Y78w`lPv{DaV2?P(Lx4{p=%i}QhqHJq>Y0O(JdZ> z6A9x^?(q#o^a1K>@J1wJA3^_o_t>^D2E&kolSsrn2cy6yQQ2FCq0j1C)~W_xqzqvG zpNrW)g`s)Zz(6CDlY>(Bc76s9g2_SxoFH~xC3$yQUFvN9pxXsm#P**UXoJH#`GjxZ z^7}I2s#GuYdC2_^3tB;N+tNd`nw{eJ{z8_gP+y>4C~{ycgl@LujbAx@{+2Wz#FKC2 zc*S!86AN7uq};M4L%FZHwbO5F_X6Q6VRlI!l#--R8UWKt@GXW1XBZ7w1e^EqrJ&Xm zUTS9?dVP}cFhsk#DAeyctHAeXB>2&SizFL?W0wL_67;8kz6;nqs-X!nHg;nROA!Qt zS~*qfJk84S%y`4;;5d^@*_?(gv0UOix2$%YTbyC~bRC}6zMc9T!}U8n z|8{PYh?uLH!*~NTa%;jNu04+Hb%e-eWT4Usp}2+Rkwov1%P5yx}d%wtT-%=e9 zey=^%D38c{b*CgHCUknd`Il*_F>pb9oSxn<@pxgd^9&|UI>2>8Z&K|qVa}PdicVuv zYcIt$j+h@ak#4uXL#7;m?*P$kbZxD2Et9lV11)(fad2%iKF7YeLKM1S`(KR8Jg5HAKivYn zEm&tnWEV;Un3td+q`5_-HI$Flcanm2YYV(PXL z;1W(=X0MlWUi6-3+ugoEZi^Z0s`E_S(YW78%D`N3`mba`c~y}Q4i<(ae{t(>1hSrJ z0F~HkTrUsBIup?8k*MUuRiC|H4HU{;W9ytpM`|E_nt!c|LAv#zm7km8TI!P&bCX zthGg&ALAbLIqsIP4H&1p@{&D;eJ)>vf|c7$9F@sho-a;u5B|4g)!yV1!q_2x9as@0SW zBbk{W;J*7^9qUSX?vm53zpbH6n37@U%SF3LQ(+x2%?Tb1{c=6CA7?hjQ$6AGW|Rs~ z+bAjH`y-axgt((;Nwo3@JqKA}PXqTIaRoIYvI(o}5)xTu;pr+8??=VNwso>zeCF2eZd-3qPZWGt60vBG`dbm}d zy<Eh*(GrEt zKKHkCf5jTB(4E#?&Jj-3oBoIq_RW8_%>C8m9X6GhQ*0umN+wxj6!b*xZbm*N|6P;< zQK>Xsk8{rZ2ksa1o^s6V2P%sf`7im`*<<51qnYU~9cH=s%C>QXHI ze3NKo}gU)ZG|8yVfiv%xrIOs<9DRq5{mEr==47y9xBV@&(_n5Ab>qVLr zGmdXsG$M(I(g@KchdNxXw*GD5;S&=~zn9XD{N>$fW8D%?pf`{Bv~VU$lw9hZ7n*pA zy@)x!_rPm%d6T%2kErPR-c8KUp}v7d6{uJccm^9}V6CCNOsyz2le5lGN{qN;-hPKe zCdY(fhL+qBgx%_)Z+!r=cGj19DR;M#GzRf^f-s~sn+juf86FhZY%z3*dG3p4CpFWw z!a6%V&cjN(e`$WY?_0n1eu^T|zvYbTI)emTv;zr&{m^Ge@wU876s*Kk!}%y_OpFip zj=nG$zwW4iP+}}=U%86=;{hp}RYS5RD zvGY-+bZ4BV-e%D9zDVly=uulxd*K006Oj!!L?1cC+&-2P>2A%-#jxpHSYf*kVg$%W zKq*+h*aD8<6gmpkpJ<TFV|m^SQ@2%hT3nt8iF#K zvy4K<@ADp3F@YOn+=Q4Y<*pVyQMLfq+-fJN_jXJC!wva2x_0}NbZtEK*v@7Mam4*TFY;o$Pd1P(_LA(7IxQm+^IC4_C`y`(t8-7_Vm@RYq@HBXlMdU z#^X_K)P!oTb92^>DnmUTZn;ORcVRaCx%+enwaK@Y>-5XhTw3m6{~!v z1$~*72D7mCbqKlTQqH9yPsH}&N~Lg6o0q)GEhNBZ=tu2terOL{a=eLRmp3e^TJ&#l z_Xb)^oqqYMK;Ocqz$3kWLibn2NMLwjzm?m0YrN1(M9l^hI$RIhSI7hj_?qZ@{G!RD zmXMfq1(u^spG~!|#N18Y>9AE;QU~kb4xVllZh=a#<5qeK12Sg8}rMPhwaM*{6S%^;uJ+jt%OnXW(tDm z5W(c&amD|cHKQM#hY4JP4@vJBn`i&PzbY{H_r|MLeWm%s9m(o*MlJbuFs(g%iWcI$ z3`3JPx(dIxtTY>JMR4v`)TyH4e>i(Hkv%J&XpFsbsoY!F^Vc-n+TsM9?d+-aLQOwz z+<>-<>9dA=raGvu#jc0&jzN)PxKOnGlt8?0Cz*97=I)t0FarM%{D9^d)Ro2hv-K>F z_S0wjvJa}daSeT8%9CeK#wifIVDE*F4^tgjJVA|Tt|xz2etF)7!X{;JI?clUT>ch?dW% z_YRR7X8WwBAR);o5eH|PGFDRxP?U$@ht-C#ASH5e`R}ZkzESaC^MtmT%5zoi)EZiw zF+XK~bGR*hMvGRw6RDc#zcRhgC3_a*tQQuwJ79I)QFu>u|I9N+Q1J) z;2d^Q=h!aB&!;4faAVGfBg6~5cf1f(?rDE-xToJizvO!~Z^R?G@WdM^lI%1lr+FoH zsR9&&s^orovFu#}2btIW2>8Wg3xD+*?IIgfzC3X}Al8KF!J?HjP82Gs4FR8U-`uHm??X9Sjo5- zB=h~`Xg+xAQvLO7EU8WTt`%tk__W)s1ykb`+&;UW7WZEh{I=mIn|S=I7BeCINGS8X zQ)H~cq7+u$Y#Te{g!xISmeM}4V2z@jdQ29lGF(+KN}RmN;y}UVSid!CY%GTAYDr}z z_VNUFS&!TItlH8@4L_E_OGst&T=#?~&a|ktiYCkSE4s2Yw&!l<6?Qh}4}%RSCRe~> z{dx$zSS>KO_}M4-swSKVJb4iDk=(7SmMit_4!0Q}%BKZuZQM}N!&+;}R8%XxP0n$C z860O{Ui%ER$JT){#zW2`8VzW4FgazIL>Kx3IX%2u0I5ly3VZ zl!cF|=J-fR0RljWcRpp;EyoH;%;cOEm7E6z8|GQ_X^KK)RJs^Q%rnG+^@t2_0@)ah zJCu-+X{c3w#W1QxvLpuPX~oCKMP<~(et6KO7`H{;Sor%$LW|lFEz(@5l9Q}=0=%4S z&8p{Y*(uEO$K$ze8p#ETWIE)j_Fj7g43m z1CzZ_`P-S{McbM`c$KRsSF2|eK(Jrc)b#1|V7=M)%_jy3Dk~D}+=;Ifg?0ZtO#&+9Tqr{#2jTe`SCN zuHXvqq8RL&1A(#9y7uNXWKC;$VF-c%f$cq5O%f>F83@vZJd&t-pQsgp?5Vq}m?4Z8 zbv4PPNkMogYk28oDLL6b2_MzDi zYOfSruJ0Ls*d>|&SeqNtB+=oq-Jn?X#??Ef&A%4n(CdL4>cHDf$fq21>19_yQ;iP) zb=QuMyjmbwd(?mU(cgtf{o;&Ipc@KvKbsS$FK)kr8ztXoh?-Y_%tJlx;FAgJ=vNB;XZx0& z?Cqus!oEW{nq|9-8)JB5c+Y-m;{AcX1X8};?Cj?+l7))cBOmQ7J)u_Txzp&Am?ggiL$J9}@7X-qOmROvva-Fdy0w?MG5_QDm6A(ea5Hkqya1 zt@YE~{fD9?d!tQ-d;=15GW8sei`$fi(`x&umh8?#o7bBlXb)tz)czDdZ$4LtyFW`r z4#01%AYpE;cS=D7gc5C5S0&Pl{Rgk6WtupV=_B0BKM3~+tzrKs9KgcB_&>N!1t^hZHJHP|*$HdX@e{u-_jUW8afFKLQ|1G@B z$j1CHYVrS6C^(t_t9J2!Rw({q4ebBjsrvt+A-I{SXj`SQT_e+iL7`s%*Gq0sK>!UN z3VoBPZ%YT12vHlfFQB8N<00O&q{Hlqy~p%je2MGErjIaW={FoXqjVgn0`?)8 zfuWJ<5d`H1S4M|_vVdHK%(;LSJDL-ORxeF&u#hO(9yCkfYCsn06rq5RAN(vbAygw! zZ3F1)>+7pRDG)ND89+_T3J20pRaz%B#^3)=FM*#L$f?GcuqH)c%ZdW%=^~JO7WnWI z(m9~B{Z$Xg638DY3=UD>VCkv}6~-^W3Vap{ zwh&a^UmFsL7ADy;MHj&>-X?eoD z?+H{LW8h~vT(fsDFkyw7taM!P#@~eRe%-Ckd_-m~3I-sM$Dq$}6L>K7^?+==$xdCP z9xf->rY{;e_S&k%ryeGKuvU<&DQ!ADKmFT^Otl@~_JLX()XO~(RkZ#8hH7&hp zb&Vgmg~qz3TDNy$kd+<8*|Gbb1>d5JnnMlL#ouTu&Y0gNa386~=NF^`EL~atem~F! z1z`1`Cws934i0e?y`kZmaJ_@meW1I0dtkTqb#Gq?NI#AP&ovDRSc6N;DEhtQljGyR z+`oQCZuBS$e4R*+jDhPvnK`i$nJFe#3_ePB5v=!)&)>)I^j?0NPJOd}ussQ9QOy0B z*x~9CA)BQo<%1V@&0gT7vHxwn@7ddtzIugr^q~f%$yWwS>xhQkyYhQ*lcE1-^OCjc z=ChGXzK3=8ZrQ*13+9$1bu~7ini;_=ygfM7fF^FJ6_fW#fMWc_Sjhog?r-LAPb(XB z*{#-7q`fZ*m{6MeF}Q60V9y+W`lBZ1VTj1XcJb~uGq*0&Fc#qbXH6&BvWFYm4^ zv)k-U5m=47Q5BGD`_skvZ+Z<8;&;s>zCBnRh9<2-#%!pyP19A?k$Jbjfji&O66v%P zicX93JSX3?8Aq9Uy`Wl;Z=vt-O7VBUi}7@&-?{4|!z^!dT*`3?47oQK#2|8Xe$7?I zE0LAWQ;;IjtM?pYBtLn4R!r6~sL7wnFPp?|r$kE>yt?5e6or2yyox|u+LG{a_j+cT z%H=p0G`LV_Qf254_UU{L`eb(Ru1jQ^WK2|l;U|pRV9q|*$EZaUDxq7p3Og`Ao7-nP z5${Zoq{LF9&a@$q#fnN+8L!OA?L8=E7eq&3{BHV2#eX$r1UZ4i7QA;YGdup|e6{dY znwr>7NXn-xN{^7Kh)BT#k>In_UODhp^PS$-2J)0iQ@H!}Ft4+miePxq356`&^ok15 zD-h*8@F~Y%t;ZEX)!n!rA`%kMswc~NXDreUz09y(C}+O@@IMfsT~2Ie%t|-_iTKsA zI>d9&0$)JslOX~-KRETg4MB%?3OfAhuxFVO_qr}ulO2q&vLP819ohLSdm$al_%+hj zI7{)G#2I`30&S-wOiLK-jIfz#@OUy)4fjwrTW$N?s*J zwB#6;uLC>c-`BYN>v`(EwvJY$<{89@O-*YG2ZE@FN?T6}nKqStzEtmKMqX3aqdBXS zhi3sQCh*T2Z7o}u{_~0oSEho#m*uU!ud%m#sm&6JzAf2rfUKhKRcn}8!_o+L^9NmL zWhP>o+CE#&);%hQP~i#!S*yGrR@$B^wi~yLV&bqw6%S5m48NJ}p3mAB>o+iRYLjb! zme&wzwLdJHrMqX(HK@845+qV0A9cK;NHJ_TL^9HMh?{Tuvg=~I>PM6z@w!aiy>cCz zTr>^HoAD@#q6!_p!twEdZzm_dv#I#=fd!#5<7=Xm6xRX;Q|$xjl<~>$JiE!{J(#2k zN_}V8U6h!+Ww z0cQJ35f2kpAw(ro0iGAH9Ymxj8KUJ6aGa&@Gk^V&;G9R)vOnVGru14NC zY03vs*oaeHh5nG4i;Z~E zwd_%s6@i zfjlfSR@04&sB6_j#^1}%solRqSq51>1k2dKI9e!QMSVYi_w)e?i0CAFCooA5_cK!t zQ`v)Z$r=e${4O&UsZz@`9lY=#d@|Tq5*V@3w0e0ttqj5o8^AtTfDBdvxb2ko0fCrV zEX7o&-DU$%H?%2tF$v<5gFQH91c9~gGMEv%DK`9kwYQ1!W$$4$eFS8ANJQLni~TGd z4ju&Bs$mFxv#uGtDKOlW$bnP&_nj7F4kEZ0&+kH*uG7emo;dGQpqk*KY>WF)Rr{M{ zf2`t9zS~)xMV^1@+A)lNnv*q`iahH!DxdLWVf$8VtbUpg1ee>Gd)YhowEgy6$%sW_ z1QXeml^>2Q>wG>%nD98`tBx(leKPyvG`Ks?c^!UcsxgOB9fjW_ABxZJLQl%aR0JB@ zkzOiGUYZcJ@yd;)^D8ZswUSui<>5YjFT+xpXd7+EPIP}oimg#5iHU3qA)IsJ zJ7?!LD4nMowp02W&s?_b)YaBzKdbD8Zkj*R?2#H_dxkjitR5AOH9g%IacY$1B$Pje1Zy4RG8FXe<^}) zN~O)z&uQUg(G>q&?YmIZaF=Q1y$5K;u7vgWNS$W7Ei&_GTu8}%vaBC39ZKYrMxu%+ ze=cre4@H|s(gN`Vn^wk$7ft@!9&!5%&b@6hR5$DvRp)WE6A)3`Rop=dF3Brt;RTXGu{YI9tPjErJR&j1H!vK8QW`xAC zN{rO z=X@!J$E(vk)8d8)pEyt0JM2fLBb7O{%I_QoWQlQigp*%gVe`-wpd!n1pOc!jb&}cd z*nkY+uz&Ts$t!GdA0?gn5aKnu)->9PBetMwp+v4F zmO1XI04UF1{fmr-->Z%J;g~cs4gs62gCb9n60o3V?nK3aqv7kkq9u4^tJbU+*I=`} zP4il<0CHIYH2aEzR<2&z5IH1H{H)H3{cZb6&|Gr*6HQrPqRc}wj7-scx%$=U-pPE9 z?Jcy$>bNJ%L1-!%!^ws+;eP{U=jKrPldXd;VMt*QufubiUiO^5_7w|i6a*t3u^`d0 zrl#Vpbm@=QS6rm=K1t8FdF+431%^Q>YeCg(XmPn(Y#EjnjwBzE+P*_l$ZO9vf4C>7 zz*jLtnZ(J$MgU%=U1!kdtb?cNZ|Zm}5UGXsIv3<$-V6#ZyUyP8U{#8>3MC;Yucw^> z{ygQ{oJ!049Z7;JC;rv~XGA@Jp;k^B3dX8M?0AwH`w>BKl_1nSpaNBx!-A{XQA7f` zUDqe#x|2P4iXu4@zNs4$P`CFKwL#yDBX{fXL~(&xmnPgBKtr)MRJ1|Egf z))?6NLy6d@!)gs|=aoxPhvF=wK-%B>cjcxTh$&&#L*3;TP?uq8oPTrZ{Cf_6ZaYn) zKKaD>uwfW~W#S-=?$pyjP3=Itk;y~c0@F5o(+-~tlX)+Sbx{8M``mDO%Y`xuXRR1L zFLe>I{W_-22rQA?lZuyYX|(MPRi<&G3J^v`NI$wVC9Td%$% z;Y_rYR)Z|02UAl=ND{v+_;7+LR2D-bOcy*(1~|Ry-R}r2846AZTalGdC1MaXN!nni z?|~K6YWDr120M)AIXngqJBnAl(u#X7>}%Yh=#;jsF&|=#6YD!>Rmn? z2E2If9QH`oJ@=dWFGXVnc>=s}*`*hZxQc3)J+2(G`|w+eR1gGaD%exOf>XSN#3nx_ zXS}WM&_L?7YDCi*M@_A-St|KSTDMVXH?6a}gM=Ek06Z>JQOAA?rG5NXAQ(}E6E_{L zme3M{WkJsT!Ho4Vk^Uw+;yu}FD41L0^#cfKWpMOJ(D6y;o)?^~NwRW2@HjH>!rY^% zLtntIBfKG0K3V^0v)*ig{M@}j;j_(Vgv%sl`#ZXmLsTS7E_uyWM}qgo%k0LZfp*IQ zSa`ToO`WBbGH{-ftB>VC!A1Yo35Rdip=TB{r!e&Ew}<`b6lc~ipv5B!+aOw>_IHI_fZTNa26?=thSr{4lD2A(JW(S$rRWHiUqrJTe zn;i;t9a2)tXLz=CdeAOz3A#1WVs*2RTUmlx%<4(g1It9Lu}yA6LuFLb+CyN28F0b5 z{fj$9jawP=2k#>%*pMbvFWNY=huJ^W<-Lu#S=PAYXv?ok-$|!)`IDFvx)mj*Wmvs! zJPVAy1Zb~!C3r$$*fgP;@eLTweqiCxU1F0O-C-ND>ix7*e`v>-6BEkbe2(|wn>5W%_cQJ_@l9i4Jn)h#)C<~8U6Y9 z|14_b!*X*ujleB>goQ3d1q7Qv7CJ9GS14JJ-tSsc&@m@9b<)ax)&wd< zekZw~e8q`|%6|1P?xC`UlJe^vNJb1ODgCJrbYO`MErN2d3mPmCc+108DFxa(Q%~g% z-;9vHA;K)_I@rw9yFZ{~s^VGSg4hffR~J3%lQ{Q=8Za+KGm`zPb8`?sd& zYa3-3|1iU2xlG^F+q`a@fW>Y=p-1MI_2t0*M==R>C1y`9R~_SeWC(k;-OA?u3d!Ps zD=|EWTlx$EHK+sl55V|^vJ?Gd?Qc#t^uF@40jGAEbsd{hW8q2!f7?E2DaT*@La{X) zh8t9&l-|DV&J8}&=>pD9)5Aw5)t&b3Dl%thvC6FLKDwxWwYMcx8;SIR;YXbT8MZxV zx3L}zwM)-7ERO;`P1$S3{wpq?A{@dIUD9?!H`MrpE=V*Z*}vQ+N6ey2W+>sUW_pb9 zA7hPIDGHC7wJF|L6RvWkDq%h?ClwC_1tdFitA%rwk>~0d)K<5_E0qQ*4!WNR^wifI zgUF-#E8`KU5UweHIp%GW?QoMC7c7$1yYptPf1D%O2{CFhflSl6hK_7AquGqd5K;Y+ zaEyTYmU`P1M?xD;kK-m74KeWbC~pIlbXRwwkV)ZKXtkrX#Du7RZn3~G9|05c;a(k0 zJK~rrh#41qnI%=zEHF+4AQ{$?uQ&OGa~*L}W;$$5^C@z^clfc&=&@$>!B(Y#?1ip5 zQhlXQbs*)MTJ9#H+4}XXPO6_SjmcY^RY7bhEl#aJ^>Qsadt#8=;Dx}X&&=5Fx!KW$ zcDr&W86c(PPuT}q*J^9Q$B04gIxFy?D(WCBPrwN}-@fF88l40IIBJN;vzoX9zuJqz zqlt)@xT$=^T|VAhqmoR)$)Pb&7}BVWG;>fK$8`TNFB5; zjSJZL9fVAA+Fyc^8fl#hdLF9cjs9FbWJ6fNSo}5)v10mn6nW8I=I#qQ1GQRF@$M&l z>saia&X-qeD;DDJd8@2~WGVI>PwaRpIkfoxjS${uUEHOR&yt9VZ<_e$MXbRx8ScaG% zUzNBzn&lDgPZ2#%AVuTQcz>TuWJYdDqMp_|xwjAv5_9Q1Pn?-ag6|H^ep@>=#}0-* zWLiu5HHbvHUGiXTUr|@9465p`uH0%b=Oi$D;t$?=GDQPf!;EzNp0D99LZ%l>DnD;0 z9Zyi5=6pk_DtaIGR>bHI)yUoMg%MkgjfUa@k7lc%qocb}s=cC9#2!WZ!qgC+`5yEW z&)Nj>l!c{|{qfwG0)tWV8j>(6D zc4=-%Kr=2f+iV|5yw9T0I*{Ii|3)Px`_Ru|U1K#7OTktA(@{lctlk_gJ?9|!{ zZpbb>xy6f!MAhSoStfbt>Z2R+5Te!X#z~bB#cUtAXhgK2YHVJl>+2qWVq&~`ac`6& zE6oOaluH>3pr5{SBjHK;=FLE*rr?Z5e)fvnIdqdMz-DcxAs%O;1|*8k-E>)O(x4g`rN5JY3L)8E4d_LYXy`KC9_0`;= zM;Ge$>zMqk<0dxT9(ir-I?6RsN{--lw(v*@D}muLp#Q;HT%#MIme48&Fc-w^aGf-1 zp+IXG`lf%ek4w3m4dL~O%PCNU9DP9RDSlmmoF@@zAjy-M+})|A+oINp&O{To%PAMj zg9j|Xmi6mChW)N(%$Wh50qQKq@H&bmTE_&Y}IqK{oZ2ph~(;(Uovs z3NU|EZKhsn8l(-FEYy?SFi}k?WL4I>+8}#taL7~IP<5!**$E=Vox?>9r9FxLNkC_| z)JAIpusGb>n-BSUD8&2Sxv|qVaXwzsvU+uAn8v>0rq#r6Mz=JWHD@n*!$?x?@zd*k z_z+l{!00L3{RpZMW?bMCX&LDd|0Lcs4F*Qj1-XVK$`)Gp2#qWEYmW9VPv0}G8g--t zInVU9>~-}g?69}WsPMTxe1E;0|D6qfns`rxF5ef=QJ6vF+j5II*>t0SCf3n5n9~qS z`ikt89_(Prl)5R`?|0013}+r90nx^u*dbovFU+$$qH%0Mm1o};k9^+@Qm7sRIJ+nw z{Zx}nl0E0PDqm{g(&ZSgt9|K%8L0&u3!}L$fERPZ|8e@j%t&S9HKMetYvpgcIl8El z?a_UQJFh~yHa%`yMfYTLRh|<|W%g=8D*~>i7MLznu9#yFdJiV?1EzsDy9mY|1{R_7 z$HS^|IYE-zG^10rbfPe)mmUAEqBM`$y};%tAvdFclPL$M$PXPr>1QZ76R>vkD{*<- z;$4-sim{GnFFQ9XEa8b4A|b25E~|{j+q7ey5hz<9KGzU$&CyCe&U-u;@G70M*$!`V z<_^3NyTD;me_yrneI^&1J_ww~Y6#^#$ivr`W~rT3(DzpD#`*0pe3hll*1+#^-h{zJ z_gu2kiZSzDms02>R9lnlSBj)fe4UPb$}%UGWxL4Du~+(7|HtgF)u-W-JuRApLk?Jj z>vz1r9o8n7aCr2(CeHZh;6So;^z3!ru>=?n_NHbNHMhy4>cgy}D6(Pyz-pc<7q6p& zur@G>{2Bp5IOQ-(G@3BeRPwNH+Z~sgc{EC>OXIVdp2NaengZ^;o^OE%dI@jXZ#L-s zBh3Fr+C4va7KRC*j%}xdj&0k?H@0otHafO#+qP}nHapm!nVQ;ns-||gYR_Nr)cNT= zr>^_{Ajp-Vj6SzltR}41&~aaHiG;m>&S0Ac3YM%oX-J#t4u8@Tum(RpQl>Y<~ynuL0rqp_s&3^QOYOTI8b{aykT@c&9lcuIIv*jDD)*-KC% zFMyRO0V^i(;kpcBb)(aKHBR5Q8K2%C!n&!_kwXHEB<%&l-w!o@FIIj$fdyxXf1$!;T#rkQX;7KyQm`u3 zT5gT9HNOlo`Qu~nP*wjn{@HQiEO1+QHsatS;g#4Zi+u;j&tY2dWek{c9!IN&}i9`*L_0l-q*$- zNTUS6cAbB~AxWW`1WV-eUYl8yt>0S_X=ngLdVGf%&Zx!Icu>4pqu>6p9^CN~a%i86 z;;yL&uFRFuxnI22h~ul0UP-qYtOjl#vX->`58mR^>*d!~P0s^(8c}n}87fi{MPZEL zlzWGt9$lPZ(~YJ*1~nYr;2v!M@DS^kMHDF%fj$}@CKYFQc*C-!mxat6IJR_UxH!rW z7bKLu9*fGI_5p9S*yEErCsFRO@1fUvq*LaQeZ->H8YgY4Sz`zC_UBy==z&PZqPz)g zxfsEoJ#4>FkuS3t0EDVOo-D58k-vryz<GyDm^<5uk#()u7TB0q7U@CIJ z7tdA?6h^SK4;Qx4C`B#C6}Le7{1r~*7u!W(f11J(g7TnMUgj44BGGGUQVCrD2}&B! zdyuTBsK+W8uw@3*`sy?IEp`eN;FtG|9%$w^p8{df!)8)ku4W+>G2Lm`UP8FSc}BSG zQfnPb;xucE!9bj~NmpbP%Xo11bD`WXAvx%Av{(3AgQ}@dr5!4P+tb-n0eN)bB-z`nsChVk!vcO4OR4LgpK~e&+-H#iH^HPWj#75 z)EMk+su{{O^qny_p#@o1+jzEYw<#rHhe|Pd(DObIQ>9R-*?fmr^Dxa7A^q6wsmaaM zw)u1AC=TAsoyiKi8U)edOmupa$!tTrT|G~!foTGg)lX0~`kB{Z8d^LU>`iA?O7nKw zU9}UxGxI{3q4ne4b&Bd4kd>EX0yky(BSYrF^Oz1xS^AlJZ_68Vl|%SEeTiK(16~zE zY`v@sJ-?T0&c*_lgVgv+r}S?-UDKRCzFpLtI5b5wg4mrVziMZM?uE>b+^QT7@7kQl z^dLmc_lZZakWyM^9U0u_MAsiykZdvmz0s>-5YS!*T(2xD7L9wi2A%p}AuR>sm|Gyx zGcMz0N<)VxyT2FFm10~x6)y9CGG_CpQzOpTk;5E_7}Z~+q8HQ}kbtevN_?#S?q%K`O!@>h+OTU#XP$rX+MBnvJx z4=Q22w*nPyn373wa8|Armxb8Mo7dAqXsSk4mVIfS5bGg}7maM=heF6L7%XAANY=mV z5LUEXOr?4^Xc zvc3(18n=^7lLxut+5}iBB#mu%x*M&HT|cK!L*oUV6REl(xC*eg0vN@XV=ed0U+Wn$p4y=*H!&t6)sD#Be|NM$%8=k zDB#7iB(VsW;;5oLy18Z+gjB_iCxR<-?C;^DHa3=-yD6P4OY&)i!Mm zOU=VHbojaLP^&a{5FHbLd=ry>XgK5WWC^Ir+O^RTSFmX2ne@T)&hNaR^tg?Uz<7LD_vD+%V&-hq@)$!r@l_BjH?(TSQ zndHv>nNbDNvAG!=kUCJq22lU%F3!nKFUNkBF2G{-xxVflN<#%dmAWHTR-2xWsou*? z-x_Mj#7Librbi$kQ>xjt=|B0)WgW!JyT+x=E_>c&Ysv7C*;~bVC%hBD z#&a5+P&`XS)z=J#qqaOlG?VCH|Jwe<)smh4&^1z*S$&=Clohy?E^L*_$iAeZOjm#~ zJ6q)G8c1{9hhH(qn>y6!-rG*u0E6m2ud(6PX<+@L&MBJCYF0$`TrtL)5-IS{iiP;yAq*=+xKSEU_}L~JzZ z@$84PE^86J4>2~aIbsJi7jSJwp+r zPLM$XVi&u(jyMPDB4g`mai26!;|2tfy2$c5-;i2!k98;Bul~3G%LT&Sz1N`dynTKF zlH7r1*N^tTda{QXD}`T5uff~C=u#LDUsn}9XMXK=Jy~vKvF<*=EOOJvRkR%Cbm@iT zQTyOaxt8d0=jBH0Om`hP`+{LW;_uVO2q|JuifGdU-;S^kN{V-NE<5N8l*UAp6R7p& zL*B}WJMn#u$f}gdiw${sRo(ke@yY#ZJxMRF%cCp{e_nHBQeUG%6=sh@R1TMKY4jRTzB98NUvx!8n9&fkdCjoDETRv*Q{7c-i%d>8mM{>F1tgpvr-x6*TF<4V2xQcC zxX9_7Pl{q=`1w&5T326;(#oqHCa~KJ3JbtTPNbBfmh=sR&DY?_M4AkcQ{Uk#;O*o> zu!ON*h0kR=q79s09=AJ3P`Ejr${Qse$|0+{3^h(YqHmU?H%>PGJ>VLzbV*iOk<^Gd{8vIkA{~ek#`_I&r z<-gd}f051qXRi4l1*-ohnJ)ijF#jjM{10mRKk+5Y|M4FG?-td69Pz*LB_lH<`@am< z|DrGd(M<+||9JjC=u1x(<*e%jx*NLwdg$zWe)$$+7MRWfw>tx9T-i(RKN?9fVOX-A6x%#EM(tQ{|@ex zngyNo?|Km(ATl6KKpytlApDsHg!8A=FpxbM*JgmWHeU}g0j7U(V|e!^08twch`@_k zi~X?|$a{=JB}juCa2p7(&d-Di3|Lx_Hm;3K7oVdan3FTa7yRHfxUt|8K@G=QiT`_x`<41HMYVnEhe&&DYE@}$_{s?M)5ho@OKfC_ z_}0b@1m33?HZpzl7%O!uoC=Ue#)sH82MjKZU5Aertm&UqpoiD%7?`NjBR)&NZQ-l-0 z=;)5h@b34~qOa0D`sVb^#z)A0Kl&fQ@{jiq@1sB-`5c_VacK~?Uzv-iYN!>j?9N