aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.wiz179
-rw-r--r--backends/fs/psp/psp-stream.h32
-rw-r--r--backends/module.mk12
-rw-r--r--backends/platform/ds/arm7/source/main.cpp4
-rw-r--r--backends/platform/ds/arm9/makefile79
-rw-r--r--backends/platform/ds/arm9/source/dsmain.cpp5
-rw-r--r--backends/platform/ds/arm9/source/fat/io_nmmc.c10
-rw-r--r--backends/platform/gp2x/graphics.cpp5
-rw-r--r--backends/platform/gp2xwiz/gp2xwiz-graphics.cpp5
-rw-r--r--backends/platform/gp2xwiz/gp2xwiz-main.cpp3
-rw-r--r--backends/platform/gp2xwiz/module.mk3
-rw-r--r--backends/platform/linuxmoto/linuxmoto-graphics.cpp5
-rw-r--r--backends/platform/ps2/Makefile.ps298
-rw-r--r--backends/platform/ps2/elf32.h209
-rw-r--r--backends/platform/ps2/module.mk3
-rw-r--r--backends/platform/ps2/systemps2.cpp9
-rw-r--r--backends/platform/psp/Makefile10
-rw-r--r--backends/platform/psp/audio.cpp4
-rw-r--r--backends/platform/psp/audio.h4
-rw-r--r--backends/platform/psp/cursor.cpp4
-rw-r--r--backends/platform/psp/default_display_client.h4
-rw-r--r--backends/platform/psp/display_client.cpp4
-rw-r--r--backends/platform/psp/display_manager.cpp4
-rw-r--r--backends/platform/psp/display_manager.h4
-rw-r--r--backends/platform/psp/input.cpp4
-rw-r--r--backends/platform/psp/psploader.cpp732
-rw-r--r--backends/platform/psp/thread.cpp4
-rw-r--r--backends/platform/psp/thread.h4
-rw-r--r--backends/platform/samsungtv/main.cpp2
-rw-r--r--backends/platform/sdl/graphics.cpp5
-rw-r--r--backends/platform/sdl/main.cpp2
-rw-r--r--backends/platform/sdl/sdl.cpp8
-rw-r--r--backends/platform/sdl/sdl.h2
-rw-r--r--backends/plugins/arm-loader.cpp169
-rw-r--r--backends/plugins/arm-loader.h37
-rw-r--r--backends/plugins/ds/ds-provider.cpp45
-rw-r--r--backends/plugins/ds/ds-provider.h32
-rw-r--r--backends/plugins/ds/plugin.ld218
-rw-r--r--backends/plugins/elf-loader.cpp413
-rw-r--r--backends/plugins/elf-loader.h67
-rw-r--r--backends/plugins/elf-provider.cpp105
-rw-r--r--backends/plugins/elf-provider.h70
-rw-r--r--backends/plugins/elf32.h229
-rw-r--r--backends/plugins/mips-loader.cpp351
-rw-r--r--backends/plugins/mips-loader.h46
-rw-r--r--backends/plugins/plugin.syms (renamed from backends/platform/psp/plugin.syms)0
-rw-r--r--backends/plugins/ps2/main_prog.ld99
-rw-r--r--backends/plugins/ps2/plugin.ld94
-rw-r--r--backends/plugins/ps2/ps2-provider.cpp44
-rw-r--r--backends/plugins/ps2/ps2-provider.h31
-rw-r--r--backends/plugins/psp/plugin.ld (renamed from backends/platform/psp/plugin.ld)0
-rw-r--r--backends/plugins/psp/psp-provider.cpp76
-rw-r--r--backends/plugins/psp/psp-provider.h8
-rw-r--r--backends/plugins/shorts-segment-manager.cpp89
-rw-r--r--backends/plugins/shorts-segment-manager.h (renamed from backends/platform/psp/psploader.h)76
-rw-r--r--backends/saves/default/default-saves.cpp4
-rw-r--r--base/commandLine.cpp35
-rw-r--r--base/commandLine.h2
-rw-r--r--base/main.cpp19
-rw-r--r--base/plugins.cpp81
-rw-r--r--base/plugins.h9
-rw-r--r--common/error.h10
-rw-r--r--common/macresman.cpp10
-rw-r--r--common/str.h6
-rw-r--r--common/stream.h2
-rw-r--r--common/unzip.cpp4
-rwxr-xr-xconfigure21
-rw-r--r--engines/drascula/animation.cpp2
-rw-r--r--engines/drascula/drascula.cpp1
-rw-r--r--engines/drascula/objects.cpp3
-rw-r--r--engines/m4/compression.h4
-rw-r--r--engines/m4/console.cpp56
-rw-r--r--engines/m4/console.h3
-rw-r--r--engines/m4/converse.cpp8
-rw-r--r--engines/m4/dialogs.cpp26
-rw-r--r--engines/m4/globals.h1
-rw-r--r--engines/m4/gui.cpp30
-rw-r--r--engines/m4/m4.cpp12
-rw-r--r--engines/m4/m4.h3
-rw-r--r--engines/m4/m4_views.cpp2
-rw-r--r--engines/m4/mads_anim.cpp16
-rw-r--r--engines/m4/mads_menus.cpp56
-rw-r--r--engines/metaengine.h1
-rw-r--r--engines/mohawk/video/cinepak.cpp286
-rw-r--r--engines/mohawk/video/cinepak.h81
-rw-r--r--engines/mohawk/video/qdm2.cpp3063
-rw-r--r--engines/mohawk/video/qdm2.h289
-rw-r--r--engines/mohawk/video/qdm2data.h531
-rw-r--r--engines/mohawk/video/qt_player.cpp1272
-rw-r--r--engines/mohawk/video/qt_player.h282
-rw-r--r--engines/mohawk/video/qtrle.cpp420
-rw-r--r--engines/mohawk/video/qtrle.h58
-rw-r--r--engines/mohawk/video/rpza.cpp208
-rw-r--r--engines/mohawk/video/rpza.h49
-rw-r--r--engines/mohawk/video/smc.cpp385
-rw-r--r--engines/mohawk/video/smc.h59
-rw-r--r--engines/mohawk/video/video.cpp377
-rw-r--r--engines/mohawk/video/video.h107
-rw-r--r--engines/parallaction/debug.cpp27
-rw-r--r--engines/parallaction/debug.h1
-rw-r--r--engines/parallaction/dialogue.cpp4
-rw-r--r--engines/parallaction/exec_br.cpp2
-rw-r--r--engines/parallaction/graphics.cpp6
-rw-r--r--engines/parallaction/input.cpp15
-rw-r--r--engines/parallaction/objects.h4
-rw-r--r--engines/parallaction/parallaction.cpp112
-rw-r--r--engines/parallaction/parallaction.h2
-rw-r--r--engines/parallaction/parallaction_br.cpp4
-rw-r--r--engines/parallaction/parser.cpp9
-rw-r--r--engines/parallaction/parser_ns.cpp2
-rw-r--r--engines/parallaction/sound_br.cpp4
-rw-r--r--engines/saga/saga.cpp14
-rw-r--r--engines/sci/engine/script_patches.cpp23
-rw-r--r--engines/sci/sound/iterator/core.cpp1013
-rw-r--r--engines/sci/sound/iterator/core.h209
-rw-r--r--engines/sci/sound/iterator/iterator.cpp1686
-rw-r--r--engines/sci/sound/iterator/iterator.h326
-rw-r--r--engines/sci/sound/iterator/iterator_internal.h276
-rw-r--r--engines/sci/sound/iterator/songlib.cpp189
-rw-r--r--engines/sci/sound/iterator/songlib.h171
-rw-r--r--engines/sci/sound/iterator/test-iterator.cpp423
-rw-r--r--engines/scumm/charset.cpp2
-rw-r--r--engines/scumm/debugger.cpp2
-rw-r--r--engines/scumm/dialogs.cpp213
-rw-r--r--engines/scumm/dialogs.h24
-rw-r--r--engines/scumm/he/resource_he.cpp4
-rw-r--r--engines/scumm/input.cpp2
-rw-r--r--engines/scumm/scumm.cpp18
-rw-r--r--engines/scumm/scumm.h2
-rw-r--r--engines/sword1/animation.cpp38
-rw-r--r--engines/sword1/animation.h1
-rw-r--r--engines/sword2/animation.cpp37
-rw-r--r--engines/sword2/animation.h1
-rw-r--r--engines/tinsel/handle.cpp3
-rw-r--r--graphics/video/coktelvideo/coktelvideo.cpp2657
-rw-r--r--graphics/video/coktelvideo/coktelvideo.h598
-rw-r--r--graphics/video/coktelvideo/indeo3.cpp3485
-rw-r--r--graphics/video/coktelvideo/indeo3.h126
-rw-r--r--gui/about.cpp35
-rw-r--r--gui/editable.cpp2
-rw-r--r--gui/launcher.cpp7
-rw-r--r--gui/themes/scummclassic/classic_layout.stx35
-rw-r--r--gui/themes/scummclassic/classic_layout_lowres.stx44
-rw-r--r--gui/themes/scummmodern/scummmodern_layout.stx35
-rw-r--r--gui/themes/scummmodern/scummmodern_layout_lowres.stx37
-rw-r--r--ports.mk8
-rw-r--r--sound/decoders/adpcm.cpp4
-rw-r--r--sound/mods/rjp1.cpp2
-rw-r--r--test/common/str.h24
-rw-r--r--tools/create_msvc/create_msvc.cpp3
-rw-r--r--tools/md5table.c4
-rw-r--r--tools/module.mk6
-rw-r--r--tools/scumm-md5.txt3
153 files changed, 22111 insertions, 1528 deletions
diff --git a/Makefile.wiz b/Makefile.wiz
new file mode 100644
index 0000000000..5370fb3ac5
--- /dev/null
+++ b/Makefile.wiz
@@ -0,0 +1,179 @@
+srcdir ?= .
+
+DEFINES := -DHAVE_CONFIG_H
+LDFLAGS :=
+INCLUDES := -I. -I$(srcdir) -I$(srcdir)/engines
+LIBS :=
+OBJS :=
+DEPDIR := .deps
+
+CXX := arm-open2x-linux-g++
+CXXFLAGS := -mcpu=arm926ej-s -mtune=arm926ej-s -I/opt/open2x/gcc-4.1.1-glibc-2.3.6/include -g -mcpu=arm926ej-s -mtune=arm926ej-s -mcpu=arm926ej-s -mtune=arm926ej-s -ansi -W -Wno-unused-parameter -Wconversion -pedantic
+LD := arm-open2x-linux-g++
+LIBS += -L/opt/open2x/gcc-4.1.1-glibc-2.3.6/lib -lvorbisidec -L/opt/open2x/gcc-4.1.1-glibc-2.3.6/lib -lmad -L/opt/open2x/gcc-4.1.1-glibc-2.3.6/lib -lz -L/opt/open2x/gcc-4.1.1-glibc-2.3.6/lib -Wl,-rpath,/opt/open2x/gcc-4.1.1-glibc-2.3.6/lib -lSDL -lpthread
+RANLIB := arm-open2x-linux-ranlib
+STRIP := arm-open2x-linux-strip
+AR := arm-open2x-linux-ar cru
+AS := arm-open2x-linux-as
+ASFLAGS := -mfloat-abi=soft
+WINDRES := arm-open2x-linux-windres
+WINDRESFLAGS :=
+WIN32PATH=C:/scummvm
+AOS4PATH=Games:ScummVM
+STATICLIBPATH=/sw
+
+BACKEND := gp2xwiz
+MODULES += backends/platform/gp2xwiz
+MODULE_DIRS +=
+EXEEXT := .wiz
+NASM :=
+NASMFLAGS :=
+
+prefix = /usr/local
+exec_prefix = ${prefix}
+bindir = ${exec_prefix}/bin
+datarootdir = ${prefix}/share
+datadir = ${datarootdir}/scummvm
+docdir = ${datarootdir}/doc/scummvm
+libdir = ${exec_prefix}/lib
+mandir = ${datarootdir}/man
+
+HAVE_GCC = 1
+USE_ARM_SOUND_ASM = 1
+USE_ARM_SMUSH_ASM = 1
+USE_ARM_GFX_ASM = 1
+USE_ARM_COSTUME_ASM = 1
+USE_ARM_SCALER_ASM = 1
+# VERBOSE_BUILD = 1
+# USE_MT32EMU = 1
+# USE_RGB_COLOR = 1
+USE_SCALERS = 1
+# USE_HQ_SCALERS = 1
+USE_INDEO3 = 1
+# USE_VORBIS = 1
+USE_TREMOR = 1
+# USE_FLAC = 1
+USE_MAD = 1
+USE_ZLIB = 1
+# USE_MPEG2 = 1
+# USE_NASM = 1
+HAVE_GCC3 = 1
+CXX_UPDATE_DEP_FLAG = -MMD -MF "$(*D)/$(DEPDIR)/$(*F).d" -MQ "$@" -MP
+
+DYNAMIC_MODULES := 1
+VERBOSE_BUILD := 1
+
+ifeq ($(DYNAMIC_MODULES),1)
+ENABLED = DYNAMIC_PLUGIN
+PLUGIN_PREFIX :=
+PLUGIN_SUFFIX := .plugin
+PLUGIN_EXTRA_DEPS = $(EXECUTABLE)
+CXXFLAGS += -DDYNAMIC_MODULES
+PLUGIN_LDFLAGS += --nostartfiles -Wl,-q,--just-symbols,scummvm.wiz,-Tbackends/platform/gp2xwiz/plugin.ld,--retain-symbols-file,backends/platform/gp2xwiz/plugin.syms -lstdc++ -lc
+PRE_OBJS_FLAGS := -Wl,-whole-archive
+POST_OBJS_FLAGS := -Wl,-no-whole-archive
+#LIBS += -ldl
+else
+ENABLED = STATIC_PLUGIN
+endif
+
+ENABLE_SCUMM = $(ENABLED)
+ENABLE_SCUMM_7_8 = $(ENABLED)
+ENABLE_HE = $(ENABLED)
+ENABLE_AGI = $(ENABLED)
+ENABLE_AGOS = $(ENABLED)
+ENABLE_AGOS2 = $(ENABLED)
+ENABLE_CINE = $(ENABLED)
+ENABLE_CRUISE = $(ENABLED)
+ENABLE_DRACI = $(ENABLED)
+ENABLE_DRASCULA = $(ENABLED)
+ENABLE_GOB = $(ENABLED)
+ENABLE_GROOVIE = $(ENABLED)
+ENABLE_GROOVIE2 = $(ENABLED)
+ENABLE_KYRA = $(ENABLED)
+ENABLE_LOL = $(ENABLED)
+ENABLE_LURE = $(ENABLED)
+ENABLE_M4 = $(ENABLED)
+ENABLE_MADE = $(ENABLED)
+ENABLE_MOHAWK = $(ENABLED)
+ENABLE_PARALLACTION = $(ENABLED)
+ENABLE_QUEEN = $(ENABLED)
+ENABLE_SAGA = $(ENABLED)
+ENABLE_IHNM = $(ENABLED)
+ENABLE_SAGA2 = $(ENABLED)
+ENABLE_SCI = $(ENABLED)
+ENABLE_SCI32 = $(ENABLED)
+ENABLE_SKY = $(ENABLED)
+ENABLE_SWORD1 = $(ENABLED)
+ENABLE_SWORD2 = $(ENABLED)
+ENABLE_TEENAGENT = $(ENABLED)
+ENABLE_TINSEL = $(ENABLED)
+ENABLE_TOUCHE = $(ENABLED)
+ENABLE_TUCKER = $(ENABLED)
+
+INCLUDES += -I/opt/open2x/gcc-4.1.1-glibc-2.3.6/include -I/opt/open2x/gcc-4.1.1-glibc-2.3.6/include -I/opt/open2x/gcc-4.1.1-glibc-2.3.6/include -I/opt/open2x/gcc-4.1.1-glibc-2.3.6/include/SDL -D_GNU_SOURCE=1 -D_REENTRANT
+OBJS +=
+DEFINES += -DNDEBUG -DUNIX -DUNIX -DGP2XWIZ -DNDEBUG -DENABLE_VKEYBD -DDATA_PATH=\"${datarootdir}/scummvm\" -DPLUGIN_DIRECTORY=\"${exec_prefix}/lib/scummvm\"
+LDFLAGS += -L/opt/open2x/gcc-4.1.1-glibc-2.3.6/lib -lm
+
+port_mk = ports.mk
+
+ifeq "$(HAVE_GCC)" "1"
+ CXXFLAGS:= -Wall $(CXXFLAGS)
+ # Turn off some annoying and not-so-useful warnings
+ CXXFLAGS+= -Wno-long-long -Wno-multichar -Wno-unknown-pragmas -Wno-reorder
+ # Enable even more warnings...
+ CXXFLAGS+= -Wpointer-arith -Wcast-qual -Wcast-align
+ CXXFLAGS+= -Wshadow -Wimplicit -Wnon-virtual-dtor -Wwrite-strings
+
+ # Currently we disable this gcc flag, since it will also warn in cases,
+ # where using GCC_PRINTF (means: __attribute__((format(printf, x, y))))
+ # is not possible, thus it would fail compiliation with -Werror without
+ # being helpful.
+ #CXXFLAGS+= -Wmissing-format-attribute
+
+ # Disable RTTI and exceptions, and enable checking of pointers returned by "new"
+ CXXFLAGS+= -fno-rtti -fno-exceptions -fcheck-new
+endif
+
+ifeq "$(HAVE_CLANG)" "1"
+ CXXFLAGS+= -Wno-conversion -Wno-shorten-64-to-32 -Wno-sign-compare -Wno-four-char-constants
+endif
+
+#######################################################################
+# Default commands - put the necessary replacements in config.mk #
+#######################################################################
+
+CAT ?= cat
+CP ?= cp
+ECHO ?= printf
+INSTALL ?= install
+MKDIR ?= mkdir -p
+RM ?= rm -f
+RM_REC ?= $(RM) -r
+ZIP ?= zip -q
+
+#######################################################################
+# Misc stuff - you should never have to edit this #
+#######################################################################
+
+EXECUTABLE := scummvm$(EXEEXT)
+
+include $(srcdir)/Makefile.common
+
+# check if configure has been run or has been changed since last run
+config.h config.mk: $(srcdir)/configure
+ifeq "$(findstring config.mk,$(MAKEFILE_LIST))" "config.mk"
+ @echo "Running $(srcdir)/configure with the last specified parameters"
+ @sleep 2
+ LDFLAGS="$(SAVED_LDFLAGS)" CXX="$(SAVED_CXX)" \
+ CXXFLAGS="$(SAVED_CXXFLAGS)" CPPFLAGS="$(SAVED_CPPFLAGS)" \
+ ASFLAGS="$(SAVED_ASFLAGS)" WINDRESFLAGS="$(SAVED_WINDRESFLAGS)" \
+ $(srcdir)/configure $(SAVED_CONFIGFLAGS)
+else
+ $(error You need to run $(srcdir)/configure before you can run make. Check $(srcdir)/configure --help for a list of parameters)
+endif
+
+ifneq ($(origin port_mk), undefined)
+include $(srcdir)/$(port_mk)
+endif
diff --git a/backends/fs/psp/psp-stream.h b/backends/fs/psp/psp-stream.h
index 9fd1ad0470..673630b685 100644
--- a/backends/fs/psp/psp-stream.h
+++ b/backends/fs/psp/psp-stream.h
@@ -35,39 +35,25 @@
*/
class PSPIoStream : public StdioStream, public Suspendable {
protected:
- Common::String _path;
- int _fileSize;
- bool _writeMode; // for resuming in the right mode
- int _physicalPos; // position in the real file
- int _pos; // position. Sometimes virtual
- bool _inCache; // whether we're in cache (virtual) mode
- bool _eos; // EOS flag
-
+ Common::String _path; /* Need to maintain for reopening after suspend */
+ bool _writeMode; /* "" */
+ int _pos; /* "" */
+ mutable int _ferror; /* Save file ferror */
+ mutable bool _feof; /* and eof */
+
enum {
SuspendError = 2,
ResumeError = 3
};
- enum {
- CACHE_SIZE = 1024,
- MIN_READ_SIZE = 1024 // reading less than 1024 takes exactly the same time as 1024
- };
-
- // For caching
- char *_cache;
- int _cacheStartOffset; // starting offset of the cache. -1 when cache is invalid
-
- mutable int _ferror; // file error state
- int _errorSuspend; // for debugging
+ int _errorSuspend;
mutable int _errorSource;
+
+ // Error checking
int _errorPos;
void * _errorHandle;
int _suspendCount;
- bool synchronizePhysicalPos(); // synchronize the physical and virtual positions
- bool isOffsetInCache(uint32 pos); // check if an offset is found in cache
- bool isCacheValid() { return _cacheStartOffset != -1; }
-
public:
/**
diff --git a/backends/module.mk b/backends/module.mk
index e0a3f4c683..c0457d8062 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -22,6 +22,12 @@ MODULE_OBJS := \
midi/timidity.o \
midi/dmedia.o \
midi/windows.o \
+ plugins/elf-loader.o \
+ plugins/mips-loader.o \
+ plugins/shorts-segment-manager.o \
+ plugins/arm-loader.o \
+ plugins/elf-provider.o \
+ plugins/dc/dc-provider.o \
plugins/posix/posix-provider.o \
plugins/sdl/sdl-provider.o \
plugins/win32/win32-provider.o \
@@ -43,7 +49,8 @@ endif
ifeq ($(BACKEND),ds)
MODULE_OBJS += \
fs/ds/ds-fs-factory.o \
- fs/ds/ds-fs.o
+ fs/ds/ds-fs.o \
+ plugins/ds/ds-provider.o
endif
ifeq ($(BACKEND),n64)
@@ -54,7 +61,8 @@ endif
ifeq ($(BACKEND),ps2)
MODULE_OBJS += \
- fs/ps2/ps2-fs-factory.o
+ fs/ps2/ps2-fs-factory.o \
+ plugins/ps2/ps2-provider.o
endif
ifeq ($(BACKEND),psp)
diff --git a/backends/platform/ds/arm7/source/main.cpp b/backends/platform/ds/arm7/source/main.cpp
index bcaaf8e936..75f7012ed0 100644
--- a/backends/platform/ds/arm7/source/main.cpp
+++ b/backends/platform/ds/arm7/source/main.cpp
@@ -40,7 +40,7 @@
#include <system.h>
#include <stdlib.h>
#include <string.h>
-#include <registers_alt.h> // Needed for SOUND_CR
+#include <registers_alt.h> // Needed for SOUND_CR
#include <NDS/scummvm_ipc.h>
//////////////////////////////////////////////////////////////////////
#ifdef USE_DEBUGGER
@@ -592,7 +592,7 @@ int main(int argc, char ** argv) {
IPC->reset = false;
- //fifoInit();
+ //fifoInit();
for (int r = 0; r < 8; r++) {
IPC->adpcm.arm7Buffer[r] = (u8 *) malloc(512);
diff --git a/backends/platform/ds/arm9/makefile b/backends/platform/ds/arm9/makefile
index eedf75c256..c9a665c442 100644
--- a/backends/platform/ds/arm9/makefile
+++ b/backends/platform/ds/arm9/makefile
@@ -1,10 +1,13 @@
srcdir ?= .
DEPDIR := .deps
-#DYNAMIC_MODULES = 1
+VERBOSE_BUILD = 1
+DYNAMIC_MODULES = 1
libndsdir = $(DEVKITPRO)/libnds
#libndsdir = /home/neil/devkitpror21/libnds
+ENABLED = DYNAMIC_PLUGIN
+
# Select the build by setting SCUMM_BUILD to a,b,c,d,e,f or g.
# Anything else gets build a.
@@ -12,7 +15,7 @@ ifeq ($(SCUMM_BUILD),k)
DS_BUILD_K = 1
else
ifeq ($(SCUMM_BUILD),j)
- DS_BUILD_J = 1
+ DS_BUILD_J = 1
else
ifeq ($(SCUMM_BUILD),i)
DS_BUILD_I = 1
@@ -64,9 +67,7 @@ ifdef DS_BUILD_F
else
ifdef DS_BUILD_E
# TODO: Inherit the earth uses so much RAM that I have removed libmad in order to
- # claw some back.
-
-
+ # claw some back.
else
ifdef DS_BUILD_I
@@ -75,7 +76,7 @@ else
ifdef DS_BUILD_K
else
- # USE_MAD = 1
+ #USE_MAD = 1
endif
endif
endif
@@ -112,7 +113,7 @@ USE_ARM_COSTUME_ASM = 1
ifdef DS_BUILD_A
DEFINES = -DDS_BUILD_A -DUSE_ARM_GFX_ASM -DUSE_ARM_COSTUME_ASM
LOGO = logoa.bmp
- ENABLE_SCUMM = STATIC_PLUGIN
+ ENABLE_SCUMM = $(ENABLED)
USE_ARM_GFX_ASM = 1
BUILD=scummvm-A
endif
@@ -120,66 +121,66 @@ endif
ifdef DS_BUILD_B
DEFINES = -DDS_BUILD_B
LOGO = logob.bmp
- ENABLE_SKY = STATIC_PLUGIN
- ENABLE_QUEEN = STATIC_PLUGIN
+ ENABLE_SKY = $(ENABLED)
+ ENABLE_QUEEN = $(ENABLED)
BUILD=scummvm-B
endif
ifdef DS_BUILD_C
DEFINES = -DDS_BUILD_C
LOGO = logoc.bmp
- ENABLE_AGOS = STATIC_PLUGIN
+ ENABLE_AGOS = $(ENABLED)
BUILD=scummvm-C
endif
ifdef DS_BUILD_D
DEFINES = -DDS_BUILD_D
LOGO = logod.bmp
- ENABLE_GOB = STATIC_PLUGIN
- ENABLE_CINE = STATIC_PLUGIN
- ENABLE_AGI = STATIC_PLUGIN
+ ENABLE_GOB = $(ENABLED)
+ ENABLE_CINE = $(ENABLED)
+ ENABLE_AGI = $(ENABLED)
BUILD=scummvm-D
endif
ifdef DS_BUILD_E
DEFINES = -DDS_BUILD_E
LOGO = logoe.bmp
- ENABLE_SAGA = STATIC_PLUGIN
+ ENABLE_SAGA = $(ENABLED)
BUILD=scummvm-E
endif
ifdef DS_BUILD_F
DEFINES = -DDS_BUILD_F
LOGO = logof.bmp
- ENABLE_KYRA = STATIC_PLUGIN
+ ENABLE_KYRA = $(ENABLED)
BUILD=scummvm-F
endif
ifdef DS_BUILD_G
DEFINES = -DDS_BUILD_G
LOGO = logog.bmp
- ENABLE_LURE = STATIC_PLUGIN
+ ENABLE_LURE = $(ENABLED)
BUILD=scummvm-G
endif
ifdef DS_BUILD_H
DEFINES = -DDS_BUILD_H
LOGO = logoh.bmp
- ENABLE_PARALLACTION = STATIC_PLUGIN
+ ENABLE_PARALLACTION = $(ENABLED)
BUILD=scummvm-H
endif
ifdef DS_BUILD_I
DEFINES = -DDS_BUILD_I
LOGO = logoi.bmp
- ENABLE_MADE = STATIC_PLUGIN
+ ENABLE_MADE = $(ENABLED)
BUILD=scummvm-I
endif
ifdef DS_BUILD_K
DEFINES = -DDS_BUILD_K
LOGO = logok.bmp
- ENABLE_CRUISE = STATIC_PLUGIN
+ ENABLE_CRUISE = $(ENABLED)
BUILD=scummvm-K
endif
@@ -187,18 +188,18 @@ endif
#ifdef DS_BUILD_L
# DEFINES = -DDS_BUILD_L
# LOGO = logog.bmp
-# ENABLE_DRASCULA = STATIC_PLUGIN
+# ENABLE_DRASCULA = $(ENABLED)
# BUILD=scummvm-K
#endif
#ifdef DS_BUILD_M
# DEFINES = -DDS_BUILD_M
# LOGO = logog.bmp
-# ENABLE_TUCKER = STATIC_PLUGIN
+# ENABLE_TUCKER = $(ENABLED)
# BUILD=scummvm-K
#endif
-ARM7BIN := -7 $(CURDIR)/../../arm7/arm7.bin
+ARM7BIN := -7 $(CURDIR)/../arm7/arm7.bin
CC = arm-eabi-gcc
CXX = arm-eabi-g++
@@ -236,14 +237,14 @@ CXXFLAGS= $(CFLAGS) -Wno-non-virtual-dtor -Wno-unknown-pragmas -Wno-reorder \
ASFLAGS = -mcpu=arm9tdmi -mthumb-interwork
-DEFINES += -D__DS__ -DNDS -DARM9 -DNONSTANDARD_PORT -DDISABLE_FANCY_THEMES -DVECTOR_RENDERER_FORMAT=1555 -DDISABLE_DOSBOX_OPL -DDISABLE_DEFAULT_SAVEFILEMANAGER -DARM
+DEFINES += -D__DS__ -DNDS -DARM9 -DNONSTANDARD_PORT -DDISABLE_FANCY_THEMES -DVECTOR_RENDERER_FORMAT=1555 -DDISABLE_DOSBOX_OPL -DDISABLE_DEFAULT_SAVEFILEMANAGER -DELF_LOADER_TARGET -DARM -DARM_TARGET#-DNEW_PLUGIN_DESIGN_FIRST_REFINEMENT
ifdef USE_MAD
DEFINES += -DUSE_MAD
endif
DEFINES += -DREDUCE_MEMORY_USAGE
-LDFLAGS = -specs=ds_arm9.specs -mthumb-interwork -mno-fpu -Wl,-Map,map.txt -Wl,--gc-sections
+LDFLAGS = -specs=ds_arm9.specs -mthumb-interwork -mno-fpu -Wl,--target1-abs,-Map,map.txt#-Wl,--gc-sections
ifdef WRAP_MALLOC
LDFLAGS += -Wl,--wrap,malloc
@@ -252,12 +253,11 @@ endif
BACKEND := ds
-INCLUDES= -I$(portdir)/$(BUILD) -I$(srcdir) -I$(srcdir)/engines \
+INCLUDES= -I$(portdir) -I$(srcdir) -I$(srcdir)/engines \
-I$(portdir)/data -I$(portdir)/../commoninclude \
-I$(portdir)/source -I$(portdir)/source/mad \
-I$(libndsdir)/include -include $(srcdir)/common/scummsys.h
-
LIBS = -lm -L$(libndsdir)/lib -L$(portdir)/lib -lnds9
ifdef USE_MAD
LIBS += -lmad
@@ -266,7 +266,19 @@ ifdef USE_DEBUGGER
LIBS += -ldsdebugger -ldswifi9
endif
+ifeq ($(DYNAMIC_MODULES),1)
+DEFINES += -DDYNAMIC_MODULES
+PRE_OBJS_FLAGS = -Wl,--whole-archive
+POST_OBJS_FLAGS = -Wl,--no-whole-archive
+endif
+
EXECUTABLE = scummvm.elf
+
+PLUGIN_PREFIX =
+PLUGIN_SUFFIX = .plg
+PLUGIN_EXTRA_DEPS = $(srcdir)/backends/plugins/ds/plugin.ld $(srcdir)/backends/plugins/plugin.syms $(EXECUTABLE)
+PLUGIN_LDFLAGS += -nostartfiles -Wl,-q,--target1-abs,--just-symbols,$(EXECUTABLE),-T$(srcdir)/backends/plugins/ds/plugin.ld,--retain-symbols-file,$(srcdir)/backends/plugins/plugin.syms -lstdc++ -lc -mthumb-interwork -mno-fpu#-Wl,--gc-sections -mno-crt0 $(DEVKITPRO)/devkitARM/arm-eabi/lib/ds_arm9_crt0.o
+
MKDIR = mkdir -p
RM = rm -f
RM_REC = rm -rf
@@ -340,12 +352,13 @@ OPT_SIZE := -Os -mthumb
OBJS := $(DATA_OBJS) $(PORT_OBJS) $(FAT_OBJS)
-
MODULE_DIRS += .
-ndsall:
- @[ -d $(BUILD) ] || mkdir -p $(BUILD)
- make -C ./$(BUILD) -f ../makefile scummvm.nds scummvm.ds.gba
+#ndsall: plugins
+# make -f makefile scummvm.nds
+
+ndsall: plugins
+ make -f makefile scummvm.nds scummvm.ds.gba
include $(srcdir)/Makefile.common
@@ -354,11 +367,10 @@ semiclean:
clean:
$(RM) $(OBJS) $(EXECUTABLE)
- rm -fr $(BUILD)
+ rm -rf *.h engines plugins scummvm.nds scummvm.ds.gba
dist : SCUMMVM.BIN plugins plugin_dist
-
#---------------------------------------------------------------------------------
# canned command sequence for binary data
#---------------------------------------------------------------------------------
@@ -400,13 +412,14 @@ endef
#---------------------------------------------------------------------------------
%.nds: %.bin
- ndstool -c $@ -9 $< $(ARM7BIN) -b ../../$(LOGO) "$(@F);ScummVM $(VERSION);DS Port"
+ ndstool -c $@ -9 $< $(ARM7BIN) -b ../$(LOGO) "$(@F);ScummVM $(VERSION);DS Port"
%.ds.gba: %.nds
dsbuild $< -o $@ -l $(portdir)/ndsloader.bin
padbin 16 $@
#---------------------------------------------------------------------------------
+
%.bin: %.elf
$(OBJCOPY) -S -O binary $< $@
diff --git a/backends/platform/ds/arm9/source/dsmain.cpp b/backends/platform/ds/arm9/source/dsmain.cpp
index 95bfdfe40a..4c7d6b89ae 100644
--- a/backends/platform/ds/arm9/source/dsmain.cpp
+++ b/backends/platform/ds/arm9/source/dsmain.cpp
@@ -105,6 +105,8 @@
#endif
#include "engine.h"
+#include "backends/plugins/ds/ds-provider.h"
+#include "backends/plugins/elf-provider.h"
#include "backends/fs/ds/ds-fs.h"
#include "base/version.h"
#include "common/util.h"
@@ -3213,6 +3215,9 @@ int main(void) {
const char *argv[] = {"/scummvmds"};
#endif
+#ifdef DYNAMIC_MODULES
+ PluginManager::instance().addPluginProvider(new DSPluginProvider());
+#endif
while (1) {
scummvm_main(ARRAYSIZE(argv), (char **) &argv);
diff --git a/backends/platform/ds/arm9/source/fat/io_nmmc.c b/backends/platform/ds/arm9/source/fat/io_nmmc.c
index 6c996f5de1..261096a27b 100644
--- a/backends/platform/ds/arm9/source/fat/io_nmmc.c
+++ b/backends/platform/ds/arm9/source/fat/io_nmmc.c
@@ -170,7 +170,7 @@ bool NMMC_IsInserted(void) {
Neo_EnableMMC( true ); // Open SPI port to MMC card
Neo_SendMMCCommand(MMC_SEND_CSD, 0);
- if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occurred
+ if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occured
Neo_EnableMMC( false );
return false;
}
@@ -227,14 +227,14 @@ bool NMMC_StartUp(void) {
// Set block length
Neo_SendMMCCommand(MMC_SET_BLOCKLEN, BYTE_PER_READ );
- if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occurred
+ if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occured
Neo_EnableMMC( false );
return false;
}
// Check if we can use a higher SPI frequency
Neo_SendMMCCommand(MMC_SEND_CSD, 0);
- if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occurred
+ if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occured
Neo_EnableMMC( false );
return false;
}
@@ -268,7 +268,7 @@ bool NMMC_WriteSectors (u32 sector, u8 numSecs, void* buffer)
Neo_EnableMMC( true ); // Open SPI port to MMC card
Neo_SendMMCCommand( 25, sector );
- if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occurred
+ if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occured
Neo_EnableMMC( false );
return false;
}
@@ -318,7 +318,7 @@ bool NMMC_ReadSectors (u32 sector, u8 numSecs, void* buffer)
while (totalSecs--) {
Neo_SendMMCCommand(MMC_READ_BLOCK, sector );
- if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occurred
+ if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occured
Neo_EnableMMC( false );
return false;
}
diff --git a/backends/platform/gp2x/graphics.cpp b/backends/platform/gp2x/graphics.cpp
index 4a3c668c52..1888cbe47c 100644
--- a/backends/platform/gp2x/graphics.cpp
+++ b/backends/platform/gp2x/graphics.cpp
@@ -1405,6 +1405,7 @@ void OSystem_GP2X::drawMouse() {
SDL_Rect zoomdst;
SDL_Rect dst;
int scale;
+ int width, height;
int hotX, hotY;
int tmpScreenWidth, tmpScreenHeight;
@@ -1425,12 +1426,16 @@ void OSystem_GP2X::drawMouse() {
if (!_overlayVisible) {
scale = _videoMode.scaleFactor;
+ width = _videoMode.screenWidth;
+ height = _videoMode.screenHeight;
dst.w = _mouseCurState.vW;
dst.h = _mouseCurState.vH;
hotX = _mouseCurState.vHotX;
hotY = _mouseCurState.vHotY;
} else {
scale = 1;
+ width = _videoMode.overlayWidth;
+ height = _videoMode.overlayHeight;
dst.w = _mouseCurState.rW;
dst.h = _mouseCurState.rH;
hotX = _mouseCurState.rHotX;
diff --git a/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp b/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp
index f6ad226d42..921558131a 100644
--- a/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp
+++ b/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp
@@ -149,6 +149,7 @@ void OSystem_GP2XWIZ::drawMouse() {
SDL_Rect dst;
int scale;
+ int width, height;
int hotX, hotY;
if (_videoMode.mode == GFX_HALF && !_overlayVisible){
@@ -161,12 +162,16 @@ void OSystem_GP2XWIZ::drawMouse() {
if (!_overlayVisible) {
scale = _videoMode.scaleFactor;
+ width = _videoMode.screenWidth;
+ height = _videoMode.screenHeight;
dst.w = _mouseCurState.vW;
dst.h = _mouseCurState.vH;
hotX = _mouseCurState.vHotX;
hotY = _mouseCurState.vHotY;
} else {
scale = 1;
+ width = _videoMode.overlayWidth;
+ height = _videoMode.overlayHeight;
dst.w = _mouseCurState.rW;
dst.h = _mouseCurState.rH;
hotX = _mouseCurState.rHotX;
diff --git a/backends/platform/gp2xwiz/gp2xwiz-main.cpp b/backends/platform/gp2xwiz/gp2xwiz-main.cpp
index 394c3090c3..8c95a94639 100644
--- a/backends/platform/gp2xwiz/gp2xwiz-main.cpp
+++ b/backends/platform/gp2xwiz/gp2xwiz-main.cpp
@@ -42,7 +42,6 @@
#include "base/main.h"
#include "backends/saves/default/default-saves.h"
-
#include "backends/timer/default/default-timer.h"
#include "sound/mixer_intern.h"
@@ -64,7 +63,7 @@ int main(int argc, char *argv[]) {
#ifdef DYNAMIC_MODULES
PluginManager::instance().addPluginProvider(new POSIXPluginProvider());
-#endif
+#endif /* DYNAMIC_MODULES */
// Invoke the actual ScummVM main entry point:
int res = scummvm_main(argc, argv);
diff --git a/backends/platform/gp2xwiz/module.mk b/backends/platform/gp2xwiz/module.mk
index edf2f2a717..c76238f679 100644
--- a/backends/platform/gp2xwiz/module.mk
+++ b/backends/platform/gp2xwiz/module.mk
@@ -4,7 +4,8 @@ MODULE_OBJS := \
gp2xwiz-events.o \
gp2xwiz-graphics.o \
gp2xwiz-hw.o \
- gp2xwiz-main.o
+ gp2xwiz-main.o \
+ gp2xwiz-loader.o
# We don't use rules.mk but rather manually update OBJS and MODULE_DIRS.
MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS))
diff --git a/backends/platform/linuxmoto/linuxmoto-graphics.cpp b/backends/platform/linuxmoto/linuxmoto-graphics.cpp
index a39416ebc4..d66d41dfab 100644
--- a/backends/platform/linuxmoto/linuxmoto-graphics.cpp
+++ b/backends/platform/linuxmoto/linuxmoto-graphics.cpp
@@ -168,6 +168,7 @@ void OSystem_LINUXMOTO::drawMouse() {
SDL_Rect dst;
int scale;
+ int width, height;
int hotX, hotY;
if (_videoMode.mode == GFX_HALF && !_overlayVisible) {
@@ -180,12 +181,16 @@ void OSystem_LINUXMOTO::drawMouse() {
if (!_overlayVisible) {
scale = _videoMode.scaleFactor;
+ width = _videoMode.screenWidth;
+ height = _videoMode.screenHeight;
dst.w = _mouseCurState.vW;
dst.h = _mouseCurState.vH;
hotX = _mouseCurState.vHotX;
hotY = _mouseCurState.vHotY;
} else {
scale = 1;
+ width = _videoMode.overlayWidth;
+ height = _videoMode.overlayHeight;
dst.w = _mouseCurState.rW;
dst.h = _mouseCurState.rH;
hotX = _mouseCurState.rHotX;
diff --git a/backends/platform/ps2/Makefile.ps2 b/backends/platform/ps2/Makefile.ps2
index d2a8d210e4..f836bd3eaa 100644
--- a/backends/platform/ps2/Makefile.ps2
+++ b/backends/platform/ps2/Makefile.ps2
@@ -1,22 +1,45 @@
# $Header: Exp $
include $(PS2SDK)/Defs.make
-PS2_EXTRA = /works/devel/ps2/sdk-extra
+PS2_EXTRA = /home/tony/GSOC/ps2/sdk-extra
PS2_EXTRA_INCS = /zlib/include /libmad/ee/include /SjPcm/ee/src /tremor
PS2_EXTRA_LIBS = /zlib/lib /libmad/ee/lib /SjPcm/ee/lib /tremor/tremor
-ENABLED=STATIC_PLUGIN
+# Set to 1 to enable, 0 to disable dynamic modules
+DYNAMIC_MODULES = 1
+# Set to 1 to enable, 0 to disable more detailed printing of gcc commands
+VERBOSE_BUILD=0
+
+# Test for dynamic plugins
+ifeq ($(DYNAMIC_MODULES),1)
+ENABLED = DYNAMIC_PLUGIN
+DEFINES = -DDYNAMIC_MODULES
+PRE_OBJS_FLAGS = -Wl,--whole-archive
+POST_OBJS_FLAGS = -Wl,--no-whole-archive
+else
+ENABLED = STATIC_PLUGIN
+endif
+
+#control build
+DISABLE_SCALERS = true
+DISABLE_HQ_SCALERS = true
ENABLE_SCUMM = $(ENABLED)
ENABLE_SCUMM_7_8 = $(ENABLED)
ENABLE_HE = $(ENABLED)
ENABLE_AGI = $(ENABLED)
ENABLE_AGOS = $(ENABLED)
+ENABLE_AGOS2 = $(ENABLED)
ENABLE_CINE = $(ENABLED)
ENABLE_CRUISE = $(ENABLED)
+ENABLE_DRACI = $(ENABLED)
ENABLE_DRASCULA = $(ENABLED)
ENABLE_GOB = $(ENABLED)
+ENABLE_GROOVIE = $(ENABLED)
+# ENABLE_GROOVIE2 = $(ENABLED)
+ENABLE_IHNM = $(ENABLED)
ENABLE_KYRA = $(ENABLED)
+# ENABLE_LOL = $(ENABLED)
ENABLE_LURE = $(ENABLED)
# ENABLE_M4 = $(ENABLED)
ENABLE_MADE = $(ENABLED)
@@ -24,16 +47,18 @@ ENABLE_PARALLACTION = $(ENABLED)
ENABLE_QUEEN = $(ENABLED)
ENABLE_SAGA = $(ENABLED)
ENABLE_SAGA2 = $(ENABLED)
-ENABLE_IHNM = $(ENABLED)
+ENABLE_SCI = $(ENABLED)
+# ENABLE_SCI32 = $(ENABLED)
ENABLE_SKY = $(ENABLED)
ENABLE_SWORD1 = $(ENABLED)
ENABLE_SWORD2 = $(ENABLED)
-# ENABLE_TINSEL = $(ENABLED)
+ENABLE_TEENAGENT = $(ENABLED)
+ENABLE_TINSEL = $(ENABLED)
ENABLE_TOUCHE = $(ENABLED)
+ENABLE_TUCKER = $(ENABLED)
HAVE_GCC3 = true
-
-CC = ee-gcc
+CC = ee-gcc
CXX = ee-g++
AS = ee-gcc
LD = ee-gcc
@@ -42,51 +67,62 @@ RANLIB = ee-ranlib
STRIP = ee-strip
MKDIR = mkdir -p
RM = rm -f
+RM_REC = rm -rf
+MODULE_DIRS = ./
srcdir = ../../..
VPATH = $(srcdir)
INCDIR = ../../../
-# DEPDIR = .deps
+DEPDIR = .deps
-DEFINES = -DUSE_VORBIS -DUSE_TREMOR -DUSE_MAD -DUSE_ZLIB -DFORCE_RTL -D_EE -D__PLAYSTATION2__ -O2 -Wall -Wno-multichar
+TARGET = elf/scummvm.elf
+DEFINES += -DUSE_VORBIS -DUSE_TREMOR -DUSE_MAD -DUSE_ZLIB -DFORCE_RTL -DDISABLE_SAVEGAME_SORTING -D_EE -D__PLAYSTATION2__ -G2 -O2 -Wall -Wno-multichar -fno-rtti -fno-exceptions -DNO_ADAPTOR
+DEFINES += -DELF_LOADER_TARGET -DMIPS_TARGET#-DNEW_PLUGIN_DESIGN_FIRST_REFINEMENT
INCLUDES = $(addprefix -I$(PS2_EXTRA),$(PS2_EXTRA_INCS))
INCLUDES += -I $(PS2SDK)/ee/include -I $(PS2SDK)/common/include -I ./common -I . -I $(srcdir) -I $(srcdir)/engines
-TARGET = elf/scummvm.elf
+CXX_UPDATE_DEP_FLAG = -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP
+
+# Variables for dynamic plugin building
+PLUGIN_PREFIX =
+PLUGIN_SUFFIX = .plg
+PLUGIN_EXTRA_DEPS = $(srcdir)/backends/plugins/plugin.syms elf/scummvm.elf
+PLUGIN_LDFLAGS += -mno-crt0 $(PS2SDK)/ee/startup/crt0.o
+PLUGIN_LDFLAGS += -nostartfiles -Wl,-q,--just-symbols,elf/scummvm.elf,-T$(srcdir)/backends/plugins/ps2/plugin.ld,--retain-symbols-file,$(srcdir)/backends/plugins/plugin.syms -lstdc++ -lc
-OBJS := backends/platform/ps2/DmaPipe.o \
- backends/platform/ps2/Gs2dScreen.o \
- backends/platform/ps2/irxboot.o \
- backends/platform/ps2/ps2input.o \
- backends/platform/ps2/ps2pad.o \
- backends/platform/ps2/savefilemgr.o \
- backends/platform/ps2/fileio.o \
- backends/platform/ps2/asyncfio.o \
- backends/platform/ps2/icon.o \
- backends/platform/ps2/cd.o \
- backends/platform/ps2/eecodyvdfs.o \
- backends/platform/ps2/rpckbd.o \
- backends/platform/ps2/systemps2.o \
- backends/platform/ps2/ps2mutex.o \
- backends/platform/ps2/ps2time.o \
- backends/platform/ps2/ps2debug.o
-
-MODULE_DIRS += .
BACKEND := ps2
include $(srcdir)/Makefile.common
-LDFLAGS += -mno-crt0 $(PS2SDK)/ee/startup/crt0.o -T $(PS2SDK)/ee/startup/linkfile
+LDFLAGS = -mno-crt0 $(PS2SDK)/ee/startup/crt0.o -T $(srcdir)/backends/plugins/ps2/main_prog.ld
LDFLAGS += -L $(PS2SDK)/ee/lib -L .
-LDFLAGS += $(addprefix -L$(PS2_EXTRA),$(PS2_EXTRA_LIBS))
+LDFLAGS += $(addprefix -L$(PS2_EXTRA),$(PS2_EXTRA_LIBS))
LDFLAGS += -lmc -lpad -lmouse -lhdd -lpoweroff -lsjpcm -lmad -ltremor -lz -lm -lc -lfileXio -lkernel -lstdc++
-LDFLAGS += -s
+
+OBJS := $(srcdir)/backends/platform/ps2/DmaPipe.o \
+ $(srcdir)/backends/platform/ps2/Gs2dScreen.o \
+ $(srcdir)/backends/platform/ps2/irxboot.o \
+ $(srcdir)/backends/platform/ps2/ps2input.o \
+ $(srcdir)/backends/platform/ps2/ps2pad.o \
+ $(srcdir)/backends/platform/ps2/savefilemgr.o \
+ $(srcdir)/backends/platform/ps2/fileio.o \
+ $(srcdir)/backends/platform/ps2/asyncfio.o \
+ $(srcdir)/backends/platform/ps2/icon.o \
+ $(srcdir)/backends/platform/ps2/cd.o \
+ $(srcdir)/backends/platform/ps2/eecodyvdfs.o \
+ $(srcdir)/backends/platform/ps2/rpckbd.o \
+ $(srcdir)/backends/platform/ps2/systemps2.o \
+ $(srcdir)/backends/platform/ps2/ps2mutex.o \
+ $(srcdir)/backends/platform/ps2/ps2time.o \
+ $(srcdir)/backends/platform/ps2/ps2debug.o
+
+include $(srcdir)/Makefile.common
all: $(TARGET)
$(TARGET): $(OBJS)
- $(LD) $^ $(LDFLAGS) -o $@
+ $(LD) $(PRE_OBJS_FLAGS) $(OBJS) $(POST_OBJS_FLAGS) $(LDFLAGS) -o $@
diff --git a/backends/platform/ps2/elf32.h b/backends/platform/ps2/elf32.h
new file mode 100644
index 0000000000..616cc4b4d2
--- /dev/null
+++ b/backends/platform/ps2/elf32.h
@@ -0,0 +1,209 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef BACKENDS_ELF_H
+#define BACKENDS_ELF_H
+
+/* ELF stuff */
+
+typedef unsigned short Elf32_Half, Elf32_Section;
+typedef unsigned int Elf32_Word, Elf32_Addr, Elf32_Off;
+typedef signed int Elf32_Sword;
+typedef Elf32_Half Elf32_Versym;
+
+#define EI_NIDENT (16)
+#define SELFMAG 6
+
+/* ELF File format structures. Look up ELF structure for more details */
+
+// ELF header (contains info about the file)
+typedef struct {
+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+ Elf32_Half e_type; /* Object file type */
+ Elf32_Half e_machine; /* Architecture */
+ Elf32_Word e_version; /* Object file version */
+ Elf32_Addr e_entry; /* Entry point virtual address */
+ Elf32_Off e_phoff; /* Program header table file offset */
+ Elf32_Off e_shoff; /* Section header table file offset */
+ Elf32_Word e_flags; /* Processor-specific flags */
+ Elf32_Half e_ehsize; /* ELF header size in bytes */
+ Elf32_Half e_phentsize; /* Program header table entry size */
+ Elf32_Half e_phnum; /* Program header table entry count */
+ Elf32_Half e_shentsize; /* Section header table entry size */
+ Elf32_Half e_shnum; /* Section header table entry count */
+ Elf32_Half e_shstrndx; /* Section header string table index */
+} Elf32_Ehdr;
+
+// Should be in e_ident
+#define ELFMAG "\177ELF\1\1" /* ELF Magic number */
+
+// e_type values
+#define ET_NONE 0 /* no file type */
+#define ET_REL 1 /* relocatable */
+#define ET_EXEC 2 /* executable */
+#define ET_DYN 3 /* shared object */
+#define ET_CORE 4 /* core file */
+
+// e_machine values
+#define EM_MIPS 8
+
+
+// Program header (contains info about segment)
+typedef struct {
+ Elf32_Word p_type; /* Segment type */
+ Elf32_Off p_offset; /* Segment file offset */
+ Elf32_Addr p_vaddr; /* Segment virtual address */
+ Elf32_Addr p_paddr; /* Segment physical address */
+ Elf32_Word p_filesz; /* Segment size in file */
+ Elf32_Word p_memsz; /* Segment size in memory */
+ Elf32_Word p_flags; /* Segment flags */
+ Elf32_Word p_align; /* Segment alignment */
+} Elf32_Phdr;
+
+// p_type values
+#define PT_NULL 0 /* ignored */
+#define PT_LOAD 1 /* loadable segment */
+#define PT_DYNAMIC 2 /* dynamic linking info */
+#define PT_INTERP 3 /* info about interpreter */
+#define PT_NOTE 4 /* note segment */
+#define PT_SHLIB 5 /* reserved */
+#define PT_PHDR 6 /* Program header table */
+#define PT_MIPS_REGINFO 0x70000000 /* register usage info */
+
+// p_flags value
+#define PF_X 1 /* execute */
+#define PF_W 2 /* write */
+#define PF_R 4 /* read */
+
+// Section header (contains info about section)
+typedef struct {
+ Elf32_Word sh_name; /* Section name (string tbl index) */
+ Elf32_Word sh_type; /* Section type */
+ Elf32_Word sh_flags; /* Section flags */
+ Elf32_Addr sh_addr; /* Section virtual addr at execution */
+ Elf32_Off sh_offset; /* Section file offset */
+ Elf32_Word sh_size; /* Section size in bytes */
+ Elf32_Word sh_link; /* Link to another section */
+ Elf32_Word sh_info; /* Additional section information */
+ Elf32_Word sh_addralign; /* Section alignment */
+ Elf32_Word sh_entsize; /* Entry size if section holds table */
+} Elf32_Shdr;
+
+// sh_type values
+#define SHT_NULL 0 /* Inactive section */
+#define SHT_PROGBITS 1 /* Proprietary */
+#define SHT_SYMTAB 2 /* Symbol table */
+#define SHT_STRTAB 3 /* String table */
+#define SHT_RELA 4 /* Relocation entries with addend */
+#define SHT_HASH 5 /* Symbol hash table */
+#define SHT_DYNAMIC 6 /* Info for dynamic linking */
+#define SHT_NOTE 7 /* Note section */
+#define SHT_NOBITS 8 /* Occupies no space */
+#define SHT_REL 9 /* Relocation entries without addend */
+#define SHT_SHLIB 10 /* Reserved */
+#define SHT_DYNSYM 11 /* Minimal set of dynamic linking symbols */
+#define SHT_MIPS_LIBLSIT 0x70000000 /* Info about dynamic shared object libs */
+#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicts btw executables and shared objects */
+#define SHT_MIPS_GPTAB 0x70000003 /* Global pointer table */
+
+// sh_flags values
+#define SHF_WRITE 0 /* writable section */
+#define SHF_ALLOC 2 /* section occupies memory */
+#define SHF_EXECINSTR 4 /* machine instructions */
+#define SHF_MIPS_GPREL 0x10000000 /* Must be made part of global data area */
+
+
+// Symbol entry (contain info about a symbol)
+typedef struct {
+ Elf32_Word st_name; /* Symbol name (string tbl index) */
+ Elf32_Addr st_value; /* Symbol value */
+ Elf32_Word st_size; /* Symbol size */
+ unsigned char st_info; /* Symbol type and binding */
+ unsigned char st_other; /* Symbol visibility */
+ Elf32_Section st_shndx; /* Section index */
+} Elf32_Sym;
+
+// Extract from the st_info
+#define SYM_TYPE(x) ((x)&0xF)
+#define SYM_BIND(x) ((x)>>4)
+
+
+// Symbol binding values from st_info
+#define STB_LOCAL 0 /* Symbol not visible outside object */
+#define STB_GLOBAL 1 /* Symbol visible to all object files */
+#define STB_WEAK 2 /* Similar to STB_GLOBAL */
+
+// Symbol type values from st_info
+#define STT_NOTYPE 0 /* Not specified */
+#define STT_OBJECT 1 /* Data object e.g. variable */
+#define STT_FUNC 2 /* Function */
+#define STT_SECTION 3 /* Section */
+#define STT_FILE 4 /* Source file associated with object file */
+
+// Special section header index values from st_shndex
+#define SHN_UNDEF 0
+#define SHN_LOPROC 0xFF00 /* Extended values */
+#define SHN_ABS 0xFFF1 /* Absolute value: don't relocate */
+#define SHN_COMMON 0xFFF2 /* Common block. Not allocated yet */
+#define SHN_HIPROC 0xFF1F
+#define SHN_HIRESERVE 0xFFFF
+
+// Relocation entry (info about how to relocate)
+typedef struct {
+ Elf32_Addr r_offset; /* Address */
+ Elf32_Word r_info; /* Relocation type and symbol index */
+} Elf32_Rel;
+
+// Access macros for the relocation info
+#define REL_TYPE(x) ((x)&0xFF) /* Extract relocation type */
+#define REL_INDEX(x) ((x)>>8) /* Extract relocation index into symbol table */
+
+// MIPS relocation types
+#define R_MIPS_NONE 0
+#define R_MIPS_16 1
+#define R_MIPS_32 2
+#define R_MIPS_REL32 3
+#define R_MIPS_26 4
+#define R_MIPS_HI16 5
+#define R_MIPS_LO16 6
+#define R_MIPS_GPREL16 7
+#define R_MIPS_LITERAL 8
+#define R_MIPS_GOT16 9
+#define R_MIPS_PC16 10
+#define R_MIPS_CALL16 11
+#define R_MIPS_GPREL32 12
+#define R_MIPS_GOTHI16 13
+#define R_MIPS_GOTLO16 14
+#define R_MIPS_CALLHI16 15
+#define R_MIPS_CALLLO16 16
+
+// Mock function to get value of global pointer
+#define getGP() ({ \
+ unsigned int __valgp; \
+ __asm__ ("add %0, $gp, $0" : "=r"(__valgp) : ); \
+ __valgp; \
+})
+
+#endif /* BACKENDS_ELF_H */
diff --git a/backends/platform/ps2/module.mk b/backends/platform/ps2/module.mk
index bf95a5501d..a12d10771f 100644
--- a/backends/platform/ps2/module.mk
+++ b/backends/platform/ps2/module.mk
@@ -16,7 +16,8 @@ MODULE_OBJS := \
systemps2.o \
ps2mutex.o \
ps2time.o \
- ps2debug.o
+ ps2debug.o \
+ ps2loader.o
# We don't use rules.mk but rather manually update OBJS and MODULE_DIRS.
MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS))
diff --git a/backends/platform/ps2/systemps2.cpp b/backends/platform/ps2/systemps2.cpp
index 7659d5194d..357404c5c4 100644
--- a/backends/platform/ps2/systemps2.cpp
+++ b/backends/platform/ps2/systemps2.cpp
@@ -59,6 +59,8 @@
#include "backends/platform/ps2/ps2debug.h"
#include "backends/fs/ps2/ps2-fs-factory.h"
+#include "backends/plugins/ps2/ps2-provider.h"
+
#include "backends/saves/default/default-saves.h"
#include "common/config-manager.h"
@@ -105,7 +107,6 @@ extern "C" int scummvm_main(int argc, char *argv[]);
extern "C" int main(int argc, char *argv[]) {
SifInitRpc(0);
-
ee_thread_t thisThread;
int tid = GetThreadId();
ReferThreadStatus(tid, &thisThread);
@@ -130,8 +131,11 @@ extern "C" int main(int argc, char *argv[]) {
sioprintf("Creating system\n");
g_system = g_systemPs2 = new OSystem_PS2(argv[0]);
- g_systemPs2->init();
+#ifdef DYNAMIC_MODULES
+ PluginManager::instance().addPluginProvider(new PS2PluginProvider());
+#endif
+ g_systemPs2->init();
sioprintf("init done. starting ScummVM.\n");
int res = scummvm_main(argc, argv);
sioprintf("scummvm_main terminated: %d\n", res);
@@ -337,6 +341,7 @@ OSystem_PS2::OSystem_PS2(const char *elfPath) {
}
void OSystem_PS2::init(void) {
+ //msgPrintf(FOREVER, "got to init! Now restart your console... %d\n", res);
sioprintf("Timer...\n");
_scummTimerManager = new DefaultTimerManager();
_scummMixer = new Audio::MixerImpl(this, 48000);
diff --git a/backends/platform/psp/Makefile b/backends/platform/psp/Makefile
index 617ef7c8cc..9c011220b8 100644
--- a/backends/platform/psp/Makefile
+++ b/backends/platform/psp/Makefile
@@ -67,7 +67,7 @@ endif
# Variables for common Scummvm makefile
CXX = psp-g++
CXXFLAGS = -O3 -Wall -Wno-multichar -fno-exceptions -fno-rtti
-DEFINES = -D__PSP__ -DNONSTANDARD_PORT -DDISABLE_TEXT_CONSOLE -DDISABLE_COMMAND_LINE -DUSE_ZLIB -DDISABLE_DOSBOX_OPL -DUSE_RGB_COLOR
+DEFINES = -D__PSP__ -DNONSTANDARD_PORT -DDISABLE_TEXT_CONSOLE -DDISABLE_COMMAND_LINE -DUSE_ZLIB -DDISABLE_DOSBOX_OPL -DUSE_RGB_COLOR -DELF_LOADER_TARGET -DMIPS_TARGET
LDFLAGS :=
INCDIR := $(srcdir) . $(srcdir)/engines/ $(PSPSDK)/include
@@ -87,8 +87,8 @@ CXX_UPDATE_DEP_FLAG = -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP
# Variables for dynamic plugin building
PLUGIN_PREFIX =
PLUGIN_SUFFIX = .plg
-PLUGIN_EXTRA_DEPS = plugin.syms scummvm-psp.elf
-PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,--just-symbols=scummvm-psp.org.elf,-Tplugin.ld,--retain-symbols-file,plugin.syms -lstdc++ -lc
+PLUGIN_EXTRA_DEPS = $(srcdir)/backends/plugins/plugin.syms scummvm-psp.elf
+PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,--just-symbols=scummvm-psp.org.elf,-T$(srcdir)/backends/plugins/psp/plugin.ld,--retain-symbols-file,$(srcdir)/backends/plugins/plugin.syms -lstdc++ -lc
# PSP-specific variables
STRIP = psp-strip
@@ -125,8 +125,7 @@ endif
# PSP LIBS
PSPLIBS = -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk \
- -lpsputility -lpspuser -lpsppower -lpsphprm -lpspsdk -lpsprtc -lpspaudio -lpspaudiocodec \
- -lpspkernel
+ -lpsputility -lpspuser -lpsppower -lpsphprm -lpspsdk -lpsprtc -lpspaudio -lpspkernel
# Add in PSPSDK includes and libraries.
LIBS += -lpng -lz -lstdc++ -lc -lm $(PSPLIBS)
@@ -150,6 +149,7 @@ OBJS := powerman.o \
mp3.o \
tests.o
+
BACKEND := psp
# Include common Scummvm makefile
diff --git a/backends/platform/psp/audio.cpp b/backends/platform/psp/audio.cpp
index e540733162..14691befee 100644
--- a/backends/platform/psp/audio.cpp
+++ b/backends/platform/psp/audio.cpp
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
- * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $
+ * $URL$
+ * $Id$
*
*/
diff --git a/backends/platform/psp/audio.h b/backends/platform/psp/audio.h
index eeba598fed..07f70cec7d 100644
--- a/backends/platform/psp/audio.h
+++ b/backends/platform/psp/audio.h
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
- * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $
+ * $URL$
+ * $Id$
*
*/
diff --git a/backends/platform/psp/cursor.cpp b/backends/platform/psp/cursor.cpp
index ae3b8f0050..cf879e095a 100644
--- a/backends/platform/psp/cursor.cpp
+++ b/backends/platform/psp/cursor.cpp
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.h $
- * $Id: osys_psp.h 46120 2009-11-24 10:33:30Z Bluddy $
+ * $URL$
+ * $Id$
*
*/
diff --git a/backends/platform/psp/default_display_client.h b/backends/platform/psp/default_display_client.h
index 716e6fcc35..2e33632eb1 100644
--- a/backends/platform/psp/default_display_client.h
+++ b/backends/platform/psp/default_display_client.h
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/trace.h $
- * $Id: trace.h 44276 2009-09-23 16:11:23Z joostp $
+ * $URL$
+ * $Id$
*
*/
diff --git a/backends/platform/psp/display_client.cpp b/backends/platform/psp/display_client.cpp
index 71b505ec7c..6360772c96 100644
--- a/backends/platform/psp/display_client.cpp
+++ b/backends/platform/psp/display_client.cpp
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
- * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $
+ * $URL$
+ * $Id$
*
*/
diff --git a/backends/platform/psp/display_manager.cpp b/backends/platform/psp/display_manager.cpp
index 5037543f12..544e5a1b25 100644
--- a/backends/platform/psp/display_manager.cpp
+++ b/backends/platform/psp/display_manager.cpp
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
- * $Id: osys_psp.cpp 47541 2010-01-25 01:39:44Z lordhoto $
+ * $URL$
+ * $Id$
*
*/
diff --git a/backends/platform/psp/display_manager.h b/backends/platform/psp/display_manager.h
index 1f7320902c..72f252faae 100644
--- a/backends/platform/psp/display_manager.h
+++ b/backends/platform/psp/display_manager.h
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
- * $Id: osys_psp.cpp 47541 2010-01-25 01:39:44Z lordhoto $
+ * $URL$
+ * $Id$
*
*/
diff --git a/backends/platform/psp/input.cpp b/backends/platform/psp/input.cpp
index 4fe7cb3f92..2a91ce455a 100644
--- a/backends/platform/psp/input.cpp
+++ b/backends/platform/psp/input.cpp
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
- * $Id: osys_psp.cpp 43618 2009-08-21 22:44:49Z joostp $
+ * $URL$
+ * $Id$
*
*/
diff --git a/backends/platform/psp/psploader.cpp b/backends/platform/psp/psploader.cpp
deleted file mode 100644
index 464e20770c..0000000000
--- a/backends/platform/psp/psploader.cpp
+++ /dev/null
@@ -1,732 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#if defined(DYNAMIC_MODULES) && defined(__PSP__)
-
-#include <string.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <malloc.h>
-#include <unistd.h>
-#include <sys/_default_fcntl.h>
-
-#include <psputils.h>
-
-#include "backends/platform/psp/psploader.h"
-#include "backends/platform/psp/powerman.h"
-
-//#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */
-//#define __PSP_DEBUG_PRINT__
-
-#include "backends/platform/psp/trace.h"
-
-extern char __plugin_hole_start; // Indicates start of hole in program file for shorts
-extern char __plugin_hole_end; // Indicates end of hole in program file
-extern char _gp[]; // Value of gp register
-
-DECLARE_SINGLETON(ShortSegmentManager) // For singleton
-
-// Get rid of symbol table in memory
-void DLObject::discard_symtab() {
- DEBUG_ENTER_FUNC();
- free(_symtab);
- free(_strtab);
- _symtab = NULL;
- _strtab = NULL;
- _symbol_cnt = 0;
-}
-
-// Unload all objects from memory
-void DLObject::unload() {
- DEBUG_ENTER_FUNC();
- discard_symtab();
- free(_segment);
- _segment = NULL;
-
- if (_shortsSegment) {
- ShortsMan.deleteSegment(_shortsSegment);
- _shortsSegment = NULL;
- }
-}
-
-/**
- * Follow the instruction of a relocation section.
- *
- * @param fd File Descriptor
- * @param offset Offset into the File
- * @param size Size of relocation section
- * @param relSegment Base address of relocated segment in memory (memory offset)
- *
- */
-bool DLObject::relocate(int fd, unsigned long offset, unsigned long size, void *relSegment) {
- DEBUG_ENTER_FUNC();
- Elf32_Rel *rel = NULL; // relocation entry
-
- // Allocate memory for relocation table
- if (!(rel = (Elf32_Rel *)malloc(size))) {
- PSP_ERROR("Out of memory.");
- return false;
- }
-
- // Read in our relocation table
- if (lseek(fd, offset, SEEK_SET) < 0 ||
- read(fd, rel, size) != (ssize_t)size) {
- PSP_ERROR("Relocation table load failed.");
- free(rel);
- return false;
- }
-
- // Treat each relocation entry. Loop over all of them
- int cnt = size / sizeof(*rel);
-
- PSP_DEBUG_PRINT("Loaded relocation table. %d entries. base address=%p\n", cnt, relSegment);
-
- bool seenHi16 = false; // For treating HI/LO16 commands
- int firstHi16 = -1; // Mark the point of the first hi16 seen
- Elf32_Addr ahl = 0; // Calculated addend
- int a = 0; // Addend: taken from the target
-
- unsigned int *lastTarget = 0; // For processing hi16 when lo16 arrives
- unsigned int relocation = 0;
- int debugRelocs[10] = {0}; // For debugging
- int extendedHi16 = 0; // Count extended hi16 treatments
- Elf32_Addr lastHiSymVal = 0;
- bool hi16InShorts = false;
-
-#define DEBUG_NUM 2
-
- // Loop over relocation entries
- for (int i = 0; i < cnt; i++) {
- // Get the symbol this relocation entry is referring to
- Elf32_Sym *sym = (Elf32_Sym *)(_symtab) + (REL_INDEX(rel[i].r_info));
-
- // Get the target instruction in the code
- unsigned int *target = (unsigned int *)((char *)relSegment + rel[i].r_offset);
-
- PSP_DEBUG_DO(unsigned int origTarget = *target); // Save for debugging
-
- // Act differently based on the type of relocation
- switch (REL_TYPE(rel[i].r_info)) {
-
- case R_MIPS_HI16: // Absolute addressing.
- if (sym->st_shndx < SHN_LOPROC && // Only shift for plugin section (ie. has a real section index)
- firstHi16 < 0) { // Only process first in block of HI16s
- firstHi16 = i; // Keep the first Hi16 we saw
- seenHi16 = true;
- ahl = (*target & 0xffff) << 16; // Take lower 16 bits shifted up
-
- lastHiSymVal = sym->st_value;
- hi16InShorts = (ShortsMan.inGeneralSegment((char *)sym->st_value)); // Fix for problem with switching btw segments
- if (debugRelocs[0]++ < DEBUG_NUM) // Print only a set number
- PSP_DEBUG_PRINT("R_MIPS_HI16: i=%d, offset=%x, ahl = %x, target = %x\n",
- i, rel[i].r_offset, ahl, *target);
- }
- break;
-
- case R_MIPS_LO16: // Absolute addressing. Needs a HI16 to come before it
- if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section. (ie. has a real section index)
- if (!seenHi16) { // We MUST have seen HI16 first
- PSP_ERROR("R_MIPS_LO16 w/o preceding R_MIPS_HI16 at relocation %d!\n", i);
- free(rel);
- return false;
- }
-
- // Fix: bug in gcc makes LO16s connect to wrong HI16s sometimes (shorts and regular segment)
- // Note that we can check the entire shorts segment because the executable's shorts don't belong to this plugin section
- // and will be screened out above
- bool lo16InShorts = ShortsMan.inGeneralSegment((char *)sym->st_value);
-
- // Correct the bug by getting the proper value in ahl (taken from the current symbol)
- if ((hi16InShorts && !lo16InShorts) || (!hi16InShorts && lo16InShorts)) {
- ahl -= (lastHiSymVal & 0xffff0000); // We assume gcc meant the same offset
- ahl += (sym->st_value & 0xffff0000);
- }
-
- ahl &= 0xffff0000; // Clean lower 16 bits for repeated LO16s
- a = *target & 0xffff; // Take lower 16 bits of the target
- a = (a << 16) >> 16; // Sign extend them
- ahl += a; // Add lower 16 bits. AHL is now complete
-
- // Fix: we can have LO16 access to the short segment sometimes
- if (lo16InShorts) {
- relocation = ahl + _shortsSegment->getOffset(); // Add in the short segment offset
- } else // It's in the regular segment
- relocation = ahl + (Elf32_Addr)_segment; // Add in the new offset for the segment
-
- if (firstHi16 >= 0) { // We haven't treated the HI16s yet so do it now
- for (int j = firstHi16; j < i; j++) {
- if (REL_TYPE(rel[j].r_info) != R_MIPS_HI16) continue; // Skip over non-Hi16s
-
- lastTarget = (unsigned int *)((char *)relSegment + rel[j].r_offset); // get hi16 target
- *lastTarget &= 0xffff0000; // Clear the lower 16 bits of the last target
- *lastTarget |= (relocation >> 16) & 0xffff; // Take the upper 16 bits of the relocation
- if (relocation & 0x8000)(*lastTarget)++; // Subtle: we need to add 1 to the HI16 in this case
- }
- firstHi16 = -1; // Reset so we'll know we treated it
- } else {
- extendedHi16++;
- }
-
- *target &= 0xffff0000; // Clear the lower 16 bits of current target
- *target |= relocation & 0xffff; // Take the lower 16 bits of the relocation
-
- if (debugRelocs[1]++ < DEBUG_NUM)
- PSP_DEBUG_PRINT("R_MIPS_LO16: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x\n",
- i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target);
- if (lo16InShorts && debugRelocs[2]++ < DEBUG_NUM)
- PSP_DEBUG_PRINT("R_MIPS_LO16s: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x\n",
- i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target);
- }
- break;
-
- case R_MIPS_26: // Absolute addressing (for jumps and branches only)
- if (sym->st_shndx < SHN_LOPROC) { // Only relocate for main segment
- a = *target & 0x03ffffff; // Get 26 bits' worth of the addend
- a = (a << 6) >> 6; // Sign extend a
- relocation = ((a << 2) + (Elf32_Addr)_segment) >> 2; // a already points to the target. Subtract our offset
- *target &= 0xfc000000; // Clean lower 26 target bits
- *target |= (relocation & 0x03ffffff);
-
- if (debugRelocs[3]++ < DEBUG_NUM)
- PSP_DEBUG_PRINT("R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x\n",
- i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target);
- } else {
- if (debugRelocs[4]++ < DEBUG_NUM)
- PSP_DEBUG_PRINT("R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x\n",
- i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target);
- }
- break;
-
- case R_MIPS_GPREL16: // GP Relative addressing
- if (_shortsSegment->getOffset() != 0 && // Only relocate if we shift the shorts section
- ShortsMan.inGeneralSegment((char *)sym->st_value)) { // Only relocate things in the plugin hole
- a = *target & 0xffff; // Get 16 bits' worth of the addend
- a = (a << 16) >> 16; // Sign extend it
-
- relocation = a + _shortsSegment->getOffset();
-
- *target &= 0xffff0000; // Clear the lower 16 bits of the target
- *target |= relocation & 0xffff;
-
- if (debugRelocs[5]++ < DEBUG_NUM)
- PSP_DEBUG_PRINT("R_MIPS_GPREL16: i=%d, a=%x, gpVal=%x, origTarget=%x, target=%x, offset=%x\n",
- i, a, _gpVal, origTarget, *target, _shortsSegment->getOffset());
- }
-
- break;
-
- case R_MIPS_32: // Absolute addressing
- if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section.
- a = *target; // Get full 32 bits of addend
-
- if (ShortsMan.inGeneralSegment((char *)sym->st_value)) // Check if we're in the shorts segment
- relocation = a + _shortsSegment->getOffset(); // Shift by shorts offset
- else // We're in the main section
- relocation = a + (Elf32_Addr)_segment; // Shift by main offset
- *target = relocation;
-
- if (debugRelocs[6]++ < DEBUG_NUM)
- PSP_DEBUG_PRINT("R_MIPS_32: i=%d, a=%x, origTarget=%x, target=%x\n", i, a, origTarget, *target);
- }
- break;
-
- default:
- PSP_ERROR("Unknown relocation type %x at relocation %d.\n", REL_TYPE(rel[i].r_info), i);
- free(rel);
- return false;
- }
- }
-
- PSP_DEBUG_PRINT("Done with relocation. extendedHi16=%d\n\n", extendedHi16);
-
- free(rel);
- return true;
-}
-
-bool DLObject::readElfHeader(int fd, Elf32_Ehdr *ehdr) {
- DEBUG_ENTER_FUNC();
- // Start reading the elf header. Check for errors
- if (read(fd, ehdr, sizeof(*ehdr)) != sizeof(*ehdr) ||
- memcmp(ehdr->e_ident, ELFMAG, SELFMAG) || // Check MAGIC
- ehdr->e_type != ET_EXEC || // Check for executable
- ehdr->e_machine != EM_MIPS || // Check for MIPS machine type
- ehdr->e_phentsize < sizeof(Elf32_Phdr) || // Check for size of program header
- ehdr->e_shentsize != sizeof(Elf32_Shdr)) { // Check for size of section header
- PSP_ERROR("Invalid file type.");
- return false;
- }
-
- PSP_DEBUG_PRINT("phoff = %d, phentsz = %d, phnum = %d\n",
- ehdr->e_phoff, ehdr->e_phentsize, ehdr->e_phnum);
-
- return true;
-}
-
-bool DLObject::readProgramHeaders(int fd, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num) {
- DEBUG_ENTER_FUNC();
- // Read program header
- if (lseek(fd, ehdr->e_phoff + sizeof(*phdr)*num, SEEK_SET) < 0 ||
- read(fd, phdr, sizeof(*phdr)) != sizeof(*phdr)) {
- PSP_ERROR("Program header load failed.");
- return false;
- }
-
- // Check program header values
- if (phdr->p_type != PT_LOAD || phdr->p_filesz > phdr->p_memsz) {
- PSP_ERROR("Invalid program header.");
- return false;
- }
-
- PSP_DEBUG_PRINT("offs = %x, filesz = %x, memsz = %x, align = %x\n",
- phdr->p_offset, phdr->p_filesz, phdr->p_memsz, phdr->p_align);
-
- return true;
-
-}
-
-bool DLObject::loadSegment(int fd, Elf32_Phdr *phdr) {
- DEBUG_ENTER_FUNC();
-
- char *baseAddress = 0;
-
- // We need to take account of non-allocated segment for shorts
- if (phdr->p_flags & PF_X) { // This is a relocated segment
-
- // Attempt to allocate memory for segment
- int extra = phdr->p_vaddr % phdr->p_align; // Get extra length TODO: check logic here
- PSP_DEBUG_PRINT("extra mem is %x\n", extra);
-
- if (phdr->p_align < 0x10000) phdr->p_align = 0x10000; // Fix for wrong alignment on e.g. AGI
-
- if (!(_segment = (char *)memalign(phdr->p_align, phdr->p_memsz + extra))) {
- PSP_ERROR("Out of memory.\n");
- return false;
- }
- PSP_DEBUG_PRINT("allocated segment @ %p\n", _segment);
-
- // Get offset to load segment into
- baseAddress = (char *)_segment + phdr->p_vaddr;
- _segmentSize = phdr->p_memsz + extra;
- } else { // This is a shorts section.
- _shortsSegment = ShortsMan.newSegment(phdr->p_memsz, (char *)phdr->p_vaddr);
-
- baseAddress = _shortsSegment->getStart();
- PSP_DEBUG_PRINT("shorts segment @ %p to %p. Segment wants to be at %x. Offset=%x\n",
- _shortsSegment->getStart(), _shortsSegment->getEnd(), phdr->p_vaddr, _shortsSegment->getOffset());
-
- }
-
- // Set bss segment to 0 if necessary (assumes bss is at the end)
- if (phdr->p_memsz > phdr->p_filesz) {
- PSP_DEBUG_PRINT("Setting %p to %p to 0 for bss\n", baseAddress + phdr->p_filesz, baseAddress + phdr->p_memsz);
- memset(baseAddress + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz);
- }
- // Read the segment into memory
- if (lseek(fd, phdr->p_offset, SEEK_SET) < 0 ||
- read(fd, baseAddress, phdr->p_filesz) != (ssize_t)phdr->p_filesz) {
- PSP_ERROR("Segment load failed.");
- return false;
- }
-
- return true;
-}
-
-
-Elf32_Shdr * DLObject::loadSectionHeaders(int fd, Elf32_Ehdr *ehdr) {
- DEBUG_ENTER_FUNC();
-
- Elf32_Shdr *shdr = NULL;
-
- // Allocate memory for section headers
- if (!(shdr = (Elf32_Shdr *)malloc(ehdr->e_shnum * sizeof(*shdr)))) {
- PSP_ERROR("Out of memory.");
- return NULL;
- }
-
- // Read from file into section headers
- if (lseek(fd, ehdr->e_shoff, SEEK_SET) < 0 ||
- read(fd, shdr, ehdr->e_shnum * sizeof(*shdr)) !=
- (ssize_t)(ehdr->e_shnum * sizeof(*shdr))) {
- PSP_ERROR("Section headers load failed.");
- return NULL;
- }
-
- return shdr;
-}
-
-int DLObject::loadSymbolTable(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) {
- DEBUG_ENTER_FUNC();
-
- // Loop over sections, looking for symbol table linked to a string table
- for (int i = 0; i < ehdr->e_shnum; i++) {
- PSP_DEBUG_PRINT("Section %d: type = %x, size = %x, entsize = %x, link = %x\n",
- i, shdr[i].sh_type, shdr[i].sh_size, shdr[i].sh_entsize, shdr[i].sh_link);
-
- if (shdr[i].sh_type == SHT_SYMTAB &&
- shdr[i].sh_entsize == sizeof(Elf32_Sym) &&
- shdr[i].sh_link < ehdr->e_shnum &&
- shdr[shdr[i].sh_link].sh_type == SHT_STRTAB &&
- _symtab_sect < 0) {
- _symtab_sect = i;
- }
- }
-
- // Check for no symbol table
- if (_symtab_sect < 0) {
- PSP_ERROR("No symbol table.");
- return -1;
- }
-
- PSP_DEBUG_PRINT("Symbol section at section %d, size %x\n", _symtab_sect, shdr[_symtab_sect].sh_size);
-
- // Allocate memory for symbol table
- if (!(_symtab = malloc(shdr[_symtab_sect].sh_size))) {
- PSP_ERROR("Out of memory.");
- return -1;
- }
-
- // Read symbol table into memory
- if (lseek(fd, shdr[_symtab_sect].sh_offset, SEEK_SET) < 0 ||
- read(fd, _symtab, shdr[_symtab_sect].sh_size) !=
- (ssize_t)shdr[_symtab_sect].sh_size) {
- PSP_ERROR("Symbol table load failed.");
- return -1;
- }
-
- // Set number of symbols
- _symbol_cnt = shdr[_symtab_sect].sh_size / sizeof(Elf32_Sym);
- PSP_DEBUG_PRINT("Loaded %d symbols.\n", _symbol_cnt);
-
- return _symtab_sect;
-
-}
-
-bool DLObject::loadStringTable(int fd, Elf32_Shdr *shdr) {
- DEBUG_ENTER_FUNC();
-
- int string_sect = shdr[_symtab_sect].sh_link;
-
- // Allocate memory for string table
- if (!(_strtab = (char *)malloc(shdr[string_sect].sh_size))) {
- PSP_ERROR("Out of memory.");
- return false;
- }
-
- // Read string table into memory
- if (lseek(fd, shdr[string_sect].sh_offset, SEEK_SET) < 0 ||
- read(fd, _strtab, shdr[string_sect].sh_size) !=
- (ssize_t)shdr[string_sect].sh_size) {
- PSP_ERROR("Symbol table strings load failed.");
- return false;
- }
- return true;
-}
-
-void DLObject::relocateSymbols(Elf32_Addr offset, Elf32_Addr shortsOffset) {
- DEBUG_ENTER_FUNC();
-
- int shortsCount = 0, othersCount = 0;
- PSP_DEBUG_PRINT("Relocating symbols by %x. Shorts offset=%x\n", offset, shortsOffset);
-
- // Loop over symbols, add relocation offset
- Elf32_Sym *s = (Elf32_Sym *)_symtab;
- for (int c = _symbol_cnt; c--; s++) {
- // Make sure we don't relocate special valued symbols
- if (s->st_shndx < SHN_LOPROC) {
- if (!ShortsMan.inGeneralSegment((char *)s->st_value)) {
- othersCount++;
- s->st_value += offset;
- if (s->st_value < (Elf32_Addr)_segment || s->st_value > (Elf32_Addr)_segment + _segmentSize)
- PSP_ERROR("Symbol out of bounds! st_value = %x\n", s->st_value);
- } else { // shorts section
- shortsCount++;
- s->st_value += shortsOffset;
- if (!_shortsSegment->inSegment((char *)s->st_value))
- PSP_ERROR("Symbol out of bounds! st_value = %x\n", s->st_value);
- }
-
- }
-
- }
-
- PSP_DEBUG_PRINT("Relocated %d short symbols, %d others.\n", shortsCount, othersCount);
-}
-
-bool DLObject::relocateRels(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) {
- DEBUG_ENTER_FUNC();
-
- // Loop over sections, finding relocation sections
- for (int i = 0; i < ehdr->e_shnum; i++) {
-
- Elf32_Shdr *curShdr = &(shdr[i]);
- //Elf32_Shdr *linkShdr = &(shdr[curShdr->sh_info]);
-
- if (curShdr->sh_type == SHT_REL && // Check for a relocation section
- curShdr->sh_entsize == sizeof(Elf32_Rel) && // Check for proper relocation size
- (int)curShdr->sh_link == _symtab_sect && // Check that the sh_link connects to our symbol table
- curShdr->sh_info < ehdr->e_shnum && // Check that the relocated section exists
- (shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) { // Check if relocated section resides in memory
- if (!ShortsMan.inGeneralSegment((char *)shdr[curShdr->sh_info].sh_addr)) { // regular segment
- if (!relocate(fd, curShdr->sh_offset, curShdr->sh_size, _segment)) {
- return false;
- }
- } else { // In Shorts segment
- if (!relocate(fd, curShdr->sh_offset, curShdr->sh_size, (void *)_shortsSegment->getOffset())) {
- return false;
- }
- }
-
- }
- }
-
- return true;
-}
-
-
-bool DLObject::load(int fd) {
- DEBUG_ENTER_FUNC();
-
- Elf32_Ehdr ehdr; // ELF header
- Elf32_Phdr phdr; // Program header
- Elf32_Shdr *shdr; // Section header
- bool ret = true;
-
- if (readElfHeader(fd, &ehdr) == false) {
- return false;
- }
-
- for (int i = 0; i < ehdr.e_phnum; i++) { // Load our 2 segments
- PSP_DEBUG_PRINT("Loading segment %d\n", i);
-
- if (readProgramHeaders(fd, &ehdr, &phdr, i) == false)
- return false;
-
- if (!loadSegment(fd, &phdr))
- return false;
- }
-
- if ((shdr = loadSectionHeaders(fd, &ehdr)) == NULL)
- ret = false;
-
- if (ret && ((_symtab_sect = loadSymbolTable(fd, &ehdr, shdr)) < 0))
- ret = false;
-
- if (ret && (loadStringTable(fd, shdr) == false))
- ret = false;
-
- if (ret)
- relocateSymbols((Elf32_Addr)_segment, _shortsSegment->getOffset()); // Offset by our segment allocated address
-
- if (ret && (relocateRels(fd, &ehdr, shdr) == false))
- ret = false;
-
- free(shdr);
-
- return ret;
-}
-
-bool DLObject::open(const char *path) {
- DEBUG_ENTER_FUNC();
- int fd;
- void *ctors_start, *ctors_end;
-
- PSP_DEBUG_PRINT("open(\"%s\")\n", path);
-
- // Get the address of the global pointer
- _gpVal = (unsigned int) & _gp;
- PSP_DEBUG_PRINT("_gpVal is %x\n", _gpVal);
-
- PowerMan.beginCriticalSection();
-
- if ((fd = ::open(path, O_RDONLY)) < 0) {
- PSP_ERROR("%s not found.", path);
- return false;
- }
-
- // Try to load and relocate
- if (!load(fd)) {
- ::close(fd);
- unload();
- return false;
- }
-
- ::close(fd);
-
- PowerMan.endCriticalSection();
-
- // flush data cache
- sceKernelDcacheWritebackAll();
-
- // Get the symbols for the global constructors and destructors
- ctors_start = symbol("___plugin_ctors");
- ctors_end = symbol("___plugin_ctors_end");
- _dtors_start = symbol("___plugin_dtors");
- _dtors_end = symbol("___plugin_dtors_end");
-
- if (ctors_start == NULL || ctors_end == NULL || _dtors_start == NULL ||
- _dtors_end == NULL) {
- PSP_ERROR("Missing ctors/dtors.");
- _dtors_start = _dtors_end = NULL;
- unload();
- return false;
- }
-
- PSP_DEBUG_PRINT("Calling constructors.\n");
- for (void (**f)(void) = (void (**)(void))ctors_start; f != ctors_end; f++)
- (**f)();
-
- PSP_DEBUG_PRINT("%s opened ok.\n", path);
- return true;
-}
-
-bool DLObject::close() {
- DEBUG_ENTER_FUNC();
- if (_dtors_start != NULL && _dtors_end != NULL)
- for (void (**f)(void) = (void (**)(void))_dtors_start; f != _dtors_end; f++)
- (**f)();
- _dtors_start = _dtors_end = NULL;
- unload();
- return true;
-}
-
-void *DLObject::symbol(const char *name) {
- DEBUG_ENTER_FUNC();
- PSP_DEBUG_PRINT("symbol(\"%s\")\n", name);
-
- if (_symtab == NULL || _strtab == NULL || _symbol_cnt < 1) {
- PSP_ERROR("No symbol table loaded.");
- return NULL;
- }
-
- Elf32_Sym *s = (Elf32_Sym *)_symtab;
- for (int c = _symbol_cnt; c--; s++) {
-
- // We can only import symbols that are global or weak in the plugin
- if ((SYM_BIND(s->st_info) == STB_GLOBAL || SYM_BIND(s->st_info) == STB_WEAK) &&
- /*_strtab[s->st_name] == '_' && */ // Try to make this more efficient
- !strcmp(name, _strtab + s->st_name)) {
-
- // We found the symbol
- PSP_DEBUG_PRINT("=> %p\n", (void*)s->st_value);
- return (void*)s->st_value;
- }
- }
-
- PSP_ERROR("Symbol \"%s\" not found.", name);
- return NULL;
-}
-
-
-
-ShortSegmentManager::ShortSegmentManager() {
- DEBUG_ENTER_FUNC();
- _shortsStart = &__plugin_hole_start ;
- _shortsEnd = &__plugin_hole_end;
-}
-
-ShortSegmentManager::Segment *ShortSegmentManager::newSegment(int size, char *origAddr) {
- DEBUG_ENTER_FUNC();
- char *lastAddress = origAddr;
- Common::List<Segment *>::iterator i;
-
- // Find a block that fits, starting from the beginning
- for (i = _list.begin(); i != _list.end(); ++i) {
- char *currAddress = (*i)->getStart();
-
- if ((int)(currAddress - lastAddress) >= size) break;
-
- lastAddress = (*i)->getEnd();
- }
-
- if ((Elf32_Addr)lastAddress & 3)
- lastAddress += 4 - ((Elf32_Addr)lastAddress & 3); // Round up to multiple of 4
-
- if (lastAddress + size > _shortsEnd) {
- PSP_ERROR("No space in shorts segment for %x bytes. Last address is %p, max address is %p.\n",
- size, lastAddress, _shortsEnd);
- return NULL;
- }
-
- Segment *seg = new Segment(lastAddress, size, origAddr); // Create a new segment
-
- if (lastAddress + size > _highestAddress) _highestAddress = lastAddress + size; // Keep track of maximum
-
- _list.insert(i, seg);
-
- PSP_DEBUG_PRINT("Shorts segment size %x allocated. End = %p. Remaining space = %x. Highest so far is %p.\n",
- size, lastAddress + size, _shortsEnd - _list.back()->getEnd(), _highestAddress);
-
- return seg;
-}
-
-void ShortSegmentManager::deleteSegment(ShortSegmentManager::Segment *seg) {
- DEBUG_ENTER_FUNC();
- PSP_DEBUG_PRINT("Deleting shorts segment from %p to %p.\n\n", seg->getStart(), seg->getEnd());
- _list.remove(seg);
- delete seg;
-}
-
-static char dlerr[MAXDLERRLEN];
-
-void *dlopen(const char *filename, int flags) {
- DLObject *obj = new DLObject(dlerr);
- if (obj->open(filename))
- return (void *)obj;
- delete obj;
- return NULL;
-}
-
-int dlclose(void *handle) {
- DLObject *obj = (DLObject *)handle;
- if (obj == NULL) {
- strcpy(dlerr, "Handle is NULL.");
- return -1;
- }
- if (obj->close()) {
- delete obj;
- return 0;
- }
- return -1;
-}
-
-void *dlsym(void *handle, const char *symbol) {
- if (handle == NULL) {
- strcpy(dlerr, "Handle is NULL.");
- return NULL;
- }
- return ((DLObject *)handle)->symbol(symbol);
-}
-
-const char *dlerror() {
- return dlerr;
-}
-
-void dlforgetsyms(void *handle) {
- if (handle != NULL)
- ((DLObject *)handle)->discard_symtab();
-}
-
-
-#endif /* DYNAMIC_MODULES && __PSP__ */
diff --git a/backends/platform/psp/thread.cpp b/backends/platform/psp/thread.cpp
index 916b1e553b..e757c2f575 100644
--- a/backends/platform/psp/thread.cpp
+++ b/backends/platform/psp/thread.cpp
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.h $
- * $Id: osys_psp.h 49173 2010-05-24 03:05:17Z bluddy $
+ * $URL$
+ * $Id$
*
*/
diff --git a/backends/platform/psp/thread.h b/backends/platform/psp/thread.h
index de1c10a2aa..44394af40a 100644
--- a/backends/platform/psp/thread.h
+++ b/backends/platform/psp/thread.h
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/portdefs.h $
- * $Id: portdefs.h 38687 2009-02-21 12:08:52Z joostp $
+ * $URL$
+ * $Id$
*
*/
diff --git a/backends/platform/samsungtv/main.cpp b/backends/platform/samsungtv/main.cpp
index 2c025b750c..a6b8376912 100644
--- a/backends/platform/samsungtv/main.cpp
+++ b/backends/platform/samsungtv/main.cpp
@@ -43,7 +43,7 @@ extern "C" int Game_Main(char *path, char *) {
// Invoke the actual ScummVM main entry point:
int res = scummvm_main(0, 0);
- ((OSystem_SDL *)g_system)->deinit();
+ g_system->quit(); // TODO: Consider removing / replacing this!
return res;
}
diff --git a/backends/platform/sdl/graphics.cpp b/backends/platform/sdl/graphics.cpp
index a97a153f3c..aec90d1352 100644
--- a/backends/platform/sdl/graphics.cpp
+++ b/backends/platform/sdl/graphics.cpp
@@ -1693,6 +1693,7 @@ void OSystem_SDL::drawMouse() {
SDL_Rect dst;
int scale;
+ int width, height;
int hotX, hotY;
dst.x = _mouseCurState.x;
@@ -1700,12 +1701,16 @@ void OSystem_SDL::drawMouse() {
if (!_overlayVisible) {
scale = _videoMode.scaleFactor;
+ width = _videoMode.screenWidth;
+ height = _videoMode.screenHeight;
dst.w = _mouseCurState.vW;
dst.h = _mouseCurState.vH;
hotX = _mouseCurState.vHotX;
hotY = _mouseCurState.vHotY;
} else {
scale = 1;
+ width = _videoMode.overlayWidth;
+ height = _videoMode.overlayHeight;
dst.w = _mouseCurState.rW;
dst.h = _mouseCurState.rH;
hotX = _mouseCurState.rHotX;
diff --git a/backends/platform/sdl/main.cpp b/backends/platform/sdl/main.cpp
index 52bbb59165..ef95a6d256 100644
--- a/backends/platform/sdl/main.cpp
+++ b/backends/platform/sdl/main.cpp
@@ -64,7 +64,7 @@ int main(int argc, char *argv[]) {
// Invoke the actual ScummVM main entry point:
int res = scummvm_main(argc, argv);
- ((OSystem_SDL *)g_system)->deinit();
+ g_system->quit(); // TODO: Consider removing / replacing this!
return res;
}
diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp
index 6686249416..5c50a43daf 100644
--- a/backends/platform/sdl/sdl.cpp
+++ b/backends/platform/sdl/sdl.cpp
@@ -483,7 +483,7 @@ bool OSystem_SDL::getFeatureState(Feature f) {
}
}
-void OSystem_SDL::deinit() {
+void OSystem_SDL::quit() {
if (_cdrom) {
SDL_CDStop(_cdrom);
SDL_CDClose(_cdrom);
@@ -505,14 +505,10 @@ void OSystem_SDL::deinit() {
SDL_Quit();
- // Event Manager requires save manager for storing
+ // Even Manager requires save manager for storing
// recorded events
delete getEventManager();
delete _savefile;
-}
-
-void OSystem_SDL::quit() {
- deinit();
#if !defined(SAMSUNGTV)
exit(0);
diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h
index 5c901ba711..ace07f349e 100644
--- a/backends/platform/sdl/sdl.h
+++ b/backends/platform/sdl/sdl.h
@@ -202,8 +202,6 @@ public:
// Quit
virtual void quit(); // overloaded by CE backend
- void deinit();
-
virtual void getTimeAndDate(TimeDate &t) const;
virtual Common::TimerManager *getTimerManager();
diff --git a/backends/plugins/arm-loader.cpp b/backends/plugins/arm-loader.cpp
new file mode 100644
index 0000000000..7e8269220b
--- /dev/null
+++ b/backends/plugins/arm-loader.cpp
@@ -0,0 +1,169 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(DYNAMIC_MODULES) && defined(ARM_TARGET)
+
+#include "backends/fs/ds/ds-fs.h"
+#include "elf-loader.h"
+#include "dsmain.h"
+#include "arm-loader.h"
+
+#define __DEBUG_PLUGINS__
+
+#ifdef __DEBUG_PLUGINS__
+#define DBG(x,...) consolePrintf(x, ## __VA_ARGS__)
+#else
+#define DBG(x,...)
+#endif
+
+#define seterror(x,...) consolePrintf(x, ## __VA_ARGS__)
+
+/**
+ * Follow the instruction of a relocation section.
+ *
+ * @param DLFile SeekableReadStream of File
+ * @param offset Offset into the File
+ * @param size Size of relocation section
+ *
+ */
+bool ARMDLObject::relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment) {
+ Elf32_Rel *rel = NULL; //relocation entry
+
+ // Allocate memory for relocation table
+ if (!(rel = (Elf32_Rel *)malloc(size))) {
+ seterror("Out of memory.");
+ return false;
+ }
+
+ // Read in our relocation table
+ if (DLFile->seek(offset, SEEK_SET) < 0 ||
+ DLFile->read(rel, size) != (ssize_t)size) {
+ seterror("Relocation table load failed.");
+ free(rel);
+ return false;
+ }
+
+ // Treat each relocation entry. Loop over all of them
+ int cnt = size / sizeof(*rel);
+
+ DBG("Loaded relocation table. %d entries. base address=%p\n", cnt, relSegment);
+
+ int a = 0;
+ unsigned int relocation = 0;
+
+ // Loop over relocation entries
+ for (int i = 0; i < cnt; i++) {
+
+ // Get the symbol this relocation entry is referring to
+ Elf32_Sym *sym = (Elf32_Sym *)(_symtab) + (REL_INDEX(rel[i].r_info));
+
+ // Get the target instruction in the code
+ unsigned int *target = (unsigned int *)((char *)relSegment + rel[i].r_offset);
+
+ unsigned int origTarget = *target; //Save for debugging
+
+ // Act differently based on the type of relocation
+ switch (REL_TYPE(rel[i].r_info)) {
+
+ case R_ARM_ABS32:
+ if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section.
+ a = *target; // Get full 32 bits of addend
+ relocation = a + (Elf32_Addr)_segment; // Shift by main offset
+
+ *target = relocation;
+
+ DBG("R_ARM_ABS32: i=%d, a=%x, origTarget=%x, target=%x\n", i, a, origTarget, *target);
+ }
+ break;
+
+ case R_ARM_THM_CALL:
+ DBG("R_ARM_THM_CALL: PC-relative jump, ld takes care of necessary relocation work for us.\n");
+ break;
+
+ case R_ARM_CALL:
+ DBG("R_ARM_CALL: PC-relative jump, ld takes care of necessary relocation work for us.\n");
+ break;
+
+ case R_ARM_JUMP24:
+ DBG("R_ARM_JUMP24: PC-relative jump, ld takes care of all relocation work for us.\n");
+ break;
+
+ case R_ARM_TARGET1:
+ if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section.
+ a = *target; // Get full 32 bits of addend
+ relocation = a + (Elf32_Addr)_segment; // Shift by main offset
+
+ *target = relocation;
+
+ DBG("R_ARM_TARGET1: i=%d, a=%x, origTarget=%x, target=%x\n", i, a, origTarget, *target);
+ DBG("Make sure --target1-abs is a flag to LD!\n");
+ }
+ break;
+
+ case R_ARM_V4BX:
+ DBG("R_ARM_V4BX: No relocation calculation necessary.\n");
+ break;
+
+ default:
+ seterror("Unknown relocation type %d.", REL_TYPE(rel[i].r_info));
+ free(rel);
+ return false;
+ }
+
+ }
+
+ free(rel);
+ return true;
+}
+
+bool ARMDLObject::relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) {
+
+ // Loop over sections, finding relocation sections
+ for (int i = 0; i < ehdr->e_shnum; i++) {
+
+ Elf32_Shdr *curShdr = &(shdr[i]);
+
+ if ((curShdr->sh_type == SHT_REL || curShdr->sh_type == SHT_RELA) && // Check for a relocation section
+ curShdr->sh_entsize == sizeof(Elf32_Rel) && // Check for proper relocation size
+ (int)curShdr->sh_link == _symtab_sect && // Check that the sh_link connects to our symbol table
+ curShdr->sh_info < ehdr->e_shnum && // Check that the relocated section exists
+ (shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) { // Check if relocated section resides in memory
+
+ if (curShdr->sh_type == SHT_RELA) {
+ seterror("RELA entries not supported yet!\n");
+ return false;
+ }
+
+ if (!relocate(DLFile, curShdr->sh_offset, curShdr->sh_size, _segment)) {
+ return false;
+ }
+
+ }
+ }
+
+ return true;
+}
+
+#endif /* defined(DYNAMIC_MODULES) && defined(ARM_TARGET) */
diff --git a/backends/plugins/arm-loader.h b/backends/plugins/arm-loader.h
new file mode 100644
index 0000000000..7f7a1f7f4b
--- /dev/null
+++ b/backends/plugins/arm-loader.h
@@ -0,0 +1,37 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "backends/fs/ds/ds-fs.h"
+#include "elf-loader.h"
+#include "dsmain.h"
+
+class ARMDLObject : public DLObject {
+protected:
+ bool relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment);
+ bool relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr);
+
+public:
+ ARMDLObject() : DLObject() {}
+};
diff --git a/backends/plugins/ds/ds-provider.cpp b/backends/plugins/ds/ds-provider.cpp
new file mode 100644
index 0000000000..7365a2e6e9
--- /dev/null
+++ b/backends/plugins/ds/ds-provider.cpp
@@ -0,0 +1,45 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(DYNAMIC_MODULES) && defined(__DS__)
+
+#include "backends/plugins/arm-loader.h"
+#include "backends/plugins/elf-provider.h"
+#include "backends/plugins/ds/ds-provider.h"
+
+
+class DSPlugin : public ELFPlugin {
+public:
+ DSPlugin(const Common::String &filename) : ELFPlugin(filename) {}
+
+ DLObject *makeDLObject() { return new ARMDLObject(); }
+};
+
+Plugin* DSPluginProvider::createPlugin(const Common::FSNode &node) const {
+ return new DSPlugin(node.getPath());
+}
+
+#endif // defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET)
+
diff --git a/backends/plugins/ds/ds-provider.h b/backends/plugins/ds/ds-provider.h
new file mode 100644
index 0000000000..462c3e3b63
--- /dev/null
+++ b/backends/plugins/ds/ds-provider.h
@@ -0,0 +1,32 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "backends/plugins/elf-provider.h"
+
+class DSPluginProvider : public ELFPluginProvider {
+ Plugin* createPlugin(const Common::FSNode &node) const;
+};
+
+
diff --git a/backends/plugins/ds/plugin.ld b/backends/plugins/ds/plugin.ld
new file mode 100644
index 0000000000..2b2bca9745
--- /dev/null
+++ b/backends/plugins/ds/plugin.ld
@@ -0,0 +1,218 @@
+OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",
+ "elf32-littlearm")
+OUTPUT_ARCH(arm)
+
+/* PHDRS specifies ELF Program Headers (or segments) to the plugin linker */
+PHDRS {
+ plugin PT_LOAD ; /* Specifies that the plugin segment should be loaded from file */
+}
+
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = 0;
+ .interp : { *(.interp) } : plugin
+ .note.gnu.build-id : { *(.note.gnu.build-id) }
+ .hash : { *(.hash) }
+ .gnu.hash : { *(.gnu.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .rel.dyn :
+ {
+ *(.rel.init)
+ *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
+ *(.rel.fini)
+ *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
+ *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*)
+ *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
+ *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
+ *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
+ *(.rel.ctors)
+ *(.rel.dtors)
+ *(.rel.got)
+ *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
+ PROVIDE_HIDDEN (__rel_iplt_start = .);
+ *(.rel.iplt)
+ PROVIDE_HIDDEN (__rel_iplt_end = .);
+ PROVIDE_HIDDEN (__rela_iplt_start = .);
+ PROVIDE_HIDDEN (__rela_iplt_end = .);
+ }
+ .rela.dyn :
+ {
+ *(.rela.init)
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+ *(.rela.fini)
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+ *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+ *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+ *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+ *(.rela.ctors)
+ *(.rela.dtors)
+ *(.rela.got)
+ *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+ PROVIDE_HIDDEN (__rel_iplt_start = .);
+ PROVIDE_HIDDEN (__rel_iplt_end = .);
+ PROVIDE_HIDDEN (__rela_iplt_start = .);
+ *(.rela.iplt)
+ PROVIDE_HIDDEN (__rela_iplt_end = .);
+ }
+ .rel.plt :
+ {
+ *(.rel.plt)
+ }
+ .rela.plt :
+ {
+ *(.rela.plt)
+ }
+ .init :
+ {
+ KEEP (*(.init))
+ } =0
+ .plt : { *(.plt) }
+ .iplt : { *(.iplt) }
+ .text :
+ {
+ *(.text.unlikely .text.*_unlikely)
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx)
+ } =0
+ .fini :
+ {
+ KEEP (*(.fini))
+ } =0
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+ .rodata1 : { *(.rodata1) }
+ .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) }
+ __exidx_start = .;
+ .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) }
+ __exidx_end = .;
+ .eh_frame_hdr : { *(.eh_frame_hdr) }
+ .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
+ .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. */
+ . = ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1));
+ /* Exception handling */
+ .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }
+ .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+ /* Thread Local Storage sections */
+ .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+ .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+ .preinit_array :
+ {
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ }
+ .init_array :
+ {
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ }
+ .fini_array :
+ {
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ }
+ .ctors :
+ {
+ ___plugin_ctors = .;
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ ___plugin_ctors_end = .;
+ }
+ .dtors :
+ {
+ ___plugin_dtors = .;
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ ___plugin_dtors_end = .;
+ }
+ .jcr : { KEEP (*(.jcr)) }
+ .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
+ .dynamic : { *(.dynamic) }
+ .got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) }
+ .data :
+ {
+ __data_start = . ;
+ *(.data .data.* .gnu.linkonce.d.*)
+ SORT(CONSTRUCTORS)
+ }
+ .data1 : { *(.data1) }
+ _edata = .; PROVIDE (edata = .);
+ __bss_start = .;
+ __bss_start__ = .;
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections.
+ FIXME: Why do we need it? When there is no .bss section, we don't
+ pad the .data section. */
+ . = ALIGN(. != 0 ? 32 / 8 : 1);
+ }
+ _bss_end__ = . ; __bss_end__ = . ;
+ . = ALIGN(32 / 8);
+ . = ALIGN(32 / 8);
+ __end__ = . ;
+ _end = .; PROVIDE (end = .);
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ /* DWARF 3 */
+ .debug_pubtypes 0 : { *(.debug_pubtypes) }
+ .debug_ranges 0 : { *(.debug_ranges) }
+ .stack 0x80000 :
+ {
+ _stack = .;
+ *(.stack)
+ }
+ .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) }
+ .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
+ /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
+}
diff --git a/backends/plugins/elf-loader.cpp b/backends/plugins/elf-loader.cpp
new file mode 100644
index 0000000000..9787c880ae
--- /dev/null
+++ b/backends/plugins/elf-loader.cpp
@@ -0,0 +1,413 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET)
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <malloc.h> // for memalign() (Linux specific)
+#include <unistd.h>
+#include <sys/fcntl.h>
+#include <sys/_default_fcntl.h> // FIXME: Why do we need this DevKitPro specific header?
+
+#include "common/file.h"
+#include "common/fs.h"
+#include "elf-loader.h"
+
+#ifdef __PSP__
+#include "backends/platform/psp/powerman.h"
+#include "psputils.h"
+#endif
+
+#ifdef __DS__
+#include <nds.h>
+#endif
+
+#define __DEBUG_PLUGINS__
+
+#ifdef __DEBUG_PLUGINS__
+#define DBG(x,...) printf(x, ## __VA_ARGS__)
+#else
+#define DBG(x,...)
+#endif
+
+#define seterror(x,...) printf(x, ## __VA_ARGS__)
+
+/**
+ * Flushes the data cache (Platform Specific).
+ */
+static void flushDataCache() {
+#ifdef __DS__
+ DC_FlushAll();
+#endif
+#ifdef __PLAYSTATION2__
+ FlushCache(0);
+ FlushCache(2);
+#endif
+#ifdef __PSP__
+ sceKernelDcacheWritebackAll();
+#endif
+}
+
+// Expel the symbol table from memory
+void DLObject::discard_symtab() {
+ free(_symtab);
+ free(_strtab);
+ _symtab = NULL;
+ _strtab = NULL;
+ _symbol_cnt = 0;
+}
+
+// Unload all objects from memory
+void DLObject::unload() {
+ discard_symtab();
+ free(_segment);
+ _segment = NULL;
+}
+
+bool DLObject::readElfHeader(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr) {
+
+ // Start reading the elf header. Check for errors
+ if (DLFile->read(ehdr, sizeof(*ehdr)) != sizeof(*ehdr) ||
+ memcmp(ehdr->e_ident, ELFMAG, SELFMAG) || // Check MAGIC
+ ehdr->e_type != ET_EXEC || // Check for executable
+#ifdef ARM_TARGET
+ ehdr->e_machine != EM_ARM || // Check for ARM machine type
+#endif
+#ifdef MIPS_TARGET
+ ehdr->e_machine != EM_MIPS || // Check for MIPS machine type
+#endif
+ ehdr->e_phentsize < sizeof(Elf32_Phdr) || // Check for size of program header
+ ehdr->e_shentsize != sizeof(Elf32_Shdr)) { // Check for size of section header
+ seterror("Invalid file type.");
+ return false;
+ }
+
+ DBG("phoff = %d, phentsz = %d, phnum = %d\n",
+ ehdr->e_phoff, ehdr->e_phentsize, ehdr->e_phnum);
+
+ return true;
+}
+
+bool DLObject::readProgramHeaders(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num) {
+
+ // Read program header
+ if (DLFile->seek(ehdr->e_phoff + sizeof(*phdr)*num, SEEK_SET) < 0 ||
+ DLFile->read(phdr, sizeof(*phdr)) != sizeof(*phdr)) {
+ seterror("Program header load failed.");
+ return false;
+ }
+
+ // Check program header values
+ if (phdr->p_type != PT_LOAD || phdr->p_filesz > phdr->p_memsz) {
+ seterror("Invalid program header.");
+ return false;
+ }
+
+ DBG("offs = %x, filesz = %x, memsz = %x, align = %x\n",
+ phdr->p_offset, phdr->p_filesz, phdr->p_memsz, phdr->p_align);
+
+ return true;
+
+}
+
+bool DLObject::loadSegment(Common::SeekableReadStream* DLFile, Elf32_Phdr *phdr) {
+
+ char *baseAddress = 0;
+
+ // Attempt to allocate memory for segment
+ int extra = phdr->p_vaddr % phdr->p_align; // Get extra length TODO: check logic here
+ DBG("extra mem is %x\n", extra);
+
+ if (!(_segment = (char *)memalign(phdr->p_align, phdr->p_memsz + extra))) {
+ seterror("Out of memory.\n");
+ return false;
+ }
+
+ DBG("allocated segment @ %p\n", _segment);
+
+ // Get offset to load segment into
+ baseAddress = (char *)_segment + phdr->p_vaddr;
+ _segmentSize = phdr->p_memsz + extra;
+
+ // Set bss segment to 0 if necessary (assumes bss is at the end)
+ if (phdr->p_memsz > phdr->p_filesz) {
+ DBG("Setting %p to %p to 0 for bss\n", baseAddress + phdr->p_filesz, baseAddress + phdr->p_memsz);
+ memset(baseAddress + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz);
+ }
+
+ DBG("Reading the segment into memory\n");
+
+ // Read the segment into memory
+ if (DLFile->seek(phdr->p_offset, SEEK_SET) < 0 ||
+ DLFile->read(baseAddress, phdr->p_filesz) != (ssize_t)phdr->p_filesz) {
+ seterror("Segment load failed.");
+ return false;
+ }
+
+ DBG("Segment has been read into memory\n");
+
+ return true;
+}
+
+Elf32_Shdr * DLObject::loadSectionHeaders(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr) {
+
+ Elf32_Shdr *shdr = NULL;
+
+ // Allocate memory for section headers
+ if (!(shdr = (Elf32_Shdr *)malloc(ehdr->e_shnum * sizeof(*shdr)))) {
+ seterror("Out of memory.");
+ return NULL;
+ }
+
+ // Read from file into section headers
+ if (DLFile->seek(ehdr->e_shoff, SEEK_SET) < 0 ||
+ DLFile->read(shdr, ehdr->e_shnum * sizeof(*shdr)) !=
+ (ssize_t)(ehdr->e_shnum * sizeof(*shdr))) {
+ seterror("Section headers load failed.");
+ return NULL;
+ }
+
+ return shdr;
+}
+
+int DLObject::loadSymbolTable(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) {
+
+ // Loop over sections, looking for symbol table linked to a string table
+ for (int i = 0; i < ehdr->e_shnum; i++) {
+ if (shdr[i].sh_type == SHT_SYMTAB &&
+ shdr[i].sh_entsize == sizeof(Elf32_Sym) &&
+ shdr[i].sh_link < ehdr->e_shnum &&
+ shdr[shdr[i].sh_link].sh_type == SHT_STRTAB &&
+ _symtab_sect < 0) {
+ _symtab_sect = i;
+ }
+ }
+
+ // Check for no symbol table
+ if (_symtab_sect < 0) {
+ seterror("No symbol table.");
+ return -1;
+ }
+
+ DBG("Symbol section at section %d, size %x\n", _symtab_sect, shdr[_symtab_sect].sh_size);
+
+ // Allocate memory for symbol table
+ if (!(_symtab = malloc(shdr[_symtab_sect].sh_size))) {
+ seterror("Out of memory.");
+ return -1;
+ }
+
+ // Read symbol table into memory
+ if (DLFile->seek(shdr[_symtab_sect].sh_offset, SEEK_SET) < 0 ||
+ DLFile->read(_symtab, shdr[_symtab_sect].sh_size) !=
+ (ssize_t)shdr[_symtab_sect].sh_size) {
+ seterror("Symbol table load failed.");
+ return -1;
+ }
+
+ // Set number of symbols
+ _symbol_cnt = shdr[_symtab_sect].sh_size / sizeof(Elf32_Sym);
+ DBG("Loaded %d symbols.\n", _symbol_cnt);
+
+ return _symtab_sect;
+
+}
+
+bool DLObject::loadStringTable(Common::SeekableReadStream* DLFile, Elf32_Shdr *shdr) {
+
+ int string_sect = shdr[_symtab_sect].sh_link;
+
+ // Allocate memory for string table
+ if (!(_strtab = (char *)malloc(shdr[string_sect].sh_size))) {
+ seterror("Out of memory.");
+ return false;
+ }
+
+ // Read string table into memory
+ if (DLFile->seek(shdr[string_sect].sh_offset, SEEK_SET) < 0 ||
+ DLFile->read(_strtab, shdr[string_sect].sh_size) !=
+ (ssize_t)shdr[string_sect].sh_size) {
+ seterror("Symbol table strings load failed.");
+ return false;
+ }
+
+ return true;
+}
+
+void DLObject::relocateSymbols(Elf32_Addr offset) {
+
+ int mainCount = 0;
+ int shortsCount= 0;
+
+ // Loop over symbols, add relocation offset
+ Elf32_Sym *s = (Elf32_Sym *)_symtab;
+ for (int c = _symbol_cnt; c--; s++) {
+
+ // Make sure we don't relocate special valued symbols
+ if (s->st_shndx < SHN_LOPROC) {
+ mainCount++;
+ s->st_value += offset;
+ if (s->st_value < (Elf32_Addr)_segment || s->st_value > (Elf32_Addr)_segment + _segmentSize)
+ seterror("Symbol out of bounds! st_value = %x\n", s->st_value);
+ }
+ }
+}
+
+bool DLObject::load(Common::SeekableReadStream* DLFile) {
+ Elf32_Ehdr ehdr;
+ Elf32_Phdr phdr;
+ Elf32_Shdr *shdr;
+ bool ret = true;
+
+ if (readElfHeader(DLFile, &ehdr) == false) {
+ return false;
+ }
+
+ for (int i = 0; i < ehdr.e_phnum; i++) { //Load our segments
+
+ DBG("Loading segment %d\n", i);
+
+ if (readProgramHeaders(DLFile, &ehdr, &phdr, i) == false)
+ return false;
+
+ if (!loadSegment(DLFile, &phdr))
+ return false;
+ }
+
+ if ((shdr = loadSectionHeaders(DLFile, &ehdr)) == NULL)
+ ret = false;
+
+ if (ret && ((_symtab_sect = loadSymbolTable(DLFile, &ehdr, shdr)) < 0))
+ ret = false;
+
+ if (ret && (loadStringTable(DLFile, shdr) == false))
+ ret = false;
+
+ if (ret)
+ relocateSymbols((Elf32_Addr)_segment); // Offset by our segment allocated address
+
+ if (ret && (relocateRels(DLFile, &ehdr, shdr) == false))
+ ret = false;
+
+ free(shdr);
+
+ return ret;
+
+}
+
+bool DLObject::open(const char *path) {
+
+ Common::SeekableReadStream* DLFile;
+ void *ctors_start, *ctors_end;
+
+#ifdef __PSP__
+ PowerMan.beginCriticalSection();
+#endif
+
+ DBG("open(\"%s\")\n", path);
+
+ Common::FSNode file(path);
+
+ if (!(DLFile = file.createReadStream())) {
+ seterror("%s not found.", path);
+ return false;
+ }
+
+ DBG("%s found!\n", path);
+
+ /*Try to load and relocate*/
+ if (!load(DLFile)) {
+ unload();
+ return false;
+ }
+
+ DBG("loaded!/n");
+
+#ifdef __PSP__
+ PowerMan.endCriticalSection();
+#endif
+
+ flushDataCache();
+
+ ctors_start = symbol("___plugin_ctors");
+ ctors_end = symbol("___plugin_ctors_end");
+ _dtors_start = symbol("___plugin_dtors");
+ _dtors_end = symbol("___plugin_dtors_end");
+
+ if (ctors_start == NULL || ctors_end == NULL || _dtors_start == NULL ||
+ _dtors_end == NULL) {
+ seterror("Missing ctors/dtors.");
+ _dtors_start = _dtors_end = NULL;
+ unload();
+ return false;
+ }
+
+ DBG(("Calling constructors.\n"));
+ for (void (**f)(void) = (void (**)(void))ctors_start; f != ctors_end; f++)
+ (**f)();
+
+ DBG(("%s opened ok.\n", path));
+
+ return true;
+}
+
+bool DLObject::close() {
+ if (_dtors_start != NULL && _dtors_end != NULL)
+ for (void (**f)(void) = (void (**)(void))_dtors_start; f != _dtors_end; f++)
+ (**f)();
+ _dtors_start = _dtors_end = NULL;
+ unload();
+ return true;
+}
+
+void *DLObject::symbol(const char *name) {
+ DBG(("symbol(\"%s\")\n", name));
+
+ if (_symtab == NULL || _strtab == NULL || _symbol_cnt < 1) {
+ seterror("No symbol table loaded.");
+ return NULL;
+ }
+
+ Elf32_Sym *s = (Elf32_Sym *)_symtab;
+ for (int c = _symbol_cnt; c--; s++)
+
+ // We can only import symbols that are global or weak in the plugin
+ if ((SYM_BIND(s->st_info) == STB_GLOBAL || SYM_BIND(s->st_info) == STB_WEAK) &&
+ !strcmp(name, _strtab + s->st_name)) {
+
+ // We found the symbol
+ DBG("=> %p\n", (void*)s->st_value);
+ return (void*)s->st_value;
+ }
+
+ // We didn't find the symbol
+ seterror("Symbol \"%s\" not found.", name);
+ return NULL;
+}
+
+#endif /* defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET) */
+
diff --git a/backends/plugins/elf-loader.h b/backends/plugins/elf-loader.h
new file mode 100644
index 0000000000..1d30aa0c3b
--- /dev/null
+++ b/backends/plugins/elf-loader.h
@@ -0,0 +1,67 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef ELF_LOADER_H
+#define ELF_LOADER_H
+
+#include "elf32.h"
+#include "common/stream.h"
+#include "backends/plugins/dynamic-plugin.h"
+
+class DLObject {
+protected:
+ void *_segment, *_symtab;
+ char *_strtab;
+ int _symbol_cnt;
+ int _symtab_sect;
+ void *_dtors_start, *_dtors_end;
+
+ int _segmentSize;
+
+ //void seterror(const char *fmt, ...);
+ virtual void unload();
+ virtual bool relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment) = 0;
+ bool load(Common::SeekableReadStream* DLFile);
+
+ bool readElfHeader(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr);
+ bool readProgramHeaders(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num);
+ virtual bool loadSegment(Common::SeekableReadStream* DLFile, Elf32_Phdr *phdr);
+ Elf32_Shdr *loadSectionHeaders(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr);
+ int loadSymbolTable(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr);
+ bool loadStringTable(Common::SeekableReadStream* DLFile, Elf32_Shdr *shdr);
+ virtual void relocateSymbols(Elf32_Addr offset);
+ virtual bool relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) = 0;
+
+public:
+ bool open(const char *path);
+ bool close();
+ void *symbol(const char *name);
+ void discard_symtab();
+
+ DLObject() : _segment(NULL), _symtab(NULL), _strtab(NULL), _symbol_cnt(0),
+ _symtab_sect(-1), _dtors_start(NULL), _dtors_end(NULL), _segmentSize(0) {}
+};
+
+#endif /* ELF_LOADER_H */
diff --git a/backends/plugins/elf-provider.cpp b/backends/plugins/elf-provider.cpp
new file mode 100644
index 0000000000..e6edd4c578
--- /dev/null
+++ b/backends/plugins/elf-provider.cpp
@@ -0,0 +1,105 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET)
+
+#include "backends/plugins/elf-provider.h"
+#include "backends/plugins/dynamic-plugin.h"
+#include "common/fs.h"
+
+#include "backends/plugins/elf-loader.h"
+
+DynamicPlugin::VoidFunc ELFPlugin::findSymbol(const char *symbol) {
+ void *func;
+ bool handleNull;
+ if (_dlHandle == NULL) {
+ func = NULL;
+ handleNull = true;
+ } else {
+ func = _dlHandle->symbol(symbol);
+ }
+ if (!func) {
+ if (handleNull) {
+ warning("Failed loading symbol '%s' from plugin '%s' (Handle is NULL)", symbol, _filename.c_str());
+ } else {
+ warning("Failed loading symbol '%s' from plugin '%s'", symbol, _filename.c_str());
+ }
+ }
+
+ // FIXME HACK: This is a HACK to circumvent a clash between the ISO C++
+ // standard and POSIX: ISO C++ disallows casting between function pointers
+ // and data pointers, but dlsym always returns a void pointer. For details,
+ // see e.g. <http://www.trilithium.com/johan/2004/12/problem-with-dlsym/>.
+ assert(sizeof(VoidFunc) == sizeof(func));
+ VoidFunc tmp;
+ memcpy(&tmp, &func, sizeof(VoidFunc));
+ return tmp;
+}
+
+bool ELFPlugin::loadPlugin() {
+ assert(!_dlHandle);
+ DLObject *obj = makeDLObject();
+ if (obj->open(_filename.c_str())) {
+ _dlHandle = obj;
+ } else {
+ delete obj;
+ _dlHandle = NULL;
+ }
+
+ if (!_dlHandle) {
+ warning("Failed loading plugin '%s'", _filename.c_str());
+ return false;
+ }
+
+ bool ret = DynamicPlugin::loadPlugin();
+
+ if (ret && _dlHandle) {
+ _dlHandle->discard_symtab();
+ }
+
+ return ret;
+};
+
+void ELFPlugin::unloadPlugin() {
+ DynamicPlugin::unloadPlugin();
+ if (_dlHandle) {
+ if (!_dlHandle->close()) {
+ warning("Failed unloading plugin '%s'", _filename.c_str());
+ }
+ delete _dlHandle;
+ _dlHandle = 0;
+ }
+}
+
+bool ELFPluginProvider::isPluginFilename(const Common::FSNode &node) const {
+ // Check the plugin suffix
+ Common::String filename = node.getName();
+ if (!filename.hasSuffix(".PLG") && !filename.hasSuffix(".plg") && !filename.hasSuffix(".PLUGIN") && !filename.hasSuffix(".plugin")) {
+ return false;
+ }
+ return true;
+}
+
+#endif // defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET)
diff --git a/backends/plugins/elf-provider.h b/backends/plugins/elf-provider.h
new file mode 100644
index 0000000000..e0382c3e45
--- /dev/null
+++ b/backends/plugins/elf-provider.h
@@ -0,0 +1,70 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef BACKENDS_PLUGINS_ELF_PROVIDER_H
+#define BACKENDS_PLUGINS_ELF_PROVIDER_H
+
+#include "base/plugins.h"
+#include "backends/plugins/dynamic-plugin.h"
+#include "common/fs.h"
+
+#include "backends/plugins/elf-loader.h"
+
+#if defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET)
+
+class ELFPlugin : public DynamicPlugin {
+protected:
+ DLObject *_dlHandle;
+ Common::String _filename;
+
+ virtual VoidFunc findSymbol(const char *symbol);
+
+public:
+ ELFPlugin(const Common::String &filename)
+ : _dlHandle(0), _filename(filename) {}
+
+ ~ELFPlugin() {
+ if (_dlHandle)
+ unloadPlugin();
+ }
+
+ virtual DLObject *makeDLObject() = 0;
+
+ bool loadPlugin();
+ void unloadPlugin();
+
+};
+
+class ELFPluginProvider : public FilePluginProvider {
+protected:
+ virtual Plugin* createPlugin(const Common::FSNode &node) const = 0;
+
+ bool isPluginFilename(const Common::FSNode &node) const;
+
+};
+
+#endif // defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET)
+
+#endif /* BACKENDS_PLUGINS_ELF_PROVIDER_H */
diff --git a/backends/plugins/elf32.h b/backends/plugins/elf32.h
new file mode 100644
index 0000000000..5dec1d2e58
--- /dev/null
+++ b/backends/plugins/elf32.h
@@ -0,0 +1,229 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef BACKENDS_ELF_H
+#define BACKENDS_ELF_H
+
+/* ELF stuff */
+
+typedef unsigned short Elf32_Half, Elf32_Section;
+typedef unsigned int Elf32_Word, Elf32_Addr, Elf32_Off;
+typedef signed int Elf32_Sword;
+typedef Elf32_Half Elf32_Versym;
+
+#define EI_NIDENT (16)
+#define SELFMAG 6
+
+/* ELF File format structures. Look up ELF structure for more details */
+
+// ELF header (contains info about the file)
+typedef struct {
+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+ Elf32_Half e_type; /* Object file type */
+ Elf32_Half e_machine; /* Architecture */
+ Elf32_Word e_version; /* Object file version */
+ Elf32_Addr e_entry; /* Entry point virtual address */
+ Elf32_Off e_phoff; /* Program header table file offset */
+ Elf32_Off e_shoff; /* Section header table file offset */
+ Elf32_Word e_flags; /* Processor-specific flags */
+ Elf32_Half e_ehsize; /* ELF header size in bytes */
+ Elf32_Half e_phentsize; /* Program header table entry size */
+ Elf32_Half e_phnum; /* Program header table entry count */
+ Elf32_Half e_shentsize; /* Section header table entry size */
+ Elf32_Half e_shnum; /* Section header table entry count */
+ Elf32_Half e_shstrndx; /* Section header string table index */
+} Elf32_Ehdr;
+
+// Should be in e_ident
+#define ELFMAG "\177ELF\1\1" /* ELF Magic number */
+
+// e_type values
+#define ET_NONE 0 /* no file type */
+#define ET_REL 1 /* relocatable */
+#define ET_EXEC 2 /* executable */
+#define ET_DYN 3 /* shared object */
+#define ET_CORE 4 /* core file */
+
+// e_machine values
+#define EM_MIPS 8
+#define EM_ARM 40
+
+// Program header (contains info about segment)
+typedef struct {
+ Elf32_Word p_type; /* Segment type */
+ Elf32_Off p_offset; /* Segment file offset */
+ Elf32_Addr p_vaddr; /* Segment virtual address */
+ Elf32_Addr p_paddr; /* Segment physical address */
+ Elf32_Word p_filesz; /* Segment size in file */
+ Elf32_Word p_memsz; /* Segment size in memory */
+ Elf32_Word p_flags; /* Segment flags */
+ Elf32_Word p_align; /* Segment alignment */
+} Elf32_Phdr;
+
+// p_type values
+#define PT_NULL 0 /* ignored */
+#define PT_LOAD 1 /* loadable segment */
+#define PT_DYNAMIC 2 /* dynamic linking info */
+#define PT_INTERP 3 /* info about interpreter */
+#define PT_NOTE 4 /* note segment */
+#define PT_SHLIB 5 /* reserved */
+#define PT_PHDR 6 /* Program header table */
+#define PT_MIPS_REGINFO 0x70000000 /* Register usage info for MIPS */
+#define PT_ARM_ARCHEXT 0x70000000 /* Platform architecture compatibility info for ARM */
+#define PT_ARM_EXIDX 0x70000001 /* Exception unwind tables for ARM */
+
+// p_flags value
+#define PF_X 1 /* execute */
+#define PF_W 2 /* write */
+#define PF_R 4 /* read */
+
+// Section header (contains info about section)
+typedef struct {
+ Elf32_Word sh_name; /* Section name (string tbl index) */
+ Elf32_Word sh_type; /* Section type */
+ Elf32_Word sh_flags; /* Section flags */
+ Elf32_Addr sh_addr; /* Section virtual addr at execution */
+ Elf32_Off sh_offset; /* Section file offset */
+ Elf32_Word sh_size; /* Section size in bytes */
+ Elf32_Word sh_link; /* Link to another section */
+ Elf32_Word sh_info; /* Additional section information */
+ Elf32_Word sh_addralign; /* Section alignment */
+ Elf32_Word sh_entsize; /* Entry size if section holds table */
+} Elf32_Shdr;
+
+// sh_type values
+#define SHT_NULL 0 /* Inactive section */
+#define SHT_PROGBITS 1 /* Proprietary */
+#define SHT_SYMTAB 2 /* Symbol table */
+#define SHT_STRTAB 3 /* String table */
+#define SHT_RELA 4 /* Relocation entries with addend */
+#define SHT_HASH 5 /* Symbol hash table */
+#define SHT_DYNAMIC 6 /* Info for dynamic linking */
+#define SHT_NOTE 7 /* Note section */
+#define SHT_NOBITS 8 /* Occupies no space */
+#define SHT_REL 9 /* Relocation entries without addend */
+#define SHT_SHLIB 10 /* Reserved */
+#define SHT_DYNSYM 11 /* Minimal set of dynamic linking symbols */
+#define SHT_MIPS_LIBLSIT 0x70000000 /* Info about dynamic shared object libs for MIPS*/
+#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicts btw executables and shared objects for MIPS */
+#define SHT_MIPS_GPTAB 0x70000003 /* Global pointer table for MIPS*/
+#define SHT_ARM_EXIDX 0x70000001 /* Exception Index table for ARM*/
+#define SHT_ARM_PREEMPTMAP 0x70000002 /* BPABI DLL dynamic linking pre-emption map for ARM */
+#define SHT_ARM_ATTRIBUTES 0x70000003 /* Object file compatibility attributes for ARM*/
+
+// sh_flags values
+#define SHF_WRITE 0 /* writable section */
+#define SHF_ALLOC 2 /* section occupies memory */
+#define SHF_EXECINSTR 4 /* machine instructions */
+#define SHF_MIPS_GPREL 0x10000000 /* Must be made part of global data area for MIPS */
+
+// Symbol entry (contain info about a symbol)
+typedef struct {
+ Elf32_Word st_name; /* Symbol name (string tbl index) */
+ Elf32_Addr st_value; /* Symbol value */
+ Elf32_Word st_size; /* Symbol size */
+ unsigned char st_info; /* Symbol type and binding */
+ unsigned char st_other; /* Symbol visibility */
+ Elf32_Section st_shndx; /* Section index */
+} Elf32_Sym;
+
+// Extract from the st_info
+#define SYM_TYPE(x) ((x)&0xF)
+#define SYM_BIND(x) ((x)>>4)
+
+// Symbol binding values from st_info
+#define STB_LOCAL 0 /* Symbol not visible outside object */
+#define STB_GLOBAL 1 /* Symbol visible to all object files */
+#define STB_WEAK 2 /* Similar to STB_GLOBAL */
+
+// Symbol type values from st_info
+#define STT_NOTYPE 0 /* Not specified */
+#define STT_OBJECT 1 /* Data object e.g. variable */
+#define STT_FUNC 2 /* Function */
+#define STT_SECTION 3 /* Section */
+#define STT_FILE 4 /* Source file associated with object file */
+
+// Special section header index values from st_shndex
+#define SHN_UNDEF 0
+#define SHN_LOPROC 0xFF00 /* Extended values */
+#define SHN_ABS 0xFFF1 /* Absolute value: don't relocate */
+#define SHN_COMMON 0xFFF2 /* Common block. Not allocated yet */
+#define SHN_HIPROC 0xFF1F
+#define SHN_HIRESERVE 0xFFFF
+
+// Relocation entry with implicit addend (info about how to relocate)
+typedef struct {
+ Elf32_Addr r_offset; /* Address */
+ Elf32_Word r_info; /* Relocation type and symbol index */
+} Elf32_Rel;
+
+// Relocation entry with explicit addend (info about how to relocate)
+typedef struct
+{
+ Elf32_Addr r_offset; /* Address */
+ Elf32_Word r_info; /* Relocation type and symbol index */
+ Elf32_Sword r_addend; /* Addend */
+} Elf32_Rela;
+
+// Access macros for the relocation info
+#define REL_TYPE(x) ((unsigned char) (x)) /* Extract relocation type */
+#define REL_INDEX(x) ((x)>>8) /* Extract relocation index into symbol table */
+
+//MIPS relocation types
+#define R_MIPS_NONE 0
+#define R_MIPS_16 1
+#define R_MIPS_32 2
+#define R_MIPS_REL32 3
+#define R_MIPS_26 4
+#define R_MIPS_HI16 5
+#define R_MIPS_LO16 6
+#define R_MIPS_GPREL16 7
+#define R_MIPS_LITERAL 8
+#define R_MIPS_GOT16 9
+#define R_MIPS_PC16 10
+#define R_MIPS_CALL16 11
+#define R_MIPS_GPREL32 12
+#define R_MIPS_GOTHI16 13
+#define R_MIPS_GOTLO16 14
+#define R_MIPS_CALLHI16 15
+#define R_MIPS_CALLLO16 16
+
+// ARM relocation types
+#define R_ARM_NONE 0
+#define R_ARM_ABS32 2
+#define R_ARM_THM_CALL 10
+#define R_ARM_CALL 28
+#define R_ARM_JUMP24 29
+#define R_ARM_TARGET1 38
+#define R_ARM_V4BX 40
+
+// Mock function to get value of global pointer for MIPS
+#define getGP() ({ \
+ unsigned int __valgp; \
+ __asm__ ("add %0, $gp, $0" : "=r"(__valgp) : ); \
+ __valgp; \
+})
+
+#endif /* BACKENDS_ELF_H */
diff --git a/backends/plugins/mips-loader.cpp b/backends/plugins/mips-loader.cpp
new file mode 100644
index 0000000000..7b59a2cffa
--- /dev/null
+++ b/backends/plugins/mips-loader.cpp
@@ -0,0 +1,351 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(DYNAMIC_MODULES) && defined(MIPS_TARGET)
+
+#include "mips-loader.h"
+
+#define __DEBUG_PLUGINS__
+
+#ifdef __DEBUG_PLUGINS__
+#define DBG(x,...) printf(x, ## __VA_ARGS__)
+#else
+#define DBG(x,...)
+#endif
+
+#define seterror(x,...) printf(x, ## __VA_ARGS__)
+
+/**
+ * Follow the instruction of a relocation section.
+ *
+ * @param DLFile SeekableReadStream of File
+ * @param offset Offset into the File
+ * @param size Size of relocation section
+ * @param relSegment Base address of relocated segment in memory (memory offset)
+ *
+ */
+bool MIPSDLObject::relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment) {
+ Elf32_Rel *rel = NULL; // relocation entry
+
+ // Allocate memory for relocation table
+ if (!(rel = (Elf32_Rel *)malloc(size))) {
+ seterror("Out of memory.");
+ return false;
+ }
+
+ // Read in our relocation table
+ if (DLFile->seek(offset, SEEK_SET) < 0 ||
+ DLFile->read(rel, size) != (ssize_t)size) {
+ seterror("Relocation table load failed.");
+ free(rel);
+ return false;
+ }
+
+ // Treat each relocation entry. Loop over all of them
+ int cnt = size / sizeof(*rel);
+
+ DBG("Loaded relocation table. %d entries. base address=%p\n", cnt, relSegment);
+
+ bool seenHi16 = false; // For treating HI/LO16 commands
+ int firstHi16 = -1; // Mark the point of the first hi16 seen
+ Elf32_Addr ahl = 0; // Calculated addend
+ int a = 0; // Addend: taken from the target
+
+ unsigned int *lastTarget = 0; // For processing hi16 when lo16 arrives
+ unsigned int relocation = 0;
+ int debugRelocs[10] = {0}; // For debugging
+ int extendedHi16 = 0; // Count extended hi16 treatments
+ Elf32_Addr lastHiSymVal = 0;
+ bool hi16InShorts = false;
+
+#define DEBUG_NUM 2
+
+ // Loop over relocation entries
+ for (int i = 0; i < cnt; i++) {
+ // Get the symbol this relocation entry is referring to
+ Elf32_Sym *sym = (Elf32_Sym *)(_symtab) + (REL_INDEX(rel[i].r_info));
+
+ // Get the target instruction in the code
+ unsigned int *target = (unsigned int *)((char *)relSegment + rel[i].r_offset);
+
+ unsigned int origTarget = *target; // Save for debugging
+
+ // Act differently based on the type of relocation
+ switch (REL_TYPE(rel[i].r_info)) {
+
+ case R_MIPS_HI16: // Absolute addressing.
+ if (sym->st_shndx < SHN_LOPROC && // Only shift for plugin section (ie. has a real section index)
+ firstHi16 < 0) { // Only process first in block of HI16s
+ firstHi16 = i; // Keep the first Hi16 we saw
+ seenHi16 = true;
+ ahl = (*target & 0xffff) << 16; // Take lower 16 bits shifted up
+
+ lastHiSymVal = sym->st_value;
+ hi16InShorts = (ShortsMan.inGeneralSegment((char *)sym->st_value)); // Fix for problem with switching btw segments
+ if (debugRelocs[0]++ < DEBUG_NUM) // Print only a set number
+ DBG("R_MIPS_HI16: i=%d, offset=%x, ahl = %x, target = %x\n",
+ i, rel[i].r_offset, ahl, *target);
+ }
+ break;
+
+ case R_MIPS_LO16: // Absolute addressing. Needs a HI16 to come before it
+ if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section. (ie. has a real section index)
+ if (!seenHi16) { // We MUST have seen HI16 first
+ seterror("R_MIPS_LO16 w/o preceding R_MIPS_HI16 at relocation %d!\n", i);
+ free(rel);
+ return false;
+ }
+
+ // Fix: bug in gcc makes LO16s connect to wrong HI16s sometimes (shorts and regular segment)
+ // Note that we can check the entire shorts segment because the executable's shorts don't belong to this plugin section
+ // and will be screened out above
+ bool lo16InShorts = ShortsMan.inGeneralSegment((char *)sym->st_value);
+
+ // Correct the bug by getting the proper value in ahl (taken from the current symbol)
+ if ((hi16InShorts && !lo16InShorts) || (!hi16InShorts && lo16InShorts)) {
+ ahl -= (lastHiSymVal & 0xffff0000); // We assume gcc meant the same offset
+ ahl += (sym->st_value & 0xffff0000);
+ }
+
+ ahl &= 0xffff0000; // Clean lower 16 bits for repeated LO16s
+ a = *target & 0xffff; // Take lower 16 bits of the target
+ a = (a << 16) >> 16; // Sign extend them
+ ahl += a; // Add lower 16 bits. AHL is now complete
+
+ // Fix: we can have LO16 access to the short segment sometimes
+ if (lo16InShorts) {
+ relocation = ahl + _shortsSegment->getOffset(); // Add in the short segment offset
+ } else // It's in the regular segment
+ relocation = ahl + (Elf32_Addr)_segment; // Add in the new offset for the segment
+
+ if (firstHi16 >= 0) { // We haven't treated the HI16s yet so do it now
+ for (int j = firstHi16; j < i; j++) {
+ if (REL_TYPE(rel[j].r_info) != R_MIPS_HI16) continue; // Skip over non-Hi16s
+
+ lastTarget = (unsigned int *)((char *)relSegment + rel[j].r_offset); // get hi16 target
+ *lastTarget &= 0xffff0000; // Clear the lower 16 bits of the last target
+ *lastTarget |= (relocation >> 16) & 0xffff; // Take the upper 16 bits of the relocation
+ if (relocation & 0x8000)(*lastTarget)++; // Subtle: we need to add 1 to the HI16 in this case
+ }
+ firstHi16 = -1; // Reset so we'll know we treated it
+ } else {
+ extendedHi16++;
+ }
+
+ *target &= 0xffff0000; // Clear the lower 16 bits of current target
+ *target |= relocation & 0xffff; // Take the lower 16 bits of the relocation
+
+ if (debugRelocs[1]++ < DEBUG_NUM)
+ DBG("R_MIPS_LO16: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x\n",
+ i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target);
+ if (lo16InShorts && debugRelocs[2]++ < DEBUG_NUM)
+ DBG("R_MIPS_LO16s: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x\n",
+ i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target);
+ }
+ break;
+
+ case R_MIPS_26: // Absolute addressing (for jumps and branches only)
+ if (sym->st_shndx < SHN_LOPROC) { // Only relocate for main segment
+ a = *target & 0x03ffffff; // Get 26 bits' worth of the addend
+ a = (a << 6) >> 6; // Sign extend a
+ relocation = ((a << 2) + (Elf32_Addr)_segment) >> 2; // a already points to the target. Subtract our offset
+ *target &= 0xfc000000; // Clean lower 26 target bits
+ *target |= (relocation & 0x03ffffff);
+
+ if (debugRelocs[3]++ < DEBUG_NUM)
+ DBG("R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x\n",
+ i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target);
+ } else {
+ if (debugRelocs[4]++ < DEBUG_NUM)
+ DBG("R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x\n",
+ i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target);
+ }
+ break;
+
+ case R_MIPS_GPREL16: // GP Relative addressing
+ if (_shortsSegment->getOffset() != 0 && // Only relocate if we shift the shorts section
+ ShortsMan.inGeneralSegment((char *)sym->st_value)) { // Only relocate things in the plugin hole
+ a = *target & 0xffff; // Get 16 bits' worth of the addend
+ a = (a << 16) >> 16; // Sign extend it
+
+ relocation = a + _shortsSegment->getOffset();
+
+ *target &= 0xffff0000; // Clear the lower 16 bits of the target
+ *target |= relocation & 0xffff;
+
+ if (debugRelocs[5]++ < DEBUG_NUM)
+ DBG("R_MIPS_GPREL16: i=%d, a=%x, gpVal=%x, origTarget=%x, target=%x, offset=%x\n",
+ i, a, _gpVal, origTarget, *target, _shortsSegment->getOffset());
+ }
+
+ break;
+
+ case R_MIPS_32: // Absolute addressing
+ if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section.
+ a = *target; // Get full 32 bits of addend
+
+ if (ShortsMan.inGeneralSegment((char *)sym->st_value)) // Check if we're in the shorts segment
+ relocation = a + _shortsSegment->getOffset(); // Shift by shorts offset
+ else // We're in the main section
+ relocation = a + (Elf32_Addr)_segment; // Shift by main offset
+ *target = relocation;
+
+ if (debugRelocs[6]++ < DEBUG_NUM)
+ DBG("R_MIPS_32: i=%d, a=%x, origTarget=%x, target=%x\n", i, a, origTarget, *target);
+ }
+ break;
+
+ default:
+ seterror("Unknown relocation type %x at relocation %d.\n", REL_TYPE(rel[i].r_info), i);
+ free(rel);
+ return false;
+ }
+ }
+
+ DBG("Done with relocation. extendedHi16=%d\n\n", extendedHi16);
+
+ free(rel);
+ return true;
+}
+
+bool MIPSDLObject::relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) {
+
+ // Loop over sections, finding relocation sections
+ for (int i = 0; i < ehdr->e_shnum; i++) {
+
+ Elf32_Shdr *curShdr = &(shdr[i]);
+ //Elf32_Shdr *linkShdr = &(shdr[curShdr->sh_info]);
+
+ if (curShdr->sh_type == SHT_REL && // Check for a relocation section
+ curShdr->sh_entsize == sizeof(Elf32_Rel) && // Check for proper relocation size
+ (int)curShdr->sh_link == _symtab_sect && // Check that the sh_link connects to our symbol table
+ curShdr->sh_info < ehdr->e_shnum && // Check that the relocated section exists
+ (shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) { // Check if relocated section resides in memory
+ if (!ShortsMan.inGeneralSegment((char *)shdr[curShdr->sh_info].sh_addr)) { // regular segment
+ if (!relocate(DLFile, curShdr->sh_offset, curShdr->sh_size, _segment)) {
+ return false;
+ }
+ } else { // In Shorts segment
+ if (!relocate(DLFile, curShdr->sh_offset, curShdr->sh_size, (void *)_shortsSegment->getOffset())) {
+ return false;
+ }
+ }
+
+ }
+ }
+
+ return true;
+}
+
+void MIPSDLObject::relocateSymbols(Elf32_Addr offset) {
+
+ int mainCount = 0;
+ int shortsCount= 0;
+
+ // Loop over symbols, add relocation offset
+ Elf32_Sym *s = (Elf32_Sym *)_symtab;
+ for (int c = _symbol_cnt; c--; s++) {
+
+ // Make sure we don't relocate special valued symbols
+ if (s->st_shndx < SHN_LOPROC) {
+ if (!ShortsMan.inGeneralSegment((char *)s->st_value)) {
+ mainCount++;
+ s->st_value += offset;
+ if (s->st_value < (Elf32_Addr)_segment || s->st_value > (Elf32_Addr)_segment + _segmentSize)
+ seterror("Symbol out of bounds! st_value = %x\n", s->st_value);
+ } else { // shorts section
+ shortsCount++;
+ s->st_value += _shortsSegment->getOffset();
+ if (!_shortsSegment->inSegment((char *)s->st_value))
+ seterror("Symbol out of bounds! st_value = %x\n", s->st_value);
+ }
+
+ }
+ }
+}
+
+bool MIPSDLObject::loadSegment(Common::SeekableReadStream* DLFile, Elf32_Phdr *phdr) {
+
+ char *baseAddress = 0;
+
+ // We need to take account of non-allocated segment for shorts
+ if (phdr->p_flags & PF_X) { // This is a relocated segment
+
+ // Attempt to allocate memory for segment
+ int extra = phdr->p_vaddr % phdr->p_align; // Get extra length TODO: check logic here
+ DBG("extra mem is %x\n", extra);
+
+ if (phdr->p_align < 0x10000) phdr->p_align = 0x10000; // Fix for wrong alignment on e.g. AGI
+
+ if (!(_segment = (char *)memalign(phdr->p_align, phdr->p_memsz + extra))) {
+ seterror("Out of memory.\n");
+ return false;
+ }
+ DBG("allocated segment @ %p\n", _segment);
+
+ // Get offset to load segment into
+ baseAddress = (char *)_segment + phdr->p_vaddr;
+ _segmentSize = phdr->p_memsz + extra;
+ } else { // This is a shorts section.
+ _shortsSegment = ShortsMan.newSegment(phdr->p_memsz, (char *)phdr->p_vaddr);
+
+ baseAddress = _shortsSegment->getStart();
+ DBG("shorts segment @ %p to %p. Segment wants to be at %x. Offset=%x\n",
+ _shortsSegment->getStart(), _shortsSegment->getEnd(), phdr->p_vaddr, _shortsSegment->getOffset());
+ }
+
+ // Set bss segment to 0 if necessary (assumes bss is at the end)
+ if (phdr->p_memsz > phdr->p_filesz) {
+ DBG("Setting %p to %p to 0 for bss\n", baseAddress + phdr->p_filesz, baseAddress + phdr->p_memsz);
+ memset(baseAddress + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz);
+ }
+
+ DBG("Reading the segment into memory\n");
+
+ // Read the segment into memory
+ if (DLFile->seek(phdr->p_offset, SEEK_SET) < 0 ||
+ DLFile->read(baseAddress, phdr->p_filesz) != (ssize_t)phdr->p_filesz) {
+ seterror("Segment load failed.");
+ return false;
+ }
+
+ DBG("Segment has been read into memory\n");
+
+ return true;
+}
+
+// Unload all objects from memory
+void MIPSDLObject::unload() {
+ discard_symtab();
+ free(_segment);
+ _segment = NULL;
+
+ if (_shortsSegment) {
+ ShortsMan.deleteSegment(_shortsSegment);
+ _shortsSegment = NULL;
+ }
+}
+
+#endif /* defined(DYNAMIC_MODULES) && defined(MIPS_TARGET) */
diff --git a/backends/plugins/mips-loader.h b/backends/plugins/mips-loader.h
new file mode 100644
index 0000000000..eb22e368f4
--- /dev/null
+++ b/backends/plugins/mips-loader.h
@@ -0,0 +1,46 @@
+
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "elf-loader.h"
+#include "shorts-segment-manager.h"
+
+class MIPSDLObject : public DLObject {
+protected:
+ ShortSegmentManager::Segment *_shortsSegment; // For assigning shorts ranges
+ unsigned int _gpVal; // Value of Global Pointer
+
+ bool relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment);
+ bool relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr);
+ void relocateSymbols(Elf32_Addr offset);
+ bool loadSegment(Common::SeekableReadStream* DLFile, Elf32_Phdr *phdr);
+ void unload();
+
+public:
+ MIPSDLObject() : DLObject() {
+ _shortsSegment = NULL;
+ _gpVal = 0;
+ }
+};
diff --git a/backends/platform/psp/plugin.syms b/backends/plugins/plugin.syms
index 24ee1a19dc..24ee1a19dc 100644
--- a/backends/platform/psp/plugin.syms
+++ b/backends/plugins/plugin.syms
diff --git a/backends/plugins/ps2/main_prog.ld b/backends/plugins/ps2/main_prog.ld
new file mode 100644
index 0000000000..9dba69c50e
--- /dev/null
+++ b/backends/plugins/ps2/main_prog.ld
@@ -0,0 +1,99 @@
+ENTRY(_start);
+
+SECTIONS {
+ .text 0x00100000: {
+ _ftext = . ;
+ *(.text)
+ *(.text.*)
+ *(.gnu.linkonce.t*)
+ KEEP(*(.init))
+ KEEP(*(.fini))
+ QUAD(0)
+ }
+
+ PROVIDE(_etext = .);
+ PROVIDE(etext = .);
+
+ .reginfo : { *(.reginfo) }
+
+ /* Global/static constructors and deconstructors. */
+ .ctors ALIGN(16): {
+ KEEP(*crtbegin*.o(.ctors))
+ KEEP(*(EXCLUDE_FILE(*crtend*.o) .ctors))
+ KEEP(*(SORT(.ctors.*)))
+ KEEP(*(.ctors))
+ }
+ .dtors ALIGN(16): {
+ KEEP(*crtbegin*.o(.dtors))
+ KEEP(*(EXCLUDE_FILE(*crtend*.o) .dtors))
+ KEEP(*(SORT(.dtors.*)))
+ KEEP(*(.dtors))
+ }
+
+ /* Static data. */
+ .rodata ALIGN(128): {
+ *(.rodata)
+ *(.rodata.*)
+ *(.gnu.linkonce.r*)
+ }
+
+ .data ALIGN(128): {
+ _fdata = . ;
+ *(.data)
+ *(.data.*)
+ *(.gnu.linkonce.d*)
+ SORT(CONSTRUCTORS)
+ }
+
+ .rdata ALIGN(128): { *(.rdata) }
+ .gcc_except_table ALIGN(128): { *(.gcc_except_table) }
+
+ _gp = ALIGN(128) + 0x7ff0;
+ .lit4 ALIGN(128): { *(.lit4) }
+ .lit8 ALIGN(128): { *(.lit8) }
+
+ .sdata ALIGN(128): {
+ *(.sdata)
+ *(.sdata.*)
+ *(.gnu.linkonce.s*)
+ }
+
+ _edata = .;
+ PROVIDE(edata = .);
+
+ /* Uninitialized data. */
+ .sbss ALIGN(128) : {
+ _fbss = . ;
+ *(.sbss)
+ *(.sbss.*)
+ *(.gnu.linkonce.sb*)
+ *(.scommon)
+ }
+
+ /*This "plugin hole" is so the plugins can all have global small data
+ in the same place.*/
+ __plugin_hole_start = .;
+ . = _gp + 0x7ff0;
+ __plugin_hole_end = .;
+
+ COMMON :
+ {
+ *(COMMON)
+ }
+ . = ALIGN(128);
+
+ .bss ALIGN(128) : {
+ *(.bss)
+ *(.bss.*)
+ *(.gnu.linkonce.b*)
+ }
+ _end_bss = .;
+
+ _end = . ;
+ PROVIDE(end = .);
+
+ /* Symbols needed by crt0.s. */
+ PROVIDE(_heap_size = -1);
+ PROVIDE(_stack = -1);
+ PROVIDE(_stack_size = 128 * 1024);
+}
diff --git a/backends/plugins/ps2/plugin.ld b/backends/plugins/ps2/plugin.ld
new file mode 100644
index 0000000000..9879413b98
--- /dev/null
+++ b/backends/plugins/ps2/plugin.ld
@@ -0,0 +1,94 @@
+/* PHDRS specifies ELF Program Headers (or segments) to the plugin linker */
+PHDRS {
+ plugin PT_LOAD ; /* Specifies that the plugin segment should be loaded from file */
+ shorts PT_LOAD ; /* Specifies that the shorts segment should be loaded from file */
+}
+SECTIONS {
+ .text 0: {
+ _ftext = . ;
+ *(.text)
+ *(.text.*)
+ *(.gnu.linkonce.t*)
+ KEEP(*(.init))
+ KEEP(*(.fini))
+ QUAD(0)
+ } : plugin /*The ": plugin" tells the linker to assign this and
+ the following sections to the "plugin" segment*/
+ PROVIDE(_etext = .);
+ PROVIDE(etext = .);
+
+ .reginfo : { *(.reginfo) }
+
+ /* Global/static constructors and deconstructors. */
+ .ctors ALIGN(16): {
+ ___plugin_ctors = .;
+ KEEP(*(SORT(.ctors.*)))
+ KEEP(*(.ctors))
+ ___plugin_ctors_end = .;
+ }
+ .dtors ALIGN(16): {
+ ___plugin_dtors = .;
+ KEEP(*(SORT(.dtors.*)))
+ KEEP(*(.dtors))
+ ___plugin_dtors_end = .;
+ }
+
+ /* Static data. */
+ .rodata ALIGN(128): {
+ *(.rodata)
+ *(.rodata.*)
+ *(.gnu.linkonce.r*)
+ }
+
+ .data ALIGN(128): {
+ _fdata = . ;
+ *(.data)
+ *(.data.*)
+ *(.gnu.linkonce.d*)
+ SORT(CONSTRUCTORS)
+ }
+
+ .rdata ALIGN(128): { *(.rdata) }
+ .gcc_except_table ALIGN(128): { *(.gcc_except_table) }
+
+ .bss ALIGN(128) : {
+ *(.bss)
+ *(.bss.*)
+ *(.gnu.linkonce.b*)
+ *(COMMON)
+ }
+ _end_bss = .;
+
+ _end = . ;
+ PROVIDE(end = .);
+
+ /* Symbols needed by crt0.s. */
+ PROVIDE(_heap_size = -1);
+ PROVIDE(_stack = -1);
+ PROVIDE(_stack_size = 128 * 1024);
+
+ /*We assign the output location counter to the plugin hole made
+ in main_prog.ld, then assign the small data sections to the shorts segment*/
+ . = __plugin_hole_start;
+ .lit4 ALIGN(128): { *(.lit4) } : shorts
+ .lit8 ALIGN(128): { *(.lit8) }
+
+ .sdata ALIGN(128): {
+ *(.sdata)
+ *(.sdata.*)
+ *(.gnu.linkonce.s*)
+ }
+
+ _edata = .;
+ PROVIDE(edata = .);
+
+ /* Uninitialized data. */
+ .sbss ALIGN(128) : {
+ _fbss = . ;
+ *(.sbss)
+ *(.sbss.*)
+ *(.gnu.linkonce.sb*)
+ *(.scommon)
+ }
+
+}
diff --git a/backends/plugins/ps2/ps2-provider.cpp b/backends/plugins/ps2/ps2-provider.cpp
new file mode 100644
index 0000000000..096c6d4050
--- /dev/null
+++ b/backends/plugins/ps2/ps2-provider.cpp
@@ -0,0 +1,44 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(DYNAMIC_MODULES) && defined(__PLAYSTATION2__)
+
+#include "backends/plugins/mips-loader.h"
+#include "backends/plugins/elf-provider.h"
+#include "backends/plugins/ps2/ps2-provider.h"
+
+
+class PS2Plugin : public ELFPlugin {
+public:
+ PS2Plugin(const Common::String &filename) : ELFPlugin(filename) {}
+
+ DLObject *makeDLObject() { return new MIPSDLObject(); }
+};
+
+Plugin* PS2PluginProvider::createPlugin(const Common::FSNode &node) const {
+ return new PS2Plugin(node.getPath());
+}
+
+#endif // defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET)
diff --git a/backends/plugins/ps2/ps2-provider.h b/backends/plugins/ps2/ps2-provider.h
new file mode 100644
index 0000000000..28a2321c29
--- /dev/null
+++ b/backends/plugins/ps2/ps2-provider.h
@@ -0,0 +1,31 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "backends/plugins/elf-provider.h"
+
+class PS2PluginProvider : public ELFPluginProvider {
+ Plugin* createPlugin(const Common::FSNode &node) const;
+};
+
diff --git a/backends/platform/psp/plugin.ld b/backends/plugins/psp/plugin.ld
index db4df45264..db4df45264 100644
--- a/backends/platform/psp/plugin.ld
+++ b/backends/plugins/psp/plugin.ld
diff --git a/backends/plugins/psp/psp-provider.cpp b/backends/plugins/psp/psp-provider.cpp
index 5760424cbf..99aa33c123 100644
--- a/backends/plugins/psp/psp-provider.cpp
+++ b/backends/plugins/psp/psp-provider.cpp
@@ -25,86 +25,20 @@
#if defined(DYNAMIC_MODULES) && defined(__PSP__)
+#include "backends/plugins/mips-loader.h"
+#include "backends/plugins/elf-provider.h"
#include "backends/plugins/psp/psp-provider.h"
-#include "backends/plugins/dynamic-plugin.h"
-#include "common/fs.h"
-#include "backends/platform/psp/psploader.h"
-
-#include "backends/platform/psp/trace.h"
-
-
-class PSPPlugin : public DynamicPlugin {
-protected:
- void *_dlHandle;
- Common::String _filename;
-
- virtual VoidFunc findSymbol(const char *symbol) {
- void *func = dlsym(_dlHandle, symbol);
- if (!func)
- warning("Failed loading symbol '%s' from plugin '%s' (%s)", symbol, _filename.c_str(), dlerror());
-
- // FIXME HACK: This is a HACK to circumvent a clash between the ISO C++
- // standard and POSIX: ISO C++ disallows casting between function pointers
- // and data pointers, but dlsym always returns a void pointer. For details,
- // see e.g. <http://www.trilithium.com/johan/2004/12/problem-with-dlsym/>.
- assert(sizeof(VoidFunc) == sizeof(func));
- VoidFunc tmp;
- memcpy(&tmp, &func, sizeof(VoidFunc));
- return tmp;
- }
+class PSPPlugin : public ELFPlugin {
public:
- PSPPlugin(const Common::String &filename)
- : _dlHandle(0), _filename(filename) {}
-
- ~PSPPlugin() {
- if (_dlHandle) unloadPlugin();
- }
-
- bool loadPlugin() {
- assert(!_dlHandle);
- _dlHandle = dlopen(_filename.c_str(), RTLD_LAZY);
-
- if (!_dlHandle) {
- warning("Failed loading plugin '%s' (%s)", _filename.c_str(), dlerror());
- return false;
- }
+ PSPPlugin(const Common::String &filename) : ELFPlugin(filename) {}
- bool ret = DynamicPlugin::loadPlugin();
-
- if (ret)
- dlforgetsyms(_dlHandle);
-
- return ret;
- }
-
- void unloadPlugin() {
- DynamicPlugin::unloadPlugin();
- if (_dlHandle) {
- if (dlclose(_dlHandle) != 0)
- warning("Failed unloading plugin '%s' (%s)", _filename.c_str(), dlerror());
- _dlHandle = 0;
- }
- }
+ DLObject *makeDLObject() { return new MIPSDLObject(); }
};
-
Plugin* PSPPluginProvider::createPlugin(const Common::FSNode &node) const {
return new PSPPlugin(node.getPath());
}
-bool PSPPluginProvider::isPluginFilename(const Common::FSNode &node) const {
- // Check the plugin suffix
- Common::String filename = node.getName();
- PSP_DEBUG_PRINT("Testing name %s", filename.c_str());
- if (!filename.hasSuffix(".PLG") && !filename.hasSuffix(".plg")) {
- PSP_DEBUG_PRINT(" fail.\n");
- return false;
- }
-
- PSP_DEBUG_PRINT(" success!\n");
- return true;
-}
-
#endif // defined(DYNAMIC_MODULES) && defined(__PSP__)
diff --git a/backends/plugins/psp/psp-provider.h b/backends/plugins/psp/psp-provider.h
index d6c44c5a85..c4debc7997 100644
--- a/backends/plugins/psp/psp-provider.h
+++ b/backends/plugins/psp/psp-provider.h
@@ -26,16 +26,12 @@
#ifndef BACKENDS_PLUGINS_PSP_PSP_PROVIDER_H
#define BACKENDS_PLUGINS_PSP_PSP_PROVIDER_H
-#include "base/plugins.h"
+#include "backends/plugins/elf-provider.h"
#if defined(DYNAMIC_MODULES) && defined(__PSP__)
-class PSPPluginProvider : public FilePluginProvider {
-protected:
+class PSPPluginProvider : public ELFPluginProvider {
Plugin* createPlugin(const Common::FSNode &node) const;
-
- bool isPluginFilename(const Common::FSNode &node) const;
-
};
#endif // defined(DYNAMIC_MODULES) && defined(__PSP__)
diff --git a/backends/plugins/shorts-segment-manager.cpp b/backends/plugins/shorts-segment-manager.cpp
new file mode 100644
index 0000000000..2376759919
--- /dev/null
+++ b/backends/plugins/shorts-segment-manager.cpp
@@ -0,0 +1,89 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(DYNAMIC_MODULES) && defined(MIPS_TARGET)
+
+#include "shorts-segment-manager.h"
+
+extern char __plugin_hole_start; // Indicates start of hole in program file for shorts
+extern char __plugin_hole_end; // Indicates end of hole in program file
+extern char _gp[]; // Value of gp register
+
+#ifdef DEBUG_PLUGINS
+#define DBG(x,...) printf(x, ## __VA_ARGS__)
+#else
+#define DBG(x,...)
+#endif
+
+#define seterror(x,...) printf(x, ## __VA_ARGS__)
+
+DECLARE_SINGLETON(ShortSegmentManager); // For singleton
+
+ShortSegmentManager::ShortSegmentManager() {
+ _shortsStart = &__plugin_hole_start ; //shorts segment begins at the plugin hole we made when linking
+ _shortsEnd = &__plugin_hole_end; //and ends at the end of that hole.
+}
+
+ShortSegmentManager::Segment *ShortSegmentManager::newSegment(int size, char *origAddr) {
+ char *lastAddress = origAddr;
+ Common::List<Segment *>::iterator i;
+
+ // Find a block that fits, starting from the beginning
+ for (i = _list.begin(); i != _list.end(); ++i) {
+ char *currAddress = (*i)->getStart();
+
+ if ((int)(currAddress - lastAddress) >= size) break;
+
+ lastAddress = (*i)->getEnd();
+ }
+
+ if ((Elf32_Addr)lastAddress & 3)
+ lastAddress += 4 - ((Elf32_Addr)lastAddress & 3); // Round up to multiple of 4
+
+ if (lastAddress + size > _shortsEnd) {
+ seterror("Error. No space in shorts segment for %x bytes. Last address is %p, max address is %p.\n",
+ size, lastAddress, _shortsEnd);
+ return NULL;
+ }
+
+ Segment *seg = new Segment(lastAddress, size, origAddr); // Create a new segment
+
+ if (lastAddress + size > _highestAddress) _highestAddress = lastAddress + size; // Keep track of maximum
+
+ _list.insert(i, seg);
+
+ DBG("Shorts segment size %x allocated. End = %p. Remaining space = %x. Highest so far is %p.\n",
+ size, lastAddress + size, _shortsEnd - _list.back()->getEnd(), _highestAddress);
+
+ return seg;
+}
+
+void ShortSegmentManager::deleteSegment(ShortSegmentManager::Segment *seg) {
+ DBG("Deleting shorts segment from %p to %p.\n\n", seg->getStart(), seg->getEnd());
+ _list.remove(seg);
+ delete seg;
+}
+
+#endif /* DYNAMIC_MODULES && MIPS_TARGET */
diff --git a/backends/platform/psp/psploader.h b/backends/plugins/shorts-segment-manager.h
index 13dcf6ef98..54a13d88e1 100644
--- a/backends/platform/psp/psploader.h
+++ b/backends/plugins/shorts-segment-manager.h
@@ -23,17 +23,21 @@
*
*/
-#ifndef PSPLOADER_H
-#define PSPLOADER_H
+#ifndef SHORTS_SEGMENT_MANAGER_H
+#define SHORTS_SEGMENT_MANAGER_H
-#include "elf32.h"
-#include "common/list.h"
#include "common/singleton.h"
+#include "common/list.h"
+#include "elf32.h"
-#define MAXDLERRLEN 80
-
-#define ShortsMan ShortSegmentManager::instance()
+#define ShortsMan ShortSegmentManager::instance()
+/**
+ * Manages the segments of small data put in the gp-relative area for MIPS processors,
+ * and lets these segments be handled differently in the ELF loader.
+ * Since there's no true dynamic linker to change the GP register between plugins and the main engine,
+ * custom linker scripts ensure the GP-area is in the same place for both.
+ */
class ShortSegmentManager : public Common::Singleton<ShortSegmentManager> {
private:
char *_shortsStart;
@@ -43,6 +47,8 @@ public:
char *getShortsStart() {
return _shortsStart;
}
+
+ // Returns whether or not an absolute address is in the GP-relative section.
bool inGeneralSegment(char *addr) {
return ((char *)addr >= _shortsStart && (char *)addr < _shortsEnd);
}
@@ -80,58 +86,4 @@ private:
char *_highestAddress;
};
-
-
-
-class DLObject {
-protected:
- char *_errbuf; /* For error messages, at least MAXDLERRLEN in size */
-
- ShortSegmentManager::Segment *_shortsSegment; // For assigning shorts ranges
- void *_segment, *_symtab;
- char *_strtab;
- int _symbol_cnt;
- int _symtab_sect;
- void *_dtors_start, *_dtors_end;
-
- unsigned int _gpVal; // Value of Global Pointer
- int _segmentSize;
-
- void seterror(const char *fmt, ...);
- void unload();
- bool relocate(int fd, unsigned long offset, unsigned long size, void *);
- bool load(int fd);
-
- bool readElfHeader(int fd, Elf32_Ehdr *ehdr);
- bool readProgramHeaders(int fd, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num);
- bool loadSegment(int fd, Elf32_Phdr *phdr);
- Elf32_Shdr *loadSectionHeaders(int fd, Elf32_Ehdr *ehdr);
- int loadSymbolTable(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr);
- bool loadStringTable(int fd, Elf32_Shdr *shdr);
- void relocateSymbols(Elf32_Addr offset, Elf32_Addr shortsOffset);
- bool relocateRels(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr);
-
-public:
- bool open(const char *path);
- bool close();
- void *symbol(const char *name);
- void discard_symtab();
-
- DLObject(char *errbuf = NULL) : _errbuf(_errbuf), _shortsSegment(NULL), _segment(NULL), _symtab(NULL),
- _strtab(NULL), _symbol_cnt(0), _symtab_sect(-1), _dtors_start(NULL), _dtors_end(NULL), _gpVal(0) ,
- _segmentSize(0) {}
-};
-
-
-
-#define RTLD_LAZY 0
-
-extern "C" {
- void *dlopen(const char *filename, int flags);
- int dlclose(void *handle);
- void *dlsym(void *handle, const char *symbol);
- const char *dlerror();
- void dlforgetsyms(void *handle);
-}
-
-#endif /* PSPLOADER_H */
+#endif /* SHORTS_SEGMENT_MANAGER_H */
diff --git a/backends/saves/default/default-saves.cpp b/backends/saves/default/default-saves.cpp
index 1ab898d2d6..55aa469309 100644
--- a/backends/saves/default/default-saves.cpp
+++ b/backends/saves/default/default-saves.cpp
@@ -131,11 +131,11 @@ bool DefaultSaveFileManager::removeSavefile(const Common::String &filename) {
// There is a nicely portable workaround, too: Make this method overloadable.
if (remove(file.getPath().c_str()) != 0) {
#ifndef _WIN32_WCE
- if (errno == EACCES)
+ if (errno == EACCES)
setError(Common::kWritePermissionDenied, "Search or write permission denied: "+file.getName());
if (errno == ENOENT)
- setError(Common::kPathDoesNotExist, "removeSavefile: '"+file.getName()+"' does not exist or path is invalid");
+ setError(Common::kPathDoesNotExist, "removeSavefile: '"+file.getName()+"' does not exist or path is invalid");
#endif
return false;
} else {
diff --git a/base/commandLine.cpp b/base/commandLine.cpp
index 2f4e78fd80..e36ddfca54 100644
--- a/base/commandLine.cpp
+++ b/base/commandLine.cpp
@@ -598,9 +598,7 @@ static void listTargets() {
}
/** List all saves states for the given target. */
-static Common::Error listSaves(const char *target) {
- Common::Error result = Common::kNoError;
-
+static void listSaves(const char *target) {
// FIXME HACK
g_system->initBackend();
@@ -625,14 +623,13 @@ static Common::Error listSaves(const char *target) {
GameDescriptor game = EngineMan.findGame(gameid, &plugin);
if (!plugin) {
- warning("Could not find any plugin to handle target '%s' (gameid '%s')", target, gameid.c_str());
- return Common::kPluginNotFound;
+ error("Could not find any plugin to handle target '%s' (gameid '%s')", target, gameid.c_str());
+ return;
}
if (!(*plugin)->hasFeature(MetaEngine::kSupportsListSaves)) {
// TODO: Include more info about the target (desc, engine name, ...) ???
printf("ScummVM does not support listing save states for target '%s' (gameid '%s') .\n", target, gameid.c_str());
- result = Common::kPluginNotSupportSaves;
} else {
// Query the plugin for a list of savegames
SaveStateList saveList = (*plugin)->listSaves(target);
@@ -642,9 +639,6 @@ static Common::Error listSaves(const char *target) {
printf(" Slot Description \n"
" ---- ------------------------------------------------------\n");
- if (saveList.size() == 0)
- result = Common::kNoSavesError;
-
for (SaveStateList::const_iterator x = saveList.begin(); x != saveList.end(); ++x) {
printf(" %-4s %s\n", x->save_slot().c_str(), x->description().c_str());
// TODO: Could also iterate over the full hashmap, printing all key-value pairs
@@ -653,8 +647,6 @@ static Common::Error listSaves(const char *target) {
// Revert to the old active domain
ConfMan.setActiveDomain(oldDomain);
-
- return result;
}
/** Lists all usable themes */
@@ -867,7 +859,7 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha
#endif // DISABLE_COMMAND_LINE
-Common::Error processSettings(Common::String &command, Common::StringMap &settings) {
+bool processSettings(Common::String &command, Common::StringMap &settings) {
#ifndef DISABLE_COMMAND_LINE
@@ -876,33 +868,34 @@ Common::Error processSettings(Common::String &command, Common::StringMap &settin
// have been loaded.
if (command == "list-targets") {
listTargets();
- return Common::kNoError;
+ return false;
} else if (command == "list-games") {
listGames();
- return Common::kNoError;
+ return false;
} else if (command == "list-saves") {
- return listSaves(settings["list-saves"].c_str());
+ listSaves(settings["list-saves"].c_str());
+ return false;
} else if (command == "list-themes") {
listThemes();
- return Common::kNoError;
+ return false;
} else if (command == "version") {
printf("%s\n", gScummVMFullVersion);
printf("Features compiled in: %s\n", gScummVMFeatures);
- return Common::kNoError;
+ return false;
} else if (command == "help") {
printf(HELP_STRING, s_appName);
- return Common::kNoError;
+ return false;
}
#ifdef DETECTOR_TESTING_HACK
else if (command == "test-detector") {
runDetectorTest();
- return Common::kNoError;
+ return false;
}
#endif
#ifdef UPGRADE_ALL_TARGETS_HACK
else if (command == "upgrade-targets") {
upgradeTargets();
- return Common::kNoError;
+ return false;
}
#endif
@@ -974,7 +967,7 @@ Common::Error processSettings(Common::String &command, Common::StringMap &settin
ConfMan.set(key, value, Common::ConfigManager::kTransientDomain);
}
- return Common::kArgumentNotProcessed;
+ return true;
}
} // End of namespace Base
diff --git a/base/commandLine.h b/base/commandLine.h
index c7e8d8b0d0..8801ed17d8 100644
--- a/base/commandLine.h
+++ b/base/commandLine.h
@@ -33,7 +33,7 @@ namespace Base {
void registerDefaults();
Common::String parseCommandLine(Common::StringMap &settings, int argc, const char * const *argv);
-Common::Error processSettings(Common::String &command, Common::StringMap &settings);
+bool processSettings(Common::String &command, Common::StringMap &settings);
} // End of namespace Base
diff --git a/base/main.cpp b/base/main.cpp
index e651456ace..08d59aafab 100644
--- a/base/main.cpp
+++ b/base/main.cpp
@@ -105,8 +105,13 @@ static const EnginePlugin *detectPlugin() {
// Query the plugins and find one that will handle the specified gameid
printf("User picked target '%s' (gameid '%s')...\n", ConfMan.getActiveDomainName().c_str(), gameid.c_str());
printf("%s", " Looking for a plugin supporting this gameid... ");
- GameDescriptor game = EngineMan.findGame(gameid, &plugin);
+#if defined(NEW_PLUGIN_DESIGN_FIRST_REFINEMENT) && defined(DYNAMIC_MODULES)
+ GameDescriptor game = EngineMan.findGameOnePlugAtATime(gameid, &plugin);
+#else
+ GameDescriptor game = EngineMan.findGame(gameid, &plugin);
+#endif
+
if (plugin == 0) {
printf("failed\n");
warning("%s is an invalid gameid. Use the --list-games option to list supported gameid", gameid.c_str());
@@ -339,8 +344,12 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) {
settings.erase("debugflags");
}
+#if defined(NEW_PLUGIN_DESIGN_FIRST_REFINEMENT) && defined(DYNAMIC_MODULES) //note: I'm going to refactor this name later :P
+ // Don't load the plugins initially in this case.
+#else
// Load the plugins.
PluginManager::instance().loadPlugins();
+#endif
// If we received an invalid music parameter via command line we check this here.
// We can't check this before loading the music plugins.
@@ -354,10 +363,8 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) {
// Process the remaining command line settings. Must be done after the
// config file and the plugins have been loaded.
- Common::Error res;
-
- if ((res = Base::processSettings(command, settings)) != Common::kArgumentNotProcessed)
- return res;
+ if (!Base::processSettings(command, settings))
+ return 0;
// Init the backend. Must take place after all config data (including
// the command line params) was read.
@@ -383,7 +390,7 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) {
// Unless a game was specified, show the launcher dialog
if (0 == ConfMan.getActiveDomain())
launcherDialog();
-
+
// FIXME: We're now looping the launcher. This, of course, doesn't
// work as well as it should. In theory everything should be destroyed
// cleanly, so this is now enabled to encourage people to fix bits :)
diff --git a/base/plugins.cpp b/base/plugins.cpp
index 5d0be11065..61cc747a41 100644
--- a/base/plugins.cpp
+++ b/base/plugins.cpp
@@ -302,6 +302,31 @@ void PluginManager::addPluginProvider(PluginProvider *pp) {
_providers.push_back(pp);
}
+bool PluginManager::loadFirstPlugin() { //TODO: only deal with engine plugins here, and have a separate "loadNonEnginePlugins" function.
+ unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL);
+ PluginList plugs;
+ for (ProviderList::iterator pp = _providers.begin();
+ pp != _providers.end();
+ ++pp) {
+ PluginList pl((*pp)->getPlugins());
+ for (PluginList::iterator p = pl.begin(); p != pl.end(); ++p) {
+ plugs.push_back(*p);
+ }
+ }
+ _pluginsEnd = plugs.end();
+ _currentPlugin = plugs.begin();
+ if (plugs.empty()) return false; //return false if there are no plugins to load.
+ return tryLoadPlugin(*_currentPlugin);
+}
+
+bool PluginManager::loadNextPlugin() {
+ // To ensure only one engine plugin is loaded at a time, we unload all engine plugins before loading a new one.
+ unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL);
+ ++_currentPlugin;
+ if (_currentPlugin == _pluginsEnd) return false; //return false if already reached the end of list of plugins.
+ return tryLoadPlugin(*_currentPlugin);
+}
+
void PluginManager::loadPlugins() {
for (ProviderList::iterator pp = _providers.begin();
pp != _providers.end();
@@ -309,7 +334,6 @@ void PluginManager::loadPlugins() {
PluginList pl((*pp)->getPlugins());
Common::for_each(pl.begin(), pl.end(), Common::bind1st(Common::mem_fun(&PluginManager::tryLoadPlugin), this));
}
-
}
void PluginManager::unloadPlugins() {
@@ -340,7 +364,7 @@ bool PluginManager::tryLoadPlugin(Plugin *plugin) {
// The plugin is valid, see if it provides the same module as an
// already loaded one and should replace it.
bool found = false;
-
+ printf("Plugin loaded is %s\n", plugin->getName());
PluginList::iterator pl = _plugins[plugin->getType()].begin();
while (!found && pl != _plugins[plugin->getType()].end()) {
if (!strcmp(plugin->getName(), (*pl)->getName())) {
@@ -366,13 +390,24 @@ bool PluginManager::tryLoadPlugin(Plugin *plugin) {
}
}
-
// Engine plugins
#include "engines/metaengine.h"
DECLARE_SINGLETON(EngineManager)
+GameDescriptor EngineManager::findGameOnePlugAtATime(const Common::String &gameName, const EnginePlugin **plugin) const {
+ GameDescriptor result;
+ PluginManager::instance().loadFirstPlugin();
+ do {
+ result = findGame(gameName, plugin);
+ if (!result.gameid().empty()) {
+ break;
+ }
+ } while (PluginManager::instance().loadNextPlugin());
+ return result;
+}
+
GameDescriptor EngineManager::findGame(const Common::String &gameName, const EnginePlugin **plugin) const {
// Find the GameDescriptor for this target
const EnginePlugin::List &plugins = getPlugins();
@@ -381,30 +416,36 @@ GameDescriptor EngineManager::findGame(const Common::String &gameName, const Eng
if (plugin)
*plugin = 0;
- EnginePlugin::List::const_iterator iter = plugins.begin();
- for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
- result = (**iter)->findGame(gameName.c_str());
- if (!result.gameid().empty()) {
- if (plugin)
- *plugin = *iter;
- break;
+ EnginePlugin::List::const_iterator iter;
+
+ for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
+ result = (**iter)->findGame(gameName.c_str());
+ if (!result.gameid().empty()) {
+ if (plugin)
+ *plugin = *iter;
+ return result;
+ }
}
- }
return result;
}
GameList EngineManager::detectGames(const Common::FSList &fslist) const {
GameList candidates;
-
- const EnginePlugin::List &plugins = getPlugins();
-
- // Iterate over all known games and for each check if it might be
- // the game in the presented directory.
+ EnginePlugin::List plugins;
EnginePlugin::List::const_iterator iter;
- for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
- candidates.push_back((**iter)->detectGames(fslist));
- }
-
+#if defined(NEW_PLUGIN_DESIGN_FIRST_REFINEMENT) && defined(DYNAMIC_MODULES)
+ PluginManager::instance().loadFirstPlugin();
+ do {
+#endif
+ plugins = getPlugins();
+ // Iterate over all known games and for each check if it might be
+ // the game in the presented directory.
+ for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
+ candidates.push_back((**iter)->detectGames(fslist));
+ }
+#if defined(NEW_PLUGIN_DESIGN_FIRST_REFINEMENT) && defined(DYNAMIC_MODULES)
+ } while (PluginManager::instance().loadNextPlugin());
+#endif
return candidates;
}
diff --git a/base/plugins.h b/base/plugins.h
index a4c7f114f9..975c815783 100644
--- a/base/plugins.h
+++ b/base/plugins.h
@@ -275,9 +275,11 @@ class PluginManager : public Common::Singleton<PluginManager> {
private:
PluginList _plugins[PLUGIN_TYPE_MAX];
ProviderList _providers;
-
+ PluginList::iterator _currentPlugin;
+ PluginList::iterator _pluginsEnd;
+
bool tryLoadPlugin(Plugin *plugin);
-
+
friend class Common::Singleton<SingletonBaseType>;
PluginManager();
@@ -286,6 +288,9 @@ public:
void addPluginProvider(PluginProvider *pp);
+ bool loadFirstPlugin();
+ bool loadNextPlugin();
+
void loadPlugins();
void unloadPlugins();
void unloadPluginsExcept(PluginType type, const Plugin *plugin);
diff --git a/common/error.h b/common/error.h
index 58343114a2..e79b8d0e91 100644
--- a/common/error.h
+++ b/common/error.h
@@ -59,16 +59,10 @@ enum Error {
kPathNotDirectory, ///< The specified path does not point to a directory
kPathNotFile, ///< The specified path does not point to a file
- kCreatingFileFailed, ///< Failed creating a (savestate) file
- kReadingFailed, ///< Failed to read a file (permission denied?)
+ kCreatingFileFailed,
+ kReadingFailed, ///< Failed creating a (savestate) file
kWritingFailed, ///< Failure to write data -- disk full?
- // The following are used by --list-saves
- kPluginNotFound, ///< Failed to find plugin to handle tager
- kPluginNotSupportSaves, ///< Failed if plugin does not support saves
- kNoSavesError, ///< There are no saves to show
-
- kArgumentNotProcessed, ///< Used in command line parsing
kUnknownError ///< Catch-all error, used if no other error code matches
};
diff --git a/common/macresman.cpp b/common/macresman.cpp
index df7351d55a..4b726a183d 100644
--- a/common/macresman.cpp
+++ b/common/macresman.cpp
@@ -439,11 +439,6 @@ Common::SeekableReadStream *MacResManager::getResource(uint32 typeID, uint16 res
_stream->seek(_dataOffset + _resLists[typeNum][resNum].dataOffset);
uint32 len = _stream->readUint32BE();
-
- // Ignore resources with 0 length
- if (!len)
- return 0;
-
return _stream->readStream(len);
}
@@ -453,11 +448,6 @@ Common::SeekableReadStream *MacResManager::getResource(const Common::String &fil
if (_resLists[i][j].nameOffset != -1 && filename.equalsIgnoreCase(_resLists[i][j].name)) {
_stream->seek(_dataOffset + _resLists[i][j].dataOffset);
uint32 len = _stream->readUint32BE();
-
- // Ignore resources with 0 length
- if (!len)
- return 0;
-
return _stream->readStream(len);
}
}
diff --git a/common/str.h b/common/str.h
index e3dec6cdc2..46e721a746 100644
--- a/common/str.h
+++ b/common/str.h
@@ -225,12 +225,6 @@ public:
typedef const char * const_iterator;
iterator begin() {
- // Since the user could potentially
- // change the string via the returned
- // iterator we have to assure we are
- // pointing to a unique storage.
- makeUnique();
-
return _str;
}
diff --git a/common/stream.h b/common/stream.h
index 5e0d7149b0..5c81063a7e 100644
--- a/common/stream.h
+++ b/common/stream.h
@@ -156,7 +156,7 @@ public:
class ReadStream : virtual public Stream {
public:
/**
- * Returns true if a read failed because the stream end has been reached.
+ * Returns true if a read failed because the stream has been reached.
* This flag is cleared by clearErr().
* For a SeekableReadStream, it is also cleared by a successful seek.
*/
diff --git a/common/unzip.cpp b/common/unzip.cpp
index a29518a796..eda42fd107 100644
--- a/common/unzip.cpp
+++ b/common/unzip.cpp
@@ -1472,11 +1472,11 @@ Common::SeekableReadStream *ZipArchive::createReadStreamForMember(const Common::
unz_file_info fileInfo;
unzOpenCurrentFile(_zipFile);
unzGetCurrentFileInfo(_zipFile, &fileInfo, NULL, 0, NULL, 0, NULL, 0);
- byte *buffer = (byte *)malloc(fileInfo.uncompressed_size);
+ byte *buffer = (byte *)calloc(fileInfo.uncompressed_size+1, 1);
assert(buffer);
unzReadCurrentFile(_zipFile, buffer, fileInfo.uncompressed_size);
unzCloseCurrentFile(_zipFile);
- return new Common::MemoryReadStream(buffer, fileInfo.uncompressed_size, DisposeAfterUse::YES);
+ return new Common::MemoryReadStream(buffer, fileInfo.uncompressed_size+1, DisposeAfterUse::YES);
// FIXME: instead of reading all into a memory stream, we could
// instead create a new ZipStream class. But then we have to be
diff --git a/configure b/configure
index db01465db0..5bfeba769d 100755
--- a/configure
+++ b/configure
@@ -1628,10 +1628,6 @@ if test -n "$_host"; then
_ar="$_host-ar cru"
_ranlib=$_host-ranlib
;;
- mips-sgi*)
- _endian=big
- _need_memalign=yes
- ;;
motoezx)
DEFINES="$DEFINES -DMOTOEZX"
ASFLAGS="$ASFLAGS -mfpu=vfp"
@@ -1996,6 +1992,23 @@ PRE_OBJS_FLAGS := -Wl,--whole-archive
POST_OBJS_FLAGS := -Wl,--export-all-symbols -Wl,--no-whole-archive -Wl,--out-implib,./libscummvm.a
'
;;
+ ps2)
+_def_plugin='
+#define PLUGIN_PREFIX ""
+#define PLUGIN_SUFFIX ".plg"
+'
+_mak_plugins='
+DYNAMIC_MODULES := 1
+PLUGIN_PREFIX :=
+PLUGIN_SUFFIX := .plg
+PLUGIN_EXTRA_DEPS = $(EXECUTABLE)
+CXXFLAGS += -DDYNAMIC_MODULES
+LDFLAGS += -Wl,-T$(srcdir)/backends/platform/ps2/main_prog.ld
+PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,--just-symbols,$(EXECUTABLE),--retain-symbols-file,$(srcdir)/backends/platform/ps2/plugin.syms,-T$(srcdir)/backends/platform/ps2/plugin.ld -lstdc++ -lc -lm -Wl,-Map,mapfile.txt
+PRE_OBJS_FLAGS := -Wl,--whole-archive
+POST_OBJS_FLAGS := -Wl,--no-whole-archive
+'
+ ;;
psp)
_def_plugin='
#define PLUGIN_PREFIX ""
diff --git a/engines/drascula/animation.cpp b/engines/drascula/animation.cpp
index d6a3bafd9f..1d6f77b8eb 100644
--- a/engines/drascula/animation.cpp
+++ b/engines/drascula/animation.cpp
@@ -1695,7 +1695,7 @@ void DrasculaEngine::animation_9_6() {
// We set the room number to -1 for the same purpose.
// Also check animation_2_1(), where the same hack was used
// by the original
- roomNumber = -2;
+ roomNumber = -1;
loadPic("nota2.alg", bgSurface, HALF_PAL);
black();
trackProtagonist = 1;
diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp
index 7e9f68a355..b1f16fa505 100644
--- a/engines/drascula/drascula.cpp
+++ b/engines/drascula/drascula.cpp
@@ -88,7 +88,6 @@ DrasculaEngine::DrasculaEngine(OSystem *syst, const DrasculaGameDescription *gam
_textverbs = 0;
_textmisc = 0;
_textd1 = 0;
- _talkSequences = 0;
_color = 0;
blinking = 0;
diff --git a/engines/drascula/objects.cpp b/engines/drascula/objects.cpp
index 73aea7b7f2..08c1a68a55 100644
--- a/engines/drascula/objects.cpp
+++ b/engines/drascula/objects.cpp
@@ -92,8 +92,7 @@ void DrasculaEngine::gotoObject(int pointX, int pointY) {
updateRoom();
updateScreen();
- // roomNumber -2 is end credits. Do not show cursor there
- if (cursorVisible && roomNumber != -2)
+ if (cursorVisible)
showCursor();
}
diff --git a/engines/m4/compression.h b/engines/m4/compression.h
index 00e3d1f927..74fed357ff 100644
--- a/engines/m4/compression.h
+++ b/engines/m4/compression.h
@@ -66,8 +66,8 @@ public:
class FabDecompressor {
private:
- int _bitsLeft;
- uint32 _bitBuffer;
+ int _bitsLeft;
+ uint32 _bitBuffer;
const byte *_srcData, *_srcP;
int _srcSize;
diff --git a/engines/m4/console.cpp b/engines/m4/console.cpp
index 71c70e3e1b..9a92cb04d1 100644
--- a/engines/m4/console.cpp
+++ b/engines/m4/console.cpp
@@ -47,6 +47,7 @@ Console::Console(MadsM4Engine *vm) : GUI::Debugger() {
DCmd_Register("start_conv", WRAP_METHOD(Console, cmdStartConversation));
DCmd_Register("textview", WRAP_METHOD(Console, cmdShowTextview));
DCmd_Register("animview", WRAP_METHOD(Console, cmdShowAnimview));
+ DCmd_Register("anim", WRAP_METHOD(Console, cmdPlayAnimation));
}
Console::~Console() {
@@ -246,6 +247,33 @@ bool Console::cmdShowAnimview(int argc, const char **argv) {
return false;
}
+bool Console::cmdPlayAnimation(int argc, const char **argv) {
+ View *view = _vm->_viewManager->getView(VIEWID_SCENE);
+ if (view == NULL) {
+ DebugPrintf("The scene view isn't currently active\n");
+ } else if (argc != 2 && argc != 3) {
+ DebugPrintf("Usage: %s <anim resource (*.aa)> <fullscreen>\n", argv[0]);
+ DebugPrintf("If fullscreen is 1, the screen palette is replaced with the palette of the animation\n");
+ } else {
+ char resourceName[20];
+ strncpy(resourceName, argv[1], 15);
+ resourceName[15] = '\0';
+ if (!strchr(resourceName, '.'))
+ strcat(resourceName, ".AA");
+
+ _vm->_viewManager->moveToFront(view);
+ if (argc == 3 && atoi(argv[2]) == 1)
+ _vm->_animation->loadFullScreen(resourceName);
+ else
+ _vm->_animation->load(resourceName);
+ _vm->_animation->start();
+ view->restore(0, 0, view->width(), view->height());
+ return false;
+ }
+
+ return true;
+}
+
/*--------------------------------------------------------------------------*/
MadsConsole::MadsConsole(MadsEngine *vm): Console(vm) {
@@ -254,7 +282,6 @@ MadsConsole::MadsConsole(MadsEngine *vm): Console(vm) {
DCmd_Register("object", WRAP_METHOD(MadsConsole, cmdObject));
DCmd_Register("message", WRAP_METHOD(MadsConsole, cmdMessage));
DCmd_Register("scene_info", WRAP_METHOD(MadsConsole, cmdSceneInfo));
- DCmd_Register("anim", WRAP_METHOD(MadsConsole, cmdPlayAnimation));
}
bool MadsConsole::cmdObject(int argc, const char **argv) {
@@ -359,33 +386,6 @@ bool MadsConsole::cmdSceneInfo(int argc, const char **argv) {
return true;
}
-bool MadsConsole::cmdPlayAnimation(int argc, const char **argv) {
- View *view = _vm->_viewManager->getView(VIEWID_SCENE);
- if (view == NULL) {
- DebugPrintf("The scene view isn't currently active\n");
- } else if (argc != 2 && argc != 3) {
- DebugPrintf("Usage: %s <anim resource (*.aa)> <fullscreen>\n", argv[0]);
- DebugPrintf("If fullscreen is 1, the screen palette is replaced with the palette of the animation\n");
- } else {
- char resourceName[20];
- strncpy(resourceName, argv[1], 15);
- resourceName[15] = '\0';
- if (!strchr(resourceName, '.'))
- strcat(resourceName, ".AA");
-
- _vm->_viewManager->moveToFront(view);
- if (argc == 3 && atoi(argv[2]) == 1)
- _madsVm->_palette->deleteAllRanges();
-
- _madsVm->scene()->_sceneAnimation->load(resourceName, 0);
-
- view->restore(0, 0, view->width(), view->height());
- return false;
- }
-
- return true;
-}
-
/*--------------------------------------------------------------------------*/
M4Console::M4Console(M4Engine *vm): Console(vm) {
diff --git a/engines/m4/console.h b/engines/m4/console.h
index 53a47dada9..b592f041cf 100644
--- a/engines/m4/console.h
+++ b/engines/m4/console.h
@@ -50,6 +50,7 @@ private:
bool cmdStartConversation(int argc, const char **argv);
bool cmdShowTextview(int argc, const char **argv);
bool cmdShowAnimview(int argc, const char **argv);
+ bool cmdPlayAnimation(int argc, const char **argv);
public:
Console(MadsM4Engine *vm);
@@ -63,8 +64,6 @@ private:
bool cmdObject(int argc, const char **argv);
bool cmdMessage(int argc, const char **argv);
bool cmdSceneInfo(int argc, const char **argv);
- bool cmdPlayAnimation(int argc, const char **argv);
-
public:
MadsConsole(MadsEngine *vm);
virtual ~MadsConsole() {}
diff --git a/engines/m4/converse.cpp b/engines/m4/converse.cpp
index af26a86313..aab2fc95ce 100644
--- a/engines/m4/converse.cpp
+++ b/engines/m4/converse.cpp
@@ -96,7 +96,7 @@ void ConversationView::setNode(int32 nodeIndex) {
_vm->_font->setFont(FONT_CONVERSATION);
// TODO: Conversation styles and colors
- _vm->_font->current()->setColours(2, 1, 3);
+ _vm->_font->setColors(2, 1, 3);
_currentNodeIndex = nodeIndex;
@@ -124,7 +124,7 @@ void ConversationView::setNode(int32 nodeIndex) {
}
// Figure out the longest string to determine where option highlighting ends
- int tempX = _vm->_font->current()->getWidth(node->entries[i]->text, 0) +
+ int tempX = _vm->_font->getWidth(node->entries[i]->text, 0) +
CONV_ENTRIES_X_OFFSET + 10;
_xEnd = MAX(_xEnd, tempX);
}
@@ -163,10 +163,10 @@ void ConversationView::onRefresh(RectList *rects, M4Surface *destSurface) {
if (i > CONV_MAX_SHOWN_ENTRIES - 1)
break;
- _vm->_font->current()->setColour((_highlightedIndex == i) ? CONVERSATION_ENTRY_HIGHLIGHTED :
+ _vm->_font->setColor((_highlightedIndex == i) ? CONVERSATION_ENTRY_HIGHLIGHTED :
CONVERSATION_ENTRY_NORMAL);
- _vm->_font->current()->writeString(this, _activeItems[i]->text, CONV_ENTRIES_X_OFFSET,
+ _vm->_font->writeString(this, _activeItems[i]->text, CONV_ENTRIES_X_OFFSET,
CONV_ENTRIES_Y_OFFSET + CONV_ENTRIES_HEIGHT * i, 0, 0);
}
}
diff --git a/engines/m4/dialogs.cpp b/engines/m4/dialogs.cpp
index a7104537f5..3af94af262 100644
--- a/engines/m4/dialogs.cpp
+++ b/engines/m4/dialogs.cpp
@@ -127,7 +127,7 @@ void Dialog::writeChars(const char *srcLine) {
strcat(line, wordStr);
lineLen = strlen(line);
- lineWidth = _vm->_font->current()->getWidth(line, DIALOG_SPACING);
+ lineWidth = _vm->_font->getWidth(line, DIALOG_SPACING);
if (((_lineX + lineLen) > _widthChars) || ((_widthX + lineWidth) > _dialogWidth)) {
incLine();
@@ -146,7 +146,7 @@ void Dialog::writeChars(const char *srcLine) {
*/
void Dialog::appendText(const char *line) {
_lineX += strlen(line);
- _widthX += _vm->_font->current()->getWidth(line, DIALOG_SPACING);
+ _widthX += _vm->_font->getWidth(line, DIALOG_SPACING);
strcat(_lines[_lines.size() - 1].data, line);
}
@@ -158,7 +158,7 @@ void Dialog::addLine(const char *line, bool underlineP) {
if ((_widthX > 0) || (_lineX > 0))
incLine();
- int lineWidth = _vm->_font->current()->getWidth(line, DIALOG_SPACING);
+ int lineWidth = _vm->_font->getWidth(line, DIALOG_SPACING);
int lineLen = strlen(line);
if ((lineWidth > _dialogWidth) || (lineLen >= _widthChars))
@@ -383,7 +383,7 @@ Dialog::Dialog(MadsM4Engine *vm, const char *msgData, const char *title): View(v
if (id > 0) {
// Suffix provided - specifies the dialog width in number of chars
_widthChars = id * 2;
- _dialogWidth = id * (_vm->_font->current()->getMaxWidth() + DIALOG_SPACING) + 10;
+ _dialogWidth = id * (_vm->_font->getMaxWidth() + DIALOG_SPACING) + 10;
}
} else if (matchCommand(cmdText, "UNDER")) {
@@ -416,7 +416,7 @@ Dialog::Dialog(MadsM4Engine *vm, const char *msgData, const char *title): View(v
Dialog::Dialog(MadsM4Engine *vm, int widthChars): View(vm, Common::Rect(0, 0, 0, 0)) {
_vm->_font->setFont(FONT_INTERFACE_MADS);
_widthChars = widthChars * 2;
- _dialogWidth = widthChars * (_vm->_font->current()->getMaxWidth() + DIALOG_SPACING) + 10;
+ _dialogWidth = widthChars * (_vm->_font->getMaxWidth() + DIALOG_SPACING) + 10;
_screenType = LAYER_DIALOG;
_lineX = 0;
_widthX = 0;
@@ -439,7 +439,7 @@ void Dialog::draw() {
// Calculate bounds
int dlgWidth = _dialogWidth;
- int dlgHeight = _lines.size() * (_vm->_font->current()->getHeight() + 1) + 10;
+ int dlgHeight = _lines.size() * (_vm->_font->getHeight() + 1) + 10;
int dialogX = (_vm->_screen->width() - dlgWidth) / 2;
int dialogY = (_vm->_screen->height() - dlgHeight) / 2;
@@ -480,26 +480,26 @@ void Dialog::draw() {
}
// Handle drawing the text contents
- _vm->_font->current()->setColours(7, 7, 7);
+ _vm->_font->setColours(7, 7, 7);
setColour(7);
- for (uint lineCtr = 0, yp = 5; lineCtr < _lines.size(); ++lineCtr, yp += _vm->_font->current()->getHeight() + 1) {
+ for (uint lineCtr = 0, yp = 5; lineCtr < _lines.size(); ++lineCtr, yp += _vm->_font->getHeight() + 1) {
if (_lines[lineCtr].barLine) {
// Bar separation line
- hLine(5, width() - 6, ((_vm->_font->current()->getHeight() + 1) >> 1) + yp);
+ hLine(5, width() - 6, ((_vm->_font->getHeight() + 1) >> 1) + yp);
} else {
// Standard line
Common::Point pt(_lines[lineCtr].xp + 5, yp);
if (_lines[lineCtr].xp & 0x40)
++pt.y;
- _vm->_font->current()->writeString(this, _lines[lineCtr].data, pt.x, pt.y, 0, DIALOG_SPACING);
+ _vm->_font->writeString(this, _lines[lineCtr].data, pt.x, pt.y, 0, DIALOG_SPACING);
if (_lines[lineCtr].underline)
// Underline needed
- hLine(pt.x, pt.x + _vm->_font->current()->getWidth(_lines[lineCtr].data, DIALOG_SPACING),
- pt.y + _vm->_font->current()->getHeight());
+ hLine(pt.x, pt.x + _vm->_font->getWidth(_lines[lineCtr].data, DIALOG_SPACING),
+ pt.y + _vm->_font->getHeight());
}
}
@@ -528,7 +528,7 @@ void Dialog::display(MadsM4Engine *vm, int widthChars, const char **descEntries)
dlg->incLine();
dlg->writeChars(*descEntries);
- int lineWidth = vm->_font->current()->getWidth(*descEntries, DIALOG_SPACING);
+ int lineWidth = vm->_font->getWidth(*descEntries, DIALOG_SPACING);
dlg->_lines[dlg->_lines.size() - 1].xp = (dlg->_dialogWidth - 10 - lineWidth) / 2;
++descEntries;
}
diff --git a/engines/m4/globals.h b/engines/m4/globals.h
index 3fc31b4ec2..2bfedf1449 100644
--- a/engines/m4/globals.h
+++ b/engines/m4/globals.h
@@ -276,7 +276,6 @@ public:
// DEPRECATED: ScummVM re-implementation keeps all the quotes loaded, so the methods below are stubs
void clearQuotes() {}
void loadQuoteRange(int startNum, int endNum) {}
- void loadQuoteSet(...) {}
void loadQuote(int quoteNum) {}
void loadMadsMessagesInfo();
diff --git a/engines/m4/gui.cpp b/engines/m4/gui.cpp
index 8665b4e767..8f949de9c5 100644
--- a/engines/m4/gui.cpp
+++ b/engines/m4/gui.cpp
@@ -290,26 +290,26 @@ void MenuButton::onRefresh() {
case OBJTYPE_SL_TEXT:
switch (_objectState) {
case OS_MOUSEOVER:
- _vm->_font->current()->setColours(TEXT_COLOR_MOUSEOVER_SHADOW, TEXT_COLOR_MOUSEOVER_FOREGROUND,
+ _vm->_font->setColors(TEXT_COLOR_MOUSEOVER_SHADOW, TEXT_COLOR_MOUSEOVER_FOREGROUND,
TEXT_COLOR_MOUSEOVER_HILIGHT);
sprite = sprites[SL_LINE_MOUSEOVER];
break;
case OS_PRESSED:
- _vm->_font->current()->setColours(TEXT_COLOR_PRESSED_SHADOW, TEXT_COLOR_PRESSED_FOREGROUND,
+ _vm->_font->setColors(TEXT_COLOR_PRESSED_SHADOW, TEXT_COLOR_PRESSED_FOREGROUND,
TEXT_COLOR_PRESSED_HILIGHT);
sprite = sprites[SL_LINE_PRESSED];
break;
case OS_GREYED:
- _vm->_font->current()->setColours(TEXT_COLOR_GREYED_SHADOW, TEXT_COLOR_GREYED_FOREGROUND,
+ _vm->_font->setColors(TEXT_COLOR_GREYED_SHADOW, TEXT_COLOR_GREYED_FOREGROUND,
TEXT_COLOR_GREYED_HILIGHT);
sprite = sprites[SL_LINE_NORMAL];
break;
default:
case OS_NORMAL:
- _vm->_font->current()->setColours(TEXT_COLOR_NORMAL_SHADOW, TEXT_COLOR_NORMAL_FOREGROUND,
+ _vm->_font->setColors(TEXT_COLOR_NORMAL_SHADOW, TEXT_COLOR_NORMAL_FOREGROUND,
TEXT_COLOR_NORMAL_HILIGHT);
sprite = sprites[SL_LINE_NORMAL];
break;
@@ -849,11 +849,11 @@ void MenuSaveLoadText::onRefresh() {
if (_displayValue != 0) {
char tempBuffer[5];
sprintf(tempBuffer, "%02d", _displayValue);
- _vm->_font->current()->writeString(_parent, tempBuffer, xp, _bounds.top + 1, 0, -1);
+ _vm->_font->writeString(_parent, tempBuffer, xp, _bounds.top + 1, 0, -1);
xp = _bounds.left + 26;
}
- _vm->_font->current()->writeString(_parent, _displayText, xp, _bounds.top + 1, 0, -1);
+ _vm->_font->writeString(_parent, _displayText, xp, _bounds.top + 1, 0, -1);
}
}
@@ -955,18 +955,18 @@ void MenuTextField::onRefresh() {
// Draw the text
_vm->_font->setFont(FONT_MENU);
- _vm->_font->current()->setColours(TEXT_COLOR_NORMAL_SHADOW, TEXT_COLOR_NORMAL_FOREGROUND,
+ _vm->_font->setColors(TEXT_COLOR_NORMAL_SHADOW, TEXT_COLOR_NORMAL_FOREGROUND,
TEXT_COLOR_NORMAL_HILIGHT);
int xp = _bounds.left + 4;
if (_displayValue != 0) {
char tempBuffer[5];
sprintf(tempBuffer, "%02d", _displayValue);
- _vm->_font->current()->writeString(_parent, tempBuffer, xp, _bounds.top + 1, 0, -1);
+ _vm->_font->writeString(_parent, tempBuffer, xp, _bounds.top + 1, 0, -1);
xp = _bounds.left + 26;
}
- _vm->_font->current()->writeString(_parent, _displayText, xp, _bounds.top + 1, 0, -1);
+ _vm->_font->writeString(_parent, _displayText, xp, _bounds.top + 1, 0, -1);
if (focused) {
// Draw in the cursor
@@ -975,7 +975,7 @@ void MenuTextField::onRefresh() {
// Get the width of the string up to the cursor position
char tempCh = *_cursor;
*_cursor = '\0';
- int stringWidth = _vm->_font->current()->getWidth(_displayText);
+ int stringWidth = _vm->_font->getWidth(_displayText);
*_cursor = tempCh;
parent()->setColor(TEXT_COLOR_MOUSEOVER_FOREGROUND);
@@ -1015,10 +1015,10 @@ bool MenuTextField::onEvent(M4EventType event, int32 param, int x, int y, MenuOb
tempP = &tempStr[tempLen];
_vm->_font->setFont(FONT_MENU);
- tempLen = _vm->_font->current()->getWidth(tempStr);
+ tempLen = _vm->_font->getWidth(tempStr);
while ((tempP != &tempStr[0]) && (tempLen > x - _bounds.left - 26)) {
*--tempP = '\0';
- tempLen = _vm->_font->current()->getWidth(tempStr);
+ tempLen = _vm->_font->getWidth(tempStr);
}
_cursor = &_displayText[tempP - &tempStr[0]];
@@ -1098,7 +1098,7 @@ bool MenuTextField::onEvent(M4EventType event, int32 param, int x, int y, MenuOb
parent()->_deleteSaveDesc = false;
_vm->_font->setFont(FONT_MENU);
- tempLen = _vm->_font->current()->getWidth(_displayText);
+ tempLen = _vm->_font->getWidth(_displayText);
if ((strlen(_displayText) < MAX_SAVEGAME_NAME - 1) &&
(tempLen < _pixelWidth - 12) && (param >= 32) && (param <= 127)) {
@@ -1140,9 +1140,9 @@ GUITextField::GUITextField(View *owner, const Common::Rect &bounds): GUIRect(own
void GUITextField::onRefresh() {
_parent->fillRect(_bounds, _vm->_palette->BLACK);
- _vm->_font->current()->setColours(3, 3, 3);
+ _vm->_font->setColors(3, 3, 3);
_vm->_font->setFont(FONT_INTERFACE);
- _vm->_font->current()->writeString(_parent, _text.c_str(), _bounds.left, _bounds.top, 0, 1);
+ _vm->_font->writeString(_parent, _text.c_str(), _bounds.left, _bounds.top, 0, 1);
}
//--------------------------------------------------------------------------
diff --git a/engines/m4/m4.cpp b/engines/m4/m4.cpp
index a999a6bd5a..824896ad33 100644
--- a/engines/m4/m4.cpp
+++ b/engines/m4/m4.cpp
@@ -145,6 +145,7 @@ MadsM4Engine::~MadsM4Engine() {
delete _script;
delete _ws;
delete _random;
+ delete _animation;
delete _palette;
delete _globals;
delete _sound;
@@ -173,7 +174,7 @@ Common::Error MadsM4Engine::run() {
_events = new Events(this);
_kernel = new Kernel(this);
_player = new Player(this);
- _font = new FontManager(this);
+ _font = new Font(this);
if (getGameType() == GType_Burger) {
_actor = new Actor(this);
_conversationView = new ConversationView(this);
@@ -187,6 +188,7 @@ Common::Error MadsM4Engine::run() {
_sound = new Sound(this, _mixer, 255);
_script = new ScriptInterpreter(this);
_ws = new WoodScript(this);
+ _animation = new Animation(this);
//_callbacks = new Callbacks(this);
_random = new Common::RandomSource();
g_eventRec.registerRandomSource(*_random, "m4");
@@ -555,9 +557,9 @@ Common::Error MadsEngine::run() {
_scene->show();
_font->setFont(FONT_MAIN_MADS);
- _font->current()->setColours(2, 1, 3);
- _font->current()->writeString(_scene->getBackgroundSurface(), "Testing the M4/MADS ScummVM engine", 5, 160, 310, 2);
- _font->current()->writeString(_scene->getBackgroundSurface(), "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 5, 180, 310, 2);
+ _font->setColors(2, 1, 3);
+ _font->writeString(_scene->getBackgroundSurface(), "Testing the M4/MADS ScummVM engine", 5, 160, 310, 2);
+ _font->writeString(_scene->getBackgroundSurface(), "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 5, 180, 310, 2);
if (getGameType() == GType_DragonSphere) {
//_scene->showMADSV2TextBox("Test", 10, 10, NULL);
@@ -573,6 +575,8 @@ Common::Error MadsEngine::run() {
while (!_events->quitFlag) {
eventHandler();
+ _animation->updateAnim();
+
if (g_system->getMillis() >= nextFrame) {
nextFrame = g_system->getMillis() + GAME_FRAME_DELAY;
++_currentTimer;
diff --git a/engines/m4/m4.h b/engines/m4/m4.h
index 3174c886d5..9e3035957a 100644
--- a/engines/m4/m4.h
+++ b/engines/m4/m4.h
@@ -192,7 +192,7 @@ public:
Player *_player;
Mouse *_mouse;
Events *_events;
- FontManager *_font;
+ Font *_font;
Actor *_actor;
Scene *_scene;
Dialogs *_dialogs;
@@ -203,6 +203,7 @@ public:
Rails *_rails;
ScriptInterpreter *_script;
WoodScript *_ws;
+ Animation *_animation;
Common::RandomSource *_random;
Scene *scene() { return _scene; }
diff --git a/engines/m4/m4_views.cpp b/engines/m4/m4_views.cpp
index f4345787df..3d633cef0d 100644
--- a/engines/m4/m4_views.cpp
+++ b/engines/m4/m4_views.cpp
@@ -34,7 +34,7 @@ namespace M4 {
GUIInventory::GUIInventory(View *owner, MadsM4Engine *vm, const Common::Rect &bounds, int horizCells,
int vertCells, int cellWidth, int cellHeight, int tag): GUIRect(owner, bounds, tag) {
- _vm = vm;
+ _vm = vm;
_cellCount.x = horizCells;
_cellCount.y = vertCells;
_cellSize.x = cellWidth;
diff --git a/engines/m4/mads_anim.cpp b/engines/m4/mads_anim.cpp
index ca53bdca75..5e19e90533 100644
--- a/engines/m4/mads_anim.cpp
+++ b/engines/m4/mads_anim.cpp
@@ -37,7 +37,7 @@ namespace M4 {
TextviewView::TextviewView(MadsM4Engine *vm):
View(vm, Common::Rect(0, 0, vm->_screen->width(), vm->_screen->height())),
_bgSurface(vm->_screen->width(), MADS_SURFACE_HEIGHT),
- _textSurface(vm->_screen->width(), MADS_SURFACE_HEIGHT + vm->_font->current()->getHeight() +
+ _textSurface(vm->_screen->width(), MADS_SURFACE_HEIGHT + vm->_font->getHeight() +
TEXTVIEW_LINE_SPACING) {
_screenType = VIEWID_TEXTVIEW;
@@ -60,7 +60,7 @@ TextviewView::TextviewView(MadsM4Engine *vm):
_vm->_palette->setPalette(&palData[0], 4, 3);
_vm->_palette->blockRange(4, 3);
- _vm->_font->current()->setColours(5, 6, 4);
+ _vm->_font->setColors(5, 6, 4);
clear();
_bgSurface.clear();
@@ -222,7 +222,7 @@ void TextviewView::updateState() {
}
} else {
// Handling a text row
- if (++_lineY == (_vm->_font->current()->getHeight() + TEXTVIEW_LINE_SPACING))
+ if (++_lineY == (_vm->_font->getHeight() + TEXTVIEW_LINE_SPACING))
processLines();
}
@@ -404,7 +404,7 @@ void TextviewView::processText() {
if (!strcmp(_currentLine, "***")) {
// Special signifier for end of script
- _scrollCount = _vm->_font->current()->getHeight() * 13;
+ _scrollCount = _vm->_font->getHeight() * 13;
_lineY = -1;
return;
}
@@ -416,7 +416,7 @@ void TextviewView::processText() {
char *centerP = strchr(_currentLine, '@');
if (centerP) {
*centerP = '\0';
- xStart = (width() / 2) - _vm->_font->current()->getWidth(_currentLine);
+ xStart = (width() / 2) - _vm->_font->getWidth(_currentLine);
// Delete the @ character and shift back the remainder of the string
char *p = centerP + 1;
@@ -424,16 +424,16 @@ void TextviewView::processText() {
strcpy(centerP, p);
} else {
- lineWidth = _vm->_font->current()->getWidth(_currentLine);
+ lineWidth = _vm->_font->getWidth(_currentLine);
xStart = (width() - lineWidth) / 2;
}
// Copy the text line onto the bottom of the textSurface surface, which will allow it
// to gradually scroll onto the screen
- int yp = _textSurface.height() - _vm->_font->current()->getHeight() - TEXTVIEW_LINE_SPACING;
+ int yp = _textSurface.height() - _vm->_font->getHeight() - TEXTVIEW_LINE_SPACING;
_textSurface.fillRect(Common::Rect(0, yp, _textSurface.width(), _textSurface.height()),
_vm->_palette->BLACK);
- _vm->_font->current()->writeString(&_textSurface, _currentLine, xStart, yp);
+ _vm->_font->writeString(&_textSurface, _currentLine, xStart, yp);
}
diff --git a/engines/m4/mads_menus.cpp b/engines/m4/mads_menus.cpp
index 810acb04fb..1ee6b3d265 100644
--- a/engines/m4/mads_menus.cpp
+++ b/engines/m4/mads_menus.cpp
@@ -617,10 +617,10 @@ void RexDialogView::initialiseLines() {
}
_totalTextEntries = 0;
- // Set up a default sprite slot entry for a full screen refresh
+ // Set up a default sprite slot entry
_spriteSlots.startIndex = 1;
- _spriteSlots[0].spriteType = FULL_SCREEN_REFRESH;
- _spriteSlots[0].seqIndex = -1;
+ _spriteSlots[0].spriteId = -2;
+ _spriteSlots[0].timerIndex = -1;
}
void RexDialogView::initialiseGraphics() {
@@ -796,8 +796,8 @@ bool RexDialogView::onEvent(M4EventType eventType, int32 param1, int x, int y, b
void RexDialogView::setFrame(int frameNumber, int depth) {
int slotIndex = _spriteSlots.getIndex();
- _spriteSlots[slotIndex].spriteType = FOREGROUND_SPRITE;
- _spriteSlots[slotIndex].seqIndex = 1;
+ _spriteSlots[slotIndex].spriteId = 1;
+ _spriteSlots[slotIndex].timerIndex = 1;
_spriteSlots[slotIndex].spriteListIndex = 0; //_menuSpritesIndex;
_spriteSlots[slotIndex].frameNumber = frameNumber;
@@ -986,15 +986,15 @@ RexGameMenuDialog::RexGameMenuDialog(): RexDialogView() {
void RexGameMenuDialog::addLines() {
// Add the title
- int top = MADS_Y_OFFSET - 2 - ((((_vm->_font->current()->getHeight() + 2) * 6) >> 1) - 78);
+ int top = MADS_Y_OFFSET - 2 - ((((_vm->_font->getHeight() + 2) * 6) >> 1) - 78);
- addQuote(_vm->_font->current(), ALIGN_CENTER, 0, top, 10);
+ addQuote(_vm->_font, ALIGN_CENTER, 0, top, 10);
// Loop for adding the option lines of the dialog
top += 6;
for (int idx = 0; idx < 5; ++idx) {
- top += _vm->_font->current()->getHeight() + 1;
- addQuote(_vm->_font->current(), ALIGN_CENTER, 0, top, 11 + idx);
+ top += _vm->_font->getHeight() + 1;
+ addQuote(_vm->_font, ALIGN_CENTER, 0, top, 11 + idx);
}
}
@@ -1070,42 +1070,42 @@ void RexOptionsDialog::reload() {
void RexOptionsDialog::addLines() {
// Add the title
- int top = MADS_Y_OFFSET - 2 - ((((_vm->_font->current()->getHeight() + 1) * 9 + 12) >> 1) - 78);
+ int top = MADS_Y_OFFSET - 2 - ((((_vm->_font->getHeight() + 1) * 9 + 12) >> 1) - 78);
- addQuote(_vm->_font->current(), ALIGN_CENTER, 0, top, 16);
+ addQuote(_vm->_font, ALIGN_CENTER, 0, top, 16);
// Music state line
- top += _vm->_font->current()->getHeight() + 1 + 6;
- addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 17, _tempConfig.musicFlag ? 24 : 25);
+ top += _vm->_font->getHeight() + 1 + 6;
+ addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 17, _tempConfig.musicFlag ? 24 : 25);
// Sound state line
- top += _vm->_font->current()->getHeight() + 1;
- addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 18, _tempConfig.soundFlag ? 26 : 27);
+ top += _vm->_font->getHeight() + 1;
+ addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 18, _tempConfig.soundFlag ? 26 : 27);
// Interface easy state line
- top += _vm->_font->current()->getHeight() + 1;
- addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 19, _tempConfig.easyMouse ? 29 : 28);
+ top += _vm->_font->getHeight() + 1;
+ addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 19, _tempConfig.easyMouse ? 29 : 28);
// Inventory sppinng state line
- top += _vm->_font->current()->getHeight() + 1;
- addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 20, _tempConfig.invObjectsStill ? 31 : 30);
+ top += _vm->_font->getHeight() + 1;
+ addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 20, _tempConfig.invObjectsStill ? 31 : 30);
// Text window state line
- top += _vm->_font->current()->getHeight() + 1;
- addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 21, _tempConfig.textWindowStill ? 33 : 32);
+ top += _vm->_font->getHeight() + 1;
+ addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 21, _tempConfig.textWindowStill ? 33 : 32);
// Screen fade state line
- top += _vm->_font->current()->getHeight() + 1;
- addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 22, _tempConfig.screenFades + 34);
+ top += _vm->_font->getHeight() + 1;
+ addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 22, _tempConfig.screenFades + 34);
// Storyline mode line
- top += _vm->_font->current()->getHeight() + 1;
- addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 23, (_tempConfig.storyMode == 1) ? 37 : 38);
+ top += _vm->_font->getHeight() + 1;
+ addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 23, (_tempConfig.storyMode == 1) ? 37 : 38);
// Add Done and Cancel button texts
- top += _vm->_font->current()->getHeight() + 1 + 6;
- addQuote(_vm->_font->current(), ALIGN_CENTER, -54, top, 1, 0);
- addQuote(_vm->_font->current(), ALIGN_CENTER, 54, top, 2, 0);
+ top += _vm->_font->getHeight() + 1 + 6;
+ addQuote(_vm->_font, ALIGN_CENTER, -54, top, 1, 0);
+ addQuote(_vm->_font, ALIGN_CENTER, 54, top, 2, 0);
}
bool RexOptionsDialog::onEvent(M4EventType eventType, int32 param1, int x, int y, bool &captureEvents) {
diff --git a/engines/metaengine.h b/engines/metaengine.h
index 7519feaaa4..964eee071c 100644
--- a/engines/metaengine.h
+++ b/engines/metaengine.h
@@ -231,6 +231,7 @@ private:
friend class Common::Singleton<SingletonBaseType>;
public:
+ GameDescriptor findGameOnePlugAtATime(const Common::String &gameName, const EnginePlugin **plugin = NULL) const;
GameDescriptor findGame(const Common::String &gameName, const EnginePlugin **plugin = NULL) const;
GameList detectGames(const Common::FSList &fslist) const;
const EnginePlugin::List &getPlugins() const;
diff --git a/engines/mohawk/video/cinepak.cpp b/engines/mohawk/video/cinepak.cpp
new file mode 100644
index 0000000000..2ffe6869ae
--- /dev/null
+++ b/engines/mohawk/video/cinepak.cpp
@@ -0,0 +1,286 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "mohawk/video/cinepak.h"
+
+#include "common/system.h"
+#include "graphics/conversion.h" // For YUV2RGB
+
+// Code here partially based off of ffmpeg ;)
+
+namespace Mohawk {
+
+#define PUT_PIXEL(offset, lum, u, v) \
+ Graphics::CPYUV2RGB(lum, u, v, r, g, b); \
+ if (_pixelFormat.bytesPerPixel == 2) \
+ *((uint16 *)_curFrame.surface->pixels + offset) = _pixelFormat.RGBToColor(r, g, b); \
+ else \
+ *((uint32 *)_curFrame.surface->pixels + offset) = _pixelFormat.RGBToColor(r, g, b)
+
+CinepakDecoder::CinepakDecoder() : Graphics::Codec() {
+ _curFrame.surface = NULL;
+ _curFrame.strips = NULL;
+ _y = 0;
+ _pixelFormat = g_system->getScreenFormat();
+
+ // We're going to have to dither if we're running in 8bpp.
+ // We'll take RGBA8888 for best color performance in this case.
+ if (_pixelFormat.bytesPerPixel == 1)
+ _pixelFormat = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
+}
+
+CinepakDecoder::~CinepakDecoder() {
+ if (_curFrame.surface)
+ _curFrame.surface->free();
+ delete[] _curFrame.strips;
+}
+
+Graphics::Surface *CinepakDecoder::decodeImage(Common::SeekableReadStream *stream) {
+ _curFrame.flags = stream->readByte();
+ _curFrame.length = (stream->readByte() << 16) + stream->readUint16BE();
+ _curFrame.width = stream->readUint16BE();
+ _curFrame.height = stream->readUint16BE();
+ _curFrame.stripCount = stream->readUint16BE();
+
+ if (_curFrame.strips == NULL)
+ _curFrame.strips = new CinepakStrip[_curFrame.stripCount];
+
+ debug (4, "Cinepak Frame: Width = %d, Height = %d, Strip Count = %d", _curFrame.width, _curFrame.height, _curFrame.stripCount);
+
+#if 0
+ // Borrowed from FFMPEG. This should cut out the extra data Cinepak for Sega has (which is useless).
+ // The theory behind this is that this is here to confuse standard Cinepak decoders. But, we won't let that happen! ;)
+ if (_curFrame.length != (uint32)stream->size()) {
+ if (stream->readUint16BE() == 0xFE00)
+ stream->readUint32BE();
+ }
+#endif
+
+ if (!_curFrame.surface) {
+ _curFrame.surface = new Graphics::Surface();
+ _curFrame.surface->create(_curFrame.width, _curFrame.height, _pixelFormat.bytesPerPixel);
+ }
+
+ // Reset the y variable.
+ _y = 0;
+
+ for (uint16 i = 0; i < _curFrame.stripCount; i++) {
+ if (i > 0 && !(_curFrame.flags & 1)) { // Use codebooks from last strip
+ for (uint16 j = 0; j < 256; j++) {
+ _curFrame.strips[i].v1_codebook[j] = _curFrame.strips[i - 1].v1_codebook[j];
+ _curFrame.strips[i].v4_codebook[j] = _curFrame.strips[i - 1].v4_codebook[j];
+ }
+ }
+
+ _curFrame.strips[i].id = stream->readUint16BE();
+ _curFrame.strips[i].length = stream->readUint16BE() - 12; // Subtract the 12 byte header
+ _curFrame.strips[i].rect.top = _y; stream->readUint16BE(); // Ignore, substitute with our own.
+ _curFrame.strips[i].rect.left = 0; stream->readUint16BE(); // Ignore, substitute with our own
+ _curFrame.strips[i].rect.bottom = _y + stream->readUint16BE();
+ _curFrame.strips[i].rect.right = _curFrame.width; stream->readUint16BE(); // Ignore, substitute with our own
+
+ //printf ("Left = %d, Top = %d, Right = %d, Bottom = %d\n", _curFrame.strips[i].rect.left, _curFrame.strips[i].rect.top, _curFrame.strips[i].rect.right, _curFrame.strips[i].rect.bottom);
+
+ // Sanity check. Because Cinepak is based on 4x4 blocks, the width and height of each strip needs to be divisible by 4.
+ assert(!(_curFrame.strips[i].rect.width() % 4) && !(_curFrame.strips[i].rect.height() % 4));
+
+ uint32 pos = stream->pos();
+
+ while ((uint32)stream->pos() < (pos + _curFrame.strips[i].length) && !stream->eos()) {
+ byte chunkID = stream->readByte();
+
+ if (stream->eos())
+ break;
+
+ // Chunk Size is 24-bit, ignore the first 4 bytes
+ uint32 chunkSize = stream->readByte() << 16;
+ chunkSize += stream->readUint16BE() - 4;
+
+ int32 startPos = stream->pos();
+
+ switch (chunkID) {
+ case 0x20:
+ case 0x21:
+ case 0x24:
+ case 0x25:
+ loadCodebook(stream, i, 4, chunkID, chunkSize);
+ break;
+ case 0x22:
+ case 0x23:
+ case 0x26:
+ case 0x27:
+ loadCodebook(stream, i, 1, chunkID, chunkSize);
+ break;
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ decodeVectors(stream, i, chunkID, chunkSize);
+ break;
+ default:
+ warning("Unknown Cinepak chunk ID %02x", chunkID);
+ return _curFrame.surface;
+ }
+
+ if (stream->pos() != startPos + (int32)chunkSize)
+ stream->seek(startPos + chunkSize);
+ }
+
+ _y = _curFrame.strips[i].rect.bottom;
+ }
+
+ return _curFrame.surface;
+}
+
+void CinepakDecoder::loadCodebook(Common::SeekableReadStream *stream, uint16 strip, byte codebookType, byte chunkID, uint32 chunkSize) {
+ CinepakCodebook *codebook = (codebookType == 1) ? _curFrame.strips[strip].v1_codebook : _curFrame.strips[strip].v4_codebook;
+
+ int32 startPos = stream->pos();
+ uint32 flag = 0, mask = 0;
+
+ for (uint16 i = 0; i < 256; i++) {
+ if ((chunkID & 0x01) && !(mask >>= 1)) {
+ if ((stream->pos() - startPos + 4) > (int32)chunkSize)
+ break;
+
+ flag = stream->readUint32BE();
+ mask = 0x80000000;
+ }
+
+ if (!(chunkID & 0x01) || (flag & mask)) {
+ byte n = (chunkID & 0x04) ? 4 : 6;
+ if ((stream->pos() - startPos + n) > (int32)chunkSize)
+ break;
+
+ for (byte j = 0; j < 4; j++)
+ codebook[i].y[j] = stream->readByte();
+
+ if (n == 6) {
+ codebook[i].u = stream->readByte() + 128;
+ codebook[i].v = stream->readByte() + 128;
+ } else {
+ /* this codebook type indicates either greyscale or
+ * palettized video; if palettized, U & V components will
+ * not be used so it is safe to set them to 128 for the
+ * benefit of greyscale rendering in YUV420P */
+ codebook[i].u = 128;
+ codebook[i].v = 128;
+ }
+ }
+ }
+}
+
+void CinepakDecoder::decodeVectors(Common::SeekableReadStream *stream, uint16 strip, byte chunkID, uint32 chunkSize) {
+ uint32 flag = 0, mask = 0;
+ uint32 iy[4];
+ int32 startPos = stream->pos();
+ byte r = 0, g = 0, b = 0;
+
+ for (uint16 y = _curFrame.strips[strip].rect.top; y < _curFrame.strips[strip].rect.bottom; y += 4) {
+ iy[0] = _curFrame.strips[strip].rect.left + y * _curFrame.width;
+ iy[1] = iy[0] + _curFrame.width;
+ iy[2] = iy[1] + _curFrame.width;
+ iy[3] = iy[2] + _curFrame.width;
+
+ for (uint16 x = _curFrame.strips[strip].rect.left; x < _curFrame.strips[strip].rect.right; x += 4) {
+ if ((chunkID & 0x01) && !(mask >>= 1)) {
+ if ((stream->pos() - startPos + 4) > (int32)chunkSize)
+ return;
+
+ flag = stream->readUint32BE();
+ mask = 0x80000000;
+ }
+
+ if (!(chunkID & 0x01) || (flag & mask)) {
+ if (!(chunkID & 0x02) && !(mask >>= 1)) {
+ if ((stream->pos() - startPos + 4) > (int32)chunkSize)
+ return;
+
+ flag = stream->readUint32BE();
+ mask = 0x80000000;
+ }
+
+ if ((chunkID & 0x02) || (~flag & mask)) {
+ if ((stream->pos() - startPos + 1) > (int32)chunkSize)
+ return;
+
+ // Get the codebook
+ CinepakCodebook codebook = _curFrame.strips[strip].v1_codebook[stream->readByte()];
+
+ PUT_PIXEL(iy[0] + 0, codebook.y[0], codebook.u, codebook.v);
+ PUT_PIXEL(iy[0] + 1, codebook.y[0], codebook.u, codebook.v);
+ PUT_PIXEL(iy[1] + 0, codebook.y[0], codebook.u, codebook.v);
+ PUT_PIXEL(iy[1] + 1, codebook.y[0], codebook.u, codebook.v);
+
+ PUT_PIXEL(iy[0] + 2, codebook.y[1], codebook.u, codebook.v);
+ PUT_PIXEL(iy[0] + 3, codebook.y[1], codebook.u, codebook.v);
+ PUT_PIXEL(iy[1] + 2, codebook.y[1], codebook.u, codebook.v);
+ PUT_PIXEL(iy[1] + 3, codebook.y[1], codebook.u, codebook.v);
+
+ PUT_PIXEL(iy[2] + 0, codebook.y[2], codebook.u, codebook.v);
+ PUT_PIXEL(iy[2] + 1, codebook.y[2], codebook.u, codebook.v);
+ PUT_PIXEL(iy[3] + 0, codebook.y[2], codebook.u, codebook.v);
+ PUT_PIXEL(iy[3] + 1, codebook.y[2], codebook.u, codebook.v);
+
+ PUT_PIXEL(iy[2] + 2, codebook.y[3], codebook.u, codebook.v);
+ PUT_PIXEL(iy[2] + 3, codebook.y[3], codebook.u, codebook.v);
+ PUT_PIXEL(iy[3] + 2, codebook.y[3], codebook.u, codebook.v);
+ PUT_PIXEL(iy[3] + 3, codebook.y[3], codebook.u, codebook.v);
+ } else if (flag & mask) {
+ if ((stream->pos() - startPos + 4) > (int32)chunkSize)
+ return;
+
+ CinepakCodebook codebook = _curFrame.strips[strip].v4_codebook[stream->readByte()];
+ PUT_PIXEL(iy[0] + 0, codebook.y[0], codebook.u, codebook.v);
+ PUT_PIXEL(iy[0] + 1, codebook.y[1], codebook.u, codebook.v);
+ PUT_PIXEL(iy[1] + 0, codebook.y[2], codebook.u, codebook.v);
+ PUT_PIXEL(iy[1] + 1, codebook.y[3], codebook.u, codebook.v);
+
+ codebook = _curFrame.strips[strip].v4_codebook[stream->readByte()];
+ PUT_PIXEL(iy[0] + 2, codebook.y[0], codebook.u, codebook.v);
+ PUT_PIXEL(iy[0] + 3, codebook.y[1], codebook.u, codebook.v);
+ PUT_PIXEL(iy[1] + 2, codebook.y[2], codebook.u, codebook.v);
+ PUT_PIXEL(iy[1] + 3, codebook.y[3], codebook.u, codebook.v);
+
+ codebook = _curFrame.strips[strip].v4_codebook[stream->readByte()];
+ PUT_PIXEL(iy[2] + 0, codebook.y[0], codebook.u, codebook.v);
+ PUT_PIXEL(iy[2] + 1, codebook.y[1], codebook.u, codebook.v);
+ PUT_PIXEL(iy[3] + 0, codebook.y[2], codebook.u, codebook.v);
+ PUT_PIXEL(iy[3] + 1, codebook.y[3], codebook.u, codebook.v);
+
+ codebook = _curFrame.strips[strip].v4_codebook[stream->readByte()];
+ PUT_PIXEL(iy[2] + 2, codebook.y[0], codebook.u, codebook.v);
+ PUT_PIXEL(iy[2] + 3, codebook.y[1], codebook.u, codebook.v);
+ PUT_PIXEL(iy[3] + 2, codebook.y[2], codebook.u, codebook.v);
+ PUT_PIXEL(iy[3] + 3, codebook.y[3], codebook.u, codebook.v);
+ }
+ }
+
+ for (byte i = 0; i < 4; i++)
+ iy[i] += 4;
+ }
+ }
+}
+
+} // End of namespace Mohawk
diff --git a/engines/mohawk/video/cinepak.h b/engines/mohawk/video/cinepak.h
new file mode 100644
index 0000000000..3f4cbba17c
--- /dev/null
+++ b/engines/mohawk/video/cinepak.h
@@ -0,0 +1,81 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef CINEPAK_H
+#define CINEPAK_H
+
+#include "common/scummsys.h"
+#include "common/stream.h"
+#include "common/rect.h"
+#include "graphics/surface.h"
+#include "graphics/pixelformat.h"
+
+#include "graphics/video/codecs/codec.h"
+
+namespace Mohawk {
+
+struct CinepakCodebook {
+ byte y[4];
+ byte u, v;
+};
+
+struct CinepakStrip {
+ uint16 id;
+ uint16 length;
+ Common::Rect rect;
+ CinepakCodebook v1_codebook[256], v4_codebook[256];
+};
+
+struct CinepakFrame {
+ byte flags;
+ uint32 length;
+ uint16 width;
+ uint16 height;
+ uint16 stripCount;
+ CinepakStrip *strips;
+
+ Graphics::Surface *surface;
+};
+
+class CinepakDecoder : public Graphics::Codec {
+public:
+ CinepakDecoder();
+ ~CinepakDecoder();
+
+ Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
+ Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
+
+private:
+ CinepakFrame _curFrame;
+ int32 _y;
+ Graphics::PixelFormat _pixelFormat;
+
+ void loadCodebook(Common::SeekableReadStream *stream, uint16 strip, byte codebookType, byte chunkID, uint32 chunkSize);
+ void decodeVectors(Common::SeekableReadStream *stream, uint16 strip, byte chunkID, uint32 chunkSize);
+};
+
+}
+
+#endif
diff --git a/engines/mohawk/video/qdm2.cpp b/engines/mohawk/video/qdm2.cpp
new file mode 100644
index 0000000000..b91440f00d
--- /dev/null
+++ b/engines/mohawk/video/qdm2.cpp
@@ -0,0 +1,3063 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+// Based off ffmpeg's QDM2 decoder
+
+#include "mohawk/video/qdm2.h"
+#include "mohawk/video/qdm2data.h"
+
+#include "common/system.h"
+
+namespace Mohawk {
+
+// Fix compilation for non C99-compliant compilers, like MSVC
+#ifndef int64_t
+typedef signed long long int int64_t;
+#endif
+
+// Integer log2 function. This is much faster than invoking
+// double precision C99 log2 math functions or equivalent, since
+// this is only used to determine maximum number of bits needed
+// i.e. only non-fractional part is needed. Also, the double
+// version is incorrect for exact cases due to floating point
+// rounding errors.
+static inline int scummvm_log2(int n) {
+ int ret = -1;
+ while(n != 0) {
+ n /= 2;
+ ret++;
+ }
+ return ret;
+}
+
+#define QDM2_LIST_ADD(list, size, packet) \
+ do { \
+ if (size > 0) \
+ list[size - 1].next = &list[size]; \
+ list[size].packet = packet; \
+ list[size].next = NULL; \
+ size++; \
+ } while(0)
+
+// Result is 8, 16 or 30
+#define QDM2_SB_USED(subSampling) (((subSampling) >= 2) ? 30 : 8 << (subSampling))
+
+#define FIX_NOISE_IDX(noiseIdx) \
+ if ((noiseIdx) >= 3840) \
+ (noiseIdx) -= 3840 \
+
+#define SB_DITHERING_NOISE(sb, noiseIdx) (_noiseTable[(noiseIdx)++] * sb_noise_attenuation[(sb)])
+
+static inline void initGetBits(GetBitContext *s, const uint8 *buffer, int bitSize) {
+ int bufferSize = (bitSize + 7) >> 3;
+
+ debug(1, "void initGetBits(GetBitContext *s, const uint8 *buffer, int bitSize)");
+
+ if (bufferSize < 0 || bitSize < 0) {
+ bufferSize = bitSize = 0;
+ buffer = NULL;
+ }
+
+ s->buffer = buffer;
+ s->sizeInBits = bitSize;
+ s->bufferEnd = buffer + bufferSize;
+ s->index = 0;
+}
+
+static inline int getBitsCount(GetBitContext *s) {
+ debug(1, "int getBitsCount(GetBitContext *s)");
+ return s->index;
+}
+
+static inline unsigned int getBits1(GetBitContext *s) {
+ int index;
+ uint8 result;
+
+ debug(1, "unsigned int getBits1(GetBitContext *s)");
+
+ index = s->index;
+ result = s->buffer[index >> 3];
+
+ debug(1, "index : %d", index);
+
+ result >>= (index & 0x07);
+ result &= 1;
+ index++;
+ s->index = index;
+
+ return result;
+}
+
+static inline unsigned int getBits(GetBitContext *s, int n) {
+ int tmp, reCache, reIndex;
+
+ debug(1, "unsigned int getBits(GetBitContext *s, int n)");
+
+ reIndex = s->index;
+
+ debug(1, "reIndex : %d", reIndex);
+
+ reCache = READ_LE_UINT32((const uint8 *)s->buffer + (reIndex >> 3)) >> (reIndex & 0x07);
+
+ tmp = (reCache) & ((uint32)0xffffffff >> (32 - n));
+
+ s->index = reIndex + n;
+
+ return tmp;
+}
+
+static inline void skipBits(GetBitContext *s, int n) {
+ int reIndex, reCache;
+
+ debug(1, "void skipBits(GetBitContext *s, int n)");
+
+ reIndex = s->index;
+ reCache = 0;
+
+ debug(1, "reIndex : %d", reIndex);
+
+ reCache = READ_LE_UINT32((const uint8 *)s->buffer + (reIndex >> 3)) >> (reIndex & 0x07);
+ s->index = reIndex + n;
+}
+
+#define BITS_LEFT(length, gb) ((length) - getBitsCount((gb)))
+
+static int splitRadixPermutation(int i, int n, int inverse) {
+ if (n <= 2)
+ return i & 1;
+
+ int m = n >> 1;
+
+ if(!(i & m))
+ return splitRadixPermutation(i, m, inverse) * 2;
+
+ m >>= 1;
+
+ if (inverse == !(i & m))
+ return splitRadixPermutation(i, m, inverse) * 4 + 1;
+
+ return splitRadixPermutation(i, m, inverse) * 4 - 1;
+}
+
+// sin(2*pi*x/n) for 0<=x<n/4, followed by n/2<=x<3n/4
+float ff_sin_16[8];
+float ff_sin_32[16];
+float ff_sin_64[32];
+float ff_sin_128[64];
+float ff_sin_256[128];
+float ff_sin_512[256];
+float ff_sin_1024[512];
+float ff_sin_2048[1024];
+float ff_sin_4096[2048];
+float ff_sin_8192[4096];
+float ff_sin_16384[8192];
+float ff_sin_32768[16384];
+float ff_sin_65536[32768];
+
+float *ff_sin_tabs[] = {
+ NULL, NULL, NULL, NULL,
+ ff_sin_16, ff_sin_32, ff_sin_64, ff_sin_128, ff_sin_256, ff_sin_512, ff_sin_1024,
+ ff_sin_2048, ff_sin_4096, ff_sin_8192, ff_sin_16384, ff_sin_32768, ff_sin_65536,
+};
+
+// cos(2*pi*x/n) for 0<=x<=n/4, followed by its reverse
+float ff_cos_16[8];
+float ff_cos_32[16];
+float ff_cos_64[32];
+float ff_cos_128[64];
+float ff_cos_256[128];
+float ff_cos_512[256];
+float ff_cos_1024[512];
+float ff_cos_2048[1024];
+float ff_cos_4096[2048];
+float ff_cos_8192[4096];
+float ff_cos_16384[8192];
+float ff_cos_32768[16384];
+float ff_cos_65536[32768];
+
+float *ff_cos_tabs[] = {
+ NULL, NULL, NULL, NULL,
+ ff_cos_16, ff_cos_32, ff_cos_64, ff_cos_128, ff_cos_256, ff_cos_512, ff_cos_1024,
+ ff_cos_2048, ff_cos_4096, ff_cos_8192, ff_cos_16384, ff_cos_32768, ff_cos_65536,
+};
+
+void initCosineTables(int index) {
+ int m = 1 << index;
+ double freq = 2 * PI / m;
+ float *tab = ff_cos_tabs[index];
+
+ for (int i = 0; i <= m / 4; i++)
+ tab[i] = cos(i * freq);
+
+ for (int i = 1; i < m / 4; i++)
+ tab[m / 2 - i] = tab[i];
+}
+
+void fftPermute(FFTContext *s, FFTComplex *z) {
+ const uint16 *revtab = s->revtab;
+ int np = 1 << s->nbits;
+
+ if (s->tmpBuf) {
+ // TODO: handle split-radix permute in a more optimal way, probably in-place
+ for (int j = 0; j < np; j++)
+ s->tmpBuf[revtab[j]] = z[j];
+ memcpy(z, s->tmpBuf, np * sizeof(FFTComplex));
+ return;
+ }
+
+ // reverse
+ for (int j = 0; j < np; j++) {
+ int k = revtab[j];
+ if (k < j) {
+ FFTComplex tmp = z[k];
+ z[k] = z[j];
+ z[j] = tmp;
+ }
+ }
+}
+
+#define DECL_FFT(n,n2,n4) \
+static void fft##n(FFTComplex *z) { \
+ fft##n2(z); \
+ fft##n4(z + n4 * 2); \
+ fft##n4(z + n4 * 3); \
+ pass(z, ff_cos_##n, n4 / 2); \
+}
+
+#ifndef M_SQRT1_2
+#define M_SQRT1_2 7.0710678118654752440E-1
+#endif
+
+#define sqrthalf (float)M_SQRT1_2
+
+#define BF(x,y,a,b) { \
+ x = a - b; \
+ y = a + b; \
+}
+
+#define BUTTERFLIES(a0, a1, a2, a3) { \
+ BF(t3, t5, t5, t1); \
+ BF(a2.re, a0.re, a0.re, t5); \
+ BF(a3.im, a1.im, a1.im, t3); \
+ BF(t4, t6, t2, t6); \
+ BF(a3.re, a1.re, a1.re, t4); \
+ BF(a2.im, a0.im, a0.im, t6); \
+}
+
+// force loading all the inputs before storing any.
+// this is slightly slower for small data, but avoids store->load aliasing
+// for addresses separated by large powers of 2.
+#define BUTTERFLIES_BIG(a0, a1, a2, a3) { \
+ float r0 = a0.re, i0 = a0.im, r1 = a1.re, i1 = a1.im; \
+ BF(t3, t5, t5, t1); \
+ BF(a2.re, a0.re, r0, t5); \
+ BF(a3.im, a1.im, i1, t3); \
+ BF(t4, t6, t2, t6); \
+ BF(a3.re, a1.re, r1, t4); \
+ BF(a2.im, a0.im, i0, t6); \
+}
+
+#define TRANSFORM(a0, a1, a2, a3, wre, wim) { \
+ t1 = a2.re * wre + a2.im * wim; \
+ t2 = a2.im * wre - a2.re * wim; \
+ t5 = a3.re * wre - a3.im * wim; \
+ t6 = a3.im * wre + a3.re * wim; \
+ BUTTERFLIES(a0, a1, a2, a3) \
+}
+
+#define TRANSFORM_ZERO(a0, a1, a2, a3) { \
+ t1 = a2.re; \
+ t2 = a2.im; \
+ t5 = a3.re; \
+ t6 = a3.im; \
+ BUTTERFLIES(a0, a1, a2, a3) \
+}
+
+// z[0...8n-1], w[1...2n-1]
+#define PASS(name) \
+static void name(FFTComplex *z, const float *wre, unsigned int n) { \
+ float t1, t2, t3, t4, t5, t6; \
+ int o1 = 2 * n; \
+ int o2 = 4 * n; \
+ int o3 = 6 * n; \
+ const float *wim = wre + o1; \
+ n--; \
+ \
+ TRANSFORM_ZERO(z[0], z[o1], z[o2], z[o3]); \
+ TRANSFORM(z[1], z[o1 + 1], z[o2 + 1], z[o3 + 1], wre[1], wim[-1]); \
+ \
+ do { \
+ z += 2; \
+ wre += 2; \
+ wim -= 2; \
+ TRANSFORM(z[0], z[o1], z[o2], z[o3], wre[0], wim[0]); \
+ TRANSFORM(z[1], z[o1 + 1],z[o2 + 1], z[o3 + 1], wre[1], wim[-1]); \
+ } while(--n); \
+}
+
+PASS(pass)
+#undef BUTTERFLIES
+#define BUTTERFLIES BUTTERFLIES_BIG
+PASS(pass_big)
+
+static void fft4(FFTComplex *z) {
+ float t1, t2, t3, t4, t5, t6, t7, t8;
+
+ BF(t3, t1, z[0].re, z[1].re);
+ BF(t8, t6, z[3].re, z[2].re);
+ BF(z[2].re, z[0].re, t1, t6);
+ BF(t4, t2, z[0].im, z[1].im);
+ BF(t7, t5, z[2].im, z[3].im);
+ BF(z[3].im, z[1].im, t4, t8);
+ BF(z[3].re, z[1].re, t3, t7);
+ BF(z[2].im, z[0].im, t2, t5);
+}
+
+static void fft8(FFTComplex *z) {
+ float t1, t2, t3, t4, t5, t6, t7, t8;
+
+ fft4(z);
+
+ BF(t1, z[5].re, z[4].re, -z[5].re);
+ BF(t2, z[5].im, z[4].im, -z[5].im);
+ BF(t3, z[7].re, z[6].re, -z[7].re);
+ BF(t4, z[7].im, z[6].im, -z[7].im);
+ BF(t8, t1, t3, t1);
+ BF(t7, t2, t2, t4);
+ BF(z[4].re, z[0].re, z[0].re, t1);
+ BF(z[4].im, z[0].im, z[0].im, t2);
+ BF(z[6].re, z[2].re, z[2].re, t7);
+ BF(z[6].im, z[2].im, z[2].im, t8);
+
+ TRANSFORM(z[1], z[3], z[5], z[7], sqrthalf, sqrthalf);
+}
+
+#undef BF
+
+DECL_FFT(16,8,4)
+DECL_FFT(32,16,8)
+DECL_FFT(64,32,16)
+DECL_FFT(128,64,32)
+DECL_FFT(256,128,64)
+DECL_FFT(512,256,128)
+#define pass pass_big
+DECL_FFT(1024,512,256)
+DECL_FFT(2048,1024,512)
+DECL_FFT(4096,2048,1024)
+DECL_FFT(8192,4096,2048)
+DECL_FFT(16384,8192,4096)
+DECL_FFT(32768,16384,8192)
+DECL_FFT(65536,32768,16384)
+
+void fftCalc(FFTContext *s, FFTComplex *z) {
+ static void (* const fftDispatch[])(FFTComplex*) = {
+ fft4, fft8, fft16, fft32, fft64, fft128, fft256, fft512, fft1024,
+ fft2048, fft4096, fft8192, fft16384, fft32768, fft65536,
+ };
+
+ fftDispatch[s->nbits - 2](z);
+}
+
+// complex multiplication: p = a * b
+#define CMUL(pre, pim, are, aim, bre, bim) \
+{\
+ float _are = (are); \
+ float _aim = (aim); \
+ float _bre = (bre); \
+ float _bim = (bim); \
+ (pre) = _are * _bre - _aim * _bim; \
+ (pim) = _are * _bim + _aim * _bre; \
+}
+
+/**
+ * Compute the middle half of the inverse MDCT of size N = 2^nbits,
+ * thus excluding the parts that can be derived by symmetry
+ * @param output N/2 samples
+ * @param input N/2 samples
+ */
+void imdctHalfC(FFTContext *s, float *output, const float *input) {
+ const uint16 *revtab = s->revtab;
+ const float *tcos = s->tcos;
+ const float *tsin = s->tsin;
+ FFTComplex *z = (FFTComplex *)output;
+
+ int n = 1 << s->mdctBits;
+ int n2 = n >> 1;
+ int n4 = n >> 2;
+ int n8 = n >> 3;
+
+ // pre rotation
+ const float *in1 = input;
+ const float *in2 = input + n2 - 1;
+ for (int k = 0; k < n4; k++) {
+ int j = revtab[k];
+ CMUL(z[j].re, z[j].im, *in2, *in1, tcos[k], tsin[k]);
+ in1 += 2;
+ in2 -= 2;
+ }
+
+ fftCalc(s, z);
+
+ // post rotation + reordering
+ for (int k = 0; k < n8; k++) {
+ float r0, i0, r1, i1;
+ CMUL(r0, i1, z[n8 - k - 1].im, z[n8 - k - 1].re, tsin[n8 - k - 1], tcos[n8 - k - 1]);
+ CMUL(r1, i0, z[n8 + k].im, z[n8 + k].re, tsin[n8 + k], tcos[n8 + k]);
+ z[n8 - k - 1].re = r0;
+ z[n8 - k - 1].im = i0;
+ z[n8 + k].re = r1;
+ z[n8 + k].im = i1;
+ }
+}
+
+/**
+ * Compute inverse MDCT of size N = 2^nbits
+ * @param output N samples
+ * @param input N/2 samples
+ */
+void imdctCalcC(FFTContext *s, float *output, const float *input) {
+ int n = 1 << s->mdctBits;
+ int n2 = n >> 1;
+ int n4 = n >> 2;
+
+ imdctHalfC(s, output + n4, input);
+
+ for (int k = 0; k < n4; k++) {
+ output[k] = -output[n2 - k - 1];
+ output[n - k - 1] = output[n2 + k];
+ }
+}
+
+/**
+ * Compute MDCT of size N = 2^nbits
+ * @param input N samples
+ * @param out N/2 samples
+ */
+void mdctCalcC(FFTContext *s, float *out, const float *input) {
+ const uint16 *revtab = s->revtab;
+ const float *tcos = s->tcos;
+ const float *tsin = s->tsin;
+ FFTComplex *x = (FFTComplex *)out;
+
+ int n = 1 << s->mdctBits;
+ int n2 = n >> 1;
+ int n4 = n >> 2;
+ int n8 = n >> 3;
+ int n3 = 3 * n4;
+
+ // pre rotation
+ for (int i = 0; i < n8; i++) {
+ float re = -input[2 * i + 3 * n4] - input[n3 - 1 - 2 * i];
+ float im = -input[n4 + 2 * i] + input[n4 - 1 - 2 * i];
+ int j = revtab[i];
+ CMUL(x[j].re, x[j].im, re, im, -tcos[i], tsin[i]);
+
+ re = input[2 * i] - input[n2 - 1 - 2 * i];
+ im = -(input[n2 + 2 * i] + input[n - 1 - 2 * i]);
+ j = revtab[n8 + i];
+ CMUL(x[j].re, x[j].im, re, im, -tcos[n8 + i], tsin[n8 + i]);
+ }
+
+ fftCalc(s, x);
+
+ // post rotation
+ for (int i = 0; i < n8; i++) {
+ float r0, i0, r1, i1;
+ CMUL(i1, r0, x[n8 - i - 1].re, x[n8 - i - 1].im, -tsin[n8 - i - 1], -tcos[n8 - i - 1]);
+ CMUL(i0, r1, x[n8 + i].re, x[n8 + i].im, -tsin[n8 + i], -tcos[n8 + i]);
+ x[n8 - i - 1].re = r0;
+ x[n8 - i - 1].im = i0;
+ x[n8 + i].re = r1;
+ x[n8 + i].im = i1;
+ }
+}
+
+int fftInit(FFTContext *s, int nbits, int inverse) {
+ int i, j, m, n;
+ float alpha, c1, s1, s2;
+
+ if (nbits < 2 || nbits > 16)
+ goto fail;
+
+ s->nbits = nbits;
+ n = 1 << nbits;
+ s->tmpBuf = NULL;
+
+ s->exptab = (FFTComplex *)malloc((n / 2) * sizeof(FFTComplex));
+ if (!s->exptab)
+ goto fail;
+
+ s->revtab = (uint16 *)malloc(n * sizeof(uint16));
+ if (!s->revtab)
+ goto fail;
+ s->inverse = inverse;
+
+ s2 = inverse ? 1.0 : -1.0;
+
+ s->fftPermute = fftPermute;
+ s->fftCalc = fftCalc;
+ s->imdctCalc = imdctCalcC;
+ s->imdctHalf = imdctHalfC;
+ s->mdctCalc = mdctCalcC;
+ s->splitRadix = 1;
+
+ if (s->splitRadix) {
+ for (j = 4; j <= nbits; j++)
+ initCosineTables(j);
+
+ for (i = 0; i < n; i++)
+ s->revtab[-splitRadixPermutation(i, n, s->inverse) & (n - 1)] = i;
+
+ s->tmpBuf = (FFTComplex *)malloc(n * sizeof(FFTComplex));
+ } else {
+ for (i = 0; i < n / 2; i++) {
+ alpha = 2 * PI * (float)i / (float)n;
+ c1 = cos(alpha);
+ s1 = sin(alpha) * s2;
+ s->exptab[i].re = c1;
+ s->exptab[i].im = s1;
+ }
+
+ //int np = 1 << nbits;
+ //int nblocks = np >> 3;
+ //int np2 = np >> 1;
+
+ // compute bit reverse table
+ for (i = 0; i < n; i++) {
+ m = 0;
+
+ for (j = 0; j < nbits; j++)
+ m |= ((i >> j) & 1) << (nbits - j - 1);
+
+ s->revtab[i] = m;
+ }
+ }
+
+ return 0;
+
+ fail:
+ free(&s->revtab);
+ free(&s->exptab);
+ free(&s->tmpBuf);
+ return -1;
+}
+
+/**
+ * Sets up a real FFT.
+ * @param nbits log2 of the length of the input array
+ * @param trans the type of transform
+ */
+int rdftInit(RDFTContext *s, int nbits, RDFTransformType trans) {
+ int n = 1 << nbits;
+ const double theta = (trans == RDFT || trans == IRIDFT ? -1 : 1) * 2 * PI / n;
+
+ s->nbits = nbits;
+ s->inverse = trans == IRDFT || trans == IRIDFT;
+ s->signConvention = trans == RIDFT || trans == IRIDFT ? 1 : -1;
+
+ if (nbits < 4 || nbits > 16)
+ return -1;
+
+ if (fftInit(&s->fft, nbits - 1, trans == IRDFT || trans == RIDFT) < 0)
+ return -1;
+
+ initCosineTables(nbits);
+ s->tcos = ff_cos_tabs[nbits];
+ s->tsin = ff_sin_tabs[nbits] + (trans == RDFT || trans == IRIDFT) * (n >> 2);
+
+ for (int i = 0; i < n >> 2; i++)
+ s->tsin[i] = sin(i*theta);
+
+ return 0;
+}
+
+/** Map one real FFT into two parallel real even and odd FFTs. Then interleave
+ * the two real FFTs into one complex FFT. Unmangle the results.
+ * ref: http://www.engineeringproductivitytools.com/stuff/T0001/PT10.HTM
+ */
+void rdftCalc(RDFTContext *s, float *data) {
+ FFTComplex ev, od;
+
+ const int n = 1 << s->nbits;
+ const float k1 = 0.5;
+ const float k2 = 0.5 - s->inverse;
+ const float *tcos = s->tcos;
+ const float *tsin = s->tsin;
+
+ if (!s->inverse) {
+ fftPermute(&s->fft, (FFTComplex *)data);
+ fftCalc(&s->fft, (FFTComplex *)data);
+ }
+
+ // i=0 is a special case because of packing, the DC term is real, so we
+ // are going to throw the N/2 term (also real) in with it.
+ ev.re = data[0];
+ data[0] = ev.re + data[1];
+ data[1] = ev.re - data[1];
+
+ int i;
+
+ for (i = 1; i < n >> 2; i++) {
+ int i1 = i * 2;
+ int i2 = n - i1;
+
+ // Separate even and odd FFTs
+ ev.re = k1 * (data[i1] + data[i2]);
+ od.im = -k2 * (data[i1] - data[i2]);
+ ev.im = k1 * (data[i1 + 1] - data[i2 + 1]);
+ od.re = k2 * (data[i1 + 1] + data[i2 + 1]);
+
+ // Apply twiddle factors to the odd FFT and add to the even FFT
+ data[i1] = ev.re + od.re * tcos[i] - od.im * tsin[i];
+ data[i1 + 1] = ev.im + od.im * tcos[i] + od.re * tsin[i];
+ data[i2] = ev.re - od.re * tcos[i] + od.im * tsin[i];
+ data[i2 + 1] = -ev.im + od.im * tcos[i] + od.re * tsin[i];
+ }
+
+ data[i * 2 + 1] = s->signConvention * data[i * 2 + 1];
+ if (s->inverse) {
+ data[0] *= k1;
+ data[1] *= k1;
+ fftPermute(&s->fft, (FFTComplex*)data);
+ fftCalc(&s->fft, (FFTComplex*)data);
+ }
+}
+
+// half mpeg encoding window (full precision)
+const int32 ff_mpa_enwindow[257] = {
+ 0, -1, -1, -1, -1, -1, -1, -2,
+ -2, -2, -2, -3, -3, -4, -4, -5,
+ -5, -6, -7, -7, -8, -9, -10, -11,
+ -13, -14, -16, -17, -19, -21, -24, -26,
+ -29, -31, -35, -38, -41, -45, -49, -53,
+ -58, -63, -68, -73, -79, -85, -91, -97,
+ -104, -111, -117, -125, -132, -139, -147, -154,
+ -161, -169, -176, -183, -190, -196, -202, -208,
+ 213, 218, 222, 225, 227, 228, 228, 227,
+ 224, 221, 215, 208, 200, 189, 177, 163,
+ 146, 127, 106, 83, 57, 29, -2, -36,
+ -72, -111, -153, -197, -244, -294, -347, -401,
+ -459, -519, -581, -645, -711, -779, -848, -919,
+ -991, -1064, -1137, -1210, -1283, -1356, -1428, -1498,
+ -1567, -1634, -1698, -1759, -1817, -1870, -1919, -1962,
+ -2001, -2032, -2057, -2075, -2085, -2087, -2080, -2063,
+ 2037, 2000, 1952, 1893, 1822, 1739, 1644, 1535,
+ 1414, 1280, 1131, 970, 794, 605, 402, 185,
+ -45, -288, -545, -814, -1095, -1388, -1692, -2006,
+ -2330, -2663, -3004, -3351, -3705, -4063, -4425, -4788,
+ -5153, -5517, -5879, -6237, -6589, -6935, -7271, -7597,
+ -7910, -8209, -8491, -8755, -8998, -9219, -9416, -9585,
+ -9727, -9838, -9916, -9959, -9966, -9935, -9863, -9750,
+ -9592, -9389, -9139, -8840, -8492, -8092, -7640, -7134,
+ 6574, 5959, 5288, 4561, 3776, 2935, 2037, 1082,
+ 70, -998, -2122, -3300, -4533, -5818, -7154, -8540,
+ -9975,-11455,-12980,-14548,-16155,-17799,-19478,-21189,
+-22929,-24694,-26482,-28289,-30112,-31947,-33791,-35640,
+-37489,-39336,-41176,-43006,-44821,-46617,-48390,-50137,
+-51853,-53534,-55178,-56778,-58333,-59838,-61289,-62684,
+-64019,-65290,-66494,-67629,-68692,-69679,-70590,-71420,
+-72169,-72835,-73415,-73908,-74313,-74630,-74856,-74992,
+ 75038
+};
+
+void ff_mpa_synth_init(int16 *window) {
+ int i;
+ int32 v;
+
+ // max = 18760, max sum over all 16 coefs : 44736
+ for(i = 0; i < 257; i++) {
+ v = ff_mpa_enwindow[i];
+ v = (v + 2) >> 2;
+ window[i] = v;
+
+ if ((i & 63) != 0)
+ v = -v;
+
+ if (i != 0)
+ window[512 - i] = v;
+ }
+}
+
+static inline uint16 round_sample(int *sum) {
+ int sum1;
+ sum1 = (*sum) >> 14;
+ *sum &= (1 << 14)-1;
+ if (sum1 < (-0x7fff - 1))
+ sum1 = (-0x7fff - 1);
+ if (sum1 > 0x7fff)
+ sum1 = 0x7fff;
+ return sum1;
+}
+
+static inline int MULH(int a, int b) {
+ return ((int64_t)(a) * (int64_t)(b))>>32;
+}
+
+// signed 16x16 -> 32 multiply add accumulate
+#define MACS(rt, ra, rb) rt += (ra) * (rb)
+
+#define MLSS(rt, ra, rb) ((rt) -= (ra) * (rb))
+
+#define SUM8(op, sum, w, p)\
+{\
+ op(sum, (w)[0 * 64], (p)[0 * 64]);\
+ op(sum, (w)[1 * 64], (p)[1 * 64]);\
+ op(sum, (w)[2 * 64], (p)[2 * 64]);\
+ op(sum, (w)[3 * 64], (p)[3 * 64]);\
+ op(sum, (w)[4 * 64], (p)[4 * 64]);\
+ op(sum, (w)[5 * 64], (p)[5 * 64]);\
+ op(sum, (w)[6 * 64], (p)[6 * 64]);\
+ op(sum, (w)[7 * 64], (p)[7 * 64]);\
+}
+
+#define SUM8P2(sum1, op1, sum2, op2, w1, w2, p) \
+{\
+ tmp_s = p[0 * 64];\
+ op1(sum1, (w1)[0 * 64], tmp_s);\
+ op2(sum2, (w2)[0 * 64], tmp_s);\
+ tmp_s = p[1 * 64];\
+ op1(sum1, (w1)[1 * 64], tmp_s);\
+ op2(sum2, (w2)[1 * 64], tmp_s);\
+ tmp_s = p[2 * 64];\
+ op1(sum1, (w1)[2 * 64], tmp_s);\
+ op2(sum2, (w2)[2 * 64], tmp_s);\
+ tmp_s = p[3 * 64];\
+ op1(sum1, (w1)[3 * 64], tmp_s);\
+ op2(sum2, (w2)[3 * 64], tmp_s);\
+ tmp_s = p[4 * 64];\
+ op1(sum1, (w1)[4 * 64], tmp_s);\
+ op2(sum2, (w2)[4 * 64], tmp_s);\
+ tmp_s = p[5 * 64];\
+ op1(sum1, (w1)[5 * 64], tmp_s);\
+ op2(sum2, (w2)[5 * 64], tmp_s);\
+ tmp_s = p[6 * 64];\
+ op1(sum1, (w1)[6 * 64], tmp_s);\
+ op2(sum2, (w2)[6 * 64], tmp_s);\
+ tmp_s = p[7 * 64];\
+ op1(sum1, (w1)[7 * 64], tmp_s);\
+ op2(sum2, (w2)[7 * 64], tmp_s);\
+}
+
+#define FIXHR(a) ((int)((a) * (1LL<<32) + 0.5))
+
+// tab[i][j] = 1.0 / (2.0 * cos(pi*(2*k+1) / 2^(6 - j)))
+
+// cos(i*pi/64)
+
+#define COS0_0 FIXHR(0.50060299823519630134/2)
+#define COS0_1 FIXHR(0.50547095989754365998/2)
+#define COS0_2 FIXHR(0.51544730992262454697/2)
+#define COS0_3 FIXHR(0.53104259108978417447/2)
+#define COS0_4 FIXHR(0.55310389603444452782/2)
+#define COS0_5 FIXHR(0.58293496820613387367/2)
+#define COS0_6 FIXHR(0.62250412303566481615/2)
+#define COS0_7 FIXHR(0.67480834145500574602/2)
+#define COS0_8 FIXHR(0.74453627100229844977/2)
+#define COS0_9 FIXHR(0.83934964541552703873/2)
+#define COS0_10 FIXHR(0.97256823786196069369/2)
+#define COS0_11 FIXHR(1.16943993343288495515/4)
+#define COS0_12 FIXHR(1.48416461631416627724/4)
+#define COS0_13 FIXHR(2.05778100995341155085/8)
+#define COS0_14 FIXHR(3.40760841846871878570/8)
+#define COS0_15 FIXHR(10.19000812354805681150/32)
+
+#define COS1_0 FIXHR(0.50241928618815570551/2)
+#define COS1_1 FIXHR(0.52249861493968888062/2)
+#define COS1_2 FIXHR(0.56694403481635770368/2)
+#define COS1_3 FIXHR(0.64682178335999012954/2)
+#define COS1_4 FIXHR(0.78815462345125022473/2)
+#define COS1_5 FIXHR(1.06067768599034747134/4)
+#define COS1_6 FIXHR(1.72244709823833392782/4)
+#define COS1_7 FIXHR(5.10114861868916385802/16)
+
+#define COS2_0 FIXHR(0.50979557910415916894/2)
+#define COS2_1 FIXHR(0.60134488693504528054/2)
+#define COS2_2 FIXHR(0.89997622313641570463/2)
+#define COS2_3 FIXHR(2.56291544774150617881/8)
+
+#define COS3_0 FIXHR(0.54119610014619698439/2)
+#define COS3_1 FIXHR(1.30656296487637652785/4)
+
+#define COS4_0 FIXHR(0.70710678118654752439/2)
+
+/* butterfly operator */
+#define BF(a, b, c, s)\
+{\
+ tmp0 = tab[a] + tab[b];\
+ tmp1 = tab[a] - tab[b];\
+ tab[a] = tmp0;\
+ tab[b] = MULH(tmp1<<(s), c);\
+}
+
+#define BF1(a, b, c, d)\
+{\
+ BF(a, b, COS4_0, 1);\
+ BF(c, d,-COS4_0, 1);\
+ tab[c] += tab[d];\
+}
+
+#define BF2(a, b, c, d)\
+{\
+ BF(a, b, COS4_0, 1);\
+ BF(c, d,-COS4_0, 1);\
+ tab[c] += tab[d];\
+ tab[a] += tab[c];\
+ tab[c] += tab[b];\
+ tab[b] += tab[d];\
+}
+
+#define ADD(a, b) tab[a] += tab[b]
+
+// DCT32 without 1/sqrt(2) coef zero scaling.
+static void dct32(int32 *out, int32 *tab) {
+ int tmp0, tmp1;
+
+ // pass 1
+ BF( 0, 31, COS0_0 , 1);
+ BF(15, 16, COS0_15, 5);
+ // pass 2
+ BF( 0, 15, COS1_0 , 1);
+ BF(16, 31,-COS1_0 , 1);
+ // pass 1
+ BF( 7, 24, COS0_7 , 1);
+ BF( 8, 23, COS0_8 , 1);
+ // pass 2
+ BF( 7, 8, COS1_7 , 4);
+ BF(23, 24,-COS1_7 , 4);
+ // pass 3
+ BF( 0, 7, COS2_0 , 1);
+ BF( 8, 15,-COS2_0 , 1);
+ BF(16, 23, COS2_0 , 1);
+ BF(24, 31,-COS2_0 , 1);
+ // pass 1
+ BF( 3, 28, COS0_3 , 1);
+ BF(12, 19, COS0_12, 2);
+ // pass 2
+ BF( 3, 12, COS1_3 , 1);
+ BF(19, 28,-COS1_3 , 1);
+ // pass 1
+ BF( 4, 27, COS0_4 , 1);
+ BF(11, 20, COS0_11, 2);
+ // pass 2
+ BF( 4, 11, COS1_4 , 1);
+ BF(20, 27,-COS1_4 , 1);
+ // pass 3
+ BF( 3, 4, COS2_3 , 3);
+ BF(11, 12,-COS2_3 , 3);
+ BF(19, 20, COS2_3 , 3);
+ BF(27, 28,-COS2_3 , 3);
+ // pass 4
+ BF( 0, 3, COS3_0 , 1);
+ BF( 4, 7,-COS3_0 , 1);
+ BF( 8, 11, COS3_0 , 1);
+ BF(12, 15,-COS3_0 , 1);
+ BF(16, 19, COS3_0 , 1);
+ BF(20, 23,-COS3_0 , 1);
+ BF(24, 27, COS3_0 , 1);
+ BF(28, 31,-COS3_0 , 1);
+
+ // pass 1
+ BF( 1, 30, COS0_1 , 1);
+ BF(14, 17, COS0_14, 3);
+ // pass 2
+ BF( 1, 14, COS1_1 , 1);
+ BF(17, 30,-COS1_1 , 1);
+ // pass 1
+ BF( 6, 25, COS0_6 , 1);
+ BF( 9, 22, COS0_9 , 1);
+ // pass 2
+ BF( 6, 9, COS1_6 , 2);
+ BF(22, 25,-COS1_6 , 2);
+ // pass 3
+ BF( 1, 6, COS2_1 , 1);
+ BF( 9, 14,-COS2_1 , 1);
+ BF(17, 22, COS2_1 , 1);
+ BF(25, 30,-COS2_1 , 1);
+
+ // pass 1
+ BF( 2, 29, COS0_2 , 1);
+ BF(13, 18, COS0_13, 3);
+ // pass 2
+ BF( 2, 13, COS1_2 , 1);
+ BF(18, 29,-COS1_2 , 1);
+ // pass 1
+ BF( 5, 26, COS0_5 , 1);
+ BF(10, 21, COS0_10, 1);
+ // pass 2
+ BF( 5, 10, COS1_5 , 2);
+ BF(21, 26,-COS1_5 , 2);
+ // pass 3
+ BF( 2, 5, COS2_2 , 1);
+ BF(10, 13,-COS2_2 , 1);
+ BF(18, 21, COS2_2 , 1);
+ BF(26, 29,-COS2_2 , 1);
+ // pass 4
+ BF( 1, 2, COS3_1 , 2);
+ BF( 5, 6,-COS3_1 , 2);
+ BF( 9, 10, COS3_1 , 2);
+ BF(13, 14,-COS3_1 , 2);
+ BF(17, 18, COS3_1 , 2);
+ BF(21, 22,-COS3_1 , 2);
+ BF(25, 26, COS3_1 , 2);
+ BF(29, 30,-COS3_1 , 2);
+
+ // pass 5
+ BF1( 0, 1, 2, 3);
+ BF2( 4, 5, 6, 7);
+ BF1( 8, 9, 10, 11);
+ BF2(12, 13, 14, 15);
+ BF1(16, 17, 18, 19);
+ BF2(20, 21, 22, 23);
+ BF1(24, 25, 26, 27);
+ BF2(28, 29, 30, 31);
+
+ // pass 6
+ ADD( 8, 12);
+ ADD(12, 10);
+ ADD(10, 14);
+ ADD(14, 9);
+ ADD( 9, 13);
+ ADD(13, 11);
+ ADD(11, 15);
+
+ out[ 0] = tab[0];
+ out[16] = tab[1];
+ out[ 8] = tab[2];
+ out[24] = tab[3];
+ out[ 4] = tab[4];
+ out[20] = tab[5];
+ out[12] = tab[6];
+ out[28] = tab[7];
+ out[ 2] = tab[8];
+ out[18] = tab[9];
+ out[10] = tab[10];
+ out[26] = tab[11];
+ out[ 6] = tab[12];
+ out[22] = tab[13];
+ out[14] = tab[14];
+ out[30] = tab[15];
+
+ ADD(24, 28);
+ ADD(28, 26);
+ ADD(26, 30);
+ ADD(30, 25);
+ ADD(25, 29);
+ ADD(29, 27);
+ ADD(27, 31);
+
+ out[ 1] = tab[16] + tab[24];
+ out[17] = tab[17] + tab[25];
+ out[ 9] = tab[18] + tab[26];
+ out[25] = tab[19] + tab[27];
+ out[ 5] = tab[20] + tab[28];
+ out[21] = tab[21] + tab[29];
+ out[13] = tab[22] + tab[30];
+ out[29] = tab[23] + tab[31];
+ out[ 3] = tab[24] + tab[20];
+ out[19] = tab[25] + tab[21];
+ out[11] = tab[26] + tab[22];
+ out[27] = tab[27] + tab[23];
+ out[ 7] = tab[28] + tab[18];
+ out[23] = tab[29] + tab[19];
+ out[15] = tab[30] + tab[17];
+ out[31] = tab[31];
+}
+
+// 32 sub band synthesis filter. Input: 32 sub band samples, Output:
+// 32 samples.
+// XXX: optimize by avoiding ring buffer usage
+void ff_mpa_synth_filter(int16 *synth_buf_ptr, int *synth_buf_offset,
+ int16 *window, int *dither_state,
+ int16 *samples, int incr,
+ int32 sb_samples[32])
+{
+ int16 *synth_buf;
+ const int16 *w, *w2, *p;
+ int j, offset;
+ int16 *samples2;
+ int32 tmp[32];
+ int sum, sum2;
+ int tmp_s;
+
+ offset = *synth_buf_offset;
+ synth_buf = synth_buf_ptr + offset;
+
+ dct32(tmp, sb_samples);
+ for(j = 0; j < 32; j++) {
+ // NOTE: can cause a loss in precision if very high amplitude sound
+ if (tmp[j] < (-0x7fff - 1))
+ synth_buf[j] = (-0x7fff - 1);
+ else if (tmp[j] > 0x7fff)
+ synth_buf[j] = 0x7fff;
+ else
+ synth_buf[j] = tmp[j];
+ }
+
+ // copy to avoid wrap
+ memcpy(synth_buf + 512, synth_buf, 32 * sizeof(int16));
+
+ samples2 = samples + 31 * incr;
+ w = window;
+ w2 = window + 31;
+
+ sum = *dither_state;
+ p = synth_buf + 16;
+ SUM8(MACS, sum, w, p);
+ p = synth_buf + 48;
+ SUM8(MLSS, sum, w + 32, p);
+ *samples = round_sample(&sum);
+ samples += incr;
+ w++;
+
+ // we calculate two samples at the same time to avoid one memory
+ // access per two sample
+ for(j = 1; j < 16; j++) {
+ sum2 = 0;
+ p = synth_buf + 16 + j;
+ SUM8P2(sum, MACS, sum2, MLSS, w, w2, p);
+ p = synth_buf + 48 - j;
+ SUM8P2(sum, MLSS, sum2, MLSS, w + 32, w2 + 32, p);
+
+ *samples = round_sample(&sum);
+ samples += incr;
+ sum += sum2;
+ *samples2 = round_sample(&sum);
+ samples2 -= incr;
+ w++;
+ w2--;
+ }
+
+ p = synth_buf + 32;
+ SUM8(MLSS, sum, w + 32, p);
+ *samples = round_sample(&sum);
+ *dither_state= sum;
+
+ offset = (offset - 32) & 511;
+ *synth_buf_offset = offset;
+}
+
+/**
+ * parses a vlc code, faster then get_vlc()
+ * @param bits is the number of bits which will be read at once, must be
+ * identical to nb_bits in init_vlc()
+ * @param max_depth is the number of times bits bits must be read to completely
+ * read the longest vlc code
+ * = (max_vlc_length + bits - 1) / bits
+ */
+static int getVlc2(GetBitContext *s, int16 (*table)[2], int bits, int maxDepth) {
+ int reIndex;
+ int reCache;
+ int index;
+ int code;
+ int n;
+
+ debug(1, "int getVlc2(GetBitContext *s, int16 (*table)[2], int bits, int maxDepth)");
+
+ reIndex = s->index;
+ reCache = READ_LE_UINT32(s->buffer + (reIndex >> 3)) >> (reIndex & 0x07);
+ index = reCache & (0xffffffff >> (32 - bits));
+ code = table[index][0];
+ n = table[index][1];
+
+ debug(1, "reIndex : %d", reIndex);
+ debug(1, "reCache : %d", reCache);
+ debug(1, "index : %d", index);
+ debug(1, "code : %d", code);
+ debug(1, "n : %d", n);
+
+ if (maxDepth > 1 && n < 0){
+ reIndex += bits;
+ reCache = READ_LE_UINT32(s->buffer + (reIndex >> 3)) >> (reIndex & 0x07);
+
+ int nbBits = -n;
+
+ index = (reCache & (0xffffffff >> (32 - nbBits))) + code;
+ code = table[index][0];
+ n = table[index][1];
+
+ if(maxDepth > 2 && n < 0) {
+ reIndex += nbBits;
+ reCache = READ_LE_UINT32(s->buffer + (reIndex >> 3)) >> (reIndex & 0x07);
+
+ nbBits = -n;
+
+ index = (reCache & (0xffffffff >> (32 - nbBits))) + code;
+ code = table[index][0];
+ n = table[index][1];
+ }
+ }
+
+ reCache >>= n;
+ s->index = reIndex + n;
+ return code;
+}
+
+static int allocTable(VLC *vlc, int size, int use_static) {
+ int index;
+ index = vlc->table_size;
+ vlc->table_size += size;
+ if (vlc->table_size > vlc->table_allocated) {
+ if(use_static)
+ error("QDM2 cant do anything, init_vlc() is used with too little memory");
+ vlc->table_allocated += (1 << vlc->bits);
+ vlc->table = (int16 (*)[2])realloc(vlc->table, sizeof(int16 *) * 2 * vlc->table_allocated);
+ if (!vlc->table)
+ return -1;
+ }
+ return index;
+}
+
+#define GET_DATA(v, table, i, wrap, size)\
+{\
+ const uint8 *ptr = (const uint8 *)table + i * wrap;\
+ switch(size) {\
+ case 1:\
+ v = *(const uint8 *)ptr;\
+ break;\
+ case 2:\
+ v = *(const uint16 *)ptr;\
+ break;\
+ default:\
+ v = *(const uint32 *)ptr;\
+ break;\
+ }\
+}
+
+static int build_table(VLC *vlc, int table_nb_bits,
+ int nb_codes,
+ const void *bits, int bits_wrap, int bits_size,
+ const void *codes, int codes_wrap, int codes_size,
+ const void *symbols, int symbols_wrap, int symbols_size,
+ int code_prefix, int n_prefix, int flags)
+{
+ int i, j, k, n, table_size, table_index, nb, n1, index, code_prefix2, symbol;
+ uint32 code;
+ int16 (*table)[2];
+
+ table_size = 1 << table_nb_bits;
+ table_index = allocTable(vlc, table_size, flags & 4);
+ debug(2, "QDM2 new table index=%d size=%d code_prefix=%x n=%d", table_index, table_size, code_prefix, n_prefix);
+ if (table_index < 0)
+ return -1;
+ table = &vlc->table[table_index];
+
+ for(i = 0; i < table_size; i++) {
+ table[i][1] = 0; //bits
+ table[i][0] = -1; //codes
+ }
+
+ // first pass: map codes and compute auxillary table sizes
+ for(i = 0; i < nb_codes; i++) {
+ GET_DATA(n, bits, i, bits_wrap, bits_size);
+ GET_DATA(code, codes, i, codes_wrap, codes_size);
+ // we accept tables with holes
+ if (n <= 0)
+ continue;
+ if (!symbols)
+ symbol = i;
+ else
+ GET_DATA(symbol, symbols, i, symbols_wrap, symbols_size);
+ debug(2, "QDM2 i=%d n=%d code=0x%x", i, n, code);
+ // if code matches the prefix, it is in the table
+ n -= n_prefix;
+ if(flags & 2)
+ code_prefix2= code & (n_prefix>=32 ? 0xffffffff : (1 << n_prefix)-1);
+ else
+ code_prefix2= code >> n;
+ if (n > 0 && code_prefix2 == code_prefix) {
+ if (n <= table_nb_bits) {
+ // no need to add another table
+ j = (code << (table_nb_bits - n)) & (table_size - 1);
+ nb = 1 << (table_nb_bits - n);
+ for(k = 0; k < nb; k++) {
+ if(flags & 2)
+ j = (code >> n_prefix) + (k<<n);
+ debug(2, "QDM2 %4x: code=%d n=%d",j, i, n);
+ if (table[j][1] /*bits*/ != 0) {
+ error("QDM2 incorrect codes");
+ return -1;
+ }
+ table[j][1] = n; //bits
+ table[j][0] = symbol;
+ j++;
+ }
+ } else {
+ n -= table_nb_bits;
+ j = (code >> ((flags & 2) ? n_prefix : n)) & ((1 << table_nb_bits) - 1);
+ debug(2, "QDM2 %4x: n=%d (subtable)", j, n);
+ // compute table size
+ n1 = -table[j][1]; //bits
+ if (n > n1)
+ n1 = n;
+ table[j][1] = -n1; //bits
+ }
+ }
+ }
+
+ // second pass : fill auxillary tables recursively
+ for(i = 0;i < table_size; i++) {
+ n = table[i][1]; //bits
+ if (n < 0) {
+ n = -n;
+ if (n > table_nb_bits) {
+ n = table_nb_bits;
+ table[i][1] = -n; //bits
+ }
+ index = build_table(vlc, n, nb_codes,
+ bits, bits_wrap, bits_size,
+ codes, codes_wrap, codes_size,
+ symbols, symbols_wrap, symbols_size,
+ (flags & 2) ? (code_prefix | (i << n_prefix)) : ((code_prefix << table_nb_bits) | i),
+ n_prefix + table_nb_bits, flags);
+ if (index < 0)
+ return -1;
+ // note: realloc has been done, so reload tables
+ table = &vlc->table[table_index];
+ table[i][0] = index; //code
+ }
+ }
+ return table_index;
+}
+
+/* Build VLC decoding tables suitable for use with get_vlc().
+
+ 'nb_bits' set thee decoding table size (2^nb_bits) entries. The
+ bigger it is, the faster is the decoding. But it should not be too
+ big to save memory and L1 cache. '9' is a good compromise.
+
+ 'nb_codes' : number of vlcs codes
+
+ 'bits' : table which gives the size (in bits) of each vlc code.
+
+ 'codes' : table which gives the bit pattern of of each vlc code.
+
+ 'symbols' : table which gives the values to be returned from get_vlc().
+
+ 'xxx_wrap' : give the number of bytes between each entry of the
+ 'bits' or 'codes' tables.
+
+ 'xxx_size' : gives the number of bytes of each entry of the 'bits'
+ or 'codes' tables.
+
+ 'wrap' and 'size' allows to use any memory configuration and types
+ (byte/word/long) to store the 'bits', 'codes', and 'symbols' tables.
+
+ 'use_static' should be set to 1 for tables, which should be freed
+ with av_free_static(), 0 if free_vlc() will be used.
+*/
+void initVlcSparse(VLC *vlc, int nb_bits, int nb_codes,
+ const void *bits, int bits_wrap, int bits_size,
+ const void *codes, int codes_wrap, int codes_size,
+ const void *symbols, int symbols_wrap, int symbols_size) {
+ vlc->bits = nb_bits;
+
+ if(vlc->table_size && vlc->table_size == vlc->table_allocated) {
+ return;
+ } else if(vlc->table_size) {
+ error("called on a partially initialized table");
+ }
+
+ debug(2, "QDM2 build table nb_codes=%d", nb_codes);
+
+ if (build_table(vlc, nb_bits, nb_codes,
+ bits, bits_wrap, bits_size,
+ codes, codes_wrap, codes_size,
+ symbols, symbols_wrap, symbols_size,
+ 0, 0, 4 | 2) < 0) {
+ free(&vlc->table);
+ return; // Error
+ }
+
+ if(vlc->table_size != vlc->table_allocated)
+ error("QDM2 needed %d had %d", vlc->table_size, vlc->table_allocated);
+}
+
+void QDM2Stream::softclipTableInit(void) {
+ uint16 i;
+ double dfl = SOFTCLIP_THRESHOLD - 32767;
+ float delta = 1.0 / -dfl;
+
+ for (i = 0; i < ARRAYSIZE(_softclipTable); i++)
+ _softclipTable[i] = SOFTCLIP_THRESHOLD - ((int)(sin((float)i * delta) * dfl) & 0x0000FFFF);
+}
+
+// random generated table
+void QDM2Stream::rndTableInit(void) {
+ uint16 i;
+ uint16 j;
+ uint32 ldw, hdw;
+ // TODO: Replace Code with uint64 less version...
+ int64_t tmp64_1;
+ int64_t random_seed = 0;
+ float delta = 1.0 / 16384.0;
+
+ for(i = 0; i < ARRAYSIZE(_noiseTable); i++) {
+ random_seed = random_seed * 214013 + 2531011;
+ _noiseTable[i] = (delta * (float)(((int32)random_seed >> 16) & 0x00007FFF)- 1.0) * 1.3;
+ }
+
+ for (i = 0; i < 256; i++) {
+ random_seed = 81;
+ ldw = i;
+ for (j = 0; j < 5; j++) {
+ _randomDequantIndex[i][j] = (uint8)((ldw / random_seed) & 0xFF);
+ ldw = (uint32)ldw % (uint32)random_seed;
+ tmp64_1 = (random_seed * 0x55555556);
+ hdw = (uint32)(tmp64_1 >> 32);
+ random_seed = (int64_t)(hdw + (ldw >> 31));
+ }
+ }
+
+ for (i = 0; i < 128; i++) {
+ random_seed = 25;
+ ldw = i;
+ for (j = 0; j < 3; j++) {
+ _randomDequantType24[i][j] = (uint8)((ldw / random_seed) & 0xFF);
+ ldw = (uint32)ldw % (uint32)random_seed;
+ tmp64_1 = (random_seed * 0x66666667);
+ hdw = (uint32)(tmp64_1 >> 33);
+ random_seed = hdw + (ldw >> 31);
+ }
+ }
+}
+
+void QDM2Stream::initNoiseSamples(void) {
+ uint16 i;
+ uint32 random_seed = 0;
+ float delta = 1.0 / 16384.0;
+
+ for (i = 0; i < ARRAYSIZE(_noiseSamples); i++) {
+ random_seed = random_seed * 214013 + 2531011;
+ _noiseSamples[i] = (delta * (float)((random_seed >> 16) & 0x00007fff) - 1.0);
+ }
+}
+
+static const uint16 qdm2_vlc_offs[18] = {
+ 0, 260, 566, 598, 894, 1166, 1230, 1294, 1678, 1950, 2214, 2278, 2310, 2570, 2834, 3124, 3448, 3838
+};
+
+void QDM2Stream::initVlc(void) {
+ static int16 qdm2_table[3838][2];
+
+ if (!_vlcsInitialized) {
+ _vlcTabLevel.table = &qdm2_table[qdm2_vlc_offs[0]];
+ _vlcTabLevel.table_allocated = qdm2_vlc_offs[1] - qdm2_vlc_offs[0];
+ _vlcTabLevel.table_size = 0;
+ initVlcSparse(&_vlcTabLevel, 8, 24,
+ vlc_tab_level_huffbits, 1, 1,
+ vlc_tab_level_huffcodes, 2, 2, NULL, 0, 0);
+
+ _vlcTabDiff.table = &qdm2_table[qdm2_vlc_offs[1]];
+ _vlcTabDiff.table_allocated = qdm2_vlc_offs[2] - qdm2_vlc_offs[1];
+ _vlcTabDiff.table_size = 0;
+ initVlcSparse(&_vlcTabDiff, 8, 37,
+ vlc_tab_diff_huffbits, 1, 1,
+ vlc_tab_diff_huffcodes, 2, 2, NULL, 0, 0);
+
+ _vlcTabRun.table = &qdm2_table[qdm2_vlc_offs[2]];
+ _vlcTabRun.table_allocated = qdm2_vlc_offs[3] - qdm2_vlc_offs[2];
+ _vlcTabRun.table_size = 0;
+ initVlcSparse(&_vlcTabRun, 5, 6,
+ vlc_tab_run_huffbits, 1, 1,
+ vlc_tab_run_huffcodes, 1, 1, NULL, 0, 0);
+
+ _fftLevelExpAltVlc.table = &qdm2_table[qdm2_vlc_offs[3]];
+ _fftLevelExpAltVlc.table_allocated = qdm2_vlc_offs[4] - qdm2_vlc_offs[3];
+ _fftLevelExpAltVlc.table_size = 0;
+ initVlcSparse(&_fftLevelExpAltVlc, 8, 28,
+ fft_level_exp_alt_huffbits, 1, 1,
+ fft_level_exp_alt_huffcodes, 2, 2, NULL, 0, 0);
+
+ _fftLevelExpVlc.table = &qdm2_table[qdm2_vlc_offs[4]];
+ _fftLevelExpVlc.table_allocated = qdm2_vlc_offs[5] - qdm2_vlc_offs[4];
+ _fftLevelExpVlc.table_size = 0;
+ initVlcSparse(&_fftLevelExpVlc, 8, 20,
+ fft_level_exp_huffbits, 1, 1,
+ fft_level_exp_huffcodes, 2, 2, NULL, 0, 0);
+
+ _fftStereoExpVlc.table = &qdm2_table[qdm2_vlc_offs[5]];
+ _fftStereoExpVlc.table_allocated = qdm2_vlc_offs[6] - qdm2_vlc_offs[5];
+ _fftStereoExpVlc.table_size = 0;
+ initVlcSparse(&_fftStereoExpVlc, 6, 7,
+ fft_stereo_exp_huffbits, 1, 1,
+ fft_stereo_exp_huffcodes, 1, 1, NULL, 0, 0);
+
+ _fftStereoPhaseVlc.table = &qdm2_table[qdm2_vlc_offs[6]];
+ _fftStereoPhaseVlc.table_allocated = qdm2_vlc_offs[7] - qdm2_vlc_offs[6];
+ _fftStereoPhaseVlc.table_size = 0;
+ initVlcSparse(&_fftStereoPhaseVlc, 6, 9,
+ fft_stereo_phase_huffbits, 1, 1,
+ fft_stereo_phase_huffcodes, 1, 1, NULL, 0, 0);
+
+ _vlcTabToneLevelIdxHi1.table = &qdm2_table[qdm2_vlc_offs[7]];
+ _vlcTabToneLevelIdxHi1.table_allocated = qdm2_vlc_offs[8] - qdm2_vlc_offs[7];
+ _vlcTabToneLevelIdxHi1.table_size = 0;
+ initVlcSparse(&_vlcTabToneLevelIdxHi1, 8, 20,
+ vlc_tab_tone_level_idx_hi1_huffbits, 1, 1,
+ vlc_tab_tone_level_idx_hi1_huffcodes, 2, 2, NULL, 0, 0);
+
+ _vlcTabToneLevelIdxMid.table = &qdm2_table[qdm2_vlc_offs[8]];
+ _vlcTabToneLevelIdxMid.table_allocated = qdm2_vlc_offs[9] - qdm2_vlc_offs[8];
+ _vlcTabToneLevelIdxMid.table_size = 0;
+ initVlcSparse(&_vlcTabToneLevelIdxMid, 8, 24,
+ vlc_tab_tone_level_idx_mid_huffbits, 1, 1,
+ vlc_tab_tone_level_idx_mid_huffcodes, 2, 2, NULL, 0, 0);
+
+ _vlcTabToneLevelIdxHi2.table = &qdm2_table[qdm2_vlc_offs[9]];
+ _vlcTabToneLevelIdxHi2.table_allocated = qdm2_vlc_offs[10] - qdm2_vlc_offs[9];
+ _vlcTabToneLevelIdxHi2.table_size = 0;
+ initVlcSparse(&_vlcTabToneLevelIdxHi2, 8, 24,
+ vlc_tab_tone_level_idx_hi2_huffbits, 1, 1,
+ vlc_tab_tone_level_idx_hi2_huffcodes, 2, 2, NULL, 0, 0);
+
+ _vlcTabType30.table = &qdm2_table[qdm2_vlc_offs[10]];
+ _vlcTabType30.table_allocated = qdm2_vlc_offs[11] - qdm2_vlc_offs[10];
+ _vlcTabType30.table_size = 0;
+ initVlcSparse(&_vlcTabType30, 6, 9,
+ vlc_tab_type30_huffbits, 1, 1,
+ vlc_tab_type30_huffcodes, 1, 1, NULL, 0, 0);
+
+ _vlcTabType34.table = &qdm2_table[qdm2_vlc_offs[11]];
+ _vlcTabType34.table_allocated = qdm2_vlc_offs[12] - qdm2_vlc_offs[11];
+ _vlcTabType34.table_size = 0;
+ initVlcSparse(&_vlcTabType34, 5, 10,
+ vlc_tab_type34_huffbits, 1, 1,
+ vlc_tab_type34_huffcodes, 1, 1, NULL, 0, 0);
+
+ _vlcTabFftToneOffset[0].table = &qdm2_table[qdm2_vlc_offs[12]];
+ _vlcTabFftToneOffset[0].table_allocated = qdm2_vlc_offs[13] - qdm2_vlc_offs[12];
+ _vlcTabFftToneOffset[0].table_size = 0;
+ initVlcSparse(&_vlcTabFftToneOffset[0], 8, 23,
+ vlc_tab_fft_tone_offset_0_huffbits, 1, 1,
+ vlc_tab_fft_tone_offset_0_huffcodes, 2, 2, NULL, 0, 0);
+
+ _vlcTabFftToneOffset[1].table = &qdm2_table[qdm2_vlc_offs[13]];
+ _vlcTabFftToneOffset[1].table_allocated = qdm2_vlc_offs[14] - qdm2_vlc_offs[13];
+ _vlcTabFftToneOffset[1].table_size = 0;
+ initVlcSparse(&_vlcTabFftToneOffset[1], 8, 28,
+ vlc_tab_fft_tone_offset_1_huffbits, 1, 1,
+ vlc_tab_fft_tone_offset_1_huffcodes, 2, 2, NULL, 0, 0);
+
+ _vlcTabFftToneOffset[2].table = &qdm2_table[qdm2_vlc_offs[14]];
+ _vlcTabFftToneOffset[2].table_allocated = qdm2_vlc_offs[15] - qdm2_vlc_offs[14];
+ _vlcTabFftToneOffset[2].table_size = 0;
+ initVlcSparse(&_vlcTabFftToneOffset[2], 8, 32,
+ vlc_tab_fft_tone_offset_2_huffbits, 1, 1,
+ vlc_tab_fft_tone_offset_2_huffcodes, 2, 2, NULL, 0, 0);
+
+ _vlcTabFftToneOffset[3].table = &qdm2_table[qdm2_vlc_offs[15]];
+ _vlcTabFftToneOffset[3].table_allocated = qdm2_vlc_offs[16] - qdm2_vlc_offs[15];
+ _vlcTabFftToneOffset[3].table_size = 0;
+ initVlcSparse(&_vlcTabFftToneOffset[3], 8, 35,
+ vlc_tab_fft_tone_offset_3_huffbits, 1, 1,
+ vlc_tab_fft_tone_offset_3_huffcodes, 2, 2, NULL, 0, 0);
+
+ _vlcTabFftToneOffset[4].table = &qdm2_table[qdm2_vlc_offs[16]];
+ _vlcTabFftToneOffset[4].table_allocated = qdm2_vlc_offs[17] - qdm2_vlc_offs[16];
+ _vlcTabFftToneOffset[4].table_size = 0;
+ initVlcSparse(&_vlcTabFftToneOffset[4], 8, 38,
+ vlc_tab_fft_tone_offset_4_huffbits, 1, 1,
+ vlc_tab_fft_tone_offset_4_huffcodes, 2, 2, NULL, 0, 0);
+
+ _vlcsInitialized = true;
+ }
+}
+
+QDM2Stream::QDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData) {
+ uint32 tmp;
+ int32 tmp_s;
+ int tmp_val;
+ int i;
+
+ debug(1, "QDM2Stream::QDM2Stream() Call");
+
+ _stream = stream;
+ _compressedData = NULL;
+ _subPacket = 0;
+ memset(_quantizedCoeffs, 0, sizeof(_quantizedCoeffs));
+ memset(_fftLevelExp, 0, sizeof(_fftLevelExp));
+ _noiseIdx = 0;
+ memset(_fftCoefsMinIndex, 0, sizeof(_fftCoefsMinIndex));
+ memset(_fftCoefsMaxIndex, 0, sizeof(_fftCoefsMaxIndex));
+ _fftToneStart = 0;
+ _fftToneEnd = 0;
+ for(i = 0; i < ARRAYSIZE(_subPacketListA); i++) {
+ _subPacketListA[i].packet = NULL;
+ _subPacketListA[i].next = NULL;
+ }
+ _subPacketsB = 0;
+ for(i = 0; i < ARRAYSIZE(_subPacketListB); i++) {
+ _subPacketListB[i].packet = NULL;
+ _subPacketListB[i].next = NULL;
+ }
+ for(i = 0; i < ARRAYSIZE(_subPacketListC); i++) {
+ _subPacketListC[i].packet = NULL;
+ _subPacketListC[i].next = NULL;
+ }
+ for(i = 0; i < ARRAYSIZE(_subPacketListD); i++) {
+ _subPacketListD[i].packet = NULL;
+ _subPacketListD[i].next = NULL;
+ }
+ memset(_synthBuf, 0, sizeof(_synthBuf));
+ memset(_synthBufOffset, 0, sizeof(_synthBufOffset));
+ memset(_sbSamples, 0, sizeof(_sbSamples));
+ memset(_outputBuffer, 0, sizeof(_outputBuffer));
+ _vlcsInitialized = false;
+ _superblocktype_2_3 = 0;
+ _hasErrors = false;
+
+ // Rewind extraData stream from any previous calls...
+ extraData->seek(0, SEEK_SET);
+
+ tmp_s = extraData->readSint32BE();
+ debug(1, "QDM2Stream::QDM2Stream() extraSize: %d", tmp_s);
+ if ((extraData->size() - extraData->pos()) / 4 + 1 != tmp_s)
+ warning("QDM2Stream::QDM2Stream() extraSize mismatch - Expected %d", (extraData->size() - extraData->pos()) / 4 + 1);
+ if (tmp_s < 12)
+ error("QDM2Stream::QDM2Stream() Insufficient extraData");
+
+ tmp = extraData->readUint32BE();
+ debug(1, "QDM2Stream::QDM2Stream() extraTag: %d", tmp);
+ if (tmp != MKID_BE('frma'))
+ warning("QDM2Stream::QDM2Stream() extraTag mismatch");
+
+ tmp = extraData->readUint32BE();
+ debug(1, "QDM2Stream::QDM2Stream() extraType: %d", tmp);
+ if (tmp == MKID_BE('QDMC'))
+ warning("QDM2Stream::QDM2Stream() QDMC stream type not supported.");
+ else if (tmp != MKID_BE('QDM2'))
+ error("QDM2Stream::QDM2Stream() Unsupported stream type");
+
+ tmp_s = extraData->readSint32BE();
+ debug(1, "QDM2Stream::QDM2Stream() extraSize2: %d", tmp_s);
+ if ((extraData->size() - extraData->pos()) + 4 != tmp_s)
+ warning("QDM2Stream::QDM2Stream() extraSize2 mismatch - Expected %d", (extraData->size() - extraData->pos()) + 4);
+
+ tmp = extraData->readUint32BE();
+ debug(1, "QDM2Stream::QDM2Stream() extraTag2: %d", tmp);
+ if (tmp != MKID_BE('QDCA'))
+ warning("QDM2Stream::QDM2Stream() extraTag2 mismatch");
+
+ if (extraData->readUint32BE() != 1)
+ warning("QDM2Stream::QDM2Stream() u0 field not 1");
+
+ _channels = extraData->readUint32BE();
+ debug(1, "QDM2Stream::QDM2Stream() channels: %d", _channels);
+
+ _sampleRate = extraData->readUint32BE();
+ debug(1, "QDM2Stream::QDM2Stream() sampleRate: %d", _sampleRate);
+
+ _bitRate = extraData->readUint32BE();
+ debug(1, "QDM2Stream::QDM2Stream() bitRate: %d", _bitRate);
+
+ _blockSize = extraData->readUint32BE();
+ debug(1, "QDM2Stream::QDM2Stream() blockSize: %d", _blockSize);
+
+ _frameSize = extraData->readUint32BE();
+ debug(1, "QDM2Stream::QDM2Stream() frameSize: %d", _frameSize);
+
+ _packetSize = extraData->readUint32BE();
+ debug(1, "QDM2Stream::QDM2Stream() packetSize: %d", _packetSize);
+
+ if (extraData->size() - extraData->pos() != 0) {
+ tmp_s = extraData->readSint32BE();
+ debug(1, "QDM2Stream::QDM2Stream() extraSize3: %d", tmp_s);
+ if (extraData->size() + 4 != tmp_s)
+ warning("QDM2Stream::QDM2Stream() extraSize3 mismatch - Expected %d", extraData->size() + 4);
+
+ tmp = extraData->readUint32BE();
+ debug(1, "QDM2Stream::QDM2Stream() extraTag3: %d", tmp);
+ if (tmp != MKID_BE('QDCP'))
+ warning("QDM2Stream::QDM2Stream() extraTag3 mismatch");
+
+ if ((float)extraData->readUint32BE() != 1.0)
+ warning("QDM2Stream::QDM2Stream() uf0 field not 1.0");
+
+ if (extraData->readUint32BE() != 0)
+ warning("QDM2Stream::QDM2Stream() u1 field not 0");
+
+ if ((float)extraData->readUint32BE() != 1.0)
+ warning("QDM2Stream::QDM2Stream() uf1 field not 1.0");
+
+ if ((float)extraData->readUint32BE() != 1.0)
+ warning("QDM2Stream::QDM2Stream() uf2 field not 1.0");
+
+ if (extraData->readUint32BE() != 27)
+ warning("QDM2Stream::QDM2Stream() u2 field not 27");
+
+ if (extraData->readUint32BE() != 8)
+ warning("QDM2Stream::QDM2Stream() u3 field not 8");
+
+ if (extraData->readUint32BE() != 0)
+ warning("QDM2Stream::QDM2Stream() u4 field not 0");
+ }
+
+ _fftOrder = scummvm_log2(_frameSize) + 1;
+ _fftFrameSize = 2 * _frameSize; // complex has two floats
+
+ // something like max decodable tones
+ _groupOrder = scummvm_log2(_blockSize) + 1;
+ _sFrameSize = _blockSize / 16; // 16 iterations per super block
+
+ _subSampling = _fftOrder - 7;
+ _frequencyRange = 255 / (1 << (2 - _subSampling));
+
+ switch ((_subSampling * 2 + _channels - 1)) {
+ case 0:
+ tmp = 40;
+ break;
+ case 1:
+ tmp = 48;
+ break;
+ case 2:
+ tmp = 56;
+ break;
+ case 3:
+ tmp = 72;
+ break;
+ case 4:
+ tmp = 80;
+ break;
+ case 5:
+ tmp = 100;
+ break;
+ default:
+ tmp = _subSampling;
+ break;
+ }
+
+ tmp_val = 0;
+ if ((tmp * 1000) < _bitRate) tmp_val = 1;
+ if ((tmp * 1440) < _bitRate) tmp_val = 2;
+ if ((tmp * 1760) < _bitRate) tmp_val = 3;
+ if ((tmp * 2240) < _bitRate) tmp_val = 4;
+ _cmTableSelect = tmp_val;
+
+ if (_subSampling == 0)
+ tmp = 7999;
+ else
+ tmp = ((-(_subSampling -1)) & 8000) + 20000;
+
+ if (tmp < 8000)
+ _coeffPerSbSelect = 0;
+ else if (tmp <= 16000)
+ _coeffPerSbSelect = 1;
+ else
+ _coeffPerSbSelect = 2;
+
+ if (_fftOrder < 7 || _fftOrder > 9)
+ error("QDM2Stream::QDM2Stream() Unsupported fft_order: %d", _fftOrder);
+
+ rdftInit(&_rdftCtx, _fftOrder, IRDFT);
+
+ initVlc();
+ ff_mpa_synth_init(ff_mpa_synth_window);
+ softclipTableInit();
+ rndTableInit();
+ initNoiseSamples();
+
+ _compressedData = new uint8[_packetSize];
+}
+
+QDM2Stream::~QDM2Stream() {
+ delete[] _compressedData;
+ delete _stream;
+}
+
+static int qdm2_get_vlc(GetBitContext *gb, VLC *vlc, int flag, int depth) {
+ int value = getVlc2(gb, vlc->table, vlc->bits, depth);
+
+ // stage-2, 3 bits exponent escape sequence
+ if (value-- == 0)
+ value = getBits(gb, getBits (gb, 3) + 1);
+
+ // stage-3, optional
+ if (flag) {
+ int tmp = vlc_stage3_values[value];
+
+ if ((value & ~3) > 0)
+ tmp += getBits(gb, (value >> 2));
+ value = tmp;
+ }
+
+ return value;
+}
+
+static int qdm2_get_se_vlc(VLC *vlc, GetBitContext *gb, int depth)
+{
+ int value = qdm2_get_vlc(gb, vlc, 0, depth);
+
+ return (value & 1) ? ((value + 1) >> 1) : -(value >> 1);
+}
+
+/**
+ * QDM2 checksum
+ *
+ * @param data pointer to data to be checksum'ed
+ * @param length data length
+ * @param value checksum value
+ *
+ * @return 0 if checksum is OK
+ */
+static uint16 qdm2_packet_checksum(const uint8 *data, int length, int value) {
+ int i;
+
+ for (i = 0; i < length; i++)
+ value -= data[i];
+
+ return (uint16)(value & 0xffff);
+}
+
+/**
+ * Fills a QDM2SubPacket structure with packet type, size, and data pointer.
+ *
+ * @param gb bitreader context
+ * @param sub_packet packet under analysis
+ */
+static void qdm2_decode_sub_packet_header(GetBitContext *gb, QDM2SubPacket *sub_packet)
+{
+ sub_packet->type = getBits (gb, 8);
+
+ if (sub_packet->type == 0) {
+ sub_packet->size = 0;
+ sub_packet->data = NULL;
+ } else {
+ sub_packet->size = getBits (gb, 8);
+
+ if (sub_packet->type & 0x80) {
+ sub_packet->size <<= 8;
+ sub_packet->size |= getBits (gb, 8);
+ sub_packet->type &= 0x7f;
+ }
+
+ if (sub_packet->type == 0x7f)
+ sub_packet->type |= (getBits (gb, 8) << 8);
+
+ sub_packet->data = &gb->buffer[getBitsCount(gb) / 8]; // FIXME: this depends on bitreader internal data
+ }
+
+ debug(1, "QDM2 Subpacket: type=%d size=%d start_offs=%x", sub_packet->type, sub_packet->size, getBitsCount(gb) / 8);
+}
+
+/**
+ * Return node pointer to first packet of requested type in list.
+ *
+ * @param list list of subpackets to be scanned
+ * @param type type of searched subpacket
+ * @return node pointer for subpacket if found, else NULL
+ */
+static QDM2SubPNode* qdm2_search_subpacket_type_in_list(QDM2SubPNode *list, int type)
+{
+ while (list != NULL && list->packet != NULL) {
+ if (list->packet->type == type)
+ return list;
+ list = list->next;
+ }
+ return NULL;
+}
+
+/**
+ * Replaces 8 elements with their average value.
+ * Called by qdm2_decode_superblock before starting subblock decoding.
+ */
+void QDM2Stream::average_quantized_coeffs(void) {
+ int i, j, n, ch, sum;
+
+ n = coeff_per_sb_for_avg[_coeffPerSbSelect][QDM2_SB_USED(_subSampling) - 1] + 1;
+
+ for (ch = 0; ch < _channels; ch++) {
+ for (i = 0; i < n; i++) {
+ sum = 0;
+
+ for (j = 0; j < 8; j++)
+ sum += _quantizedCoeffs[ch][i][j];
+
+ sum /= 8;
+ if (sum > 0)
+ sum--;
+
+ for (j = 0; j < 8; j++)
+ _quantizedCoeffs[ch][i][j] = sum;
+ }
+ }
+}
+
+/**
+ * Build subband samples with noise weighted by q->tone_level.
+ * Called by synthfilt_build_sb_samples.
+ *
+ * @param sb subband index
+ */
+void QDM2Stream::build_sb_samples_from_noise(int sb) {
+ int ch, j;
+
+ FIX_NOISE_IDX(_noiseIdx);
+
+ if (!_channels)
+ return;
+
+ for (ch = 0; ch < _channels; ch++) {
+ for (j = 0; j < 64; j++) {
+ _sbSamples[ch][j * 2][sb] = (int32)(SB_DITHERING_NOISE(sb, _noiseIdx) * _toneLevel[ch][sb][j] + .5);
+ _sbSamples[ch][j * 2 + 1][sb] = (int32)(SB_DITHERING_NOISE(sb, _noiseIdx) * _toneLevel[ch][sb][j] + .5);
+ }
+ }
+}
+
+/**
+ * Called while processing data from subpackets 11 and 12.
+ * Used after making changes to coding_method array.
+ *
+ * @param sb subband index
+ * @param channels number of channels
+ * @param coding_method q->coding_method[0][0][0]
+ */
+void QDM2Stream::fix_coding_method_array(int sb, int channels, sb_int8_array coding_method)
+{
+ int j, k;
+ int ch;
+ int run, case_val;
+ int switchtable[23] = {0,5,1,5,5,5,5,5,2,5,5,5,5,5,5,5,3,5,5,5,5,5,4};
+
+ for (ch = 0; ch < channels; ch++) {
+ for (j = 0; j < 64; ) {
+ if((coding_method[ch][sb][j] - 8) > 22) {
+ run = 1;
+ case_val = 8;
+ } else {
+ switch (switchtable[coding_method[ch][sb][j]-8]) {
+ case 0: run = 10; case_val = 10; break;
+ case 1: run = 1; case_val = 16; break;
+ case 2: run = 5; case_val = 24; break;
+ case 3: run = 3; case_val = 30; break;
+ case 4: run = 1; case_val = 30; break;
+ case 5: run = 1; case_val = 8; break;
+ default: run = 1; case_val = 8; break;
+ }
+ }
+ for (k = 0; k < run; k++)
+ if (j + k < 128)
+ if (coding_method[ch][sb + (j + k) / 64][(j + k) % 64] > coding_method[ch][sb][j])
+ if (k > 0) {
+ warning("QDM2 Untested Code: not debugged, almost never used");
+ memset(&coding_method[ch][sb][j + k], case_val, k * sizeof(int8));
+ memset(&coding_method[ch][sb][j + k], case_val, 3 * sizeof(int8));
+ }
+ j += run;
+ }
+ }
+}
+
+/**
+ * Related to synthesis filter
+ * Called by process_subpacket_10
+ *
+ * @param flag 1 if called after getting data from subpacket 10, 0 if no subpacket 10
+ */
+void QDM2Stream::fill_tone_level_array(int flag) {
+ int i, sb, ch, sb_used;
+ int tmp, tab;
+
+ // This should never happen
+ if (_channels <= 0)
+ return;
+
+ for (ch = 0; ch < _channels; ch++) {
+ for (sb = 0; sb < 30; sb++) {
+ for (i = 0; i < 8; i++) {
+ if ((tab=coeff_per_sb_for_dequant[_coeffPerSbSelect][sb]) < (last_coeff[_coeffPerSbSelect] - 1))
+ tmp = _quantizedCoeffs[ch][tab + 1][i] * dequant_table[_coeffPerSbSelect][tab + 1][sb]+
+ _quantizedCoeffs[ch][tab][i] * dequant_table[_coeffPerSbSelect][tab][sb];
+ else
+ tmp = _quantizedCoeffs[ch][tab][i] * dequant_table[_coeffPerSbSelect][tab][sb];
+ if(tmp < 0)
+ tmp += 0xff;
+ _toneLevelIdxBase[ch][sb][i] = (tmp / 256) & 0xff;
+ }
+ }
+ }
+
+ sb_used = QDM2_SB_USED(_subSampling);
+
+ if ((_superblocktype_2_3 != 0) && !flag) {
+ for (sb = 0; sb < sb_used; sb++) {
+ for (ch = 0; ch < _channels; ch++) {
+ for (i = 0; i < 64; i++) {
+ _toneLevelIdx[ch][sb][i] = _toneLevelIdxBase[ch][sb][i / 8];
+ if (_toneLevelIdx[ch][sb][i] < 0)
+ _toneLevel[ch][sb][i] = 0;
+ else
+ _toneLevel[ch][sb][i] = fft_tone_level_table[0][_toneLevelIdx[ch][sb][i] & 0x3f];
+ }
+ }
+ }
+ } else {
+ tab = _superblocktype_2_3 ? 0 : 1;
+ for (sb = 0; sb < sb_used; sb++) {
+ if ((sb >= 4) && (sb <= 23)) {
+ for (ch = 0; ch < _channels; ch++) {
+ for (i = 0; i < 64; i++) {
+ tmp = _toneLevelIdxBase[ch][sb][i / 8] -
+ _toneLevelIdxHi1[ch][sb / 8][i / 8][i % 8] -
+ _toneLevelIdxMid[ch][sb - 4][i / 8] -
+ _toneLevelIdxHi2[ch][sb - 4];
+ _toneLevelIdx[ch][sb][i] = tmp & 0xff;
+ if ((tmp < 0) || (!_superblocktype_2_3 && !tmp))
+ _toneLevel[ch][sb][i] = 0;
+ else
+ _toneLevel[ch][sb][i] = fft_tone_level_table[tab][tmp & 0x3f];
+ }
+ }
+ } else {
+ if (sb > 4) {
+ for (ch = 0; ch < _channels; ch++) {
+ for (i = 0; i < 64; i++) {
+ tmp = _toneLevelIdxBase[ch][sb][i / 8] -
+ _toneLevelIdxHi1[ch][2][i / 8][i % 8] -
+ _toneLevelIdxHi2[ch][sb - 4];
+ _toneLevelIdx[ch][sb][i] = tmp & 0xff;
+ if ((tmp < 0) || (!_superblocktype_2_3 && !tmp))
+ _toneLevel[ch][sb][i] = 0;
+ else
+ _toneLevel[ch][sb][i] = fft_tone_level_table[tab][tmp & 0x3f];
+ }
+ }
+ } else {
+ for (ch = 0; ch < _channels; ch++) {
+ for (i = 0; i < 64; i++) {
+ tmp = _toneLevelIdx[ch][sb][i] = _toneLevelIdxBase[ch][sb][i / 8];
+ if ((tmp < 0) || (!_superblocktype_2_3 && !tmp))
+ _toneLevel[ch][sb][i] = 0;
+ else
+ _toneLevel[ch][sb][i] = fft_tone_level_table[tab][tmp & 0x3f];
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Related to synthesis filter
+ * Called by process_subpacket_11
+ * c is built with data from subpacket 11
+ * Most of this function is used only if superblock_type_2_3 == 0, never seen it in samples
+ *
+ * @param tone_level_idx
+ * @param tone_level_idx_temp
+ * @param coding_method q->coding_method[0][0][0]
+ * @param nb_channels number of channels
+ * @param c coming from subpacket 11, passed as 8*c
+ * @param superblocktype_2_3 flag based on superblock packet type
+ * @param cm_table_select q->cm_table_select
+ */
+void QDM2Stream::fill_coding_method_array(sb_int8_array tone_level_idx, sb_int8_array tone_level_idx_temp,
+ sb_int8_array coding_method, int nb_channels,
+ int c, int superblocktype_2_3, int cm_table_select) {
+ int ch, sb, j;
+ int tmp, acc, esp_40, comp;
+ int add1, add2, add3, add4;
+ // TODO : Remove multres 64 bit variable necessity...
+ int64_t multres;
+
+ // This should never happen
+ if (nb_channels <= 0)
+ return;
+ if (!superblocktype_2_3) {
+ warning("QDM2 This case is untested, no samples available");
+ for (ch = 0; ch < nb_channels; ch++)
+ for (sb = 0; sb < 30; sb++) {
+ for (j = 1; j < 63; j++) { // The loop only iterates to 63 so the code doesn't overflow the buffer
+ add1 = tone_level_idx[ch][sb][j] - 10;
+ if (add1 < 0)
+ add1 = 0;
+ add2 = add3 = add4 = 0;
+ if (sb > 1) {
+ add2 = tone_level_idx[ch][sb - 2][j] + tone_level_idx_offset_table[sb][0] - 6;
+ if (add2 < 0)
+ add2 = 0;
+ }
+ if (sb > 0) {
+ add3 = tone_level_idx[ch][sb - 1][j] + tone_level_idx_offset_table[sb][1] - 6;
+ if (add3 < 0)
+ add3 = 0;
+ }
+ if (sb < 29) {
+ add4 = tone_level_idx[ch][sb + 1][j] + tone_level_idx_offset_table[sb][3] - 6;
+ if (add4 < 0)
+ add4 = 0;
+ }
+ tmp = tone_level_idx[ch][sb][j + 1] * 2 - add4 - add3 - add2 - add1;
+ if (tmp < 0)
+ tmp = 0;
+ tone_level_idx_temp[ch][sb][j + 1] = tmp & 0xff;
+ }
+ tone_level_idx_temp[ch][sb][0] = tone_level_idx_temp[ch][sb][1];
+ }
+ acc = 0;
+ for (ch = 0; ch < nb_channels; ch++)
+ for (sb = 0; sb < 30; sb++)
+ for (j = 0; j < 64; j++)
+ acc += tone_level_idx_temp[ch][sb][j];
+
+ multres = 0x66666667 * (acc * 10);
+ esp_40 = (multres >> 32) / 8 + ((multres & 0xffffffff) >> 31);
+ for (ch = 0; ch < nb_channels; ch++)
+ for (sb = 0; sb < 30; sb++)
+ for (j = 0; j < 64; j++) {
+ comp = tone_level_idx_temp[ch][sb][j]* esp_40 * 10;
+ if (comp < 0)
+ comp += 0xff;
+ comp /= 256; // signed shift
+ switch(sb) {
+ case 0:
+ if (comp < 30)
+ comp = 30;
+ comp += 15;
+ break;
+ case 1:
+ if (comp < 24)
+ comp = 24;
+ comp += 10;
+ break;
+ case 2:
+ case 3:
+ case 4:
+ if (comp < 16)
+ comp = 16;
+ }
+ if (comp <= 5)
+ tmp = 0;
+ else if (comp <= 10)
+ tmp = 10;
+ else if (comp <= 16)
+ tmp = 16;
+ else if (comp <= 24)
+ tmp = -1;
+ else
+ tmp = 0;
+ coding_method[ch][sb][j] = ((tmp & 0xfffa) + 30 )& 0xff;
+ }
+ for (sb = 0; sb < 30; sb++)
+ fix_coding_method_array(sb, nb_channels, coding_method);
+ for (ch = 0; ch < nb_channels; ch++)
+ for (sb = 0; sb < 30; sb++)
+ for (j = 0; j < 64; j++)
+ if (sb >= 10) {
+ if (coding_method[ch][sb][j] < 10)
+ coding_method[ch][sb][j] = 10;
+ } else {
+ if (sb >= 2) {
+ if (coding_method[ch][sb][j] < 16)
+ coding_method[ch][sb][j] = 16;
+ } else {
+ if (coding_method[ch][sb][j] < 30)
+ coding_method[ch][sb][j] = 30;
+ }
+ }
+ } else { // superblocktype_2_3 != 0
+ for (ch = 0; ch < nb_channels; ch++)
+ for (sb = 0; sb < 30; sb++)
+ for (j = 0; j < 64; j++)
+ coding_method[ch][sb][j] = coding_method_table[cm_table_select][sb];
+ }
+}
+
+/**
+ *
+ * Called by process_subpacket_11 to process more data from subpacket 11 with sb 0-8
+ * Called by process_subpacket_12 to process data from subpacket 12 with sb 8-sb_used
+ *
+ * @param gb bitreader context
+ * @param length packet length in bits
+ * @param sb_min lower subband processed (sb_min included)
+ * @param sb_max higher subband processed (sb_max excluded)
+ */
+void QDM2Stream::synthfilt_build_sb_samples(GetBitContext *gb, int length, int sb_min, int sb_max) {
+ int sb, j, k, n, ch, run, channels;
+ int joined_stereo, zero_encoding, chs;
+ int type34_first;
+ float type34_div = 0;
+ float type34_predictor;
+ float samples[10], sign_bits[16];
+
+ if (length == 0) {
+ // If no data use noise
+ for (sb = sb_min; sb < sb_max; sb++)
+ build_sb_samples_from_noise(sb);
+
+ return;
+ }
+
+ for (sb = sb_min; sb < sb_max; sb++) {
+ FIX_NOISE_IDX(_noiseIdx);
+
+ channels = _channels;
+
+ if (_channels <= 1 || sb < 12)
+ joined_stereo = 0;
+ else if (sb >= 24)
+ joined_stereo = 1;
+ else
+ joined_stereo = (BITS_LEFT(length,gb) >= 1) ? getBits1 (gb) : 0;
+
+ if (joined_stereo) {
+ if (BITS_LEFT(length,gb) >= 16)
+ for (j = 0; j < 16; j++)
+ sign_bits[j] = getBits1(gb);
+
+ for (j = 0; j < 64; j++)
+ if (_codingMethod[1][sb][j] > _codingMethod[0][sb][j])
+ _codingMethod[0][sb][j] = _codingMethod[1][sb][j];
+
+ fix_coding_method_array(sb, _channels, _codingMethod);
+ channels = 1;
+ }
+
+ for (ch = 0; ch < channels; ch++) {
+ zero_encoding = (BITS_LEFT(length,gb) >= 1) ? getBits1(gb) : 0;
+ type34_predictor = 0.0;
+ type34_first = 1;
+
+ for (j = 0; j < 128; ) {
+ switch (_codingMethod[ch][sb][j / 2]) {
+ case 8:
+ if (BITS_LEFT(length,gb) >= 10) {
+ if (zero_encoding) {
+ for (k = 0; k < 5; k++) {
+ if ((j + 2 * k) >= 128)
+ break;
+ samples[2 * k] = getBits1(gb) ? dequant_1bit[joined_stereo][2 * getBits1(gb)] : 0;
+ }
+ } else {
+ n = getBits(gb, 8);
+ for (k = 0; k < 5; k++)
+ samples[2 * k] = dequant_1bit[joined_stereo][_randomDequantIndex[n][k]];
+ }
+ for (k = 0; k < 5; k++)
+ samples[2 * k + 1] = SB_DITHERING_NOISE(sb, _noiseIdx);
+ } else {
+ for (k = 0; k < 10; k++)
+ samples[k] = SB_DITHERING_NOISE(sb, _noiseIdx);
+ }
+ run = 10;
+ break;
+
+ case 10:
+ if (BITS_LEFT(length,gb) >= 1) {
+ double f = 0.81;
+
+ if (getBits1(gb))
+ f = -f;
+ f -= _noiseSamples[((sb + 1) * (j +5 * ch + 1)) & 127] * 9.0 / 40.0;
+ samples[0] = f;
+ } else {
+ samples[0] = SB_DITHERING_NOISE(sb, _noiseIdx);
+ }
+ run = 1;
+ break;
+
+ case 16:
+ if (BITS_LEFT(length,gb) >= 10) {
+ if (zero_encoding) {
+ for (k = 0; k < 5; k++) {
+ if ((j + k) >= 128)
+ break;
+ samples[k] = (getBits1(gb) == 0) ? 0 : dequant_1bit[joined_stereo][2 * getBits1(gb)];
+ }
+ } else {
+ n = getBits (gb, 8);
+ for (k = 0; k < 5; k++)
+ samples[k] = dequant_1bit[joined_stereo][_randomDequantIndex[n][k]];
+ }
+ } else {
+ for (k = 0; k < 5; k++)
+ samples[k] = SB_DITHERING_NOISE(sb, _noiseIdx);
+ }
+ run = 5;
+ break;
+
+ case 24:
+ if (BITS_LEFT(length,gb) >= 7) {
+ n = getBits(gb, 7);
+ for (k = 0; k < 3; k++)
+ samples[k] = (_randomDequantType24[n][k] - 2.0) * 0.5;
+ } else {
+ for (k = 0; k < 3; k++)
+ samples[k] = SB_DITHERING_NOISE(sb, _noiseIdx);
+ }
+ run = 3;
+ break;
+
+ case 30:
+ if (BITS_LEFT(length,gb) >= 4)
+ samples[0] = type30_dequant[qdm2_get_vlc(gb, &_vlcTabType30, 0, 1)];
+ else
+ samples[0] = SB_DITHERING_NOISE(sb, _noiseIdx);
+
+ run = 1;
+ break;
+
+ case 34:
+ if (BITS_LEFT(length,gb) >= 7) {
+ if (type34_first) {
+ type34_div = (float)(1 << getBits(gb, 2));
+ samples[0] = ((float)getBits(gb, 5) - 16.0) / 15.0;
+ type34_predictor = samples[0];
+ type34_first = 0;
+ } else {
+ samples[0] = type34_delta[qdm2_get_vlc(gb, &_vlcTabType34, 0, 1)] / type34_div + type34_predictor;
+ type34_predictor = samples[0];
+ }
+ } else {
+ samples[0] = SB_DITHERING_NOISE(sb, _noiseIdx);
+ }
+ run = 1;
+ break;
+
+ default:
+ samples[0] = SB_DITHERING_NOISE(sb, _noiseIdx);
+ run = 1;
+ break;
+ }
+
+ if (joined_stereo) {
+ float tmp[10][MPA_MAX_CHANNELS];
+
+ for (k = 0; k < run; k++) {
+ tmp[k][0] = samples[k];
+ tmp[k][1] = (sign_bits[(j + k) / 8]) ? -samples[k] : samples[k];
+ }
+ for (chs = 0; chs < _channels; chs++)
+ for (k = 0; k < run; k++)
+ if ((j + k) < 128)
+ _sbSamples[chs][j + k][sb] = (int32)(_toneLevel[chs][sb][((j + k)/2)] * tmp[k][chs] + .5);
+ } else {
+ for (k = 0; k < run; k++)
+ if ((j + k) < 128)
+ _sbSamples[ch][j + k][sb] = (int32)(_toneLevel[ch][sb][(j + k)/2] * samples[k] + .5);
+ }
+
+ j += run;
+ } // j loop
+ } // channel loop
+ } // subband loop
+}
+
+/**
+ * Init the first element of a channel in quantized_coeffs with data from packet 10 (quantized_coeffs[ch][0]).
+ * This is similar to process_subpacket_9, but for a single channel and for element [0]
+ * same VLC tables as process_subpacket_9 are used.
+ *
+ * @param quantized_coeffs pointer to quantized_coeffs[ch][0]
+ * @param gb bitreader context
+ * @param length packet length in bits
+ */
+void QDM2Stream::init_quantized_coeffs_elem0(int8 *quantized_coeffs, GetBitContext *gb, int length) {
+ int i, k, run, level, diff;
+
+ if (BITS_LEFT(length,gb) < 16)
+ return;
+ level = qdm2_get_vlc(gb, &_vlcTabLevel, 0, 2);
+
+ quantized_coeffs[0] = level;
+
+ for (i = 0; i < 7; ) {
+ if (BITS_LEFT(length,gb) < 16)
+ break;
+ run = qdm2_get_vlc(gb, &_vlcTabRun, 0, 1) + 1;
+
+ if (BITS_LEFT(length,gb) < 16)
+ break;
+ diff = qdm2_get_se_vlc(&_vlcTabDiff, gb, 2);
+
+ for (k = 1; k <= run; k++)
+ quantized_coeffs[i + k] = (level + ((k * diff) / run));
+
+ level += diff;
+ i += run;
+ }
+}
+
+/**
+ * Related to synthesis filter, process data from packet 10
+ * Init part of quantized_coeffs via function init_quantized_coeffs_elem0
+ * Init tone_level_idx_hi1, tone_level_idx_hi2, tone_level_idx_mid with data from packet 10
+ *
+ * @param gb bitreader context
+ * @param length packet length in bits
+ */
+void QDM2Stream::init_tone_level_dequantization(GetBitContext *gb, int length) {
+ int sb, j, k, n, ch;
+
+ for (ch = 0; ch < _channels; ch++) {
+ init_quantized_coeffs_elem0(_quantizedCoeffs[ch][0], gb, length);
+
+ if (BITS_LEFT(length,gb) < 16) {
+ memset(_quantizedCoeffs[ch][0], 0, 8);
+ break;
+ }
+ }
+
+ n = _subSampling + 1;
+
+ for (sb = 0; sb < n; sb++)
+ for (ch = 0; ch < _channels; ch++)
+ for (j = 0; j < 8; j++) {
+ if (BITS_LEFT(length,gb) < 1)
+ break;
+ if (getBits1(gb)) {
+ for (k=0; k < 8; k++) {
+ if (BITS_LEFT(length,gb) < 16)
+ break;
+ _toneLevelIdxHi1[ch][sb][j][k] = qdm2_get_vlc(gb, &_vlcTabToneLevelIdxHi1, 0, 2);
+ }
+ } else {
+ for (k=0; k < 8; k++)
+ _toneLevelIdxHi1[ch][sb][j][k] = 0;
+ }
+ }
+
+ n = QDM2_SB_USED(_subSampling) - 4;
+
+ for (sb = 0; sb < n; sb++)
+ for (ch = 0; ch < _channels; ch++) {
+ if (BITS_LEFT(length,gb) < 16)
+ break;
+ _toneLevelIdxHi2[ch][sb] = qdm2_get_vlc(gb, &_vlcTabToneLevelIdxHi2, 0, 2);
+ if (sb > 19)
+ _toneLevelIdxHi2[ch][sb] -= 16;
+ else
+ for (j = 0; j < 8; j++)
+ _toneLevelIdxMid[ch][sb][j] = -16;
+ }
+
+ n = QDM2_SB_USED(_subSampling) - 5;
+
+ for (sb = 0; sb < n; sb++) {
+ for (ch = 0; ch < _channels; ch++) {
+ for (j = 0; j < 8; j++) {
+ if (BITS_LEFT(length,gb) < 16)
+ break;
+ _toneLevelIdxMid[ch][sb][j] = qdm2_get_vlc(gb, &_vlcTabToneLevelIdxMid, 0, 2) - 32;
+ }
+ }
+ }
+}
+
+/**
+ * Process subpacket 9, init quantized_coeffs with data from it
+ *
+ * @param node pointer to node with packet
+ */
+void QDM2Stream::process_subpacket_9(QDM2SubPNode *node) {
+ GetBitContext gb;
+ int i, j, k, n, ch, run, level, diff;
+
+ initGetBits(&gb, node->packet->data, node->packet->size*8);
+
+ n = coeff_per_sb_for_avg[_coeffPerSbSelect][QDM2_SB_USED(_subSampling) - 1] + 1; // same as averagesomething function
+
+ for (i = 1; i < n; i++)
+ for (ch = 0; ch < _channels; ch++) {
+ level = qdm2_get_vlc(&gb, &_vlcTabLevel, 0, 2);
+ _quantizedCoeffs[ch][i][0] = level;
+
+ for (j = 0; j < (8 - 1); ) {
+ run = qdm2_get_vlc(&gb, &_vlcTabRun, 0, 1) + 1;
+ diff = qdm2_get_se_vlc(&_vlcTabDiff, &gb, 2);
+
+ for (k = 1; k <= run; k++)
+ _quantizedCoeffs[ch][i][j + k] = (level + ((k*diff) / run));
+
+ level += diff;
+ j += run;
+ }
+ }
+
+ for (ch = 0; ch < _channels; ch++)
+ for (i = 0; i < 8; i++)
+ _quantizedCoeffs[ch][0][i] = 0;
+}
+
+/**
+ * Process subpacket 10 if not null, else
+ *
+ * @param node pointer to node with packet
+ * @param length packet length in bits
+ */
+void QDM2Stream::process_subpacket_10(QDM2SubPNode *node, int length) {
+ GetBitContext gb;
+
+ initGetBits(&gb, ((node == NULL) ? _emptyBuffer : node->packet->data), ((node == NULL) ? 0 : node->packet->size*8));
+
+ if (length != 0) {
+ init_tone_level_dequantization(&gb, length);
+ fill_tone_level_array(1);
+ } else {
+ fill_tone_level_array(0);
+ }
+}
+
+/**
+ * Process subpacket 11
+ *
+ * @param node pointer to node with packet
+ * @param length packet length in bit
+ */
+void QDM2Stream::process_subpacket_11(QDM2SubPNode *node, int length) {
+ GetBitContext gb;
+
+ initGetBits(&gb, ((node == NULL) ? _emptyBuffer : node->packet->data), ((node == NULL) ? 0 : node->packet->size*8));
+ if (length >= 32) {
+ int c = getBits (&gb, 13);
+
+ if (c > 3)
+ fill_coding_method_array(_toneLevelIdx, _toneLevelIdxTemp, _codingMethod,
+ _channels, 8*c, _superblocktype_2_3, _cmTableSelect);
+ }
+
+ synthfilt_build_sb_samples(&gb, length, 0, 8);
+}
+
+/**
+ * Process subpacket 12
+ *
+ * @param node pointer to node with packet
+ * @param length packet length in bits
+ */
+void QDM2Stream::process_subpacket_12(QDM2SubPNode *node, int length) {
+ GetBitContext gb;
+
+ initGetBits(&gb, ((node == NULL) ? _emptyBuffer : node->packet->data), ((node == NULL) ? 0 : node->packet->size*8));
+ synthfilt_build_sb_samples(&gb, length, 8, QDM2_SB_USED(_subSampling));
+}
+
+/*
+ * Process new subpackets for synthesis filter
+ *
+ * @param list list with synthesis filter packets (list D)
+ */
+void QDM2Stream::process_synthesis_subpackets(QDM2SubPNode *list) {
+ struct QDM2SubPNode *nodes[4];
+
+ nodes[0] = qdm2_search_subpacket_type_in_list(list, 9);
+ if (nodes[0] != NULL)
+ process_subpacket_9(nodes[0]);
+
+ nodes[1] = qdm2_search_subpacket_type_in_list(list, 10);
+ if (nodes[1] != NULL)
+ process_subpacket_10(nodes[1], nodes[1]->packet->size << 3);
+ else
+ process_subpacket_10(NULL, 0);
+
+ nodes[2] = qdm2_search_subpacket_type_in_list(list, 11);
+ if (nodes[0] != NULL && nodes[1] != NULL && nodes[2] != NULL)
+ process_subpacket_11(nodes[2], (nodes[2]->packet->size << 3));
+ else
+ process_subpacket_11(NULL, 0);
+
+ nodes[3] = qdm2_search_subpacket_type_in_list(list, 12);
+ if (nodes[0] != NULL && nodes[1] != NULL && nodes[3] != NULL)
+ process_subpacket_12(nodes[3], (nodes[3]->packet->size << 3));
+ else
+ process_subpacket_12(NULL, 0);
+}
+
+/*
+ * Decode superblock, fill packet lists.
+ *
+ */
+void QDM2Stream::qdm2_decode_super_block(void) {
+ GetBitContext gb;
+ struct QDM2SubPacket header, *packet;
+ int i, packet_bytes, sub_packet_size, subPacketsD;
+ unsigned int next_index = 0;
+
+ memset(_toneLevelIdxHi1, 0, sizeof(_toneLevelIdxHi1));
+ memset(_toneLevelIdxMid, 0, sizeof(_toneLevelIdxMid));
+ memset(_toneLevelIdxHi2, 0, sizeof(_toneLevelIdxHi2));
+
+ _subPacketsB = 0;
+ subPacketsD = 0;
+
+ average_quantized_coeffs(); // average elements in quantized_coeffs[max_ch][10][8]
+
+ initGetBits(&gb, _compressedData, _packetSize*8);
+ qdm2_decode_sub_packet_header(&gb, &header);
+
+ if (header.type < 2 || header.type >= 8) {
+ _hasErrors = true;
+ error("QDM2 : bad superblock type");
+ return;
+ }
+
+ _superblocktype_2_3 = (header.type == 2 || header.type == 3);
+ packet_bytes = (_packetSize - getBitsCount(&gb) / 8);
+
+ initGetBits(&gb, header.data, header.size*8);
+
+ if (header.type == 2 || header.type == 4 || header.type == 5) {
+ int csum = 257 * getBits(&gb, 8) + 2 * getBits(&gb, 8);
+
+ csum = qdm2_packet_checksum(_compressedData, _packetSize, csum);
+
+ if (csum != 0) {
+ _hasErrors = true;
+ error("QDM2 : bad packet checksum");
+ return;
+ }
+ }
+
+ _subPacketListB[0].packet = NULL;
+ _subPacketListD[0].packet = NULL;
+
+ for (i = 0; i < 6; i++)
+ if (--_fftLevelExp[i] < 0)
+ _fftLevelExp[i] = 0;
+
+ for (i = 0; packet_bytes > 0; i++) {
+ int j;
+
+ _subPacketListA[i].next = NULL;
+
+ if (i > 0) {
+ _subPacketListA[i - 1].next = &_subPacketListA[i];
+
+ // seek to next block
+ initGetBits(&gb, header.data, header.size*8);
+ skipBits(&gb, next_index*8);
+
+ if (next_index >= header.size)
+ break;
+ }
+
+ // decode subpacket
+ packet = &_subPackets[i];
+ qdm2_decode_sub_packet_header(&gb, packet);
+ next_index = packet->size + getBitsCount(&gb) / 8;
+ sub_packet_size = ((packet->size > 0xff) ? 1 : 0) + packet->size + 2;
+
+ if (packet->type == 0)
+ break;
+
+ if (sub_packet_size > packet_bytes) {
+ if (packet->type != 10 && packet->type != 11 && packet->type != 12)
+ break;
+ packet->size += packet_bytes - sub_packet_size;
+ }
+
+ packet_bytes -= sub_packet_size;
+
+ // add subpacket to 'all subpackets' list
+ _subPacketListA[i].packet = packet;
+
+ // add subpacket to related list
+ if (packet->type == 8) {
+ error("Unsupported packet type 8");
+ return;
+ } else if (packet->type >= 9 && packet->type <= 12) {
+ // packets for MPEG Audio like Synthesis Filter
+ QDM2_LIST_ADD(_subPacketListD, subPacketsD, packet);
+ } else if (packet->type == 13) {
+ for (j = 0; j < 6; j++)
+ _fftLevelExp[j] = getBits(&gb, 6);
+ } else if (packet->type == 14) {
+ for (j = 0; j < 6; j++)
+ _fftLevelExp[j] = qdm2_get_vlc(&gb, &_fftLevelExpVlc, 0, 2);
+ } else if (packet->type == 15) {
+ error("Unsupported packet type 15");
+ return;
+ } else if (packet->type >= 16 && packet->type < 48 && !fft_subpackets[packet->type - 16]) {
+ // packets for FFT
+ QDM2_LIST_ADD(_subPacketListB, _subPacketsB, packet);
+ }
+ } // Packet bytes loop
+
+// ****************************************************************
+ if (_subPacketListD[0].packet != NULL) {
+ process_synthesis_subpackets(_subPacketListD);
+ _doSynthFilter = 1;
+ } else if (_doSynthFilter) {
+ process_subpacket_10(NULL, 0);
+ process_subpacket_11(NULL, 0);
+ process_subpacket_12(NULL, 0);
+ }
+// ****************************************************************
+}
+
+void QDM2Stream::qdm2_fft_init_coefficient(int sub_packet, int offset, int duration,
+ int channel, int exp, int phase) {
+ if (_fftCoefsMinIndex[duration] < 0)
+ _fftCoefsMinIndex[duration] = _fftCoefsIndex;
+
+ _fftCoefs[_fftCoefsIndex].sub_packet = ((sub_packet >= 16) ? (sub_packet - 16) : sub_packet);
+ _fftCoefs[_fftCoefsIndex].channel = channel;
+ _fftCoefs[_fftCoefsIndex].offset = offset;
+ _fftCoefs[_fftCoefsIndex].exp = exp;
+ _fftCoefs[_fftCoefsIndex].phase = phase;
+ _fftCoefsIndex++;
+}
+
+void QDM2Stream::qdm2_fft_decode_tones(int duration, GetBitContext *gb, int b) {
+ debug(1, "QDM2Stream::qdm2_fft_decode_tones() duration: %d b:%d", duration, b);
+ int channel, stereo, phase, exp;
+ int local_int_4, local_int_8, stereo_phase, local_int_10;
+ int local_int_14, stereo_exp, local_int_20, local_int_28;
+ int n, offset;
+
+ local_int_4 = 0;
+ local_int_28 = 0;
+ local_int_20 = 2;
+ local_int_8 = (4 - duration);
+ local_int_10 = 1 << (_groupOrder - duration - 1);
+ offset = 1;
+
+ while (1) {
+ if (_superblocktype_2_3) {
+ debug(1, "QDM2Stream::qdm2_fft_decode_tones() local_int_8: %d", local_int_8);
+ while ((n = qdm2_get_vlc(gb, &_vlcTabFftToneOffset[local_int_8], 1, 2)) < 2) {
+ debug(1, "QDM2Stream::qdm2_fft_decode_tones() local_int_8: %d", local_int_8);
+ offset = 1;
+ if (n == 0) {
+ local_int_4 += local_int_10;
+ local_int_28 += (1 << local_int_8);
+ } else {
+ local_int_4 += 8*local_int_10;
+ local_int_28 += (8 << local_int_8);
+ }
+ }
+ offset += (n - 2);
+ } else {
+ offset += qdm2_get_vlc(gb, &_vlcTabFftToneOffset[local_int_8], 1, 2);
+ while (offset >= (local_int_10 - 1)) {
+ offset += (1 - (local_int_10 - 1));
+ local_int_4 += local_int_10;
+ local_int_28 += (1 << local_int_8);
+ }
+ }
+
+ if (local_int_4 >= _blockSize)
+ return;
+
+ local_int_14 = (offset >> local_int_8);
+
+ if (_channels > 1) {
+ channel = getBits1(gb);
+ stereo = getBits1(gb);
+ } else {
+ channel = 0;
+ stereo = 0;
+ }
+
+ exp = qdm2_get_vlc(gb, (b ? &_fftLevelExpVlc : &_fftLevelExpAltVlc), 0, 2);
+ exp += _fftLevelExp[fft_level_index_table[local_int_14]];
+ exp = (exp < 0) ? 0 : exp;
+
+ phase = getBits(gb, 3);
+ stereo_exp = 0;
+ stereo_phase = 0;
+
+ if (stereo) {
+ stereo_exp = (exp - qdm2_get_vlc(gb, &_fftStereoExpVlc, 0, 1));
+ stereo_phase = (phase - qdm2_get_vlc(gb, &_fftStereoPhaseVlc, 0, 1));
+ if (stereo_phase < 0)
+ stereo_phase += 8;
+ }
+
+ if (_frequencyRange > (local_int_14 + 1)) {
+ int sub_packet = (local_int_20 + local_int_28);
+
+ qdm2_fft_init_coefficient(sub_packet, offset, duration, channel, exp, phase);
+ if (stereo)
+ qdm2_fft_init_coefficient(sub_packet, offset, duration, (1 - channel), stereo_exp, stereo_phase);
+ }
+
+ offset++;
+ }
+}
+
+void QDM2Stream::qdm2_decode_fft_packets(void) {
+ debug(1, "QDM2Stream::qdm2_decode_fft_packets()");
+ int i, j, min, max, value, type, unknown_flag;
+ GetBitContext gb;
+
+ if (_subPacketListB[0].packet == NULL)
+ return;
+
+ // reset minimum indexes for FFT coefficients
+ _fftCoefsIndex = 0;
+ for (i=0; i < 5; i++)
+ _fftCoefsMinIndex[i] = -1;
+
+ // process subpackets ordered by type, largest type first
+ for (i = 0, max = 256; i < _subPacketsB; i++) {
+ QDM2SubPacket *packet= NULL;
+
+ // find subpacket with largest type less than max
+ for (j = 0, min = 0; j < _subPacketsB; j++) {
+ value = _subPacketListB[j].packet->type;
+ if (value > min && value < max) {
+ min = value;
+ packet = _subPacketListB[j].packet;
+ }
+ }
+
+ max = min;
+
+ // check for errors (?)
+ if (!packet)
+ return;
+
+ if (i == 0 && (packet->type < 16 || packet->type >= 48 || fft_subpackets[packet->type - 16]))
+ return;
+
+ // decode FFT tones
+ debug(1, "QDM2Stream::qdm2_decode_fft_packets initGetBits() packet->size*8: %d", packet->size*8);
+ initGetBits(&gb, packet->data, packet->size*8);
+
+ if (packet->type >= 32 && packet->type < 48 && !fft_subpackets[packet->type - 16])
+ unknown_flag = 1;
+ else
+ unknown_flag = 0;
+
+ type = packet->type;
+
+ if ((type >= 17 && type < 24) || (type >= 33 && type < 40)) {
+ int duration = _subSampling + 5 - (type & 15);
+
+ if (duration >= 0 && duration < 4) { // TODO: Should be <= 4?
+ debug(1, "QDM2Stream::qdm2_decode_fft_packets qdm2_fft_decode_tones() #1");
+ qdm2_fft_decode_tones(duration, &gb, unknown_flag);
+ }
+ } else if (type == 31) {
+ for (j=0; j < 4; j++) {
+ debug(1, "QDM2Stream::qdm2_decode_fft_packets qdm2_fft_decode_tones() #2");
+ qdm2_fft_decode_tones(j, &gb, unknown_flag);
+ }
+ } else if (type == 46) {
+ for (j=0; j < 6; j++)
+ _fftLevelExp[j] = getBits(&gb, 6);
+ for (j=0; j < 4; j++) {
+ debug(1, "QDM2Stream::qdm2_decode_fft_packets qdm2_fft_decode_tones() #3");
+ qdm2_fft_decode_tones(j, &gb, unknown_flag);
+ }
+ }
+ } // Loop on B packets
+
+ // calculate maximum indexes for FFT coefficients
+ for (i = 0, j = -1; i < 5; i++)
+ if (_fftCoefsMinIndex[i] >= 0) {
+ if (j >= 0)
+ _fftCoefsMaxIndex[j] = _fftCoefsMinIndex[i];
+ j = i;
+ }
+ if (j >= 0)
+ _fftCoefsMaxIndex[j] = _fftCoefsIndex;
+}
+
+void QDM2Stream::qdm2_fft_generate_tone(FFTTone *tone)
+{
+ float level, f[6];
+ int i;
+ QDM2Complex c;
+ const double iscale = 2.0 * PI / 512.0;
+
+ tone->phase += tone->phase_shift;
+
+ // calculate current level (maximum amplitude) of tone
+ level = fft_tone_envelope_table[tone->duration][tone->time_index] * tone->level;
+ c.im = level * sin(tone->phase*iscale);
+ c.re = level * cos(tone->phase*iscale);
+
+ // generate FFT coefficients for tone
+ if (tone->duration >= 3 || tone->cutoff >= 3) {
+ tone->complex[0].im += c.im;
+ tone->complex[0].re += c.re;
+ tone->complex[1].im -= c.im;
+ tone->complex[1].re -= c.re;
+ } else {
+ f[1] = -tone->table[4];
+ f[0] = tone->table[3] - tone->table[0];
+ f[2] = 1.0 - tone->table[2] - tone->table[3];
+ f[3] = tone->table[1] + tone->table[4] - 1.0;
+ f[4] = tone->table[0] - tone->table[1];
+ f[5] = tone->table[2];
+ for (i = 0; i < 2; i++) {
+ tone->complex[fft_cutoff_index_table[tone->cutoff][i]].re += c.re * f[i];
+ tone->complex[fft_cutoff_index_table[tone->cutoff][i]].im += c.im *((tone->cutoff <= i) ? -f[i] : f[i]);
+ }
+ for (i = 0; i < 4; i++) {
+ tone->complex[i].re += c.re * f[i+2];
+ tone->complex[i].im += c.im * f[i+2];
+ }
+ }
+
+ // copy the tone if it has not yet died out
+ if (++tone->time_index < ((1 << (5 - tone->duration)) - 1)) {
+ memcpy(&_fftTones[_fftToneEnd], tone, sizeof(FFTTone));
+ _fftToneEnd = (_fftToneEnd + 1) % 1000;
+ }
+}
+
+void QDM2Stream::qdm2_fft_tone_synthesizer(uint8 sub_packet) {
+ int i, j, ch;
+ const double iscale = 0.25 * PI;
+
+ for (ch = 0; ch < _channels; ch++) {
+ memset(_fft.complex[ch], 0, _frameSize * sizeof(QDM2Complex));
+ }
+
+ // apply FFT tones with duration 4 (1 FFT period)
+ if (_fftCoefsMinIndex[4] >= 0)
+ for (i = _fftCoefsMinIndex[4]; i < _fftCoefsMaxIndex[4]; i++) {
+ float level;
+ QDM2Complex c;
+
+ if (_fftCoefs[i].sub_packet != sub_packet)
+ break;
+
+ ch = (_channels == 1) ? 0 : _fftCoefs[i].channel;
+ level = (_fftCoefs[i].exp < 0) ? 0.0 : fft_tone_level_table[_superblocktype_2_3 ? 0 : 1][_fftCoefs[i].exp & 63];
+
+ c.re = level * cos(_fftCoefs[i].phase * iscale);
+ c.im = level * sin(_fftCoefs[i].phase * iscale);
+ _fft.complex[ch][_fftCoefs[i].offset + 0].re += c.re;
+ _fft.complex[ch][_fftCoefs[i].offset + 0].im += c.im;
+ _fft.complex[ch][_fftCoefs[i].offset + 1].re -= c.re;
+ _fft.complex[ch][_fftCoefs[i].offset + 1].im -= c.im;
+ }
+
+ // generate existing FFT tones
+ for (i = _fftToneEnd; i != _fftToneStart; ) {
+ qdm2_fft_generate_tone(&_fftTones[_fftToneStart]);
+ _fftToneStart = (_fftToneStart + 1) % 1000;
+ }
+
+ // create and generate new FFT tones with duration 0 (long) to 3 (short)
+ for (i = 0; i < 4; i++)
+ if (_fftCoefsMinIndex[i] >= 0) {
+ for (j = _fftCoefsMinIndex[i]; j < _fftCoefsMaxIndex[i]; j++) {
+ int offset, four_i;
+ FFTTone tone;
+
+ if (_fftCoefs[j].sub_packet != sub_packet)
+ break;
+
+ four_i = (4 - i);
+ offset = _fftCoefs[j].offset >> four_i;
+ ch = (_channels == 1) ? 0 : _fftCoefs[j].channel;
+
+ if (offset < _frequencyRange) {
+ if (offset < 2)
+ tone.cutoff = offset;
+ else
+ tone.cutoff = (offset >= 60) ? 3 : 2;
+
+ tone.level = (_fftCoefs[j].exp < 0) ? 0.0 : fft_tone_level_table[_superblocktype_2_3 ? 0 : 1][_fftCoefs[j].exp & 63];
+ tone.complex = &_fft.complex[ch][offset];
+ tone.table = fft_tone_sample_table[i][_fftCoefs[j].offset - (offset << four_i)];
+ tone.phase = 64 * _fftCoefs[j].phase - (offset << 8) - 128;
+ tone.phase_shift = (2 * _fftCoefs[j].offset + 1) << (7 - four_i);
+ tone.duration = i;
+ tone.time_index = 0;
+
+ qdm2_fft_generate_tone(&tone);
+ }
+ }
+ _fftCoefsMinIndex[i] = j;
+ }
+}
+
+void QDM2Stream::qdm2_calculate_fft(int channel) {
+ debug(1, "QDM2Stream::qdm2_calculate_fft channel: %d", channel);
+ const float gain = (_channels == 1 && _channels == 2) ? 0.5f : 1.0f;
+ int i;
+
+ _fft.complex[channel][0].re *= 2.0f;
+ _fft.complex[channel][0].im = 0.0f;
+
+ //debug(1, "QDM2Stream::qdm2_calculate_fft _fft.complex[channel][0].re: %lf", _fft.complex[channel][0].re);
+ //debug(1, "QDM2Stream::qdm2_calculate_fft _fft.complex[channel][0].im: %lf", _fft.complex[channel][0].im);
+
+ rdftCalc(&_rdftCtx, (float *)_fft.complex[channel]);
+
+ // add samples to output buffer
+ for (i = 0; i < ((_fftFrameSize + 15) & ~15); i++)
+ _outputBuffer[_channels * i + channel] += ((float *) _fft.complex[channel])[i] * gain;
+}
+
+/**
+ * @param index subpacket number
+ */
+void QDM2Stream::qdm2_synthesis_filter(uint8 index)
+{
+ int16 samples[MPA_MAX_CHANNELS * MPA_FRAME_SIZE];
+ int i, k, ch, sb_used, sub_sampling, dither_state = 0;
+
+ // copy sb_samples
+ sb_used = QDM2_SB_USED(_subSampling);
+
+ for (ch = 0; ch < _channels; ch++)
+ for (i = 0; i < 8; i++)
+ for (k = sb_used; k < 32; k++)
+ _sbSamples[ch][(8 * index) + i][k] = 0;
+
+ for (ch = 0; ch < _channels; ch++) {
+ int16 *samples_ptr = samples + ch;
+
+ for (i = 0; i < 8; i++) {
+ ff_mpa_synth_filter(_synthBuf[ch], &(_synthBufOffset[ch]),
+ ff_mpa_synth_window, &dither_state,
+ samples_ptr, _channels,
+ _sbSamples[ch][(8 * index) + i]);
+ samples_ptr += 32 * _channels;
+ }
+ }
+
+ // add samples to output buffer
+ sub_sampling = (4 >> _subSampling);
+
+ for (ch = 0; ch < _channels; ch++)
+ for (i = 0; i < _sFrameSize; i++)
+ _outputBuffer[_channels * i + ch] += (float)(samples[_channels * sub_sampling * i + ch] >> (sizeof(int16)*8-16));
+}
+
+int QDM2Stream::qdm2_decodeFrame(Common::SeekableReadStream *in) {
+ debug(1, "QDM2Stream::qdm2_decodeFrame in->pos(): %d in->size(): %d", in->pos(), in->size());
+ int ch, i;
+ const int frame_size = (_sFrameSize * _channels);
+
+ // select input buffer
+ if(in->eos() || in->size() == in->pos()) {
+ debug(1, "QDM2Stream::qdm2_decodeFrame End of Input Stream");
+ return 0;
+ }
+ if((in->size() - in->pos()) < _packetSize) {
+ debug(1, "QDM2Stream::qdm2_decodeFrame Insufficient Packet Data in Input Stream Found: %d Need: %d", in->size() - in->pos(), _packetSize);
+ return 0;
+ }
+
+ in->read(_compressedData, _packetSize);
+ debug(1, "QDM2Stream::qdm2_decodeFrame constructed input data");
+
+ // copy old block, clear new block of output samples
+ memmove(_outputBuffer, &_outputBuffer[frame_size], frame_size * sizeof(float));
+ memset(&_outputBuffer[frame_size], 0, frame_size * sizeof(float));
+ debug(1, "QDM2Stream::qdm2_decodeFrame cleared outputBuffer");
+
+ // decode block of QDM2 compressed data
+ debug(1, "QDM2Stream::qdm2_decodeFrame decode block of QDM2 compressed data");
+ if (_subPacket == 0) {
+ _hasErrors = false; // reset it for a new super block
+ debug(1, "QDM2 : Superblock follows");
+ qdm2_decode_super_block();
+ }
+
+ // parse subpackets
+ debug(1, "QDM2Stream::qdm2_decodeFrame parse subpackets");
+ if (!_hasErrors) {
+ if (_subPacket == 2) {
+ debug(1, "QDM2Stream::qdm2_decodeFrame qdm2_decode_fft_packets()");
+ qdm2_decode_fft_packets();
+ }
+
+ debug(1, "QDM2Stream::qdm2_decodeFrame qdm2_fft_tone_synthesizer(%d)", _subPacket);
+ qdm2_fft_tone_synthesizer(_subPacket);
+ }
+
+ // sound synthesis stage 1 (FFT)
+ debug(1, "QDM2Stream::qdm2_decodeFrame sound synthesis stage 1 (FFT)");
+ for (ch = 0; ch < _channels; ch++) {
+ qdm2_calculate_fft(ch);
+
+ if (!_hasErrors && _subPacketListC[0].packet != NULL) {
+ error("QDM2 : has errors, and C list is not empty");
+ return 0;
+ }
+ }
+
+ // sound synthesis stage 2 (MPEG audio like synthesis filter)
+ debug(1, "QDM2Stream::qdm2_decodeFrame sound synthesis stage 2 (MPEG audio like synthesis filter)");
+ if (!_hasErrors && _doSynthFilter)
+ qdm2_synthesis_filter(_subPacket);
+
+ _subPacket = (_subPacket + 1) % 16;
+
+ if(_hasErrors)
+ warning("QDM2 Packet error...");
+
+ // clip and convert output float[] to 16bit signed samples
+ debug(1, "QDM2Stream::qdm2_decodeFrame clip and convert output float[] to 16bit signed samples");
+
+/*
+ debugN(1, "Input Data Packet:");
+ for(i = 0; i < _packetSize; i++) {
+ debugN(1, " %d", _compressedData[i]);
+ }
+ debugN(1, " Output Data Packet:");
+ for(i = 0; i < frame_size; i++) {
+ debugN(1, " %d", (int)_outputBuffer[i]);
+ }
+ debug(1, "");
+*/
+
+ for (i = 0; i < frame_size; i++) {
+ //debug(1, "QDM2Stream::qdm2_decodeFrame i: %d", i);
+ int value = (int)_outputBuffer[i];
+
+ if (value > SOFTCLIP_THRESHOLD)
+ value = (value > HARDCLIP_THRESHOLD) ? 32767 : _softclipTable[ value - SOFTCLIP_THRESHOLD];
+ else if (value < -SOFTCLIP_THRESHOLD)
+ value = (value < -HARDCLIP_THRESHOLD) ? -32767 : -_softclipTable[-value - SOFTCLIP_THRESHOLD];
+
+ _outputSamples.push_back(value);
+ }
+ return frame_size;
+}
+
+int QDM2Stream::readBuffer(int16 *buffer, const int numSamples) {
+ debug(1, "QDM2Stream::readBuffer numSamples: %d", numSamples);
+ int32 decodedSamples = _outputSamples.size();
+ int32 i;
+
+ //while((int)_outputSamples.size() < numSamples) {
+ while(!_stream->eos() && _stream->pos() != _stream->size()) {
+ i = qdm2_decodeFrame(_stream);
+ if(i == 0)
+ break; // Out Of Decode Frames...
+ decodedSamples += i;
+ }
+ if(decodedSamples > numSamples)
+ decodedSamples = numSamples;
+
+ for(i = 0; i < decodedSamples; i++)
+ buffer[i] = _outputSamples.remove_at(0);
+
+ return decodedSamples;
+}
+
+} // End of namespace Mohawk
diff --git a/engines/mohawk/video/qdm2.h b/engines/mohawk/video/qdm2.h
new file mode 100644
index 0000000000..ffa5f77030
--- /dev/null
+++ b/engines/mohawk/video/qdm2.h
@@ -0,0 +1,289 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef MOHAWK_VIDEO_QDM2_H
+#define MOHAWK_VIDEO_QDM2_H
+
+#include "sound/audiostream.h"
+#include "common/array.h"
+#include "common/stream.h"
+
+namespace Mohawk {
+
+enum {
+ SOFTCLIP_THRESHOLD = 27600,
+ HARDCLIP_THRESHOLD = 35716,
+ MPA_MAX_CHANNELS = 2,
+ MPA_FRAME_SIZE = 1152,
+ FF_INPUT_BUFFER_PADDING_SIZE = 8
+};
+
+typedef int8 sb_int8_array[2][30][64];
+
+/* bit input */
+/* buffer, buffer_end and size_in_bits must be present and used by every reader */
+struct GetBitContext {
+ const uint8 *buffer, *bufferEnd;
+ int index;
+ int sizeInBits;
+};
+
+struct QDM2SubPacket {
+ int type;
+ unsigned int size;
+ const uint8 *data; // pointer to subpacket data (points to input data buffer, it's not a private copy)
+};
+
+struct QDM2SubPNode {
+ QDM2SubPacket *packet;
+ struct QDM2SubPNode *next; // pointer to next packet in the list, NULL if leaf node
+};
+
+struct QDM2Complex {
+ float re;
+ float im;
+};
+
+struct FFTTone {
+ float level;
+ QDM2Complex *complex;
+ const float *table;
+ int phase;
+ int phase_shift;
+ int duration;
+ short time_index;
+ short cutoff;
+};
+
+struct FFTCoefficient {
+ int16 sub_packet;
+ uint8 channel;
+ int16 offset;
+ int16 exp;
+ uint8 phase;
+};
+
+struct VLC {
+ int32 bits;
+ int16 (*table)[2]; // code, bits
+ int32 table_size;
+ int32 table_allocated;
+};
+
+#include "common/pack-start.h"
+struct QDM2FFT {
+ QDM2Complex complex[MPA_MAX_CHANNELS][256];
+} PACKED_STRUCT;
+#include "common/pack-end.h"
+
+enum RDFTransformType {
+ RDFT,
+ IRDFT,
+ RIDFT,
+ IRIDFT
+};
+
+struct FFTComplex {
+ float re, im;
+};
+
+struct FFTContext {
+ int nbits;
+ int inverse;
+ uint16 *revtab;
+ FFTComplex *exptab;
+ FFTComplex *tmpBuf;
+ int mdctSize; // size of MDCT (i.e. number of input data * 2)
+ int mdctBits; // n = 2^nbits
+ // pre/post rotation tables
+ float *tcos;
+ float *tsin;
+ void (*fftPermute)(struct FFTContext *s, FFTComplex *z);
+ void (*fftCalc)(struct FFTContext *s, FFTComplex *z);
+ void (*imdctCalc)(struct FFTContext *s, float *output, const float *input);
+ void (*imdctHalf)(struct FFTContext *s, float *output, const float *input);
+ void (*mdctCalc)(struct FFTContext *s, float *output, const float *input);
+ int splitRadix;
+ int permutation;
+};
+
+enum {
+ FF_MDCT_PERM_NONE = 0,
+ FF_MDCT_PERM_INTERLEAVE = 1
+};
+
+struct RDFTContext {
+ int nbits;
+ int inverse;
+ int signConvention;
+
+ // pre/post rotation tables
+ float *tcos;
+ float *tsin;
+ FFTContext fft;
+};
+
+class QDM2Stream : public Audio::AudioStream {
+public:
+ QDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData);
+ ~QDM2Stream();
+
+ bool isStereo() const { return _channels == 2; }
+ bool endOfData() const { return ((_stream->pos() == _stream->size()) && (_outputSamples.size() == 0)); }
+ int getRate() const { return _sampleRate; }
+ int readBuffer(int16 *buffer, const int numSamples);
+
+private:
+ Common::SeekableReadStream *_stream;
+
+ // Parameters from codec header, do not change during playback
+ uint8 _channels;
+ uint16 _sampleRate;
+ uint16 _bitRate;
+ uint16 _blockSize; // Group
+ uint16 _frameSize; // FFT
+ uint16 _packetSize; // Checksum
+
+ // Parameters built from header parameters, do not change during playback
+ int _groupOrder; // order of frame group
+ int _fftOrder; // order of FFT (actually fft order+1)
+ int _fftFrameSize; // size of fft frame, in components (1 comples = re + im)
+ int _sFrameSize; // size of data frame
+ int _frequencyRange;
+ int _subSampling; // subsampling: 0=25%, 1=50%, 2=100% */
+ int _coeffPerSbSelect; // selector for "num. of coeffs. per subband" tables. Can be 0, 1, 2
+ int _cmTableSelect; // selector for "coding method" tables. Can be 0, 1 (from init: 0-4)
+
+ // Packets and packet lists
+ QDM2SubPacket _subPackets[16]; // the packets themselves
+ QDM2SubPNode _subPacketListA[16]; // list of all packets
+ QDM2SubPNode _subPacketListB[16]; // FFT packets B are on list
+ int _subPacketsB; // number of packets on 'B' list
+ QDM2SubPNode _subPacketListC[16]; // packets with errors?
+ QDM2SubPNode _subPacketListD[16]; // DCT packets
+
+ // FFT and tones
+ FFTTone _fftTones[1000];
+ int _fftToneStart;
+ int _fftToneEnd;
+ FFTCoefficient _fftCoefs[1000];
+ int _fftCoefsIndex;
+ int _fftCoefsMinIndex[5];
+ int _fftCoefsMaxIndex[5];
+ int _fftLevelExp[6];
+ //RDFTContext _rdftCtx;
+ QDM2FFT _fft;
+
+ // I/O data
+ uint8 *_compressedData;
+ float _outputBuffer[1024];
+ Common::Array<int16> _outputSamples;
+
+ // Synthesis filter
+ int16 ff_mpa_synth_window[512];
+ int16 _synthBuf[MPA_MAX_CHANNELS][512*2];
+ int _synthBufOffset[MPA_MAX_CHANNELS];
+ int32 _sbSamples[MPA_MAX_CHANNELS][128][32];
+
+ // Mixed temporary data used in decoding
+ float _toneLevel[MPA_MAX_CHANNELS][30][64];
+ int8 _codingMethod[MPA_MAX_CHANNELS][30][64];
+ int8 _quantizedCoeffs[MPA_MAX_CHANNELS][10][8];
+ int8 _toneLevelIdxBase[MPA_MAX_CHANNELS][30][8];
+ int8 _toneLevelIdxHi1[MPA_MAX_CHANNELS][3][8][8];
+ int8 _toneLevelIdxMid[MPA_MAX_CHANNELS][26][8];
+ int8 _toneLevelIdxHi2[MPA_MAX_CHANNELS][26];
+ int8 _toneLevelIdx[MPA_MAX_CHANNELS][30][64];
+ int8 _toneLevelIdxTemp[MPA_MAX_CHANNELS][30][64];
+
+ // Flags
+ bool _hasErrors; // packet has errors
+ int _superblocktype_2_3; // select fft tables and some algorithm based on superblock type
+ int _doSynthFilter; // used to perform or skip synthesis filter
+
+ uint8 _subPacket; // 0 to 15
+ int _noiseIdx; // index for dithering noise table
+
+ byte _emptyBuffer[FF_INPUT_BUFFER_PADDING_SIZE];
+
+ VLC _vlcTabLevel;
+ VLC _vlcTabDiff;
+ VLC _vlcTabRun;
+ VLC _fftLevelExpAltVlc;
+ VLC _fftLevelExpVlc;
+ VLC _fftStereoExpVlc;
+ VLC _fftStereoPhaseVlc;
+ VLC _vlcTabToneLevelIdxHi1;
+ VLC _vlcTabToneLevelIdxMid;
+ VLC _vlcTabToneLevelIdxHi2;
+ VLC _vlcTabType30;
+ VLC _vlcTabType34;
+ VLC _vlcTabFftToneOffset[5];
+ bool _vlcsInitialized;
+ void initVlc(void);
+
+ uint16 _softclipTable[HARDCLIP_THRESHOLD - SOFTCLIP_THRESHOLD + 1];
+ void softclipTableInit(void);
+
+ float _noiseTable[4096];
+ byte _randomDequantIndex[256][5];
+ byte _randomDequantType24[128][3];
+ void rndTableInit(void);
+
+ float _noiseSamples[128];
+ void initNoiseSamples(void);
+
+ RDFTContext _rdftCtx;
+
+ void average_quantized_coeffs(void);
+ void build_sb_samples_from_noise(int sb);
+ void fix_coding_method_array(int sb, int channels, sb_int8_array coding_method);
+ void fill_tone_level_array(int flag);
+ void fill_coding_method_array(sb_int8_array tone_level_idx, sb_int8_array tone_level_idx_temp,
+ sb_int8_array coding_method, int nb_channels,
+ int c, int superblocktype_2_3, int cm_table_select);
+ void synthfilt_build_sb_samples(GetBitContext *gb, int length, int sb_min, int sb_max);
+ void init_quantized_coeffs_elem0(int8 *quantized_coeffs, GetBitContext *gb, int length);
+ void init_tone_level_dequantization(GetBitContext *gb, int length);
+ void process_subpacket_9(QDM2SubPNode *node);
+ void process_subpacket_10(QDM2SubPNode *node, int length);
+ void process_subpacket_11(QDM2SubPNode *node, int length);
+ void process_subpacket_12(QDM2SubPNode *node, int length);
+ void process_synthesis_subpackets(QDM2SubPNode *list);
+ void qdm2_decode_super_block(void);
+ void qdm2_fft_init_coefficient(int sub_packet, int offset, int duration,
+ int channel, int exp, int phase);
+ void qdm2_fft_decode_tones(int duration, GetBitContext *gb, int b);
+ void qdm2_decode_fft_packets(void);
+ void qdm2_fft_generate_tone(FFTTone *tone);
+ void qdm2_fft_tone_synthesizer(uint8 sub_packet);
+ void qdm2_calculate_fft(int channel);
+ void qdm2_synthesis_filter(uint8 index);
+ int qdm2_decodeFrame(Common::SeekableReadStream *in);
+};
+
+} // End of namespace Mohawk
+
+#endif
diff --git a/engines/mohawk/video/qdm2data.h b/engines/mohawk/video/qdm2data.h
new file mode 100644
index 0000000000..f1c18db41c
--- /dev/null
+++ b/engines/mohawk/video/qdm2data.h
@@ -0,0 +1,531 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef MOHAWK_VIDEO_QDM2DATA_H
+#define MOHAWK_VIDEO_QDM2DATA_H
+
+#include "common/scummsys.h"
+
+namespace Mohawk {
+
+/// VLC TABLES
+
+// values in this table range from -1..23; adjust retrieved value by -1
+static const uint16 vlc_tab_level_huffcodes[24] = {
+ 0x037c, 0x0004, 0x003c, 0x004c, 0x003a, 0x002c, 0x001c, 0x001a,
+ 0x0024, 0x0014, 0x0001, 0x0002, 0x0000, 0x0003, 0x0007, 0x0005,
+ 0x0006, 0x0008, 0x0009, 0x000a, 0x000c, 0x00fc, 0x007c, 0x017c
+};
+
+static const byte vlc_tab_level_huffbits[24] = {
+ 10, 6, 7, 7, 6, 6, 6, 6, 6, 5, 4, 4, 4, 3, 3, 3, 3, 4, 4, 5, 7, 8, 9, 10
+};
+
+// values in this table range from -1..36; adjust retrieved value by -1
+static const uint16 vlc_tab_diff_huffcodes[37] = {
+ 0x1c57, 0x0004, 0x0000, 0x0001, 0x0003, 0x0002, 0x000f, 0x000e,
+ 0x0007, 0x0016, 0x0037, 0x0027, 0x0026, 0x0066, 0x0006, 0x0097,
+ 0x0046, 0x01c6, 0x0017, 0x0786, 0x0086, 0x0257, 0x00d7, 0x0357,
+ 0x00c6, 0x0386, 0x0186, 0x0000, 0x0157, 0x0c57, 0x0057, 0x0000,
+ 0x0b86, 0x0000, 0x1457, 0x0000, 0x0457
+};
+
+static const byte vlc_tab_diff_huffbits[37] = {
+ 13, 3, 3, 2, 3, 3, 4, 4, 6, 5, 6, 6, 7, 7, 8, 8,
+ 8, 9, 8, 11, 9, 10, 8, 10, 9, 12, 10, 0, 10, 13, 11, 0,
+ 12, 0, 13, 0, 13
+};
+
+// values in this table range from -1..5; adjust retrieved value by -1
+static const byte vlc_tab_run_huffcodes[6] = {
+ 0x1f, 0x00, 0x01, 0x03, 0x07, 0x0f
+};
+
+static const byte vlc_tab_run_huffbits[6] = {
+ 5, 1, 2, 3, 4, 5
+};
+
+// values in this table range from -1..19; adjust retrieved value by -1
+static const uint16 vlc_tab_tone_level_idx_hi1_huffcodes[20] = {
+ 0x5714, 0x000c, 0x0002, 0x0001, 0x0000, 0x0004, 0x0034, 0x0054,
+ 0x0094, 0x0014, 0x0114, 0x0214, 0x0314, 0x0614, 0x0e14, 0x0f14,
+ 0x2714, 0x0714, 0x1714, 0x3714
+};
+
+static const byte vlc_tab_tone_level_idx_hi1_huffbits[20] = {
+ 15, 4, 2, 1, 3, 5, 6, 7, 8, 10, 10, 11, 11, 12, 12, 12, 14, 14, 15, 14
+};
+
+// values in this table range from -1..23; adjust retrieved value by -1
+static const uint16 vlc_tab_tone_level_idx_mid_huffcodes[24] = {
+ 0x0fea, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x03ea, 0x00ea, 0x002a, 0x001a,
+ 0x0006, 0x0001, 0x0000, 0x0002, 0x000a, 0x006a, 0x01ea, 0x07ea
+};
+
+static const byte vlc_tab_tone_level_idx_mid_huffbits[24] = {
+ 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 7, 5, 3, 1, 2, 4, 6, 8, 10, 12
+};
+
+// values in this table range from -1..23; adjust retrieved value by -1
+static const uint16 vlc_tab_tone_level_idx_hi2_huffcodes[24] = {
+ 0x0664, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0064, 0x00e4,
+ 0x00a4, 0x0068, 0x0004, 0x0008, 0x0014, 0x0018, 0x0000, 0x0001,
+ 0x0002, 0x0003, 0x000c, 0x0028, 0x0024, 0x0164, 0x0000, 0x0264
+};
+
+static const byte vlc_tab_tone_level_idx_hi2_huffbits[24] = {
+ 11, 0, 0, 0, 0, 0, 10, 8, 8, 7, 6, 6, 5, 5, 4, 2, 2, 2, 4, 7, 8, 9, 0, 11
+};
+
+// values in this table range from -1..8; adjust retrieved value by -1
+static const byte vlc_tab_type30_huffcodes[9] = {
+ 0x3c, 0x06, 0x00, 0x01, 0x03, 0x02, 0x04, 0x0c, 0x1c
+};
+
+static const byte vlc_tab_type30_huffbits[9] = {
+ 6, 3, 3, 2, 2, 3, 4, 5, 6
+};
+
+// values in this table range from -1..9; adjust retrieved value by -1
+static const byte vlc_tab_type34_huffcodes[10] = {
+ 0x18, 0x00, 0x01, 0x04, 0x05, 0x07, 0x03, 0x02, 0x06, 0x08
+};
+
+static const byte vlc_tab_type34_huffbits[10] = {
+ 5, 4, 3, 3, 3, 3, 3, 3, 3, 5
+};
+
+// values in this table range from -1..22; adjust retrieved value by -1
+static const uint16 vlc_tab_fft_tone_offset_0_huffcodes[23] = {
+ 0x038e, 0x0001, 0x0000, 0x0022, 0x000a, 0x0006, 0x0012, 0x0002,
+ 0x001e, 0x003e, 0x0056, 0x0016, 0x000e, 0x0032, 0x0072, 0x0042,
+ 0x008e, 0x004e, 0x00f2, 0x002e, 0x0036, 0x00c2, 0x018e
+};
+
+static const byte vlc_tab_fft_tone_offset_0_huffbits[23] = {
+ 10, 1, 2, 6, 4, 5, 6, 7, 6, 6, 7, 7, 8, 7, 8, 8, 9, 7, 8, 6, 6, 8, 10
+};
+
+// values in this table range from -1..27; adjust retrieved value by -1
+static const uint16 vlc_tab_fft_tone_offset_1_huffcodes[28] = {
+ 0x07a4, 0x0001, 0x0020, 0x0012, 0x001c, 0x0008, 0x0006, 0x0010,
+ 0x0000, 0x0014, 0x0004, 0x0032, 0x0070, 0x000c, 0x0002, 0x003a,
+ 0x001a, 0x002c, 0x002a, 0x0022, 0x0024, 0x000a, 0x0064, 0x0030,
+ 0x0062, 0x00a4, 0x01a4, 0x03a4
+};
+
+static const byte vlc_tab_fft_tone_offset_1_huffbits[28] = {
+ 11, 1, 6, 6, 5, 4, 3, 6, 6, 5, 6, 6, 7, 6, 6, 6,
+ 6, 6, 6, 7, 8, 6, 7, 7, 7, 9, 10, 11
+};
+
+// values in this table range from -1..31; adjust retrieved value by -1
+static const uint16 vlc_tab_fft_tone_offset_2_huffcodes[32] = {
+ 0x1760, 0x0001, 0x0000, 0x0082, 0x000c, 0x0006, 0x0003, 0x0007,
+ 0x0008, 0x0004, 0x0010, 0x0012, 0x0022, 0x001a, 0x0000, 0x0020,
+ 0x000a, 0x0040, 0x004a, 0x006a, 0x002a, 0x0042, 0x0002, 0x0060,
+ 0x00aa, 0x00e0, 0x00c2, 0x01c2, 0x0160, 0x0360, 0x0760, 0x0f60
+};
+
+static const byte vlc_tab_fft_tone_offset_2_huffbits[32] = {
+ 13, 2, 0, 8, 4, 3, 3, 3, 4, 4, 5, 5, 6, 5, 7, 7,
+ 7, 7, 7, 7, 8, 8, 8, 9, 8, 8, 9, 9, 10, 11, 13, 12
+};
+
+// values in this table range from -1..34; adjust retrieved value by -1
+static const uint16 vlc_tab_fft_tone_offset_3_huffcodes[35] = {
+ 0x33ea, 0x0005, 0x0000, 0x000c, 0x0000, 0x0006, 0x0003, 0x0008,
+ 0x0002, 0x0001, 0x0004, 0x0007, 0x001a, 0x000f, 0x001c, 0x002c,
+ 0x000a, 0x001d, 0x002d, 0x002a, 0x000d, 0x004c, 0x008c, 0x006a,
+ 0x00cd, 0x004d, 0x00ea, 0x020c, 0x030c, 0x010c, 0x01ea, 0x07ea,
+ 0x0bea, 0x03ea, 0x13ea
+};
+
+static const byte vlc_tab_fft_tone_offset_3_huffbits[35] = {
+ 14, 4, 0, 10, 4, 3, 3, 4, 4, 3, 4, 4, 5, 4, 5, 6,
+ 6, 5, 6, 7, 7, 7, 8, 8, 8, 8, 9, 10, 10, 10, 10, 11,
+ 12, 13, 14
+};
+
+// values in this table range from -1..37; adjust retrieved value by -1
+static const uint16 vlc_tab_fft_tone_offset_4_huffcodes[38] = {
+ 0x5282, 0x0016, 0x0000, 0x0136, 0x0004, 0x0000, 0x0007, 0x000a,
+ 0x000e, 0x0003, 0x0001, 0x000d, 0x0006, 0x0009, 0x0012, 0x0005,
+ 0x0025, 0x0022, 0x0015, 0x0002, 0x0076, 0x0035, 0x0042, 0x00c2,
+ 0x0182, 0x00b6, 0x0036, 0x03c2, 0x0482, 0x01c2, 0x0682, 0x0882,
+ 0x0a82, 0x0082, 0x0282, 0x1282, 0x3282, 0x2282
+};
+
+static const byte vlc_tab_fft_tone_offset_4_huffbits[38] = {
+ 15, 6, 0, 9, 3, 3, 3, 4, 4, 3, 4, 4, 5, 4, 5, 6,
+ 6, 6, 6, 8, 7, 6, 8, 9, 9, 8, 9, 10, 11, 10, 11, 12,
+ 12, 12, 14, 15, 14, 14
+};
+
+/// FFT TABLES
+
+// values in this table range from -1..27; adjust retrieved value by -1
+static const uint16 fft_level_exp_alt_huffcodes[28] = {
+ 0x1ec6, 0x0006, 0x00c2, 0x0142, 0x0242, 0x0246, 0x00c6, 0x0046,
+ 0x0042, 0x0146, 0x00a2, 0x0062, 0x0026, 0x0016, 0x000e, 0x0005,
+ 0x0004, 0x0003, 0x0000, 0x0001, 0x000a, 0x0012, 0x0002, 0x0022,
+ 0x01c6, 0x02c6, 0x06c6, 0x0ec6
+};
+
+static const byte fft_level_exp_alt_huffbits[28] = {
+ 13, 7, 8, 9, 10, 10, 10, 10, 10, 9, 8, 7, 6, 5, 4, 3,
+ 3, 2, 3, 3, 4, 5, 7, 8, 9, 11, 12, 13
+};
+
+// values in this table range from -1..19; adjust retrieved value by -1
+static const uint16 fft_level_exp_huffcodes[20] = {
+ 0x0f24, 0x0001, 0x0002, 0x0000, 0x0006, 0x0005, 0x0007, 0x000c,
+ 0x000b, 0x0014, 0x0013, 0x0004, 0x0003, 0x0023, 0x0064, 0x00a4,
+ 0x0024, 0x0124, 0x0324, 0x0724
+};
+
+static const byte fft_level_exp_huffbits[20] = {
+ 12, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 8, 9, 10, 11, 12
+};
+
+// values in this table range from -1..6; adjust retrieved value by -1
+static const byte fft_stereo_exp_huffcodes[7] = {
+ 0x3e, 0x01, 0x00, 0x02, 0x06, 0x0e, 0x1e
+};
+
+static const byte fft_stereo_exp_huffbits[7] = {
+ 6, 1, 2, 3, 4, 5, 6
+};
+
+// values in this table range from -1..8; adjust retrieved value by -1
+static const byte fft_stereo_phase_huffcodes[9] = {
+ 0x35, 0x02, 0x00, 0x01, 0x0d, 0x15, 0x05, 0x09, 0x03
+};
+
+static const byte fft_stereo_phase_huffbits[9] = {
+ 6, 2, 2, 4, 4, 6, 5, 4, 2
+};
+
+static const int fft_cutoff_index_table[4][2] = {
+ { 1, 2 }, {-1, 0 }, {-1,-2 }, { 0, 0 }
+};
+
+static const int16 fft_level_index_table[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+};
+
+static const byte last_coeff[3] = {
+ 4, 7, 10
+};
+
+static const byte coeff_per_sb_for_avg[3][30] = {
+ { 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
+ { 0, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 },
+ { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9 }
+};
+
+static const uint32 dequant_table[3][10][30] = {
+ { { 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 256, 256, 205, 154, 102, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 51, 102, 154, 205, 256, 238, 219, 201, 183, 165, 146, 128, 110, 91, 73, 55, 37, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 18, 37, 55, 73, 91, 110, 128, 146, 165, 183, 201, 219, 238, 256, 228, 199, 171, 142, 114, 85, 57, 28 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+ { { 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 256, 171, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 85, 171, 256, 171, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 85, 171, 256, 219, 183, 146, 110, 73, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 73, 110, 146, 183, 219, 256, 228, 199, 171, 142, 114, 85, 57, 28, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 57, 85, 114, 142, 171, 199, 228, 256, 213, 171, 128, 85, 43 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+ { { 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 256, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 256, 171, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 85, 171, 256, 192, 128, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 128, 192, 256, 205, 154, 102, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 102, 154, 205, 256, 213, 171, 128, 85, 43, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 85, 128, 171, 213, 256, 213, 171, 128, 85, 43 } }
+};
+
+static const byte coeff_per_sb_for_dequant[3][30] = {
+ { 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
+ { 0, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6 },
+ { 0, 1, 2, 3, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9 }
+};
+
+// first index is subband, 2nd index is 0, 1 or 3 (2 is unused)
+static const int8 tone_level_idx_offset_table[30][4] = {
+ { -50, -50, 0, -50 },
+ { -50, -50, 0, -50 },
+ { -50, -9, 0, -19 },
+ { -16, -6, 0, -12 },
+ { -11, -4, 0, -8 },
+ { -8, -3, 0, -6 },
+ { -7, -3, 0, -5 },
+ { -6, -2, 0, -4 },
+ { -5, -2, 0, -3 },
+ { -4, -1, 0, -3 },
+ { -4, -1, 0, -2 },
+ { -3, -1, 0, -2 },
+ { -3, -1, 0, -2 },
+ { -3, -1, 0, -2 },
+ { -2, -1, 0, -1 },
+ { -2, -1, 0, -1 },
+ { -2, -1, 0, -1 },
+ { -2, 0, 0, -1 },
+ { -2, 0, 0, -1 },
+ { -1, 0, 0, -1 },
+ { -1, 0, 0, -1 },
+ { -1, 0, 0, -1 },
+ { -1, 0, 0, -1 },
+ { -1, 0, 0, -1 },
+ { -1, 0, 0, -1 },
+ { -1, 0, 0, -1 },
+ { -1, 0, 0, 0 },
+ { -1, 0, 0, 0 },
+ { -1, 0, 0, 0 },
+ { -1, 0, 0, 0 }
+};
+
+/* all my samples have 1st index 0 or 1 */
+/* second index is subband, only indexes 0-29 seem to be used */
+static const int8 coding_method_table[5][30] = {
+ { 34, 30, 24, 24, 16, 16, 16, 16, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10
+ },
+ { 34, 30, 24, 24, 16, 16, 16, 16, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10
+ },
+ { 34, 30, 30, 30, 24, 24, 16, 16, 16, 16, 16, 16, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10
+ },
+ { 34, 34, 30, 30, 24, 24, 24, 24, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 10, 10, 10, 10, 10, 10, 10, 10
+ },
+ { 34, 34, 30, 30, 30, 30, 30, 30, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16
+ },
+};
+
+static const int vlc_stage3_values[60] = {
+ 0, 1, 2, 3, 4, 6, 8, 10, 12, 16, 20, 24,
+ 28, 36, 44, 52, 60, 76, 92, 108, 124, 156, 188, 220,
+ 252, 316, 380, 444, 508, 636, 764, 892, 1020, 1276, 1532, 1788,
+ 2044, 2556, 3068, 3580, 4092, 5116, 6140, 7164, 8188, 10236, 12284, 14332,
+ 16380, 20476, 24572, 28668, 32764, 40956, 49148, 57340, 65532, 81916, 98300,114684
+};
+
+static const float fft_tone_sample_table[4][16][5] = {
+ { { .0100000000f,-.0037037037f,-.0020000000f,-.0069444444f,-.0018416207f },
+ { .0416666667f, .0000000000f, .0000000000f,-.0208333333f,-.0123456791f },
+ { .1250000000f, .0558035709f, .0330687836f,-.0164473690f,-.0097465888f },
+ { .1562500000f, .0625000000f, .0370370370f,-.0062500000f,-.0037037037f },
+ { .1996007860f, .0781250000f, .0462962948f, .0022727272f, .0013468013f },
+ { .2000000000f, .0625000000f, .0370370373f, .0208333333f, .0074074073f },
+ { .2127659619f, .0555555556f, .0329218097f, .0208333333f, .0123456791f },
+ { .2173913121f, .0473484844f, .0280583613f, .0347222239f, .0205761325f },
+ { .2173913121f, .0347222239f, .0205761325f, .0473484844f, .0280583613f },
+ { .2127659619f, .0208333333f, .0123456791f, .0555555556f, .0329218097f },
+ { .2000000000f, .0208333333f, .0074074073f, .0625000000f, .0370370370f },
+ { .1996007860f, .0022727272f, .0013468013f, .0781250000f, .0462962948f },
+ { .1562500000f,-.0062500000f,-.0037037037f, .0625000000f, .0370370370f },
+ { .1250000000f,-.0164473690f,-.0097465888f, .0558035709f, .0330687836f },
+ { .0416666667f,-.0208333333f,-.0123456791f, .0000000000f, .0000000000f },
+ { .0100000000f,-.0069444444f,-.0018416207f,-.0037037037f,-.0020000000f } },
+
+ { { .0050000000f,-.0200000000f, .0125000000f,-.3030303030f, .0020000000f },
+ { .1041666642f, .0400000000f,-.0250000000f, .0333333333f,-.0200000000f },
+ { .1250000000f, .0100000000f, .0142857144f,-.0500000007f,-.0200000000f },
+ { .1562500000f,-.0006250000f,-.00049382716f,-.000625000f,-.00049382716f },
+ { .1562500000f,-.0006250000f,-.00049382716f,-.000625000f,-.00049382716f },
+ { .1250000000f,-.0500000000f,-.0200000000f, .0100000000f, .0142857144f },
+ { .1041666667f, .0333333333f,-.0200000000f, .0400000000f,-.0250000000f },
+ { .0050000000f,-.3030303030f, .0020000001f,-.0200000000f, .0125000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f } },
+
+ { { .1428571492f, .1250000000f,-.0285714287f,-.0357142873f, .0208333333f },
+ { .1818181818f, .0588235296f, .0333333333f, .0212765951f, .0100000000f },
+ { .1818181818f, .0212765951f, .0100000000f, .0588235296f, .0333333333f },
+ { .1428571492f,-.0357142873f, .0208333333f, .1250000000f,-.0285714287f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f } },
+
+ { { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
+ { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f } }
+};
+
+static const float fft_tone_level_table[2][64] = { {
+// pow ~ (i > 46) ? 0 : (((((i & 1) ? 431 : 304) << (i >> 1))) / 1024.0);
+ 0.17677669f, 0.42677650f, 0.60355347f, 0.85355347f,
+ 1.20710683f, 1.68359375f, 2.37500000f, 3.36718750f,
+ 4.75000000f, 6.73437500f, 9.50000000f, 13.4687500f,
+ 19.0000000f, 26.9375000f, 38.0000000f, 53.8750000f,
+ 76.0000000f, 107.750000f, 152.000000f, 215.500000f,
+ 304.000000f, 431.000000f, 608.000000f, 862.000000f,
+ 1216.00000f, 1724.00000f, 2432.00000f, 3448.00000f,
+ 4864.00000f, 6896.00000f, 9728.00000f, 13792.0000f,
+ 19456.0000f, 27584.0000f, 38912.0000f, 55168.0000f,
+ 77824.0000f, 110336.000f, 155648.000f, 220672.000f,
+ 311296.000f, 441344.000f, 622592.000f, 882688.000f,
+ 1245184.00f, 1765376.00f, 2490368.00f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ }, {
+// pow = (i > 45) ? 0 : ((((i & 1) ? 431 : 304) << (i >> 1)) / 512.0);
+ 0.59375000f, 0.84179688f, 1.18750000f, 1.68359375f,
+ 2.37500000f, 3.36718750f, 4.75000000f, 6.73437500f,
+ 9.50000000f, 13.4687500f, 19.0000000f, 26.9375000f,
+ 38.0000000f, 53.8750000f, 76.0000000f, 107.750000f,
+ 152.000000f, 215.500000f, 304.000000f, 431.000000f,
+ 608.000000f, 862.000000f, 1216.00000f, 1724.00000f,
+ 2432.00000f, 3448.00000f, 4864.00000f, 6896.00000f,
+ 9728.00000f, 13792.0000f, 19456.0000f, 27584.0000f,
+ 38912.0000f, 55168.0000f, 77824.0000f, 110336.000f,
+ 155648.000f, 220672.000f, 311296.000f, 441344.000f,
+ 622592.000f, 882688.000f, 1245184.00f, 1765376.00f,
+ 2490368.00f, 3530752.00f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+ 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f
+} };
+
+static const float fft_tone_envelope_table[4][31] = {
+ { .009607375f, .038060248f, .084265202f, .146446645f, .222214907f, .308658302f,
+ .402454883f, .500000060f, .597545207f, .691341758f, .777785182f, .853553414f,
+ .915734828f, .961939812f, .990392685f, 1.00000000f, .990392625f, .961939752f,
+ .915734768f, .853553295f, .777785063f, .691341639f, .597545087f, .500000000f,
+ .402454853f, .308658272f, .222214878f, .146446615f, .084265172f, .038060218f,
+ .009607345f },
+ { .038060248f, .146446645f, .308658302f, .500000060f, .691341758f, .853553414f,
+ .961939812f, 1.00000000f, .961939752f, .853553295f, .691341639f, .500000000f,
+ .308658272f, .146446615f, .038060218f, .000000000f, .000000000f, .000000000f,
+ .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
+ .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
+ .000000000f },
+ { .146446645f, .500000060f, .853553414f, 1.00000000f, .853553295f, .500000000f,
+ .146446615f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
+ .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
+ .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
+ .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
+ .000000000f },
+ { .500000060f, 1.00000000f, .500000000f, .000000000f, .000000000f, .000000000f,
+ .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
+ .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
+ .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
+ .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
+ .000000000f }
+};
+
+static const float sb_noise_attenuation[32] = {
+ 0.0f, 0.0f, 0.3f, 0.4f, 0.5f, 0.7f, 1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
+};
+
+static const byte fft_subpackets[32] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0
+};
+
+// first index is joined_stereo, second index is 0 or 2 (1 is unused)
+static const float dequant_1bit[2][3] = {
+ {-0.920000f, 0.000000f, 0.920000f },
+ {-0.890000f, 0.000000f, 0.890000f }
+};
+
+static const float type30_dequant[8] = {
+ -1.0f,-0.625f,-0.291666656732559f,0.0f,
+ 0.25f,0.5f,0.75f,1.0f,
+};
+
+static const float type34_delta[10] = { // FIXME: covers 8 entries..
+ -1.0f,-0.60947573184967f,-0.333333343267441f,-0.138071194291115f,0.0f,
+ 0.138071194291115f,0.333333343267441f,0.60947573184967f,1.0f,0.0f,
+};
+
+} // End of namespace Mohawk
+
+#endif
diff --git a/engines/mohawk/video/qt_player.cpp b/engines/mohawk/video/qt_player.cpp
new file mode 100644
index 0000000000..0ed05bb84d
--- /dev/null
+++ b/engines/mohawk/video/qt_player.cpp
@@ -0,0 +1,1272 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+//
+// Heavily based on ffmpeg code.
+//
+// Copyright (c) 2001 Fabrice Bellard.
+// First version by Francois Revol revol@free.fr
+// Seek function by Gael Chardon gael.dev@4now.net
+//
+
+#include "mohawk/video/qt_player.h"
+
+#include "common/debug.h"
+#include "common/endian.h"
+#include "common/util.h"
+#include "common/zlib.h"
+
+// Audio codecs
+#include "sound/decoders/adpcm.h"
+#include "sound/decoders/raw.h"
+#include "mohawk/video/qdm2.h"
+
+// Video codecs
+#include "mohawk/jpeg.h"
+#include "mohawk/video/cinepak.h"
+#include "mohawk/video/qtrle.h"
+#include "mohawk/video/rpza.h"
+#include "mohawk/video/smc.h"
+
+namespace Mohawk {
+
+////////////////////////////////////////////
+// QTPlayer
+////////////////////////////////////////////
+
+QTPlayer::QTPlayer() : Graphics::VideoDecoder() {
+ _audStream = NULL;
+ _beginOffset = 0;
+ _videoCodec = NULL;
+ _curFrame = -1;
+ _startTime = _nextFrameStartTime = 0;
+ _audHandle = Audio::SoundHandle();
+ _numStreams = 0;
+ _fd = 0;
+ _scaledSurface = 0;
+ _dirtyPalette = false;
+}
+
+QTPlayer::~QTPlayer() {
+ close();
+}
+
+uint16 QTPlayer::getWidth() const {
+ if (_videoStreamIndex < 0)
+ return 0;
+
+ return _streams[_videoStreamIndex]->width / getScaleMode();
+}
+
+uint16 QTPlayer::getHeight() const {
+ if (_videoStreamIndex < 0)
+ return 0;
+
+ return _streams[_videoStreamIndex]->height / getScaleMode();
+}
+
+uint32 QTPlayer::getFrameCount() const {
+ if (_videoStreamIndex < 0)
+ return 0;
+
+ return _streams[_videoStreamIndex]->nb_frames;
+}
+
+byte QTPlayer::getBitsPerPixel() {
+ if (_videoStreamIndex < 0)
+ return 0;
+
+ return _streams[_videoStreamIndex]->bits_per_sample & 0x1F;
+}
+
+uint32 QTPlayer::getCodecTag() {
+ if (_videoStreamIndex < 0)
+ return 0;
+
+ return _streams[_videoStreamIndex]->codec_tag;
+}
+
+ScaleMode QTPlayer::getScaleMode() const {
+ if (_videoStreamIndex < 0)
+ return kScaleNormal;
+
+ return (ScaleMode)(_scaleMode * _streams[_videoStreamIndex]->scaleMode);
+}
+
+uint32 QTPlayer::getFrameDuration() {
+ if (_videoStreamIndex < 0)
+ return 0;
+
+ uint32 curFrameIndex = 0;
+ for (int32 i = 0; i < _streams[_videoStreamIndex]->stts_count; i++) {
+ curFrameIndex += _streams[_videoStreamIndex]->stts_data[i].count;
+ if ((uint32)_curFrame < curFrameIndex) {
+ // Ok, now we have what duration this frame has.
+ return _streams[_videoStreamIndex]->stts_data[i].duration;
+ }
+ }
+
+ // This should never occur
+ error ("Cannot find duration for frame %d", _curFrame);
+ return 0;
+}
+
+Graphics::PixelFormat QTPlayer::getPixelFormat() const {
+ if (!_videoCodec)
+ return Graphics::PixelFormat::createFormatCLUT8();
+
+ return _videoCodec->getPixelFormat();
+}
+
+void QTPlayer::rewind() {
+ delete _videoCodec; _videoCodec = NULL;
+ _curFrame = -1;
+ _startTime = _nextFrameStartTime = 0;
+
+ // Restart the audio too
+ stopAudio();
+ if (_audioStreamIndex >= 0) {
+ _curAudioChunk = 0;
+ _audStream = Audio::makeQueuingAudioStream(_streams[_audioStreamIndex]->sample_rate, _streams[_audioStreamIndex]->channels == 2);
+ }
+ startAudio();
+}
+
+Graphics::Codec *QTPlayer::createCodec(uint32 codecTag, byte bitsPerPixel) {
+ if (codecTag == MKID_BE('cvid')) {
+ // Cinepak: As used by most Myst and all Riven videos as well as some Myst ME videos. "The Chief" videos also use this.
+ return new CinepakDecoder();
+ } else if (codecTag == MKID_BE('rpza')) {
+ // Apple Video ("Road Pizza"): Used by some Myst videos.
+ return new RPZADecoder(getWidth(), getHeight());
+ } else if (codecTag == MKID_BE('rle ')) {
+ // QuickTime RLE: Used by some Myst ME videos.
+ return new QTRLEDecoder(getWidth(), getHeight(), bitsPerPixel);
+ } else if (codecTag == MKID_BE('smc ')) {
+ // Apple SMC: Used by some Myst videos.
+ return new SMCDecoder(getWidth(), getHeight());
+ } else if (codecTag == MKID_BE('SVQ1')) {
+ // Sorenson Video 1: Used by some Myst ME videos.
+ warning ("Sorenson Video 1 not yet supported");
+ } else if (codecTag == MKID_BE('SVQ3')) {
+ // Sorenson Video 3: Used by some Myst ME videos.
+ warning ("Sorenson Video 3 not yet supported");
+ } else if (codecTag == MKID_BE('jpeg')) {
+ // Motion JPEG: Used by some Myst ME 10th Anniversary videos.
+ return new JPEGDecoder(true);
+ } else if (codecTag == MKID_BE('QkBk')) {
+ // CDToons: Used by most of the Broderbund games. This is an unknown format so far.
+ warning ("CDToons not yet supported");
+ } else {
+ warning ("Unsupported codec \'%s\'", tag2str(codecTag));
+ }
+
+ return NULL;
+}
+
+void QTPlayer::startAudio() {
+ if (_audStream) // No audio/audio not supported
+ g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_audHandle, _audStream);
+}
+
+void QTPlayer::stopAudio() {
+ if (_audStream) {
+ g_system->getMixer()->stopHandle(_audHandle);
+ _audStream = NULL; // the mixer automatically frees the stream
+ }
+}
+
+void QTPlayer::pauseVideoIntern(bool pause) {
+ if (_audStream)
+ g_system->getMixer()->pauseHandle(_audHandle, pause);
+}
+
+Graphics::Surface *QTPlayer::decodeNextFrame() {
+ if (!_videoCodec || _curFrame >= (int32)getFrameCount() - 1)
+ return NULL;
+
+ if (_startTime == 0)
+ _startTime = g_system->getMillis();
+
+ _curFrame++;
+ _nextFrameStartTime += getFrameDuration();
+
+ Common::SeekableReadStream *frameData = getNextFramePacket();
+
+ if (frameData) {
+ Graphics::Surface *frame = _videoCodec->decodeImage(frameData);
+ delete frameData;
+ return scaleSurface(frame);
+ }
+
+ return NULL;
+}
+
+Graphics::Surface *QTPlayer::scaleSurface(Graphics::Surface *frame) {
+ if (getScaleMode() == kScaleNormal)
+ return frame;
+
+ assert(_scaledSurface);
+
+ for (uint32 j = 0; j < _scaledSurface->h; j++)
+ for (uint32 k = 0; k < _scaledSurface->w; k++)
+ memcpy(_scaledSurface->getBasePtr(k, j), frame->getBasePtr(k * getScaleMode(), j * getScaleMode()), frame->bytesPerPixel);
+
+ return _scaledSurface;
+}
+
+bool QTPlayer::endOfVideo() const {
+ return (!_audStream || _audStream->endOfData()) && (!_videoCodec || _curFrame >= (int32)getFrameCount() - 1);
+}
+
+bool QTPlayer::needsUpdate() const {
+ return !endOfVideo() && getTimeToNextFrame() == 0;
+}
+
+uint32 QTPlayer::getElapsedTime() const {
+ if (_audStream)
+ return g_system->getMixer()->getSoundElapsedTime(_audHandle);
+
+ return g_system->getMillis() - _startTime;
+}
+
+uint32 QTPlayer::getTimeToNextFrame() const {
+ if (endOfVideo() || _curFrame < 0)
+ return 0;
+
+ // Convert from the Sega FILM base to 1000
+ uint32 nextFrameStartTime = _nextFrameStartTime * 1000 / _streams[_videoStreamIndex]->time_scale;
+ uint32 elapsedTime = getElapsedTime();
+
+ if (nextFrameStartTime <= elapsedTime)
+ return 0;
+
+ return nextFrameStartTime - elapsedTime;
+}
+
+bool QTPlayer::load(Common::SeekableReadStream &stream) {
+ _fd = &stream;
+ _foundMOOV = _foundMDAT = false;
+ _numStreams = 0;
+ _partial = 0;
+ _videoStreamIndex = _audioStreamIndex = -1;
+ _startTime = 0;
+
+ initParseTable();
+
+ MOVatom atom = { 0, 0, 0xffffffff };
+
+ if (readDefault(atom) < 0 || (!_foundMOOV && !_foundMDAT))
+ return false;
+
+ debug(0, "on_parse_exit_offset=%d", _fd->pos());
+
+ // some cleanup : make sure we are on the mdat atom
+ if((uint32)_fd->pos() != _mdatOffset)
+ _fd->seek(_mdatOffset, SEEK_SET);
+
+ _next_chunk_offset = _mdatOffset; // initialise reading
+
+ for (uint32 i = 0; i < _numStreams;) {
+ if (_streams[i]->codec_type == CODEC_TYPE_MOV_OTHER) {// not audio, not video, delete
+ delete _streams[i];
+ for (uint32 j = i + 1; j < _numStreams; j++)
+ _streams[j - 1] = _streams[j];
+ _numStreams--;
+ } else
+ i++;
+ }
+
+ for (uint32 i = 0; i < _numStreams; i++) {
+ MOVStreamContext *sc = _streams[i];
+
+ if(!sc->time_rate)
+ sc->time_rate = 1;
+
+ if(!sc->time_scale)
+ sc->time_scale = _timeScale;
+
+ //av_set_pts_info(s->streams[i], 64, sc->time_rate, sc->time_scale);
+
+ sc->duration /= sc->time_rate;
+
+ sc->ffindex = i;
+ sc->is_ff_stream = 1;
+
+ if (sc->codec_type == CODEC_TYPE_VIDEO && _videoStreamIndex < 0)
+ _videoStreamIndex = i;
+ else if (sc->codec_type == CODEC_TYPE_AUDIO && _audioStreamIndex < 0)
+ _audioStreamIndex = i;
+ }
+
+ if (_audioStreamIndex >= 0 && checkAudioCodecSupport(_streams[_audioStreamIndex]->codec_tag)) {
+ _audStream = Audio::makeQueuingAudioStream(_streams[_audioStreamIndex]->sample_rate, _streams[_audioStreamIndex]->channels == 2);
+ _curAudioChunk = 0;
+
+ // Make sure the bits per sample transfers to the sample size
+ if (_streams[_audioStreamIndex]->codec_tag == MKID_BE('raw ') || _streams[_audioStreamIndex]->codec_tag == MKID_BE('twos'))
+ _streams[_audioStreamIndex]->sample_size = (_streams[_audioStreamIndex]->bits_per_sample / 8) * _streams[_audioStreamIndex]->channels;
+
+ startAudio();
+ }
+
+ if (_videoStreamIndex >= 0) {
+ _videoCodec = createCodec(getCodecTag(), getBitsPerPixel());
+
+ if (getScaleMode() != kScaleNormal) {
+ // We have to initialize the scaled surface
+ _scaledSurface = new Graphics::Surface();
+ _scaledSurface->create(getWidth(), getHeight(), getPixelFormat().bytesPerPixel);
+ }
+ }
+
+ return true;
+}
+
+void QTPlayer::initParseTable() {
+ static const ParseTable p[] = {
+ { MKID_BE('dinf'), &QTPlayer::readDefault },
+ { MKID_BE('dref'), &QTPlayer::readLeaf },
+ { MKID_BE('edts'), &QTPlayer::readDefault },
+ { MKID_BE('elst'), &QTPlayer::readELST },
+ { MKID_BE('hdlr'), &QTPlayer::readHDLR },
+ { MKID_BE('mdat'), &QTPlayer::readMDAT },
+ { MKID_BE('mdhd'), &QTPlayer::readMDHD },
+ { MKID_BE('mdia'), &QTPlayer::readDefault },
+ { MKID_BE('minf'), &QTPlayer::readDefault },
+ { MKID_BE('moov'), &QTPlayer::readMOOV },
+ { MKID_BE('mvhd'), &QTPlayer::readMVHD },
+ { MKID_BE('smhd'), &QTPlayer::readLeaf },
+ { MKID_BE('stbl'), &QTPlayer::readDefault },
+ { MKID_BE('stco'), &QTPlayer::readSTCO },
+ { MKID_BE('stsc'), &QTPlayer::readSTSC },
+ { MKID_BE('stsd'), &QTPlayer::readSTSD },
+ { MKID_BE('stss'), &QTPlayer::readSTSS },
+ { MKID_BE('stsz'), &QTPlayer::readSTSZ },
+ { MKID_BE('stts'), &QTPlayer::readSTTS },
+ { MKID_BE('tkhd'), &QTPlayer::readTKHD },
+ { MKID_BE('trak'), &QTPlayer::readTRAK },
+ { MKID_BE('udta'), &QTPlayer::readLeaf },
+ { MKID_BE('vmhd'), &QTPlayer::readLeaf },
+ { MKID_BE('cmov'), &QTPlayer::readCMOV },
+ { MKID_BE('wave'), &QTPlayer::readWAVE },
+ { 0, 0 }
+ };
+
+ _parseTable = p;
+}
+
+int QTPlayer::readDefault(MOVatom atom) {
+ uint32 total_size = 0;
+ MOVatom a;
+ int err = 0;
+
+ a.offset = atom.offset;
+
+ while(((total_size + 8) < atom.size) && !_fd->eos() && !err) {
+ a.size = atom.size;
+ a.type = 0;
+
+ if (atom.size >= 8) {
+ a.size = _fd->readUint32BE();
+ a.type = _fd->readUint32BE();
+ }
+
+ total_size += 8;
+ a.offset += 8;
+ debug(4, "type: %08x %.4s sz: %x %x %x", a.type, tag2str(a.type), a.size, atom.size, total_size);
+
+ if (a.size == 1) { // 64 bit extended size
+ warning("64 bit extended size is not supported in QuickTime");
+ return -1;
+ }
+
+ if (a.size == 0) {
+ a.size = atom.size - total_size;
+ if (a.size <= 8)
+ break;
+ }
+
+ uint32 i = 0;
+
+ for (; _parseTable[i].type != 0 && _parseTable[i].type != a.type; i++)
+ // empty;
+
+ if (a.size < 8)
+ break;
+
+ a.size -= 8;
+
+ if (_parseTable[i].type == 0) { // skip leaf atoms data
+ debug(0, ">>> Skipped [%s]", tag2str(a.type));
+
+ _fd->seek(a.size, SEEK_CUR);
+ } else {
+ uint32 start_pos = _fd->pos();
+ err = (this->*_parseTable[i].func)(a);
+
+ uint32 left = a.size - _fd->pos() + start_pos;
+
+ if (left > 0) // skip garbage at atom end
+ _fd->seek(left, SEEK_CUR);
+ }
+
+ a.offset += a.size;
+ total_size += a.size;
+ }
+
+ if (!err && total_size < atom.size)
+ _fd->seek(atom.size - total_size, SEEK_SET);
+
+ return err;
+}
+
+int QTPlayer::readLeaf(MOVatom atom) {
+ if (atom.size > 1)
+ _fd->seek(atom.size, SEEK_SET);
+
+ return 0;
+}
+
+int QTPlayer::readMOOV(MOVatom atom) {
+ if (readDefault(atom) < 0)
+ return -1;
+
+ // we parsed the 'moov' atom, we can terminate the parsing as soon as we find the 'mdat'
+ // so we don't parse the whole file if over a network
+ _foundMOOV = true;
+
+ if(_foundMDAT)
+ return 1; // found both, just go
+
+ return 0; // now go for mdat
+}
+
+int QTPlayer::readCMOV(MOVatom atom) {
+#ifdef USE_ZLIB
+ // Read in the dcom atom
+ _fd->readUint32BE();
+ if (_fd->readUint32BE() != MKID_BE('dcom'))
+ return -1;
+ if (_fd->readUint32BE() != MKID_BE('zlib')) {
+ warning("Unknown cmov compression type");
+ return -1;
+ }
+
+ // Read in the cmvd atom
+ uint32 compressedSize = _fd->readUint32BE() - 12;
+ if (_fd->readUint32BE() != MKID_BE('cmvd'))
+ return -1;
+ uint32 uncompressedSize = _fd->readUint32BE();
+
+ // Read in data
+ byte *compressedData = (byte *)malloc(compressedSize);
+ _fd->read(compressedData, compressedSize);
+
+ // Create uncompressed stream
+ byte *uncompressedData = (byte *)malloc(uncompressedSize);
+
+ // Uncompress the data
+ unsigned long dstLen = uncompressedSize;
+ if (!Common::uncompress(uncompressedData, &dstLen, compressedData, compressedSize)) {
+ warning ("Could not uncompress cmov chunk");
+ return -1;
+ }
+
+ // Load data into a new MemoryReadStream and assign _fd to be that
+ Common::SeekableReadStream *oldStream = _fd;
+ _fd = new Common::MemoryReadStream(uncompressedData, uncompressedSize, DisposeAfterUse::YES);
+
+ // Read the contents of the uncompressed data
+ MOVatom a = { MKID_BE('moov'), 0, uncompressedSize };
+ int err = readDefault(a);
+
+ // Assign the file handle back to the original handle
+ free(compressedData);
+ delete _fd;
+ _fd = oldStream;
+
+ return err;
+#else
+ warning ("zlib not found, cannot read QuickTime cmov atom");
+ return -1;
+#endif
+}
+
+int QTPlayer::readMVHD(MOVatom atom) {
+ byte version = _fd->readByte(); // version
+ _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
+
+ if (version == 1) {
+ warning("QuickTime version 1");
+ _fd->readUint32BE(); _fd->readUint32BE();
+ _fd->readUint32BE(); _fd->readUint32BE();
+ } else {
+ _fd->readUint32BE(); // creation time
+ _fd->readUint32BE(); // modification time
+ }
+
+ _timeScale = _fd->readUint32BE(); // time scale
+ debug(0, "time scale = %i\n", _timeScale);
+
+ // duration
+ _duration = (version == 1) ? (_fd->readUint32BE(), _fd->readUint32BE()) : _fd->readUint32BE();
+ _fd->readUint32BE(); // preferred scale
+
+ _fd->readUint16BE(); // preferred volume
+
+ _fd->seek(10, SEEK_CUR); // reserved
+
+ // We only need two values from the movie display matrix. Most of the values are just
+ // skipped. xMod and yMod are 16:16 fixed point numbers, the last part of the 3x3 matrix
+ // is 2:30.
+ uint32 xMod = _fd->readUint32BE();
+ _fd->skip(12);
+ uint32 yMod = _fd->readUint32BE();
+ _fd->skip(16);
+
+ if (xMod != yMod)
+ error("X and Y resolution modifiers differ");
+
+ if (xMod == 0x8000)
+ _scaleMode = kScaleHalf;
+ else if (xMod == 0x4000)
+ _scaleMode = kScaleQuarter;
+ else
+ _scaleMode = kScaleNormal;
+
+ debug(1, "readMVHD(): scaleMode = %d", (int)_scaleMode);
+
+ _fd->readUint32BE(); // preview time
+ _fd->readUint32BE(); // preview duration
+ _fd->readUint32BE(); // poster time
+ _fd->readUint32BE(); // selection time
+ _fd->readUint32BE(); // selection duration
+ _fd->readUint32BE(); // current time
+ _fd->readUint32BE(); // next track ID
+
+ return 0;
+}
+
+int QTPlayer::readTRAK(MOVatom atom) {
+ MOVStreamContext *sc = new MOVStreamContext();
+
+ if (!sc)
+ return -1;
+
+ sc->sample_to_chunk_index = -1;
+ sc->codec_type = CODEC_TYPE_MOV_OTHER;
+ sc->start_time = 0; // XXX: check
+ _streams[_numStreams++] = sc;
+
+ return readDefault(atom);
+}
+
+// this atom contains actual media data
+int QTPlayer::readMDAT(MOVatom atom) {
+ if (atom.size == 0) // wrong one (MP4)
+ return 0;
+
+ _foundMDAT = true;
+
+ _mdatOffset = atom.offset;
+ _mdatSize = atom.size;
+
+ if (_foundMOOV)
+ return 1; // found both, just go
+
+ _fd->seek(atom.size, SEEK_CUR);
+
+ return 0; // now go for moov
+}
+
+int QTPlayer::readTKHD(MOVatom atom) {
+ MOVStreamContext *st = _streams[_numStreams - 1];
+ byte version = _fd->readByte();
+
+ _fd->readByte(); _fd->readByte();
+ _fd->readByte(); // flags
+ //
+ //MOV_TRACK_ENABLED 0x0001
+ //MOV_TRACK_IN_MOVIE 0x0002
+ //MOV_TRACK_IN_PREVIEW 0x0004
+ //MOV_TRACK_IN_POSTER 0x0008
+ //
+
+ if (version == 1) {
+ _fd->readUint32BE(); _fd->readUint32BE();
+ _fd->readUint32BE(); _fd->readUint32BE();
+ } else {
+ _fd->readUint32BE(); // creation time
+ _fd->readUint32BE(); // modification time
+ }
+
+ /* st->id = */_fd->readUint32BE(); // track id (NOT 0 !)
+ _fd->readUint32BE(); // reserved
+ //st->start_time = 0; // check
+ (version == 1) ? (_fd->readUint32BE(), _fd->readUint32BE()) : _fd->readUint32BE(); // highlevel (considering edits) duration in movie timebase
+ _fd->readUint32BE(); // reserved
+ _fd->readUint32BE(); // reserved
+
+ _fd->readUint16BE(); // layer
+ _fd->readUint16BE(); // alternate group
+ _fd->readUint16BE(); // volume
+ _fd->readUint16BE(); // reserved
+
+ // We only need the two values from the displacement matrix for a track.
+ // See readMVHD() for more information.
+ uint32 xMod = _fd->readUint32BE();
+ _fd->skip(12);
+ uint32 yMod = _fd->readUint32BE();
+ _fd->skip(16);
+
+ if (xMod != yMod)
+ error("X and Y resolution modifiers differ");
+
+ if (xMod == 0x8000)
+ st->scaleMode = kScaleHalf;
+ else if (xMod == 0x4000)
+ st->scaleMode = kScaleQuarter;
+ else
+ st->scaleMode = kScaleNormal;
+
+ debug(1, "readTKHD(): scaleMode = %d", (int)_scaleMode);
+
+ // these are fixed-point, 16:16
+ // uint32 tkWidth = _fd->readUint32BE() >> 16; // track width
+ // uint32 tkHeight = _fd->readUint32BE() >> 16; // track height
+
+ return 0;
+}
+
+// edit list atom
+int QTPlayer::readELST(MOVatom atom) {
+ _fd->readByte(); // version
+ _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
+ uint32 editCount = _streams[_numStreams - 1]->edit_count = _fd->readUint32BE(); // entries
+
+ for (uint32 i = 0; i < editCount; i++){
+ _fd->readUint32BE(); // Track duration
+ _fd->readUint32BE(); // Media time
+ _fd->readUint32BE(); // Media rate
+ }
+
+ debug(0, "track[%i].edit_count = %i", _numStreams - 1, _streams[_numStreams - 1]->edit_count);
+
+ if (editCount != 1)
+ warning("Multiple edit list entries. Things may go awry");
+
+ return 0;
+}
+
+int QTPlayer::readHDLR(MOVatom atom) {
+ MOVStreamContext *st = _streams[_numStreams - 1];
+
+ _fd->readByte(); // version
+ _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
+
+ // component type
+ uint32 ctype = _fd->readUint32LE();
+ uint32 type = _fd->readUint32BE(); // component subtype
+
+ debug(0, "ctype= %s (0x%08lx)", tag2str(ctype), (long)ctype);
+ debug(0, "stype= %s", tag2str(type));
+
+ if(ctype == MKID_BE('mhlr')) // MOV
+ debug(0, "MOV detected");
+ else if(ctype == 0) {
+ warning("MP4 streams are not supported");
+ return -1;
+ }
+
+ if (type == MKID_BE('vide'))
+ st->codec_type = CODEC_TYPE_VIDEO;
+ else if (type == MKID_BE('soun'))
+ st->codec_type = CODEC_TYPE_AUDIO;
+
+ _fd->readUint32BE(); // component manufacture
+ _fd->readUint32BE(); // component flags
+ _fd->readUint32BE(); // component flags mask
+
+ if (atom.size <= 24)
+ return 0; // nothing left to read
+
+ // .mov: PASCAL string
+ byte len = _fd->readByte();
+ _fd->seek(len, SEEK_CUR);
+
+ _fd->seek(atom.size - (_fd->pos() - atom.offset), SEEK_CUR);
+
+ return 0;
+}
+
+int QTPlayer::readMDHD(MOVatom atom) {
+ MOVStreamContext *st = _streams[_numStreams - 1];
+ byte version = _fd->readByte();
+
+ if (version > 1)
+ return 1; // unsupported
+
+ _fd->readByte(); _fd->readByte();
+ _fd->readByte(); // flags
+
+ if (version == 1) {
+ _fd->readUint32BE(); _fd->readUint32BE();
+ _fd->readUint32BE(); _fd->readUint32BE();
+ } else {
+ _fd->readUint32BE(); // creation time
+ _fd->readUint32BE(); // modification time
+ }
+
+ st->time_scale = _fd->readUint32BE();
+ st->duration = (version == 1) ? (_fd->readUint32BE(), _fd->readUint32BE()) : _fd->readUint32BE(); // duration
+
+ _fd->readUint16BE(); // language
+ _fd->readUint16BE(); // quality
+
+ return 0;
+}
+
+int QTPlayer::readSTSD(MOVatom atom) {
+ MOVStreamContext *st = _streams[_numStreams - 1];
+
+ _fd->readByte(); // version
+ _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
+
+ uint32 entries = _fd->readUint32BE();
+
+ while (entries--) { //Parsing Sample description table
+ MOVatom a = { 0, 0, 0 };
+ uint32 start_pos = _fd->pos();
+ int size = _fd->readUint32BE(); // size
+ uint32 format = _fd->readUint32BE(); // data format
+
+ _fd->readUint32BE(); // reserved
+ _fd->readUint16BE(); // reserved
+ _fd->readUint16BE(); // index
+
+ debug(0, "size=%d 4CC= %s codec_type=%d", size, tag2str(format), st->codec_type);
+ st->codec_tag = format;
+
+ if (st->codec_type == CODEC_TYPE_VIDEO) {
+ debug(0, "Video Codec FourCC: \'%s\'", tag2str(format));
+
+ _fd->readUint16BE(); // version
+ _fd->readUint16BE(); // revision level
+ _fd->readUint32BE(); // vendor
+ _fd->readUint32BE(); // temporal quality
+ _fd->readUint32BE(); // spacial quality
+
+ st->width = _fd->readUint16BE(); // width
+ st->height = _fd->readUint16BE(); // height
+
+ _fd->readUint32BE(); // horiz resolution
+ _fd->readUint32BE(); // vert resolution
+ _fd->readUint32BE(); // data size, always 0
+ uint16 frames_per_sample = _fd->readUint16BE(); // frames per samples
+
+ debug(0, "frames/samples = %d", frames_per_sample);
+
+ byte codec_name[32];
+ _fd->read(codec_name, 32); // codec name, pascal string (FIXME: true for mp4?)
+ if (codec_name[0] <= 31) {
+ memcpy(st->codec_name, &codec_name[1], codec_name[0]);
+ st->codec_name[codec_name[0]] = 0;
+ }
+
+ st->bits_per_sample = _fd->readUint16BE(); // depth
+ st->color_table_id = _fd->readUint16BE(); // colortable id
+
+// These are set in mov_read_stts and might already be set!
+// st->codec->time_base.den = 25;
+// st->codec->time_base.num = 1;
+
+
+ // figure out the palette situation
+ byte colorDepth = st->bits_per_sample & 0x1F;
+ bool colorGreyscale = (st->bits_per_sample & 0x20) != 0;
+
+ debug(0, "color depth: %d", colorDepth);
+
+ // if the depth is 2, 4, or 8 bpp, file is palettized
+ if (colorDepth == 2 || colorDepth == 4 || colorDepth == 8) {
+ _dirtyPalette = true;
+
+ if (colorGreyscale) {
+ debug(0, "Greyscale palette");
+
+ // compute the greyscale palette
+ uint16 colorCount = 1 << colorDepth;
+ int16 colorIndex = 255;
+ byte colorDec = 256 / (colorCount - 1);
+ for (byte j = 0; j < colorCount; j++) {
+ _palette[j * 3] = _palette[j * 3 + 1] = _palette[j * 3 + 2] = colorIndex;
+ colorIndex -= colorDec;
+ if (colorIndex < 0)
+ colorIndex = 0;
+ }
+ } else if (st->color_table_id & 0x08) {
+ // if flag bit 3 is set, use the default palette
+ //uint16 colorCount = 1 << colorDepth;
+
+ warning("Predefined palette! %dbpp", colorDepth);
+#if 0
+ byte *color_table;
+ byte r, g, b;
+
+ if (colorDepth == 2)
+ color_table = ff_qt_default_palette_4;
+ else if (colorDepth == 4)
+ color_table = ff_qt_default_palette_16;
+ else
+ color_table = ff_qt_default_palette_256;
+
+ for (byte j = 0; j < color_count; j++) {
+ r = color_table[j * 4 + 0];
+ g = color_table[j * 4 + 1];
+ b = color_table[j * 4 + 2];
+ _palette_control.palette[j] = (r << 16) | (g << 8) | (b);
+ }
+#endif
+
+ } else {
+ debug(0, "Palette from file");
+
+ // load the palette from the file
+ uint32 colorStart = _fd->readUint32BE();
+ /* uint16 colorCount = */ _fd->readUint16BE();
+ uint16 colorEnd = _fd->readUint16BE();
+ for (uint32 j = colorStart; j <= colorEnd; j++) {
+ // each R, G, or B component is 16 bits;
+ // only use the top 8 bits; skip alpha bytes
+ // up front
+ _fd->readByte();
+ _fd->readByte();
+ _palette[j * 3] = _fd->readByte();
+ _fd->readByte();
+ _palette[j * 3 + 1] = _fd->readByte();
+ _fd->readByte();
+ _palette[j * 3 + 2] = _fd->readByte();
+ _fd->readByte();
+ }
+ }
+ st->palettized = true;
+ } else
+ st->palettized = false;
+ } else if (st->codec_type == CODEC_TYPE_AUDIO) {
+ debug(0, "Audio Codec FourCC: \'%s\'", tag2str(format));
+
+ st->stsd_version = _fd->readUint16BE();
+ _fd->readUint16BE(); // revision level
+ _fd->readUint32BE(); // vendor
+
+ st->channels = _fd->readUint16BE(); // channel count
+ st->bits_per_sample = _fd->readUint16BE(); // sample size
+ // do we need to force to 16 for AMR ?
+
+ // handle specific s8 codec
+ _fd->readUint16BE(); // compression id = 0
+ _fd->readUint16BE(); // packet size = 0
+
+ st->sample_rate = (_fd->readUint32BE() >> 16);
+
+ debug(0, "stsd version =%d", st->stsd_version);
+ if (st->stsd_version == 0) {
+ // Not used, except in special cases. See below.
+ st->samples_per_frame = st->bytes_per_frame = 0;
+ } else if (st->stsd_version == 1) {
+ // Read QT version 1 fields. In version 0 these dont exist.
+ st->samples_per_frame = _fd->readUint32BE();
+ debug(0, "stsd samples_per_frame =%d", st->samples_per_frame);
+ _fd->readUint32BE(); // bytes per packet
+ st->bytes_per_frame = _fd->readUint32BE();
+ debug(0, "stsd bytes_per_frame =%d", st->bytes_per_frame);
+ _fd->readUint32BE(); // bytes per sample
+ } else {
+ warning("Unsupported QuickTime STSD audio version %d", st->stsd_version);
+ return 1;
+ }
+
+ // Version 0 videos (such as the Riven ones) don't have this set,
+ // but we need it later on. Add it in here.
+ if (format == MKID_BE('ima4')) {
+ st->samples_per_frame = 64;
+ st->bytes_per_frame = 34 * st->channels;
+ }
+ } else {
+ // other codec type, just skip (rtp, mp4s, tmcd ...)
+ _fd->seek(size - (_fd->pos() - start_pos), SEEK_CUR);
+ }
+
+ // this will read extra atoms at the end (wave, alac, damr, avcC, SMI ...)
+ a.size = size - (_fd->pos() - start_pos);
+ if (a.size > 8)
+ readDefault(a);
+ else if (a.size > 0)
+ _fd->seek(a.size, SEEK_CUR);
+ }
+
+ if (st->codec_type == CODEC_TYPE_AUDIO && st->sample_rate == 0 && st->time_scale > 1)
+ st->sample_rate= st->time_scale;
+
+ return 0;
+}
+
+int QTPlayer::readSTSC(MOVatom atom) {
+ MOVStreamContext *st = _streams[_numStreams - 1];
+
+ _fd->readByte(); // version
+ _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
+
+ st->sample_to_chunk_sz = _fd->readUint32BE();
+
+ debug(0, "track[%i].stsc.entries = %i", _numStreams - 1, st->sample_to_chunk_sz);
+
+ st->sample_to_chunk = new MOVstsc[st->sample_to_chunk_sz];
+
+ if (!st->sample_to_chunk)
+ return -1;
+
+ for (uint32 i = 0; i < st->sample_to_chunk_sz; i++) {
+ st->sample_to_chunk[i].first = _fd->readUint32BE();
+ st->sample_to_chunk[i].count = _fd->readUint32BE();
+ st->sample_to_chunk[i].id = _fd->readUint32BE();
+ //printf ("Sample to Chunk[%d]: First = %d, Count = %d\n", i, st->sample_to_chunk[i].first, st->sample_to_chunk[i].count);
+ }
+
+ return 0;
+}
+
+int QTPlayer::readSTSS(MOVatom atom) {
+ MOVStreamContext *st = _streams[_numStreams - 1];
+
+ _fd->readByte(); // version
+ _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
+
+ st->keyframe_count = _fd->readUint32BE();
+
+ debug(0, "keyframe_count = %d", st->keyframe_count);
+
+ st->keyframes = new uint32[st->keyframe_count];
+
+ if (!st->keyframes)
+ return -1;
+
+ for (uint32 i = 0; i < st->keyframe_count; i++) {
+ st->keyframes[i] = _fd->readUint32BE();
+ debug(6, "keyframes[%d] = %d", i, st->keyframes[i]);
+
+ }
+ return 0;
+}
+
+int QTPlayer::readSTSZ(MOVatom atom) {
+ MOVStreamContext *st = _streams[_numStreams - 1];
+
+ _fd->readByte(); // version
+ _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
+
+ st->sample_size = _fd->readUint32BE();
+ st->sample_count = _fd->readUint32BE();
+
+ debug(5, "sample_size = %d sample_count = %d", st->sample_size, st->sample_count);
+
+ if (st->sample_size)
+ return 0; // there isn't any table following
+
+ st->sample_sizes = new uint32[st->sample_count];
+
+ if (!st->sample_sizes)
+ return -1;
+
+ for(uint32 i = 0; i < st->sample_count; i++) {
+ st->sample_sizes[i] = _fd->readUint32BE();
+ debug(6, "sample_sizes[%d] = %d", i, st->sample_sizes[i]);
+ }
+
+ return 0;
+}
+
+static uint32 ff_gcd(uint32 a, uint32 b) {
+ if(b) return ff_gcd(b, a%b);
+ else return a;
+}
+
+int QTPlayer::readSTTS(MOVatom atom) {
+ MOVStreamContext *st = _streams[_numStreams - 1];
+ uint32 duration = 0;
+ uint32 total_sample_count = 0;
+
+ _fd->readByte(); // version
+ _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
+
+ st->stts_count = _fd->readUint32BE();
+ st->stts_data = new MOVstts[st->stts_count];
+
+ debug(0, "track[%i].stts.entries = %i", _numStreams - 1, st->stts_count);
+
+ st->time_rate = 0;
+
+ for (int32 i = 0; i < st->stts_count; i++) {
+ int sample_duration;
+ int sample_count;
+
+ sample_count = _fd->readUint32BE();
+ sample_duration = _fd->readUint32BE();
+ st->stts_data[i].count = sample_count;
+ st->stts_data[i].duration = sample_duration;
+
+ st->time_rate = ff_gcd(st->time_rate, sample_duration);
+
+ debug(0, "sample_count=%d, sample_duration=%d", sample_count, sample_duration);
+
+ duration += sample_duration * sample_count;
+ total_sample_count += sample_count;
+ }
+
+ st->nb_frames = total_sample_count;
+
+ if (duration)
+ st->duration = duration;
+
+ return 0;
+}
+
+int QTPlayer::readSTCO(MOVatom atom) {
+ MOVStreamContext *st = _streams[_numStreams - 1];
+
+ _fd->readByte(); // version
+ _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
+
+ st->chunk_count = _fd->readUint32BE();
+ st->chunk_offsets = new uint32[st->chunk_count];
+
+ if (!st->chunk_offsets)
+ return -1;
+
+ for (uint32 i = 0; i < st->chunk_count; i++) {
+ // WORKAROUND/HACK: The offsets in Riven videos (ones inside the Mohawk archives themselves)
+ // have offsets relative to the archive and not the video. This is quite nasty. We subtract
+ // the initial offset of the stream to get the correct value inside of the stream.
+ st->chunk_offsets[i] = _fd->readUint32BE() - _beginOffset;
+ }
+
+ for (uint32 i = 0; i < _numStreams; i++) {
+ MOVStreamContext *sc2 = _streams[i];
+
+ if(sc2 && sc2->chunk_offsets){
+ uint32 first = sc2->chunk_offsets[0];
+ uint32 last = sc2->chunk_offsets[sc2->chunk_count - 1];
+
+ if(first >= st->chunk_offsets[st->chunk_count - 1] || last <= st->chunk_offsets[0])
+ _ni = 1;
+ }
+ }
+
+ return 0;
+}
+
+int QTPlayer::readWAVE(MOVatom atom) {
+ if (_numStreams < 1)
+ return 0;
+
+ MOVStreamContext *st = _streams[_numStreams - 1];
+
+ if (atom.size > (1 << 30))
+ return -1;
+
+ if (st->codec_tag == MKID_BE('QDM2')) // Read extradata for QDM2
+ st->extradata = _fd->readStream(atom.size - 8);
+ else if (atom.size > 8)
+ return readDefault(atom);
+ else
+ _fd->skip(atom.size);
+
+ return 0;
+}
+
+void QTPlayer::close() {
+ stopAudio();
+
+ delete _videoCodec; _videoCodec = 0;
+
+ for (uint32 i = 0; i < _numStreams; i++)
+ delete _streams[i];
+
+ delete _fd;
+
+ if (_scaledSurface) {
+ _scaledSurface->free();
+ delete _scaledSurface;
+ _scaledSurface = 0;
+ }
+
+ // The audio stream is deleted automatically
+ _audStream = NULL;
+
+ Graphics::VideoDecoder::reset();
+}
+
+Common::SeekableReadStream *QTPlayer::getNextFramePacket() {
+ if (_videoStreamIndex < 0)
+ return NULL;
+
+ // First, we have to track down which chunk holds the sample and which sample in the chunk contains the frame we are looking for.
+ int32 totalSampleCount = 0;
+ int32 sampleInChunk = 0;
+ int32 actualChunk = -1;
+
+ for (uint32 i = 0; i < _streams[_videoStreamIndex]->chunk_count; i++) {
+ int32 sampleToChunkIndex = -1;
+
+ for (uint32 j = 0; j < _streams[_videoStreamIndex]->sample_to_chunk_sz; j++)
+ if (i >= _streams[_videoStreamIndex]->sample_to_chunk[j].first - 1)
+ sampleToChunkIndex = j;
+
+ if (sampleToChunkIndex < 0)
+ error("This chunk (%d) is imaginary", sampleToChunkIndex);
+
+ totalSampleCount += _streams[_videoStreamIndex]->sample_to_chunk[sampleToChunkIndex].count;
+
+ if (totalSampleCount > getCurFrame()) {
+ actualChunk = i;
+ sampleInChunk = _streams[_videoStreamIndex]->sample_to_chunk[sampleToChunkIndex].count - totalSampleCount + getCurFrame();
+ break;
+ }
+ }
+
+ if (actualChunk < 0) {
+ warning ("Could not find data for frame %d", getCurFrame());
+ return NULL;
+ }
+
+ // Next seek to that frame
+ _fd->seek(_streams[_videoStreamIndex]->chunk_offsets[actualChunk]);
+
+ // Then, if the chunk holds more than one frame, seek to where the frame we want is located
+ for (int32 i = getCurFrame() - sampleInChunk; i < getCurFrame(); i++) {
+ if (_streams[_videoStreamIndex]->sample_size != 0)
+ _fd->skip(_streams[_videoStreamIndex]->sample_size);
+ else
+ _fd->skip(_streams[_videoStreamIndex]->sample_sizes[i]);
+ }
+
+ // Finally, read in the raw data for the frame
+ //printf ("Frame Data[%d]: Offset = %d, Size = %d\n", getCurFrame(), _fd->pos(), _streams[_videoStreamIndex]->sample_sizes[getCurFrame()]);
+
+ if (_streams[_videoStreamIndex]->sample_size != 0)
+ return _fd->readStream(_streams[_videoStreamIndex]->sample_size);
+
+ return _fd->readStream(_streams[_videoStreamIndex]->sample_sizes[getCurFrame()]);
+}
+
+bool QTPlayer::checkAudioCodecSupport(uint32 tag) {
+ // Check if the codec is a supported codec
+ if (tag == MKID_BE('twos') || tag == MKID_BE('raw ') || tag == MKID_BE('ima4') || tag == MKID_BE('QDM2'))
+ return true;
+
+ warning("Audio Codec Not Supported: \'%s\'", tag2str(tag));
+
+ return false;
+}
+
+Audio::AudioStream *QTPlayer::createAudioStream(Common::SeekableReadStream *stream) {
+ if (!stream || _audioStreamIndex < 0)
+ return NULL;
+
+ if (_streams[_audioStreamIndex]->codec_tag == MKID_BE('twos') || _streams[_audioStreamIndex]->codec_tag == MKID_BE('raw ')) {
+ // Fortunately, most of the audio used in Myst videos is raw...
+ uint16 flags = 0;
+ if (_streams[_audioStreamIndex]->codec_tag == MKID_BE('raw '))
+ flags |= Audio::FLAG_UNSIGNED;
+ if (_streams[_audioStreamIndex]->channels == 2)
+ flags |= Audio::FLAG_STEREO;
+ if (_streams[_audioStreamIndex]->bits_per_sample == 16)
+ flags |= Audio::FLAG_16BITS;
+ uint32 dataSize = stream->size();
+ byte *data = (byte *)malloc(dataSize);
+ stream->read(data, dataSize);
+ delete stream;
+ return Audio::makeRawStream(data, dataSize, _streams[_audioStreamIndex]->sample_rate, flags);
+ } else if (_streams[_audioStreamIndex]->codec_tag == MKID_BE('ima4')) {
+ // Riven uses this codec (as do some Myst ME videos)
+ return Audio::makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), Audio::kADPCMApple, _streams[_audioStreamIndex]->sample_rate, _streams[_audioStreamIndex]->channels, 34);
+ } else if (_streams[_audioStreamIndex]->codec_tag == MKID_BE('QDM2')) {
+ // Several Myst ME videos use this codec
+ return new QDM2Stream(stream, _streams[_audioStreamIndex]->extradata);
+ }
+
+ error("Unsupported audio codec");
+
+ return NULL;
+}
+
+void QTPlayer::updateAudioBuffer() {
+ if (!_audStream)
+ return;
+
+ // Keep two streams in buffer so that when the first ends, it goes right into the next
+ for (; _audStream->numQueuedStreams() < 2 && _curAudioChunk < _streams[_audioStreamIndex]->chunk_count; _curAudioChunk++) {
+ Common::MemoryWriteStreamDynamic *wStream = new Common::MemoryWriteStreamDynamic();
+
+ _fd->seek(_streams[_audioStreamIndex]->chunk_offsets[_curAudioChunk]);
+
+ // First, we have to get the sample count
+ uint32 sampleCount = 0;
+ for (uint32 j = 0; j < _streams[_audioStreamIndex]->sample_to_chunk_sz; j++)
+ if (_curAudioChunk >= (_streams[_audioStreamIndex]->sample_to_chunk[j].first - 1))
+ sampleCount = _streams[_audioStreamIndex]->sample_to_chunk[j].count;
+ assert(sampleCount);
+
+ // Then calculate the right sizes
+ while (sampleCount > 0) {
+ uint32 samples = 0, size = 0;
+
+ if (_streams[_audioStreamIndex]->samples_per_frame >= 160) {
+ samples = _streams[_audioStreamIndex]->samples_per_frame;
+ size = _streams[_audioStreamIndex]->bytes_per_frame;
+ } else if (_streams[_audioStreamIndex]->samples_per_frame > 1) {
+ samples = MIN<uint32>((1024 / _streams[_audioStreamIndex]->samples_per_frame) * _streams[_audioStreamIndex]->samples_per_frame, sampleCount);
+ size = (samples / _streams[_audioStreamIndex]->samples_per_frame) * _streams[_audioStreamIndex]->bytes_per_frame;
+ } else {
+ samples = MIN<uint32>(1024, sampleCount);
+ size = samples * _streams[_audioStreamIndex]->sample_size;
+ }
+
+ // Now, we read in the data for this data and output it
+ byte *data = (byte *)malloc(size);
+ _fd->read(data, size);
+ wStream->write(data, size);
+ free(data);
+ sampleCount -= samples;
+ }
+
+ // Now queue the buffer
+ _audStream->queueAudioStream(createAudioStream(new Common::MemoryReadStream(wStream->getData(), wStream->size(), DisposeAfterUse::YES)));
+ delete wStream;
+ }
+}
+
+} // End of namespace Mohawk
diff --git a/engines/mohawk/video/qt_player.h b/engines/mohawk/video/qt_player.h
new file mode 100644
index 0000000000..6657d3edba
--- /dev/null
+++ b/engines/mohawk/video/qt_player.h
@@ -0,0 +1,282 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+//
+// Heavily based on ffmpeg code.
+//
+// Copyright (c) 2001 Fabrice Bellard.
+// First version by Francois Revol revol@free.fr
+// Seek function by Gael Chardon gael.dev@4now.net
+//
+
+#ifndef MOHAWK_QT_PLAYER_H
+#define MOHAWK_QT_PLAYER_H
+
+#include "common/scummsys.h"
+#include "common/queue.h"
+
+#include "graphics/video/video_decoder.h"
+#include "graphics/video/codecs/codec.h"
+
+#include "sound/audiostream.h"
+#include "sound/mixer.h"
+
+namespace Common {
+ class File;
+}
+
+namespace Mohawk {
+
+enum ScaleMode {
+ kScaleNormal = 1,
+ kScaleHalf = 2,
+ kScaleQuarter = 4
+};
+
+class QTPlayer : public Graphics::RewindableVideoDecoder {
+public:
+ QTPlayer();
+ virtual ~QTPlayer();
+
+ /**
+ * Returns the width of the video
+ * @return the width of the video
+ */
+ uint16 getWidth() const;
+
+ /**
+ * Returns the height of the video
+ * @return the height of the video
+ */
+ uint16 getHeight() const;
+
+ /**
+ * Returns the amount of frames in the video
+ * @return the amount of frames in the video
+ */
+ uint32 getFrameCount() const;
+
+ /**
+ * Load a QuickTime video file from a SeekableReadStream
+ * @param stream the stream to load
+ */
+ bool load(Common::SeekableReadStream &stream);
+
+ /**
+ * Close a QuickTime encoded video file
+ */
+ void close();
+
+ /**
+ * Returns the palette of the video
+ * @return the palette of the video
+ */
+ byte *getPalette() { _dirtyPalette = false; return _palette; }
+ bool hasDirtyPalette() const { return _dirtyPalette; }
+
+ /**
+ * Set the beginning offset of the video so we can modify the offsets in the stco
+ * atom of videos inside the Mohawk archives
+ * @param the beginning offset of the video
+ */
+ void setChunkBeginOffset(uint32 offset) { _beginOffset = offset; }
+
+ bool isVideoLoaded() const { return _fd != 0; }
+ Graphics::Surface *decodeNextFrame();
+ bool needsUpdate() const;
+ bool endOfVideo() const;
+ uint32 getElapsedTime() const;
+ uint32 getTimeToNextFrame() const;
+ Graphics::PixelFormat getPixelFormat() const;
+
+ // RewindableVideoDecoder API
+ void rewind();
+
+ // TODO: This audio function need to be removed from the public and/or added to
+ // the VideoDecoder API directly. I plan on replacing this function with something
+ // that can figure out how much audio is needed instead of constantly keeping two
+ // chunks in memory.
+ void updateAudioBuffer();
+
+protected:
+ // This is the file handle from which data is read from. It can be the actual file handle or a decompressed stream.
+ Common::SeekableReadStream *_fd;
+
+ struct MOVatom {
+ uint32 type;
+ uint32 offset;
+ uint32 size;
+ };
+
+ struct ParseTable {
+ uint32 type;
+ int (QTPlayer::*func)(MOVatom atom);
+ };
+
+ struct MOVstts {
+ int count;
+ int duration;
+ };
+
+ struct MOVstsc {
+ uint32 first;
+ uint32 count;
+ uint32 id;
+ };
+
+ enum CodecType {
+ CODEC_TYPE_MOV_OTHER,
+ CODEC_TYPE_VIDEO,
+ CODEC_TYPE_AUDIO
+ };
+
+ struct MOVStreamContext {
+ MOVStreamContext() { memset(this, 0, sizeof(MOVStreamContext)); }
+ ~MOVStreamContext() {
+ delete[] chunk_offsets;
+ delete[] stts_data;
+ delete[] ctts_data;
+ delete[] sample_to_chunk;
+ delete[] sample_sizes;
+ delete[] keyframes;
+ delete extradata;
+ }
+
+ int ffindex; /* the ffmpeg stream id */
+ int is_ff_stream; /* Is this stream presented to ffmpeg ? i.e. is this an audio or video stream ? */
+ uint32 next_chunk;
+ uint32 chunk_count;
+ uint32 *chunk_offsets;
+ int stts_count;
+ MOVstts *stts_data;
+ int ctts_count;
+ MOVstts *ctts_data;
+ int edit_count; /* number of 'edit' (elst atom) */
+ uint32 sample_to_chunk_sz;
+ MOVstsc *sample_to_chunk;
+ int32 sample_to_chunk_index;
+ int sample_to_time_index;
+ uint32 sample_to_time_sample;
+ uint32 sample_to_time_time;
+ int sample_to_ctime_index;
+ int sample_to_ctime_sample;
+ uint32 sample_size;
+ uint32 sample_count;
+ uint32 *sample_sizes;
+ uint32 keyframe_count;
+ uint32 *keyframes;
+ int32 time_scale;
+ int time_rate;
+ uint32 current_sample;
+ uint32 left_in_chunk; /* how many samples before next chunk */
+
+ uint16 width;
+ uint16 height;
+ int codec_type;
+ uint32 codec_tag;
+ char codec_name[32];
+ uint16 bits_per_sample;
+ uint16 color_table_id;
+ bool palettized;
+ Common::SeekableReadStream *extradata;
+
+ uint16 stsd_version;
+ uint16 channels;
+ uint16 sample_rate;
+ uint32 samples_per_frame;
+ uint32 bytes_per_frame;
+
+ uint32 nb_frames;
+ uint32 duration;
+ uint32 start_time;
+ ScaleMode scaleMode;
+ };
+
+ const ParseTable *_parseTable;
+ bool _foundMOOV;
+ bool _foundMDAT;
+ uint32 _timeScale;
+ uint32 _duration;
+ uint32 _mdatOffset;
+ uint32 _mdatSize;
+ uint32 _next_chunk_offset;
+ MOVStreamContext *_partial;
+ uint32 _numStreams;
+ int _ni;
+ ScaleMode _scaleMode;
+ MOVStreamContext *_streams[20];
+ byte _palette[256 * 3];
+ bool _dirtyPalette;
+ uint32 _beginOffset;
+
+ void initParseTable();
+ Audio::AudioStream *createAudioStream(Common::SeekableReadStream *stream);
+ bool checkAudioCodecSupport(uint32 tag);
+ Common::SeekableReadStream *getNextFramePacket();
+ uint32 getFrameDuration();
+ uint32 getCodecTag();
+ byte getBitsPerPixel();
+
+ Audio::QueuingAudioStream *_audStream;
+ void startAudio();
+ void stopAudio();
+ int8 _audioStreamIndex;
+ uint _curAudioChunk;
+ Audio::SoundHandle _audHandle;
+
+ Graphics::Codec *createCodec(uint32 codecTag, byte bitsPerPixel);
+ Graphics::Codec *_videoCodec;
+ uint32 _nextFrameStartTime;
+ int8 _videoStreamIndex;
+
+ Graphics::Surface *_scaledSurface;
+ Graphics::Surface *scaleSurface(Graphics::Surface *frame);
+ ScaleMode getScaleMode() const;
+
+ void pauseVideoIntern(bool pause);
+
+ int readDefault(MOVatom atom);
+ int readLeaf(MOVatom atom);
+ int readELST(MOVatom atom);
+ int readHDLR(MOVatom atom);
+ int readMDAT(MOVatom atom);
+ int readMDHD(MOVatom atom);
+ int readMOOV(MOVatom atom);
+ int readMVHD(MOVatom atom);
+ int readTKHD(MOVatom atom);
+ int readTRAK(MOVatom atom);
+ int readSTCO(MOVatom atom);
+ int readSTSC(MOVatom atom);
+ int readSTSD(MOVatom atom);
+ int readSTSS(MOVatom atom);
+ int readSTSZ(MOVatom atom);
+ int readSTTS(MOVatom atom);
+ int readCMOV(MOVatom atom);
+ int readWAVE(MOVatom atom);
+};
+
+} // End of namespace Mohawk
+
+#endif
diff --git a/engines/mohawk/video/qtrle.cpp b/engines/mohawk/video/qtrle.cpp
new file mode 100644
index 0000000000..c06dbefcb3
--- /dev/null
+++ b/engines/mohawk/video/qtrle.cpp
@@ -0,0 +1,420 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+// QuickTime RLE Decoder
+// Based off ffmpeg's QuickTime RLE decoder (written by Mike Melanson)
+
+#include "mohawk/video/qtrle.h"
+
+#include "common/scummsys.h"
+#include "common/stream.h"
+#include "common/system.h"
+#include "graphics/colormasks.h"
+#include "graphics/surface.h"
+
+namespace Mohawk {
+
+QTRLEDecoder::QTRLEDecoder(uint16 width, uint16 height, byte bitsPerPixel) : Graphics::Codec() {
+ _bitsPerPixel = bitsPerPixel;
+ _pixelFormat = g_system->getScreenFormat();
+
+ // We need to increase the surface size to a multiple of 4
+ uint16 wMod = width % 4;
+ if(wMod != 0)
+ width += 4 - wMod;
+
+ debug(2, "QTRLE corrected width: %d", width);
+
+ _surface = new Graphics::Surface();
+ _surface->create(width, height, _bitsPerPixel <= 8 ? 1 : _pixelFormat.bytesPerPixel);
+}
+
+#define CHECK_STREAM_PTR(n) \
+ if ((stream->pos() + n) > stream->size()) { \
+ warning ("Problem: stream out of bounds (%d >= %d)", stream->pos() + n, stream->size()); \
+ return; \
+ }
+
+#define CHECK_PIXEL_PTR(n) \
+ if ((int32)pixelPtr + n > _surface->w * _surface->h) { \
+ warning ("Problem: pixel ptr = %d, pixel limit = %d", pixelPtr + n, _surface->w * _surface->h); \
+ return; \
+ } \
+
+void QTRLEDecoder::decode1(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) {
+ uint32 pixelPtr = 0;
+ byte *rgb = (byte *)_surface->pixels;
+
+ while (linesToChange) {
+ CHECK_STREAM_PTR(2);
+ byte skip = stream->readByte();
+ int8 rleCode = stream->readSByte();
+
+ if (rleCode == 0)
+ break;
+
+ if (skip & 0x80) {
+ linesToChange--;
+ rowPtr += _surface->w;
+ pixelPtr = rowPtr + 2 * (skip & 0x7f);
+ } else
+ pixelPtr += 2 * skip;
+
+ if (rleCode < 0) {
+ // decode the run length code
+ rleCode = -rleCode;
+ // get the next 2 bytes from the stream, treat them as groups of 8 pixels, and output them rleCode times */
+ CHECK_STREAM_PTR(2);
+ byte pi0 = stream->readByte();
+ byte pi1 = stream->readByte();
+ CHECK_PIXEL_PTR(rleCode * 2);
+
+ while (rleCode--) {
+ rgb[pixelPtr++] = pi0;
+ rgb[pixelPtr++] = pi1;
+ }
+ } else {
+ // copy the same pixel directly to output 2 times
+ rleCode *= 2;
+ CHECK_STREAM_PTR(rleCode);
+ CHECK_PIXEL_PTR(rleCode);
+
+ while (rleCode--)
+ rgb[pixelPtr++] = stream->readByte();
+ }
+ }
+}
+
+void QTRLEDecoder::decode2_4(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange, byte bpp) {
+ uint32 pixelPtr = 0;
+ byte *rgb = (byte *)_surface->pixels;
+ byte numPixels = (bpp == 4) ? 8 : 16;
+
+ while (linesToChange--) {
+ CHECK_STREAM_PTR(2);
+ pixelPtr = rowPtr + (numPixels * (stream->readByte() - 1));
+
+ for (int8 rleCode = stream->readSByte(); rleCode != -1; rleCode = stream->readSByte()) {
+ if (rleCode == 0) {
+ // there's another skip code in the stream
+ CHECK_STREAM_PTR(1);
+ pixelPtr += (numPixels * (stream->readByte() - 1));
+ } else if (rleCode < 0) {
+ // decode the run length code
+ rleCode = -rleCode;
+
+ // get the next 4 bytes from the stream, treat them as palette indices, and output them rleCode times */
+ CHECK_STREAM_PTR(4);
+
+ byte pi[16]; // 16 palette indices
+
+ for (int8 i = numPixels - 1; i >= 0; i--) {
+ pi[numPixels - 1 - i] = (stream->readByte() >> ((i * bpp) & 0x07)) & ((1 << bpp) - 1);
+
+ // FIXME: Is this right?
+ //stream_ptr += ((i & ((num_pixels>>2)-1)) == 0);
+ if ((i & ((numPixels >> 2) - 1)) == 0)
+ stream->readByte();
+ }
+
+ CHECK_PIXEL_PTR(rleCode * numPixels);
+
+ while (rleCode--)
+ for (byte i = 0; i < numPixels; i++)
+ rgb[pixelPtr++] = pi[i];
+ } else {
+ // copy the same pixel directly to output 4 times
+ rleCode *= 4;
+ CHECK_STREAM_PTR(rleCode);
+ CHECK_PIXEL_PTR(rleCode * (numPixels >> 2));
+
+ while (rleCode--) {
+ byte temp = stream->readByte();
+ if (bpp == 4) {
+ rgb[pixelPtr++] = (temp >> 4) & 0x0f;
+ rgb[pixelPtr++] = temp & 0x0f;
+ } else {
+ rgb[pixelPtr++] = (temp >> 6) & 0x03;
+ rgb[pixelPtr++] = (temp >> 4) & 0x03;
+ rgb[pixelPtr++] = (temp >> 2) & 0x03;
+ rgb[pixelPtr++] = temp & 0x03;
+ }
+ }
+ }
+ }
+
+ rowPtr += _surface->w;
+ }
+}
+
+void QTRLEDecoder::decode8(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) {
+ uint32 pixelPtr = 0;
+ byte *rgb = (byte *)_surface->pixels;
+
+ while (linesToChange--) {
+ CHECK_STREAM_PTR(2);
+ pixelPtr = rowPtr + 4 * (stream->readByte() - 1);
+
+ for (int8 rleCode = stream->readSByte(); rleCode != -1; rleCode = stream->readSByte()) {
+ if (rleCode == 0) {
+ // there's another skip code in the stream
+ CHECK_STREAM_PTR(1);
+ pixelPtr += 4 * (stream->readByte() - 1);
+ } else if (rleCode < 0) {
+ // decode the run length code
+ rleCode = -rleCode;
+
+ // get the next 4 bytes from the stream, treat them as palette indices, and output them rleCode times
+ CHECK_STREAM_PTR(4);
+
+ byte pi[4]; // 4 palette indexes
+
+ for (byte i = 0; i < 4; i++)
+ pi[i] = stream->readByte();
+
+ CHECK_PIXEL_PTR(rleCode * 4);
+
+ while (rleCode--)
+ for (byte i = 0; i < 4; i++)
+ rgb[pixelPtr++] = pi[i];
+ } else {
+ // copy the same pixel directly to output 4 times
+ rleCode *= 4;
+ CHECK_STREAM_PTR(rleCode);
+ CHECK_PIXEL_PTR(rleCode);
+
+ while (rleCode--)
+ rgb[pixelPtr++] = stream->readByte();
+ }
+ }
+
+ rowPtr += _surface->w;
+ }
+}
+
+void QTRLEDecoder::decode16(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) {
+ uint32 pixelPtr = 0;
+ OverlayColor *rgb = (OverlayColor *)_surface->pixels;
+
+ while (linesToChange--) {
+ CHECK_STREAM_PTR(2);
+ pixelPtr = rowPtr + stream->readByte() - 1;
+
+ for (int8 rleCode = stream->readSByte(); rleCode != -1; rleCode = stream->readSByte()) {
+ if (rleCode == 0) {
+ // there's another skip code in the stream
+ CHECK_STREAM_PTR(1);
+ pixelPtr += stream->readByte() - 1;
+ } else if (rleCode < 0) {
+ // decode the run length code
+ rleCode = -rleCode;
+ CHECK_STREAM_PTR(2);
+
+ uint16 rgb16 = stream->readUint16BE();
+
+ CHECK_PIXEL_PTR(rleCode);
+
+ while (rleCode--) {
+ // Convert from RGB555 to the format specified by the Overlay
+ byte r = 0, g = 0, b = 0;
+ Graphics::colorToRGB<Graphics::ColorMasks<555> >(rgb16, r, g, b);
+ rgb[pixelPtr++] = _pixelFormat.RGBToColor(r, g, b);
+ }
+ } else {
+ CHECK_STREAM_PTR(rleCode * 2);
+ CHECK_PIXEL_PTR(rleCode);
+
+ // copy pixels directly to output
+ while (rleCode--) {
+ uint16 rgb16 = stream->readUint16BE();
+
+ // Convert from RGB555 to the format specified by the Overlay
+ byte r = 0, g = 0, b = 0;
+ Graphics::colorToRGB<Graphics::ColorMasks<555> >(rgb16, r, g, b);
+ rgb[pixelPtr++] = _pixelFormat.RGBToColor(r, g, b);
+ }
+ }
+ }
+
+ rowPtr += _surface->w;
+ }
+}
+
+void QTRLEDecoder::decode24(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) {
+ uint32 pixelPtr = 0;
+ OverlayColor *rgb = (OverlayColor *)_surface->pixels;
+
+ while (linesToChange--) {
+ CHECK_STREAM_PTR(2);
+ pixelPtr = rowPtr + stream->readByte() - 1;
+
+ for (int8 rleCode = stream->readSByte(); rleCode != -1; rleCode = stream->readSByte()) {
+ if (rleCode == 0) {
+ // there's another skip code in the stream
+ CHECK_STREAM_PTR(1);
+ pixelPtr += stream->readByte() - 1;
+ } else if (rleCode < 0) {
+ // decode the run length code
+ rleCode = -rleCode;
+
+ CHECK_STREAM_PTR(3);
+
+ byte r = stream->readByte();
+ byte g = stream->readByte();
+ byte b = stream->readByte();
+
+ CHECK_PIXEL_PTR(rleCode);
+
+ while (rleCode--)
+ rgb[pixelPtr++] = _pixelFormat.RGBToColor(r, g, b);
+ } else {
+ CHECK_STREAM_PTR(rleCode * 3);
+ CHECK_PIXEL_PTR(rleCode);
+
+ // copy pixels directly to output
+ while (rleCode--) {
+ byte r = stream->readByte();
+ byte g = stream->readByte();
+ byte b = stream->readByte();
+ rgb[pixelPtr++] = _pixelFormat.RGBToColor(r, g, b);
+ }
+ }
+ }
+
+ rowPtr += _surface->w;
+ }
+}
+
+void QTRLEDecoder::decode32(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) {
+ uint32 pixelPtr = 0;
+ OverlayColor *rgb = (OverlayColor *)_surface->pixels;
+
+ while (linesToChange--) {
+ CHECK_STREAM_PTR(2);
+ pixelPtr = rowPtr + stream->readByte() - 1;
+
+ for (int8 rleCode = stream->readSByte(); rleCode != -1; rleCode = stream->readSByte()) {
+ if (rleCode == 0) {
+ // there's another skip code in the stream
+ CHECK_STREAM_PTR(1);
+ pixelPtr += stream->readByte() - 1;
+ } else if (rleCode < 0) {
+ // decode the run length code
+ rleCode = -rleCode;
+
+ CHECK_STREAM_PTR(4);
+
+ byte a = stream->readByte();
+ byte r = stream->readByte();
+ byte g = stream->readByte();
+ byte b = stream->readByte();
+
+ CHECK_PIXEL_PTR(rleCode);
+
+ while (rleCode--)
+ rgb[pixelPtr++] = _pixelFormat.ARGBToColor(a, r, g, b);
+ } else {
+ CHECK_STREAM_PTR(rleCode * 4);
+ CHECK_PIXEL_PTR(rleCode);
+
+ // copy pixels directly to output
+ while (rleCode--) {
+ byte a = stream->readByte();
+ byte r = stream->readByte();
+ byte g = stream->readByte();
+ byte b = stream->readByte();
+ rgb[pixelPtr++] = _pixelFormat.ARGBToColor(a, r, g, b);
+ }
+ }
+ }
+
+ rowPtr += _surface->w;
+ }
+}
+
+Graphics::Surface *QTRLEDecoder::decodeImage(Common::SeekableReadStream *stream) {
+ uint16 start_line = 0;
+ uint16 height = _surface->h;
+
+ // check if this frame is even supposed to change
+ if (stream->size() < 8)
+ return _surface;
+
+ // start after the chunk size
+ stream->readUint32BE();
+
+ // fetch the header
+ uint16 header = stream->readUint16BE();
+
+ // if a header is present, fetch additional decoding parameters
+ if (header & 8) {
+ if(stream->size() < 14)
+ return _surface;
+ start_line = stream->readUint16BE();
+ stream->readUint16BE(); // Unknown
+ height = stream->readUint16BE();
+ stream->readUint16BE(); // Unknown
+ }
+
+ uint32 row_ptr = _surface->w * start_line;
+
+ switch (_bitsPerPixel) {
+ case 1:
+ case 33:
+ decode1(stream, row_ptr, height);
+ break;
+ case 2:
+ case 34:
+ decode2_4(stream, row_ptr, height, 2);
+ break;
+ case 4:
+ case 36:
+ decode2_4(stream, row_ptr, height, 4);
+ break;
+ case 8:
+ case 40:
+ decode8(stream, row_ptr, height);
+ break;
+ case 16:
+ decode16(stream, row_ptr, height);
+ break;
+ case 24:
+ decode24(stream, row_ptr, height);
+ break;
+ case 32:
+ decode32(stream, row_ptr, height);
+ break;
+ default:
+ error ("Unsupported bits per pixel %d", _bitsPerPixel);
+ }
+
+ return _surface;
+}
+
+QTRLEDecoder::~QTRLEDecoder() {
+ _surface->free();
+}
+
+} // End of namespace Mohawk
diff --git a/engines/mohawk/video/qtrle.h b/engines/mohawk/video/qtrle.h
new file mode 100644
index 0000000000..2832bd6b24
--- /dev/null
+++ b/engines/mohawk/video/qtrle.h
@@ -0,0 +1,58 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef MOHAWK_QTRLE_H
+#define MOHAWK_QTRLE_H
+
+#include "graphics/pixelformat.h"
+#include "graphics/video/codecs/codec.h"
+
+namespace Mohawk {
+
+class QTRLEDecoder : public Graphics::Codec {
+public:
+ QTRLEDecoder(uint16 width, uint16 height, byte bitsPerPixel);
+ ~QTRLEDecoder();
+
+ Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
+ Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
+
+private:
+ byte _bitsPerPixel;
+
+ Graphics::Surface *_surface;
+ Graphics::PixelFormat _pixelFormat;
+
+ void decode1(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange);
+ void decode2_4(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange, byte bpp);
+ void decode8(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange);
+ void decode16(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange);
+ void decode24(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange);
+ void decode32(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange);
+};
+
+} // End of namespace Mohawk
+
+#endif
diff --git a/engines/mohawk/video/rpza.cpp b/engines/mohawk/video/rpza.cpp
new file mode 100644
index 0000000000..f48c055ae2
--- /dev/null
+++ b/engines/mohawk/video/rpza.cpp
@@ -0,0 +1,208 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+ // Based off ffmpeg's RPZA decoder
+
+#include "mohawk/video/rpza.h"
+
+#include "common/system.h"
+#include "graphics/colormasks.h"
+
+namespace Mohawk {
+
+RPZADecoder::RPZADecoder(uint16 width, uint16 height) : Graphics::Codec() {
+ _pixelFormat = g_system->getScreenFormat();
+
+ // We need to increase the surface size to a multiple of 4
+ uint16 wMod = width % 4;
+ if(wMod != 0)
+ width += 4 - wMod;
+
+ debug(2, "RPZA corrected width: %d", width);
+
+ _surface = new Graphics::Surface();
+ _surface->create(width, height, _pixelFormat.bytesPerPixel);
+}
+
+#define ADVANCE_BLOCK() \
+ pixelPtr += 4; \
+ if (pixelPtr >= _surface->w) { \
+ pixelPtr = 0; \
+ rowPtr += _surface->w * 4; \
+ } \
+ totalBlocks--; \
+ if (totalBlocks < 0) \
+ error("block counter just went negative (this should not happen)") \
+
+// Convert from RGB555 to the format specified by the screen
+#define PUT_PIXEL(color) \
+ if ((int32)blockPtr < _surface->w * _surface->h) { \
+ byte r = 0, g = 0, b = 0; \
+ Graphics::colorToRGB<Graphics::ColorMasks<555> >(color, r, g, b); \
+ if (_pixelFormat.bytesPerPixel == 2) \
+ *((uint16 *)_surface->pixels + blockPtr) = _pixelFormat.RGBToColor(r, g, b); \
+ else \
+ *((uint32 *)_surface->pixels + blockPtr) = _pixelFormat.RGBToColor(r, g, b); \
+ } \
+ blockPtr++
+
+Graphics::Surface *RPZADecoder::decodeImage(Common::SeekableReadStream *stream) {
+ uint16 colorA = 0, colorB = 0;
+ uint16 color4[4];
+
+ uint32 rowPtr = 0;
+ uint32 pixelPtr = 0;
+ uint32 blockPtr = 0;
+ uint32 rowInc = _surface->w - 4;
+ uint16 ta;
+ uint16 tb;
+
+ // First byte is always 0xe1. Warn if it's different
+ byte firstByte = stream->readByte();
+ if (firstByte != 0xe1)
+ warning("First RPZA chunk byte is 0x%02x instead of 0xe1", firstByte);
+
+ // Get chunk size, ingnoring first byte
+ uint32 chunkSize = stream->readUint16BE() << 8;
+ chunkSize += stream->readByte();
+
+ // If length mismatch use size from MOV file and try to decode anyway
+ if (chunkSize != (uint32)stream->size()) {
+ warning("MOV chunk size != encoded chunk size; using MOV chunk size");
+ chunkSize = stream->size();
+ }
+
+ // Number of 4x4 blocks in frame
+ int32 totalBlocks = ((_surface->w + 3) / 4) * ((_surface->h + 3) / 4);
+
+ // Process chunk data
+ while ((uint32)stream->pos() < chunkSize) {
+ byte opcode = stream->readByte(); // Get opcode
+ byte numBlocks = (opcode & 0x1f) + 1; // Extract block counter from opcode
+
+ // If opcode MSbit is 0, we need more data to decide what to do
+ if ((opcode & 0x80) == 0) {
+ colorA = (opcode << 8) | stream->readByte();
+ opcode = 0;
+ if (stream->readByte() & 0x80) {
+ // Must behave as opcode 110xxxxx, using colorA computed
+ // above. Use fake opcode 0x20 to enter switch block at
+ // the right place
+ opcode = 0x20;
+ numBlocks = 1;
+ }
+ stream->seek(-1, SEEK_CUR);
+ }
+
+ switch (opcode & 0xe0) {
+ case 0x80: // Skip blocks
+ while (numBlocks--) {
+ ADVANCE_BLOCK();
+ }
+ break;
+ case 0xa0: // Fill blocks with one color
+ colorA = stream->readUint16BE();
+ while (numBlocks--) {
+ blockPtr = rowPtr + pixelPtr;
+ for (byte pixel_y = 0; pixel_y < 4; pixel_y++) {
+ for (byte pixel_x = 0; pixel_x < 4; pixel_x++) {
+ PUT_PIXEL(colorA);
+ }
+ blockPtr += rowInc;
+ }
+ ADVANCE_BLOCK();
+ }
+ break;
+
+ // Fill blocks with 4 colors
+ case 0xc0:
+ colorA = stream->readUint16BE();
+ case 0x20:
+ colorB = stream->readUint16BE();
+
+ // Sort out the colors
+ color4[0] = colorB;
+ color4[1] = 0;
+ color4[2] = 0;
+ color4[3] = colorA;
+
+ // Red components
+ ta = (colorA >> 10) & 0x1F;
+ tb = (colorB >> 10) & 0x1F;
+ color4[1] |= ((11 * ta + 21 * tb) >> 5) << 10;
+ color4[2] |= ((21 * ta + 11 * tb) >> 5) << 10;
+
+ // Green components
+ ta = (colorA >> 5) & 0x1F;
+ tb = (colorB >> 5) & 0x1F;
+ color4[1] |= ((11 * ta + 21 * tb) >> 5) << 5;
+ color4[2] |= ((21 * ta + 11 * tb) >> 5) << 5;
+
+ // Blue components
+ ta = colorA & 0x1F;
+ tb = colorB & 0x1F;
+ color4[1] |= ((11 * ta + 21 * tb) >> 5);
+ color4[2] |= ((21 * ta + 11 * tb) >> 5);
+
+ while (numBlocks--) {
+ blockPtr = rowPtr + pixelPtr;
+ for (byte pixel_y = 0; pixel_y < 4; pixel_y++) {
+ byte index = stream->readByte();
+ for (byte pixel_x = 0; pixel_x < 4; pixel_x++){
+ byte idx = (index >> (2 * (3 - pixel_x))) & 0x03;
+ PUT_PIXEL(color4[idx]);
+ }
+ blockPtr += rowInc;
+ }
+ ADVANCE_BLOCK();
+ }
+ break;
+
+ // Fill block with 16 colors
+ case 0x00:
+ blockPtr = rowPtr + pixelPtr;
+ for (byte pixel_y = 0; pixel_y < 4; pixel_y++) {
+ for (byte pixel_x = 0; pixel_x < 4; pixel_x++){
+ // We already have color of upper left pixel
+ if (pixel_y != 0 || pixel_x != 0)
+ colorA = stream->readUint16BE();
+
+ PUT_PIXEL(colorA);
+ }
+ blockPtr += rowInc;
+ }
+ ADVANCE_BLOCK();
+ break;
+
+ // Unknown opcode
+ default:
+ error("Unknown opcode %02x in rpza chunk", opcode);
+ }
+ }
+
+ return _surface;
+}
+
+} // End of namespace Mohawk
diff --git a/engines/mohawk/video/rpza.h b/engines/mohawk/video/rpza.h
new file mode 100644
index 0000000000..c6d0ada6f5
--- /dev/null
+++ b/engines/mohawk/video/rpza.h
@@ -0,0 +1,49 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef MOHAWK_RPZA_H
+#define MOHAWK_RPZA_H
+
+#include "graphics/pixelformat.h"
+#include "graphics/video/codecs/codec.h"
+
+namespace Mohawk {
+
+class RPZADecoder : public Graphics::Codec {
+public:
+ RPZADecoder(uint16 width, uint16 height);
+ ~RPZADecoder() { delete _surface; }
+
+ Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
+ Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
+
+private:
+ Graphics::Surface *_surface;
+ Graphics::PixelFormat _pixelFormat;
+};
+
+} // End of namespace Mohawk
+
+#endif
diff --git a/engines/mohawk/video/smc.cpp b/engines/mohawk/video/smc.cpp
new file mode 100644
index 0000000000..4a0d16dfcc
--- /dev/null
+++ b/engines/mohawk/video/smc.cpp
@@ -0,0 +1,385 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+// Based off ffmpeg's SMC decoder
+
+#include "mohawk/video/smc.h"
+
+namespace Mohawk {
+
+#define GET_BLOCK_COUNT() \
+ (opcode & 0x10) ? (1 + stream->readByte()) : 1 + (opcode & 0x0F);
+
+#define ADVANCE_BLOCK() \
+{ \
+ pixelPtr += 4; \
+ if (pixelPtr >= _surface->w) { \
+ pixelPtr = 0; \
+ rowPtr += _surface->w * 4; \
+ } \
+ totalBlocks--; \
+ if (totalBlocks < 0) { \
+ warning("block counter just went negative (this should not happen)"); \
+ return _surface; \
+ } \
+}
+
+SMCDecoder::SMCDecoder(uint16 width, uint16 height) {
+ _surface = new Graphics::Surface();
+ _surface->create(width, height, 1);
+}
+
+Graphics::Surface *SMCDecoder::decodeImage(Common::SeekableReadStream *stream) {
+ byte *pixels = (byte *)_surface->pixels;
+
+ uint32 numBlocks = 0;
+ uint32 colorFlags = 0;
+ uint32 colorFlagsA = 0;
+ uint32 colorFlagsB = 0;
+
+ const uint16 rowInc = _surface->w - 4;
+ int32 rowPtr = 0;
+ int32 pixelPtr = 0;
+ uint32 blockPtr = 0;
+ uint32 prevBlockPtr = 0;
+ uint32 prevBlockPtr1 = 0, prevBlockPtr2 = 0;
+ byte prevBlockFlag = false;
+ byte pixel = 0;
+
+ uint32 colorPairIndex = 0;
+ uint32 colorQuadIndex = 0;
+ uint32 colorOctetIndex = 0;
+ uint32 colorTableIndex = 0; // indices to color pair, quad, or octet tables
+
+ int32 chunkSize = stream->readUint32BE() & 0x00FFFFFF;
+ if (chunkSize != stream->size())
+ warning("MOV chunk size != SMC chunk size (%d != %d); ignoring SMC chunk size", chunkSize, stream->size());
+
+ int32 totalBlocks = ((_surface->w + 3) / 4) * ((_surface->h + 3) / 4);
+
+ // traverse through the blocks
+ while (totalBlocks != 0) {
+ // sanity checks
+
+ // make sure stream ptr hasn't gone out of bounds
+ if (stream->pos() > stream->size()) {
+ warning("SMC decoder just went out of bounds (stream ptr = %d, chunk size = %d)", stream->pos(), stream->size());
+ return _surface;
+ }
+
+ // make sure the row pointer hasn't gone wild
+ if (rowPtr >= _surface->w * _surface->h) {
+ warning("SMC decoder just went out of bounds (row ptr = %d, size = %d)", rowPtr, _surface->w * _surface->h);
+ return _surface;
+ }
+
+ byte opcode = stream->readByte();
+
+ switch (opcode & 0xF0) {
+ // skip n blocks
+ case 0x00:
+ case 0x10:
+ numBlocks = GET_BLOCK_COUNT();
+ while (numBlocks--) {
+ ADVANCE_BLOCK();
+ }
+ break;
+
+ // repeat last block n times
+ case 0x20:
+ case 0x30:
+ numBlocks = GET_BLOCK_COUNT();
+
+ // sanity check
+ if (rowPtr == 0 && pixelPtr == 0) {
+ warning("encountered repeat block opcode (%02X) but no blocks rendered yet", opcode & 0xF0);
+ break;
+ }
+
+ // figure out where the previous block started
+ if (pixelPtr == 0)
+ prevBlockPtr1 = (rowPtr - _surface->w * 4) + _surface->w - 4;
+ else
+ prevBlockPtr1 = rowPtr + pixelPtr - 4;
+
+ while (numBlocks--) {
+ blockPtr = rowPtr + pixelPtr;
+ prevBlockPtr = prevBlockPtr1;
+ for (byte y = 0; y < 4; y++) {
+ for (byte x = 0; x < 4; x++)
+ pixels[blockPtr++] = pixels[prevBlockPtr++];
+ blockPtr += rowInc;
+ prevBlockPtr += rowInc;
+ }
+ ADVANCE_BLOCK();
+ }
+ break;
+
+ // repeat previous pair of blocks n times
+ case 0x40:
+ case 0x50:
+ numBlocks = GET_BLOCK_COUNT();
+ numBlocks *= 2;
+
+ // sanity check
+ if (rowPtr == 0 && pixelPtr < 2 * 4) {
+ warning("encountered repeat block opcode (%02X) but not enough blocks rendered yet", opcode & 0xF0);
+ break;
+ }
+
+ // figure out where the previous 2 blocks started
+ if (pixelPtr == 0)
+ prevBlockPtr1 = (rowPtr - _surface->w * 4) + _surface->w - 4 * 2;
+ else if (pixelPtr == 4)
+ prevBlockPtr1 = (rowPtr - _surface->w * 4) + rowInc;
+ else
+ prevBlockPtr1 = rowPtr + pixelPtr - 4 * 2;
+
+ if (pixelPtr == 0)
+ prevBlockPtr2 = (rowPtr - _surface->w * 4) + rowInc;
+ else
+ prevBlockPtr2 = rowPtr + pixelPtr - 4;
+
+ prevBlockFlag = 0;
+ while (numBlocks--) {
+ blockPtr = rowPtr + pixelPtr;
+
+ if (prevBlockFlag)
+ prevBlockPtr = prevBlockPtr2;
+ else
+ prevBlockPtr = prevBlockPtr1;
+
+ prevBlockFlag = !prevBlockFlag;
+
+ for (byte y = 0; y < 4; y++) {
+ for (byte x = 0; x < 4; x++)
+ pixels[blockPtr++] = pixels[prevBlockPtr++];
+
+ blockPtr += rowInc;
+ prevBlockPtr += rowInc;
+ }
+ ADVANCE_BLOCK();
+ }
+ break;
+
+ // 1-color block encoding
+ case 0x60:
+ case 0x70:
+ numBlocks = GET_BLOCK_COUNT();
+ pixel = stream->readByte();
+
+ while (numBlocks--) {
+ blockPtr = rowPtr + pixelPtr;
+ for (byte y = 0; y < 4; y++) {
+ for (byte x = 0; x < 4; x++)
+ pixels[blockPtr++] = pixel;
+
+ blockPtr += rowInc;
+ }
+ ADVANCE_BLOCK();
+ }
+ break;
+
+ // 2-color block encoding
+ case 0x80:
+ case 0x90:
+ numBlocks = (opcode & 0x0F) + 1;
+
+ // figure out which color pair to use to paint the 2-color block
+ if ((opcode & 0xF0) == 0x80) {
+ // fetch the next 2 colors from bytestream and store in next
+ // available entry in the color pair table
+ for (byte i = 0; i < CPAIR; i++) {
+ pixel = stream->readByte();
+ colorTableIndex = CPAIR * colorPairIndex + i;
+ _colorPairs[colorTableIndex] = pixel;
+ }
+
+ // this is the base index to use for this block
+ colorTableIndex = CPAIR * colorPairIndex;
+ colorPairIndex++;
+
+ // wraparound
+ if (colorPairIndex == COLORS_PER_TABLE)
+ colorPairIndex = 0;
+ } else
+ colorTableIndex = CPAIR * stream->readByte();
+
+ while (numBlocks--) {
+ colorFlags = stream->readUint16BE();
+ uint16 flagMask = 0x8000;
+ blockPtr = rowPtr + pixelPtr;
+ for (byte y = 0; y < 4; y++) {
+ for (byte x = 0; x < 4; x++) {
+ if (colorFlags & flagMask)
+ pixel = colorTableIndex + 1;
+ else
+ pixel = colorTableIndex;
+
+ flagMask >>= 1;
+ pixels[blockPtr++] = _colorPairs[pixel];
+ }
+
+ blockPtr += rowInc;
+ }
+ ADVANCE_BLOCK();
+ }
+ break;
+
+ // 4-color block encoding
+ case 0xA0:
+ case 0xB0:
+ numBlocks = (opcode & 0x0F) + 1;
+
+ // figure out which color quad to use to paint the 4-color block
+ if ((opcode & 0xF0) == 0xA0) {
+ // fetch the next 4 colors from bytestream and store in next
+ // available entry in the color quad table
+ for (byte i = 0; i < CQUAD; i++) {
+ pixel = stream->readByte();
+ colorTableIndex = CQUAD * colorQuadIndex + i;
+ _colorQuads[colorTableIndex] = pixel;
+ }
+
+ // this is the base index to use for this block
+ colorTableIndex = CQUAD * colorQuadIndex;
+ colorQuadIndex++;
+
+ // wraparound
+ if (colorQuadIndex == COLORS_PER_TABLE)
+ colorQuadIndex = 0;
+ } else
+ colorTableIndex = CQUAD * stream->readByte();
+
+ while (numBlocks--) {
+ colorFlags = stream->readUint32BE();
+
+ // flag mask actually acts as a bit shift count here
+ byte flagMask = 30;
+ blockPtr = rowPtr + pixelPtr;
+
+ for (byte y = 0; y < 4; y++) {
+ for (byte x = 0; x < 4; x++) {
+ pixel = colorTableIndex + ((colorFlags >> flagMask) & 0x03);
+ flagMask -= 2;
+ pixels[blockPtr++] = _colorQuads[pixel];
+ }
+ blockPtr += rowInc;
+ }
+ ADVANCE_BLOCK();
+ }
+ break;
+
+ // 8-color block encoding
+ case 0xC0:
+ case 0xD0:
+ numBlocks = (opcode & 0x0F) + 1;
+
+ // figure out which color octet to use to paint the 8-color block
+ if ((opcode & 0xF0) == 0xC0) {
+ // fetch the next 8 colors from bytestream and store in next
+ // available entry in the color octet table
+ for (byte i = 0; i < COCTET; i++) {
+ pixel = stream->readByte();
+ colorTableIndex = COCTET * colorOctetIndex + i;
+ _colorOctets[colorTableIndex] = pixel;
+ }
+
+ // this is the base index to use for this block
+ colorTableIndex = COCTET * colorOctetIndex;
+ colorOctetIndex++;
+
+ // wraparound
+ if (colorOctetIndex == COLORS_PER_TABLE)
+ colorOctetIndex = 0;
+ } else
+ colorTableIndex = COCTET * stream->readByte();
+
+ while (numBlocks--) {
+ /*
+ For this input of 6 hex bytes:
+ 01 23 45 67 89 AB
+ Mangle it to this output:
+ flags_a = xx012456, flags_b = xx89A37B
+ */
+
+ // build the color flags
+ byte flagData[6];
+ stream->read(flagData, 6);
+
+ colorFlagsA = ((READ_BE_UINT16(flagData) & 0xFFF0) << 8) | (READ_BE_UINT16(flagData + 2) >> 4);
+ colorFlagsB = ((READ_BE_UINT16(flagData + 4) & 0xFFF0) << 8) | ((flagData[1] & 0xF) << 8) |
+ ((flagData[3] & 0xF) << 4) | (flagData[5] & 0xf);
+
+ colorFlags = colorFlagsA;
+
+ // flag mask actually acts as a bit shift count here
+ byte flagMask = 21;
+ blockPtr = rowPtr + pixelPtr;
+ for (byte y = 0; y < 4; y++) {
+ // reload flags at third row (iteration y == 2)
+ if (y == 2) {
+ colorFlags = colorFlagsB;
+ flagMask = 21;
+ }
+
+ for (byte x = 0; x < 4; x++) {
+ pixel = colorTableIndex + ((colorFlags >> flagMask) & 0x07);
+ flagMask -= 3;
+ pixels[blockPtr++] = _colorOctets[pixel];
+ }
+
+ blockPtr += rowInc;
+ }
+ ADVANCE_BLOCK();
+ }
+ break;
+
+ // 16-color block encoding (every pixel is a different color)
+ case 0xE0:
+ numBlocks = (opcode & 0x0F) + 1;
+
+ while (numBlocks--) {
+ blockPtr = rowPtr + pixelPtr;
+ for (byte y = 0; y < 4; y++) {
+ for (byte x = 0; x < 4; x++)
+ pixels[blockPtr++] = stream->readByte();
+
+ blockPtr += rowInc;
+ }
+ ADVANCE_BLOCK();
+ }
+ break;
+
+ case 0xF0:
+ warning("0xF0 opcode seen in SMC chunk (contact the developers)");
+ break;
+ }
+ }
+
+ return _surface;
+}
+
+} // End of namespace Mohawk
diff --git a/engines/mohawk/video/smc.h b/engines/mohawk/video/smc.h
new file mode 100644
index 0000000000..c52226100e
--- /dev/null
+++ b/engines/mohawk/video/smc.h
@@ -0,0 +1,59 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef MOHAWK_VIDEO_SMC_H
+#define MOHAWK_VIDEO_SMC_H
+
+#include "graphics/video/codecs/codec.h"
+
+namespace Mohawk {
+
+enum {
+ CPAIR = 2,
+ CQUAD = 4,
+ COCTET = 8,
+ COLORS_PER_TABLE = 256
+};
+
+class SMCDecoder : public Graphics::Codec {
+public:
+ SMCDecoder(uint16 width, uint16 height);
+ ~SMCDecoder() { delete _surface; }
+
+ Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
+ Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); }
+
+private:
+ Graphics::Surface *_surface;
+
+ // SMC color tables
+ byte _colorPairs[COLORS_PER_TABLE * CPAIR];
+ byte _colorQuads[COLORS_PER_TABLE * CQUAD];
+ byte _colorOctets[COLORS_PER_TABLE * COCTET];
+};
+
+} // End of namespace Mohawk
+
+#endif
diff --git a/engines/mohawk/video/video.cpp b/engines/mohawk/video/video.cpp
new file mode 100644
index 0000000000..86ecd4dedf
--- /dev/null
+++ b/engines/mohawk/video/video.cpp
@@ -0,0 +1,377 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "mohawk/resource.h"
+#include "mohawk/video/video.h"
+#include "mohawk/video/qt_player.h"
+
+#include "common/events.h"
+
+namespace Mohawk {
+
+VideoManager::VideoManager(MohawkEngine* vm) : _vm(vm) {
+}
+
+VideoManager::~VideoManager() {
+ _mlstRecords.clear();
+ stopVideos();
+}
+
+void VideoManager::pauseVideos() {
+ for (uint16 i = 0; i < _videoStreams.size(); i++)
+ _videoStreams[i]->pauseVideo(true);
+}
+
+void VideoManager::resumeVideos() {
+ for (uint16 i = 0; i < _videoStreams.size(); i++)
+ _videoStreams[i]->pauseVideo(false);
+}
+
+void VideoManager::stopVideos() {
+ for (uint16 i = 0; i < _videoStreams.size(); i++)
+ delete _videoStreams[i].video;
+ _videoStreams.clear();
+}
+
+void VideoManager::playMovie(Common::String filename, uint16 x, uint16 y, bool clearScreen) {
+ VideoHandle videoHandle = createVideoHandle(filename, x, y, false);
+ if (videoHandle == NULL_VID_HANDLE)
+ return;
+
+ // Clear screen if requested
+ if (clearScreen) {
+ _vm->_system->fillScreen(_vm->_system->getScreenFormat().RGBToColor(0, 0, 0));
+ _vm->_system->updateScreen();
+ }
+
+ waitUntilMovieEnds(videoHandle);
+}
+
+void VideoManager::playMovieCentered(Common::String filename, bool clearScreen) {
+ VideoHandle videoHandle = createVideoHandle(filename, 0, 0, false);
+ if (videoHandle == NULL_VID_HANDLE)
+ return;
+
+ // Clear screen if requested
+ if (clearScreen) {
+ _vm->_system->fillScreen(_vm->_system->getScreenFormat().RGBToColor(0, 0, 0));
+ _vm->_system->updateScreen();
+ }
+
+ _videoStreams[videoHandle].x = (_vm->_system->getWidth() - _videoStreams[videoHandle]->getWidth()) / 2;
+ _videoStreams[videoHandle].y = (_vm->_system->getHeight() - _videoStreams[videoHandle]->getHeight()) / 2;
+
+ waitUntilMovieEnds(videoHandle);
+}
+
+void VideoManager::waitUntilMovieEnds(VideoHandle videoHandle) {
+ bool continuePlaying = true;
+
+ while (!_videoStreams[videoHandle]->endOfVideo() && !_vm->shouldQuit() && continuePlaying) {
+ if (updateBackgroundMovies())
+ _vm->_system->updateScreen();
+
+ Common::Event event;
+ while (_vm->_system->getEventManager()->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_RTL:
+ case Common::EVENT_QUIT:
+ continuePlaying = false;
+ break;
+ case Common::EVENT_KEYDOWN:
+ switch (event.kbd.keycode) {
+ case Common::KEYCODE_SPACE:
+ _vm->pauseGame();
+ break;
+ case Common::KEYCODE_ESCAPE:
+ continuePlaying = false;
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ // Cut down on CPU usage
+ _vm->_system->delayMillis(10);
+ }
+
+ _videoStreams[videoHandle]->close();
+ _videoStreams.clear();
+}
+
+void VideoManager::playBackgroundMovie(Common::String filename, int16 x, int16 y, bool loop) {
+ VideoHandle videoHandle = createVideoHandle(filename, x, y, loop);
+ if (videoHandle == NULL_VID_HANDLE)
+ return;
+
+ // Center x if requested
+ if (x < 0)
+ _videoStreams[videoHandle].x = (_vm->_system->getWidth() - _videoStreams[videoHandle]->getWidth()) / 2;
+
+ // Center y if requested
+ if (y < 0)
+ _videoStreams[videoHandle].y = (_vm->_system->getHeight() - _videoStreams[videoHandle]->getHeight()) / 2;
+}
+
+bool VideoManager::updateBackgroundMovies() {
+ bool updateScreen = false;
+
+ for (uint32 i = 0; i < _videoStreams.size() && !_vm->shouldQuit(); i++) {
+ // Skip deleted videos
+ if (!_videoStreams[i].video)
+ continue;
+
+ // Remove any videos that are over
+ if (_videoStreams[i]->endOfVideo()) {
+ if (_videoStreams[i].loop) {
+ _videoStreams[i]->rewind();
+ } else {
+ delete _videoStreams[i].video;
+ memset(&_videoStreams[i], 0, sizeof(VideoEntry));
+ _videoStreams[i].video = NULL;
+ continue;
+ }
+ }
+
+ // Check if we need to draw a frame
+ if (_videoStreams[i]->needsUpdate()) {
+ Graphics::Surface *frame = _videoStreams[i]->decodeNextFrame();
+ bool deleteFrame = false;
+
+ if (frame && _videoStreams[i].enabled) {
+ // Convert from 8bpp to the current screen format if necessary
+ if (frame->bytesPerPixel == 1) {
+ Graphics::Surface *newFrame = new Graphics::Surface();
+ Graphics::PixelFormat pixelFormat = _vm->_system->getScreenFormat();
+ byte *palette = _videoStreams[i]->getPalette();
+ assert(palette);
+
+ newFrame->create(frame->w, frame->h, pixelFormat.bytesPerPixel);
+
+ for (uint16 j = 0; j < frame->h; j++) {
+ for (uint16 k = 0; k < frame->w; k++) {
+ byte palIndex = *((byte *)frame->getBasePtr(k, j));
+ byte r = palette[palIndex * 3];
+ byte g = palette[palIndex * 3 + 1];
+ byte b = palette[palIndex * 3 + 2];
+ if (pixelFormat.bytesPerPixel == 2)
+ *((uint16 *)newFrame->getBasePtr(k, j)) = pixelFormat.RGBToColor(r, g, b);
+ else
+ *((uint32 *)newFrame->getBasePtr(k, j)) = pixelFormat.RGBToColor(r, g, b);
+ }
+ }
+
+ frame = newFrame;
+ deleteFrame = true;
+ }
+
+ // Clip the width/height to make sure we stay on the screen (Myst does this a few times)
+ uint16 width = MIN<int32>(_videoStreams[i]->getWidth(), _vm->_system->getWidth() - _videoStreams[i].x);
+ uint16 height = MIN<int32>(_videoStreams[i]->getHeight(), _vm->_system->getHeight() - _videoStreams[i].y);
+ _vm->_system->copyRectToScreen((byte*)frame->pixels, frame->pitch, _videoStreams[i].x, _videoStreams[i].y, width, height);
+
+ // We've drawn something to the screen, make sure we update it
+ updateScreen = true;
+
+ // Delete the frame if we're using the buffer from the 8bpp conversion
+ if (deleteFrame) {
+ frame->free();
+ delete frame;
+ }
+ }
+ }
+
+ // Update the audio buffer too
+ _videoStreams[i]->updateAudioBuffer();
+ }
+
+ // Return true if we need to update the screen
+ return updateScreen;
+}
+
+void VideoManager::activateMLST(uint16 mlstId, uint16 card) {
+ Common::SeekableReadStream *mlstStream = _vm->getRawData(ID_MLST, card);
+ uint16 recordCount = mlstStream->readUint16BE();
+
+ for (uint16 i = 0; i < recordCount; i++) {
+ MLSTRecord mlstRecord;
+ mlstRecord.index = mlstStream->readUint16BE();
+ mlstRecord.movieID = mlstStream->readUint16BE();
+ mlstRecord.code = mlstStream->readUint16BE();
+ mlstRecord.left = mlstStream->readUint16BE();
+ mlstRecord.top = mlstStream->readUint16BE();
+
+ for (byte j = 0; j < 2; j++)
+ if (mlstStream->readUint16BE() != 0)
+ warning("u0[%d] in MLST non-zero", j);
+
+ if (mlstStream->readUint16BE() != 0xFFFF)
+ warning("u0[2] in MLST not 0xFFFF");
+
+ mlstRecord.loop = mlstStream->readUint16BE();
+ mlstRecord.volume = mlstStream->readUint16BE();
+ mlstRecord.u1 = mlstStream->readUint16BE();
+
+ if (mlstRecord.u1 != 1)
+ warning("mlstRecord.u1 not 1");
+
+ if (mlstRecord.index == mlstId) {
+ _mlstRecords.push_back(mlstRecord);
+ break;
+ }
+ }
+
+ delete mlstStream;
+}
+
+void VideoManager::playMovie(uint16 id) {
+ for (uint16 i = 0; i < _mlstRecords.size(); i++)
+ if (_mlstRecords[i].code == id) {
+ debug(1, "Play tMOV %d (non-blocking) at (%d, %d) %s", _mlstRecords[i].movieID, _mlstRecords[i].left, _mlstRecords[i].top, _mlstRecords[i].loop != 0 ? "looping" : "non-looping");
+ createVideoHandle(_mlstRecords[i].movieID, _mlstRecords[i].left, _mlstRecords[i].top, _mlstRecords[i].loop != 0);
+ return;
+ }
+}
+
+void VideoManager::playMovieBlocking(uint16 id) {
+ for (uint16 i = 0; i < _mlstRecords.size(); i++)
+ if (_mlstRecords[i].code == id) {
+ debug(1, "Play tMOV %d (blocking) at (%d, %d)", _mlstRecords[i].movieID, _mlstRecords[i].left, _mlstRecords[i].top);
+ VideoHandle videoHandle = createVideoHandle(_mlstRecords[i].movieID, _mlstRecords[i].left, _mlstRecords[i].top, false);
+ waitUntilMovieEnds(videoHandle);
+ return;
+ }
+}
+
+void VideoManager::stopMovie(uint16 id) {
+ debug(2, "Stopping movie %d", id);
+ for (uint16 i = 0; i < _mlstRecords.size(); i++)
+ if (_mlstRecords[i].code == id)
+ for (uint16 j = 0; j < _videoStreams.size(); j++)
+ if (_mlstRecords[i].movieID == _videoStreams[j].id) {
+ delete _videoStreams[i].video;
+ memset(&_videoStreams[i].video, 0, sizeof(VideoEntry));
+ return;
+ }
+}
+
+void VideoManager::enableMovie(uint16 id) {
+ debug(2, "Enabling movie %d", id);
+ for (uint16 i = 0; i < _mlstRecords.size(); i++)
+ if (_mlstRecords[i].code == id)
+ for (uint16 j = 0; j < _videoStreams.size(); j++)
+ if (_mlstRecords[i].movieID == _videoStreams[j].id) {
+ _videoStreams[j].enabled = true;
+ return;
+ }
+}
+
+void VideoManager::disableMovie(uint16 id) {
+ debug(2, "Disabling movie %d", id);
+ for (uint16 i = 0; i < _mlstRecords.size(); i++)
+ if (_mlstRecords[i].code == id)
+ for (uint16 j = 0; j < _videoStreams.size(); j++)
+ if (_mlstRecords[i].movieID == _videoStreams[j].id) {
+ _videoStreams[j].enabled = false;
+ return;
+ }
+}
+
+void VideoManager::disableAllMovies() {
+ debug(2, "Disabling all movies");
+ for (uint16 i = 0; i < _videoStreams.size(); i++)
+ _videoStreams[i].enabled = false;
+}
+
+VideoHandle VideoManager::createVideoHandle(uint16 id, uint16 x, uint16 y, bool loop) {
+ // First, check to see if that video is already playing
+ for (uint32 i = 0; i < _videoStreams.size(); i++)
+ if (_videoStreams[i].id == id)
+ return i;
+
+ // Otherwise, create a new entry
+ VideoEntry entry;
+ entry.video = new QTPlayer();
+ entry.x = x;
+ entry.y = y;
+ entry.filename = "";
+ entry.id = id;
+ entry.loop = loop;
+ entry.enabled = true;
+ entry->setChunkBeginOffset(_vm->getResourceOffset(ID_TMOV, id));
+ entry->load(*_vm->getRawData(ID_TMOV, id));
+
+ // Search for any deleted videos so we can take a formerly used slot
+ for (uint32 i = 0; i < _videoStreams.size(); i++)
+ if (!_videoStreams[i].video) {
+ _videoStreams[i] = entry;
+ return i;
+ }
+
+ // Otherwise, just add it to the list
+ _videoStreams.push_back(entry);
+ return _videoStreams.size() - 1;
+}
+
+VideoHandle VideoManager::createVideoHandle(Common::String filename, uint16 x, uint16 y, bool loop) {
+ // First, check to see if that video is already playing
+ for (uint32 i = 0; i < _videoStreams.size(); i++)
+ if (_videoStreams[i].filename == filename)
+ return i;
+
+ // Otherwise, create a new entry
+ VideoEntry entry;
+ entry.video = new QTPlayer();
+ entry.x = x;
+ entry.y = y;
+ entry.filename = filename;
+ entry.id = 0;
+ entry.loop = loop;
+ entry.enabled = true;
+
+ Common::File *file = new Common::File();
+ if (!file->open(filename)) {
+ delete file;
+ return NULL_VID_HANDLE;
+ }
+
+ entry->load(*file);
+
+ // Search for any deleted videos so we can take a formerly used slot
+ for (uint32 i = 0; i < _videoStreams.size(); i++)
+ if (!_videoStreams[i].video) {
+ _videoStreams[i] = entry;
+ return i;
+ }
+
+ // Otherwise, just add it to the list
+ _videoStreams.push_back(entry);
+ return _videoStreams.size() - 1;
+}
+
+} // End of namespace Mohawk
diff --git a/engines/mohawk/video/video.h b/engines/mohawk/video/video.h
new file mode 100644
index 0000000000..a5d2bde65d
--- /dev/null
+++ b/engines/mohawk/video/video.h
@@ -0,0 +1,107 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef MOHAWK_VIDEO_H
+#define MOHAWK_VIDEO_H
+
+#include "graphics/pixelformat.h"
+
+namespace Mohawk {
+
+class MohawkEngine;
+
+struct MLSTRecord {
+ uint16 index;
+ uint16 movieID;
+ uint16 code;
+ uint16 left;
+ uint16 top;
+ uint16 u0[3];
+ uint16 loop;
+ uint16 volume;
+ uint16 u1;
+};
+
+class QTPlayer;
+
+struct VideoEntry {
+ QTPlayer *video;
+ uint16 x;
+ uint16 y;
+ bool loop;
+ Common::String filename;
+ uint16 id; // Riven only
+ bool enabled;
+
+ QTPlayer *operator->() const { assert(video); return video; }
+};
+
+typedef int32 VideoHandle;
+
+enum {
+ NULL_VID_HANDLE = -1
+};
+
+class VideoManager {
+public:
+ VideoManager(MohawkEngine *vm);
+ ~VideoManager();
+
+ // Generic movie functions
+ void playMovie(Common::String filename, uint16 x = 0, uint16 y = 0, bool clearScreen = false);
+ void playMovieCentered(Common::String filename, bool clearScreen = true);
+ void playBackgroundMovie(Common::String filename, int16 x = -1, int16 y = -1, bool loop = false);
+ bool updateBackgroundMovies();
+ void pauseVideos();
+ void resumeVideos();
+ void stopVideos();
+
+ // Riven-related functions
+ void activateMLST(uint16 mlstId, uint16 card);
+ void enableMovie(uint16 id);
+ void disableMovie(uint16 id);
+ void disableAllMovies();
+ void playMovie(uint16 id);
+ void stopMovie(uint16 id);
+ void playMovieBlocking(uint16 id);
+
+ // Riven-related variables
+ Common::Array<MLSTRecord> _mlstRecords;
+
+private:
+ MohawkEngine *_vm;
+
+ void waitUntilMovieEnds(VideoHandle videoHandle);
+
+ // Keep tabs on any videos playing
+ Common::Array<VideoEntry> _videoStreams;
+
+ VideoHandle createVideoHandle(uint16 id, uint16 x, uint16 y, bool loop);
+ VideoHandle createVideoHandle(Common::String filename, uint16 x, uint16 y, bool loop);
+};
+
+} // End of namespace Mohawk
+
+#endif
diff --git a/engines/parallaction/debug.cpp b/engines/parallaction/debug.cpp
index b5eb82b456..8864c84e2f 100644
--- a/engines/parallaction/debug.cpp
+++ b/engines/parallaction/debug.cpp
@@ -42,7 +42,6 @@ Debugger::Debugger(Parallaction *vm)
DCmd_Register("zones", WRAP_METHOD(Debugger, Cmd_Zones));
DCmd_Register("animations", WRAP_METHOD(Debugger, Cmd_Animations));
DCmd_Register("globalflags",WRAP_METHOD(Debugger, Cmd_GlobalFlags));
- DCmd_Register("toggleglobalflag",WRAP_METHOD(Debugger, Cmd_ToggleGlobalFlag));
DCmd_Register("localflags", WRAP_METHOD(Debugger, Cmd_LocalFlags));
DCmd_Register("locations", WRAP_METHOD(Debugger, Cmd_Locations));
DCmd_Register("gfxobjects", WRAP_METHOD(Debugger, Cmd_GfxObjects));
@@ -118,32 +117,6 @@ bool Debugger::Cmd_GlobalFlags(int argc, const char **argv) {
return true;
}
-bool Debugger::Cmd_ToggleGlobalFlag(int argc, const char **argv) {
-
- int i;
-
- switch (argc) {
- case 2:
- i = _vm->_globalFlagsNames->lookup(argv[1]);
- if (i == Table::notFound) {
- DebugPrintf("invalid flag '%s'\n", argv[1]);
- } else {
- i--;
- if ((_globalFlags & (1 << i)) == 0)
- _globalFlags |= (1 << i);
- else
- _globalFlags &= ~(1 << i);
- }
- break;
-
- default:
- DebugPrintf("toggleglobalflag <flag name>\n");
-
- }
-
- return true;
-}
-
bool Debugger::Cmd_LocalFlags(int argc, const char **argv) {
uint32 flags = _vm->getLocationFlags();
diff --git a/engines/parallaction/debug.h b/engines/parallaction/debug.h
index 5267206d04..54b578e95f 100644
--- a/engines/parallaction/debug.h
+++ b/engines/parallaction/debug.h
@@ -28,7 +28,6 @@ protected:
bool Cmd_Animations(int argc, const char **argv);
bool Cmd_LocalFlags(int argc, const char **argv);
bool Cmd_GlobalFlags(int argc, const char **argv);
- bool Cmd_ToggleGlobalFlag(int argc, const char **argv);
bool Cmd_Locations(int argc, const char **argv);
bool Cmd_GfxObjects(int argc, const char **argv);
bool Cmd_Programs(int argc, const char** argv);
diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp
index 7a28d18f17..6332600226 100644
--- a/engines/parallaction/dialogue.cpp
+++ b/engines/parallaction/dialogue.cpp
@@ -461,10 +461,6 @@ public:
void Parallaction::enterDialogueMode(ZonePtr z) {
- if (!z->u._speakDialogue) {
- return;
- }
-
debugC(1, kDebugDialogue, "Parallaction::enterDialogueMode(%s)", z->u._filename.c_str());
_dialogueMan = createDialogueManager(z);
assert(_dialogueMan);
diff --git a/engines/parallaction/exec_br.cpp b/engines/parallaction/exec_br.cpp
index 1d8724e2d8..13c1318123 100644
--- a/engines/parallaction/exec_br.cpp
+++ b/engines/parallaction/exec_br.cpp
@@ -337,7 +337,7 @@ DECLARE_COMMAND_OPCODE(speak) {
return;
}
- if (ACTIONTYPE(ctxt._cmd->_zone) == kZoneSpeak && ctxt._cmd->_zone->u._speakDialogue) {
+ if (ACTIONTYPE(ctxt._cmd->_zone) == kZoneSpeak) {
_vm->enterDialogueMode(ctxt._cmd->_zone);
} else {
_vm->_activeZone = ctxt._cmd->_zone;
diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp
index 2990d024d2..326ae2c519 100644
--- a/engines/parallaction/graphics.cpp
+++ b/engines/parallaction/graphics.cpp
@@ -538,12 +538,12 @@ GfxObj *Gfx::renderFloatingLabel(Font *font, char *text) {
setupLabelSurface(*cnv, w, h);
- font->setColor((_gameType == GType_BRA) ? 0 : 7);
+ font->setColor((_vm->getGameType() == GType_BRA) ? 0 : 7);
font->drawString((byte*)cnv->pixels + 1, cnv->w, text);
font->drawString((byte*)cnv->pixels + 1 + cnv->w * 2, cnv->w, text);
font->drawString((byte*)cnv->pixels + cnv->w, cnv->w, text);
font->drawString((byte*)cnv->pixels + 2 + cnv->w, cnv->w, text);
- font->setColor((_gameType == GType_BRA) ? 11 : 1);
+ font->setColor((_vm->getGameType() == GType_BRA) ? 11 : 1);
font->drawString((byte*)cnv->pixels + 1 + cnv->w, cnv->w, text);
} else {
w = font->getStringWidth(text);
@@ -835,7 +835,7 @@ void Gfx::setBackground(uint type, BackgroundInfo *info) {
// The PC version of BRA needs the entries 20-31 of the palette to be constant, but
// the background resource files are screwed up. The right colors come from an unused
// bitmap (pointer.bmp). Nothing is known about the Amiga version so far.
- if ((_gameType == GType_BRA) && (_vm->getPlatform() == Common::kPlatformPC)) {
+ if ((_vm->getGameType() == GType_BRA) && (_vm->getPlatform() == Common::kPlatformPC)) {
int r, g, b;
for (uint i = 16; i < 32; i++) {
_backupPal.getEntry(i, r, g, b);
diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp
index ca8f358158..7ad1be8681 100644
--- a/engines/parallaction/input.cpp
+++ b/engines/parallaction/input.cpp
@@ -203,13 +203,13 @@ int Input::updateGameInput() {
return event;
}
- if (_gameType == GType_Nippon) {
+ if (_vm->getGameType() == GType_Nippon) {
if (_hasKeyPressEvent && (_vm->getFeatures() & GF_DEMO) == 0) {
if (_keyPressed.keycode == Common::KEYCODE_l) event = kEvLoadGame;
if (_keyPressed.keycode == Common::KEYCODE_s) event = kEvSaveGame;
}
} else
- if (_gameType == GType_BRA) {
+ if (_vm->getGameType() == GType_BRA) {
if (_hasKeyPressEvent && (_vm->getFeatures() & GF_DEMO) == 0) {
if (_keyPressed.keycode == Common::KEYCODE_F5) event = kEvIngameMenu;
}
@@ -325,13 +325,8 @@ bool Input::translateGameInput() {
if ((_mouseButtons == kMouseLeftUp) && ((_activeItem._id != 0) || (ACTIONTYPE(z) == kZoneCommand))) {
- bool noWalk = z->_flags & kFlagsNoWalk; // check the explicit no-walk flag
- if (_gameType == GType_BRA) {
- // action performed on object marked for self-use do not need walk in BRA
- noWalk |= ((z->_flags & kFlagsYourself) != 0);
- }
-
- if (noWalk) {
+ if (z->_flags & kFlagsNoWalk) {
+ // character doesn't need to walk to take specified action
takeAction(z);
} else {
// action delayed: if Zone defined a moveto position the character is programmed to move there,
@@ -356,7 +351,7 @@ bool Input::translateGameInput() {
void Input::enterInventoryMode() {
Common::Point mousePos;
- getAbsoluteCursorPos(mousePos);
+ getCursorPos(mousePos);
bool hitCharacter = _vm->hitZone(kZoneYou, mousePos.x, mousePos.y);
if (hitCharacter) {
diff --git a/engines/parallaction/objects.h b/engines/parallaction/objects.h
index 36231cfcc5..50a789247f 100644
--- a/engines/parallaction/objects.h
+++ b/engines/parallaction/objects.h
@@ -88,9 +88,9 @@ enum ZoneFlags {
kFlagsNoWalk = 0x800, // Zone: character doesn't need to walk towards object to interact
// BRA specific
- kFlagsYourself = 0x1000, // BRA: marks zones used by the character on him/herself
+ kFlagsYourself = 0x1000,
kFlagsScaled = 0x2000,
- kFlagsSelfuse = 0x4000, // BRA: marks zones to be preserved across location changes (see Parallaction::freeZones)
+ kFlagsSelfuse = 0x4000,
kFlagsIsAnimation = 0x1000000, // BRA: used in walk code (trap check), to tell is a Zone is an Animation
kFlagsAnimLinked = 0x2000000
};
diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp
index ce7525345a..cb208a17ff 100644
--- a/engines/parallaction/parallaction.cpp
+++ b/engines/parallaction/parallaction.cpp
@@ -102,8 +102,7 @@ Parallaction::~Parallaction() {
Common::Error Parallaction::init() {
-
- _gameType = getGameType();
+
_engineFlags = 0;
_objectsNames = NULL;
_globalFlagsNames = NULL;
@@ -409,7 +408,7 @@ void Parallaction::drawAnimation(AnimationPtr anim) {
uint16 layer = LAYER_FOREGROUND;
uint16 scale = 100;
- switch (_gameType) {
+ switch (getGameType()) {
case GType_Nippon:
if ((anim->_flags & kFlagsNoMasked) == 0) {
// Layer in NS depends on where the animation is on the screen, for each animation.
@@ -524,7 +523,7 @@ void Parallaction::enterCommentMode(ZonePtr z) {
}
// TODO: move this balloons stuff into DialogueManager and BalloonManager
- if (_gameType == GType_Nippon) {
+ if (getGameType() == GType_Nippon) {
if (!data->_filename.empty()) {
if (data->_gfxobj == 0) {
data->_gfxobj = _disk->loadStatic(data->_filename.c_str());
@@ -541,7 +540,7 @@ void Parallaction::enterCommentMode(ZonePtr z) {
_gfx->setItem(_char._talk, 190, 80);
}
} else
- if (_gameType == GType_BRA) {
+ if (getGameType() == GType_BRA) {
_balloonMan->setSingleBalloon(data->_examineText.c_str(), 0, 0, 1, BalloonManager::kNormalColor);
_gfx->setItem(_char._talk, 10, 80);
}
@@ -652,21 +651,13 @@ bool Parallaction::pickupItem(ZonePtr z) {
return (slot != -1);
}
+// FIXME: input coordinates must be offseted to handle scrolling!
bool Parallaction::checkSpecialZoneBox(ZonePtr z, uint32 type, uint x, uint y) {
- // check if really a special zone
- if (_gameType == GType_Nippon) {
- // so-called special zones in NS have special x coordinates
- if ((z->getX() != -2) && (z->getX() != -3)) {
- return false;
- }
- }
- if (_gameType == GType_BRA) {
- // so far, special zones in BRA are only merge zones
- if (ACTIONTYPE(z) != kZoneMerge) {
- return false;
- }
+ // not a special zone
+ if ((z->getX() != -2) && (z->getX() != -3)) {
+ return false;
}
-
+
// WORKAROUND: this huge condition is needed because we made TypeData a collection of structs
// instead of an union. So, merge->_obj1 and get->_icon were just aliases in the original engine,
// but we need to check it separately here. The same workaround is applied in freeZones.
@@ -690,33 +681,7 @@ bool Parallaction::checkSpecialZoneBox(ZonePtr z, uint32 type, uint x, uint y) {
return false;
}
-bool Parallaction::checkZoneType(ZonePtr z, uint32 type) {
- if (_gameType == GType_Nippon) {
- if ((type == 0) && (ITEMTYPE(z) == 0))
- return true;
- }
-
- if (_gameType == GType_BRA) {
- if (type == 0) {
- if (ITEMTYPE(z) == 0) {
- if (ACTIONTYPE(z) != kZonePath) {
- return true;
- }
- }
- if (ACTIONTYPE(z) == kZoneDoor) {
- return true;
- }
- }
- }
-
- if (z->_type == type)
- return true;
- if (ITEMTYPE(z) == type)
- return true;
-
- return false;
-}
-
+// FIXME: input coordinates must be offseted to handle scrolling!
bool Parallaction::checkZoneBox(ZonePtr z, uint32 type, uint x, uint y) {
if (z->_flags & kFlagsRemove)
return false;
@@ -724,30 +689,29 @@ bool Parallaction::checkZoneBox(ZonePtr z, uint32 type, uint x, uint y) {
debugC(5, kDebugExec, "checkZoneBox for %s (type = %x, x = %i, y = %i)", z->_name, type, x, y);
if (!z->hitRect(x, y)) {
+
// check for special zones (items defined in common.loc)
if (checkSpecialZoneBox(z, type, x, y))
return true;
- // check if self-use zone (nothing to do with kFlagsSelfuse)
- if (_gameType == GType_Nippon) {
- if (z->getX() != -1) { // no explicit self-use flag in NS
- return false;
- }
- }
- if (_gameType == GType_BRA) {
- if (!(z->_flags & kFlagsYourself)) {
- return false;
- }
- }
- if (!_char._ani->hitFrameRect(x, y)) {
+ if (z->getX() != -1)
+ return false;
+ if (!_char._ani->hitFrameRect(x, y))
return false;
- }
- // we get here only if (x,y) hits the character and the zone is marked as self-use
}
- return checkZoneType(z, type);
+ // normal Zone
+ if ((type == 0) && (ITEMTYPE(z) == 0))
+ return true;
+ if (z->_type == type)
+ return true;
+ if (ITEMTYPE(z) == type)
+ return true;
+
+ return false;
}
+// FIXME: input coordinates must be offseted to handle scrolling!
bool Parallaction::checkLinkedAnimBox(ZonePtr z, uint32 type, uint x, uint y) {
if (z->_flags & kFlagsRemove)
return false;
@@ -763,14 +727,18 @@ bool Parallaction::checkLinkedAnimBox(ZonePtr z, uint32 type, uint x, uint y) {
return false;
}
- return checkZoneType(z, type);
-}
+ // NOTE: the implementation of the following lines is a different in the
+ // original... it is working so far, though
+ if ((type == 0) && (ITEMTYPE(z) == 0))
+ return true;
+ if (z->_type == type)
+ return true;
+ if (ITEMTYPE(z) == type)
+ return true;
-/* NOTE: hitZone needs to be passed absolute game coordinates to work.
+ return false;
+}
- When type is kZoneMerge, then x and y are the identifiers of the objects to merge,
- and the above requirement does not apply.
-*/
ZonePtr Parallaction::hitZone(uint32 type, uint16 x, uint16 y) {
uint16 _di = y;
uint16 _si = x;
@@ -784,20 +752,14 @@ ZonePtr Parallaction::hitZone(uint32 type, uint16 x, uint16 y) {
}
}
+
int16 _a, _b, _c, _d;
bool _ef;
for (AnimationList::iterator ait = _location._animations.begin(); ait != _location._animations.end(); ++ait) {
AnimationPtr a = *ait;
- _a = (a->_flags & kFlagsActive) ? 1 : 0; // _a: active Animation
-
- if (!_a) {
- if (_gameType == GType_BRA && ACTIONTYPE(a) != kZoneTrap) {
- continue;
- }
- }
-
+ _a = (a->_flags & kFlagsActive) ? 1 : 0; // _a: active Animation
_ef = a->hitFrameRect(_si, _di);
_b = ((type != 0) || (a->_type == kZoneYou)) ? 0 : 1; // _b: (no type specified) AND (Animation is not the character)
@@ -989,7 +951,7 @@ bool CharacterName::dummy() const {
}
void Parallaction::beep() {
- if (_gameType == GType_Nippon) {
+ if (getGameType() == GType_Nippon) {
_soundMan->execute(SC_SETSFXCHANNEL, 3);
_soundMan->execute(SC_SETSFXVOLUME, 127);
_soundMan->execute(SC_SETSFXLOOPING, (int32)0);
diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h
index 7bbdf79f1c..3a84aa215e 100644
--- a/engines/parallaction/parallaction.h
+++ b/engines/parallaction/parallaction.h
@@ -280,7 +280,6 @@ public:
int32 _screenWidth;
int32 _screenHeight;
int32 _screenSize;
- int _gameType;
// subsystems
Gfx *_gfx;
@@ -361,7 +360,6 @@ public:
uint32 getLocationFlags();
bool checkSpecialZoneBox(ZonePtr z, uint32 type, uint x, uint y);
bool checkZoneBox(ZonePtr z, uint32 type, uint x, uint y);
- bool checkZoneType(ZonePtr z, uint32 type);
bool checkLinkedAnimBox(ZonePtr z, uint32 type, uint x, uint y);
ZonePtr hitZone(uint32 type, uint16 x, uint16 y);
void runZone(ZonePtr z);
diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp
index 470c698a21..ee718189b5 100644
--- a/engines/parallaction/parallaction_br.cpp
+++ b/engines/parallaction/parallaction_br.cpp
@@ -196,7 +196,7 @@ void Parallaction_br::runPendingZones() {
if (_activeZone) {
z = _activeZone; // speak Zone or sound
_activeZone.reset();
- if (ACTIONTYPE(z) == kZoneSpeak && z->u._speakDialogue) {
+ if (ACTIONTYPE(z) == kZoneSpeak) {
enterDialogueMode(z);
} else {
runZone(z); // FIXME: BRA doesn't handle sound yet
@@ -206,7 +206,7 @@ void Parallaction_br::runPendingZones() {
if (_activeZone2) {
z = _activeZone2; // speak Zone or sound
_activeZone2.reset();
- if (ACTIONTYPE(z) == kZoneSpeak && z->u._speakDialogue) {
+ if (ACTIONTYPE(z) == kZoneSpeak) {
enterDialogueMode(z);
} else {
runZone(z); // FIXME: BRA doesn't handle sound yet
diff --git a/engines/parallaction/parser.cpp b/engines/parallaction/parser.cpp
index df1e91e8b4..928f3f5b74 100644
--- a/engines/parallaction/parser.cpp
+++ b/engines/parallaction/parser.cpp
@@ -44,10 +44,8 @@ Script::~Script() {
/*
* readLineIntern read a text line and prepares it for
* parsing, by stripping the leading whitespace and
- * changing tabs to spaces. It will stop on a CR, LF, or
- * SUB (0x1A), which may all occur at the end of a script
- * line.
- * Returns an empty string (length = 0) when a line
+ * changing tabs to spaces. It will stop on a CR or LF,
+ * and return an empty string (length = 0) when a line
* has no printable text in it.
*/
char *Script::readLineIntern(char *buf, size_t bufSize) {
@@ -56,8 +54,7 @@ char *Script::readLineIntern(char *buf, size_t bufSize) {
char c = _input->readSByte();
if (_input->eos())
break;
- // break if EOL
- if (c == '\n' || c == '\r' || c == (char)0x1A)
+ if (c == '\n' || c == '\r')
break;
if (c == '\t')
c = ' ';
diff --git a/engines/parallaction/parser_ns.cpp b/engines/parallaction/parser_ns.cpp
index ff24a06ceb..be72cf73a1 100644
--- a/engines/parallaction/parser_ns.cpp
+++ b/engines/parallaction/parser_ns.cpp
@@ -286,7 +286,6 @@ void LocationParser_ns::parseAnimation(AnimationList &list, char *name) {
debugC(5, kDebugParser, "parseAnimation(name: %s)", name);
if (_vm->_location.findAnimation(name)) {
- _zoneProg++;
_script->skip("endanimation");
return;
}
@@ -1306,7 +1305,6 @@ void LocationParser_ns::parseZone(ZoneList &list, char *name) {
debugC(5, kDebugParser, "parseZone(name: %s)", name);
if (_vm->_location.findZone(name)) {
- _zoneProg++;
_script->skip("endzone");
return;
}
diff --git a/engines/parallaction/sound_br.cpp b/engines/parallaction/sound_br.cpp
index 407dd86ec3..1c724ddc1c 100644
--- a/engines/parallaction/sound_br.cpp
+++ b/engines/parallaction/sound_br.cpp
@@ -172,11 +172,11 @@ bool MidiParser_MSC::loadMusic(byte *data, uint32 size) {
byte *pos = data;
- if (memcmp("MSCt", pos, 4)) {
+ uint32 signature = read4high(pos);
+ if (memcmp("tCSM", &signature, 4)) {
warning("Expected header not found in music file.");
return false;
}
- pos += 4;
_beats = read1(pos);
_ppqn = read2low(pos);
diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp
index 1b7fa97f8d..025462c558 100644
--- a/engines/saga/saga.cpp
+++ b/engines/saga/saga.cpp
@@ -316,6 +316,20 @@ Common::Error SagaEngine::run() {
syncSoundSettings();
+
+#if 0
+ // FIXME: Disabled this code for now. We want to get rid of OSystem::kFeatureAutoComputeDirtyRects
+ // and this is the last place to make use of it. We need to find out whether doing
+ // so causes any regressions. If it does, we can reenable it, if not, we can remove
+ // this code in 0.13.0.
+
+ // FIXME: This is the ugly way of reducing redraw overhead. It works
+ // well for 320x200 but it's unclear how well it will work for
+ // 640x480.
+ if (getGameId() == GID_ITE)
+ _system->setFeatureState(OSystem::kFeatureAutoComputeDirtyRects, true);
+#endif
+
int msec = 0;
_previousTicks = _system->getMillis();
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index ef7b7dcb41..e5fcbf72c2 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -52,7 +52,7 @@ struct SciScriptSignature {
// - rinse and repeat
-// daySixBeignet::changeState (4) is called when the cop goes out and sets cycles to 220.
+// daySixBeignet::changeState is called when the cop goes out and sets cycles to 220.
// this is not enough time to get to the door, so we patch that to 23 seconds
const byte gk1SignatureDay6PoliceBeignet[] = {
4,
@@ -78,8 +78,6 @@ const uint16 gk1PatchDay6PoliceBeignet[] = {
PATCH_END
};
-// sargSleeping::changeState (8) is called when the cop falls asleep and sets cycles to 220.
-// this is not enough time to get to the door, so we patch it to 42 seconds
const byte gk1SignatureDay6PoliceSleep[] = {
4,
0x35, 0x08, // ldi 08
@@ -99,27 +97,8 @@ const uint16 gk1PatchDay6PoliceSleep[] = {
PATCH_END
};
-// startOfDay5::changeState (20h) - when gabriel goes to the phone the script will hang
-const byte gk1SignatureDay5PhoneFreeze[] = {
- 5,
- 0x35, 0x03, // ldi 03
- 0x65, 0x1a, // aTop cycles
- 0x32, // jmp [end]
- +2, 3, // [skip 2 bytes, offset of jmp]
- 0x3c, // dup
- 0x35, 0x21, // ldi 21
- 0
-};
-
-const uint16 gk1PatchDay5PhoneFreeze[] = {
- 0x35, 0x06, // ldi 06
- 0x65, 0x20, // aTop ticks
- PATCH_END
-};
-
// script, description, magic DWORD, adjust
const SciScriptSignature gk1Signatures[] = {
- { 212, "day 5 phone freeze", PATCH_MAGICDWORD(0x35, 0x03, 0x65, 0x1a), 0, gk1SignatureDay5PhoneFreeze, gk1PatchDay5PhoneFreeze },
{ 230, "day 6 police beignet timer issue", PATCH_MAGICDWORD(0x34, 0xdc, 0x00, 0x65), -16, gk1SignatureDay6PoliceBeignet, gk1PatchDay6PoliceBeignet },
{ 230, "day 6 police sleep timer issue", PATCH_MAGICDWORD(0x34, 0xdc, 0x00, 0x65), -5, gk1SignatureDay6PoliceSleep, gk1PatchDay6PoliceSleep },
{ 0, NULL, 0, 0, NULL, NULL }
diff --git a/engines/sci/sound/iterator/core.cpp b/engines/sci/sound/iterator/core.cpp
new file mode 100644
index 0000000000..7cd730b3e2
--- /dev/null
+++ b/engines/sci/sound/iterator/core.cpp
@@ -0,0 +1,1013 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+/* Sound subsystem core: Event handler, sound player dispatching */
+
+#include "sci/sci.h"
+#ifdef USE_OLD_MUSIC_FUNCTIONS
+
+#include "sci/sound/iterator/core.h"
+#include "sci/sound/iterator/iterator.h"
+#include "sci/sound/drivers/mididriver.h"
+
+#include "common/system.h"
+#include "common/timer.h"
+
+#include "sound/mixer.h"
+
+namespace Sci {
+
+/* Plays a song iterator that found a PCM through a PCM device, if possible
+** Parameters: (SongIterator *) it: The iterator to play
+** (SongHandle) handle: Debug handle
+** Returns : (int) 0 if the effect will not be played, nonzero if it will
+** This assumes that the last call to 'it->next()' returned SI_PCM.
+*/
+static int sfx_play_iterator_pcm(SongIterator *it, SongHandle handle);
+
+
+#pragma mark -
+
+
+class SfxPlayer {
+public:
+ /** Number of voices that can play simultaneously */
+ int _polyphony;
+
+protected:
+ SciVersion _soundVersion;
+ MidiPlayer *_mididrv;
+
+ SongIterator *_iterator;
+ Audio::Timestamp _wakeupTime;
+ Audio::Timestamp _currentTime;
+ uint32 _pauseTimeDiff;
+
+ bool _paused;
+ bool _iteratorIsDone;
+ uint32 _tempo;
+
+ Common::Mutex _mutex;
+ int _volume;
+
+ void play_song(SongIterator *it);
+ static void player_timer_callback(void *refCon);
+
+public:
+ SfxPlayer(SciVersion soundVersion);
+ ~SfxPlayer();
+
+ /**
+ * Initializes the player.
+ * @param resMan a resource manager for driver initialization
+ * @param expected_latency expected delay in between calls to 'maintenance' (in microseconds)
+ * @return Common::kNoError on success, Common::kUnknownError on failure
+ */
+ Common::Error init(ResourceManager *resMan, int expected_latency);
+
+ /**
+ * Adds an iterator to the song player
+ * @param it The iterator to play
+ * @param start_time The time to assume as the time the first MIDI command executes at
+ * @return Common::kNoError on success, Common::kUnknownError on failure
+ *
+ * The iterator should not be cloned (to avoid memory leaks) and
+ * may be modified according to the needs of the player.
+ * Implementors may use the 'sfx_iterator_combine()' function
+ * to add iterators onto their already existing iterators.
+ */
+ Common::Error add_iterator(SongIterator *it, uint32 start_time);
+
+ /**
+ * Stops the currently playing song and deletes the associated iterator.
+ * @return Common::kNoError on success, Common::kUnknownError on failure
+ */
+ Common::Error stop();
+
+ /**
+ * Transmits a song iterator message to the active song.
+ * @param msg the message to transmit
+ * @return Common::kNoError on success, Common::kUnknownError on failure
+ */
+ Common::Error iterator_message(const SongIterator::Message &msg);
+
+ /**
+ * Pauses song playing.
+ * @return Common::kNoError on success, Common::kUnknownError on failure
+ */
+ Common::Error pause();
+
+ /**
+ * Resumes song playing after a pause.
+ * @return Common::kNoError on success, Common::kUnknownError on failure
+ */
+ Common::Error resume();
+
+ /**
+ * Pass a raw MIDI event to the synth.
+ * @param argc length of buffer holding the midi event
+ * @param argv the buffer itself
+ */
+ void tell_synth(int buf_nr, byte *buf);
+
+ void setVolume(int vol);
+
+ int getVolume();
+};
+
+SfxPlayer::SfxPlayer(SciVersion soundVersion)
+ : _soundVersion(soundVersion), _wakeupTime(0, SFX_TICKS_PER_SEC), _currentTime(0, 1) {
+ _polyphony = 0;
+
+ _mididrv = 0;
+
+ _iterator = NULL;
+ _pauseTimeDiff = 0;
+
+ _paused = false;
+ _iteratorIsDone = false;
+ _tempo = 0;
+
+ _volume = 15;
+}
+
+SfxPlayer::~SfxPlayer() {
+ if (_mididrv) {
+ _mididrv->close();
+ delete _mididrv;
+ }
+ delete _iterator;
+ _iterator = NULL;
+}
+
+void SfxPlayer::play_song(SongIterator *it) {
+ while (_iterator && _wakeupTime.msecsDiff(_currentTime) <= 0) {
+ int delay;
+ byte buf[8];
+ int result;
+
+ switch ((delay = songit_next(&(_iterator),
+ buf, &result,
+ IT_READER_MASK_ALL
+ | IT_READER_MAY_FREE
+ | IT_READER_MAY_CLEAN))) {
+
+ case SI_FINISHED:
+ delete _iterator;
+ _iterator = NULL;
+ _iteratorIsDone = true;
+ return;
+
+ case SI_IGNORE:
+ case SI_LOOP:
+ case SI_RELATIVE_CUE:
+ case SI_ABSOLUTE_CUE:
+ break;
+
+ case SI_PCM:
+ sfx_play_iterator_pcm(_iterator, 0);
+ break;
+
+ case 0:
+ static_cast<MidiDriver *>(_mididrv)->send(buf[0], buf[1], buf[2]);
+
+ break;
+
+ default:
+ _wakeupTime = _wakeupTime.addFrames(delay);
+ }
+ }
+}
+
+void SfxPlayer::tell_synth(int buf_nr, byte *buf) {
+ byte op1 = (buf_nr < 2 ? 0 : buf[1]);
+ byte op2 = (buf_nr < 3 ? 0 : buf[2]);
+
+ static_cast<MidiDriver *>(_mididrv)->send(buf[0], op1, op2);
+}
+
+void SfxPlayer::player_timer_callback(void *refCon) {
+ SfxPlayer *thePlayer = (SfxPlayer *)refCon;
+ assert(refCon);
+ Common::StackLock lock(thePlayer->_mutex);
+
+ if (thePlayer->_iterator && !thePlayer->_iteratorIsDone && !thePlayer->_paused) {
+ thePlayer->play_song(thePlayer->_iterator);
+ }
+
+ thePlayer->_currentTime = thePlayer->_currentTime.addFrames(1);
+}
+
+/* API implementation */
+
+Common::Error SfxPlayer::init(ResourceManager *resMan, int expected_latency) {
+ MidiDriverType musicDriver = MidiDriver::detectMusicDriver(MDT_PCSPK | MDT_ADLIB);
+
+ switch (musicDriver) {
+ case MD_ADLIB:
+ // FIXME: There's no Amiga sound option, so we hook it up to AdLib
+ if (g_sci->getPlatform() == Common::kPlatformAmiga)
+ _mididrv = MidiPlayer_Amiga_create(_soundVersion);
+ else
+ _mididrv = MidiPlayer_AdLib_create(_soundVersion);
+ break;
+ case MD_PCJR:
+ _mididrv = MidiPlayer_PCJr_create(_soundVersion);
+ break;
+ case MD_PCSPK:
+ _mididrv = MidiPlayer_PCSpeaker_create(_soundVersion);
+ break;
+ default:
+ break;
+ }
+
+ assert(_mididrv);
+
+ _polyphony = _mididrv->getPolyphony();
+
+ _tempo = _mididrv->getBaseTempo();
+ uint32 time = g_system->getMillis();
+ _currentTime = Audio::Timestamp(time, 1000000 / _tempo);
+ _wakeupTime = Audio::Timestamp(time, SFX_TICKS_PER_SEC);
+
+ _mididrv->setTimerCallback(this, player_timer_callback);
+ _mididrv->open(resMan);
+ _mididrv->setVolume(_volume);
+
+ return Common::kNoError;
+}
+
+Common::Error SfxPlayer::add_iterator(SongIterator *it, uint32 start_time) {
+ Common::StackLock lock(_mutex);
+ SIMSG_SEND(it, SIMSG_SET_PLAYMASK(_mididrv->getPlayId()));
+ SIMSG_SEND(it, SIMSG_SET_RHYTHM(_mididrv->hasRhythmChannel()));
+
+ if (_iterator == NULL) {
+ // Resync with clock
+ _currentTime = Audio::Timestamp(g_system->getMillis(), 1000000 / _tempo);
+ _wakeupTime = Audio::Timestamp(start_time, SFX_TICKS_PER_SEC);
+ }
+
+ _iterator = sfx_iterator_combine(_iterator, it);
+ _iteratorIsDone = false;
+
+ return Common::kNoError;
+}
+
+Common::Error SfxPlayer::stop() {
+ debug(3, "Player: Stopping song iterator %p", (void *)_iterator);
+ Common::StackLock lock(_mutex);
+ delete _iterator;
+ _iterator = NULL;
+ for (int i = 0; i < MIDI_CHANNELS; i++)
+ static_cast<MidiDriver *>(_mididrv)->send(0xb0 + i, SCI_MIDI_CHANNEL_NOTES_OFF, 0);
+
+ return Common::kNoError;
+}
+
+Common::Error SfxPlayer::iterator_message(const SongIterator::Message &msg) {
+ Common::StackLock lock(_mutex);
+ if (!_iterator) {
+ return Common::kUnknownError;
+ }
+
+ songit_handle_message(&_iterator, msg);
+
+ return Common::kNoError;
+}
+
+Common::Error SfxPlayer::pause() {
+ Common::StackLock lock(_mutex);
+
+ _paused = true;
+ _pauseTimeDiff = _wakeupTime.msecsDiff(_currentTime);
+
+ _mididrv->playSwitch(false);
+
+ return Common::kNoError;
+}
+
+Common::Error SfxPlayer::resume() {
+ Common::StackLock lock(_mutex);
+
+ _wakeupTime = Audio::Timestamp(_currentTime.msecs() + _pauseTimeDiff, SFX_TICKS_PER_SEC);
+ _mididrv->playSwitch(true);
+ _paused = false;
+
+ return Common::kNoError;
+}
+
+void SfxPlayer::setVolume(int vol) {
+ _mididrv->setVolume(vol);
+}
+
+int SfxPlayer::getVolume() {
+ return _mididrv->getVolume();
+}
+
+#pragma mark -
+
+void SfxState::sfx_reset_player() {
+ if (_player)
+ _player->stop();
+}
+
+void SfxState::sfx_player_tell_synth(int buf_nr, byte *buf) {
+ if (_player)
+ _player->tell_synth(buf_nr, buf);
+}
+
+int SfxState::sfx_get_player_polyphony() {
+ if (_player)
+ return _player->_polyphony;
+ else
+ return 0;
+}
+
+SfxState::SfxState() {
+ _player = NULL;
+ _it = NULL;
+ _flags = 0;
+ _song = NULL;
+ _suspended = 0;
+}
+
+SfxState::~SfxState() {
+}
+
+
+void SfxState::freezeTime() {
+ /* Freezes the top song delay time */
+ const Audio::Timestamp ctime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC);
+ Song *song = _song;
+
+ while (song) {
+ song->_delay = song->_wakeupTime.frameDiff(ctime);
+ if (song->_delay < 0)
+ song->_delay = 0;
+
+ song = song->_nextPlaying;
+ }
+}
+
+void SfxState::thawTime() {
+ /* inverse of freezeTime() */
+ const Audio::Timestamp ctime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC);
+ Song *song = _song;
+
+ while (song) {
+ song->_wakeupTime = ctime.addFrames(song->_delay);
+
+ song = song->_nextPlaying;
+ }
+}
+
+#if 0
+// Unreferenced - removed
+static void _dump_playing_list(SfxState *self, char *msg) {
+ Song *song = self->_song;
+
+ fprintf(stderr, "[] Song list : [ ");
+ song = *(self->_songlib.lib);
+ while (song) {
+ fprintf(stderr, "%08lx:%d ", song->handle, song->_status);
+ song = song->_nextPlaying;
+ }
+ fprintf(stderr, "]\n");
+
+ fprintf(stderr, "[] Play list (%s) : [ " , msg);
+
+ while (song) {
+ fprintf(stderr, "%08lx ", song->handle);
+ song = song->_nextPlaying;
+ }
+
+ fprintf(stderr, "]\n");
+}
+#endif
+
+#if 0
+static void _dump_songs(SfxState *self) {
+ Song *song = self->_song;
+
+ fprintf(stderr, "Cue iterators:\n");
+ song = *(self->_songlib.lib);
+ while (song) {
+ fprintf(stderr, " **\tHandle %08x (p%d): status %d\n",
+ song->handle, song->_priority, song->_status);
+ SIMSG_SEND(song->_it, SIMSG_PRINT(1));
+ song = song->_next;
+ }
+
+ if (self->_player) {
+ fprintf(stderr, "Audio iterator:\n");
+ self->_player->iterator_message(SongIterator::Message(0, SIMSG_PRINT(1)));
+ }
+}
+#endif
+
+bool SfxState::isPlaying(Song *song) {
+ Song *playing_song = _song;
+
+ /* _dump_playing_list(this, "is-playing");*/
+
+ while (playing_song) {
+ if (playing_song == song)
+ return true;
+ playing_song = playing_song->_nextPlaying;
+ }
+ return false;
+}
+
+void SfxState::setSongStatus(Song *song, int status) {
+ const Audio::Timestamp ctime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC);
+
+ switch (status) {
+
+ case SOUND_STATUS_STOPPED:
+ // Reset
+ song->_it->init();
+ break;
+
+ case SOUND_STATUS_SUSPENDED:
+ case SOUND_STATUS_WAITING:
+ if (song->_status == SOUND_STATUS_PLAYING) {
+ // Update delay, set wakeup_time
+ song->_delay += song->_wakeupTime.frameDiff(ctime);
+ song->_wakeupTime = ctime;
+ }
+ if (status == SOUND_STATUS_SUSPENDED)
+ break;
+
+ /* otherwise... */
+
+ case SOUND_STATUS_PLAYING:
+ if (song->_status == SOUND_STATUS_STOPPED) {
+ // Starting anew
+ song->_wakeupTime = ctime;
+ }
+
+ if (isPlaying(song))
+ status = SOUND_STATUS_PLAYING;
+ else
+ status = SOUND_STATUS_WAITING;
+ break;
+
+ default:
+ fprintf(stderr, "%s L%d: Attempt to set invalid song"
+ " state %d!\n", __FILE__, __LINE__, status);
+ return;
+
+ }
+ song->_status = status;
+}
+
+/* Update internal state iff only one song may be played */
+void SfxState::updateSingleSong() {
+ Song *newsong = _songlib.findFirstActive();
+
+ if (newsong != _song) {
+ freezeTime(); /* Store song delay time */
+
+ if (_player)
+ _player->stop();
+
+ if (newsong) {
+ if (!newsong->_it)
+ return; /* Restore in progress and not ready for this yet */
+
+ /* Change song */
+ if (newsong->_status == SOUND_STATUS_WAITING)
+ setSongStatus(newsong, SOUND_STATUS_PLAYING);
+
+ /* Change instrument mappings */
+ } else {
+ /* Turn off sound */
+ }
+ if (_song) {
+ if (_song->_status == SOUND_STATUS_PLAYING)
+ setSongStatus(newsong, SOUND_STATUS_WAITING);
+ }
+
+ Common::String debugMessage = "[SFX] Changing active song:";
+ if (!_song) {
+ debugMessage += " New song:";
+ } else {
+ char tmp[50];
+ sprintf(tmp, " pausing %08lx, now playing ", _song->_handle);
+ debugMessage += tmp;
+ }
+
+ if (newsong) {
+ char tmp[20];
+ sprintf(tmp, "%08lx\n", newsong->_handle);
+ debugMessage += tmp;
+ } else {
+ debugMessage += " none\n";
+ }
+
+ debugC(2, kDebugLevelSound, "%s", debugMessage.c_str());
+
+ _song = newsong;
+ thawTime(); /* Recover song delay time */
+
+ if (newsong && _player) {
+ SongIterator *clonesong = newsong->_it->clone(newsong->_delay);
+
+ _player->add_iterator(clonesong, newsong->_wakeupTime.msecs());
+ }
+ }
+}
+
+
+void SfxState::updateMultiSong() {
+ Song *oldfirst = _song;
+ Song *oldseeker;
+ Song *newsong = _songlib.findFirstActive();
+ Song *newseeker;
+ Song not_playing_anymore; /* Dummy object, referenced by
+ ** songs which are no longer
+ ** active. */
+
+ /* _dump_playing_list(this, "before");*/
+ freezeTime(); /* Store song delay time */
+
+ // WORKAROUND: sometimes, newsong can be NULL (e.g. in SQ4).
+ // Handle this here, so that we avoid a crash
+ if (!newsong) {
+ // Iterators should get freed when there's only one song left playing
+ if(oldfirst && oldfirst->_status == SOUND_STATUS_STOPPED) {
+ debugC(2, kDebugLevelSound, "[SFX] Stopping song %lx", oldfirst->_handle);
+ if (_player && oldfirst->_it)
+ _player->iterator_message(SongIterator::Message(oldfirst->_it->ID, SIMSG_STOP));
+ }
+ return;
+ }
+
+ for (newseeker = newsong; newseeker;
+ newseeker = newseeker->_nextPlaying) {
+ if (!newseeker || !newseeker->_it)
+ return; /* Restore in progress and not ready for this yet */
+ }
+
+ /* First, put all old songs into the 'stopping' list and
+ ** mark their 'next-playing' as not_playing_anymore. */
+ for (oldseeker = oldfirst; oldseeker;
+ oldseeker = oldseeker->_nextStopping) {
+ oldseeker->_nextStopping = oldseeker->_nextPlaying;
+ oldseeker->_nextPlaying = &not_playing_anymore;
+
+ if (oldseeker == oldseeker->_nextPlaying) {
+ error("updateMultiSong() failed. Breakpoint in %s, line %d", __FILE__, __LINE__);
+ }
+ }
+
+ /* Second, re-generate the new song queue. */
+ for (newseeker = newsong; newseeker; newseeker = newseeker->_nextPlaying) {
+ newseeker->_nextPlaying = _songlib.findNextActive(newseeker);
+
+ if (newseeker == newseeker->_nextPlaying) {
+ error("updateMultiSong() failed. Breakpoint in %s, line %d", __FILE__, __LINE__);
+ }
+ }
+ /* We now need to update the currently playing song list, because we're
+ ** going to use some functions that require this list to be in a sane
+ ** state (particularly isPlaying(), indirectly */
+ _song = newsong;
+
+ /* Third, stop all old songs */
+ for (oldseeker = oldfirst; oldseeker;
+ oldseeker = oldseeker->_nextStopping)
+ if (oldseeker->_nextPlaying == &not_playing_anymore) {
+ setSongStatus(oldseeker, SOUND_STATUS_SUSPENDED);
+ debugC(2, kDebugLevelSound, "[SFX] Stopping song %lx", oldseeker->_handle);
+
+ if (_player && oldseeker->_it)
+ _player->iterator_message(SongIterator::Message(oldseeker->_it->ID, SIMSG_STOP));
+ oldseeker->_nextPlaying = NULL; /* Clear this pointer; we don't need the tag anymore */
+ }
+
+ for (newseeker = newsong; newseeker; newseeker = newseeker->_nextPlaying) {
+ if (newseeker->_status != SOUND_STATUS_PLAYING && _player) {
+ debugC(2, kDebugLevelSound, "[SFX] Adding song %lx", newseeker->_it->ID);
+
+ SongIterator *clonesong = newseeker->_it->clone(newseeker->_delay);
+ _player->add_iterator(clonesong, g_system->getMillis());
+ }
+ setSongStatus(newseeker, SOUND_STATUS_PLAYING);
+ }
+
+ _song = newsong;
+ thawTime();
+ /* _dump_playing_list(this, "after");*/
+}
+
+/* Update internal state */
+void SfxState::update() {
+ if (_flags & SFX_STATE_FLAG_MULTIPLAY)
+ updateMultiSong();
+ else
+ updateSingleSong();
+}
+
+static int sfx_play_iterator_pcm(SongIterator *it, SongHandle handle) {
+#ifdef DEBUG_SONG_API
+ fprintf(stderr, "[sfx-core] Playing PCM: %08lx\n", handle);
+#endif
+ if (g_system->getMixer()->isReady()) {
+ Audio::AudioStream *newfeed = it->getAudioStream();
+ if (newfeed) {
+ g_system->getMixer()->playStream(Audio::Mixer::kSFXSoundType, 0, newfeed);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#define DELAY (1000000 / SFX_TICKS_PER_SEC)
+
+void SfxState::sfx_init(ResourceManager *resMan, int flags, SciVersion soundVersion) {
+ _songlib._lib = 0;
+ _song = NULL;
+ _flags = flags;
+
+ _player = NULL;
+
+ if (flags & SFX_STATE_FLAG_NOSOUND) {
+ warning("[SFX] Sound disabled");
+ return;
+ }
+
+#ifdef DEBUG_SONG_API
+ fprintf(stderr, "[sfx-core] Initialising: flags=%x\n", flags);
+#endif
+
+ /*-------------------*/
+ /* Initialise player */
+ /*-------------------*/
+
+ if (!resMan) {
+ warning("[SFX] Warning: No resource manager present, cannot initialise player");
+ return;
+ }
+
+ _player = new SfxPlayer(soundVersion);
+
+ if (!_player) {
+ warning("[SFX] No song player found");
+ return;
+ }
+
+ if (_player->init(resMan, DELAY / 1000)) {
+ warning("[SFX] Song player reported error, disabled");
+ delete _player;
+ _player = NULL;
+ }
+
+ _resMan = resMan;
+}
+
+void SfxState::sfx_exit() {
+#ifdef DEBUG_SONG_API
+ fprintf(stderr, "[sfx-core] Uninitialising\n");
+#endif
+
+ delete _player;
+ _player = 0;
+
+ g_system->getMixer()->stopAll();
+
+ _songlib.freeSounds();
+}
+
+void SfxState::sfx_suspend(bool suspend) {
+#ifdef DEBUG_SONG_API
+ fprintf(stderr, "[sfx-core] Suspending? = %d\n", suspend);
+#endif
+ if (suspend && (!_suspended)) {
+ /* suspend */
+
+ freezeTime();
+ if (_player)
+ _player->pause();
+ /* Suspend song player */
+
+ } else if (!suspend && (_suspended)) {
+ /* unsuspend */
+
+ thawTime();
+ if (_player)
+ _player->resume();
+
+ /* Unsuspend song player */
+ }
+
+ _suspended = suspend;
+}
+
+int SfxState::sfx_poll(SongHandle *handle, int *cue) {
+ if (!_song)
+ return 0; /* No milk today */
+
+ *handle = _song->_handle;
+
+#ifdef DEBUG_SONG_API
+ fprintf(stderr, "[sfx-core] Polling any (%08lx)\n", *handle);
+#endif
+ return sfx_poll_specific(*handle, cue);
+}
+
+int SfxState::sfx_poll_specific(SongHandle handle, int *cue) {
+ const Audio::Timestamp ctime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC);
+ Song *song = _song;
+
+ while (song && song->_handle != handle)
+ song = song->_nextPlaying;
+
+ if (!song)
+ return 0; /* Song not playing */
+
+ debugC(2, kDebugLevelSound, "[SFX:CUE] Polled song %08lx ", handle);
+
+ while (1) {
+ if (song->_wakeupTime.frameDiff(ctime) > 0)
+ return 0; /* Patience, young hacker! */
+
+ byte buf[8];
+ int result = songit_next(&(song->_it), buf, cue, IT_READER_MASK_ALL);
+
+ switch (result) {
+
+ case SI_FINISHED:
+ setSongStatus(song, SOUND_STATUS_STOPPED);
+ update();
+ /* ...fall through... */
+ case SI_LOOP:
+ case SI_RELATIVE_CUE:
+ case SI_ABSOLUTE_CUE:
+ if (result == SI_FINISHED)
+ debugC(2, kDebugLevelSound, " => finished");
+ else {
+ if (result == SI_LOOP)
+ debugC(2, kDebugLevelSound, " => Loop: %d (0x%x)", *cue, *cue);
+ else
+ debugC(2, kDebugLevelSound, " => Cue: %d (0x%x)", *cue, *cue);
+
+ }
+ return result;
+
+ default:
+ if (result > 0)
+ song->_wakeupTime = song->_wakeupTime.addFrames(result);
+
+ /* Delay */
+ break;
+ }
+ }
+
+}
+
+
+/*****************/
+/* Song basics */
+/*****************/
+
+void SfxState::sfx_add_song(SongIterator *it, int priority, SongHandle handle, int number) {
+ Song *song = _songlib.findSong(handle);
+
+#ifdef DEBUG_SONG_API
+ fprintf(stderr, "[sfx-core] Adding song: %08lx at %d, it=%p\n", handle, priority, it);
+#endif
+ if (!it) {
+ error("[SFX] Attempt to add empty song with handle %08lx", handle);
+ return;
+ }
+
+ it->init();
+
+ /* If we're already playing this, stop it */
+ /* Tell player to shut up */
+// _dump_songs(this);
+
+ if (_player)
+ _player->iterator_message(SongIterator::Message(handle, SIMSG_STOP));
+
+ if (song) {
+ setSongStatus( song, SOUND_STATUS_STOPPED);
+
+ fprintf(stderr, "Overwriting old song (%08lx) ...\n", handle);
+ if (song->_status == SOUND_STATUS_PLAYING || song->_status == SOUND_STATUS_SUSPENDED) {
+ delete it;
+ error("Unexpected (error): Song %ld still playing/suspended (%d)",
+ handle, song->_status);
+ return;
+ } else {
+ _songlib.removeSong(handle); /* No duplicates */
+ }
+
+ }
+
+ song = new Song(handle, it, priority);
+ song->_resourceNum = number;
+ song->_hold = 0;
+ song->_loops = 0;
+ song->_wakeupTime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC);
+ _songlib.addSong(song);
+ _song = NULL; /* As above */
+ update();
+
+ return;
+}
+
+void SfxState::sfx_remove_song(SongHandle handle) {
+#ifdef DEBUG_SONG_API
+ fprintf(stderr, "[sfx-core] Removing song: %08lx\n", handle);
+#endif
+ if (_song && _song->_handle == handle)
+ _song = NULL;
+
+ _songlib.removeSong(handle);
+ update();
+}
+
+
+
+/**********************/
+/* Song modifications */
+/**********************/
+
+#define ASSERT_SONG(s) if (!(s)) { warning("Looking up song handle %08lx failed in %s, L%d", handle, __FILE__, __LINE__); return; }
+
+void SfxState::sfx_song_set_status(SongHandle handle, int status) {
+ Song *song = _songlib.findSong(handle);
+ ASSERT_SONG(song);
+#ifdef DEBUG_SONG_API
+ fprintf(stderr, "[sfx-core] Setting song status to %d"
+ " (0:stop, 1:play, 2:susp, 3:wait): %08lx\n", status, handle);
+#endif
+
+ setSongStatus(song, status);
+
+ update();
+}
+
+void SfxState::sfx_song_set_fade(SongHandle handle, fade_params_t *params) {
+#ifdef DEBUG_SONG_API
+ static const char *stopmsg[] = {"??? Should not happen", "Do not stop afterwards", "Stop afterwards"};
+#endif
+ Song *song = _songlib.findSong(handle);
+
+ ASSERT_SONG(song);
+
+#ifdef DEBUG_SONG_API
+ fprintf(stderr, "[sfx-core] Setting fade params of %08lx to "
+ "final volume %d in steps of %d per %d ticks. %s.",
+ handle, fade->final_volume, fade->step_size, fade->ticks_per_step,
+ stopmsg[fade->action]);
+#endif
+
+ SIMSG_SEND_FADE(song->_it, params);
+
+ update();
+}
+
+void SfxState::sfx_song_renice(SongHandle handle, int priority) {
+ Song *song = _songlib.findSong(handle);
+ ASSERT_SONG(song);
+#ifdef DEBUG_SONG_API
+ fprintf(stderr, "[sfx-core] Renicing song %08lx to %d\n",
+ handle, priority);
+#endif
+
+ song->_priority = priority;
+
+ update();
+}
+
+void SfxState::sfx_song_set_loops(SongHandle handle, int loops) {
+ Song *song = _songlib.findSong(handle);
+ SongIterator::Message msg = SongIterator::Message(handle, SIMSG_SET_LOOPS(loops));
+ ASSERT_SONG(song);
+
+ song->_loops = loops;
+#ifdef DEBUG_SONG_API
+ fprintf(stderr, "[sfx-core] Setting loops on %08lx to %d\n",
+ handle, loops);
+#endif
+ songit_handle_message(&(song->_it), msg);
+
+ if (_player/* && _player->send_iterator_message*/)
+ /* FIXME: The above should be optional! */
+ _player->iterator_message(msg);
+}
+
+void SfxState::sfx_song_set_hold(SongHandle handle, int hold) {
+ Song *song = _songlib.findSong(handle);
+ SongIterator::Message msg = SongIterator::Message(handle, SIMSG_SET_HOLD(hold));
+ ASSERT_SONG(song);
+
+ song->_hold = hold;
+#ifdef DEBUG_SONG_API
+ fprintf(stderr, "[sfx-core] Setting hold on %08lx to %d\n",
+ handle, hold);
+#endif
+ songit_handle_message(&(song->_it), msg);
+
+ if (_player/* && _player->send_iterator_message*/)
+ /* FIXME: The above should be optional! */
+ _player->iterator_message(msg);
+}
+
+/* Different from the one in iterator.c */
+static const int MIDI_cmdlen[16] = {0, 0, 0, 0, 0, 0, 0, 0,
+ 3, 3, 0, 3, 2, 0, 3, 0
+ };
+
+static const SongHandle midi_send_base = 0xffff0000;
+
+Common::Error SfxState::sfx_send_midi(SongHandle handle, int channel,
+ int command, int arg1, int arg2) {
+ byte buffer[5];
+
+ /* Yes, in that order. SCI channel mutes are actually done via
+ a counting semaphore. 0 means to decrement the counter, 1
+ to increment it. */
+ static const char *channel_state[] = {"ON", "OFF"};
+
+ if (command == 0xb0 &&
+ arg1 == SCI_MIDI_CHANNEL_MUTE) {
+ warning("TODO: channel mute (channel %d %s)", channel, channel_state[arg2]);
+ /* We need to have a GET_PLAYMASK interface to use
+ here. SET_PLAYMASK we've got.
+ */
+ return Common::kNoError;
+ }
+
+ buffer[0] = channel | command; /* No channel remapping yet */
+
+ switch (command) {
+ case 0x80 :
+ case 0x90 :
+ case 0xb0 :
+ buffer[1] = arg1 & 0xff;
+ buffer[2] = arg2 & 0xff;
+ break;
+ case 0xc0 :
+ buffer[1] = arg1 & 0xff;
+ break;
+ case 0xe0 :
+ buffer[1] = (arg1 & 0x7f) | 0x80;
+ buffer[2] = (arg1 & 0xff00) >> 7;
+ break;
+ default:
+ warning("Unexpected explicit MIDI command %02x", command);
+ return Common::kUnknownError;
+ }
+
+ if (_player)
+ _player->tell_synth(MIDI_cmdlen[command >> 4], buffer);
+ return Common::kNoError;
+}
+
+int SfxState::sfx_getVolume() {
+ return _player->getVolume();
+}
+
+void SfxState::sfx_setVolume(int volume) {
+ _player->setVolume(volume);
+}
+
+void SfxState::sfx_all_stop() {
+#ifdef DEBUG_SONG_API
+ fprintf(stderr, "[sfx-core] All stop\n");
+#endif
+
+ _songlib.freeSounds();
+ update();
+}
+
+} // End of namespace Sci
+
+#endif // USE_OLD_MUSIC_FUNCTIONS
diff --git a/engines/sci/sound/iterator/core.h b/engines/sci/sound/iterator/core.h
new file mode 100644
index 0000000000..a44fe2ecae
--- /dev/null
+++ b/engines/sci/sound/iterator/core.h
@@ -0,0 +1,209 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+/* Sound engine */
+#ifndef SCI_SFX_CORE_H
+#define SCI_SFX_CORE_H
+
+#include "common/error.h"
+
+#include "sci/sci.h" // for USE_OLD_MUSIC_FUNCTIONS
+
+#ifdef USE_OLD_MUSIC_FUNCTIONS
+#include "sci/sound/iterator/songlib.h"
+#include "sci/resource.h"
+
+namespace Sci {
+
+class SfxPlayer;
+class SongIterator;
+struct fade_params_t;
+
+#define SFX_TICKS_PER_SEC 60 /* MIDI ticks per second */
+
+
+#define SFX_STATE_FLAG_MULTIPLAY (1 << 0) /* More than one song playable
+** simultaneously ? */
+#define SFX_STATE_FLAG_NOSOUND (1 << 1) /* Completely disable sound playing */
+
+class SfxState {
+private:
+ SfxPlayer *_player;
+
+public: // FIXME, make private
+ SongIterator *_it; /**< The song iterator at the heart of things */
+ uint _flags; /**< SFX_STATE_FLAG_* */
+ SongLibrary _songlib; /**< Song library */
+ Song *_song; /**< Active song, or start of active song chain */
+ bool _suspended; /**< Whether we are suspended */
+ ResourceManager *_resMan;
+
+public:
+ SfxState();
+ ~SfxState();
+
+ /***********/
+ /* General */
+ /***********/
+
+ /* Initializes the sound engine
+ ** Parameters: (ResourceManager *) resMan: Resource manager for initialization
+ ** (int) flags: SFX_STATE_FLAG_*
+ */
+ void sfx_init(ResourceManager *resMan, int flags, SciVersion soundVersion);
+
+ /** Deinitializes the sound subsystem. */
+ void sfx_exit();
+
+ /* Suspends/unsuspends the sound sybsystem
+ ** Parameters: (int) suspend: Whether to suspend (non-null) or to unsuspend
+ */
+ void sfx_suspend(bool suspend);
+
+ /* Polls the sound server for cues etc.
+ ** Returns : (int) 0 if the cue queue is empty, SI_LOOP, SI_CUE, or SI_FINISHED otherwise
+ ** (SongHandle) *handle: The affected handle
+ ** (int) *cue: The sound cue number (if SI_CUE), or the loop number (if SI_LOOP)
+ */
+ int sfx_poll(SongHandle *handle, int *cue);
+
+ /* Polls the sound server for cues etc.
+ ** Parameters: (SongHandle) handle: The handle to poll
+ ** Returns : (int) 0 if the cue queue is empty, SI_LOOP, SI_CUE, or SI_FINISHED otherwise
+ ** (int) *cue: The sound cue number (if SI_CUE), or the loop number (if SI_LOOP)
+ */
+ int sfx_poll_specific(SongHandle handle, int *cue);
+
+ /* Determines the current global volume settings
+ ** Returns : (int) The global volume, between 0 (silent) and 127 (max. volume)
+ */
+ int sfx_getVolume();
+
+ /* Determines the current global volume settings
+ ** Parameters: (int) volume: The new global volume, between 0 and 127 (see above)
+ */
+ void sfx_setVolume(int volume);
+
+ /* Stops all songs currently playing, purges song library
+ */
+ void sfx_all_stop();
+
+
+ /*****************/
+ /* Song basics */
+ /*****************/
+
+ /* Adds a song to the internal sound library
+ ** Parameters: (SongIterator *) it: The iterator describing the song
+ ** (int) priority: Initial song priority (higher <-> more important)
+ ** (SongHandle) handle: The handle to associate with the song
+ */
+ void sfx_add_song(SongIterator *it, int priority, SongHandle handle, int resnum);
+
+
+ /* Deletes a song and its associated song iterator from the song queue
+ ** Parameters: (SongHandle) handle: The song to remove
+ */
+ void sfx_remove_song(SongHandle handle);
+
+
+ /**********************/
+ /* Song modifications */
+ /**********************/
+
+
+ /* Sets the song status, i.e. whether it is playing, suspended, or stopped.
+ ** Parameters: (SongHandle) handle: Handle of the song to modify
+ ** (int) status: The song status the song should assume
+ ** WAITING and PLAYING are set implicitly and essentially describe the same state
+ ** as far as this function is concerned.
+ */
+ void sfx_song_set_status(SongHandle handle, int status);
+
+ /* Sets the new song priority
+ ** Parameters: (SongHandle) handle: The handle to modify
+ ** (int) priority: The priority to set
+ */
+ void sfx_song_renice(SongHandle handle, int priority);
+
+ /* Sets the number of loops for the specified song
+ ** Parameters: (SongHandle) handle: The song handle to reference
+ ** (int) loops: Number of loops to set
+ */
+ void sfx_song_set_loops(SongHandle handle, int loops);
+
+ /* Sets the number of loops for the specified song
+ ** Parameters: (SongHandle) handle: The song handle to reference
+ ** (int) hold: Number of loops to setn
+ */
+ void sfx_song_set_hold(SongHandle handle, int hold);
+
+ /* Instructs a song to be faded out
+ ** Parameters: (SongHandle) handle: The song handle to reference
+ ** (fade_params_t *) fade_setup: The precise fade-out configuration to use
+ */
+ void sfx_song_set_fade(SongHandle handle, fade_params_t *fade_setup);
+
+
+ // Previously undocumented:
+ Common::Error sfx_send_midi(SongHandle handle, int channel,
+ int command, int arg1, int arg2);
+
+ // misc
+
+ /**
+ * Determines the polyphony of the player in use.
+ * @return Number of voices the active player can emit
+ */
+ int sfx_get_player_polyphony();
+
+ /**
+ * Tells the player to stop its internal iterator.
+ */
+ void sfx_reset_player();
+
+ /**
+ * Pass a raw MIDI event to the synth of the player.
+ * @param argc Length of buffer holding the midi event
+ * @param argv The buffer itself
+ */
+ void sfx_player_tell_synth(int buf_nr, byte *buf);
+
+protected:
+ void freezeTime();
+ void thawTime();
+
+ bool isPlaying(Song *song);
+ void setSongStatus(Song *song, int status);
+ void updateSingleSong();
+ void updateMultiSong();
+ void update();
+};
+
+} // End of namespace Sci
+
+#endif // USE_OLD_MUSIC_FUNCTIONS
+
+#endif // SCI_SFX_CORE_H
diff --git a/engines/sci/sound/iterator/iterator.cpp b/engines/sci/sound/iterator/iterator.cpp
new file mode 100644
index 0000000000..5d9d63e5af
--- /dev/null
+++ b/engines/sci/sound/iterator/iterator.cpp
@@ -0,0 +1,1686 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+/* Song iterators */
+
+#include "common/util.h"
+
+#include "sci/sci.h"
+#ifdef USE_OLD_MUSIC_FUNCTIONS
+
+#include "sci/sound/iterator/iterator_internal.h"
+#include "sci/engine/state.h" // for sfx_player_tell_synth :/
+#include "sci/sound/iterator/core.h" // for sfx_player_tell_synth
+
+#include "sound/audiostream.h"
+#include "sound/mixer.h"
+#include "sound/decoders/raw.h"
+
+namespace Sci {
+
+
+static const int MIDI_cmdlen[16] = {0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 2, 2, 2, 1, 1, 2, 0
+ };
+
+/*#define DEBUG_DECODING*/
+/*#define DEBUG_VERBOSE*/
+
+/** Find first set bit in bits and return its index. Returns 0 if bits is 0. */
+static int sci_ffs(int bits) {
+ if (!bits)
+ return 0;
+
+ int retval = 1;
+
+ while (!(bits & 1)) {
+ retval++;
+ bits >>= 1;
+ }
+
+ return retval;
+}
+
+static void print_tabs_id(int nr, songit_id_t id) {
+ while (nr-- > 0)
+ fprintf(stderr, "\t");
+
+ fprintf(stderr, "[%08lx] ", id);
+}
+
+BaseSongIterator::BaseSongIterator(byte *data, uint size, songit_id_t id)
+ : _data(data, size) {
+ ID = id;
+}
+
+/************************************/
+/*-- SCI0 iterator implementation --*/
+/************************************/
+
+#define SCI0_MIDI_OFFSET 33
+#define SCI0_END_OF_SONG 0xfc /* proprietary MIDI command */
+
+#define SCI0_PCM_SAMPLE_RATE_OFFSET 0x0e
+#define SCI0_PCM_SIZE_OFFSET 0x20
+#define SCI0_PCM_DATA_OFFSET 0x2c
+
+#define CHECK_FOR_END_ABSOLUTE(offset) \
+ if (offset > _data.size()) { \
+ warning("Reached end of song without terminator (%x/%x) at %d", offset, _data.size(), __LINE__); \
+ return SI_FINISHED; \
+ }
+
+#define CHECK_FOR_END(offset_augment) \
+ if ((channel->offset + (offset_augment)) > channel->end) { \
+ channel->state = SI_STATE_FINISHED; \
+ warning("Reached end of track %d without terminator (%x+%x/%x) at %d", channel->id, channel->offset, offset_augment, channel->end, __LINE__); \
+ return SI_FINISHED; \
+ }
+
+
+static int _parse_ticks(byte *data, int *offset_p, int size) {
+ int ticks = 0;
+ int tempticks;
+ int offset = 0;
+
+ do {
+ tempticks = data[offset++];
+ ticks += (tempticks == SCI_MIDI_TIME_EXPANSION_PREFIX) ?
+ SCI_MIDI_TIME_EXPANSION_LENGTH : tempticks;
+ } while (tempticks == SCI_MIDI_TIME_EXPANSION_PREFIX
+ && offset < size);
+
+ if (offset_p)
+ *offset_p = offset;
+
+ return ticks;
+}
+
+
+static int _sci0_get_pcm_data(Sci0SongIterator *self, int *rate, int *xoffset, uint *xsize);
+
+
+#define PARSE_FLAG_LOOPS_UNLIMITED (1 << 0) /* Unlimited # of loops? */
+#define PARSE_FLAG_PARAMETRIC_CUE (1 << 1) /* Assume that cues take an additional "cue value" argument */
+/* This implements a difference between SCI0 and SCI1 cues. */
+
+void SongIteratorChannel::init(int id_, int offset_, int end_) {
+ playmask = PLAYMASK_NONE; /* Disable all channels */
+ id = id_;
+ state = SI_STATE_DELTA_TIME;
+ loop_timepos = 0;
+ total_timepos = 0;
+ timepos_increment = 0;
+ delay = 0; /* Only used for more than one channel */
+ last_cmd = 0xfe;
+
+ offset = loop_offset = initial_offset = offset_;
+ end = end_;
+}
+
+void SongIteratorChannel::resetSynthChannels() {
+ byte buf[5];
+
+ // FIXME: Evil hack
+ SfxState &sound = g_sci->getEngineState()->_sound;
+
+ for (int i = 0; i < MIDI_CHANNELS; i++) {
+ if (playmask & (1 << i)) {
+ buf[0] = 0xe0 | i; /* Pitch bend */
+ buf[1] = 0x80; /* Wheel center */
+ buf[2] = 0x40;
+ sound.sfx_player_tell_synth(3, buf);
+
+ buf[0] = 0xb0 | i; // Set control
+ buf[1] = 0x40; // Hold pedal
+ buf[2] = 0x00; // Off
+ sound.sfx_player_tell_synth(3, buf);
+ /* TODO: Reset other controls? */
+ }
+ }
+}
+
+int BaseSongIterator::parseMidiCommand(byte *buf, int *result, SongIteratorChannel *channel, int flags) {
+ byte cmd;
+ int paramsleft;
+ int midi_op;
+ int midi_channel;
+
+ channel->state = SI_STATE_DELTA_TIME;
+
+ cmd = _data[channel->offset++];
+
+ if (!(cmd & 0x80)) {
+ /* 'Running status' mode */
+ channel->offset--;
+ cmd = channel->last_cmd;
+ }
+
+ if (cmd == 0xfe) {
+ warning("song iterator subsystem: Corrupted sound resource detected.");
+ return SI_FINISHED;
+ }
+
+ midi_op = cmd >> 4;
+ midi_channel = cmd & 0xf;
+ paramsleft = MIDI_cmdlen[midi_op];
+
+#if 0
+ if (1) {
+ fprintf(stderr, "[IT]: off=%x, cmd=%02x, takes %d args ",
+ channel->offset - 1, cmd, paramsleft);
+ fprintf(stderr, "[%02x %02x <%02x> %02x %02x %02x]\n",
+ _data[channel->offset-3],
+ _data[channel->offset-2],
+ _data[channel->offset-1],
+ _data[channel->offset],
+ _data[channel->offset+1],
+ _data[channel->offset+2]);
+ }
+#endif
+
+ buf[0] = cmd;
+
+
+ CHECK_FOR_END(paramsleft);
+ memcpy(buf + 1, _data.begin() + channel->offset, paramsleft);
+ *result = 1 + paramsleft;
+
+ channel->offset += paramsleft;
+
+ channel->last_cmd = cmd;
+
+ /* Are we supposed to play this channel? */
+ if (
+ /* First, exclude "global" properties-- such as cues-- from consideration */
+ (midi_op < 0xf
+ && !(cmd == SCI_MIDI_SET_SIGNAL)
+ && !(SCI_MIDI_CONTROLLER(cmd)
+ && buf[1] == SCI_MIDI_CUMULATIVE_CUE))
+
+ /* Next, check if the channel is allowed */
+ && (!((1 << midi_channel) & channel->playmask)))
+ return /* Execute next command */
+ nextCommand(buf, result);
+
+
+ if (cmd == SCI_MIDI_EOT) {
+ /* End of track? */
+ channel->resetSynthChannels();
+ if (_loops > 1) {
+ /* If allowed, decrement the number of loops */
+ if (!(flags & PARSE_FLAG_LOOPS_UNLIMITED))
+ *result = --_loops;
+
+#ifdef DEBUG_DECODING
+ fprintf(stderr, "%s L%d: (%p):%d Looping ", __FILE__, __LINE__, this, channel->id);
+ if (flags & PARSE_FLAG_LOOPS_UNLIMITED)
+ fprintf(stderr, "(indef.)");
+ else
+ fprintf(stderr, "(%d)", _loops);
+ fprintf(stderr, " %x -> %x\n",
+ channel->offset, channel->loop_offset);
+#endif
+ channel->offset = channel->loop_offset;
+ channel->state = SI_STATE_DELTA_TIME;
+ channel->total_timepos = channel->loop_timepos;
+ channel->last_cmd = 0xfe;
+ debugC(2, kDebugLevelSound, "Looping song iterator %08lx.", ID);
+ return SI_LOOP;
+ } else {
+ channel->state = SI_STATE_FINISHED;
+ return SI_FINISHED;
+ }
+
+ } else if (cmd == SCI_MIDI_SET_SIGNAL) {
+ if (buf[1] == SCI_MIDI_SET_SIGNAL_LOOP) {
+ channel->loop_offset = channel->offset;
+ channel->loop_timepos = channel->total_timepos;
+
+ return /* Execute next command */
+ nextCommand(buf, result);
+ } else {
+ /* Used to be conditional <= 127 */
+ *result = buf[1]; /* Absolute cue */
+ return SI_ABSOLUTE_CUE;
+ }
+ } else if (SCI_MIDI_CONTROLLER(cmd)) {
+ switch (buf[1]) {
+
+ case SCI_MIDI_CUMULATIVE_CUE:
+ if (flags & PARSE_FLAG_PARAMETRIC_CUE)
+ _ccc += buf[2];
+ else { /* No parameter to CC */
+ _ccc++;
+ /* channel->offset--; */
+ }
+ *result = _ccc;
+ return SI_RELATIVE_CUE;
+
+ case SCI_MIDI_RESET_ON_SUSPEND:
+ _resetflag = buf[2];
+ break;
+
+ case SCI_MIDI_SET_POLYPHONY:
+ _polyphony[midi_channel] = buf[2];
+
+#if 0
+ {
+ Sci1SongIterator *self1 = (Sci1SongIterator *)this;
+ int i;
+ int voices = 0;
+ for (i = 0; i < self1->_numChannels; i++) {
+ voices += _polyphony[i];
+ }
+
+ printf("SET_POLYPHONY(%d, %d) for a total of %d voices\n", midi_channel, buf[2], voices);
+ printf("[iterator] DEBUG: Polyphony = [ ");
+ for (i = 0; i < self1->_numChannels; i++)
+ printf("%d ", _polyphony[i]);
+ printf("]\n");
+ printf("[iterator] DEBUG: Importance = [ ");
+ printf("]\n");
+ }
+#endif
+ break;
+
+ case SCI_MIDI_SET_REVERB:
+ break;
+
+ case SCI_MIDI_CHANNEL_MUTE:
+ warning("CHANNEL_MUTE(%d, %d)", midi_channel, buf[2]);
+ break;
+
+ case SCI_MIDI_HOLD: {
+ // Safe cast: This controller is only used in SCI1
+ Sci1SongIterator *self1 = (Sci1SongIterator *)this;
+
+ if (buf[2] == self1->_hold) {
+ channel->offset = channel->initial_offset;
+ channel->state = SI_STATE_COMMAND;
+ channel->total_timepos = 0;
+
+ self1->_numLoopedChannels = self1->_numActiveChannels - 1;
+
+ // FIXME:
+ // This implementation of hold breaks getting out of the
+ // limo when visiting the airport near the start of LSL5.
+ // It seems like all channels should be reset here somehow,
+ // but not sure how.
+ // Forcing all channel offsets to 0 seems to fix the hang,
+ // but somehow slows the exit sequence down to take 20 seconds
+ // instead of about 3.
+
+ return SI_LOOP;
+ }
+
+ break;
+ }
+ case 0x04: /* UNKNOWN NYI (happens in LSL2 gameshow) */
+ case 0x46: /* UNKNOWN NYI (happens in LSL3 binoculars) */
+ case 0x61: /* UNKNOWN NYI (special for AdLib? Iceman) */
+ case 0x73: /* UNKNOWN NYI (happens in Hoyle) */
+ case 0xd1: /* UNKNOWN NYI (happens in KQ4 when riding the unicorn) */
+ return /* Execute next command */
+ nextCommand(buf, result);
+
+ case 0x01: /* modulation */
+ case 0x07: /* volume */
+ case 0x0a: /* panpot */
+ case 0x0b: /* expression */
+ case 0x40: /* hold */
+ case 0x79: /* reset all */
+ /* No special treatment neccessary */
+ break;
+
+ }
+ return 0;
+
+ } else {
+#if 0
+ /* Perform remapping, if neccessary */
+ if (cmd != SCI_MIDI_SET_SIGNAL
+ && cmd < 0xf0) { /* Not a generic command */
+ int chan = cmd & 0xf;
+ int op = cmd & 0xf0;
+
+ chan = channel_remap[chan];
+ buf[0] = chan | op;
+ }
+#endif
+
+ /* Process as normal MIDI operation */
+ return 0;
+ }
+}
+
+int BaseSongIterator::processMidi(byte *buf, int *result,
+ SongIteratorChannel *channel, int flags) {
+ CHECK_FOR_END(0);
+
+ switch (channel->state) {
+
+ case SI_STATE_PCM: {
+ if (_data[channel->offset] == 0
+ && _data[channel->offset + 1] == SCI_MIDI_EOT)
+ /* Fake one extra tick to trick the interpreter into not killing the song iterator right away */
+ channel->state = SI_STATE_PCM_MAGIC_DELTA;
+ else
+ channel->state = SI_STATE_DELTA_TIME;
+ return SI_PCM;
+ }
+
+ case SI_STATE_PCM_MAGIC_DELTA: {
+ int rate;
+ int offset;
+ uint size;
+ int delay;
+ if (_sci0_get_pcm_data((Sci0SongIterator *)this, &rate, &offset, &size))
+ return SI_FINISHED; /* 'tis broken */
+ channel->state = SI_STATE_FINISHED;
+ delay = (size * 50 + rate - 1) / rate; /* number of ticks to completion*/
+
+ debugC(2, kDebugLevelSound, "delaying %d ticks", delay);
+ return delay;
+ }
+
+ case SI_STATE_UNINITIALISED:
+ warning("Attempt to read command from uninitialized iterator");
+ init();
+ return nextCommand(buf, result);
+
+ case SI_STATE_FINISHED:
+ return SI_FINISHED;
+
+ case SI_STATE_DELTA_TIME: {
+ int offset;
+ int ticks = _parse_ticks(_data.begin() + channel->offset,
+ &offset,
+ _data.size() - channel->offset);
+
+ channel->offset += offset;
+ channel->delay += ticks;
+ channel->timepos_increment = ticks;
+
+ CHECK_FOR_END(0);
+
+ channel->state = SI_STATE_COMMAND;
+
+ if (ticks)
+ return ticks;
+ }
+
+ /* continute otherwise... */
+
+ case SI_STATE_COMMAND: {
+ int retval;
+ channel->total_timepos += channel->timepos_increment;
+ channel->timepos_increment = 0;
+
+ retval = parseMidiCommand(buf, result, channel, flags);
+
+ if (retval == SI_FINISHED) {
+ if (_numActiveChannels)
+ --(_numActiveChannels);
+#ifdef DEBUG_DECODING
+ fprintf(stderr, "%s L%d: (%p):%d Finished channel, %d channels left\n",
+ __FILE__, __LINE__, this, channel->id,
+ _numActiveChannels);
+#endif
+ /* If we still have channels left... */
+ if (_numActiveChannels) {
+ return nextCommand(buf, result);
+ }
+
+ /* Otherwise, we have reached the end */
+ _loops = 0;
+ }
+
+ return retval;
+ }
+
+ default:
+ error("Invalid iterator state %d", channel->state);
+ return SI_FINISHED;
+ }
+}
+
+int Sci0SongIterator::nextCommand(byte *buf, int *result) {
+ return processMidi(buf, result, &_channel, PARSE_FLAG_PARAMETRIC_CUE);
+}
+
+static int _sci0_header_magic_p(byte *data, int offset, int size) {
+ if (offset + 0x10 > size)
+ return 0;
+ return (data[offset] == 0x1a)
+ && (data[offset + 1] == 0x00)
+ && (data[offset + 2] == 0x01)
+ && (data[offset + 3] == 0x00);
+}
+
+
+static int _sci0_get_pcm_data(Sci0SongIterator *self,
+ int *rate, int *xoffset, uint *xsize) {
+ int tries = 2;
+ bool found_it = false;
+ byte *pcm_data;
+ int size;
+ uint offset = SCI0_MIDI_OFFSET;
+
+ if (self->_data[0] != 2)
+ return 1;
+ /* No such luck */
+
+ while ((tries--) && (offset < self->_data.size()) && (!found_it)) {
+ // Search through the garbage manually
+ // FIXME: Replace offset by an iterator
+ Common::Array<byte>::iterator iter = Common::find(self->_data.begin() + offset, self->_data.end(), SCI0_END_OF_SONG);
+
+ if (iter == self->_data.end()) {
+ warning("Playing unterminated song");
+ return 1;
+ }
+
+ // add one to move it past the END_OF_SONG marker
+ iter++;
+ offset = iter - self->_data.begin(); // FIXME
+
+
+ if (_sci0_header_magic_p(self->_data.begin(), offset, self->_data.size()))
+ found_it = true;
+ }
+
+ if (!found_it) {
+ warning("Song indicates presence of PCM, but"
+ " none found (finally at offset %04x)", offset);
+
+ return 1;
+ }
+
+ pcm_data = self->_data.begin() + offset;
+
+ size = READ_LE_UINT16(pcm_data + SCI0_PCM_SIZE_OFFSET);
+
+ /* Two of the format parameters are fixed by design: */
+ *rate = READ_LE_UINT16(pcm_data + SCI0_PCM_SAMPLE_RATE_OFFSET);
+
+ if (offset + SCI0_PCM_DATA_OFFSET + size != self->_data.size()) {
+ int d = offset + SCI0_PCM_DATA_OFFSET + size - self->_data.size();
+
+ warning("PCM advertizes %d bytes of data, but %d"
+ " bytes are trailing in the resource",
+ size, self->_data.size() - (offset + SCI0_PCM_DATA_OFFSET));
+
+ if (d > 0)
+ size -= d; /* Fix this */
+ }
+
+ *xoffset = offset;
+ *xsize = size;
+
+ return 0;
+}
+
+static Audio::AudioStream *makeStream(byte *data, int size, int rate) {
+ debugC(2, kDebugLevelSound, "Playing PCM data of size %d, rate %d", size, rate);
+
+ // Duplicate the data
+ byte *sound = (byte *)malloc(size);
+ memcpy(sound, data, size);
+
+ // Convert stream format flags
+ int flags = Audio::FLAG_UNSIGNED;
+ return Audio::makeRawStream(sound, size, rate, flags);
+}
+
+Audio::AudioStream *Sci0SongIterator::getAudioStream() {
+ int rate;
+ int offset;
+ uint size;
+ if (_sci0_get_pcm_data(this, &rate, &offset, &size))
+ return NULL;
+
+ _channel.state = SI_STATE_FINISHED; /* Don't play both PCM and music */
+
+ return makeStream(_data.begin() + offset + SCI0_PCM_DATA_OFFSET, size, rate);
+}
+
+SongIterator *Sci0SongIterator::handleMessage(Message msg) {
+ if (msg._class == _SIMSG_BASE) {
+ switch (msg._type) {
+
+ case _SIMSG_BASEMSG_PRINT:
+ print_tabs_id(msg._arg.i, ID);
+ debugC(2, kDebugLevelSound, "SCI0: dev=%d, active-chan=%d, size=%d, loops=%d",
+ _deviceId, _numActiveChannels, _data.size(), _loops);
+ break;
+
+ case _SIMSG_BASEMSG_SET_LOOPS:
+ _loops = msg._arg.i;
+ break;
+
+ case _SIMSG_BASEMSG_STOP: {
+ songit_id_t sought_id = msg.ID;
+
+ if (sought_id == ID)
+ _channel.state = SI_STATE_FINISHED;
+ break;
+ }
+
+ case _SIMSG_BASEMSG_SET_PLAYMASK: {
+ int i;
+ _deviceId = msg._arg.i;
+
+ /* Set all but the rhytm channel mask bits */
+ _channel.playmask &= ~(1 << MIDI_RHYTHM_CHANNEL);
+
+ for (i = 0; i < MIDI_CHANNELS; i++)
+ if (_data[2 + (i << 1)] & _deviceId
+ && i != MIDI_RHYTHM_CHANNEL)
+ _channel.playmask |= (1 << i);
+ }
+ break;
+
+ case _SIMSG_BASEMSG_SET_RHYTHM:
+ _channel.playmask &= ~(1 << MIDI_RHYTHM_CHANNEL);
+ if (msg._arg.i)
+ _channel.playmask |= (1 << MIDI_RHYTHM_CHANNEL);
+ break;
+
+ case _SIMSG_BASEMSG_SET_FADE: {
+ fade_params_t *fp = (fade_params_t *) msg._arg.p;
+ fade.action = fp->action;
+ fade.final_volume = fp->final_volume;
+ fade.ticks_per_step = fp->ticks_per_step;
+ fade.step_size = fp->step_size;
+ break;
+ }
+
+ default:
+ return NULL;
+ }
+
+ return this;
+ }
+ return NULL;
+}
+
+int Sci0SongIterator::getTimepos() {
+ return _channel.total_timepos;
+}
+
+Sci0SongIterator::Sci0SongIterator(byte *data, uint size, songit_id_t id)
+ : BaseSongIterator(data, size, id) {
+ channel_mask = 0xffff; // Allocate all channels by default
+ _channel.state = SI_STATE_UNINITIALISED;
+
+ for (int i = 0; i < MIDI_CHANNELS; i++)
+ _polyphony[i] = data[1 + (i << 1)];
+
+ init();
+}
+
+void Sci0SongIterator::init() {
+ fade.action = FADE_ACTION_NONE;
+ _resetflag = 0;
+ _loops = 0;
+ priority = 0;
+
+ _ccc = 0; /* Reset cumulative cue counter */
+ _numActiveChannels = 1;
+ _channel.init(0, SCI0_MIDI_OFFSET, _data.size());
+ _channel.resetSynthChannels();
+
+ if (_data[0] == 2) /* Do we have an embedded PCM? */
+ _channel.state = SI_STATE_PCM;
+}
+
+SongIterator *Sci0SongIterator::clone(int delta) {
+ Sci0SongIterator *newit = new Sci0SongIterator(*this);
+ return newit;
+}
+
+
+/***************************/
+/*-- SCI1 song iterators --*/
+/***************************/
+
+int Sci1SongIterator::initSample(const int offset) {
+ Sci1Sample sample;
+ int rate;
+ int length;
+ int begin;
+ int end;
+
+ CHECK_FOR_END_ABSOLUTE((uint)offset + 10);
+ if (_data[offset + 1] != 0)
+ warning("[iterator-1] In sample at offset 0x04x: Byte #1 is %02x instead of zero",
+ _data[offset + 1]);
+
+ rate = (int16)READ_LE_UINT16(_data.begin() + offset + 2);
+ length = READ_LE_UINT16(_data.begin() + offset + 4);
+ begin = (int16)READ_LE_UINT16(_data.begin() + offset + 6);
+ end = (int16)READ_LE_UINT16(_data.begin() + offset + 8);
+
+ CHECK_FOR_END_ABSOLUTE((uint)(offset + 10 + length));
+
+ sample.delta = begin;
+ sample.size = length;
+ sample._data = _data.begin() + offset + 10;
+
+#ifdef DEBUG_VERBOSE
+ fprintf(stderr, "[SAMPLE] %x/%x/%x/%x l=%x\n",
+ offset + 10, begin, end, _data.size(), length);
+#endif
+
+ sample.rate = rate;
+
+ sample.announced = false;
+
+ /* Insert into the sample list at the right spot, keeping it sorted by delta */
+ Common::List<Sci1Sample>::iterator seeker = _samples.begin();
+ while (seeker != _samples.end() && seeker->delta < begin)
+ ++seeker;
+ _samples.insert(seeker, sample);
+
+ return 0; /* Everything's fine */
+}
+
+int Sci1SongIterator::initSong() {
+ int last_time;
+ uint offset = 0;
+ _numChannels = 0;
+ _samples.clear();
+// _deviceId = 0x0c;
+
+ if (_data[offset] == 0xf0) {
+ priority = _data[offset + 1];
+
+ offset += 8;
+ }
+
+ while (_data[offset] != 0xff
+ && _data[offset] != _deviceId) {
+ offset++;
+ CHECK_FOR_END_ABSOLUTE(offset + 1);
+ while (_data[offset] != 0xff) {
+ CHECK_FOR_END_ABSOLUTE(offset + 7);
+ offset += 6;
+ }
+ offset++;
+ }
+
+ if (_data[offset] == 0xff) {
+ warning("[iterator] Song does not support hardware 0x%02x", _deviceId);
+ return 1;
+ }
+
+ offset++;
+
+ while (_data[offset] != 0xff) { /* End of list? */
+ uint track_offset;
+ int end;
+ offset += 2;
+
+ CHECK_FOR_END_ABSOLUTE(offset + 4);
+
+ track_offset = READ_LE_UINT16(_data.begin() + offset);
+ end = READ_LE_UINT16(_data.begin() + offset + 2);
+
+ CHECK_FOR_END_ABSOLUTE(track_offset - 1);
+
+ if (_data[track_offset] == 0xfe) {
+ if (initSample(track_offset))
+ return 1; /* Error */
+ } else {
+ /* Regular MIDI channel */
+ if (_numChannels >= MIDI_CHANNELS) {
+ warning("[iterator] Song has more than %d channels, cutting them off",
+ MIDI_CHANNELS);
+ break; /* Scan for remaining samples */
+ } else {
+ int channel_nr = _data[track_offset] & 0xf;
+ SongIteratorChannel &channel = _channels[_numChannels++];
+
+ /*
+ if (_data[track_offset] & 0xf0)
+ printf("Channel %d has mapping bits %02x\n",
+ channel_nr, _data[track_offset] & 0xf0);
+ */
+
+ // Add 2 to skip over header bytes */
+ channel.init(channel_nr, track_offset + 2, track_offset + end);
+ channel.resetSynthChannels();
+
+ _polyphony[_numChannels - 1] = _data[channel.offset - 1] & 15;
+
+ channel.playmask = ~0; /* Enable all */
+ channel_mask |= (1 << channel_nr);
+
+ CHECK_FOR_END_ABSOLUTE(offset + end);
+ }
+ }
+ offset += 4;
+ CHECK_FOR_END_ABSOLUTE(offset);
+ }
+
+ /* Now ensure that sample deltas are relative to the previous sample */
+ last_time = 0;
+ _numActiveChannels = _numChannels;
+ _numLoopedChannels = 0;
+
+ for (Common::List<Sci1Sample>::iterator seeker = _samples.begin();
+ seeker != _samples.end(); ++seeker) {
+ int prev_last_time = last_time;
+ //printf("[iterator] Detected sample: %d Hz, %d bytes at time %d\n",
+ // seeker->format.rate, seeker->size, seeker->delta);
+ last_time = seeker->delta;
+ seeker->delta -= prev_last_time;
+ }
+
+ return 0; /* Success */
+}
+
+int Sci1SongIterator::getSmallestDelta() const {
+ int d = -1;
+ for (int i = 0; i < _numChannels; i++)
+ if (_channels[i].state == SI_STATE_COMMAND
+ && (d == -1 || _channels[i].delay < d))
+ d = _channels[i].delay;
+
+ if (!_samples.empty() && _samples.begin()->delta < d)
+ return _samples.begin()->delta;
+ else
+ return d;
+}
+
+void Sci1SongIterator::updateDelta(int delta) {
+ if (!_samples.empty())
+ _samples.begin()->delta -= delta;
+
+ for (int i = 0; i < _numChannels; i++)
+ if (_channels[i].state == SI_STATE_COMMAND)
+ _channels[i].delay -= delta;
+}
+
+bool Sci1SongIterator::noDeltaTime() const {
+ for (int i = 0; i < _numChannels; i++)
+ if (_channels[i].state == SI_STATE_DELTA_TIME)
+ return false;
+ return true;
+}
+
+#define COMMAND_INDEX_NONE -1
+#define COMMAND_INDEX_PCM -2
+
+int Sci1SongIterator::getCommandIndex() const {
+ /* Determine the channel # of the next active event, or -1 */
+ int i;
+ int base_delay = 0x7ffffff;
+ int best_chan = COMMAND_INDEX_NONE;
+
+ for (i = 0; i < _numChannels; i++)
+ if ((_channels[i].state != SI_STATE_PENDING)
+ && (_channels[i].state != SI_STATE_FINISHED)) {
+
+ if ((_channels[i].state == SI_STATE_DELTA_TIME)
+ && (_channels[i].delay == 0))
+ return i;
+ /* First, read all unknown delta times */
+
+ if (_channels[i].delay < base_delay) {
+ best_chan = i;
+ base_delay = _channels[i].delay;
+ }
+ }
+
+ if (!_samples.empty() && base_delay >= _samples.begin()->delta)
+ return COMMAND_INDEX_PCM;
+
+ return best_chan;
+}
+
+
+Audio::AudioStream *Sci1SongIterator::getAudioStream() {
+ Common::List<Sci1Sample>::iterator sample = _samples.begin();
+ if (sample != _samples.end() && sample->delta <= 0) {
+ Audio::AudioStream *feed = makeStream(sample->_data, sample->size, sample->rate);
+ _samples.erase(sample);
+
+ return feed;
+ } else
+ return NULL;
+}
+
+int Sci1SongIterator::nextCommand(byte *buf, int *result) {
+
+ if (!_initialised) {
+ //printf("[iterator] DEBUG: Initialising for %d\n", _deviceId);
+ _initialised = true;
+ if (initSong())
+ return SI_FINISHED;
+ }
+
+
+ if (_delayRemaining) {
+ int delay = _delayRemaining;
+ _delayRemaining = 0;
+ return delay;
+ }
+
+ int retval = 0;
+ do { /* All delays must be processed separately */
+ int chan = getCommandIndex();
+
+ if (chan == COMMAND_INDEX_NONE) {
+ return SI_FINISHED;
+ }
+
+ if (chan == COMMAND_INDEX_PCM) {
+
+ if (_samples.begin()->announced) {
+ /* Already announced; let's discard it */
+ Audio::AudioStream *feed = getAudioStream();
+ delete feed;
+ } else {
+ int delay = _samples.begin()->delta;
+
+ if (delay) {
+ updateDelta(delay);
+ return delay;
+ }
+ /* otherwise we're touching a PCM */
+ _samples.begin()->announced = true;
+ return SI_PCM;
+ }
+ } else { /* Not a PCM */
+
+ retval = processMidi(buf, result,
+ &(_channels[chan]),
+ PARSE_FLAG_LOOPS_UNLIMITED);
+
+ if (retval == SI_LOOP) {
+ _numLoopedChannels++;
+ _channels[chan].state = SI_STATE_PENDING;
+ _channels[chan].delay = 0;
+
+ if (_numLoopedChannels == _numActiveChannels) {
+ int i;
+
+ /* Everyone's ready: Let's loop */
+ for (i = 0; i < _numChannels; i++)
+ if (_channels[i].state == SI_STATE_PENDING)
+ _channels[i].state = SI_STATE_DELTA_TIME;
+
+ _numLoopedChannels = 0;
+ return SI_LOOP;
+ }
+ } else if (retval == SI_FINISHED) {
+#ifdef DEBUG
+ fprintf(stderr, "FINISHED some channel\n");
+#endif
+ } else if (retval > 0) {
+ int sd ;
+ sd = getSmallestDelta();
+
+ if (noDeltaTime() && sd) {
+ /* No other channel is ready */
+ updateDelta(sd);
+
+ /* Only from here do we return delta times */
+ return sd;
+ }
+ }
+
+ } /* Not a PCM */
+
+ } while (retval > 0);
+
+ return retval;
+}
+
+SongIterator *Sci1SongIterator::handleMessage(Message msg) {
+ if (msg._class == _SIMSG_BASE) { /* May extend this in the future */
+ switch (msg._type) {
+
+ case _SIMSG_BASEMSG_PRINT: {
+ int playmask = 0;
+ int i;
+
+ for (i = 0; i < _numChannels; i++)
+ playmask |= _channels[i].playmask;
+
+ print_tabs_id(msg._arg.i, ID);
+ debugC(2, kDebugLevelSound, "SCI1: chan-nr=%d, playmask=%04x",
+ _numChannels, playmask);
+ }
+ break;
+
+ case _SIMSG_BASEMSG_STOP: {
+ songit_id_t sought_id = msg.ID;
+ int i;
+
+ if (sought_id == ID) {
+ ID = 0;
+
+ for (i = 0; i < _numChannels; i++)
+ _channels[i].state = SI_STATE_FINISHED;
+ }
+ break;
+ }
+
+ case _SIMSG_BASEMSG_SET_PLAYMASK:
+ if (msg.ID == ID) {
+ channel_mask = 0;
+
+ _deviceId = msg._arg.i;
+
+ if (_initialised) {
+ int i;
+ int toffset = -1;
+
+ for (i = 0; i < _numChannels; i++)
+ if (_channels[i].state != SI_STATE_FINISHED
+ && _channels[i].total_timepos > toffset) {
+ toffset = _channels[i].total_timepos
+ + _channels[i].timepos_increment
+ - _channels[i].delay;
+ }
+
+ /* Find an active channel so that we can
+ ** get the correct time offset */
+
+ initSong();
+
+ toffset -= _delayRemaining;
+ _delayRemaining = 0;
+
+ if (toffset > 0)
+ return new_fast_forward_iterator(this, toffset);
+ } else {
+ initSong();
+ _initialised = true;
+ }
+
+ break;
+
+ }
+
+ case _SIMSG_BASEMSG_SET_LOOPS:
+ if (msg.ID == ID)
+ _loops = (msg._arg.i > 32767) ? 99 : 0;
+ /* 99 is arbitrary, but we can't use '1' because of
+ ** the way we're testing in the decoding section. */
+ break;
+
+ case _SIMSG_BASEMSG_SET_HOLD:
+ _hold = msg._arg.i;
+ break;
+ case _SIMSG_BASEMSG_SET_RHYTHM:
+ /* Ignore */
+ break;
+
+ case _SIMSG_BASEMSG_SET_FADE: {
+ fade_params_t *fp = (fade_params_t *) msg._arg.p;
+ fade.action = fp->action;
+ fade.final_volume = fp->final_volume;
+ fade.ticks_per_step = fp->ticks_per_step;
+ fade.step_size = fp->step_size;
+ break;
+ }
+
+ default:
+ warning("Unsupported command %d to SCI1 iterator", msg._type);
+ }
+ return this;
+ }
+ return NULL;
+}
+
+Sci1SongIterator::Sci1SongIterator(byte *data, uint size, songit_id_t id)
+ : BaseSongIterator(data, size, id) {
+ channel_mask = 0; // Defer channel allocation
+
+ for (int i = 0; i < MIDI_CHANNELS; i++)
+ _polyphony[i] = 0; // Unknown
+
+ init();
+}
+
+void Sci1SongIterator::init() {
+ fade.action = FADE_ACTION_NONE;
+ _resetflag = 0;
+ _loops = 0;
+ priority = 0;
+
+ _ccc = 0;
+ _deviceId = 0x00; // Default to Sound Blaster/AdLib for purposes of cue computation
+ _numChannels = 0;
+ _initialised = false;
+ _delayRemaining = 0;
+ _loops = 0;
+ _hold = 0;
+ memset(_polyphony, 0, sizeof(_polyphony));
+}
+
+Sci1SongIterator::~Sci1SongIterator() {
+}
+
+
+SongIterator *Sci1SongIterator::clone(int delta) {
+ Sci1SongIterator *newit = new Sci1SongIterator(*this);
+ newit->_delayRemaining = delta;
+ return newit;
+}
+
+int Sci1SongIterator::getTimepos() {
+ int max = 0;
+ int i;
+
+ for (i = 0; i < _numChannels; i++)
+ if (_channels[i].total_timepos > max)
+ max = _channels[i].total_timepos;
+
+ return max;
+}
+
+/**
+ * A song iterator with the purpose of sending notes-off channel commands.
+ */
+class CleanupSongIterator : public SongIterator {
+public:
+ CleanupSongIterator(uint channels) {
+ channel_mask = channels;
+ ID = 17;
+ }
+
+ int nextCommand(byte *buf, int *result);
+ Audio::AudioStream *getAudioStream() { return NULL; }
+ SongIterator *handleMessage(Message msg);
+ int getTimepos() { return 0; }
+ SongIterator *clone(int delta) { return new CleanupSongIterator(*this); }
+};
+
+SongIterator *CleanupSongIterator::handleMessage(Message msg) {
+ if (msg._class == _SIMSG_BASEMSG_PRINT && msg._type == _SIMSG_BASEMSG_PRINT) {
+ print_tabs_id(msg._arg.i, ID);
+ debugC(2, kDebugLevelSound, "CLEANUP");
+ }
+
+ return NULL;
+}
+
+int CleanupSongIterator::nextCommand(byte *buf, int *result) {
+ /* Task: Return channel-notes-off for each channel */
+ if (channel_mask) {
+ int bs = sci_ffs(channel_mask) - 1;
+
+ channel_mask &= ~(1 << bs);
+ buf[0] = 0xb0 | bs; /* Controller */
+ buf[1] = SCI_MIDI_CHANNEL_NOTES_OFF;
+ buf[2] = 0; /* Hmm... */
+ *result = 3;
+ return 0;
+ } else
+ return SI_FINISHED;
+}
+
+/**********************/
+/*-- Timer iterator --*/
+/**********************/
+int TimerSongIterator::nextCommand(byte *buf, int *result) {
+ if (_delta) {
+ int d = _delta;
+ _delta = 0;
+ return d;
+ }
+ return SI_FINISHED;
+}
+
+SongIterator *new_timer_iterator(int delta) {
+ return new TimerSongIterator(delta);
+}
+
+/**********************************/
+/*-- Fast-forward song iterator --*/
+/**********************************/
+
+int FastForwardSongIterator::nextCommand(byte *buf, int *result) {
+ if (_delta <= 0)
+ return SI_MORPH; /* Did our duty */
+
+ while (1) {
+ int rv = _delegate->nextCommand(buf, result);
+
+ if (rv > 0) {
+ /* Subtract from the delta we want to wait */
+ _delta -= rv;
+
+ /* Done */
+ if (_delta < 0)
+ return -_delta;
+ }
+
+ if (rv <= 0)
+ return rv;
+ }
+}
+
+Audio::AudioStream *FastForwardSongIterator::getAudioStream() {
+ return _delegate->getAudioStream();
+}
+
+SongIterator *FastForwardSongIterator::handleMessage(Message msg) {
+ if (msg._class == _SIMSG_PLASTICWRAP) {
+ assert(msg._type == _SIMSG_PLASTICWRAP_ACK_MORPH);
+
+ if (_delta <= 0) {
+ SongIterator *it = _delegate;
+ delete this;
+ return it;
+ }
+
+ warning("[ff-iterator] Morphing without need");
+ return this;
+ }
+
+ if (msg._class == _SIMSG_BASE && msg._type == _SIMSG_BASEMSG_PRINT) {
+ print_tabs_id(msg._arg.i, ID);
+ debugC(2, kDebugLevelSound, "FASTFORWARD:");
+ msg._arg.i++;
+ }
+
+ // And continue with the delegate
+ songit_handle_message(&_delegate, msg);
+
+ return NULL;
+}
+
+
+int FastForwardSongIterator::getTimepos() {
+ return _delegate->getTimepos();
+}
+
+FastForwardSongIterator::FastForwardSongIterator(SongIterator *capsit, int delta)
+ : _delegate(capsit), _delta(delta) {
+
+ channel_mask = capsit->channel_mask;
+}
+
+SongIterator *FastForwardSongIterator::clone(int delta) {
+ FastForwardSongIterator *newit = new FastForwardSongIterator(*this);
+ newit->_delegate = _delegate->clone(delta);
+ return newit;
+}
+
+SongIterator *new_fast_forward_iterator(SongIterator *capsit, int delta) {
+ if (capsit == NULL)
+ return NULL;
+
+ FastForwardSongIterator *it = new FastForwardSongIterator(capsit, delta);
+ return it;
+}
+
+
+/********************/
+/*-- Tee iterator --*/
+/********************/
+
+
+static void song_iterator_add_death_listener(SongIterator *it, TeeSongIterator *client) {
+ for (int i = 0; i < SONGIT_MAX_LISTENERS; ++i) {
+ if (it->_deathListeners[i] == 0) {
+ it->_deathListeners[i] = client;
+ return;
+ }
+ }
+ error("FATAL: Too many death listeners for song iterator");
+}
+
+static void song_iterator_remove_death_listener(SongIterator *it, TeeSongIterator *client) {
+ for (int i = 0; i < SONGIT_MAX_LISTENERS; ++i) {
+ if (it->_deathListeners[i] == client) {
+ it->_deathListeners[i] = 0;
+ return;
+ }
+ }
+}
+
+static void song_iterator_transfer_death_listeners(SongIterator *it, SongIterator *it_from) {
+ for (int i = 0; i < SONGIT_MAX_LISTENERS; ++i) {
+ if (it_from->_deathListeners[i])
+ song_iterator_add_death_listener(it, it_from->_deathListeners[i]);
+ it_from->_deathListeners[i] = 0;
+ }
+}
+
+static void songit_tee_death_notification(TeeSongIterator *self, SongIterator *corpse) {
+ if (corpse == self->_children[TEE_LEFT].it) {
+ self->_status &= ~TEE_LEFT_ACTIVE;
+ self->_children[TEE_LEFT].it = NULL;
+ } else if (corpse == self->_children[TEE_RIGHT].it) {
+ self->_status &= ~TEE_RIGHT_ACTIVE;
+ self->_children[TEE_RIGHT].it = NULL;
+ } else {
+ error("songit_tee_death_notification() failed: Breakpoint in %s, line %d", __FILE__, __LINE__);
+ }
+}
+
+TeeSongIterator::TeeSongIterator(SongIterator *left, SongIterator *right) {
+ int i;
+ int firstfree = 1; /* First free channel */
+ int incomplete_map = 0;
+
+ _readyToMorph = false;
+ _status = TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE;
+
+ _children[TEE_LEFT].it = left;
+ _children[TEE_RIGHT].it = right;
+
+ /* Default to lhs channels */
+ channel_mask = left->channel_mask;
+ for (i = 0; i < 16; i++)
+ if (channel_mask & (1 << i) & right->channel_mask
+ && (i != MIDI_RHYTHM_CHANNEL) /* Share rhythm */) { /*conflict*/
+ while ((firstfree == MIDI_RHYTHM_CHANNEL)
+ /* Either if it's the rhythm channel or if it's taken */
+ || (firstfree < MIDI_CHANNELS
+ && ((1 << firstfree) & channel_mask)))
+ ++firstfree;
+
+ if (firstfree == MIDI_CHANNELS) {
+ incomplete_map = 1;
+ //warning("[songit-tee <%08lx,%08lx>] Could not remap right channel #%d: Out of channels",
+ // left->ID, right->ID, i);
+ } else {
+ _children[TEE_RIGHT].it->channel_remap[i] = firstfree;
+
+ channel_mask |= (1 << firstfree);
+ }
+ }
+#ifdef DEBUG_TEE_ITERATOR
+ if (incomplete_map) {
+ int c;
+ fprintf(stderr, "[songit-tee <%08lx,%08lx>] Channels:"
+ " %04x <- %04x | %04x\n",
+ left->ID, right->ID,
+ channel_mask,
+ left->channel_mask, right->channel_mask);
+ for (c = 0 ; c < 2; c++)
+ for (i = 0 ; i < 16; i++)
+ fprintf(stderr, " map [%d][%d] -> %d\n",
+ c, i, _children[c].it->channel_remap[i]);
+ }
+#endif
+
+
+ song_iterator_add_death_listener(left, this);
+ song_iterator_add_death_listener(right, this);
+}
+
+TeeSongIterator::~TeeSongIterator() {
+ // When we die, remove any listeners from our children
+ if (_children[TEE_LEFT].it) {
+ song_iterator_remove_death_listener(_children[TEE_LEFT].it, this);
+ }
+
+ if (_children[TEE_RIGHT].it) {
+ song_iterator_remove_death_listener(_children[TEE_RIGHT].it, this);
+ }
+}
+
+
+int TeeSongIterator::nextCommand(byte *buf, int *result) {
+ static const int ready_masks[2] = {TEE_LEFT_READY, TEE_RIGHT_READY};
+ static const int active_masks[2] = {TEE_LEFT_ACTIVE, TEE_RIGHT_ACTIVE};
+ static const int pcm_masks[2] = {TEE_LEFT_PCM, TEE_RIGHT_PCM};
+ int i;
+ int retid;
+
+#ifdef DEBUG_TEE_ITERATOR
+ fprintf(stderr, "[Tee] %02x\n", _status);
+#endif
+
+ if (!(_status & (TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE)))
+ /* None is active? */
+ return SI_FINISHED;
+
+ if (_readyToMorph)
+ return SI_MORPH;
+
+ if ((_status & (TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE))
+ != (TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE)) {
+ /* Not all are is active? */
+ int which = 0;
+#ifdef DEBUG_TEE_ITERATOR
+ fprintf(stderr, "\tRequesting transformation...\n");
+#endif
+ if (_status & TEE_LEFT_ACTIVE)
+ which = TEE_LEFT;
+ else if (_status & TEE_RIGHT_ACTIVE)
+ which = TEE_RIGHT;
+ memcpy(buf, _children[which].buf, sizeof(buf));
+ *result = _children[which].result;
+ _readyToMorph = true;
+ return _children[which].retval;
+ }
+
+ /* First, check for unreported PCMs */
+ for (i = TEE_LEFT; i <= TEE_RIGHT; i++)
+ if ((_status & (ready_masks[i] | pcm_masks[i]))
+ == (ready_masks[i] | pcm_masks[i])) {
+ _status &= ~ready_masks[i];
+ return SI_PCM;
+ }
+
+ for (i = TEE_LEFT; i <= TEE_RIGHT; i++)
+ if (!(_status & ready_masks[i])) {
+
+ /* Buffers aren't ready yet */
+ _children[i].retval =
+ songit_next(&(_children[i].it),
+ _children[i].buf,
+ &(_children[i].result),
+ IT_READER_MASK_ALL
+ | IT_READER_MAY_FREE
+ | IT_READER_MAY_CLEAN);
+
+ _status |= ready_masks[i];
+#ifdef DEBUG_TEE_ITERATOR
+ fprintf(stderr, "\t Must check %d: %d\n", i, _children[i].retval);
+#endif
+
+ if (_children[i].retval == SI_ABSOLUTE_CUE ||
+ _children[i].retval == SI_RELATIVE_CUE)
+ return _children[i].retval;
+ if (_children[i].retval == SI_FINISHED) {
+ _status &= ~active_masks[i];
+ /* Recurse to complete */
+#ifdef DEBUG_TEE_ITERATOR
+ fprintf(stderr, "\t Child %d signalled completion, recursing w/ status %02x\n", i, _status);
+#endif
+ return nextCommand(buf, result);
+ } else if (_children[i].retval == SI_PCM) {
+ _status |= pcm_masks[i];
+ _status &= ~ready_masks[i];
+ return SI_PCM;
+ }
+ }
+
+
+ /* We've already handled PCM, MORPH and FINISHED, CUEs & LOOP remain */
+
+ retid = TEE_LEFT;
+ if ((_children[TEE_LEFT].retval > 0)
+ /* Asked to delay */
+ && (_children[TEE_RIGHT].retval <= _children[TEE_LEFT].retval))
+ /* Is not delaying or not delaying as much */
+ retid = TEE_RIGHT;
+
+#ifdef DEBUG_TEE_ITERATOR
+ fprintf(stderr, "\tl:%d / r:%d / chose %d\n",
+ _children[TEE_LEFT].retval, _children[TEE_RIGHT].retval, retid);
+#endif
+
+ /* Adjust delta times */
+ if (_children[retid].retval > 0
+ && _children[1-retid].retval > 0) {
+ if (_children[1-retid].retval
+ == _children[retid].retval)
+ /* If both _children wait the same amount of time,
+ ** we have to re-fetch commands from both */
+ _status &= ~ready_masks[1-retid];
+ else
+ /* If they don't, we can/must re-use the other
+ ** child's delay time */
+ _children[1-retid].retval
+ -= _children[retid].retval;
+ }
+
+ _status &= ~ready_masks[retid];
+ memcpy(buf, _children[retid].buf, sizeof(buf));
+ *result = _children[retid].result;
+
+ return _children[retid].retval;
+}
+
+Audio::AudioStream *TeeSongIterator::getAudioStream() {
+ static const int pcm_masks[2] = {TEE_LEFT_PCM, TEE_RIGHT_PCM};
+ int i;
+
+ for (i = TEE_LEFT; i <= TEE_RIGHT; i++)
+ if (_status & pcm_masks[i]) {
+ _status &= ~pcm_masks[i];
+ return _children[i].it->getAudioStream();
+ }
+
+ return NULL; // No iterator
+}
+
+SongIterator *TeeSongIterator::handleMessage(Message msg) {
+ if (msg._class == _SIMSG_PLASTICWRAP) {
+ assert(msg._type == _SIMSG_PLASTICWRAP_ACK_MORPH);
+
+ SongIterator *old_it;
+ if (!(_status & (TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE))) {
+ delete this;
+ return NULL;
+ } else if (!(_status & TEE_LEFT_ACTIVE)) {
+ delete _children[TEE_LEFT].it;
+ _children[TEE_LEFT].it = 0;
+ old_it = _children[TEE_RIGHT].it;
+ song_iterator_remove_death_listener(old_it, this);
+ song_iterator_transfer_death_listeners(old_it, this);
+ delete this;
+ return old_it;
+ } else if (!(_status & TEE_RIGHT_ACTIVE)) {
+ delete _children[TEE_RIGHT].it;
+ _children[TEE_RIGHT].it = 0;
+ old_it = _children[TEE_LEFT].it;
+ song_iterator_remove_death_listener(old_it, this);
+ song_iterator_transfer_death_listeners(old_it, this);
+ delete this;
+ return old_it;
+ }
+
+ warning("[tee-iterator] Morphing without need");
+ return this;
+ }
+
+ if (msg._class == _SIMSG_BASE && msg._type == _SIMSG_BASEMSG_PRINT) {
+ print_tabs_id(msg._arg.i, ID);
+ debugC(2, kDebugLevelSound, "TEE:");
+ msg._arg.i++;
+ }
+
+ // And continue with the children
+ if (_children[TEE_LEFT].it)
+ songit_handle_message(&(_children[TEE_LEFT].it), msg);
+ if (_children[TEE_RIGHT].it)
+ songit_handle_message(&(_children[TEE_RIGHT].it), msg);
+
+ return NULL;
+}
+
+void TeeSongIterator::init() {
+ _status = TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE;
+ _children[TEE_LEFT].it->init();
+ _children[TEE_RIGHT].it->init();
+}
+
+SongIterator *TeeSongIterator::clone(int delta) {
+ TeeSongIterator *newit = new TeeSongIterator(*this);
+
+ if (_children[TEE_LEFT].it)
+ newit->_children[TEE_LEFT].it = _children[TEE_LEFT].it->clone(delta);
+ if (_children[TEE_RIGHT].it)
+ newit->_children[TEE_RIGHT].it = _children[TEE_RIGHT].it->clone(delta);
+
+ return newit;
+}
+
+
+/*************************************/
+/*-- General purpose functionality --*/
+/*************************************/
+
+int songit_next(SongIterator **it, byte *buf, int *result, int mask) {
+ int retval;
+
+ if (!*it)
+ return SI_FINISHED;
+
+ do {
+ retval = (*it)->nextCommand(buf, result);
+ if (retval == SI_MORPH) {
+ debugC(2, kDebugLevelSound, " Morphing %p (stored at %p)", (void *)*it, (void *)it);
+ if (!SIMSG_SEND((*it), SIMSG_ACK_MORPH)) {
+ error("SI_MORPH failed. Breakpoint in %s, line %d", __FILE__, __LINE__);
+ } else
+ debugC(2, kDebugLevelSound, "SI_MORPH successful");
+ }
+
+ if (retval == SI_FINISHED)
+ debugC(2, kDebugLevelSound, "[song-iterator] Song finished. mask = %04x, cm=%04x",
+ mask, (*it)->channel_mask);
+ if (retval == SI_FINISHED
+ && (mask & IT_READER_MAY_CLEAN)
+ && (*it)->channel_mask) { /* This last test will fail
+ ** with a terminated
+ ** cleanup iterator */
+ int channel_mask = (*it)->channel_mask;
+
+ SongIterator *old_it = *it;
+ *it = new CleanupSongIterator(channel_mask);
+ for(uint i = 0; i < MIDI_CHANNELS; i++)
+ (*it)->channel_remap[i] = old_it->channel_remap[i];
+ song_iterator_transfer_death_listeners(*it, old_it);
+ if (mask & IT_READER_MAY_FREE)
+ delete old_it;
+ retval = -9999; /* Continue */
+ }
+ } while (!( /* Until one of the following holds */
+ (retval > 0 && (mask & IT_READER_MASK_DELAY))
+ || (retval == 0 && (mask & IT_READER_MASK_MIDI))
+ || (retval == SI_LOOP && (mask & IT_READER_MASK_LOOP))
+ || (retval == SI_ABSOLUTE_CUE &&
+ (mask & IT_READER_MASK_CUE))
+ || (retval == SI_RELATIVE_CUE &&
+ (mask & IT_READER_MASK_CUE))
+ || (retval == SI_PCM && (mask & IT_READER_MASK_PCM))
+ || (retval == SI_FINISHED)
+ ));
+
+ if (retval == SI_FINISHED && (mask & IT_READER_MAY_FREE)) {
+ delete *it;
+ *it = NULL;
+ }
+
+ return retval;
+}
+
+SongIterator::SongIterator() {
+ ID = 0;
+ channel_mask = 0;
+ fade.action = FADE_ACTION_NONE;
+ priority = 0;
+ memset(_deathListeners, 0, sizeof(_deathListeners));
+
+ // By default, don't remap
+ for (uint i = 0; i < 16; i++)
+ channel_remap[i] = i;
+}
+
+SongIterator::SongIterator(const SongIterator &si) {
+ ID = si.ID;
+ channel_mask = si.channel_mask;
+ fade = si.fade;
+ priority = si.priority;
+ memset(_deathListeners, 0, sizeof(_deathListeners));
+
+ for (uint i = 0; i < 16; i++)
+ channel_remap[i] = si.channel_remap[i];
+}
+
+
+SongIterator::~SongIterator() {
+ for (int i = 0; i < SONGIT_MAX_LISTENERS; ++i)
+ if (_deathListeners[i])
+ songit_tee_death_notification(_deathListeners[i], this);
+}
+
+SongIterator *songit_new(byte *data, uint size, SongIteratorType type, songit_id_t id) {
+ BaseSongIterator *it;
+
+ if (!data || size < 22) {
+ warning("Attempt to instantiate song iterator for null song data");
+ return NULL;
+ }
+
+
+ switch (type) {
+ case SCI_SONG_ITERATOR_TYPE_SCI0:
+ it = new Sci0SongIterator(data, size, id);
+ break;
+
+ case SCI_SONG_ITERATOR_TYPE_SCI1:
+ it = new Sci1SongIterator(data, size, id);
+ break;
+
+ default:
+ /**-- Invalid/unsupported sound resources --**/
+ warning("Attempt to instantiate invalid/unknown song iterator type %d", type);
+ return NULL;
+ }
+
+ return it;
+}
+
+int songit_handle_message(SongIterator **it_reg_p, SongIterator::Message msg) {
+ SongIterator *it = *it_reg_p;
+ SongIterator *newit;
+
+ newit = it->handleMessage(msg);
+
+ if (!newit)
+ return 0; /* Couldn't handle */
+
+ *it_reg_p = newit; /* Might have self-morphed */
+ return 1;
+}
+
+SongIterator *sfx_iterator_combine(SongIterator *it1, SongIterator *it2) {
+ if (it1 == NULL)
+ return it2;
+ if (it2 == NULL)
+ return it1;
+
+ /* Both are non-NULL: */
+ return new TeeSongIterator(it1, it2);
+}
+
+} // End of namespace Sci
+
+#endif // USE_OLD_MUSIC_FUNCTIONS
diff --git a/engines/sci/sound/iterator/iterator.h b/engines/sci/sound/iterator/iterator.h
new file mode 100644
index 0000000000..e5c8f50702
--- /dev/null
+++ b/engines/sci/sound/iterator/iterator.h
@@ -0,0 +1,326 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+/* Song iterator declarations */
+
+#ifndef SCI_SFX_SFX_ITERATOR_H
+#define SCI_SFX_SFX_ITERATOR_H
+
+#include "sci/sci.h" // for USE_OLD_MUSIC_FUNCTIONS
+
+#ifdef USE_OLD_MUSIC_FUNCTIONS
+#include "sci/sound/drivers/mididriver.h"
+
+namespace Audio {
+ class AudioStream;
+}
+
+namespace Sci {
+
+enum SongIteratorStatus {
+ SI_FINISHED = -1, /**< Song finished playing */
+ SI_LOOP = -2, /**< Song just looped */
+ SI_ABSOLUTE_CUE = -3, /**< Found a song cue (absolute) */
+ SI_RELATIVE_CUE = -4, /**< Found a song cue (relative) */
+ SI_PCM = -5, /**< Found a PCM */
+ SI_IGNORE = -6, /**< This event got edited out by the remapper */
+ SI_MORPH = -255 /**< Song iterator requested self-morph. */
+};
+
+#define FADE_ACTION_NONE 0
+#define FADE_ACTION_FADE_AND_STOP 1
+#define FADE_ACTION_FADE_AND_CONT 2
+
+struct fade_params_t {
+ int ticks_per_step;
+ int final_volume;
+ int step_size;
+ int action;
+};
+
+/* Helper defs for messages */
+enum {
+ _SIMSG_BASE, /* Any base decoder */
+ _SIMSG_PLASTICWRAP /* Any "Plastic" (discardable) wrapper decoder */
+};
+
+/* Base messages */
+enum {
+ _SIMSG_BASEMSG_SET_LOOPS, /* Set loops */
+ _SIMSG_BASEMSG_SET_PLAYMASK, /* Set the current playmask for filtering */
+ _SIMSG_BASEMSG_SET_RHYTHM, /* Activate/deactivate rhythm channel */
+ _SIMSG_BASEMSG_ACK_MORPH, /* Acknowledge self-morph */
+ _SIMSG_BASEMSG_STOP, /* Stop iterator */
+ _SIMSG_BASEMSG_PRINT, /* Print self to stderr, after printing param1 tabs */
+ _SIMSG_BASEMSG_SET_HOLD, /* Set value of hold parameter to expect */
+ _SIMSG_BASEMSG_SET_FADE /* Set fade parameters */
+};
+
+/* "Plastic" (discardable) wrapper messages */
+enum {
+ _SIMSG_PLASTICWRAP_ACK_MORPH = _SIMSG_BASEMSG_ACK_MORPH /* Acknowledge self-morph */
+};
+
+/* Messages */
+#define SIMSG_SET_LOOPS(x) _SIMSG_BASE,_SIMSG_BASEMSG_SET_LOOPS,(x)
+#define SIMSG_SET_PLAYMASK(x) _SIMSG_BASE,_SIMSG_BASEMSG_SET_PLAYMASK,(x)
+#define SIMSG_SET_RHYTHM(x) _SIMSG_BASE,_SIMSG_BASEMSG_SET_RHYTHM,(x)
+#define SIMSG_ACK_MORPH _SIMSG_PLASTICWRAP,_SIMSG_PLASTICWRAP_ACK_MORPH,0
+#define SIMSG_STOP _SIMSG_BASE,_SIMSG_BASEMSG_STOP,0
+#define SIMSG_PRINT(indentation) _SIMSG_BASE,_SIMSG_BASEMSG_PRINT,(indentation)
+#define SIMSG_SET_HOLD(x) _SIMSG_BASE,_SIMSG_BASEMSG_SET_HOLD,(x)
+
+/* Message transmission macro: Takes song reference, message reference */
+#define SIMSG_SEND(o, m) songit_handle_message(&(o), SongIterator::Message((o)->ID, m))
+#define SIMSG_SEND_FADE(o, m) songit_handle_message(&(o), SongIterator::Message((o)->ID, _SIMSG_BASE, _SIMSG_BASEMSG_SET_FADE, m))
+
+typedef unsigned long songit_id_t;
+
+
+#define SONGIT_MAX_LISTENERS 2
+
+class TeeSongIterator;
+
+class SongIterator {
+public:
+ struct Message {
+ songit_id_t ID;
+ uint _class; /* Type of iterator supposed to receive this */
+ uint _type;
+ union {
+ uint i;
+ void *p;
+ } _arg;
+
+ Message() : ID(0), _class(0xFFFF), _type(0xFFFF) {}
+
+ /**
+ * Create a song iterator message.
+ *
+ * @param id: song ID the message is targeted to
+ * @param recipient_class: Message recipient class
+ * @param type message type
+ * @param a argument
+ *
+ * @note You should only use this with the SIMSG_* macros
+ */
+ Message(songit_id_t id, int recipient_class, int type, int a)
+ : ID(id), _class(recipient_class), _type(type) {
+ _arg.i = a;
+ }
+
+ /**
+ * Create a song iterator message, wherein the first parameter is a pointer.
+ *
+ * @param id: song ID the message is targeted to
+ * @param recipient_class: Message recipient class
+ * @param type message type
+ * @param a argument
+ *
+ * @note You should only use this with the SIMSG_* macros
+ */
+ Message(songit_id_t id, int recipient_class, int type, void *a)
+ : ID(id), _class(recipient_class), _type(type) {
+ _arg.p = a;
+ }
+ };
+
+public:
+ songit_id_t ID;
+ uint16 channel_mask; /* Bitmask of all channels this iterator will use */
+ fade_params_t fade;
+ int priority;
+
+ /* Death listeners */
+ /* These are not reset during initialisation */
+ TeeSongIterator *_deathListeners[SONGIT_MAX_LISTENERS];
+
+ /* See songit_* for the constructor and non-virtual member functions */
+
+ byte channel_remap[MIDI_CHANNELS]; ///< Remapping for channels
+
+public:
+ SongIterator();
+ SongIterator(const SongIterator &);
+ virtual ~SongIterator();
+
+ /**
+ * Resets/initializes the sound iterator.
+ */
+ virtual void init() {}
+
+ /**
+ * Reads the next MIDI operation _or_ delta time.
+ * @param buf The buffer to write to (needs to be able to store at least 4 bytes)
+ * @param result Number of bytes written to the buffer
+ * (equals the number of bytes that need to be passed
+ * to the lower layers) for 0, the cue value for SI_CUE,
+ * or the number of loops remaining for SI_LOOP.
+ * @return zero if a MIDI operation was written, SI_FINISHED
+ * if the song has finished playing, SI_LOOP if looping
+ * (after updating the loop variable), SI_CUE if we found
+ * a cue, SI_PCM if a PCM was found, or the number of ticks
+ * to wait before this function should be called next.
+ *
+ * @note If SI_PCM is returned, get_pcm() may be used to retrieve the associated
+ * PCM, but this must be done before any subsequent calls to next().
+ *
+ * @todo The actual buffer size should either be specified or passed in, so that
+ * we can detect buffer overruns.
+ */
+ virtual int nextCommand(byte *buf, int *result) = 0;
+
+ /**
+ Checks for the presence of a pcm sample.
+ * @return NULL if no PCM data was found, an AudioStream otherwise.
+ */
+ virtual Audio::AudioStream *getAudioStream() = 0;
+
+ /**
+ * Handles a message to the song iterator.
+ * @param msg the message to handle
+ * @return NULL if the message was not understood,
+ * this if the message could be handled, or a new song iterator
+ * if the current iterator had to be morphed (but the message could
+ * still be handled)
+ *
+ * @note This function is not supposed to be called directly; use
+ * songit_handle_message() instead. It should not recurse, since songit_handle_message()
+ * takes care of that and makes sure that its delegate received the message (and
+ * was morphed) before self.
+ */
+ virtual SongIterator *handleMessage(Message msg) = 0;
+
+ /**
+ * Gets the song position to store in a savegame.
+ */
+ virtual int getTimepos() = 0;
+
+ /**
+ * Clone this song iterator.
+ * @param delta number of ticks that still need to elapse until the
+ * next item should be read from the song iterator
+ */
+ virtual SongIterator *clone(int delta) = 0;
+
+
+private:
+ // Make the assignment operator unreachable, just in case...
+ SongIterator& operator=(const SongIterator&);
+};
+
+
+/********************************/
+/*-- Song iterator operations --*/
+/********************************/
+
+enum SongIteratorType {
+ SCI_SONG_ITERATOR_TYPE_SCI0 = 0,
+ SCI_SONG_ITERATOR_TYPE_SCI1 = 1
+};
+
+#define IT_READER_MASK_MIDI (1 << 0)
+#define IT_READER_MASK_DELAY (1 << 1)
+#define IT_READER_MASK_LOOP (1 << 2)
+#define IT_READER_MASK_CUE (1 << 3)
+#define IT_READER_MASK_PCM (1 << 4)
+#define IT_READER_MAY_FREE (1 << 10) /* Free SI_FINISHED iterators */
+#define IT_READER_MAY_CLEAN (1 << 11)
+/* MAY_CLEAN: May instantiate cleanup iterators
+** (use for players; this closes open channels at the end of a song) */
+
+#define IT_READER_MASK_ALL ( IT_READER_MASK_MIDI \
+ | IT_READER_MASK_DELAY \
+ | IT_READER_MASK_LOOP \
+ | IT_READER_MASK_CUE \
+ | IT_READER_MASK_PCM )
+
+/* Convenience wrapper around it->next
+** Parameters: (SongIterator **it) Reference to the iterator to access
+** (byte *) buf: The buffer to write to (needs to be able to
+** store at least 4 bytes)
+** (int) mask: IT_READER_MASK options specifying the events to
+** listen for
+** Returns : (int) zero if a MIDI operation was written, SI_FINISHED
+** if the song has finished playing, SI_LOOP if looping
+** (after updating the loop variable), SI_CUE if we found
+** a cue, SI_PCM if a PCM was found, or the number of ticks
+** to wait before this function should be called next.
+** (int) *result: Number of bytes written to the buffer
+** (equals the number of bytes that need to be passed
+** to the lower layers) for 0, the cue value for SI_CUE,
+** or the number of loops remaining for SI_LOOP.
+*/
+int songit_next(SongIterator **it, byte *buf, int *result, int mask);
+
+/* Constructs a new song iterator object
+** Parameters: (byte *) data: The song data to iterate over
+** (uint) size: Number of bytes in the song
+** (int) type: One of the SCI_SONG_ITERATOR_TYPEs
+** (songit_id_t) id: An ID for addressing the song iterator
+** Returns : (SongIterator *) A newly allocated but uninitialized song
+** iterator, or NULL if 'type' was invalid or unsupported
+*/
+SongIterator *songit_new(byte *data, uint size, SongIteratorType type, songit_id_t id);
+
+/* Constructs a new song timer iterator object
+** Parameters: (int) delta: The delta after which to fire SI_FINISHED
+** Returns : (SongIterator *) A newly allocated but uninitialized song
+** iterator
+*/
+SongIterator *new_timer_iterator(int delta);
+
+/* Handles a message to the song iterator
+** Parameters: (SongIterator **): A reference to the variable storing the song iterator
+** Returns : (int) Non-zero if the message was understood
+** The song iterator may polymorph as result of msg, so a writeable reference is required.
+*/
+int songit_handle_message(SongIterator **it_reg, SongIterator::Message msg);
+
+
+/* Creates a new song iterator which fast-forwards
+** Parameters: (SongIterator *) it: The iterator to wrap
+** (int) delta: The number of ticks to skip
+** Returns : (SongIterator) A newly created song iterator
+** which skips all delta times
+** until 'delta' has been used up
+*/
+SongIterator *new_fast_forward_iterator(SongIterator *it, int delta);
+
+/* Combines two song iterators into one
+** Parameters: (sfx_iterator_t *) it1: One of the two iterators, or NULL
+** (sfx_iterator_t *) it2: The other iterator, or NULL
+** Returns : (sfx_iterator_t *) A combined iterator
+** If a combined iterator is returned, it will be flagged to be allowed to
+** dispose of 'it1' and 'it2', where applicable. This means that this
+** call should be used by song players, but not by the core sound system
+*/
+SongIterator *sfx_iterator_combine(SongIterator *it1, SongIterator *it2);
+
+} // End of namespace Sci
+
+#endif // USE_OLD_MUSIC_FUNCTIONS
+
+#endif // SCI_SFX_SFX_ITERATOR_H
diff --git a/engines/sci/sound/iterator/iterator_internal.h b/engines/sci/sound/iterator/iterator_internal.h
new file mode 100644
index 0000000000..5a0f0d3ec9
--- /dev/null
+++ b/engines/sci/sound/iterator/iterator_internal.h
@@ -0,0 +1,276 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef SCI_SFX_SFX_ITERATOR_INTERNAL
+#define SCI_SFX_SFX_ITERATOR_INTERNAL
+
+#include "sci/sci.h" // for USE_OLD_MUSIC_FUNCTIONS
+
+#ifdef USE_OLD_MUSIC_FUNCTIONS
+#include "sci/sound/iterator/iterator.h"
+#include "sci/sound/drivers/mididriver.h"
+
+#include "common/array.h"
+#include "common/list.h"
+
+namespace Sci {
+
+/* Iterator types */
+
+enum {
+ SI_STATE_UNINITIALISED = -1,
+ SI_STATE_DELTA_TIME = 0, ///< Now at a delta time
+ SI_STATE_COMMAND = 1, ///< Now at a MIDI operation
+ SI_STATE_PENDING = 2, ///< Pending for loop
+ SI_STATE_FINISHED = 3, ///< End of song
+ SI_STATE_PCM = 4, ///< Should report a PCM next (-> DELTA_TIME)
+ SI_STATE_PCM_MAGIC_DELTA = 5 ///< Should report a ``magic'' one tick delta time next (goes on to FINISHED)
+};
+
+struct SongIteratorChannel {
+
+ int state; ///< State of this song iterator channel
+ int offset; ///< Offset into the data chunk */
+ int end; ///< Last allowed byte in track */
+ int id; ///< Some channel ID */
+
+ /**
+ * Number of ticks before the specified channel is next used, or
+ * CHANNEL_DELAY_MISSING to indicate that the delay has not yet
+ * been read.
+ */
+ int delay;
+
+ /* Two additional offsets for recovering: */
+ int loop_offset;
+ int initial_offset;
+
+ int playmask; ///< Active playmask (MIDI channels to play in here) */
+ int loop_timepos; ///< Total delay for this channel's loop marker */
+ int total_timepos; ///< Number of ticks since the beginning, ignoring loops */
+ int timepos_increment; ///< Number of ticks until the next command (to add) */
+
+ byte last_cmd; ///< Last operation executed, for running status */
+
+public:
+ void init(int id, int offset, int end);
+ void resetSynthChannels();
+};
+
+class BaseSongIterator : public SongIterator {
+public:
+ int _polyphony[MIDI_CHANNELS]; ///< # of simultaneous notes on each
+
+ int _ccc; ///< Cumulative cue counter, for those who need it
+ byte _resetflag; ///< for 0x4C -- on DoSound StopSound, do we return to start?
+ int _deviceId; ///< ID of the device we generating events for
+ int _numActiveChannels; ///< Number of active channels
+ Common::Array<byte> _data; ///< Song data
+
+ int _loops; ///< Number of loops remaining
+
+public:
+ BaseSongIterator(byte *data, uint size, songit_id_t id);
+
+protected:
+ int parseMidiCommand(byte *buf, int *result, SongIteratorChannel *channel, int flags);
+ int processMidi(byte *buf, int *result, SongIteratorChannel *channel, int flags);
+};
+
+/********************************/
+/*--------- SCI 0 --------------*/
+/********************************/
+
+class Sci0SongIterator : public BaseSongIterator {
+public:
+ SongIteratorChannel _channel;
+
+public:
+ Sci0SongIterator(byte *data, uint size, songit_id_t id);
+
+ int nextCommand(byte *buf, int *result);
+ Audio::AudioStream *getAudioStream();
+ SongIterator *handleMessage(Message msg);
+ void init();
+ int getTimepos();
+ SongIterator *clone(int delta);
+};
+
+
+/********************************/
+/*--------- SCI 1 --------------*/
+/********************************/
+
+
+struct Sci1Sample {
+ /**
+ * Time left-- initially, this is 'Sample point 1'.
+ * After initialisation, it is 'sample point 1 minus the sample
+ * point of the previous sample'
+ */
+ int delta;
+ int size;
+ bool announced; /* Announced for download (SI_PCM) */
+ int rate;
+ byte *_data;
+};
+
+class Sci1SongIterator : public BaseSongIterator {
+public:
+ SongIteratorChannel _channels[MIDI_CHANNELS];
+
+ /* Invariant: Whenever channels[i].delay == CHANNEL_DELAY_MISSING,
+ ** channel_offset[i] points to a delta time object. */
+
+ bool _initialised; /**!< Whether the MIDI channel setup has been initialised */
+ int _numChannels; /**!< Number of channels actually used */
+ Common::List<Sci1Sample> _samples;
+ int _numLoopedChannels; /**!< Number of channels that are ready to loop */
+
+ int _delayRemaining; /**!< Number of ticks that haven't been polled yet */
+ int _hold;
+
+public:
+ Sci1SongIterator(byte *data, uint size, songit_id_t id);
+ ~Sci1SongIterator();
+
+ int nextCommand(byte *buf, int *result);
+ Audio::AudioStream *getAudioStream();
+ SongIterator *handleMessage(Message msg);
+ void init();
+ int getTimepos();
+ SongIterator *clone(int delta);
+
+private:
+ int initSample(const int offset);
+ int initSong();
+
+ int getSmallestDelta() const;
+
+ void updateDelta(int delta);
+
+ /** Checks that none of the channels is waiting for its delta to be read */
+ bool noDeltaTime() const;
+
+ /** Determine the channel # of the next active event, or -1 */
+ int getCommandIndex() const;
+};
+
+#define PLAYMASK_NONE 0x0
+
+/***************************/
+/*--------- Timer ---------*/
+/***************************/
+
+/**
+ * A song iterator which waits a specified time and then fires
+ * SI_FINISHED. Used by DoSound, where audio resources are played (SCI1)
+ */
+class TimerSongIterator : public SongIterator {
+protected:
+ int _delta; /**!< Remaining time */
+
+public:
+ TimerSongIterator(int delta) : _delta(delta) {}
+
+ int nextCommand(byte *buf, int *result);
+ Audio::AudioStream *getAudioStream() { return NULL; }
+ SongIterator *handleMessage(Message msg) { return NULL; }
+ int getTimepos() { return 0; }
+ SongIterator *clone(int delta) { return new TimerSongIterator(*this); }
+};
+
+/**********************************/
+/*--------- Fast Forward ---------*/
+/**********************************/
+
+/**
+ * A song iterator which fast-forwards another iterator.
+ * Skips all delta times until a specified 'delta' has been used up.
+ */
+class FastForwardSongIterator : public SongIterator {
+protected:
+ SongIterator *_delegate;
+ int _delta; /**!< Remaining time */
+
+public:
+ FastForwardSongIterator(SongIterator *capsit, int delta);
+
+ int nextCommand(byte *buf, int *result);
+ Audio::AudioStream *getAudioStream();
+ SongIterator *handleMessage(Message msg);
+ int getTimepos();
+ SongIterator *clone(int delta);
+};
+
+
+/**********************************/
+/*--------- Tee iterator ---------*/
+/**********************************/
+
+enum {
+ TEE_LEFT = 0,
+ TEE_RIGHT = 1,
+ TEE_LEFT_ACTIVE = (1<<0),
+ TEE_RIGHT_ACTIVE = (1<<1),
+ TEE_LEFT_READY = (1<<2), /**!< left result is ready */
+ TEE_RIGHT_READY = (1<<3), /**!< right result is ready */
+ TEE_LEFT_PCM = (1<<4),
+ TEE_RIGHT_PCM = (1<<5)
+};
+
+/**
+ * This iterator combines two iterators, returns the next event available from either.
+ */
+class TeeSongIterator : public SongIterator {
+public:
+ int _status;
+
+ bool _readyToMorph; /**!< One of TEE_MORPH_* above */
+
+ struct {
+ SongIterator *it;
+ byte buf[4];
+ int result;
+ int retval;
+ } _children[2];
+
+public:
+ TeeSongIterator(SongIterator *left, SongIterator *right);
+ ~TeeSongIterator();
+
+ int nextCommand(byte *buf, int *result);
+ Audio::AudioStream *getAudioStream();
+ SongIterator *handleMessage(Message msg);
+ void init();
+ int getTimepos() { return 0; }
+ SongIterator *clone(int delta);
+};
+
+} // End of namespace Sci
+
+#endif // USE_OLD_MUSIC_FUNCTIONS
+
+#endif // SCI_SFX_SFX_ITERATOR_INTERNAL
diff --git a/engines/sci/sound/iterator/songlib.cpp b/engines/sci/sound/iterator/songlib.cpp
new file mode 100644
index 0000000000..8bc2e8f476
--- /dev/null
+++ b/engines/sci/sound/iterator/songlib.cpp
@@ -0,0 +1,189 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "sci/sci.h" // for USE_OLD_MUSIC_FUNCTIONS
+
+#ifdef USE_OLD_MUSIC_FUNCTIONS
+#include "sci/sound/iterator/core.h"
+#include "sci/sound/iterator/iterator.h"
+
+namespace Sci {
+
+#define debug_stream stderr
+
+Song::Song() : _wakeupTime(0, SFX_TICKS_PER_SEC) {
+ _handle = 0;
+ _resourceNum = 0;
+ _priority = 0;
+ _status = SOUND_STATUS_STOPPED;
+
+ _restoreBehavior = RESTORE_BEHAVIOR_CONTINUE;
+ _restoreTime = 0;
+
+ _loops = 0;
+ _hold = 0;
+
+ _it = 0;
+ _delay = 0;
+
+ _next = NULL;
+ _nextPlaying = NULL;
+ _nextStopping = NULL;
+}
+
+Song::Song(SongHandle handle, SongIterator *it, int priority) : _wakeupTime(0, SFX_TICKS_PER_SEC) {
+ _handle = handle;
+ _resourceNum = 0;
+ _priority = priority;
+ _status = SOUND_STATUS_STOPPED;
+
+ _restoreBehavior = RESTORE_BEHAVIOR_CONTINUE;
+ _restoreTime = 0;
+
+ _loops = 0;
+ _hold = 0;
+
+ _it = it;
+ _delay = 0;
+
+ _next = NULL;
+ _nextPlaying = NULL;
+ _nextStopping = NULL;
+}
+
+void SongLibrary::addSong(Song *song) {
+ Song **seeker = NULL;
+ int pri = song->_priority;
+
+ if (NULL == song) {
+ warning("addSong(): NULL passed for song");
+ return;
+ }
+
+ seeker = &_lib;
+ while (*seeker && ((*seeker)->_priority > pri))
+ seeker = &((*seeker)->_next);
+
+ song->_next = *seeker;
+ *seeker = song;
+}
+
+void SongLibrary::freeSounds() {
+ Song *next = _lib;
+ while (next) {
+ Song *song = next;
+ delete song->_it;
+ song->_it = NULL;
+ next = song->_next;
+ delete song;
+ }
+ _lib = NULL;
+}
+
+
+Song *SongLibrary::findSong(SongHandle handle) {
+ Song *seeker = _lib;
+
+ while (seeker) {
+ if (seeker->_handle == handle)
+ break;
+ seeker = seeker->_next;
+ }
+
+ return seeker;
+}
+
+Song *SongLibrary::findNextActive(Song *other) {
+ Song *seeker = other ? other->_next : _lib;
+
+ while (seeker) {
+ if ((seeker->_status == SOUND_STATUS_WAITING) ||
+ (seeker->_status == SOUND_STATUS_PLAYING))
+ break;
+ seeker = seeker->_next;
+ }
+
+ /* Only return songs that have equal priority */
+ if (other && seeker && other->_priority > seeker->_priority)
+ return NULL;
+
+ return seeker;
+}
+
+Song *SongLibrary::findFirstActive() {
+ return findNextActive(NULL);
+}
+
+int SongLibrary::removeSong(SongHandle handle) {
+ int retval;
+ Song *goner = _lib;
+
+ if (!goner)
+ return -1;
+
+ if (goner->_handle == handle)
+ _lib = goner->_next;
+
+ else {
+ while ((goner->_next) && (goner->_next->_handle != handle))
+ goner = goner->_next;
+
+ if (goner->_next) { /* Found him? */
+ Song *oldnext = goner->_next;
+
+ goner->_next = goner->_next->_next;
+ goner = oldnext;
+ } else return -1; /* No. */
+ }
+
+ retval = goner->_status;
+
+ delete goner->_it;
+ delete goner;
+
+ return retval;
+}
+
+int SongLibrary::countSongs() {
+ Song *seeker = _lib;
+ int retval = 0;
+
+ while (seeker) {
+ retval++;
+ seeker = seeker->_next;
+ }
+
+ return retval;
+}
+
+void SongLibrary::setSongRestoreBehavior(SongHandle handle, RESTORE_BEHAVIOR action) {
+ Song *seeker = findSong(handle);
+
+ seeker->_restoreBehavior = action;
+}
+
+} // End of namespace Sci
+
+#endif // USE_OLD_MUSIC_FUNCTIONS
diff --git a/engines/sci/sound/iterator/songlib.h b/engines/sci/sound/iterator/songlib.h
new file mode 100644
index 0000000000..acb704edaa
--- /dev/null
+++ b/engines/sci/sound/iterator/songlib.h
@@ -0,0 +1,171 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+/* Song library */
+
+#ifndef SCI_SFX_SFX_SONGLIB_H
+#define SCI_SFX_SFX_SONGLIB_H
+
+#include "common/scummsys.h"
+#include "sound/timestamp.h"
+
+#include "sci/sci.h" // for USE_OLD_MUSIC_FUNCTIONS
+#ifdef USE_OLD_MUSIC_FUNCTIONS
+
+namespace Sci {
+
+class SongIterator;
+
+#define SOUND_STATUS_STOPPED 0
+#define SOUND_STATUS_PLAYING 1
+#define SOUND_STATUS_SUSPENDED 2
+/* suspended: only if ordered from kernel space */
+#define SOUND_STATUS_WAITING 3
+/* "waiting" means "tagged for playing, but not active right now" */
+
+typedef unsigned long SongHandle;
+
+enum RESTORE_BEHAVIOR {
+ RESTORE_BEHAVIOR_CONTINUE, /* restart a song when restored from
+ a saved game */
+ RESTORE_BEHAVIOR_RESTART /* continue it from where it was */
+};
+
+class Song {
+public:
+ SongHandle _handle;
+ int _resourceNum; /**<! Resource number */
+ int _priority; /**!< Song priority (more important if priority is higher) */
+ int _status; /* See above */
+
+ int _restoreBehavior;
+ int _restoreTime;
+
+ /* Grabbed from the sound iterator, for save/restore purposes */
+ int _loops;
+ int _hold;
+
+ SongIterator *_it;
+ int _delay; /**!< Delay before accessing the iterator, in ticks */
+
+ Audio::Timestamp _wakeupTime; /**!< Timestamp indicating the next MIDI event */
+
+ Song *_next; /**!< Next song or NULL if this is the last one */
+
+ /**
+ * Next playing song. Used by the core song system.
+ */
+ Song *_nextPlaying;
+
+ /**
+ * Next song pending stopping. Used exclusively by the core song system's
+ * _update_multi_song()
+ */
+ Song *_nextStopping;
+
+public:
+
+ Song();
+
+ /**
+ * Initializes a new song.
+ * @param handle the sound handle
+ * @param it the song
+ * @param priority the song's priority
+ * @return a freshly allocated song
+ */
+ Song(SongHandle handle, SongIterator *it, int priority);
+};
+
+
+class SongLibrary {
+public:
+ Song *_lib;
+
+public:
+ SongLibrary() : _lib(0) {}
+
+ /** Frees a song library. */
+ void freeSounds();
+
+ /**
+ * Adds a song to a song library.
+ * @param song song to add
+ */
+ void addSong(Song *song);
+
+ /**
+ * Looks up the song with the specified handle.
+ * @param handle sound handle to look for
+ * @return the song or NULL if it wasn't found
+ */
+ Song *findSong(SongHandle handle);
+
+ /**
+ * Finds the first song playing with the highest priority.
+ * @return the song that should be played next, or NULL if there is none
+ */
+ Song *findFirstActive();
+
+ /**
+ * Finds the next song playing with the highest priority.
+ *
+ * The functions 'findFirstActive' and 'findNextActive'
+ * allow to iterate over all songs that satisfy the requirement of
+ * being 'playable'.
+ *
+ * @param song a song previously returned from the song library
+ * @return the next song to play relative to 'song', or NULL if none are left
+ */
+ Song *findNextActive(Song *song);
+
+ /**
+ * Removes a song from the library.
+ * @param handle handle of the song to remove
+ * @return the status of the song that was removed
+ */
+ int removeSong(SongHandle handle);
+
+ /**
+ * Counts the number of songs in a song library.
+ * @return the number of songs
+ */
+ int countSongs();
+
+ /**
+ * Determines what should be done with the song "handle" when restoring
+ * it from a saved game.
+ * @param handle sound handle being restored
+ * @param action desired action
+ */
+ void setSongRestoreBehavior(SongHandle handle,
+ RESTORE_BEHAVIOR action);
+};
+
+} // End of namespace Sci
+
+#endif // USE_OLD_MUSIC_FUNCTIONS
+
+#endif // SCI_SSFX_SFX_SONGLIB_H
diff --git a/engines/sci/sound/iterator/test-iterator.cpp b/engines/sci/sound/iterator/test-iterator.cpp
new file mode 100644
index 0000000000..0d603a89fd
--- /dev/null
+++ b/engines/sci/sound/iterator/test-iterator.cpp
@@ -0,0 +1,423 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "iterator.h"
+#include "iterator_internal.h"
+#include <stdarg.h>
+#include <stdio.h>
+
+using namespace Sci;
+
+#define ASSERT_S(x) if (!(x)) { error("Failed assertion in L%d: " #x, __LINE__); return; }
+#define ASSERT(x) ASSERT_S(x)
+
+/* Tests the song iterators */
+
+int errors = 0;
+
+void error(char *fmt, ...) {
+ va_list ap;
+
+ fprintf(stderr, "[ERROR] ");
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ ++errors;
+}
+
+
+/* The simple iterator will finish after a fixed amount of time. Before that,
+** it emits (absolute) cues in ascending order. */
+struct simple_iterator : public SongIterator {
+ int lifetime_remaining;
+ char *cues;
+ int cue_counter;
+ int cue_progress;
+ int cues_nr;
+};
+
+int simple_it_next(SongIterator *_self, unsigned char *buf, int *result) {
+ simple_iterator *self = (simple_iterator *)_self;
+
+ if (self->lifetime_remaining == -1) {
+ error("Song iterator called post mortem");
+ return SI_FINISHED;
+ }
+
+ if (self->lifetime_remaining) {
+
+ if (self->cue_counter < self->cues_nr) {
+ int time_to_cue = self->cues[self->cue_counter];
+
+ if (self->cue_progress == time_to_cue) {
+ ++self->cue_counter;
+ self->cue_progress = 0;
+ *result = self->cue_counter;
+ return SI_ABSOLUTE_CUE;
+ } else {
+ int retval = time_to_cue - self->cue_progress;
+ self->cue_progress = time_to_cue;
+
+ if (retval > self->lifetime_remaining) {
+ retval = self->lifetime_remaining;
+ self->lifetime_remaining = 0;
+ self->cue_progress = retval;
+ return retval;
+ }
+
+ self->lifetime_remaining -= retval;
+ return retval;
+ }
+ } else {
+ int retval = self->lifetime_remaining;
+ self->lifetime_remaining = 0;
+ return retval;
+ }
+
+ } else {
+ self->lifetime_remaining = -1;
+ return SI_FINISHED;
+ }
+}
+
+Audio::AudioStream *simple_it_pcm_feed(SongIterator *_self) {
+ error("No PCM feed");
+ return NULL;
+}
+
+void simple_it_init(SongIterator *_self) {
+}
+
+SongIterator *simple_it_handle_message(SongIterator *_self, SongIterator::Message msg) {
+ return NULL;
+}
+
+void simple_it_cleanup(SongIterator *_self) {
+}
+
+/* Initialises the simple iterator.
+** Parameters: (int) delay: Number of ticks until the iterator finishes
+** (int *) cues: An array of cue delays (cue values are [1,2...])
+** (int) cues_nr: Number of cues in ``cues''
+** The first cue is emitted after cues[0] ticks, and it is 1. After cues[1] additional ticks
+** the next cue is emitted, and so on. */
+SongIterator *setup_simple_iterator(int delay, char *cues, int cues_nr) {
+ simple_iterator.lifetime_remaining = delay;
+ simple_iterator.cues = cues;
+ simple_iterator.cue_counter = 0;
+ simple_iterator.cues_nr = cues_nr;
+ simple_iterator.cue_progress = 0;
+
+ simple_iterator.ID = 42;
+ simple_iterator.channel_mask = 0x004f;
+ simple_iterator.flags = 0;
+ simple_iterator.priority = 1;
+
+ simple_iterator.death_listeners_nr = 0;
+
+ simple_iterator.cleanup = simple_it_cleanup;
+ simple_iterator.init = simple_it_init;
+ simple_iterator.handle_message = simple_it_handle_message;
+ simple_iterator.get_pcm_feed = simple_it_pcm_feed;
+ simple_iterator.next = simple_it_next;
+
+ return (SongIterator *) &simple_iterator;
+}
+
+#define ASSERT_SIT ASSERT(it == simple_it)
+#define ASSERT_FFIT ASSERT(it == ff_it)
+#define ASSERT_NEXT(n) ASSERT(songit_next(&it, data, &result, IT_READER_MASK_ALL) == n)
+#define ASSERT_RESULT(n) ASSERT(result == n)
+#define ASSERT_CUE(n) ASSERT_NEXT(SI_ABSOLUTE_CUE); ASSERT_RESULT(n)
+
+void test_simple_it() {
+ SongIterator *it;
+ SongIterator *simple_it = (SongIterator *) & simple_iterator;
+ unsigned char data[4];
+ int result;
+ puts("[TEST] simple iterator (test artifact)");
+
+ it = setup_simple_iterator(42, NULL, 0);
+
+ ASSERT_SIT;
+ ASSERT_NEXT(42);
+ ASSERT_SIT;
+ ASSERT_NEXT(SI_FINISHED);
+ ASSERT_SIT;
+
+ it = setup_simple_iterator(42, "\003\004", 2);
+ ASSERT_SIT;
+ ASSERT_NEXT(3);
+ ASSERT_CUE(1);
+ ASSERT_SIT;
+ ASSERT_NEXT(4);
+ ASSERT_CUE(2);
+ ASSERT_SIT;
+// warning("XXX => %d", songit_next(&it, data, &result, IT_READER_MASK_ALL));
+ ASSERT_NEXT(35);
+ ASSERT_NEXT(SI_FINISHED);
+ ASSERT_SIT;
+
+ puts("[TEST] Test OK.");
+}
+
+void test_fastforward() {
+ SongIterator *it;
+ SongIterator *simple_it = (SongIterator *) & simple_iterator;
+ SongIterator *ff_it;
+ unsigned char data[4];
+ int result;
+ puts("[TEST] fast-forward iterator");
+
+ it = setup_simple_iterator(42, NULL, 0);
+ ff_it = it = new_fast_forward_iterator(it, 0);
+ ASSERT_FFIT;
+ ASSERT_NEXT(42);
+ ASSERT_SIT; /* Must have morphed back */
+ ASSERT_NEXT(SI_FINISHED);
+ ASSERT_SIT;
+
+ it = setup_simple_iterator(42, NULL, 0);
+ ff_it = it = new_fast_forward_iterator(it, 1);
+ ASSERT_FFIT;
+ ASSERT_NEXT(41);
+ /* May or may not have morphed back here */
+ ASSERT_NEXT(SI_FINISHED);
+ ASSERT_SIT;
+
+ it = setup_simple_iterator(42, NULL, 0);
+ ff_it = it = new_fast_forward_iterator(it, 41);
+ ASSERT_FFIT;
+ ASSERT_NEXT(1);
+ /* May or may not have morphed back here */
+ ASSERT_NEXT(SI_FINISHED);
+ ASSERT_SIT;
+
+ it = setup_simple_iterator(42, NULL, 0);
+ ff_it = it = new_fast_forward_iterator(it, 42);
+ ASSERT_NEXT(SI_FINISHED);
+ /* May or may not have morphed back here */
+
+ it = setup_simple_iterator(42, NULL, 0);
+ ff_it = it = new_fast_forward_iterator(it, 10000);
+ ASSERT_NEXT(SI_FINISHED);
+ /* May or may not have morphed back here */
+
+ it = setup_simple_iterator(42, "\003\004", 2);
+ ff_it = it = new_fast_forward_iterator(it, 2);
+ ASSERT_FFIT;
+ ASSERT_NEXT(1);
+ ASSERT_CUE(1);
+ ASSERT_SIT;
+ ASSERT_NEXT(4);
+ ASSERT_CUE(2);
+ ASSERT_SIT;
+ ASSERT_NEXT(35);
+ ASSERT_NEXT(SI_FINISHED);
+ ASSERT_SIT;
+
+ it = setup_simple_iterator(42, "\003\004", 2);
+ ff_it = it = new_fast_forward_iterator(it, 5);
+ ASSERT_FFIT;
+ ASSERT_CUE(1);
+ ASSERT_FFIT;
+ ASSERT_NEXT(2);
+ ASSERT_CUE(2);
+ ASSERT_SIT;
+ ASSERT_NEXT(35);
+ ASSERT_NEXT(SI_FINISHED);
+ ASSERT_SIT;
+
+ it = setup_simple_iterator(42, "\003\004", 2);
+ ff_it = it = new_fast_forward_iterator(it, 41);
+ ASSERT_FFIT;
+ ASSERT_CUE(1);
+ ASSERT_FFIT;
+ ASSERT_CUE(2);
+ ASSERT_FFIT;
+ ASSERT_NEXT(1);
+ ASSERT_NEXT(SI_FINISHED);
+ ASSERT_SIT;
+
+ puts("[TEST] Test OK.");
+}
+
+#define SIMPLE_SONG_SIZE 50
+
+static unsigned char simple_song[SIMPLE_SONG_SIZE] = {
+ 0x00, /* Regular song */
+ /* Only use channel 0 for all devices */
+ 0x02, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* Song begins here */
+ 42, 0x90, 60, 0x7f, /* Play C after 42 ticks */
+ 02, 64, 0x42, /* Play E after 2 more ticks, using running status mode */
+ 0xf8, 10, 0x80, 60, 0x02, /* Stop C after 250 ticks */
+ 0, 64, 0x00, /* Stop E immediately */
+ 00, 0xfc /* Stop song */
+};
+
+#define ASSERT_MIDI3(cmd, arg0, arg1) \
+ ASSERT(data[0] == cmd); \
+ ASSERT(data[1] == arg0); \
+ ASSERT(data[2] == arg1);
+
+void test_iterator_sci0() {
+ SongIterator *it = songit_new(simple_song, SIMPLE_SONG_SIZE, SCI_SONG_ITERATOR_TYPE_SCI0, 0l);
+ unsigned char data[4];
+ int result;
+ SIMSG_SEND(it, SIMSG_SET_PLAYMASK(0x0001)); /* Initialise song, enabling channel 0 */
+
+ puts("[TEST] SCI0-style song");
+ ASSERT_NEXT(42);
+ ASSERT_NEXT(0);
+ ASSERT_MIDI3(0x90, 60, 0x7f);
+ ASSERT_NEXT(2);
+ ASSERT_NEXT(0);
+ ASSERT_MIDI3(0x90, 64, 0x42);
+ ASSERT_NEXT(250);
+ ASSERT_NEXT(0);
+ ASSERT_MIDI3(0x80, 60, 0x02);
+ ASSERT_NEXT(0);
+ ASSERT_MIDI3(0x80, 64, 0x00);
+ ASSERT_NEXT(SI_FINISHED);
+ puts("[TEST] Test OK.");
+}
+
+
+
+void test_iterator_sci0_loop() {
+ SongIterator *it = songit_new(simple_song, SIMPLE_SONG_SIZE, SCI_SONG_ITERATOR_TYPE_SCI0, 0l);
+ unsigned char data[4];
+ int result;
+ SIMSG_SEND(it, SIMSG_SET_PLAYMASK(0x0001)); /* Initialise song, enabling channel 0 */
+ SIMSG_SEND(it, SIMSG_SET_LOOPS(2)); /* Loop one additional time */
+
+ puts("[TEST] SCI0-style song with looping");
+ ASSERT_NEXT(42);
+ ASSERT_NEXT(0);
+ ASSERT_MIDI3(0x90, 60, 0x7f);
+ ASSERT_NEXT(2);
+ ASSERT_NEXT(0);
+ ASSERT_MIDI3(0x90, 64, 0x42);
+ ASSERT_NEXT(250);
+ ASSERT_NEXT(0);
+ ASSERT_MIDI3(0x80, 60, 0x02);
+ ASSERT_NEXT(0);
+ ASSERT_MIDI3(0x80, 64, 0x00);
+ ASSERT_NEXT(SI_LOOP);
+ ASSERT_NEXT(42);
+ ASSERT_NEXT(0);
+ ASSERT_MIDI3(0x90, 60, 0x7f);
+ ASSERT_NEXT(2);
+ ASSERT_NEXT(0);
+ ASSERT_MIDI3(0x90, 64, 0x42);
+ ASSERT_NEXT(250);
+ ASSERT_NEXT(0);
+ ASSERT_MIDI3(0x80, 60, 0x02);
+ ASSERT_NEXT(0);
+ ASSERT_MIDI3(0x80, 64, 0x00);
+ ASSERT_NEXT(SI_FINISHED);
+ puts("[TEST] Test OK.");
+}
+
+
+
+#define LOOP_SONG_SIZE 54
+
+unsigned char loop_song[LOOP_SONG_SIZE] = {
+ 0x00, /* Regular song song */
+ /* Only use channel 0 for all devices */
+ 0x02, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* Song begins here */
+ 42, 0x90, 60, 0x7f, /* Play C after 42 ticks */
+ 13, 0x80, 60, 0x00, /* Stop C after 13 ticks */
+ 00, 0xCF, 0x7f, /* Set loop point */
+ 02, 0x90, 64, 0x42, /* Play E after 2 more ticks, using running status mode */
+ 03, 0x80, 64, 0x00, /* Stop E after 3 ticks */
+ 00, 0xfc /* Stop song/loop */
+};
+
+
+void test_iterator_sci0_mark_loop() {
+ SongIterator *it = songit_new(loop_song, LOOP_SONG_SIZE, SCI_SONG_ITERATOR_TYPE_SCI0, 0l);
+ unsigned char data[4];
+ int result;
+ SIMSG_SEND(it, SIMSG_SET_PLAYMASK(0x0001)); /* Initialise song, enabling channel 0 */
+ SIMSG_SEND(it, SIMSG_SET_LOOPS(3)); /* Loop once more */
+
+ puts("[TEST] SCI0-style song with loop mark, looping");
+ ASSERT_NEXT(42);
+ ASSERT_NEXT(0);
+ ASSERT_MIDI3(0x90, 60, 0x7f);
+ ASSERT_NEXT(13);
+ ASSERT_NEXT(0);
+ ASSERT_MIDI3(0x80, 60, 0x00);
+ /* Loop point here: we don't observe that in the iterator interface yet, though */
+ ASSERT_NEXT(2);
+ ASSERT_NEXT(0);
+ ASSERT_MIDI3(0x90, 64, 0x42);
+ ASSERT_NEXT(3);
+ ASSERT_NEXT(0);
+ ASSERT_MIDI3(0x80, 64, 0x00);
+ /* Now we loop back to the loop pont */
+ ASSERT_NEXT(SI_LOOP);
+ ASSERT_NEXT(2);
+ ASSERT_NEXT(0);
+ ASSERT_MIDI3(0x90, 64, 0x42);
+ ASSERT_NEXT(3);
+ ASSERT_NEXT(0);
+ ASSERT_MIDI3(0x80, 64, 0x00);
+ /* ...and one final time */
+ ASSERT_NEXT(SI_LOOP);
+ ASSERT_NEXT(2);
+ ASSERT_NEXT(0);
+ ASSERT_MIDI3(0x90, 64, 0x42);
+ ASSERT_NEXT(3);
+ ASSERT_NEXT(0);
+ ASSERT_MIDI3(0x80, 64, 0x00);
+
+ ASSERT_NEXT(SI_FINISHED);
+ puts("[TEST] Test OK.");
+}
+
+
+
+int main(int argc, char **argv) {
+ test_simple_it();
+ test_fastforward();
+ test_iterator_sci0();
+ test_iterator_sci0_loop();
+ test_iterator_sci0_mark_loop();
+ if (errors != 0)
+ warning("[ERROR] %d errors total", errors);
+ return (errors != 0);
+}
diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp
index fa4804ce7d..053bf597f8 100644
--- a/engines/scumm/charset.cpp
+++ b/engines/scumm/charset.cpp
@@ -844,7 +844,7 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) {
offsX = offsY = 0;
} else {
uint32 charOffs = READ_LE_UINT32(_fontPtr + chr * 4 + 4);
- assert(charOffs < 0x14000);
+ assert(charOffs < 0x10000);
if (!charOffs)
return;
charPtr = _fontPtr + charOffs;
diff --git a/engines/scumm/debugger.cpp b/engines/scumm/debugger.cpp
index b5a4070f0b..e0582f79ef 100644
--- a/engines/scumm/debugger.cpp
+++ b/engines/scumm/debugger.cpp
@@ -868,7 +868,7 @@ bool ScummDebugger::Cmd_Passcode(int argc, const char **argv) {
detach();
} else {
- DebugPrintf("Current Passcode is %d \nUse 'passcode <SEGA CD Passcode>'\n",_vm->_scummVars[411]);
+ DebugPrintf("Use 'passcode <SEGA CD Passcode>'\n");
return true;
}
return false;
diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index 1e0bf6d4be..b160dac6f2 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -234,6 +234,19 @@ protected:
#endif
+class ConfigDialog : public GUI::OptionsDialog {
+protected:
+#ifdef SMALL_SCREEN_DEVICE
+ GUI::Dialog *_keysDialog;
+#endif
+
+public:
+ ConfigDialog();
+ ~ConfigDialog();
+
+ virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
+};
+
#pragma mark -
ScummDialog::ScummDialog(int x, int y, int w, int h) : GUI::Dialog(x, y, w, h) {
@@ -246,31 +259,223 @@ ScummDialog::ScummDialog(String name) : GUI::Dialog(name) {
#pragma mark -
-#ifndef DISABLE_HELP
+enum {
+ kSaveCmd = 'SAVE',
+ kLoadCmd = 'LOAD',
+ kPlayCmd = 'PLAY',
+ kOptionsCmd = 'OPTN',
+ kHelpCmd = 'HELP',
+ kAboutCmd = 'ABOU',
+ kQuitCmd = 'QUIT',
+ kChooseCmd = 'CHOS'
+};
ScummMenuDialog::ScummMenuDialog(ScummEngine *scumm)
- : MainMenuDialog(scumm) {
+ : ScummDialog("ScummMain"), _vm(scumm) {
+
+ new GUI::ButtonWidget(this, "ScummMain.Resume", "Resume", kPlayCmd, 'P');
+
+ _loadButton = new GUI::ButtonWidget(this, "ScummMain.Load", "Load", kLoadCmd, 'L');
+ _saveButton = new GUI::ButtonWidget(this, "ScummMain.Save", "Save", kSaveCmd, 'S');
+
+ new GUI::ButtonWidget(this, "ScummMain.Options", "Options", kOptionsCmd, 'O');
+#ifndef DISABLE_HELP
+ new GUI::ButtonWidget(this, "ScummMain.Help", "Help", kHelpCmd, 'H');
+#endif
+ new GUI::ButtonWidget(this, "ScummMain.About", "About", kAboutCmd, 'A');
+
+ new GUI::ButtonWidget(this, "ScummMain.Quit", "Quit", kQuitCmd, 'Q');
+
+ //
+ // Create the sub dialog(s)
+ //
+ _aboutDialog = new GUI::AboutDialog();
+ _optionsDialog = new ConfigDialog();
+#ifndef DISABLE_HELP
_helpDialog = new HelpDialog(scumm->_game);
- _helpButton->setEnabled(true);
+#endif
+ _saveDialog = new GUI::SaveLoadChooser("Save game:", "Save");
+ _saveDialog->setSaveMode(true);
+ _loadDialog = new GUI::SaveLoadChooser("Load game:", "Load");
+ _loadDialog->setSaveMode(false);
}
ScummMenuDialog::~ScummMenuDialog() {
+ delete _aboutDialog;
+ delete _optionsDialog;
+#ifndef DISABLE_HELP
delete _helpDialog;
+#endif
+ delete _saveDialog;
+ delete _loadDialog;
+}
+
+int ScummMenuDialog::runModal() {
+ _loadButton->setEnabled(_vm->canLoadGameStateCurrently());
+ _saveButton->setEnabled(_vm->canSaveGameStateCurrently());
+ return ScummDialog::runModal();
+}
+
+void ScummMenuDialog::reflowLayout() {
+ _loadButton->setEnabled(_vm->canLoadGameStateCurrently());
+ _saveButton->setEnabled(_vm->canSaveGameStateCurrently());
+ Dialog::reflowLayout();
}
void ScummMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
switch (cmd) {
+ case kSaveCmd:
+ save();
+ break;
+ case kLoadCmd:
+ load();
+ break;
+ case kPlayCmd:
+ close();
+ break;
+ case kOptionsCmd:
+ _optionsDialog->runModal();
+ break;
+ case kAboutCmd:
+ _aboutDialog->runModal();
+ break;
+#ifndef DISABLE_HELP
case kHelpCmd:
_helpDialog->runModal();
break;
+#endif
+ case kQuitCmd:
+ _vm->quitGame();
+ close();
+ break;
default:
- MainMenuDialog::handleCommand(sender, cmd, data);
+ ScummDialog::handleCommand(sender, cmd, data);
+ }
+}
+
+void ScummMenuDialog::save() {
+ Common::String gameId = ConfMan.get("gameid");
+
+ const EnginePlugin *plugin = 0;
+ EngineMan.findGame(gameId, &plugin);
+
+ int idx = _saveDialog->runModal(plugin, ConfMan.getActiveDomainName());
+ if (idx >= 0) {
+ String result(_saveDialog->getResultString());
+ char buffer[20];
+ const char *str;
+ if (result.empty()) {
+ // If the user was lazy and entered no save name, come up with a default name.
+ sprintf(buffer, "Save %d", idx);
+ str = buffer;
+ } else
+ str = result.c_str();
+ _vm->requestSave(idx, str);
+ close();
+ }
+}
+
+void ScummMenuDialog::load() {
+ Common::String gameId = ConfMan.get("gameid");
+
+ const EnginePlugin *plugin = 0;
+ EngineMan.findGame(gameId, &plugin);
+
+ int idx = _loadDialog->runModal(plugin, ConfMan.getActiveDomainName());
+ if (idx >= 0) {
+ _vm->requestLoad(idx);
+ close();
}
}
#pragma mark -
enum {
+ kKeysCmd = 'KEYS'
+};
+
+// FIXME: We use the empty string as domain name here. This tells the
+// ConfigManager to use the 'default' domain for all its actions. We do that
+// to get as close as possible to editing the 'active' settings.
+//
+// However, that requires bad & evil hacks in the ConfigManager code,
+// and even then still doesn't work quite correctly.
+// For example, if the transient domain contains 'false' for the 'fullscreen'
+// flag, but the user used a hotkey to switch to windowed mode, then the dialog
+// will display the wrong value anyway.
+//
+// Proposed solution consisting of multiple steps:
+// 1) Add special code to the open() code that reads out everything stored
+// in the transient domain that is controlled by this dialog, and updates
+// the dialog accordingly.
+// 2) Even more code is added to query the backend for current settings, like
+// the fullscreen mode flag etc., and also updates the dialog accordingly.
+// 3) The domain being edited is set to the active game domain.
+// 4) If the dialog is closed with the "OK" button, then we remove everything
+// stored in the transient domain (or at least everything corresponding to
+// switches in this dialog.
+// If OTOH the dialog is closed with "Cancel" we do no such thing.
+//
+// These changes will achieve two things at once: Allow us to get rid of using
+// "" as value for the domain, and in fact provide a somewhat better user
+// experience at the same time.
+ConfigDialog::ConfigDialog()
+ : GUI::OptionsDialog("", "ScummConfig") {
+
+ //
+ // Sound controllers
+ //
+
+ addVolumeControls(this, "ScummConfig.");
+
+ //
+ // Some misc options
+ //
+
+ // SCUMM has a talkspeed range of 0-9
+ addSubtitleControls(this, "ScummConfig.", 9);
+
+ //
+ // Add the buttons
+ //
+
+ new GUI::ButtonWidget(this, "ScummConfig.Ok", "OK", GUI::kOKCmd, 'O');
+ new GUI::ButtonWidget(this, "ScummConfig.Cancel", "Cancel", GUI::kCloseCmd, 'C');
+#ifdef SMALL_SCREEN_DEVICE
+ new GUI::ButtonWidget(this, "ScummConfig.Keys", "Keys", kKeysCmd, 'K');
+ _keysDialog = NULL;
+#endif
+}
+
+ConfigDialog::~ConfigDialog() {
+#ifdef SMALL_SCREEN_DEVICE
+ delete _keysDialog;
+#endif
+}
+
+void ConfigDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
+ switch (cmd) {
+ case kKeysCmd:
+#ifdef SMALL_SCREEN_DEVICE
+ //
+ // Create the sub dialog(s)
+ //
+ _keysDialog = new GUI::KeysDialog();
+ _keysDialog->runModal();
+ delete _keysDialog;
+ _keysDialog = NULL;
+#endif
+ break;
+ default:
+ GUI::OptionsDialog::handleCommand (sender, cmd, data);
+ }
+}
+
+#ifndef DISABLE_HELP
+
+#pragma mark -
+
+enum {
kNextCmd = 'NEXT',
kPrevCmd = 'PREV'
};
diff --git a/engines/scumm/dialogs.h b/engines/scumm/dialogs.h
index 41a8ec83c1..7889027dcf 100644
--- a/engines/scumm/dialogs.h
+++ b/engines/scumm/dialogs.h
@@ -27,8 +27,9 @@
#include "common/str.h"
#include "gui/dialog.h"
+#include "gui/options.h"
#include "gui/widget.h"
-#include "engines/dialogs.h"
+#include "gui/saveload.h"
#include "scumm/detection.h"
@@ -51,17 +52,32 @@ protected:
typedef Common::String String;
};
-#ifndef DISABLE_HELP
-class ScummMenuDialog : public MainMenuDialog {
+class ScummMenuDialog : public ScummDialog {
public:
ScummMenuDialog(ScummEngine *scumm);
~ScummMenuDialog();
virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
+ virtual void reflowLayout();
+
+ int runModal();
protected:
+ ScummEngine *_vm;
+
+ GUI::Dialog *_aboutDialog;
+ GUI::Dialog *_optionsDialog;
+#ifndef DISABLE_HELP
GUI::Dialog *_helpDialog;
-};
#endif
+ GUI::SaveLoadChooser *_saveDialog;
+ GUI::SaveLoadChooser *_loadDialog;
+
+ GUI::ButtonWidget *_loadButton;
+ GUI::ButtonWidget *_saveButton;
+
+ void save();
+ void load();
+};
/**
* A dialog which displays an arbitrary message to the user and returns
diff --git a/engines/scumm/he/resource_he.cpp b/engines/scumm/he/resource_he.cpp
index c259c3ffd2..886ee99e57 100644
--- a/engines/scumm/he/resource_he.cpp
+++ b/engines/scumm/he/resource_he.cpp
@@ -633,10 +633,8 @@ Win32ResExtractor::WinResource *Win32ResExtractor::list_pe_resources(WinLibrary
wr[c].children = fi->first_resource + (FROM_LE_32(dirent[c].offset_to_data) & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY);
/* fill in wr->id, wr->numeric_id */
- if (!decode_pe_resource_id(fi, wr + c, FROM_LE_32(dirent[c].name))) {
- free(wr);
+ if (!decode_pe_resource_id(fi, wr + c, FROM_LE_32(dirent[c].name)))
return NULL;
- }
}
return wr;
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index dc3a5d26b3..8a9570f534 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -508,7 +508,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
if (VAR_SAVELOAD_SCRIPT != 0xFF && _currentRoom != 0)
runScript(VAR(VAR_SAVELOAD_SCRIPT), 0, 0, 0);
- openMainMenuDialog(); // Display global main menu
+ scummMenuDialog(); // Display GUI
if (VAR_SAVELOAD_SCRIPT != 0xFF && _currentRoom != 0)
runScript(VAR(VAR_SAVELOAD_SCRIPT2), 0, 0, 0);
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index fc95060b6f..dcbe4e6c0a 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -108,7 +108,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
_language(dr.language),
_debugger(0),
_currentScript(0xFF), // Let debug() work on init stage
- _messageDialog(0), _pauseDialog(0), _versionDialog(0) {
+ _messageDialog(0), _pauseDialog(0), _scummMenuDialog(0), _versionDialog(0) {
if (_game.platform == Common::kPlatformNES) {
_gdi = new GdiNES(this);
@@ -140,6 +140,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
_fileHandle = 0;
+
// Init all vars
_v0ObjectIndex = false;
_v0ObjectInInventory = false;
@@ -151,6 +152,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
_sound = NULL;
memset(&vm, 0, sizeof(vm));
_pauseDialog = NULL;
+ _scummMenuDialog = NULL;
_versionDialog = NULL;
_fastMode = 0;
_actors = NULL;
@@ -550,12 +552,6 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
for (int i = 0; i < ARRAYSIZE(debugChannels); ++i)
DebugMan.addDebugChannel(debugChannels[i].flag, debugChannels[i].channel, debugChannels[i].desc);
-#ifndef DISABLE_HELP
- // Create custom GMM dialog providing a help subdialog
- assert(!_mainMenuDialog);
- _mainMenuDialog = new ScummMenuDialog(this);
-#endif
-
g_eventRec.registerRandomSource(_rnd, "scumm");
}
@@ -576,6 +572,7 @@ ScummEngine::~ScummEngine() {
delete _charset;
delete _messageDialog;
delete _pauseDialog;
+ delete _scummMenuDialog;
delete _versionDialog;
delete _fileHandle;
@@ -2447,6 +2444,13 @@ void ScummEngine::versionDialog() {
runDialog(*_versionDialog);
}
+void ScummEngine::scummMenuDialog() {
+ if (!_scummMenuDialog)
+ _scummMenuDialog = new ScummMenuDialog(this);
+ runDialog(*_scummMenuDialog);
+ syncSoundSettings();
+}
+
void ScummEngine::confirmExitDialog() {
ConfirmDialog d(this, 6);
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 42322ba5a2..885ab790de 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -530,6 +530,7 @@ protected:
Dialog *_pauseDialog;
Dialog *_messageDialog;
Dialog *_versionDialog;
+ Dialog *_scummMenuDialog;
virtual int runDialog(Dialog &dialog);
void confirmExitDialog();
@@ -537,6 +538,7 @@ protected:
void pauseDialog();
void messageDialog(const char *message);
void versionDialog();
+ void scummMenuDialog();
char displayMessage(const char *altButton, const char *message, ...) GCC_PRINTF(3, 4);
diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp
index 441e622184..c0e7be7758 100644
--- a/engines/sword1/animation.cpp
+++ b/engines/sword1/animation.cpp
@@ -23,6 +23,7 @@
*
*/
+
#include "common/file.h"
#include "sword1/sword1.h"
#include "sword1/animation.h"
@@ -71,9 +72,6 @@ MoviePlayer::MoviePlayer(SwordEngine *vm, Text *textMan, Audio::Mixer *snd, OSys
_bgSoundStream = NULL;
_decoderType = decoderType;
_decoder = decoder;
-
- _white = 255;
- _black = 0;
}
MoviePlayer::~MoviePlayer() {
@@ -256,35 +254,9 @@ bool MoviePlayer::playVideo() {
if (frame)
_vm->_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h);
- if (_decoder->hasDirtyPalette()) {
+ if (_decoder->hasDirtyPalette())
_decoder->setSystemPalette();
- uint32 maxWeight = 0;
- uint32 minWeight = 0xFFFFFFFF;
- uint32 weight;
- byte r, g, b;
-
- byte *palette = _decoder->getPalette();
-
- for (int i = 0; i < 256; i++) {
- r = *palette++;
- g = *palette++;
- b = *palette++;
-
- weight = 3 * r * r + 6 * g * g + 2 * b * b;
-
- if (weight >= maxWeight) {
- maxWeight = weight;
- _white = i;
- }
-
- if (weight <= minWeight) {
- minWeight = weight;
- _black = i;
- }
- }
- }
-
Graphics::Surface *screen = _vm->_system->lockScreen();
performPostProcessing((byte *)screen->pixels);
_vm->_system->unlockScreen();
@@ -295,19 +267,17 @@ bool MoviePlayer::playVideo() {
while (_vm->_system->getEventManager()->pollEvent(event))
if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP)
return false;
-
- _vm->_system->delayMillis(10);
}
return !_vm->shouldQuit();
}
byte MoviePlayer::findBlackPalIndex() {
- return _black;
+ return 0;
}
byte MoviePlayer::findWhitePalIndex() {
- return _white;
+ return 0xff;
}
DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle)
diff --git a/engines/sword1/animation.h b/engines/sword1/animation.h
index 193d5cf7ca..82343f2800 100644
--- a/engines/sword1/animation.h
+++ b/engines/sword1/animation.h
@@ -85,7 +85,6 @@ protected:
OSystem *_system;
Common::Array<MovieText *> _movieTexts;
int _textX, _textY, _textWidth, _textHeight;
- byte _white, _black;
DecoderType _decoderType;
Graphics::VideoDecoder *_decoder;
diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp
index 10895b2ec1..c3f3e796b2 100644
--- a/engines/sword2/animation.cpp
+++ b/engines/sword2/animation.cpp
@@ -51,9 +51,6 @@ MoviePlayer::MoviePlayer(Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, A
_bgSoundStream = NULL;
_decoderType = decoderType;
_decoder = decoder;
-
- _white = 255;
- _black = 0;
}
MoviePlayer:: ~MoviePlayer() {
@@ -283,35 +280,9 @@ bool MoviePlayer::playVideo() {
if (frame)
_vm->_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h);
- if (_decoder->hasDirtyPalette()) {
+ if (_decoder->hasDirtyPalette())
_decoder->setSystemPalette();
- uint32 maxWeight = 0;
- uint32 minWeight = 0xFFFFFFFF;
- uint32 weight;
- byte r, g, b;
-
- byte *palette = _decoder->getPalette();
-
- for (int i = 0; i < 256; i++) {
- r = *palette++;
- g = *palette++;
- b = *palette++;
-
- weight = 3 * r * r + 6 * g * g + 2 * b * b;
-
- if (weight >= maxWeight) {
- maxWeight = weight;
- _white = i;
- }
-
- if (weight <= minWeight) {
- minWeight = weight;
- _black = i;
- }
- }
- }
-
Graphics::Surface *screen = _vm->_system->lockScreen();
performPostProcessing((byte *)screen->pixels);
_vm->_system->unlockScreen();
@@ -322,19 +293,17 @@ bool MoviePlayer::playVideo() {
while (_vm->_system->getEventManager()->pollEvent(event))
if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP)
return false;
-
- _vm->_system->delayMillis(10);
}
return !_vm->shouldQuit();
}
byte MoviePlayer::findBlackPalIndex() {
- return _black;
+ return 0;
}
byte MoviePlayer::findWhitePalIndex() {
- return _white;
+ return 0xff;
}
DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle)
diff --git a/engines/sword2/animation.h b/engines/sword2/animation.h
index ee32b1d5f2..bbf83e264c 100644
--- a/engines/sword2/animation.h
+++ b/engines/sword2/animation.h
@@ -87,7 +87,6 @@ protected:
uint32 _currentMovieText;
byte *_textSurface;
int _textX, _textY;
- byte _white, _black;
DecoderType _decoderType;
Graphics::VideoDecoder *_decoder;
diff --git a/engines/tinsel/handle.cpp b/engines/tinsel/handle.cpp
index fdc4484a7c..df686f8bee 100644
--- a/engines/tinsel/handle.cpp
+++ b/engines/tinsel/handle.cpp
@@ -284,8 +284,7 @@ void LoadFile(MEMHANDLE *pH) {
}
// extract and zero terminate the filename
- memcpy(szFilename, pH->szName, sizeof(pH->szName));
- szFilename[sizeof(pH->szName)] = 0;
+ Common::strlcpy(szFilename, pH->szName, sizeof(pH->szName));
if (f.open(szFilename)) {
// read the data
diff --git a/graphics/video/coktelvideo/coktelvideo.cpp b/graphics/video/coktelvideo/coktelvideo.cpp
new file mode 100644
index 0000000000..4d93815b44
--- /dev/null
+++ b/graphics/video/coktelvideo/coktelvideo.cpp
@@ -0,0 +1,2657 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "graphics/video/coktelvideo/coktelvideo.h"
+
+#ifdef GRAPHICS_VIDEO_COKTELVIDEO_H
+
+#include "common/endian.h"
+#include "common/system.h"
+
+#include "graphics/dither.h"
+#include "graphics/video/coktelvideo/indeo3.h"
+
+#include "sound/audiostream.h"
+#include "sound/decoders/raw.h"
+
+namespace Graphics {
+
+PreImd::PreImd() {
+ zeroData();
+
+ _forcedWidth = 0;
+ _forcedHeight = 0;
+}
+
+PreImd::PreImd(int16 width, int16 height) {
+ zeroData();
+
+ _forcedWidth = width;
+ _forcedHeight = height;
+}
+
+PreImd::~PreImd() {
+ deleteData();
+ zeroData();
+}
+
+uint32 PreImd::getFeatures() const {
+ return _features;
+}
+
+uint16 PreImd::getFlags() const {
+ return _flags;
+}
+
+int16 PreImd::getX() const {
+ return _x;
+}
+
+int16 PreImd::getY() const {
+ return _y;
+}
+
+int16 PreImd::getWidth() const {
+ return _width;
+}
+
+int16 PreImd::getHeight() const {
+ return _height;
+}
+
+uint16 PreImd::getFramesCount() const {
+ return _framesCount;
+}
+
+uint16 PreImd::getCurrentFrame() const {
+ return _curFrame;
+}
+
+void PreImd::setFrameRate(int16 frameRate) {
+ if (frameRate == 0)
+ frameRate = 1;
+
+ _frameRate = frameRate;
+ _frameLength = 1000 / _frameRate;
+}
+
+int16 PreImd::getFrameRate() const {
+ return 0;
+}
+
+uint32 PreImd::getSyncLag() const {
+ return 0;
+}
+
+const byte *PreImd::getPalette() const {
+ return _palette;
+}
+
+bool PreImd::getFrameCoords(int16 frame,
+ int16 &x, int16 &y, int16 &width, int16 &height) {
+
+ return false;
+}
+
+bool PreImd::hasExtraData() const {
+ return false;
+}
+
+bool PreImd::hasExtraData(const char *fileName) const {
+ return false;
+}
+
+Common::MemoryReadStream *PreImd::getExtraData(const char *fileName) {
+ return 0;
+}
+
+bool PreImd::load(Common::SeekableReadStream &stream) {
+ // Since PreIMDs don't have any width and height values stored,
+ // we need them to be specified in the constructor
+ assert((_forcedWidth > 0) && (_forcedHeight > 0));
+
+ unload();
+
+ _stream = &stream;
+
+ _stream->seek(0);
+
+ _framesCount = _stream->readUint16LE();
+
+ _width = _forcedWidth;
+ _height = _forcedHeight;
+
+ _vidBufferSize = _width * _height;
+ _vidBuffer = new byte[_vidBufferSize];
+ memset(_vidBuffer, 0, _vidBufferSize);
+
+ return true;
+}
+
+void PreImd::unload() {
+ clear();
+}
+
+void PreImd::setXY(int16 x, int16 y) {
+ _x = x;
+ _y = y;
+}
+
+void PreImd::setVideoMemory(byte *vidMem, uint16 width, uint16 height) {
+ deleteVidMem();
+
+ _hasOwnVidMem = false;
+ _vidMem = vidMem;
+ _vidMemWidth = width;
+ _vidMemHeight = height;
+}
+
+void PreImd::setVideoMemory() {
+ deleteVidMem();
+
+ if ((_width > 0) && (_height > 0)) {
+ setXY(0, 0);
+ _hasOwnVidMem = true;
+ _vidMem = new byte[_width * _height];
+ _vidMemWidth = _width;
+ _vidMemHeight = _height;
+
+ memset(_vidMem, 0, _width * _height);
+ }
+}
+
+void PreImd::setDoubleMode(bool doubleMode) {
+}
+
+void PreImd::enableSound(Audio::Mixer &mixer) {
+}
+
+void PreImd::disableSound() {
+}
+
+bool PreImd::isSoundPlaying() const {
+ return false;
+}
+
+void PreImd::seekFrame(int32 frame, int16 whence, bool restart) {
+ if (!_stream)
+ // Nothing to do
+ return;
+
+ // Find the frame to which to seek
+ if (whence == SEEK_CUR)
+ frame += _curFrame;
+ else if (whence == SEEK_END)
+ frame = _framesCount - frame - 1;
+ else if (whence != SEEK_SET)
+ return;
+
+ if ((frame < 0) || (frame >= _framesCount) || (frame == _curFrame))
+ // Nothing to do
+ return;
+
+ // Run through the frames
+ _curFrame = 0;
+ _stream->seek(2);
+ while (_curFrame != frame) {
+ uint16 frameSize = _stream->readUint16LE();
+
+ _stream->skip(frameSize + 2);
+
+ _curFrame++;
+ }
+}
+
+CoktelVideo::State PreImd::nextFrame() {
+ return processFrame(_curFrame);
+}
+
+uint32 PreImd::getFrameWaitTime() {
+ return _frameLength;
+}
+
+void PreImd::waitEndFrame() {
+ uint32 waitTime = getFrameWaitTime();
+ if (waitTime > 0)
+ g_system->delayMillis(waitTime);
+}
+
+void PreImd::copyCurrentFrame(byte *dest,
+ uint16 left, uint16 top, uint16 width, uint16 height,
+ uint16 x, uint16 y, uint16 pitch, int16 transp) {
+}
+
+void PreImd::zeroVidMem() {
+ _hasOwnVidMem = false;
+ _vidMem = 0;
+ _vidMemWidth = 0;
+ _vidMemHeight = 0;
+}
+
+void PreImd::deleteVidMem() {
+ if (_hasOwnVidMem)
+ delete[] _vidMem;
+
+ zeroVidMem();
+}
+
+void PreImd::zeroData() {
+ _stream = 0;
+
+ _features = 0;
+ _flags = 0;
+
+ _x = 0;
+ _y = 0;
+ _width = 0;
+ _height = 0;
+
+ _framesCount = 0;
+ _curFrame = 0;
+ _frameRate = 12;
+ _frameLength = 1000 / _frameRate;
+
+ memset(_palette, 0, 768);
+
+ zeroVidMem();
+
+ _vidBufferSize = 0;
+ _vidBuffer = 0;
+}
+
+void PreImd::deleteData() {
+ deleteVidMem();
+
+ delete[] _vidBuffer;
+}
+
+void PreImd::clear() {
+ deleteData();
+ zeroData();
+}
+
+CoktelVideo::State PreImd::processFrame(uint16 frame) {
+ assert((_width > 0) && (_height > 0));
+
+ State state;
+
+ if (!_stream || (frame >= _framesCount)) {
+ state.flags = kStateBreak;
+ return state;
+ }
+
+ if (frame != _curFrame) {
+ state.flags |= kStateSeeked;
+ seekFrame(frame);
+ }
+
+ if (!_vidMem)
+ setVideoMemory();
+
+ uint16 frameSize = _stream->readUint16LE();
+
+ uint32 nextFramePos = _stream->pos() + frameSize + 2;
+
+ byte cmd;
+
+ cmd = _stream->readByte();
+ frameSize--;
+
+ bool hasPalette = false;
+ if (cmd == 0) {
+ // Palette. Ignored by Fascination, though
+
+ hasPalette = true;
+
+ _stream->read(_palette, 768);
+
+ frameSize -= 769;
+
+ cmd = _stream->readByte();
+ }
+
+ if (cmd != 2) {
+ // Partial frame data
+
+ uint32 fSize = frameSize;
+ uint32 vidSize = _vidBufferSize;
+ byte *vidBuffer = _vidBuffer;
+
+ while ((fSize > 0) && (vidSize > 0)) {
+ uint32 n = _stream->readByte();
+ fSize--;
+
+ if ((n & 0x80) != 0) {
+ // Data
+
+ n = MIN<uint32>((n & 0x7F) + 1, MIN(fSize, vidSize));
+
+ _stream->read(vidBuffer, n);
+
+ vidBuffer += n;
+ vidSize -= n;
+ fSize -= n;
+
+ } else {
+ // Skip
+
+ n = MIN<uint32>(n + 1, vidSize);
+
+ vidBuffer += n;
+ vidSize -= n;
+ }
+ }
+
+ } else {
+ // Full direct frame
+
+ uint32 vidSize = MIN<uint32>(_vidBufferSize, frameSize);
+
+ _stream->read(_vidBuffer, vidSize);
+ }
+
+ renderFrame();
+
+ _stream->seek(nextFramePos);
+
+ _curFrame++;
+
+ // Complete frame needs to be updated
+ state.left = _x;
+ state.top = _y;
+ state.right = _x + _width - 1;
+ state.bottom = _y + _height - 1;
+
+ return state;
+}
+
+// Simple blit
+void PreImd::renderFrame() {
+ assert(_vidMem);
+
+ uint16 w = MIN<uint16>(_vidMemWidth , _width);
+ uint16 h = MIN<uint16>(_vidMemHeight, _height);
+
+ const byte *src = _vidBuffer;
+ byte *dst = _vidMem + (_y * _vidMemWidth) + _x;
+
+ uint32 frameDataSize = _vidBufferSize;
+
+ while (h-- > 0) {
+ uint32 n = MIN<uint32>(w, frameDataSize);
+
+ memcpy(dst, src, n);
+
+ src += _width;
+ dst += _vidMemWidth;
+
+ frameDataSize -= n;
+ }
+}
+
+
+Imd::Imd() {
+ zeroData();
+}
+
+Imd::~Imd() {
+ deleteData();
+ zeroData();
+}
+
+void Imd::setFrameRate(int16 frameRate) {
+ if (frameRate == 0)
+ frameRate = 1;
+
+ _frameRate = frameRate;
+ _frameLength = 1000 / _frameRate;
+}
+
+int16 Imd::getFrameRate() const {
+ if (!_hasSound)
+ return _frameRate;
+
+ return 1000 / (_soundSliceLength >> 16);
+}
+
+uint32 Imd::getSyncLag() const {
+ return _skipFrames;
+}
+
+bool Imd::loadCoordinates() {
+ // Standard coordinates
+ if (_version >= 3) {
+ _stdX = _stream->readUint16LE();
+ if (_stdX > 1) {
+ warning("IMD: More than one standard coordinate quad found (%d)", _stdX);
+ return false;
+ }
+ if (_stdX != 0) {
+ _stdX = _stream->readSint16LE();
+ _stdY = _stream->readSint16LE();
+ _stdWidth = _stream->readSint16LE();
+ _stdHeight = _stream->readSint16LE();
+ _features |= kFeaturesStdCoords;
+ } else
+ _stdX = -1;
+ } else
+ _stdX = -1;
+
+ return true;
+}
+
+bool Imd::loadFrameTableOffsets(uint32 &framesPosPos, uint32 &framesCoordsPos) {
+ framesPosPos = 0;
+ framesCoordsPos = 0;
+
+ // Frame positions
+ if (_version >= 4) {
+ framesPosPos = _stream->readUint32LE();
+ if (framesPosPos != 0) {
+ _framesPos = new uint32[_framesCount];
+ assert(_framesPos);
+ _features |= kFeaturesFramesPos;
+ }
+ }
+
+ // Frame coordinates
+ if (_features & kFeaturesFrameCoords)
+ framesCoordsPos = _stream->readUint32LE();
+
+ return true;
+}
+
+bool Imd::assessVideoProperties() {
+ // Sizes of the frame data and extra video buffer
+ if (_features & kFeaturesDataSize) {
+ _frameDataSize = _stream->readUint16LE();
+ if (_frameDataSize == 0) {
+ _frameDataSize = _stream->readUint32LE();
+ _vidBufferSize = _stream->readUint32LE();
+ } else
+ _vidBufferSize = _stream->readUint16LE();
+ } else {
+ _frameDataSize = _width * _height + 500;
+ if (!(_flags & 0x100) || (_flags & 0x1000))
+ _vidBufferSize = _frameDataSize;
+ }
+
+ // Allocating working memory
+ _frameData = new byte[_frameDataSize + 500];
+ assert(_frameData);
+ memset(_frameData, 0, _frameDataSize + 500);
+ _vidBuffer = new byte[_vidBufferSize + 500];
+ assert(_vidBuffer);
+ memset(_vidBuffer, 0, _vidBufferSize + 500);
+
+ return true;
+}
+
+bool Imd::assessAudioProperties() {
+ if (_features & kFeaturesSound) {
+ _soundFreq = _stream->readSint16LE();
+ _soundSliceSize = _stream->readSint16LE();
+ _soundSlicesCount = _stream->readSint16LE();
+
+ if (_soundFreq < 0)
+ _soundFreq = -_soundFreq;
+
+ if (_soundSlicesCount < 0)
+ _soundSlicesCount = -_soundSlicesCount - 1;
+
+ if (_soundSlicesCount > 40) {
+ warning("Imd::load(): More than 40 sound slices found (%d)", _soundSlicesCount);
+ return false;
+ }
+
+ _soundSliceLength = (uint32) (((double) (1000 << 16)) /
+ ((double) _soundFreq / (double) _soundSliceSize));
+ _frameLength = _soundSliceLength >> 16;
+
+ _soundStage = 1;
+ _hasSound = true;
+
+ _audioStream = Audio::makeQueuingAudioStream(_soundFreq, false);
+ } else
+ _frameLength = 1000 / _frameRate;
+
+ return true;
+}
+
+bool Imd::loadFrameTables(uint32 framesPosPos, uint32 framesCoordsPos) {
+ // Positions table
+ if (_framesPos) {
+ _stream->seek(framesPosPos, SEEK_SET);
+ for (int i = 0; i < _framesCount; i++)
+ _framesPos[i] = _stream->readUint32LE();
+ }
+
+ // Coordinates table
+ if (_features & kFeaturesFrameCoords) {
+ _stream->seek(framesCoordsPos, SEEK_SET);
+ _frameCoords = new Coord[_framesCount];
+ assert(_frameCoords);
+ for (int i = 0; i < _framesCount; i++) {
+ _frameCoords[i].left = _stream->readSint16LE();
+ _frameCoords[i].top = _stream->readSint16LE();
+ _frameCoords[i].right = _stream->readSint16LE();
+ _frameCoords[i].bottom = _stream->readSint16LE();
+ }
+ }
+
+ return true;
+}
+
+bool Imd::load(Common::SeekableReadStream &stream) {
+ unload();
+
+ _stream = &stream;
+
+ uint16 handle;
+
+ handle = _stream->readUint16LE();
+ _version = _stream->readByte();
+
+ // Version checking
+ if ((handle != 0) || (_version < 2)) {
+ warning("Imd::load(): Version incorrect (%d,%X)", handle, _version);
+ unload();
+ return false;
+ }
+
+ // Rest header
+ _features = _stream->readByte();
+ _framesCount = _stream->readUint16LE();
+ _x = _stream->readSint16LE();
+ _y = _stream->readSint16LE();
+ _width = _stream->readSint16LE();
+ _height = _stream->readSint16LE();
+ _flags = _stream->readUint16LE();
+ _firstFramePos = _stream->readUint16LE();
+
+ // IMDs always have video
+ _features |= kFeaturesVideo;
+ // IMDs always have palettes
+ _features |= kFeaturesPalette;
+
+ // Palette
+ _stream->read((byte *) _palette, 768);
+
+ if (!loadCoordinates()) {
+ unload();
+ return false;
+ }
+
+ uint32 framesPosPos, frameCoordsPos;
+ if (!loadFrameTableOffsets(framesPosPos, frameCoordsPos)) {
+ unload();
+ return false;
+ }
+
+ if (!assessAudioProperties()) {
+ unload();
+ return false;
+ }
+
+ if (!assessVideoProperties()) {
+ unload();
+ return false;
+ }
+
+ if (!loadFrameTables(framesPosPos, frameCoordsPos)) {
+ unload();
+ return false;
+ }
+
+ // Seek to the first frame
+ _stream->seek(_firstFramePos, SEEK_SET);
+
+ return true;
+}
+
+void Imd::unload() {
+ clear();
+}
+
+void Imd::setXY(int16 x, int16 y) {
+ // Adjusting the standard coordinates
+ if (_stdX != -1) {
+ if (x >= 0)
+ _stdX = _stdX - _x + x;
+ if (y >= 0)
+ _stdY = _stdY - _y + y;
+ }
+
+ // Going through the coordinate table as well
+ if (_frameCoords) {
+ for (int i = 0; i < _framesCount; i++) {
+ if (_frameCoords[i].left != -1) {
+ if (x >= 0) {
+ _frameCoords[i].left = _frameCoords[i].left - _x + x;
+ _frameCoords[i].right = _frameCoords[i].right - _x + x;
+ }
+ if (y >= 0) {
+ _frameCoords[i].top = _frameCoords[i].top - _y + y;
+ _frameCoords[i].bottom = _frameCoords[i].bottom - _y + y;
+ }
+ }
+ }
+ }
+
+ if (x >= 0)
+ _x = x;
+ if (y >= 0)
+ _y = y;
+}
+
+void Imd::enableSound(Audio::Mixer &mixer) {
+ // Sanity check
+ if (mixer.getOutputRate() == 0)
+ return;
+
+ // Only possible on the first frame
+ if (_curFrame > 0)
+ return;
+
+ _mixer = &mixer;
+ _soundEnabled = true;
+}
+
+void Imd::disableSound() {
+ if (_audioStream) {
+
+ if (_soundStage == 2) {
+ _audioStream->finish();
+ _mixer->stopHandle(_audioHandle);
+ } else
+ delete _audioStream;
+
+ _audioStream = 0;
+ _soundStage = 0;
+ }
+ _soundEnabled = false;
+ _mixer = 0;
+}
+
+bool Imd::isSoundPlaying() const {
+ if (_audioStream && _mixer && _mixer->isSoundHandleActive(_audioHandle))
+ return true;
+
+ return false;
+}
+
+void Imd::seekFrame(int32 frame, int16 whence, bool restart) {
+ if (!_stream)
+ // Nothing to do
+ return;
+
+ // Find the frame to which to seek
+ if (whence == SEEK_CUR)
+ frame += _curFrame;
+ else if (whence == SEEK_END)
+ frame = _framesCount - frame - 1;
+ else if (whence != SEEK_SET)
+ return;
+
+ if ((frame < 0) || (frame >= _framesCount) || (frame == _curFrame))
+ // Nothing to do
+ return;
+
+ // Try every possible way to find a file offset to that frame
+ uint32 framePos = 0;
+ if (frame == 0) {
+ framePos = _firstFramePos;
+ } else if (frame == 1) {
+ framePos = _firstFramePos;
+ _stream->seek(framePos, SEEK_SET);
+ framePos += _stream->readUint16LE() + 4;
+ } else if (_framesPos) {
+ framePos = _framesPos[frame];
+ } else if (restart && (_soundStage == 0)) {
+ for (int i = ((frame > _curFrame) ? _curFrame : 0); i <= frame; i++)
+ processFrame(i);
+ return;
+//FIXME: This workaround is needed for Bargon Attack intro, which was broken by a fix concerning Ween in r42995.
+ } else if (_soundStage == 0) {
+ warning("Imd::seekFrame(): Avoiding \"Frame %d is not directly accessible\"", frame);
+ _curFrame = frame;
+//End of fixme
+ } else
+ error("Imd::seekFrame(): Frame %d is not directly accessible", frame);
+
+ // Seek
+ _stream->seek(framePos);
+ _curFrame = frame;
+}
+
+CoktelVideo::State Imd::nextFrame() {
+ return processFrame(_curFrame);
+}
+
+uint32 Imd::getFrameWaitTime() {
+ if (_soundEnabled && _hasSound) {;
+ if (_soundStage != 2)
+ return 0;
+
+ if (_skipFrames == 0) {
+ int32 waitTime = (int16) (((_curFrame * _soundSliceLength) -
+ (_mixer->getSoundElapsedTime(_audioHandle) << 16)) >> 16);
+
+ if (waitTime < 0) {
+ _skipFrames = -waitTime / (_soundSliceLength >> 16);
+ warning("Video A/V sync broken, skipping %d frame(s)", _skipFrames + 1);
+ } else if (waitTime > 0)
+ return waitTime;
+
+ } else
+ _skipFrames--;
+ } else
+ return _frameLength;
+
+ return 0;
+}
+
+void Imd::copyCurrentFrame(byte *dest,
+ uint16 left, uint16 top, uint16 width, uint16 height,
+ uint16 x, uint16 y, uint16 pitch, int16 transp) {
+
+ if (!_vidMem)
+ return;
+
+ if (((left + width) > _width) || ((top + height) > _height))
+ return;
+
+ dest += pitch * y;
+ byte *vidMem = _vidMem + _width * top;
+
+ if (transp < 0) {
+ // No transparency
+ if ((x > 0) || (left > 0) || (pitch != _width) || (width != _width)) {
+ // Copy row-by-row
+ for (int i = 0; i < height; i++) {
+ byte *d = dest + x;
+ byte *s = vidMem + left;
+
+ memcpy(d, s, width);
+
+ dest += pitch;
+ vidMem += _width;
+ }
+ } else
+ // Dimensions fit, copy everything at once
+ memcpy(dest, vidMem, width * height);
+
+ return;
+ }
+
+ for (int i = 0; i < height; i++) {
+ byte *d = dest + x;
+ byte *s = vidMem + left;
+
+ for (int j = 0; j < width; j++) {
+ if (*s != transp)
+ *d = *s;
+
+ s++;
+ d++;
+ }
+
+ dest += pitch;
+ vidMem += _width;
+ }
+
+}
+
+void Imd::zeroData() {
+ PreImd::zeroData();
+
+ _version = 0;
+
+ _stdX = 0;
+ _stdY = 0;
+ _stdWidth = 0;
+ _stdHeight = 0;
+
+ _framesPos = 0;
+ _firstFramePos = 0;
+ _frameCoords = 0;
+
+ _frameDataSize = 0;
+ _frameData = 0;
+ _frameDataLen = 0;
+
+ _hasSound = false;
+ _soundEnabled = false;
+ _soundStage = 0;
+ _skipFrames = 0;
+
+ _soundFlags = 0;
+ _soundFreq = 0;
+ _soundSliceSize = 0;
+ _soundSlicesCount = 0;
+ _soundSliceLength = 0;
+ _audioStream = 0;
+
+ _lastFrameTime = 0;
+}
+
+void Imd::deleteData() {
+ PreImd::deleteData();
+
+ delete[] _framesPos;
+ delete[] _frameCoords;
+ delete[] _frameData;
+
+ disableSound();
+}
+
+void Imd::clear() {
+ deleteData();
+ zeroData();
+}
+
+void Imd::nextSoundSlice(bool hasNextCmd) {
+ if (hasNextCmd || !_soundEnabled) {
+ _stream->seek(_soundSliceSize, SEEK_CUR);
+ return;
+ }
+
+ byte *soundBuf = (byte *)malloc(_soundSliceSize);
+
+ _stream->read(soundBuf, _soundSliceSize);
+ unsignedToSigned(soundBuf, _soundSliceSize);
+
+ _audioStream->queueBuffer(soundBuf, _soundSliceSize, DisposeAfterUse::YES, 0);
+}
+
+bool Imd::initialSoundSlice(bool hasNextCmd) {
+ int dataLength = _soundSliceSize * _soundSlicesCount;
+
+ if (hasNextCmd || !_soundEnabled) {
+ _stream->seek(dataLength, SEEK_CUR);
+ return false;
+ }
+
+ byte *soundBuf = (byte *)malloc(dataLength);
+
+ _stream->read(soundBuf, dataLength);
+ unsignedToSigned(soundBuf, dataLength);
+
+ _audioStream->queueBuffer(soundBuf, dataLength, DisposeAfterUse::YES, 0);
+
+ return _soundStage == 1;
+}
+
+void Imd::emptySoundSlice(bool hasNextCmd) {
+ if (hasNextCmd || !_soundEnabled)
+ return;
+
+ byte *soundBuf = (byte *)malloc(_soundSliceSize);
+
+ memset(soundBuf, 0, _soundSliceSize);
+
+ _audioStream->queueBuffer(soundBuf, _soundSliceSize, DisposeAfterUse::YES, 0);
+}
+
+void Imd::videoData(uint32 size, State &state) {
+ _stream->read(_frameData, size);
+ _frameDataLen = size;
+
+/*
+ if (_vidMemWidth <= state.right) {
+ state.left = 0;
+ state.right -= state.left;
+ }
+ if (_vidMemWidth <= state.right)
+ state.right = _vidMemWidth - 1;
+ if (_vidMemHeight <= state.bottom) {
+ state.top = 0;
+ state.bottom -= state.top;
+ }
+ if (_vidMemHeight <= state.bottom)
+ state.bottom = _vidMemHeight -1;
+*/
+
+ state.flags |= renderFrame(state.left, state.top, state.right, state.bottom);
+ state.flags |= _frameData[0];
+}
+
+void Imd::calcFrameCoords(uint16 frame, State &state) {
+ if (_stdX != -1) {
+ state.left = _stdX;
+ state.top = _stdY;
+ state.right = _stdWidth + state.left - 1;
+ state.bottom = _stdHeight + state.top - 1;
+ state.flags |= kStateStdCoords;
+ }
+ if (_frameCoords &&
+ (_frameCoords[frame].left != -1)) {
+ state.left = _frameCoords[frame].left;
+ state.top = _frameCoords[frame].top;
+ state.right = _frameCoords[frame].right;
+ state.bottom = _frameCoords[frame].bottom;
+ state.flags |= kStateFrameCoords;
+ }
+}
+
+CoktelVideo::State Imd::processFrame(uint16 frame) {
+ State state;
+ uint32 cmd = 0;
+ bool hasNextCmd = false;
+ bool startSound = false;
+
+ if (!_stream || (frame >= _framesCount)) {
+ state.flags = kStateBreak;
+ return state;
+ }
+
+ if (frame != _curFrame) {
+ state.flags |= kStateSeeked;
+ seekFrame(frame);
+ }
+
+ if (!_vidMem)
+ setVideoMemory();
+
+ state.left = _x;
+ state.top = _y;
+ state.right = _width + state.left - 1;
+ state.bottom = _height + state.top - 1;
+
+ do {
+ if (frame != 0)
+ calcFrameCoords(frame, state);
+
+ cmd = _stream->readUint16LE();
+
+ if ((cmd & kCommandBreakMask) == kCommandBreak) {
+ // Flow control
+
+ if (cmd == kCommandBreak) {
+ _stream->seek(2, SEEK_CUR);
+ cmd = _stream->readUint16LE();
+ }
+
+ // Break
+ if (cmd == kCommandBreakSkip0) {
+ state.flags = kStateBreak;
+ continue;
+ } else if (cmd == kCommandBreakSkip16) {
+ cmd = _stream->readUint16LE();
+ _stream->seek(cmd, SEEK_CUR);
+ state.flags = kStateBreak;
+ continue;
+ } else if (cmd == kCommandBreakSkip32) {
+ cmd = _stream->readUint32LE();
+ _stream->seek(cmd, SEEK_CUR);
+ state.flags = kStateBreak;
+ continue;
+ }
+ }
+
+ // Audio
+ if (_soundStage != 0) {
+ if (cmd == kCommandNextSound) {
+
+ nextSoundSlice(hasNextCmd);
+ cmd = _stream->readUint16LE();
+
+ } else if (cmd == kCommandStartSound) {
+
+ startSound = initialSoundSlice(hasNextCmd);
+ cmd = _stream->readUint16LE();
+
+ } else
+ emptySoundSlice(hasNextCmd);
+ }
+
+ // Set palette
+ if (cmd == kCommandPalette) {
+ _stream->seek(2, SEEK_CUR);
+ state.flags |= kStatePalette;
+
+ _stream->read(_palette, 768);
+ cmd = _stream->readUint16LE();
+ }
+
+ hasNextCmd = false;
+
+ if (cmd == kCommandJump) {
+ // Jump to frame
+
+ frame = _stream->readSint16LE();
+ if (_framesPos) {
+ _curFrame = frame;
+ _stream->seek(_framesPos[frame], SEEK_SET);
+
+ hasNextCmd = true;
+ state.flags |= kStateJump;
+ }
+
+ } else if (cmd == kCommandVideoData) {
+ uint32 size = _stream->readUint32LE() + 2;
+
+ videoData(size, state);
+
+ state.flags |= 1;
+
+ } else if (cmd != 0) {
+ uint32 size = cmd + 2;
+
+ videoData(size, state);
+
+ } else
+ state.flags |= kStateNoVideoData;
+
+ } while (hasNextCmd);
+
+ if (startSound && _soundEnabled) {
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_audioHandle, _audioStream);
+ _skipFrames = 0;
+ _soundStage = 2;
+ }
+
+ _curFrame++;
+ if ((_curFrame == _framesCount) && (_soundStage == 2)) {
+ _audioStream->finish();
+ _mixer->stopHandle(_audioHandle);
+ _audioStream = 0;
+ _soundStage = 0;
+ }
+
+ _lastFrameTime = g_system->getMillis();
+ return state;
+}
+
+// A whole, completely filled block
+void Imd::renderBlockWhole(byte *dest, const byte *src, int16 width, int16 height,
+ int16 destPitch, int16 srcPitch) {
+
+ for (int i = 0; i < height; i++) {
+ memcpy(dest, src, width);
+
+ src += srcPitch;
+ dest += destPitch;
+ }
+}
+
+// A quarter-wide whole, completely filled block
+void Imd::renderBlockWhole4X(byte *dest, const byte *src, int16 width, int16 height,
+ int16 destPitch, int16 srcPitch) {
+
+ for (int i = 0; i < height; i++) {
+ byte *destRow = dest;
+ const byte *srcRow = src;
+
+ for (int j = 0; j < width; j += 4, destRow += 4, srcRow++)
+ memset(destRow, *srcRow, 4);
+
+ src += srcPitch;
+ dest += destPitch;
+ }
+}
+
+// A half-high whole, completely filled block
+void Imd::renderBlockWhole2Y(byte *dest, const byte *src, int16 width, int16 height,
+ int16 destPitch, int16 srcPitch) {
+
+ while (height > 1) {
+ memcpy(dest , src, width);
+ memcpy(dest + destPitch, src, width);
+
+ height -= 2;
+ dest += 2 * destPitch;
+ src += srcPitch;
+ }
+
+ if (height == 1)
+ memcpy(dest, src, width);
+}
+
+// A sparse block
+void Imd::renderBlockSparse(byte *dest, const byte *src, int16 width, int16 height,
+ int16 destPitch, int16 srcPitch) {
+
+ for (int i = 0; i < height; i++) {
+ byte *destRow = dest;
+ int16 pixWritten = 0;
+
+ while (pixWritten < srcPitch) {
+ int16 pixCount = *src++;
+
+ if (pixCount & 0x80) { // Data
+ int16 copyCount;
+
+ pixCount = MIN((pixCount & 0x7F) + 1, srcPitch - pixWritten);
+ copyCount = MAX<int16>(0, MIN<int16>(pixCount, width - pixWritten));
+ memcpy(destRow, src, copyCount);
+
+ pixWritten += pixCount;
+ destRow += pixCount;
+ src += pixCount;
+ } else { // "Hole"
+ pixWritten += pixCount + 1;
+ destRow += pixCount + 1;
+ }
+
+ }
+
+ dest += destPitch;
+ }
+}
+
+// A half-high sparse block
+void Imd::renderBlockSparse2Y(byte *dest, const byte *src, int16 width, int16 height,
+ int16 destPitch, int16 srcPitch) {
+
+ for (int i = 0; i < height; i += 2) {
+ byte *destRow = dest;
+ int16 pixWritten = 0;
+
+ while (pixWritten < srcPitch) {
+ int16 pixCount = *src++;
+
+ if (pixCount & 0x80) { // Data
+ int16 copyCount;
+
+ pixCount = MIN((pixCount & 0x7F) + 1, srcPitch - pixWritten);
+ copyCount = MAX<int16>(0, MIN<int16>(pixCount, width - pixWritten));
+ memcpy(destRow , src, pixCount);
+ memcpy(destRow + destPitch, src, pixCount);
+
+ pixWritten += pixCount;
+ destRow += pixCount;
+ src += pixCount;
+ } else { // "Hole"
+ pixWritten += pixCount + 1;
+ destRow += pixCount + 1;
+ }
+
+ }
+
+ dest += destPitch;
+ }
+}
+
+uint32 Imd::renderFrame(int16 left, int16 top, int16 right, int16 bottom) {
+ if (!_frameData || !_vidMem || (_width <= 0) || (_height <= 0))
+ return 0;
+
+ uint32 retVal = 0;
+
+ int16 width = right - left + 1;
+ int16 height = bottom - top + 1;
+ int16 sW = _vidMemWidth;
+ int16 sH = _vidMemHeight;
+
+ byte *dataPtr = _frameData;
+ byte *imdVidMem = _vidMem + sW * top + left;
+ byte *srcPtr;
+
+ uint8 type = *dataPtr++;
+
+ if (type & 0x10) { // Palette data
+ // One byte index
+ int index = *dataPtr++;
+ // 16 entries with each 3 bytes (RGB)
+ memcpy(_palette + index * 3, dataPtr, MIN((255 - index) * 3, 48));
+
+ retVal = kStatePalette;
+ dataPtr += 48;
+ type ^= 0x10;
+ }
+
+ srcPtr = dataPtr;
+
+ if (type & 0x80) {
+ // Frame data is compressed
+
+ srcPtr = _vidBuffer;
+ type &= 0x7F;
+ if ((type == 2) && (width == sW)) {
+ // Directly uncompress onto the video surface
+ deLZ77(imdVidMem, dataPtr);
+ return retVal;
+ } else
+ deLZ77(srcPtr, dataPtr);
+ }
+
+ int16 drawWidth = MAX<int16>(0, MIN<int16>(width , sW - left));
+ int16 drawHeight = MAX<int16>(0, MIN<int16>(height, sH - top ));
+
+ // Evaluate the block type
+ if (type == 0x01)
+ renderBlockSparse (imdVidMem, srcPtr, drawWidth, drawHeight, sW, width);
+ else if (type == 0x02)
+ renderBlockWhole (imdVidMem, srcPtr, drawWidth, drawHeight, sW, width);
+ else if (type == 0x42)
+ renderBlockWhole4X (imdVidMem, srcPtr, drawWidth, drawHeight, sW, width);
+ else if ((type & 0x0F) == 0x02)
+ renderBlockWhole2Y (imdVidMem, srcPtr, drawWidth, drawHeight, sW, width);
+ else
+ renderBlockSparse2Y(imdVidMem, srcPtr, drawWidth, drawHeight, sW, width);
+
+ return retVal;
+}
+
+void Imd::deLZ77(byte *dest, byte *src) {
+ int i;
+ byte buf[4370];
+ uint16 chunkLength;
+ uint32 frameLength;
+ uint16 bufPos1;
+ uint16 bufPos2;
+ uint16 tmp;
+ uint8 chunkBitField;
+ uint8 chunkCount;
+ bool mode;
+
+ frameLength = READ_LE_UINT32(src);
+ src += 4;
+
+ if ((READ_LE_UINT16(src) == 0x1234) && (READ_LE_UINT16(src + 2) == 0x5678)) {
+ src += 4;
+ bufPos1 = 273;
+ mode = 1; // 123Ch (cmp al, 12h)
+ } else {
+ bufPos1 = 4078;
+ mode = 0; // 275h (jnz +2)
+ }
+
+ memset(buf, 32, bufPos1);
+ chunkCount = 1;
+ chunkBitField = 0;
+
+ while (frameLength > 0) {
+ chunkCount--;
+ if (chunkCount == 0) {
+ tmp = *src++;
+ chunkCount = 8;
+ chunkBitField = tmp;
+ }
+ if (chunkBitField % 2) {
+ chunkBitField >>= 1;
+ buf[bufPos1] = *src;
+ *dest++ = *src++;
+ bufPos1 = (bufPos1 + 1) % 4096;
+ frameLength--;
+ continue;
+ }
+ chunkBitField >>= 1;
+
+ tmp = READ_LE_UINT16(src);
+ src += 2;
+ chunkLength = ((tmp & 0xF00) >> 8) + 3;
+
+ if ((mode && ((chunkLength & 0xFF) == 0x12)) ||
+ (!mode && (chunkLength == 0)))
+ chunkLength = *src++ + 0x12;
+
+ bufPos2 = (tmp & 0xFF) + ((tmp >> 4) & 0x0F00);
+ if (((tmp + chunkLength) >= 4096) ||
+ ((chunkLength + bufPos1) >= 4096)) {
+
+ for (i = 0; i < chunkLength; i++, dest++) {
+ *dest = buf[bufPos2];
+ buf[bufPos1] = buf[bufPos2];
+ bufPos1 = (bufPos1 + 1) % 4096;
+ bufPos2 = (bufPos2 + 1) % 4096;
+ }
+
+ } else if (((tmp + chunkLength) < bufPos1) ||
+ ((chunkLength + bufPos1) < bufPos2)) {
+
+ memcpy(dest, buf + bufPos2, chunkLength);
+ memmove(buf + bufPos1, buf + bufPos2, chunkLength);
+
+ dest += chunkLength;
+ bufPos1 += chunkLength;
+ bufPos2 += chunkLength;
+
+ } else {
+
+ for (i = 0; i < chunkLength; i++, dest++, bufPos1++, bufPos2++) {
+ *dest = buf[bufPos2];
+ buf[bufPos1] = buf[bufPos2];
+ }
+
+ }
+ frameLength -= chunkLength;
+
+ }
+}
+
+inline void Imd::unsignedToSigned(byte *buffer, int length) {
+ while (length-- > 0) *buffer++ ^= 0x80;
+}
+
+
+Vmd::ExtraData::ExtraData() {
+ memset(name, 0, 16);
+
+ offset = 0;
+ size = 0;
+ realSize = 0;
+}
+
+
+Vmd::Part::Part() {
+ type = kPartTypeSeparator;
+ field_1 = 0;
+ field_E = 0;
+ size = 0;
+ left = 0;
+ top = 0;
+ right = 0;
+ bottom = 0;
+ id = 0;
+ flags = 0;
+}
+
+
+Vmd::Frame::Frame() {
+ parts = 0;
+ offset = 0;
+}
+
+Vmd::Frame::~Frame() {
+ delete[] parts;
+}
+
+
+const uint16 Vmd::_tableDPCM[128] = {
+ 0x0000, 0x0008, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, 0x0070, 0x0080,
+ 0x0090, 0x00A0, 0x00B0, 0x00C0, 0x00D0, 0x00E0, 0x00F0, 0x0100, 0x0110, 0x0120,
+ 0x0130, 0x0140, 0x0150, 0x0160, 0x0170, 0x0180, 0x0190, 0x01A0, 0x01B0, 0x01C0,
+ 0x01D0, 0x01E0, 0x01F0, 0x0200, 0x0208, 0x0210, 0x0218, 0x0220, 0x0228, 0x0230,
+ 0x0238, 0x0240, 0x0248, 0x0250, 0x0258, 0x0260, 0x0268, 0x0270, 0x0278, 0x0280,
+ 0x0288, 0x0290, 0x0298, 0x02A0, 0x02A8, 0x02B0, 0x02B8, 0x02C0, 0x02C8, 0x02D0,
+ 0x02D8, 0x02E0, 0x02E8, 0x02F0, 0x02F8, 0x0300, 0x0308, 0x0310, 0x0318, 0x0320,
+ 0x0328, 0x0330, 0x0338, 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370,
+ 0x0378, 0x0380, 0x0388, 0x0390, 0x0398, 0x03A0, 0x03A8, 0x03B0, 0x03B8, 0x03C0,
+ 0x03C8, 0x03D0, 0x03D8, 0x03E0, 0x03E8, 0x03F0, 0x03F8, 0x0400, 0x0440, 0x0480,
+ 0x04C0, 0x0500, 0x0540, 0x0580, 0x05C0, 0x0600, 0x0640, 0x0680, 0x06C0, 0x0700,
+ 0x0740, 0x0780, 0x07C0, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00,
+ 0x0F00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000
+};
+
+const int32 Vmd::_tableADPCM[] = {
+ 7, 8, 9, 10, 11, 12, 13, 14,
+ 16, 17, 19, 21, 23, 25, 28, 31,
+ 34, 37, 41, 45, 50, 55, 60, 66,
+ 73, 80, 88, 97, 107, 118, 130, 143,
+ 157, 173, 190, 209, 230, 253, 279, 307,
+ 337, 371, 408, 449, 494, 544, 598, 658,
+ 724, 796, 876, 963, 1060, 1166, 1282, 1411,
+ 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
+ 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
+ 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
+ 32767, 0
+};
+
+const int32 Vmd::_tableADPCMStep[] = {
+ -1, -1, -1, -1, 2, 4, 6, 8,
+ -1, -1, -1, -1, 2, 4, 6, 8
+};
+
+Vmd::Vmd(Graphics::PaletteLUT *palLUT) : _palLUT(palLUT) {
+ zeroData();
+}
+
+Vmd::~Vmd() {
+ deleteData();
+ zeroData();
+}
+
+bool Vmd::assessVideoProperties() {
+ if (_bytesPerPixel > 1)
+ _features |= kFeaturesFullColor;
+ else
+ _features |= kFeaturesPalette;
+
+ if ((_version & 2) && !(_version & 8)) {
+ _externalCodec = true;
+ _frameDataSize = _vidBufferSize = 0;
+ } else
+ _externalCodec = false;
+
+ if (_externalCodec) {
+ if (_videoCodec == MKID_BE('iv32')) {
+#ifdef USE_INDEO3
+ _features &= ~kFeaturesPalette;
+ _features |= kFeaturesFullColor;
+ _codecIndeo3 = new Indeo3(_width, _height, _palLUT);
+#else
+ warning("Vmd::assessVideoProperties(): Indeo3 decoder not compiled in");
+#endif
+ } else {
+ char *fourcc = (char *) &_videoCodec;
+
+ warning("Vmd::assessVideoProperties(): Unknow video codec FourCC \'%c%c%c%c\'",
+ fourcc[3], fourcc[2], fourcc[1], fourcc[0]);
+ return false;
+ }
+ }
+
+ _preScaleX = 1;
+ _postScaleX = 1;
+
+ if (_externalCodec)
+ _blitMode = 0;
+ else if (_bytesPerPixel == 1)
+ _blitMode = 0;
+ else if ((_bytesPerPixel == 2) || (_bytesPerPixel == 3)) {
+ int n = (_flags & 0x80) ? 2 : 3;
+
+ _blitMode = n - 1;
+
+ if (_bytesPerPixel == 2) {
+ _preScaleX = n;
+ _postScaleX = 1;
+ } else if (_bytesPerPixel == 3) {
+ _preScaleX = 1;
+ _postScaleX = n;
+ }
+
+ _bytesPerPixel = n;
+ }
+
+ _scaleExternalX = 1;
+ if (!_externalCodec && !(_flags & 0x1000))
+ _scaleExternalX = _bytesPerPixel;
+
+ if (_hasVideo) {
+ if ((_frameDataSize == 0) || (_frameDataSize > 1048576))
+ _frameDataSize = _width * _height + 1000;
+ if ((_vidBufferSize == 0) || (_vidBufferSize > 1048576))
+ _vidBufferSize = _frameDataSize;
+
+ _frameData = new byte[_frameDataSize];
+ assert(_frameData);
+ memset(_frameData, 0, _frameDataSize);
+
+ _vidBuffer = new byte[_vidBufferSize];
+ assert(_vidBuffer);
+ memset(_vidBuffer, 0, _vidBufferSize);
+
+ if (_blitMode > 0) {
+ _vidMemBuffer = new byte[_bytesPerPixel * (_width * _height + 1000)];
+ memset(_vidMemBuffer, 0, _bytesPerPixel * (_width * _height + 1000));
+ }
+ }
+
+#ifdef USE_INDEO3
+ if (_externalCodec && _codecIndeo3)
+ _features |= kFeaturesSupportsDouble;
+#endif
+
+ return true;
+}
+
+bool Vmd::assessAudioProperties() {
+ bool supportedFormat = true;
+
+ _features |= kFeaturesSound;
+
+ _soundStereo = (_soundFlags & 0x8000) ? 1 : ((_soundFlags & 0x200) ? 2 : 0);
+
+ if (_soundSliceSize < 0) {
+ _soundBytesPerSample = 2;
+ _soundSliceSize = -_soundSliceSize;
+
+ if (_soundFlags & 0x10) {
+ _audioFormat = kAudioFormat16bitADPCM;
+ _soundHeaderSize = 3;
+ _soundDataSize = _soundSliceSize >> 1;
+
+ if (_soundStereo > 0)
+ supportedFormat = false;
+
+ } else {
+ _audioFormat = kAudioFormat16bitDPCM;
+ _soundHeaderSize = 1;
+ _soundDataSize = _soundSliceSize;
+
+ if (_soundStereo == 1) {
+ supportedFormat = false;
+ } else if (_soundStereo == 2) {
+ _soundDataSize = 2 * _soundDataSize + 2;
+ _soundHeaderSize = 4;
+ }
+
+ }
+ } else {
+ _soundBytesPerSample = 1;
+ _audioFormat = kAudioFormat8bitDirect;
+ _soundHeaderSize = 0;
+ _soundDataSize = _soundSliceSize;
+
+ if (_soundStereo > 0)
+ supportedFormat = false;
+ }
+
+ if (!supportedFormat) {
+ warning("Vmd::assessAudioProperties(): Unsupported audio format: %d bits, encoding %d, stereo %d",
+ _soundBytesPerSample * 8, _audioFormat, _soundStereo);
+ return false;
+ }
+
+ _soundSliceLength = (uint32) (((double) (1000 << 16)) /
+ ((double) _soundFreq / (double) _soundSliceSize));
+ _frameLength = _soundSliceLength >> 16;
+
+ _soundStage = 1;
+
+ _audioStream = Audio::makeQueuingAudioStream(_soundFreq, _soundStereo != 0);
+
+ return true;
+}
+
+void Vmd::readFrameTable(int &numExtraData) {
+ numExtraData = 0;
+
+ _stream->seek(_frameInfoOffset);
+ _frames = new Frame[_framesCount];
+ for (uint16 i = 0; i < _framesCount; i++) {
+ _frames[i].parts = new Part[_partsPerFrame];
+ _stream->skip(2); // Unknown
+ _frames[i].offset = _stream->readUint32LE();
+ }
+
+ for (uint16 i = 0; i < _framesCount; i++) {
+ bool separator = false;
+
+ for (uint16 j = 0; j < _partsPerFrame; j++) {
+
+ _frames[i].parts[j].type = (PartType) _stream->readByte();
+ _frames[i].parts[j].field_1 = _stream->readByte();
+ _frames[i].parts[j].size = _stream->readUint32LE();
+
+ if (_frames[i].parts[j].type == kPartTypeAudio) {
+
+ _frames[i].parts[j].flags = _stream->readByte();
+ _stream->skip(9); // Unknown
+
+ } else if (_frames[i].parts[j].type == kPartTypeVideo) {
+
+ _frames[i].parts[j].left = _stream->readUint16LE();
+ _frames[i].parts[j].top = _stream->readUint16LE();
+ _frames[i].parts[j].right = _stream->readUint16LE();
+ _frames[i].parts[j].bottom = _stream->readUint16LE();
+ _frames[i].parts[j].field_E = _stream->readByte();
+ _frames[i].parts[j].flags = _stream->readByte();
+
+ } else if (_frames[i].parts[j].type == kPartTypeSpeech) {
+ _frames[i].parts[j].id = _stream->readUint16LE();
+ // Speech text file name
+ _stream->skip(8);
+ } else if (_frames[i].parts[j].type == kPartTypeExtraData) {
+ if (!separator)
+ numExtraData++;
+ _stream->skip(10);
+ } else if (_frames[i].parts[j].type == kPartTypeSeparator) {
+ separator = true;
+ _stream->skip(10);
+ } else {
+ // Unknow type
+ _stream->skip(10);
+ }
+
+ }
+ }
+}
+
+void Vmd::readExtraData() {
+ uint32 ssize = _stream->size();
+ for (uint16 i = 0; i < _framesCount; i++) {
+ _stream->seek(_frames[i].offset);
+
+ for (uint16 j = 0; j < _partsPerFrame; j++) {
+ if (_frames[i].parts[j].type == kPartTypeSeparator)
+ break;
+
+ if (_frames[i].parts[j].type == kPartTypeExtraData) {
+ ExtraData data;
+
+ data.offset = _stream->pos() + 20;
+ data.size = _frames[i].parts[j].size;
+ data.realSize = _stream->readUint32LE();
+
+ _stream->read(data.name, 16);
+ data.name[15] = '\0';
+
+ _stream->skip(_frames[i].parts[j].size - 20);
+
+ if ((((uint32) data.realSize) >= ssize) || (data.name[0] == 0))
+ continue;
+
+ _extraData.push_back(data);
+
+ } else
+ _stream->skip(_frames[i].parts[j].size);
+ }
+ }
+}
+
+bool Vmd::load(Common::SeekableReadStream &stream) {
+ unload();
+
+ _stream = &stream;
+
+ uint16 headerLength;
+ uint16 handle;
+
+ headerLength = _stream->readUint16LE();
+ handle = _stream->readUint16LE();
+ _version = _stream->readUint16LE();
+
+ bool readPalette;
+
+ // Version checking
+ if (headerLength == 50) {
+ // Newer version, used in Addy 5 upwards
+ warning("Vmd::load(): TODO: Addy 5 videos");
+ readPalette = false;
+ } else if (headerLength == 814) {
+ // Old version
+ readPalette = true;
+ } else {
+ warning("Vmd::load(): Version incorrect (%d, %d, %d)", headerLength, handle, _version);
+ unload();
+ return false;
+ }
+
+ _framesCount = _stream->readUint16LE();
+
+ _x = _stream->readSint16LE();
+ _y = _stream->readSint16LE();
+ _width = _stream->readSint16LE();
+ _height = _stream->readSint16LE();
+
+ if ((_width != 0) && (_height != 0)) {
+
+ _hasVideo = true;
+ _features |= kFeaturesVideo;
+
+ } else
+ _hasVideo = false;
+
+ _bytesPerPixel = 1;
+ if (_version & 4)
+ _bytesPerPixel = handle + 1;
+
+ if (_bytesPerPixel > 3) {
+ warning("Vmd::load(): Requested %d bytes per pixel (%d, %d, %d)", _bytesPerPixel, headerLength, handle, _version);
+ unload();
+ return false;
+ }
+
+ _flags = _stream->readUint16LE();
+
+ _partsPerFrame = _stream->readUint16LE();
+ _firstFramePos = _stream->readUint32LE();
+
+ _videoCodec = _stream->readUint32BE();
+
+ if (readPalette)
+ _stream->read((byte *) _palette, 768);
+
+ _frameDataSize = _stream->readUint32LE();
+ _vidBufferSize = _stream->readUint32LE();
+
+ _doubleMode = false;
+
+ if (_hasVideo) {
+ if (!assessVideoProperties()) {
+ unload();
+ return false;
+ }
+ }
+
+ _soundFreq = _stream->readSint16LE();
+ _soundSliceSize = _stream->readSint16LE();
+ _soundSlicesCount = _stream->readSint16LE();
+ _soundFlags = _stream->readUint16LE();
+
+ _hasSound = (_soundFreq != 0);
+
+ if (_hasSound) {
+ if (!assessAudioProperties()) {
+ unload();
+ return false;
+ }
+ } else
+ _frameLength = 1000 / _frameRate;
+
+ _frameInfoOffset = _stream->readUint32LE();
+
+ int numExtraData;
+ readFrameTable(numExtraData);
+
+ _stream->seek(_firstFramePos);
+
+ if (numExtraData == 0)
+ return true;
+
+ _extraData.reserve(numExtraData);
+ readExtraData();
+
+ _stream->seek(_firstFramePos);
+ return true;
+}
+
+void Vmd::unload() {
+ clear();
+}
+
+int16 Vmd::getWidth() const {
+ return preScaleX(_width);
+}
+
+void Vmd::setXY(int16 x, int16 y) {
+
+ x *= _scaleExternalX;
+
+ for (int i = 0; i < _framesCount; i++) {
+ for (int j = 0; j < _partsPerFrame; j++) {
+
+ if (_frames[i].parts[j].type == kPartTypeVideo) {
+ if (x >= 0) {
+ _frames[i].parts[j].left = _frames[i].parts[j].left - _x + x;
+ _frames[i].parts[j].right = _frames[i].parts[j].right - _x + x;
+ }
+ if (y >= 0) {
+ _frames[i].parts[j].top = _frames[i].parts[j].top - _y + y;
+ _frames[i].parts[j].bottom = _frames[i].parts[j].bottom - _y + y;
+ }
+ }
+
+ }
+ }
+
+ if (x >= 0)
+ _x = x;
+ if (y >= 0)
+ _y = y;
+}
+
+void Vmd::setDoubleMode(bool doubleMode) {
+ if (_doubleMode == doubleMode)
+ return;
+
+ if (_vidBuffer) {
+ delete[] _vidBuffer;
+
+ if (doubleMode)
+ _vidBufferSize *= 4;
+ else
+ _vidBufferSize /= 4;
+
+ _vidBuffer = new byte[_vidBufferSize];
+ assert(_vidBuffer);
+ memset(_vidBuffer, 0, _vidBufferSize);
+
+ }
+
+#ifdef USE_INDEO3
+ if (_codecIndeo3) {
+ delete _codecIndeo3;
+
+ _codecIndeo3 = new Indeo3(_width * (doubleMode ? 2 : 1),
+ _height * (doubleMode ? 2 : 1), _palLUT);
+ }
+#endif
+
+ _doubleMode = doubleMode;
+}
+
+void Vmd::seekFrame(int32 frame, int16 whence, bool restart) {
+ if (!_stream)
+ // Nothing to do
+ return;
+
+ // Find the frame to which to seek
+ if (whence == SEEK_CUR)
+ frame += _curFrame;
+ else if (whence == SEEK_END)
+ frame = _framesCount - frame - 1;
+ else if (whence != SEEK_SET)
+ return;
+
+ if ((frame < 0) || (frame >= _framesCount))
+ // Nothing to do
+ return;
+
+ // Restart sound
+ if (_hasSound && (frame == 0) && (_soundStage == 0) && !_audioStream) {
+ _soundStage = 1;
+ _audioStream = Audio::makeQueuingAudioStream(_soundFreq, _soundStereo != 0);
+ }
+
+ // Seek
+ _stream->seek(_frames[frame].offset);
+ _curFrame = frame;
+}
+
+CoktelVideo::State Vmd::nextFrame() {
+ State state;
+
+ state = processFrame(_curFrame);
+ _curFrame++;
+ return state;
+}
+
+void Vmd::zeroData() {
+ Imd::zeroData();
+
+ _hasVideo = true;
+ _videoCodec = 0;
+
+#ifdef USE_INDEO3
+ _codecIndeo3 = 0;
+#endif
+
+ _partsPerFrame = 0;
+ _frames = 0;
+
+ _extraData.clear();
+
+ _soundBytesPerSample = 1;
+ _soundStereo = 0;
+ _soundHeaderSize = 0;
+ _soundDataSize = 0;
+ _audioFormat = kAudioFormat8bitDirect;
+
+ _externalCodec = false;
+ _doubleMode = false;
+ _blitMode = 0;
+ _bytesPerPixel = 1;
+ _preScaleX = 1;
+ _postScaleX = 1;
+ _scaleExternalX = 1;
+ _vidMemBuffer = 0;
+}
+
+void Vmd::deleteData() {
+ Imd::deleteData();
+
+#ifdef USE_INDEO3
+ delete _codecIndeo3;
+#endif
+ delete[] _frames;
+ delete[] _vidMemBuffer;
+}
+
+void Vmd::clear() {
+ deleteData();
+ zeroData();
+}
+
+CoktelVideo::State Vmd::processFrame(uint16 frame) {
+ State state;
+ bool startSound = false;
+
+ seekFrame(frame);
+
+ state.flags |= kStateNoVideoData;
+ state.left = 0x7FFF;
+ state.top = 0x7FFF;
+ state.right = 0;
+ state.bottom = 0;
+
+ if (!_vidMem)
+ setVideoMemory();
+
+ for (uint16 i = 0; (i < _partsPerFrame) && (frame < _framesCount); i++) {
+ uint32 pos = _stream->pos();
+
+ Part &part = _frames[frame].parts[i];
+
+ if (part.type == kPartTypeAudio) {
+ // Next sound slice data
+ if (part.flags == 1) {
+
+ if (_soundEnabled) {
+ filledSoundSlice(part.size);
+
+ if (_soundStage == 1)
+ startSound = true;
+
+ } else
+ _stream->skip(part.size);
+
+ // Initial sound data (all slices)
+ } else if (part.flags == 2) {
+
+ if (_soundEnabled) {
+ uint32 mask = _stream->readUint32LE();
+ filledSoundSlices(part.size - 4, mask);
+
+ if (_soundStage == 1)
+ startSound = true;
+
+ } else
+ _stream->skip(part.size);
+
+ // Empty sound slice
+ } else if (part.flags == 3) {
+
+ if (_soundEnabled) {
+ emptySoundSlice(_soundDataSize * _soundBytesPerSample);
+
+ if (_soundStage == 1)
+ startSound = true;
+ }
+
+ _stream->skip(part.size);
+ } else if (part.flags == 4) {
+ warning("Vmd::processFrame(): TODO: Addy 5 sound type 4 (%d)", part.size);
+ disableSound();
+ _stream->skip(part.size);
+ } else {
+ warning("Vmd::processFrame(): Unknown sound type %d", part.flags);
+ _stream->skip(part.size);
+ }
+
+ _stream->seek(pos + part.size);
+
+ } else if ((part.type == kPartTypeVideo) && !_hasVideo) {
+ warning("Vmd::processFrame(): Header claims there's no video, but video found (%d)", part.size);
+ _stream->skip(part.size);
+ } else if ((part.type == kPartTypeVideo) && _hasVideo) {
+ state.flags &= ~kStateNoVideoData;
+
+ uint32 size = part.size;
+
+ // New palette
+ if (part.flags & 2) {
+ uint8 index = _stream->readByte();
+ uint8 count = _stream->readByte();
+
+ _stream->read(_palette + index * 3, (count + 1) * 3);
+ _stream->skip((255 - count) * 3);
+
+ state.flags |= kStatePalette;
+
+ size -= (768 + 2);
+ }
+
+ _stream->read(_frameData, size);
+ _frameDataLen = size;
+
+ int16 l = part.left, t = part.top, r = part.right, b = part.bottom;
+ if (renderFrame(l, t, r, b)) {
+ if (!_externalCodec) {
+ l = preScaleX(l);
+ r = preScaleX(r);
+ }
+ // Rendering succeeded, merging areas
+ state.left = MIN(state.left, l);
+ state.top = MIN(state.top, t);
+ state.right = MAX(state.right, r);
+ state.bottom = MAX(state.bottom, b);
+ }
+
+ } else if (part.type == kPartTypeSeparator) {
+ } else if (part.type == kPartTypeExtraData) {
+ _stream->skip(part.size);
+ } else if (part.type == kPartType4) {
+ // Unknown
+ _stream->skip(part.size);
+ } else if (part.type == kPartTypeSpeech) {
+ state.flags |= kStateSpeech;
+ state.speechId = part.id;
+ // Always triggers when speech starts
+ _stream->skip(part.size);
+ } else {
+ warning("Vmd::processFrame(): Unknown frame part type %d, size %d (%d of %d)", part.type, part.size, i + 1, _partsPerFrame);
+ }
+ }
+
+ if (startSound && _soundEnabled) {
+ if (_hasSound && _audioStream) {
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_audioHandle, _audioStream);
+ _skipFrames = 0;
+ _soundStage = 2;
+ } else
+ _soundStage = 0;
+ }
+
+ if ((_curFrame == (_framesCount - 1)) && (_soundStage == 2)) {
+ _audioStream->finish();
+ _mixer->stopHandle(_audioHandle);
+ _audioStream = 0;
+ _soundStage = 0;
+ }
+
+ // If these are still 0x7FFF, no video data has been processed
+ if ((state.left == 0x7FFF) || (state.top == 0x7FFF))
+ state.left = state.top = state.right = state.bottom = 0;
+
+ _lastFrameTime = g_system->getMillis();
+ return state;
+}
+
+void Vmd::deRLE(byte *&destPtr, const byte *&srcPtr, int16 destLen, int16 srcLen) {
+ srcPtr++;
+
+ if (srcLen & 1) {
+ byte data = *srcPtr++;
+
+ if (destLen > 0) {
+ *destPtr++ = data;
+ destLen--;
+ }
+ }
+
+ srcLen >>= 1;
+
+ while (srcLen > 0) {
+ uint8 tmp = *srcPtr++;
+ if (tmp & 0x80) { // Verbatim copy
+ tmp &= 0x7F;
+
+ int16 copyCount = MAX<int16>(0, MIN<int16>(destLen, tmp * 2));
+
+ memcpy(destPtr, srcPtr, copyCount);
+
+ srcPtr += tmp * 2;
+ destPtr += copyCount;
+ destLen -= copyCount;
+ } else { // 2 bytes tmp times
+ for (int i = 0; (i < tmp) && (destLen > 0); i++) {
+ for (int j = 0; j < 2; j++) {
+ if (destLen <= 0)
+ break;
+
+ *destPtr++ = srcPtr[j];
+ destLen--;
+ }
+ }
+ srcPtr += 2;
+ }
+ srcLen -= tmp;
+ }
+}
+
+// A run-length-encoded sparse block
+void Vmd::renderBlockRLE(byte *dest, const byte *src, int16 width, int16 height,
+ int16 destPitch, int16 srcPitch) {
+
+ for (int i = 0; i < height; i++) {
+ byte *destRow = dest;
+ int16 pixWritten = 0;
+
+ while (pixWritten < srcPitch) {
+ int16 pixCount = *src++;
+
+ if (pixCount & 0x80) {
+ int16 copyCount;
+
+ pixCount = (pixCount & 0x7F) + 1;
+ copyCount = MAX<int16>(0, MIN<int16>(pixCount, width - pixWritten));
+
+ if (*src != 0xFF) { // Normal copy
+
+ memcpy(destRow, src, copyCount);
+ destRow += copyCount;
+ src += pixCount;
+ } else
+ deRLE(destRow, src, copyCount, pixCount);
+
+ pixWritten += pixCount;
+ } else { // "Hole"
+ int16 copyCount = MAX<int16>(0, MIN<int16>(pixCount + 1, width - pixWritten));
+
+ destRow += copyCount;
+ pixWritten += pixCount + 1;
+ }
+
+ }
+
+ dest += destPitch;
+ }
+
+}
+
+uint32 Vmd::renderFrame(int16 &left, int16 &top, int16 &right, int16 &bottom) {
+ if (!_frameData || !_vidMem || (_width <= 0) || (_height <= 0))
+ return 0;
+
+ int16 width = right - left + 1;
+ int16 height = bottom - top + 1;
+ int16 sW = _vidMemWidth;
+ int16 sH = _vidMemHeight;
+
+ byte *dataPtr = _frameData;
+ byte *imdVidMem = _vidMem + sW * top + left;
+ byte *srcPtr;
+
+ if ((left < 0) || (top < 0) || (right < 0) || (bottom < 0))
+ return 1;
+ if ((width <= 0) || (height <= 0))
+ return 1;
+
+ uint8 type;
+ byte *dest = imdVidMem;
+
+#ifdef USE_INDEO3
+ uint32 dataLen = _frameDataLen;
+
+ if (Indeo3::isIndeo3(dataPtr, dataLen)) {
+ if (!_codecIndeo3)
+ return 0;
+
+ if (!_codecIndeo3->decompressFrame(dataPtr, dataLen, _vidBuffer,
+ width * (_doubleMode ? 2 : 1), height * (_doubleMode ? 2 : 1)))
+ return 0;
+
+ type = 2;
+ srcPtr = _vidBuffer;
+ width = _width * (_doubleMode ? 2 : 1);
+ height = _height * (_doubleMode ? 2 : 1);
+ right = left + width - 1;
+ bottom = top + height - 1;
+
+ } else {
+
+ if (_externalCodec) {
+ warning("Unknown external codec");
+ return 0;
+ }
+
+#else
+
+ if (_externalCodec) {
+ return 0;
+ } else {
+
+#endif
+
+ type = *dataPtr++;
+ srcPtr = dataPtr;
+
+ if (_blitMode > 0) {
+ dest = _vidMemBuffer + postScaleX(_width) * (top - _y) + postScaleX((left - _x));
+ imdVidMem = _vidMem + _vidMemWidth * top + preScaleX(left);
+ sW = postScaleX(_width);
+ sH = _height;
+ }
+
+ if (type & 0x80) {
+ // Frame data is compressed
+
+ srcPtr = _vidBuffer;
+ type &= 0x7F;
+ if ((type == 2) && (postScaleX(width) == sW)) {
+ // Directly uncompress onto the video surface
+ deLZ77(dest, dataPtr);
+ blit(imdVidMem, dest, width, height);
+ return 1;
+ } else
+ deLZ77(srcPtr, dataPtr);
+ }
+
+ }
+
+ width = postScaleX(width);
+
+ int16 drawWidth = MAX<int16>(0, MIN<int16>(width , sW - left));
+ int16 drawHeight = MAX<int16>(0, MIN<int16>(height, sH - top ));
+
+ // Evaluate the block type
+ if (type == 0x01)
+ renderBlockSparse (dest, srcPtr, drawWidth, drawHeight, sW, width);
+ else if (type == 0x02)
+ renderBlockWhole (dest, srcPtr, drawWidth, drawHeight, sW, width);
+ else if (type == 0x03)
+ renderBlockRLE (dest, srcPtr, drawWidth, drawHeight, sW, width);
+ else if (type == 0x42)
+ renderBlockWhole4X (dest, srcPtr, drawWidth, drawHeight, sW, width);
+ else if ((type & 0x0F) == 0x02)
+ renderBlockWhole2Y (dest, srcPtr, drawWidth, drawHeight, sW, width);
+ else
+ renderBlockSparse2Y(dest, srcPtr, drawWidth, drawHeight, sW, width);
+
+ dest = _vidMemBuffer + postScaleX(_width) * (top - _y) + postScaleX(left - _x);
+ blit(imdVidMem, dest, width, height);
+
+ return 1;
+}
+
+inline int32 Vmd::preScaleX(int32 x) const {
+ return x / _preScaleX;
+}
+
+inline int32 Vmd::postScaleX(int32 x) const {
+ return x * _postScaleX;
+}
+
+void Vmd::blit(byte *dest, byte *src, int16 width, int16 height) {
+ if (_blitMode == 0)
+ return;
+
+ if (_blitMode == 1)
+ blit16(dest, src, preScaleX(_width), preScaleX(width), height);
+ else if (_blitMode == 2)
+ blit24(dest, src, preScaleX(_width), preScaleX(width), height);
+}
+
+void Vmd::blit16(byte *dest, byte *src, int16 srcPitch, int16 width, int16 height) {
+ assert(_palLUT);
+
+ Graphics::SierraLight *dither =
+ new Graphics::SierraLight(width, _palLUT);
+
+ for (int i = 0; i < height; i++) {
+ byte *d = dest;
+ byte *s = src;
+
+ for (int j = 0; j < width; j++, s += 2) {
+ uint16 data = READ_LE_UINT16(s);
+ byte r = ((data & 0x7C00) >> 10);
+ byte g = ((data & 0x03E0) >> 5);
+ byte b = ((data & 0x001F) >> 0);
+ byte dY, dU, dV;
+
+ Graphics::PaletteLUT::RGB2YUV(r << 3, g << 3, b << 3, dY, dU, dV);
+
+ byte p = dither->dither(dY, dU, dV, j);
+
+ if ((dY == 0) || ((r == 0) && (g == 0) && (b == 0)))
+ *d++ = 0;
+ else
+ *d++ = p;
+ }
+
+ dither->nextLine();
+ dest += _vidMemWidth;
+ src += 2 * srcPitch;
+ }
+
+ delete dither;
+}
+
+void Vmd::blit24(byte *dest, byte *src, int16 srcPitch, int16 width, int16 height) {
+ assert(_palLUT);
+
+ Graphics::SierraLight *dither =
+ new Graphics::SierraLight(width, _palLUT);
+
+ for (int i = 0; i < height; i++) {
+ byte *d = dest;
+ byte *s = src;
+
+ for (int j = 0; j < width; j++, s += 3) {
+ byte r = s[2];
+ byte g = s[1];
+ byte b = s[0];
+ byte dY, dU, dV;
+
+ Graphics::PaletteLUT::RGB2YUV(r, g, b, dY, dU, dV);
+
+ byte p = dither->dither(dY, dU, dV, j);
+
+ if ((dY == 0) || ((r == 0) && (g == 0) && (b == 0)))
+ *d++ = 0;
+ else
+ *d++ = p;
+ }
+
+ dither->nextLine();
+ dest += _vidMemWidth;
+ src += 3 * srcPitch;
+ }
+
+ delete dither;
+}
+
+byte *Vmd::deDPCM(const byte *data, uint32 &size, int32 init[2]) {
+ if (!data || (size == 0))
+ return 0;
+
+ int channels = (_soundStereo > 0) ? 2 : 1;
+
+ uint32 inSize = size;
+ uint32 outSize = size + channels;
+
+ int16 *out = (int16 *)malloc(outSize * 2);
+ byte *sound = (byte *) out;
+
+ int channel = 0;
+
+ for (int i = 0; i < channels; i++) {
+ *out++ = TO_BE_16(init[channel]);
+
+ channel = (channel + 1) % channels;
+ }
+
+ while (inSize-- > 0) {
+ if (*data & 0x80)
+ init[channel] -= _tableDPCM[*data++ & 0x7F];
+ else
+ init[channel] += _tableDPCM[*data++];
+
+ init[channel] = CLIP<int32>(init[channel], -32768, 32767);
+ *out++ = TO_BE_16(init[channel]);
+
+ channel = (channel + 1) % channels;
+ }
+
+ size = outSize * 2;
+ return sound;
+}
+
+// Yet another IMA ADPCM variant
+byte *Vmd::deADPCM(const byte *data, uint32 &size, int32 init, int32 index) {
+ if (!data || (size == 0))
+ return 0;
+
+ uint32 outSize = size * 2;
+
+ int16 *out = (int16 *)malloc(outSize * 2);
+ byte *sound = (byte *) out;
+
+ index = CLIP<int32>(index, 0, 88);
+
+ int32 predictor = _tableADPCM[index];
+
+ uint32 dataByte = 0;
+ bool newByte = true;
+
+ size *= 2;
+ while (size -- > 0) {
+ byte code = 0;
+
+ if (newByte) {
+ dataByte = *data++;
+ code = (dataByte >> 4) & 0xF;
+ } else
+ code = dataByte & 0xF;
+
+ newByte = !newByte;
+
+ index += _tableADPCMStep[code];
+ index = CLIP<int32>(index, 0, 88);
+
+ int32 value = predictor / 8;
+
+ if (code & 4)
+ value += predictor;
+ if (code & 2)
+ value += predictor / 2;
+ if (code & 1)
+ value += predictor / 4;
+
+ if (code & 8)
+ init -= value;
+ else
+ init += value;
+
+ init = CLIP<int32>(init, -32768, 32767);
+
+ predictor = _tableADPCM[index];
+
+ *out++ = TO_BE_16(init);
+ }
+
+ size = outSize * 2;
+ return sound;
+}
+
+byte *Vmd::soundEmpty(uint32 &size) {
+ if (!_audioStream)
+ return 0;
+
+ byte *soundBuf = (byte *)malloc(size);
+ memset(soundBuf, 0, size);
+
+ return soundBuf;
+}
+
+byte *Vmd::sound8bitDirect(uint32 &size) {
+ if (!_audioStream) {
+ _stream->skip(size);
+ return 0;
+ }
+
+ byte *soundBuf = (byte *)malloc(size);
+ _stream->read(soundBuf, size);
+ unsignedToSigned(soundBuf, size);
+
+ return soundBuf;
+}
+
+byte *Vmd::sound16bitDPCM(uint32 &size) {
+ if (!_audioStream) {
+ _stream->skip(size);
+ return 0;
+ }
+
+ int32 init[2];
+
+ init[0] = _stream->readSint16LE();
+ size -= 2;
+
+ if (_soundStereo > 0) {
+ init[1] = _stream->readSint16LE();
+ size -= 2;
+ }
+
+ byte *data = new byte[size];
+ byte *sound = 0;
+
+ if (_stream->read(data, size) == size)
+ sound = deDPCM(data, size, init);
+
+ delete[] data;
+
+ return sound;
+}
+
+byte *Vmd::sound16bitADPCM(uint32 &size) {
+ if (!_audioStream) {
+ _stream->skip(size);
+ return 0;
+ }
+
+ int32 init = _stream->readSint16LE();
+ size -= 2;
+
+ int32 index = _stream->readByte();
+ size--;
+
+ byte *data = new byte[size];
+ byte *sound = 0;
+
+ if (_stream->read(data, size) == size)
+ sound = deADPCM(data, size, init, index);
+
+ delete[] data;
+
+ return sound;
+}
+
+void Vmd::emptySoundSlice(uint32 size) {
+ byte *sound = soundEmpty(size);
+
+ if (sound) {
+ uint32 flags = 0;
+ flags |= (_soundBytesPerSample == 2) ? Audio::FLAG_16BITS : 0;
+ flags |= (_soundStereo > 0) ? Audio::FLAG_STEREO : 0;
+
+ _audioStream->queueBuffer(sound, size, DisposeAfterUse::YES, flags);
+ }
+}
+
+void Vmd::filledSoundSlice(uint32 size) {
+ byte *sound = 0;
+ if (_audioFormat == kAudioFormat8bitDirect)
+ sound = sound8bitDirect(size);
+ else if (_audioFormat == kAudioFormat16bitDPCM)
+ sound = sound16bitDPCM(size);
+ else if (_audioFormat == kAudioFormat16bitADPCM)
+ sound = sound16bitADPCM(size);
+
+ if (sound) {
+ uint32 flags = 0;
+ flags |= (_soundBytesPerSample == 2) ? Audio::FLAG_16BITS : 0;
+ flags |= (_soundStereo > 0) ? Audio::FLAG_STEREO : 0;
+
+ _audioStream->queueBuffer(sound, size, DisposeAfterUse::YES, flags);
+ }
+}
+
+uint8 Vmd::evaluateMask(uint32 mask, bool *fillInfo, uint8 &max) {
+ max = MIN<int>(_soundSlicesCount - 1, 31);
+
+ uint8 n = 0;
+ for (int i = 0; i < max; i++) {
+
+ if (!(mask & 1)) {
+ n++;
+ *fillInfo++ = true;
+ } else
+ *fillInfo++ = false;
+
+ mask >>= 1;
+ }
+
+ return n;
+}
+
+void Vmd::filledSoundSlices(uint32 size, uint32 mask) {
+ bool fillInfo[32];
+
+ uint8 max;
+ uint8 n = evaluateMask(mask, fillInfo, max);
+
+ int32 extraSize;
+
+ extraSize = size - n * _soundDataSize;
+
+ if (_soundSlicesCount > 32)
+ extraSize -= (_soundSlicesCount - 32) * _soundDataSize;
+
+ if (n > 0)
+ extraSize /= n;
+
+ for (uint8 i = 0; i < max; i++)
+ if (fillInfo[i])
+ filledSoundSlice(_soundDataSize + extraSize);
+ else
+ emptySoundSlice(_soundDataSize * _soundBytesPerSample);
+
+ if (_soundSlicesCount > 32)
+ filledSoundSlice((_soundSlicesCount - 32) * _soundDataSize + _soundHeaderSize);
+}
+
+bool Vmd::getPartCoords(int16 frame, PartType type,
+ int16 &x, int16 &y, int16 &width, int16 &height) {
+
+ if (frame >= _framesCount)
+ return false;
+
+ Frame &f = _frames[frame];
+
+ // Look for a part matching the requested type, stopping at a separator
+ Part *part = 0;
+ for (int i = 0; i < _partsPerFrame; i++) {
+ Part &p = f.parts[i];
+
+ if ((p.type == kPartTypeSeparator) || (p.type == type)) {
+ part = &p;
+ break;
+ }
+ }
+
+ if (!part)
+ return false;
+
+ x = part->left;
+ y = part->top;
+ width = part->right - part->left + 1;
+ height = part->bottom - part->top + 1;
+
+ return true;
+}
+
+bool Vmd::getFrameCoords(int16 frame,
+ int16 &x, int16 &y, int16 &width, int16 &height) {
+
+ return getPartCoords(frame, kPartTypeVideo, x, y, width, height);
+}
+
+bool Vmd::hasExtraData() const {
+ return !_extraData.empty();
+}
+
+bool Vmd::hasExtraData(const char *fileName) const {
+ for (uint i = 0; i < _extraData.size(); i++)
+ if (!scumm_stricmp(_extraData[i].name, fileName))
+ return true;
+
+ return false;
+}
+
+Common::MemoryReadStream *Vmd::getExtraData(const char *fileName) {
+ uint i = 0;
+
+ for (i = 0; i < _extraData.size(); i++)
+ if (!scumm_stricmp(_extraData[i].name, fileName))
+ break;
+
+ if (i >= _extraData.size())
+ return 0;
+
+ if ((_extraData[i].size - 20) != _extraData[i].realSize) {
+ warning("Vmd::getExtraData(): Sizes for \"%s\" differ! (%d, %d)",
+ fileName, (_extraData[i].size - 20), _extraData[i].realSize);
+ return 0;
+ }
+
+ if (!_stream->seek(_extraData[i].offset)) {
+ warning("Vmd::getExtraData(): Can't seek to offset %d to (file \"%s\")",
+ _extraData[i].offset, fileName);
+ return 0;
+ }
+
+ byte *data = (byte *) malloc(_extraData[i].realSize);
+ if (_stream->read(data, _extraData[i].realSize) != _extraData[i].realSize) {
+ free(data);
+ warning("Vmd::getExtraData(): Couldn't read %d bytes (file \"%s\")",
+ _extraData[i].realSize, fileName);
+ }
+
+ Common::MemoryReadStream *stream =
+ new Common::MemoryReadStream(data, _extraData[i].realSize, DisposeAfterUse::YES);
+
+ return stream;
+}
+
+} // End of namespace Graphics
+
+#endif // GRAPHICS_VIDEO_COKTELVIDEO_H
diff --git a/graphics/video/coktelvideo/coktelvideo.h b/graphics/video/coktelvideo/coktelvideo.h
new file mode 100644
index 0000000000..8fbd861e82
--- /dev/null
+++ b/graphics/video/coktelvideo/coktelvideo.h
@@ -0,0 +1,598 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+// Currently, only GOB and SCI32 games play IMDs and VMDs, so skip compiling if GOB and SCI32 is disabled.
+#if !(defined(ENABLE_GOB) || defined(ENABLE_SCI32) || defined(DYNAMIC_MODULES))
+
+// Do not compile the CoktelVideo code
+
+#else
+
+#ifndef GRAPHICS_VIDEO_COKTELVIDEO_H
+#define GRAPHICS_VIDEO_COKTELVIDEO_H
+
+#include "common/scummsys.h"
+#include "common/stream.h"
+#include "common/array.h"
+#include "graphics/dither.h"
+#include "sound/mixer.h"
+
+namespace Audio {
+ class QueuingAudioStream;
+}
+
+namespace Graphics {
+
+#ifdef USE_INDEO3
+class Indeo3;
+#endif
+
+/** Common interface for handling Coktel Vision videos and derivated formats. */
+class CoktelVideo {
+public:
+ enum Features {
+ kFeaturesNone = 0,
+ /** Has an own palette. */
+ kFeaturesPalette = 8,
+ /** Suggests a data size. */
+ kFeaturesDataSize = 0x20,
+ /** Has sound. */
+ kFeaturesSound = 0x40,
+ /** Has specific frame coordinates. */
+ kFeaturesFrameCoords = 0x80,
+ /** Has general standard coordinates. */
+ kFeaturesStdCoords = 0x100,
+ /** Has a frame positions table. */
+ kFeaturesFramesPos = 0x200,
+ /** Has video. */
+ kFeaturesVideo = 0x400,
+ /** Is a full color (non-paletted) video. */
+ kFeaturesFullColor = 0x4000,
+ /** Supports automatic doubling. */
+ kFeaturesSupportsDouble = 0x40000000
+ };
+
+ enum StateFlags {
+ kStateNone = 0,
+ /** Changed the palette. */
+ kStatePalette = 0x10,
+ /** Performed a jump to another frame. */
+ kStateJump = 0x200,
+ /** Updated according to the specific frame coordinates. */
+ kStateFrameCoords = 0x400,
+ /** Got no frame data. */
+ kStateNoVideoData = 0x800,
+ /** Updated according to the general standard coordinates. */
+ kStateStdCoords = 0x1000,
+ /** Had to explicitely seek to the frame. */
+ kStateSeeked = 0x2000,
+ /** Reached a break-point. */
+ kStateBreak = 0x8000,
+ /** Frame marks the beginning of speech. */
+ kStateSpeech = 0x4000000
+ };
+
+ struct State {
+ /** Left-most value of the updated rectangle. */
+ int16 left;
+ /** Top-most value of the updated rectangle. */
+ int16 top;
+ /** Right-most value of the updated rectangle. */
+ int16 right;
+ /** Bottom-most value of the updated rectangle. */
+ int16 bottom;
+ /** Set accordingly to what was done. */
+ uint32 flags;
+ /** The id of the spoken words. */
+ uint16 speechId;
+
+ State() : left(0), top(0), right(0), bottom(0), flags(0), speechId(0) { }
+ };
+
+ virtual ~CoktelVideo() { }
+
+ /** Returns the features the loaded video possesses. */
+ virtual uint32 getFeatures() const = 0;
+ /** Returns the flags the loaded video possesses. */
+ virtual uint16 getFlags() const = 0;
+ /** Returns the x coordinate of the video. */
+ virtual int16 getX() const = 0;
+ /** Returns the y coordinate of the video. */
+ virtual int16 getY() const = 0;
+ /** Returns the width of the video. */
+ virtual int16 getWidth() const = 0;
+ /** Returns the height of the video. */
+ virtual int16 getHeight() const = 0;
+
+ /** Returns the number of frames the loaded video has. */
+ virtual uint16 getFramesCount() const = 0;
+ /** Returns the current frame number.
+ *
+ * This is the current frame after the last nextFrame()-call,
+ * i.e. it's 0 after loading, 1 after the first nextFrame()-call, etc..
+ */
+ virtual uint16 getCurrentFrame() const = 0;
+ /** Returns the frame rate. */
+ virtual int16 getFrameRate() const = 0;
+ /** Returns the number of frames the video lags behind the audio. */
+ virtual uint32 getSyncLag() const = 0;
+ /** Returns the current frame's palette. */
+ virtual const byte *getPalette() const = 0;
+
+ /** Returns the frame's coordinates */
+ virtual bool getFrameCoords(int16 frame,
+ int16 &x, int16 &y, int16 &width, int16 &height) = 0;
+
+ /** Returns whether any extra data files are embedded in this video. */
+ virtual bool hasExtraData() const = 0;
+ /** Returns whether that extra data file exists */
+ virtual bool hasExtraData(const char *fileName) const = 0;
+ /** Returns an extra data file */
+ virtual Common::MemoryReadStream *getExtraData(const char *fileName) = 0;
+
+ /** Load a video out of a stream. */
+ virtual bool load(Common::SeekableReadStream &stream) = 0;
+ /** Unload the currently loaded video. */
+ virtual void unload() = 0;
+
+ /** Set the frame rate. */
+ virtual void setFrameRate(int16 frameRate) = 0;
+
+ /** Set the coordinations where to draw the video. */
+ virtual void setXY(int16 x, int16 y) = 0;
+ /** Use a specific memory block as video memory. */
+ virtual void setVideoMemory(byte *vidMem, uint16 width, uint16 height) = 0;
+ /** Use an own memory block as video memory. */
+ virtual void setVideoMemory() = 0;
+
+ /** Double the video's resolution. */
+ virtual void setDoubleMode(bool doubleMode) = 0;
+
+ /** Play sound (if the video has sound). */
+ virtual void enableSound(Audio::Mixer &mixer) = 0;
+ /** Don't play sound or stop currently playing sound. */
+ virtual void disableSound() = 0;
+
+ /** Is sound currently playing? */
+ virtual bool isSoundPlaying() const = 0;
+
+ /** Seek to a specific frame.
+ *
+ * @param frame The frame to which to seek.
+ * @param whence The offset from whence the frame is given.
+ * @param restart Restart the video to reach an otherwise inaccessible frame?
+ */
+ virtual void seekFrame(int32 frame, int16 whence = SEEK_SET, bool restart = false) = 0;
+
+ /** Render the next frame. */
+ virtual State nextFrame() = 0;
+ /** Get the time in ms until the next frame can be displayed. Already includes A/V sync measures. */
+ virtual uint32 getFrameWaitTime() = 0;
+ /** Wait for the frame to end. */
+ virtual void waitEndFrame() = 0;
+
+ /** Copy the current frame.
+ *
+ * @param dest The memory to which to copy the current frame.
+ * @param left The x position within the frame.
+ * @param top The y position within the frame.
+ * @param width The width of the area to copy.
+ * @param height The height of the area to copy.
+ * @param x The x position to where to copy.
+ * @param y The y position to where to copy.
+ * @param pitch The buffer's width.
+ * @param transp Which color should be seen as transparent?
+ */
+ virtual void copyCurrentFrame(byte *dest,
+ uint16 left, uint16 top, uint16 width, uint16 height,
+ uint16 x, uint16 y, uint16 pitch, int16 transp = -1) = 0;
+};
+
+/** Coktel Vision's first simple IMD format, used by Fascination.
+ */
+class PreImd : public CoktelVideo {
+public:
+ PreImd();
+ PreImd(int16 width, int16 height);
+ ~PreImd();
+
+ uint32 getFeatures() const;
+ uint16 getFlags() const;
+
+ int16 getX() const;
+ int16 getY() const;
+ int16 getWidth() const;
+ int16 getHeight() const;
+
+ uint16 getFramesCount() const;
+ uint16 getCurrentFrame() const;
+
+ void setFrameRate(int16 frameRate);
+ int16 getFrameRate() const;
+
+ uint32 getSyncLag() const;
+
+ const byte *getPalette() const;
+
+ bool getFrameCoords(int16 frame,
+ int16 &x, int16 &y, int16 &width, int16 &height);
+
+ bool hasExtraData() const;
+ bool hasExtraData(const char *fileName) const;
+ Common::MemoryReadStream *getExtraData(const char *fileName);
+
+ bool load(Common::SeekableReadStream &stream);
+ void unload();
+
+ void setXY(int16 x, int16 y);
+ void setVideoMemory(byte *vidMem, uint16 width, uint16 height);
+ void setVideoMemory();
+
+ void setDoubleMode(bool doubleMode);
+
+ void enableSound(Audio::Mixer &mixer);
+ void disableSound();
+
+ bool isSoundPlaying() const;
+
+ void seekFrame(int32 frame, int16 whence = SEEK_SET, bool restart = false);
+
+ State nextFrame();
+ uint32 getFrameWaitTime();
+ void waitEndFrame();
+
+ void copyCurrentFrame(byte *dest,
+ uint16 left, uint16 top, uint16 width, uint16 height,
+ uint16 x, uint16 y, uint16 pitch, int16 transp = -1);
+
+protected:
+ Common::SeekableReadStream *_stream;
+
+ // Properties
+ uint32 _features;
+ uint16 _flags;
+
+ int16 _forcedWidth;
+ int16 _forcedHeight;
+
+ // Current coordinates
+ int16 _x;
+ int16 _y;
+ int16 _width;
+ int16 _height;
+
+ uint16 _framesCount;
+ uint16 _curFrame;
+ int16 _frameRate;
+ uint32 _frameLength;
+
+ byte _palette[768];
+
+ // Video memory
+ bool _hasOwnVidMem;
+ byte *_vidMem;
+ uint16 _vidMemWidth;
+ uint16 _vidMemHeight;
+
+ byte *_vidBuffer;
+ uint32 _vidBufferSize;
+
+ void clear();
+ void zeroData();
+ void deleteData();
+
+ void zeroVidMem();
+ void deleteVidMem();
+
+ State processFrame(uint16 frame);
+ void renderFrame();
+};
+
+/** Coktel Vision's IMD files.
+ */
+class Imd : public PreImd {
+public:
+ Imd();
+ ~Imd();
+
+ void setFrameRate(int16 frameRate);
+ int16 getFrameRate() const;
+
+ uint32 getSyncLag() const;
+
+ bool load(Common::SeekableReadStream &stream);
+ void unload();
+
+ void setXY(int16 x, int16 y);
+
+ void enableSound(Audio::Mixer &mixer);
+ void disableSound();
+
+ bool isSoundPlaying() const;
+
+ void seekFrame(int32 frame, int16 whence = SEEK_SET, bool restart = false);
+
+ State nextFrame();
+ uint32 getFrameWaitTime();
+
+ void copyCurrentFrame(byte *dest,
+ uint16 left, uint16 top, uint16 width, uint16 height,
+ uint16 x, uint16 y, uint16 pitch, int16 transp = -1);
+
+protected:
+ enum Command {
+ kCommandNextSound = 0xFF00,
+ kCommandStartSound = 0xFF01,
+
+ kCommandBreak = 0xFFF0,
+ kCommandBreakSkip0 = 0xFFF1,
+ kCommandBreakSkip16 = 0xFFF2,
+ kCommandBreakSkip32 = 0xFFF3,
+ kCommandBreakMask = 0xFFF8,
+
+ kCommandPalette = 0xFFF4,
+ kCommandVideoData = 0xFFFC,
+
+ kCommandJump = 0xFFFD
+ };
+
+ struct Coord {
+ int16 left;
+ int16 top;
+ int16 right;
+ int16 bottom;
+ } PACKED_STRUCT;
+
+ // Properties
+ uint16 _version;
+
+ // Standard coordinates gives by the header
+ int16 _stdX;
+ int16 _stdY;
+ int16 _stdWidth;
+ int16 _stdHeight;
+
+ uint32 *_framesPos;
+ uint32 _firstFramePos;
+ Coord *_frameCoords;
+
+ // Buffer for raw frame data
+ byte *_frameData;
+ uint32 _frameDataSize;
+ uint32 _frameDataLen;
+
+ // Sound properties
+ uint16 _soundFlags;
+ int16 _soundFreq;
+ int16 _soundSliceSize;
+ int16 _soundSlicesCount;
+ uint32 _soundSliceLength;
+
+ // Current sound state
+ bool _hasSound;
+ bool _soundEnabled;
+ uint8 _soundStage; // (0: no sound, 1: loaded, 2: playing)
+ uint32 _skipFrames;
+
+ Audio::QueuingAudioStream *_audioStream;
+ Audio::SoundHandle _audioHandle;
+
+ uint32 _lastFrameTime;
+
+ Audio::Mixer *_mixer;
+
+ void clear();
+ void zeroData();
+ void deleteData();
+
+ void unsignedToSigned(byte *buffer, int length);
+
+ bool loadCoordinates();
+ bool loadFrameTableOffsets(uint32 &framesPosPos, uint32 &framesCoordsPos);
+ bool assessVideoProperties();
+ bool assessAudioProperties();
+ bool loadFrameTables(uint32 framesPosPos, uint32 framesCoordsPos);
+
+ State processFrame(uint16 frame);
+ uint32 renderFrame(int16 left, int16 top, int16 right, int16 bottom);
+ void deLZ77(byte *dest, byte *src);
+
+ void renderBlockWhole (byte *dest, const byte *src, int16 width, int16 height,
+ int16 destPitch, int16 srcPitch);
+ void renderBlockWhole4X (byte *dest, const byte *src, int16 width, int16 height,
+ int16 destPitch, int16 srcPitch);
+ void renderBlockWhole2Y (byte *dest, const byte *src, int16 width, int16 height,
+ int16 destPitch, int16 srcPitch);
+ void renderBlockSparse (byte *dest, const byte *src, int16 width, int16 height,
+ int16 destPitch, int16 srcPitch);
+ void renderBlockSparse2Y(byte *dest, const byte *src, int16 width, int16 height,
+ int16 destPitch, int16 srcPitch);
+
+ void calcFrameCoords(uint16 frame, State &state);
+
+ void nextSoundSlice(bool hasNextCmd);
+ bool initialSoundSlice(bool hasNextCmd);
+ void emptySoundSlice(bool hasNextCmd);
+
+ void videoData(uint32 size, State &state);
+};
+
+class Vmd : public Imd {
+public:
+ Vmd(Graphics::PaletteLUT *palLUT = 0);
+ ~Vmd();
+
+ bool getFrameCoords(int16 frame,
+ int16 &x, int16 &y, int16 &width, int16 &height);
+
+ bool hasExtraData() const;
+ bool hasExtraData(const char *fileName) const;
+ Common::MemoryReadStream *getExtraData(const char *fileName);
+
+ bool load(Common::SeekableReadStream &stream);
+ void unload();
+
+ int16 getWidth() const;
+
+ void setXY(int16 x, int16 y);
+
+ void setDoubleMode(bool doubleMode);
+
+ void seekFrame(int32 frame, int16 whence = SEEK_SET, bool restart = false);
+
+ State nextFrame();
+
+protected:
+ enum PartType {
+ kPartTypeSeparator = 0,
+ kPartTypeAudio = 1,
+ kPartTypeVideo = 2,
+ kPartTypeExtraData = 3,
+ kPartType4 = 4,
+ kPartTypeSpeech = 5
+ };
+
+ enum AudioFormat {
+ kAudioFormat8bitDirect = 0,
+ kAudioFormat16bitDPCM = 1,
+ kAudioFormat16bitADPCM = 2
+ };
+
+ struct ExtraData {
+ char name[16];
+ uint32 offset;
+ uint32 size;
+ uint32 realSize;
+
+ ExtraData();
+ } PACKED_STRUCT;
+
+ struct Part {
+ PartType type;
+ byte field_1;
+ byte field_E;
+ uint32 size;
+ int16 left;
+ int16 top;
+ int16 right;
+ int16 bottom;
+ uint16 id;
+ byte flags;
+
+ Part();
+ } PACKED_STRUCT;
+
+ struct Frame {
+ uint32 offset;
+ Part *parts;
+
+ Frame();
+ ~Frame();
+ } PACKED_STRUCT;
+
+ // Tables for the audio decompressors
+ static const uint16 _tableDPCM[128];
+ static const int32 _tableADPCM[];
+ static const int32 _tableADPCMStep[];
+
+ bool _hasVideo;
+ uint32 _videoCodec;
+
+ uint32 _frameInfoOffset;
+ uint16 _partsPerFrame;
+ Frame *_frames;
+
+ Common::Array<ExtraData> _extraData;
+
+ // Sound properties
+ byte _soundBytesPerSample;
+ byte _soundStereo; // (0: mono, 1: old-style stereo, 2: new-style stereo)
+ uint32 _soundHeaderSize;
+ uint32 _soundDataSize;
+ AudioFormat _audioFormat;
+
+ // Video properties
+ bool _externalCodec;
+ byte _blitMode;
+ byte _bytesPerPixel;
+ byte _preScaleX;
+ byte _postScaleX;
+ byte _scaleExternalX;
+ byte *_vidMemBuffer;
+
+ bool _doubleMode;
+
+ Graphics::PaletteLUT *_palLUT;
+
+#ifdef USE_INDEO3
+ Indeo3 *_codecIndeo3;
+#endif
+
+ void clear();
+ void zeroData();
+ void deleteData();
+
+ bool getPartCoords(int16 frame, PartType type,
+ int16 &x, int16 &y, int16 &width, int16 &height);
+
+ bool assessVideoProperties();
+ bool assessAudioProperties();
+ void readFrameTable(int &numExtraData);
+ void readExtraData();
+
+ State processFrame(uint16 frame);
+ uint32 renderFrame(int16 &left, int16 &top, int16 &right, int16 &bottom);
+
+ void renderBlockRLE(byte *dest, const byte *src, int16 width, int16 height,
+ int16 destPitch, int16 srcPitch);
+
+ void deRLE(byte *&destPtr, const byte *&srcPtr, int16 destLen, int16 srcLen);
+
+ inline int32 preScaleX(int32 x) const;
+ inline int32 postScaleX(int32 x) const;
+
+ void blit(byte *dest, byte *src, int16 width, int16 height);
+ void blit16(byte *dest, byte *src, int16 srcPitch, int16 width, int16 height);
+ void blit24(byte *dest, byte *src, int16 srcPitch, int16 width, int16 height);
+
+ byte *deDPCM(const byte *data, uint32 &size, int32 init[2]);
+ byte *deADPCM(const byte *data, uint32 &size, int32 init, int32 v28);
+
+ byte *soundEmpty(uint32 &size);
+ byte *sound8bitDirect(uint32 &size);
+ byte *sound16bitDPCM(uint32 &size);
+ byte *sound16bitADPCM(uint32 &size);
+
+ uint8 evaluateMask(uint32 mask, bool *fillInfo, uint8 &max);
+ void emptySoundSlice(uint32 size);
+ void filledSoundSlice(uint32 size);
+ void filledSoundSlices(uint32 size, uint32 mask);
+};
+
+} // End of namespace Graphics
+
+#endif // GRAPHICS_VIDEO_COKTELVIDEO_H
+
+#endif // Engine and dynamic plugins guard
diff --git a/graphics/video/coktelvideo/indeo3.cpp b/graphics/video/coktelvideo/indeo3.cpp
new file mode 100644
index 0000000000..983705ab9c
--- /dev/null
+++ b/graphics/video/coktelvideo/indeo3.cpp
@@ -0,0 +1,3485 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/scummsys.h"
+
+#ifdef USE_INDEO3
+
+/* Intel Indeo 3 decompressor, derived from ffmpeg.
+ *
+ * Original copyright note: * Intel Indeo 3 (IV31, IV32, etc.) video decoder for ffmpeg
+ * written, produced, and directed by Alan Smithee
+ */
+
+#include "common/system.h"
+#include "common/endian.h"
+#include "common/frac.h"
+#include "common/file.h"
+
+#include "graphics/dither.h"
+#include "graphics/video/coktelvideo/indeo3.h"
+
+namespace Graphics {
+
+Indeo3::Indeo3(int16 width, int16 height, Graphics::PaletteLUT *palLUT) {
+ assert((width > 0) && (height > 0));
+
+ _width = width;
+ _height = height;
+ _palLUT = palLUT;
+
+ _ditherSL = 0;
+ setDither(kDitherSierraLight);
+
+ buildModPred();
+ allocFrames();
+}
+
+Indeo3::~Indeo3() {
+ delete[] _iv_frame[0].the_buf;
+ delete[] _ModPred;
+ delete[] _corrector_type;
+ delete _ditherSL;
+}
+
+bool Indeo3::isIndeo3(byte *data, uint32 dataLen) {
+ // No data, no Indeo 3
+ if (!data)
+ return false;
+
+ // Less than 16 bytes? This can't be right
+ if (dataLen < 16)
+ return false;
+
+ // Unknown, but according to the docs, always 0
+ if (READ_LE_UINT32(data + 4) != 0)
+ return false;
+
+ uint32 id;
+ id = READ_LE_UINT32(data ); // frame number
+ id ^= READ_LE_UINT32(data + 4); // unknown
+ id ^= READ_LE_UINT32(data + 8); // checksum
+ id ^= READ_LE_UINT32(data + 12); // frame data length
+
+ // These 4 uint32s XOR'd need to spell "FRMH"
+ if (id != MKID_BE('FRMH'))
+ return false;
+
+ return true;
+}
+
+void Indeo3::setDither(DitherAlgorithm dither) {
+ delete _ditherSL;
+ _ditherSL = 0;
+
+ _dither = dither;
+
+ switch (dither) {
+ case kDitherSierraLight:
+ _ditherSL = new Graphics::SierraLight(_width, _palLUT);
+ break;
+
+ default:
+ return;
+ }
+}
+
+void Indeo3::buildModPred() {
+ _ModPred = new byte[8 * 128];
+
+ for (int i = 0; i < 128; i++) {
+ _ModPred[i+0*128] = (i > 126) ? 254 : 2*((i + 1) - ((i + 1) % 2));
+ _ModPred[i+1*128] = (i == 7) ? 20 : ((i == 119 || i == 120)
+ ? 236 : 2*((i + 2) - ((i + 1) % 3)));
+ _ModPred[i+2*128] = (i > 125) ? 248 : 2*((i + 2) - ((i + 2) % 4));
+ _ModPred[i+3*128] = 2*((i + 1) - ((i - 3) % 5));
+ _ModPred[i+4*128] = (i == 8) ? 20 : 2*((i + 1) - ((i - 3) % 6));
+ _ModPred[i+5*128] = 2*((i + 4) - ((i + 3) % 7));
+ _ModPred[i+6*128] = (i > 123) ? 240 : 2*((i + 4) - ((i + 4) % 8));
+ _ModPred[i+7*128] = 2*((i + 5) - ((i + 4) % 9));
+ }
+
+ _corrector_type = new uint16[24 * 256];
+
+ for (int i = 0; i < 24; i++) {
+ for (int j = 0; j < 256; j++) {
+ _corrector_type[i*256+j] =
+ (j < _corrector_type_0[i]) ? 1 :
+ ((j < 248 || (i == 16 && j == 248)) ? 0 :
+ _corrector_type_2[j - 248]);
+ }
+ }
+}
+
+void Indeo3::allocFrames() {
+ int32 luma_width = (_width + 3) & (~3);
+ int32 luma_height = (_height + 3) & (~3);
+
+ int32 chroma_width = ((luma_width >> 2) + 3) & (~3);
+ int32 chroma_height = ((luma_height>> 2) + 3) & (~3);
+
+ int32 luma_pixels = luma_width * luma_height;
+ int32 chroma_pixels = chroma_width * chroma_height;
+
+ uint32 bufsize = luma_pixels * 2 + luma_width * 3 +
+ (chroma_pixels + chroma_width) * 4;
+
+ _iv_frame[0].y_w = _iv_frame[1].y_w = luma_width;
+ _iv_frame[0].y_h = _iv_frame[1].y_h = luma_height;
+ _iv_frame[0].uv_w = _iv_frame[1].uv_w = chroma_width;
+ _iv_frame[0].uv_h = _iv_frame[1].uv_h = chroma_height;
+
+ _iv_frame[0].the_buf_size = bufsize;
+ _iv_frame[1].the_buf_size = 0;
+
+ _iv_frame[0].the_buf = new byte[bufsize];
+ memset(_iv_frame[0].the_buf, 0, bufsize);
+ _iv_frame[1].the_buf = 0;
+
+ uint32 offs = 0;
+
+ _iv_frame[0].Ybuf = _iv_frame[0].the_buf + luma_width;
+ offs += luma_pixels + luma_width * 2;
+ _iv_frame[1].Ybuf = _iv_frame[0].the_buf + offs;
+ offs += (luma_pixels + luma_width);
+ _iv_frame[0].Ubuf = _iv_frame[0].the_buf + offs;
+ offs += (chroma_pixels + chroma_width);
+ _iv_frame[1].Ubuf = _iv_frame[0].the_buf + offs;
+ offs += (chroma_pixels + chroma_width);
+ _iv_frame[0].Vbuf = _iv_frame[0].the_buf + offs;
+ offs += (chroma_pixels + chroma_width);
+ _iv_frame[1].Vbuf = _iv_frame[0].the_buf + offs;
+
+ for (int i = 1; i <= luma_width; i++)
+ _iv_frame[0].Ybuf[-i] = _iv_frame[1].Ybuf[-i] =
+ _iv_frame[0].Ubuf[-i] = 0x80;
+
+ for (int i = 1; i <= chroma_width; i++) {
+ _iv_frame[1].Ubuf[-i] = 0x80;
+ _iv_frame[0].Vbuf[-i] = 0x80;
+ _iv_frame[1].Vbuf[-i] = 0x80;
+ _iv_frame[1].Vbuf[chroma_pixels+i-1] = 0x80;
+ }
+}
+
+bool Indeo3::decompressFrame(byte *inData, uint32 dataLen,
+ byte *outData, uint16 width, uint16 height) {
+
+ // Not Indeo 3? Fail
+ if (!isIndeo3(inData, dataLen))
+ return false;
+
+ assert(outData);
+ assert(_palLUT);
+
+ uint32 frameDataLen = READ_LE_UINT32(inData + 12);
+
+ // Less data than the frame should have? Fail
+ if (dataLen < (frameDataLen - 16))
+ return false;
+
+ Common::MemoryReadStream frame(inData, dataLen);
+
+ frame.skip(16); // Header
+ frame.skip(2); // Unknown
+
+ uint16 flags1 = frame.readUint16LE();
+ uint32 flags3 = frame.readUint32LE();
+ uint8 flags2 = frame.readByte();
+
+ // Finding the reference frame
+ if (flags1 & 0x200) {
+ _cur_frame = _iv_frame + 1;
+ _ref_frame = _iv_frame;
+ } else {
+ _cur_frame = _iv_frame;
+ _ref_frame = _iv_frame + 1;
+ }
+
+ if (flags3 == 0x80)
+ return true;
+
+ frame.skip(3);
+
+ uint16 fHeight = frame.readUint16LE();
+ uint16 fWidth = frame.readUint16LE();
+
+ uint32 chromaHeight = ((fHeight >> 2) + 3) & 0x7FFC;
+ uint32 chromaWidth = ((fWidth >> 2) + 3) & 0x7FFC;
+
+ uint32 offs;
+ uint32 offsY = frame.readUint32LE() + 16;
+ uint32 offsU = frame.readUint32LE() + 16;
+ uint32 offsV = frame.readUint32LE() + 16;
+
+ frame.skip(4);
+
+ uint32 hPos = frame.pos();
+
+ byte *hdr_pos = inData + hPos;
+ byte *buf_pos;
+
+ // Luminance Y
+ frame.seek(offsY);
+ buf_pos = inData + offsY + 4;
+ offs = frame.readUint32LE();
+ decodeChunk(_cur_frame->Ybuf, _ref_frame->Ybuf, fWidth, fHeight,
+ buf_pos + offs * 2, flags2, hdr_pos, buf_pos, MIN<int>(fWidth, 160));
+
+ // Chrominance U
+ frame.seek(offsU);
+ buf_pos = inData + offsU + 4;
+ offs = frame.readUint32LE();
+ decodeChunk(_cur_frame->Vbuf, _ref_frame->Vbuf, chromaWidth, chromaHeight,
+ buf_pos + offs * 2, flags2, hdr_pos, buf_pos, MIN<int>(chromaWidth, 40));
+
+ // Chrominance V
+ frame.seek(offsV);
+ buf_pos = inData + offsV + 4;
+ offs = frame.readUint32LE();
+ decodeChunk(_cur_frame->Ubuf, _ref_frame->Ubuf, chromaWidth, chromaHeight,
+ buf_pos + offs * 2, flags2, hdr_pos, buf_pos, MIN<int>(chromaWidth, 40));
+
+ BlitState blitState;
+
+ blitState.widthY = _cur_frame->y_w;
+ blitState.widthUV = _cur_frame->uv_w;
+ blitState.uwidthUV = chromaWidth;
+ blitState.uwidthOut = fWidth;
+ blitState.heightY = _cur_frame->y_h;
+ blitState.heightUV = _cur_frame->uv_h;
+ blitState.uheightUV = chromaHeight;
+ blitState.uheightOut = fHeight;
+ blitState.scaleWYUV = blitState.widthY / blitState.widthUV;
+ blitState.scaleHYUV = blitState.heightY / blitState.heightUV;
+ blitState.scaleWYOut = blitState.widthY / blitState.uwidthOut;
+ blitState.scaleHYOut = blitState.heightY / blitState.uheightOut;
+ blitState.lineWidthOut = blitState.scaleWYOut * blitState.uwidthOut;
+ blitState.lineHeightOut = blitState.scaleHYOut * blitState.uheightOut;
+ blitState.bufY = _cur_frame->Ybuf;
+ blitState.bufU = _cur_frame->Ubuf;
+ blitState.bufV = _cur_frame->Vbuf;
+ blitState.bufOut = outData;
+
+ blitFrame(blitState);
+
+ return true;
+}
+
+void Indeo3::blitFrame(BlitState &s) {
+ if (_ditherSL)
+ _ditherSL->newFrame();
+
+ for (s.curY = 0; s.curY < s.uheightOut; s.curY++) {
+ if (_dither == kDitherNone)
+ blitLine(s);
+ else
+ blitLineDither(s);
+ }
+}
+
+void Indeo3::blitLine(BlitState &s) {
+ byte *lineU = s.bufU + (s.curY >> 2) * s.uwidthUV;
+ byte *lineV = s.bufV + (s.curY >> 2) * s.uwidthUV;
+
+ for (s.curX = 0; s.curX < s.uwidthOut; s.curX++) {
+ byte dataY = *s.bufY++;
+ byte dataU = lineU[s.curX >> 2];
+ byte dataV = lineV[s.curX >> 2];
+
+ for (int n = 0; n < s.scaleWYOut; n++)
+ *s.bufOut++ = _palLUT->findNearest(dataY, dataU, dataV);
+ }
+
+ byte *lineDest = s.bufOut - s.lineWidthOut;
+ for (int n = 1; n < s.scaleHYOut; n++) {
+ memcpy(s.bufOut, lineDest, s.lineWidthOut);
+ s.bufOut += s.lineWidthOut;
+ }
+}
+
+void Indeo3::blitLineDither(BlitState &s) {
+ byte *lineU = s.bufU + (s.curY >> 2) * s.uwidthUV;
+ byte *lineV = s.bufV + (s.curY >> 2) * s.uwidthUV;
+
+ for (uint16 i = 0; i < s.scaleHYOut; i++) {
+ byte *bufY = s.bufY;
+
+ for (s.curX = 0; s.curX < s.uwidthOut; s.curX++) {
+ byte dataY = *bufY++;
+ byte dataU = lineU[s.curX >> 2];
+ byte dataV = lineV[s.curX >> 2];
+
+ for (int n = 0; n < s.scaleWYOut; n++)
+ *s.bufOut++ = _ditherSL->dither(dataY, dataU, dataV, s.curX * s.scaleWYOut + n);
+
+ }
+
+ _ditherSL->nextLine();
+ }
+
+ s.bufY += s.uwidthOut;
+}
+
+typedef struct {
+ int32 xpos;
+ int32 ypos;
+ int32 width;
+ int32 height;
+ int32 split_flag;
+ int32 split_direction;
+ int32 usl7;
+} ustr_t;
+
+/* ---------------------------------------------------------------------- */
+
+#define LV1_CHECK(buf1,rle_v3,lv1,lp2) \
+ if ((lv1 & 0x80) != 0) { \
+ if (rle_v3 != 0) \
+ rle_v3 = 0; \
+ else { \
+ rle_v3 = 1; \
+ buf1 -= 2; \
+ } \
+ } \
+ lp2 = 4;
+
+
+#define RLE_V3_CHECK(buf1,rle_v1,rle_v2,rle_v3) \
+ if (rle_v3 == 0) { \
+ rle_v2 = *buf1; \
+ rle_v1 = 1; \
+ if (rle_v2 > 32) { \
+ rle_v2 -= 32; \
+ rle_v1 = 0; \
+ } \
+ rle_v3 = 1; \
+ } \
+ buf1--;
+
+
+#define LP2_CHECK(buf1,rle_v3,lp2) \
+ if (lp2 == 0 && rle_v3 != 0) \
+ rle_v3 = 0; \
+ else { \
+ buf1--; \
+ rle_v3 = 1; \
+ }
+
+
+#define RLE_V2_CHECK(buf1,rle_v2, rle_v3,lp2) \
+ rle_v2--; \
+ if (rle_v2 == 0) { \
+ rle_v3 = 0; \
+ buf1 += 2; \
+ } \
+ lp2 = 4;
+
+void Indeo3::decodeChunk(byte *cur, byte *ref, int width, int height,
+ const byte *buf1, uint32 fflags2, const byte *hdr,
+ const byte *buf2, int min_width_160) {
+
+ byte bit_buf;
+ uint32 bit_pos, lv, lv1, lv2;
+ int32 *width_tbl, width_tbl_arr[10];
+ const int8 *ref_vectors;
+ byte *cur_frm_pos, *ref_frm_pos, *cp, *cp2;
+ uint32 *cur_lp, *ref_lp;
+ const uint32 *correction_lp[2], *correctionloworder_lp[2], *correctionhighorder_lp[2];
+ uint16 *correction_type_sp[2];
+ ustr_t strip_tbl[20], *strip;
+ int i, j, k, lp1, lp2, flag1, cmd;
+ int blks_width, blks_height, region_160_width;
+ int rle_v1, rle_v2, rle_v3;
+ uint16 res;
+
+ bit_buf = 0;
+ ref_vectors = NULL;
+
+ width_tbl = width_tbl_arr + 1;
+ i = (width < 0 ? width + 3 : width)/4;
+ for (j = -1; j < 8; j++)
+ width_tbl[j] = i * j;
+
+ strip = strip_tbl;
+
+ for (region_160_width = 0; region_160_width < (width - min_width_160); region_160_width += min_width_160)
+ ;
+
+ strip->ypos = strip->xpos = 0;
+ for (strip->width = min_width_160; width > strip->width; strip->width *= 2)
+ ;
+ strip->height = height;
+ strip->split_direction = 0;
+ strip->split_flag = 0;
+ strip->usl7 = 0;
+
+ bit_pos = 0;
+
+ rle_v1 = rle_v2 = rle_v3 = 0;
+
+ while (strip >= strip_tbl) {
+ if (bit_pos <= 0) {
+ bit_pos = 8;
+ bit_buf = *buf1++;
+ }
+
+ bit_pos -= 2;
+ cmd = (bit_buf >> bit_pos) & 0x03;
+
+ if (cmd == 0) {
+ strip++;
+ memcpy(strip, strip-1, sizeof(ustr_t));
+ strip->split_flag = 1;
+ strip->split_direction = 0;
+ strip->height = (strip->height > 8 ? ((strip->height+8)>>4)<<3 : 4);
+ continue;
+ } else if (cmd == 1) {
+ strip++;
+ memcpy(strip, strip-1, sizeof(ustr_t));
+ strip->split_flag = 1;
+ strip->split_direction = 1;
+ strip->width = (strip->width > 8 ? ((strip->width+8)>>4)<<3 : 4);
+ continue;
+ } else if (cmd == 2) {
+ if (strip->usl7 == 0) {
+ strip->usl7 = 1;
+ ref_vectors = NULL;
+ continue;
+ }
+ } else if (cmd == 3) {
+ if (strip->usl7 == 0) {
+ strip->usl7 = 1;
+ ref_vectors = (const signed char*)buf2 + (*buf1 * 2);
+ buf1++;
+ continue;
+ }
+ }
+
+ cur_frm_pos = cur + width * strip->ypos + strip->xpos;
+
+ if ((blks_width = strip->width) < 0)
+ blks_width += 3;
+ blks_width >>= 2;
+ blks_height = strip->height;
+
+ if (ref_vectors != NULL) {
+ ref_frm_pos = ref + (ref_vectors[0] + strip->ypos) * width +
+ ref_vectors[1] + strip->xpos;
+ } else
+ ref_frm_pos = cur_frm_pos - width_tbl[4];
+
+ if (cmd == 2) {
+ if (bit_pos <= 0) {
+ bit_pos = 8;
+ bit_buf = *buf1++;
+ }
+
+ bit_pos -= 2;
+ cmd = (bit_buf >> bit_pos) & 0x03;
+
+ if (cmd == 0 || ref_vectors != NULL) {
+ for (lp1 = 0; lp1 < blks_width; lp1++) {
+ for (i = 0, j = 0; i < blks_height; i++, j += width_tbl[1])
+ ((uint32 *)cur_frm_pos)[j] = ((uint32 *)ref_frm_pos)[j];
+ cur_frm_pos += 4;
+ ref_frm_pos += 4;
+ }
+ } else if (cmd != 1)
+ return;
+ } else {
+ k = *buf1 >> 4;
+ j = *buf1 & 0x0f;
+ buf1++;
+ lv = j + fflags2;
+
+ if ((lv - 8) <= 7 && (k == 0 || k == 3 || k == 10)) {
+ cp2 = _ModPred + ((lv - 8) << 7);
+ cp = ref_frm_pos;
+ for (i = 0; i < blks_width << 2; i++) {
+ int v = *cp >> 1;
+ *(cp++) = cp2[v];
+ }
+ }
+
+ if (k == 1 || k == 4) {
+ lv = (hdr[j] & 0xf) + fflags2;
+ correction_type_sp[0] = _corrector_type + (lv << 8);
+ correction_lp[0] = correction + (lv << 8);
+ lv = (hdr[j] >> 4) + fflags2;
+ correction_lp[1] = correction + (lv << 8);
+ correction_type_sp[1] = _corrector_type + (lv << 8);
+ } else {
+ correctionloworder_lp[0] = correctionloworder_lp[1] = correctionloworder + (lv << 8);
+ correctionhighorder_lp[0] = correctionhighorder_lp[1] = correctionhighorder + (lv << 8);
+ correction_type_sp[0] = correction_type_sp[1] = _corrector_type + (lv << 8);
+ correction_lp[0] = correction_lp[1] = correction + (lv << 8);
+ }
+
+ switch (k) {
+ case 1:
+ case 0: /********** CASE 0 **********/
+ for ( ; blks_height > 0; blks_height -= 4) {
+ for (lp1 = 0; lp1 < blks_width; lp1++) {
+ for (lp2 = 0; lp2 < 4; ) {
+ k = *buf1++;
+ cur_lp = ((uint32 *)cur_frm_pos) + width_tbl[lp2];
+ ref_lp = ((uint32 *)ref_frm_pos) + width_tbl[lp2];
+
+ switch (correction_type_sp[0][k]) {
+ case 0:
+ *cur_lp = FROM_LE_32(((FROM_LE_32(*ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1);
+ lp2++;
+ break;
+ case 1:
+ res = ((FROM_LE_16(((uint16 *)(ref_lp))[0]) >> 1) + correction_lp[lp2 & 0x01][*buf1]) << 1;
+ ((uint16 *)cur_lp)[0] = FROM_LE_16(res);
+ res = ((FROM_LE_16(((uint16 *)(ref_lp))[1]) >> 1) + correction_lp[lp2 & 0x01][k]) << 1;
+ ((uint16 *)cur_lp)[1] = FROM_LE_16(res);
+ buf1++;
+ lp2++;
+ break;
+ case 2:
+ if (lp2 == 0) {
+ for (i = 0, j = 0; i < 2; i++, j += width_tbl[1])
+ cur_lp[j] = ref_lp[j];
+ lp2 += 2;
+ }
+ break;
+ case 3:
+ if (lp2 < 2) {
+ for (i = 0, j = 0; i < (3 - lp2); i++, j += width_tbl[1])
+ cur_lp[j] = ref_lp[j];
+ lp2 = 3;
+ }
+ break;
+ case 8:
+ if (lp2 == 0) {
+ RLE_V3_CHECK(buf1,rle_v1,rle_v2,rle_v3)
+
+ if (rle_v1 == 1 || ref_vectors != NULL) {
+ for (i = 0, j = 0; i < 4; i++, j += width_tbl[1])
+ cur_lp[j] = ref_lp[j];
+ }
+
+ RLE_V2_CHECK(buf1,rle_v2, rle_v3,lp2)
+ break;
+ } else {
+ rle_v1 = 1;
+ rle_v2 = *buf1 - 1;
+ }
+ case 5:
+ LP2_CHECK(buf1,rle_v3,lp2)
+ case 4:
+ for (i = 0, j = 0; i < (4 - lp2); i++, j += width_tbl[1])
+ cur_lp[j] = ref_lp[j];
+ lp2 = 4;
+ break;
+
+ case 7:
+ if (rle_v3 != 0)
+ rle_v3 = 0;
+ else {
+ buf1--;
+ rle_v3 = 1;
+ }
+ case 6:
+ if (ref_vectors != NULL) {
+ for (i = 0, j = 0; i < 4; i++, j += width_tbl[1])
+ cur_lp[j] = ref_lp[j];
+ }
+ lp2 = 4;
+ break;
+
+ case 9:
+ lv1 = *buf1++;
+ lv = (lv1 & 0x7F) << 1;
+ lv += (lv << 8);
+ lv += (lv << 16);
+ for (i = 0, j = 0; i < 4; i++, j += width_tbl[1])
+ cur_lp[j] = lv;
+
+ LV1_CHECK(buf1,rle_v3,lv1,lp2)
+ break;
+ default:
+ return;
+ }
+ }
+
+ cur_frm_pos += 4;
+ ref_frm_pos += 4;
+ }
+
+ cur_frm_pos += ((width - blks_width) * 4);
+ ref_frm_pos += ((width - blks_width) * 4);
+ }
+ break;
+
+ case 4:
+ case 3: /********** CASE 3 **********/
+ if (ref_vectors != NULL)
+ return;
+ flag1 = 1;
+
+ for ( ; blks_height > 0; blks_height -= 8) {
+ for (lp1 = 0; lp1 < blks_width; lp1++) {
+ for (lp2 = 0; lp2 < 4; ) {
+ k = *buf1++;
+
+ cur_lp = ((uint32 *)cur_frm_pos) + width_tbl[lp2 * 2];
+ ref_lp = ((uint32 *)cur_frm_pos) + width_tbl[(lp2 * 2) - 1];
+
+ switch (correction_type_sp[lp2 & 0x01][k]) {
+ case 0:
+ cur_lp[width_tbl[1]] = FROM_LE_32(((FROM_LE_32(*ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1);
+ if (lp2 > 0 || flag1 == 0 || strip->ypos != 0)
+ cur_lp[0] = ((cur_lp[-width_tbl[1]] >> 1) + (cur_lp[width_tbl[1]] >> 1)) & 0xFEFEFEFE;
+ else
+ cur_lp[0] = FROM_LE_32(((FROM_LE_32(*ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1);
+ lp2++;
+ break;
+
+ case 1:
+ res = ((FROM_LE_16(((uint16 *)ref_lp)[0]) >> 1) + correction_lp[lp2 & 0x01][*buf1]) << 1;
+ ((uint16 *)cur_lp)[width_tbl[2]] = FROM_LE_16(res);
+ res = ((FROM_LE_16(((uint16 *)ref_lp)[1]) >> 1) + correction_lp[lp2 & 0x01][k]) << 1;
+ ((uint16 *)cur_lp)[width_tbl[2]+1] = FROM_LE_16(res);
+
+ if (lp2 > 0 || flag1 == 0 || strip->ypos != 0)
+ cur_lp[0] = ((cur_lp[-width_tbl[1]] >> 1) + (cur_lp[width_tbl[1]] >> 1)) & 0xFEFEFEFE;
+ else
+ cur_lp[0] = cur_lp[width_tbl[1]];
+ buf1++;
+ lp2++;
+ break;
+
+ case 2:
+ if (lp2 == 0) {
+ for (i = 0, j = 0; i < 4; i++, j += width_tbl[1])
+ cur_lp[j] = *ref_lp;
+ lp2 += 2;
+ }
+ break;
+
+ case 3:
+ if (lp2 < 2) {
+ for (i = 0, j = 0; i < 6 - (lp2 * 2); i++, j += width_tbl[1])
+ cur_lp[j] = *ref_lp;
+ lp2 = 3;
+ }
+ break;
+
+ case 6:
+ lp2 = 4;
+ break;
+
+ case 7:
+ if (rle_v3 != 0)
+ rle_v3 = 0;
+ else {
+ buf1--;
+ rle_v3 = 1;
+ }
+ lp2 = 4;
+ break;
+
+ case 8:
+ if (lp2 == 0) {
+ RLE_V3_CHECK(buf1,rle_v1,rle_v2,rle_v3)
+
+ if (rle_v1 == 1) {
+ for (i = 0, j = 0; i < 8; i++, j += width_tbl[1])
+ cur_lp[j] = ref_lp[j];
+ }
+
+ RLE_V2_CHECK(buf1,rle_v2, rle_v3,lp2)
+ break;
+ } else {
+ rle_v2 = (*buf1) - 1;
+ rle_v1 = 1;
+ }
+ case 5:
+ LP2_CHECK(buf1,rle_v3,lp2)
+ case 4:
+ for (i = 0, j = 0; i < 8 - (lp2 * 2); i++, j += width_tbl[1])
+ cur_lp[j] = *ref_lp;
+ lp2 = 4;
+ break;
+
+ case 9:
+ warning("Indeo3::decodeChunk: Untested (1)");
+ lv1 = *buf1++;
+ lv = (lv1 & 0x7F) << 1;
+ lv += (lv << 8);
+ lv += (lv << 16);
+
+ for (i = 0, j = 0; i < 4; i++, j += width_tbl[1])
+ cur_lp[j] = lv;
+
+ LV1_CHECK(buf1,rle_v3,lv1,lp2)
+ break;
+
+ default:
+ return;
+ }
+ }
+
+ cur_frm_pos += 4;
+ }
+
+ cur_frm_pos += (((width * 2) - blks_width) * 4);
+ flag1 = 0;
+ }
+ break;
+
+ case 10: /********** CASE 10 **********/
+ if (ref_vectors == NULL) {
+ flag1 = 1;
+
+ for ( ; blks_height > 0; blks_height -= 8) {
+ for (lp1 = 0; lp1 < blks_width; lp1 += 2) {
+ for (lp2 = 0; lp2 < 4; ) {
+ k = *buf1++;
+ cur_lp = ((uint32 *)cur_frm_pos) + width_tbl[lp2 * 2];
+ ref_lp = ((uint32 *)cur_frm_pos) + width_tbl[(lp2 * 2) - 1];
+ lv1 = ref_lp[0];
+ lv2 = ref_lp[1];
+ if (lp2 == 0 && flag1 != 0) {
+#if defined(SCUMM_BIG_ENDIAN)
+ lv1 = lv1 & 0xFF00FF00;
+ lv1 = (lv1 >> 8) | lv1;
+ lv2 = lv2 & 0xFF00FF00;
+ lv2 = (lv2 >> 8) | lv2;
+#else
+ lv1 = lv1 & 0x00FF00FF;
+ lv1 = (lv1 << 8) | lv1;
+ lv2 = lv2 & 0x00FF00FF;
+ lv2 = (lv2 << 8) | lv2;
+#endif
+ }
+
+ switch (correction_type_sp[lp2 & 0x01][k]) {
+ case 0:
+ cur_lp[width_tbl[1]] = FROM_LE_32(((FROM_LE_32(lv1) >> 1) + correctionloworder_lp[lp2 & 0x01][k]) << 1);
+ cur_lp[width_tbl[1]+1] = FROM_LE_32(((FROM_LE_32(lv2) >> 1) + correctionhighorder_lp[lp2 & 0x01][k]) << 1);
+ if (lp2 > 0 || strip->ypos != 0 || flag1 == 0) {
+ cur_lp[0] = ((cur_lp[-width_tbl[1]] >> 1) + (cur_lp[width_tbl[1]] >> 1)) & 0xFEFEFEFE;
+ cur_lp[1] = ((cur_lp[-width_tbl[1]+1] >> 1) + (cur_lp[width_tbl[1]+1] >> 1)) & 0xFEFEFEFE;
+ } else {
+ cur_lp[0] = cur_lp[width_tbl[1]];
+ cur_lp[1] = cur_lp[width_tbl[1]+1];
+ }
+ lp2++;
+ break;
+
+ case 1:
+ cur_lp[width_tbl[1]] = FROM_LE_32(((FROM_LE_32(lv1) >> 1) + correctionloworder_lp[lp2 & 0x01][*buf1]) << 1);
+ cur_lp[width_tbl[1]+1] = FROM_LE_32(((FROM_LE_32(lv2) >> 1) + correctionloworder_lp[lp2 & 0x01][k]) << 1);
+ if (lp2 > 0 || strip->ypos != 0 || flag1 == 0) {
+ cur_lp[0] = ((cur_lp[-width_tbl[1]] >> 1) + (cur_lp[width_tbl[1]] >> 1)) & 0xFEFEFEFE;
+ cur_lp[1] = ((cur_lp[-width_tbl[1]+1] >> 1) + (cur_lp[width_tbl[1]+1] >> 1)) & 0xFEFEFEFE;
+ } else {
+ cur_lp[0] = cur_lp[width_tbl[1]];
+ cur_lp[1] = cur_lp[width_tbl[1]+1];
+ }
+ buf1++;
+ lp2++;
+ break;
+
+ case 2:
+ if (lp2 == 0) {
+ if (flag1 != 0) {
+ for (i = 0, j = width_tbl[1]; i < 3; i++, j += width_tbl[1]) {
+ cur_lp[j] = lv1;
+ cur_lp[j+1] = lv2;
+ }
+ cur_lp[0] = ((cur_lp[-width_tbl[1]] >> 1) + (cur_lp[width_tbl[1]] >> 1)) & 0xFEFEFEFE;
+ cur_lp[1] = ((cur_lp[-width_tbl[1]+1] >> 1) + (cur_lp[width_tbl[1]+1] >> 1)) & 0xFEFEFEFE;
+ } else {
+ for (i = 0, j = 0; i < 4; i++, j += width_tbl[1]) {
+ cur_lp[j] = lv1;
+ cur_lp[j+1] = lv2;
+ }
+ }
+ lp2 += 2;
+ }
+ break;
+
+ case 3:
+ if (lp2 < 2) {
+ if (lp2 == 0 && flag1 != 0) {
+ for (i = 0, j = width_tbl[1]; i < 5; i++, j += width_tbl[1]) {
+ cur_lp[j] = lv1;
+ cur_lp[j+1] = lv2;
+ }
+ cur_lp[0] = ((cur_lp[-width_tbl[1]] >> 1) + (cur_lp[width_tbl[1]] >> 1)) & 0xFEFEFEFE;
+ cur_lp[1] = ((cur_lp[-width_tbl[1]+1] >> 1) + (cur_lp[width_tbl[1]+1] >> 1)) & 0xFEFEFEFE;
+ } else {
+ for (i = 0, j = 0; i < 6 - (lp2 * 2); i++, j += width_tbl[1]) {
+ cur_lp[j] = lv1;
+ cur_lp[j+1] = lv2;
+ }
+ }
+ lp2 = 3;
+ }
+ break;
+
+ case 8:
+ if (lp2 == 0) {
+ RLE_V3_CHECK(buf1,rle_v1,rle_v2,rle_v3)
+ if (rle_v1 == 1) {
+ if (flag1 != 0) {
+ for (i = 0, j = width_tbl[1]; i < 7; i++, j += width_tbl[1]) {
+ cur_lp[j] = lv1;
+ cur_lp[j+1] = lv2;
+ }
+ cur_lp[0] = ((cur_lp[-width_tbl[1]] >> 1) + (cur_lp[width_tbl[1]] >> 1)) & 0xFEFEFEFE;
+ cur_lp[1] = ((cur_lp[-width_tbl[1]+1] >> 1) + (cur_lp[width_tbl[1]+1] >> 1)) & 0xFEFEFEFE;
+ } else {
+ for (i = 0, j = 0; i < 8; i++, j += width_tbl[1]) {
+ cur_lp[j] = lv1;
+ cur_lp[j+1] = lv2;
+ }
+ }
+ }
+ RLE_V2_CHECK(buf1,rle_v2, rle_v3,lp2)
+ break;
+ } else {
+ rle_v1 = 1;
+ rle_v2 = (*buf1) - 1;
+ }
+ case 5:
+ LP2_CHECK(buf1,rle_v3,lp2)
+ case 4:
+ if (lp2 == 0 && flag1 != 0) {
+ for (i = 0, j = width_tbl[1]; i < 7; i++, j += width_tbl[1]) {
+ cur_lp[j] = lv1;
+ cur_lp[j+1] = lv2;
+ }
+ cur_lp[0] = ((cur_lp[-width_tbl[1]] >> 1) + (cur_lp[width_tbl[1]] >> 1)) & 0xFEFEFEFE;
+ cur_lp[1] = ((cur_lp[-width_tbl[1]+1] >> 1) + (cur_lp[width_tbl[1]+1] >> 1)) & 0xFEFEFEFE;
+ } else {
+ for (i = 0, j = 0; i < 8 - (lp2 * 2); i++, j += width_tbl[1]) {
+ cur_lp[j] = lv1;
+ cur_lp[j+1] = lv2;
+ }
+ }
+ lp2 = 4;
+ break;
+
+ case 6:
+ lp2 = 4;
+ break;
+
+ case 7:
+ if (lp2 == 0) {
+ if (rle_v3 != 0)
+ rle_v3 = 0;
+ else {
+ buf1--;
+ rle_v3 = 1;
+ }
+ lp2 = 4;
+ }
+ break;
+
+ case 9:
+ warning("Indeo3::decodeChunk: Untested (2)");
+ lv1 = *buf1;
+ lv = (lv1 & 0x7F) << 1;
+ lv += (lv << 8);
+ lv += (lv << 16);
+ for (i = 0, j = 0; i < 8; i++, j += width_tbl[1])
+ cur_lp[j] = lv;
+ LV1_CHECK(buf1,rle_v3,lv1,lp2)
+ break;
+
+ default:
+ return;
+ }
+ }
+
+ cur_frm_pos += 8;
+ }
+
+ cur_frm_pos += (((width * 2) - blks_width) * 4);
+ flag1 = 0;
+ }
+ } else {
+ for ( ; blks_height > 0; blks_height -= 8) {
+ for (lp1 = 0; lp1 < blks_width; lp1 += 2) {
+ for (lp2 = 0; lp2 < 4; ) {
+ k = *buf1++;
+ cur_lp = ((uint32 *)cur_frm_pos) + width_tbl[lp2 * 2];
+ ref_lp = ((uint32 *)ref_frm_pos) + width_tbl[lp2 * 2];
+
+ switch (correction_type_sp[lp2 & 0x01][k]) {
+ case 0:
+ lv1 = correctionloworder_lp[lp2 & 0x01][k];
+ lv2 = correctionhighorder_lp[lp2 & 0x01][k];
+ cur_lp[0] = FROM_LE_32(((FROM_LE_32(ref_lp[0]) >> 1) + lv1) << 1);
+ cur_lp[1] = FROM_LE_32(((FROM_LE_32(ref_lp[1]) >> 1) + lv2) << 1);
+ cur_lp[width_tbl[1]] = FROM_LE_32(((FROM_LE_32(ref_lp[width_tbl[1]]) >> 1) + lv1) << 1);
+ cur_lp[width_tbl[1]+1] = FROM_LE_32(((FROM_LE_32(ref_lp[width_tbl[1]+1]) >> 1) + lv2) << 1);
+ lp2++;
+ break;
+
+ case 1:
+ lv1 = correctionloworder_lp[lp2 & 0x01][*buf1++];
+ lv2 = correctionloworder_lp[lp2 & 0x01][k];
+ cur_lp[0] = FROM_LE_32(((FROM_LE_32(ref_lp[0]) >> 1) + lv1) << 1);
+ cur_lp[1] = FROM_LE_32(((FROM_LE_32(ref_lp[1]) >> 1) + lv2) << 1);
+ cur_lp[width_tbl[1]] = FROM_LE_32(((FROM_LE_32(ref_lp[width_tbl[1]]) >> 1) + lv1) << 1);
+ cur_lp[width_tbl[1]+1] = FROM_LE_32(((FROM_LE_32(ref_lp[width_tbl[1]+1]) >> 1) + lv2) << 1);
+ lp2++;
+ break;
+
+ case 2:
+ if (lp2 == 0) {
+ for (i = 0, j = 0; i < 4; i++, j += width_tbl[1]) {
+ cur_lp[j] = ref_lp[j];
+ cur_lp[j+1] = ref_lp[j+1];
+ }
+ lp2 += 2;
+ }
+ break;
+
+ case 3:
+ if (lp2 < 2) {
+ for (i = 0, j = 0; i < 6 - (lp2 * 2); i++, j += width_tbl[1]) {
+ cur_lp[j] = ref_lp[j];
+ cur_lp[j+1] = ref_lp[j+1];
+ }
+ lp2 = 3;
+ }
+ break;
+
+ case 8:
+ if (lp2 == 0) {
+ RLE_V3_CHECK(buf1,rle_v1,rle_v2,rle_v3)
+ for (i = 0, j = 0; i < 8; i++, j += width_tbl[1]) {
+ ((uint32 *)cur_frm_pos)[j] = ((uint32 *)ref_frm_pos)[j];
+ ((uint32 *)cur_frm_pos)[j+1] = ((uint32 *)ref_frm_pos)[j+1];
+ }
+ RLE_V2_CHECK(buf1,rle_v2, rle_v3,lp2)
+ break;
+ } else {
+ rle_v1 = 1;
+ rle_v2 = (*buf1) - 1;
+ }
+ case 5:
+ case 7:
+ LP2_CHECK(buf1,rle_v3,lp2)
+ case 6:
+ case 4:
+ for (i = 0, j = 0; i < 8 - (lp2 * 2); i++, j += width_tbl[1]) {
+ cur_lp[j] = ref_lp[j];
+ cur_lp[j+1] = ref_lp[j+1];
+ }
+ lp2 = 4;
+ break;
+
+ case 9:
+ warning("Indeo3::decodeChunk: Untested (3)");
+ lv1 = *buf1;
+ lv = (lv1 & 0x7F) << 1;
+ lv += (lv << 8);
+ lv += (lv << 16);
+ for (i = 0, j = 0; i < 8; i++, j += width_tbl[1])
+ ((uint32 *)cur_frm_pos)[j] = ((uint32 *)cur_frm_pos)[j+1] = lv;
+ LV1_CHECK(buf1,rle_v3,lv1,lp2)
+ break;
+
+ default:
+ return;
+ }
+ }
+
+ cur_frm_pos += 8;
+ ref_frm_pos += 8;
+ }
+
+ cur_frm_pos += (((width * 2) - blks_width) * 4);
+ ref_frm_pos += (((width * 2) - blks_width) * 4);
+ }
+ }
+ break;
+
+ case 11: /********** CASE 11 **********/
+ if (ref_vectors == NULL)
+ return;
+
+ for ( ; blks_height > 0; blks_height -= 8) {
+ for (lp1 = 0; lp1 < blks_width; lp1++) {
+ for (lp2 = 0; lp2 < 4; ) {
+ k = *buf1++;
+ cur_lp = ((uint32 *)cur_frm_pos) + width_tbl[lp2 * 2];
+ ref_lp = ((uint32 *)ref_frm_pos) + width_tbl[lp2 * 2];
+
+ switch (correction_type_sp[lp2 & 0x01][k]) {
+ case 0:
+ cur_lp[0] = FROM_LE_32(((FROM_LE_32(*ref_lp) >> 1) + correction_lp[lp2 & 0x01][k]) << 1);
+ cur_lp[width_tbl[1]] = FROM_LE_32(((FROM_LE_32(ref_lp[width_tbl[1]]) >> 1) + correction_lp[lp2 & 0x01][k]) << 1);
+ lp2++;
+ break;
+
+ case 1:
+ lv1 = (uint16)(correction_lp[lp2 & 0x01][*buf1++]);
+ lv2 = (uint16)(correction_lp[lp2 & 0x01][k]);
+ res = (uint16)(((FROM_LE_16(((uint16 *)ref_lp)[0]) >> 1) + lv1) << 1);
+ ((uint16 *)cur_lp)[0] = FROM_LE_16(res);
+ res = (uint16)(((FROM_LE_16(((uint16 *)ref_lp)[1]) >> 1) + lv2) << 1);
+ ((uint16 *)cur_lp)[1] = FROM_LE_16(res);
+ res = (uint16)(((FROM_LE_16(((uint16 *)ref_lp)[width_tbl[2]]) >> 1) + lv1) << 1);
+ ((uint16 *)cur_lp)[width_tbl[2]] = FROM_LE_16(res);
+ res = (uint16)(((FROM_LE_16(((uint16 *)ref_lp)[width_tbl[2]+1]) >> 1) + lv2) << 1);
+ ((uint16 *)cur_lp)[width_tbl[2]+1] = FROM_LE_16(res);
+ lp2++;
+ break;
+
+ case 2:
+ if (lp2 == 0) {
+ for (i = 0, j = 0; i < 4; i++, j += width_tbl[1])
+ cur_lp[j] = ref_lp[j];
+ lp2 += 2;
+ }
+ break;
+
+ case 3:
+ if (lp2 < 2) {
+ for (i = 0, j = 0; i < 6 - (lp2 * 2); i++, j += width_tbl[1])
+ cur_lp[j] = ref_lp[j];
+ lp2 = 3;
+ }
+ break;
+
+ case 8:
+ if (lp2 == 0) {
+ RLE_V3_CHECK(buf1,rle_v1,rle_v2,rle_v3)
+
+ for (i = 0, j = 0; i < 8; i++, j += width_tbl[1])
+ cur_lp[j] = ref_lp[j];
+
+ RLE_V2_CHECK(buf1,rle_v2, rle_v3,lp2)
+ break;
+ } else {
+ rle_v1 = 1;
+ rle_v2 = (*buf1) - 1;
+ }
+ case 5:
+ case 7:
+ LP2_CHECK(buf1,rle_v3,lp2)
+ case 4:
+ case 6:
+ for (i = 0, j = 0; i < 8 - (lp2 * 2); i++, j += width_tbl[1])
+ cur_lp[j] = ref_lp[j];
+ lp2 = 4;
+ break;
+
+ case 9:
+ warning("Indeo3::decodeChunk: Untested (4)");
+ lv1 = *buf1++;
+ lv = (lv1 & 0x7F) << 1;
+ lv += (lv << 8);
+ lv += (lv << 16);
+ for (i = 0, j = 0; i < 4; i++, j += width_tbl[1])
+ cur_lp[j] = lv;
+ LV1_CHECK(buf1,rle_v3,lv1,lp2)
+ break;
+
+ default:
+ return;
+ }
+ }
+
+ cur_frm_pos += 4;
+ ref_frm_pos += 4;
+ }
+
+ cur_frm_pos += (((width * 2) - blks_width) * 4);
+ ref_frm_pos += (((width * 2) - blks_width) * 4);
+ }
+ break;
+
+ default:
+ // FIXME: I've seen case 13 happen in Urban
+ // Runner. Perhaps it uses a more recent form of
+ // Indeo 3? There appears to have been several.
+ warning("Indeo3::decodeChunk: Unknown case %d", k);
+ return;
+ }
+ }
+
+ if (strip < strip_tbl)
+ return;
+
+ for ( ; strip >= strip_tbl; strip--) {
+ if (strip->split_flag != 0) {
+ strip->split_flag = 0;
+ strip->usl7 = (strip-1)->usl7;
+
+ if (strip->split_direction) {
+ strip->xpos += strip->width;
+ strip->width = (strip-1)->width - strip->width;
+ if (region_160_width <= strip->xpos && width < strip->width + strip->xpos)
+ strip->width = width - strip->xpos;
+ } else {
+ strip->ypos += strip->height;
+ strip->height = (strip-1)->height - strip->height;
+ }
+ break;
+ }
+ }
+ }
+}
+
+// static data
+
+const int Indeo3::_corrector_type_0[24] = {
+ 195, 159, 133, 115, 101, 93, 87, 77,
+ 195, 159, 133, 115, 101, 93, 87, 77,
+ 128, 79, 79, 79, 79, 79, 79, 79
+};
+
+const int Indeo3::_corrector_type_2[8] = { 9, 7, 6, 8, 5, 4, 3, 2 };
+
+const uint32 Indeo3::correction[] = {
+ 0x00000000, 0x00000202, 0xfffffdfe, 0x000002ff, 0xfffffd01, 0xffffff03, 0x000000fd, 0x00000404,
+ 0xfffffbfc, 0x00000501, 0xfffffaff, 0x00000105, 0xfffffefb, 0x000003fc, 0xfffffc04, 0x000005fe,
+ 0xfffffa02, 0xfffffe06, 0x000001fa, 0x00000904, 0xfffff6fc, 0x00000409, 0xfffffbf7, 0x00000909,
+ 0xfffff6f7, 0x00000a01, 0xfffff5ff, 0x0000010a, 0xfffffef6, 0x000007fb, 0xfffff805, 0xfffffb08,
+ 0x000004f8, 0x00000f09, 0xfffff0f7, 0x0000090f, 0xfffff6f1, 0x00000bfd, 0xfffff403, 0xfffffd0c,
+ 0x000002f4, 0x00001004, 0xffffeffc, 0x00000410, 0xfffffbf0, 0x00001010, 0xffffeff0, 0x00001200,
+ 0xffffee00, 0x00000012, 0xffffffee, 0x00000bf4, 0xfffff40c, 0x00000ff7, 0xfffff009, 0xfffff710,
+ 0x000008f0, 0x00001b0b, 0xffffe4f5, 0x00000b1b, 0xfffff4e5, 0x00001c13, 0xffffe3ed, 0x0000131c,
+ 0xffffece4, 0x000015fa, 0xffffea06, 0xfffffa16, 0x000005ea, 0x00001d04, 0xffffe2fc, 0x0000041d,
+ 0xfffffbe3, 0x00001e1e, 0xffffe1e2, 0x000020fe, 0xffffdf02, 0xfffffe21, 0x000001df, 0x000016ee,
+ 0xffffe912, 0xffffee17, 0x000011e9, 0x00001df1, 0xffffe20f, 0xfffff11e, 0x00000ee2, 0x00002e16,
+ 0xffffd1ea, 0x0000162e, 0xffffe9d2, 0x00002f0d, 0xffffd0f3, 0x00000d2f, 0xfffff2d1, 0x00003123,
+ 0xffffcedd, 0x00002331, 0xffffdccf, 0x000028f5, 0xffffd70b, 0xfffff529, 0x00000ad7, 0x00003304,
+ 0xffffccfc, 0x00000433, 0xfffffbcd, 0x00003636, 0xffffc9ca, 0x000021de, 0xffffde22, 0x000029e3,
+ 0xffffd61d, 0xffffe32a, 0x00001cd6, 0x00003bfa, 0xffffc406, 0xfffffa3c, 0x000005c4, 0x00004c1b,
+ 0xffffb3e5, 0x00001b4c, 0xffffe4b4, 0x00004d2b, 0xffffb2d5, 0x00002b4d, 0xffffd4b3, 0x000036e8,
+ 0xffffc918, 0xffffe837, 0x000017c9, 0x00004f0e, 0xffffb0f2, 0x00000e4f, 0xfffff1b1, 0x0000533f,
+ 0xffffacc1, 0x00003f53, 0xffffc0ad, 0x000049ec, 0xffffb614, 0xffffec4a, 0x000013b6, 0x00005802,
+ 0xffffa7fe, 0x00000258, 0xfffffda8, 0x00005d5d, 0xffffa2a3, 0x00003ccc, 0xffffc334, 0xffffcc3d,
+ 0x000033c3, 0x00007834, 0xffff87cc, 0x00003478, 0xffffcb88, 0x00004ad3, 0xffffb52d, 0xffffd34b,
+ 0x00002cb5, 0x00007d4b, 0xffff82b5, 0x00004b7d, 0xffffb483, 0x00007a21, 0xffff85df, 0x0000217a,
+ 0xffffde86, 0x000066f3, 0xffff990d, 0xfffff367, 0x00000c99, 0x00005fd8, 0xffffa028, 0xffffd860,
+ 0x000027a0, 0x00007ede, 0xffff8122, 0xffffde7f, 0x00002181, 0x000058a7, 0xffffa759, 0x000068b2,
+ 0xffff974e, 0xffffb269, 0x00004d97, 0x00000c0c, 0xfffff3f4, 0x00001717, 0xffffe8e9, 0x00002a2a,
+ 0xffffd5d6, 0x00004949, 0xffffb6b7, 0x00000000, 0x02020000, 0xfdfe0000, 0x02ff0000, 0xfd010000,
+ 0xff030000, 0x00fd0000, 0x00000202, 0x02020202, 0xfdfe0202, 0x02ff0202, 0xfd010202, 0xff030202,
+ 0x00fd0202, 0xfffffdfe, 0x0201fdfe, 0xfdfdfdfe, 0x02fefdfe, 0xfd00fdfe, 0xff02fdfe, 0x00fcfdfe,
+ 0x000002ff, 0x020202ff, 0xfdfe02ff, 0x02ff02ff, 0xfd0102ff, 0xff0302ff, 0x00fd02ff, 0xfffffd01,
+ 0x0201fd01, 0xfdfdfd01, 0x02fefd01, 0xfd00fd01, 0xff02fd01, 0x00fcfd01, 0xffffff03, 0x0201ff03,
+ 0xfdfdff03, 0x02feff03, 0xfd00ff03, 0xff02ff03, 0x00fcff03, 0x000000fd, 0x020200fd, 0xfdfe00fd,
+ 0x02ff00fd, 0xfd0100fd, 0xff0300fd, 0x00fd00fd, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000303, 0xfffffcfd, 0x000003ff, 0xfffffc01, 0xffffff04, 0x000000fc, 0x00000707,
+ 0xfffff8f9, 0x00000802, 0xfffff7fe, 0x00000208, 0xfffffdf8, 0x000008fe, 0xfffff702, 0xfffffe09,
+ 0x000001f7, 0x000005fa, 0xfffffa06, 0x00000d06, 0xfffff2fa, 0x0000060d, 0xfffff9f3, 0x00000d0d,
+ 0xfffff2f3, 0x00000e01, 0xfffff1ff, 0x0000010e, 0xfffffef2, 0x00000bf8, 0xfffff408, 0xfffff80c,
+ 0x000007f4, 0x0000170e, 0xffffe8f2, 0x00000e17, 0xfffff1e9, 0x000011fb, 0xffffee05, 0xfffffb12,
+ 0x000004ee, 0x00001806, 0xffffe7fa, 0x00000618, 0xfffff9e8, 0x00001818, 0xffffe7e8, 0x00001aff,
+ 0xffffe501, 0xffffff1b, 0x000000e5, 0x000010ef, 0xffffef11, 0x000016f3, 0xffffe90d, 0xfffff317,
+ 0x00000ce9, 0x00002810, 0xffffd7f0, 0x00001028, 0xffffefd8, 0x0000291c, 0xffffd6e4, 0x00001c29,
+ 0xffffe3d7, 0x000020f7, 0xffffdf09, 0xfffff721, 0x000008df, 0x00002b06, 0xffffd4fa, 0x0000062b,
+ 0xfffff9d5, 0x00002e2e, 0xffffd1d2, 0x000031fc, 0xffffce04, 0xfffffc32, 0x000003ce, 0x000021e5,
+ 0xffffde1b, 0xffffe522, 0x00001ade, 0x00002cea, 0xffffd316, 0xffffea2d, 0x000015d3, 0x00004522,
+ 0xffffbade, 0x00002245, 0xffffddbb, 0x00004613, 0xffffb9ed, 0x00001346, 0xffffecba, 0x00004935,
+ 0xffffb6cb, 0x00003549, 0xffffcab7, 0x00003def, 0xffffc211, 0xffffef3e, 0x000010c2, 0x00004d05,
+ 0xffffb2fb, 0x0000054d, 0xfffffab3, 0x00005252, 0xffffadae, 0x000032cd, 0xffffcd33, 0x00003fd5,
+ 0xffffc02b, 0xffffd540, 0x00002ac0, 0x000059f6, 0xffffa60a, 0xfffff65a, 0x000009a6, 0x00007229,
+ 0xffff8dd7, 0x00002972, 0xffffd68e, 0x00007440, 0xffff8bc0, 0x00004074, 0xffffbf8c, 0x000051db,
+ 0xffffae25, 0xffffdb52, 0x000024ae, 0x00007716, 0xffff88ea, 0x00001677, 0xffffe989, 0x00007c5f,
+ 0xffff83a1, 0x00005f7c, 0xffffa084, 0x00006ee2, 0xffff911e, 0xffffe26f, 0x00001d91, 0x00005bb2,
+ 0xffffa44e, 0xffffb25c, 0x00004da4, 0x000070bc, 0xffff8f44, 0xffffbc71, 0x0000438f, 0x00001212,
+ 0xffffedee, 0x00002222, 0xffffddde, 0x00003f3f, 0xffffc0c1, 0x00006d6d, 0xffff9293, 0x00000000,
+ 0x03030000, 0xfcfd0000, 0x03ff0000, 0xfc010000, 0xff040000, 0x00fc0000, 0x07070000, 0xf8f90000,
+ 0x00000303, 0x03030303, 0xfcfd0303, 0x03ff0303, 0xfc010303, 0xff040303, 0x00fc0303, 0x07070303,
+ 0xf8f90303, 0xfffffcfd, 0x0302fcfd, 0xfcfcfcfd, 0x03fefcfd, 0xfc00fcfd, 0xff03fcfd, 0x00fbfcfd,
+ 0x0706fcfd, 0xf8f8fcfd, 0x000003ff, 0x030303ff, 0xfcfd03ff, 0x03ff03ff, 0xfc0103ff, 0xff0403ff,
+ 0x00fc03ff, 0x070703ff, 0xf8f903ff, 0xfffffc01, 0x0302fc01, 0xfcfcfc01, 0x03fefc01, 0xfc00fc01,
+ 0xff03fc01, 0x00fbfc01, 0x0706fc01, 0xf8f8fc01, 0xffffff04, 0x0302ff04, 0xfcfcff04, 0x03feff04,
+ 0xfc00ff04, 0xff03ff04, 0x00fbff04, 0x0706ff04, 0xf8f8ff04, 0x000000fc, 0x030300fc, 0xfcfd00fc,
+ 0x03ff00fc, 0xfc0100fc, 0xff0400fc, 0x00fc00fc, 0x070700fc, 0xf8f900fc, 0x00000707, 0x03030707,
+ 0xfcfd0707, 0x03ff0707, 0xfc010707, 0xff040707, 0x00fc0707, 0x07070707, 0xf8f90707, 0xfffff8f9,
+ 0x0302f8f9, 0xfcfcf8f9, 0x03fef8f9, 0xfc00f8f9, 0xff03f8f9, 0x00fbf8f9, 0x0706f8f9, 0xf8f8f8f9,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000404, 0xfffffbfc, 0x000004ff, 0xfffffb01, 0xffffff05, 0x000000fb, 0x00000a03,
+ 0xfffff5fd, 0x0000030a, 0xfffffcf6, 0x00000909, 0xfffff6f7, 0x000006f9, 0xfffff907, 0x00000bfd,
+ 0xfffff403, 0xfffffd0c, 0x000002f4, 0x00001108, 0xffffeef8, 0x00000811, 0xfffff7ef, 0x00001111,
+ 0xffffeeef, 0x00001301, 0xffffecff, 0x00000113, 0xfffffeed, 0x00000ff5, 0xfffff00b, 0xfffff510,
+ 0x00000af0, 0x000016fa, 0xffffe906, 0xfffffa17, 0x000005e9, 0x00001f12, 0xffffe0ee, 0x0000121f,
+ 0xffffede1, 0x00002008, 0xffffdff8, 0x00000820, 0xfffff7e0, 0x00002121, 0xffffdedf, 0x000023ff,
+ 0xffffdc01, 0xffffff24, 0x000000dc, 0x000016e9, 0xffffe917, 0x00001eef, 0xffffe111, 0xffffef1f,
+ 0x000010e1, 0x00003615, 0xffffc9eb, 0x00001536, 0xffffeaca, 0x00003725, 0xffffc8db, 0x00002537,
+ 0xffffdac9, 0x00002bf4, 0xffffd40c, 0xfffff42c, 0x00000bd4, 0x00003908, 0xffffc6f8, 0x00000839,
+ 0xfffff7c7, 0x00003d3d, 0xffffc2c3, 0x000041fb, 0xffffbe05, 0xfffffb42, 0x000004be, 0x00002cdc,
+ 0xffffd324, 0xffffdc2d, 0x000023d3, 0x00003be3, 0xffffc41d, 0xffffe33c, 0x00001cc4, 0x00005c2d,
+ 0xffffa3d3, 0x00002d5c, 0xffffd2a4, 0x00005d19, 0xffffa2e7, 0x0000195d, 0xffffe6a3, 0x00006147,
+ 0xffff9eb9, 0x00004761, 0xffffb89f, 0x000052ea, 0xffffad16, 0xffffea53, 0x000015ad, 0x00006607,
+ 0xffff99f9, 0x00000766, 0xfffff89a, 0x00006d6d, 0xffff9293, 0x000043bc, 0xffffbc44, 0x000054c7,
+ 0xffffab39, 0xffffc755, 0x000038ab, 0x000077f3, 0xffff880d, 0xfffff378, 0x00000c88, 0x00006dcf,
+ 0xffff9231, 0xffffcf6e, 0x00003092, 0x00007a98, 0xffff8568, 0xffff987b, 0x00006785, 0x00001818,
+ 0xffffe7e8, 0x00002e2e, 0xffffd1d2, 0x00005454, 0xffffabac, 0x00000000, 0x04040000, 0xfbfc0000,
+ 0x04ff0000, 0xfb010000, 0xff050000, 0x00fb0000, 0x0a030000, 0xf5fd0000, 0x030a0000, 0x00000404,
+ 0x04040404, 0xfbfc0404, 0x04ff0404, 0xfb010404, 0xff050404, 0x00fb0404, 0x0a030404, 0xf5fd0404,
+ 0x030a0404, 0xfffffbfc, 0x0403fbfc, 0xfbfbfbfc, 0x04fefbfc, 0xfb00fbfc, 0xff04fbfc, 0x00fafbfc,
+ 0x0a02fbfc, 0xf5fcfbfc, 0x0309fbfc, 0x000004ff, 0x040404ff, 0xfbfc04ff, 0x04ff04ff, 0xfb0104ff,
+ 0xff0504ff, 0x00fb04ff, 0x0a0304ff, 0xf5fd04ff, 0x030a04ff, 0xfffffb01, 0x0403fb01, 0xfbfbfb01,
+ 0x04fefb01, 0xfb00fb01, 0xff04fb01, 0x00fafb01, 0x0a02fb01, 0xf5fcfb01, 0x0309fb01, 0xffffff05,
+ 0x0403ff05, 0xfbfbff05, 0x04feff05, 0xfb00ff05, 0xff04ff05, 0x00faff05, 0x0a02ff05, 0xf5fcff05,
+ 0x0309ff05, 0x000000fb, 0x040400fb, 0xfbfc00fb, 0x04ff00fb, 0xfb0100fb, 0xff0500fb, 0x00fb00fb,
+ 0x0a0300fb, 0xf5fd00fb, 0x030a00fb, 0x00000a03, 0x04040a03, 0xfbfc0a03, 0x04ff0a03, 0xfb010a03,
+ 0xff050a03, 0x00fb0a03, 0x0a030a03, 0xf5fd0a03, 0x030a0a03, 0xfffff5fd, 0x0403f5fd, 0xfbfbf5fd,
+ 0x04fef5fd, 0xfb00f5fd, 0xff04f5fd, 0x00faf5fd, 0x0a02f5fd, 0xf5fcf5fd, 0x0309f5fd, 0x0000030a,
+ 0x0404030a, 0xfbfc030a, 0x04ff030a, 0xfb01030a, 0xff05030a, 0x00fb030a, 0x0a03030a, 0xf5fd030a,
+ 0x030a030a, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000505, 0xfffffafb, 0x000006fe, 0xfffff902, 0xfffffe07, 0x000001f9, 0x00000b0b,
+ 0xfffff4f5, 0x00000d03, 0xfffff2fd, 0x0000030d, 0xfffffcf3, 0x000008f7, 0xfffff709, 0x00000efc,
+ 0xfffff104, 0xfffffc0f, 0x000003f1, 0x0000160b, 0xffffe9f5, 0x00000b16, 0xfffff4ea, 0x00001515,
+ 0xffffeaeb, 0x00001802, 0xffffe7fe, 0x00000218, 0xfffffde8, 0x000013f2, 0xffffec0e, 0xfffff214,
+ 0x00000dec, 0x00002617, 0xffffd9e9, 0x00001726, 0xffffe8da, 0x00001cf8, 0xffffe308, 0xfffff81d,
+ 0x000007e3, 0x0000270b, 0xffffd8f5, 0x00000b27, 0xfffff4d9, 0x00002929, 0xffffd6d7, 0x00002cff,
+ 0xffffd301, 0xffffff2d, 0x000000d3, 0x00001ce3, 0xffffe31d, 0x000026ea, 0xffffd916, 0xffffea27,
+ 0x000015d9, 0x0000431b, 0xffffbce5, 0x00001b43, 0xffffe4bd, 0x0000452f, 0xffffbad1, 0x00002f45,
+ 0xffffd0bb, 0x000037f1, 0xffffc80f, 0xfffff138, 0x00000ec8, 0x0000470b, 0xffffb8f5, 0x00000b47,
+ 0xfffff4b9, 0x00004c4c, 0xffffb3b4, 0x000052fa, 0xffffad06, 0xfffffa53, 0x000005ad, 0x000038d3,
+ 0xffffc72d, 0xffffd339, 0x00002cc7, 0x00004adc, 0xffffb524, 0xffffdc4b, 0x000023b5, 0x00007338,
+ 0xffff8cc8, 0x00003873, 0xffffc78d, 0x0000751f, 0xffff8ae1, 0x00001f75, 0xffffe08b, 0x00007a58,
+ 0xffff85a8, 0x0000587a, 0xffffa786, 0x000067e4, 0xffff981c, 0xffffe468, 0x00001b98, 0x000054ab,
+ 0xffffab55, 0x000069b8, 0xffff9648, 0xffffb86a, 0x00004796, 0x00001e1e, 0xffffe1e2, 0x00003a3a,
+ 0xffffc5c6, 0x00006969, 0xffff9697, 0x00000000, 0x05050000, 0xfafb0000, 0x06fe0000, 0xf9020000,
+ 0xfe070000, 0x01f90000, 0x0b0b0000, 0xf4f50000, 0x0d030000, 0xf2fd0000, 0x00000505, 0x05050505,
+ 0xfafb0505, 0x06fe0505, 0xf9020505, 0xfe070505, 0x01f90505, 0x0b0b0505, 0xf4f50505, 0x0d030505,
+ 0xf2fd0505, 0xfffffafb, 0x0504fafb, 0xfafafafb, 0x06fdfafb, 0xf901fafb, 0xfe06fafb, 0x01f8fafb,
+ 0x0b0afafb, 0xf4f4fafb, 0x0d02fafb, 0xf2fcfafb, 0x000006fe, 0x050506fe, 0xfafb06fe, 0x06fe06fe,
+ 0xf90206fe, 0xfe0706fe, 0x01f906fe, 0x0b0b06fe, 0xf4f506fe, 0x0d0306fe, 0xf2fd06fe, 0xfffff902,
+ 0x0504f902, 0xfafaf902, 0x06fdf902, 0xf901f902, 0xfe06f902, 0x01f8f902, 0x0b0af902, 0xf4f4f902,
+ 0x0d02f902, 0xf2fcf902, 0xfffffe07, 0x0504fe07, 0xfafafe07, 0x06fdfe07, 0xf901fe07, 0xfe06fe07,
+ 0x01f8fe07, 0x0b0afe07, 0xf4f4fe07, 0x0d02fe07, 0xf2fcfe07, 0x000001f9, 0x050501f9, 0xfafb01f9,
+ 0x06fe01f9, 0xf90201f9, 0xfe0701f9, 0x01f901f9, 0x0b0b01f9, 0xf4f501f9, 0x0d0301f9, 0xf2fd01f9,
+ 0x00000b0b, 0x05050b0b, 0xfafb0b0b, 0x06fe0b0b, 0xf9020b0b, 0xfe070b0b, 0x01f90b0b, 0x0b0b0b0b,
+ 0xf4f50b0b, 0x0d030b0b, 0xf2fd0b0b, 0xfffff4f5, 0x0504f4f5, 0xfafaf4f5, 0x06fdf4f5, 0xf901f4f5,
+ 0xfe06f4f5, 0x01f8f4f5, 0x0b0af4f5, 0xf4f4f4f5, 0x0d02f4f5, 0xf2fcf4f5, 0x00000d03, 0x05050d03,
+ 0xfafb0d03, 0x06fe0d03, 0xf9020d03, 0xfe070d03, 0x01f90d03, 0x0b0b0d03, 0xf4f50d03, 0x0d030d03,
+ 0xf2fd0d03, 0xfffff2fd, 0x0504f2fd, 0xfafaf2fd, 0x06fdf2fd, 0xf901f2fd, 0xfe06f2fd, 0x01f8f2fd,
+ 0x0b0af2fd, 0xf4f4f2fd, 0x0d02f2fd, 0xf2fcf2fd, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000606, 0xfffff9fa, 0x000007fe, 0xfffff802, 0xfffffe08, 0x000001f8, 0x00000d0d,
+ 0xfffff2f3, 0x00000f04, 0xfffff0fc, 0x0000040f, 0xfffffbf1, 0x00000af5, 0xfffff50b, 0x000011fb,
+ 0xffffee05, 0xfffffb12, 0x000004ee, 0x00001a0d, 0xffffe5f3, 0x00000d1a, 0xfffff2e6, 0x00001a1a,
+ 0xffffe5e6, 0x00001d02, 0xffffe2fe, 0x0000021d, 0xfffffde3, 0x000017f0, 0xffffe810, 0xfffff018,
+ 0x00000fe8, 0x00002e1c, 0xffffd1e4, 0x00001c2e, 0xffffe3d2, 0x000022f7, 0xffffdd09, 0xfffff723,
+ 0x000008dd, 0x00002f0d, 0xffffd0f3, 0x00000d2f, 0xfffff2d1, 0x00003131, 0xffffcecf, 0x000035ff,
+ 0xffffca01, 0xffffff36, 0x000000ca, 0x000022dd, 0xffffdd23, 0x00002ee6, 0xffffd11a, 0xffffe62f,
+ 0x000019d1, 0x00005120, 0xffffaee0, 0x00002051, 0xffffdfaf, 0x00005338, 0xffffacc8, 0x00003853,
+ 0xffffc7ad, 0x000042ee, 0xffffbd12, 0xffffee43, 0x000011bd, 0x0000560d, 0xffffa9f3, 0x00000d56,
+ 0xfffff2aa, 0x00005b5b, 0xffffa4a5, 0x000062f9, 0xffff9d07, 0xfffff963, 0x0000069d, 0x000043ca,
+ 0xffffbc36, 0xffffca44, 0x000035bc, 0x000059d4, 0xffffa62c, 0xffffd45a, 0x00002ba6, 0x00007bdf,
+ 0xffff8421, 0xffffdf7c, 0x00002084, 0x00006699, 0xffff9967, 0x00007eaa, 0xffff8156, 0xffffaa7f,
+ 0x00005581, 0x00002525, 0xffffdadb, 0x00004545, 0xffffbabb, 0x00000000, 0x06060000, 0xf9fa0000,
+ 0x07fe0000, 0xf8020000, 0xfe080000, 0x01f80000, 0x0d0d0000, 0xf2f30000, 0x0f040000, 0xf0fc0000,
+ 0x040f0000, 0x00000606, 0x06060606, 0xf9fa0606, 0x07fe0606, 0xf8020606, 0xfe080606, 0x01f80606,
+ 0x0d0d0606, 0xf2f30606, 0x0f040606, 0xf0fc0606, 0x040f0606, 0xfffff9fa, 0x0605f9fa, 0xf9f9f9fa,
+ 0x07fdf9fa, 0xf801f9fa, 0xfe07f9fa, 0x01f7f9fa, 0x0d0cf9fa, 0xf2f2f9fa, 0x0f03f9fa, 0xf0fbf9fa,
+ 0x040ef9fa, 0x000007fe, 0x060607fe, 0xf9fa07fe, 0x07fe07fe, 0xf80207fe, 0xfe0807fe, 0x01f807fe,
+ 0x0d0d07fe, 0xf2f307fe, 0x0f0407fe, 0xf0fc07fe, 0x040f07fe, 0xfffff802, 0x0605f802, 0xf9f9f802,
+ 0x07fdf802, 0xf801f802, 0xfe07f802, 0x01f7f802, 0x0d0cf802, 0xf2f2f802, 0x0f03f802, 0xf0fbf802,
+ 0x040ef802, 0xfffffe08, 0x0605fe08, 0xf9f9fe08, 0x07fdfe08, 0xf801fe08, 0xfe07fe08, 0x01f7fe08,
+ 0x0d0cfe08, 0xf2f2fe08, 0x0f03fe08, 0xf0fbfe08, 0x040efe08, 0x000001f8, 0x060601f8, 0xf9fa01f8,
+ 0x07fe01f8, 0xf80201f8, 0xfe0801f8, 0x01f801f8, 0x0d0d01f8, 0xf2f301f8, 0x0f0401f8, 0xf0fc01f8,
+ 0x040f01f8, 0x00000d0d, 0x06060d0d, 0xf9fa0d0d, 0x07fe0d0d, 0xf8020d0d, 0xfe080d0d, 0x01f80d0d,
+ 0x0d0d0d0d, 0xf2f30d0d, 0x0f040d0d, 0xf0fc0d0d, 0x040f0d0d, 0xfffff2f3, 0x0605f2f3, 0xf9f9f2f3,
+ 0x07fdf2f3, 0xf801f2f3, 0xfe07f2f3, 0x01f7f2f3, 0x0d0cf2f3, 0xf2f2f2f3, 0x0f03f2f3, 0xf0fbf2f3,
+ 0x040ef2f3, 0x00000f04, 0x06060f04, 0xf9fa0f04, 0x07fe0f04, 0xf8020f04, 0xfe080f04, 0x01f80f04,
+ 0x0d0d0f04, 0xf2f30f04, 0x0f040f04, 0xf0fc0f04, 0x040f0f04, 0xfffff0fc, 0x0605f0fc, 0xf9f9f0fc,
+ 0x07fdf0fc, 0xf801f0fc, 0xfe07f0fc, 0x01f7f0fc, 0x0d0cf0fc, 0xf2f2f0fc, 0x0f03f0fc, 0xf0fbf0fc,
+ 0x040ef0fc, 0x0000040f, 0x0606040f, 0xf9fa040f, 0x07fe040f, 0xf802040f, 0xfe08040f, 0x01f8040f,
+ 0x0d0d040f, 0xf2f3040f, 0x0f04040f, 0xf0fc040f, 0x040f040f, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000707, 0xfffff8f9, 0x000009fd, 0xfffff603, 0xfffffd0a, 0x000002f6, 0x00001010,
+ 0xffffeff0, 0x00001205, 0xffffedfb, 0x00000512, 0xfffffaee, 0x00000cf3, 0xfffff30d, 0x000014fa,
+ 0xffffeb06, 0xfffffa15, 0x000005eb, 0x00001e0f, 0xffffe1f1, 0x00000f1e, 0xfffff0e2, 0x00001e1e,
+ 0xffffe1e2, 0x00002202, 0xffffddfe, 0x00000222, 0xfffffdde, 0x00001bed, 0xffffe413, 0xffffed1c,
+ 0x000012e4, 0x00003620, 0xffffc9e0, 0x00002036, 0xffffdfca, 0x000028f5, 0xffffd70b, 0xfffff529,
+ 0x00000ad7, 0x0000370f, 0xffffc8f1, 0x00000f37, 0xfffff0c9, 0x00003939, 0xffffc6c7, 0x00003eff,
+ 0xffffc101, 0xffffff3f, 0x000000c1, 0x000027d8, 0xffffd828, 0x000036e2, 0xffffc91e, 0xffffe237,
+ 0x00001dc9, 0x00005e25, 0xffffa1db, 0x0000255e, 0xffffdaa2, 0x00006041, 0xffff9fbf, 0x00004160,
+ 0xffffbea0, 0x00004deb, 0xffffb215, 0xffffeb4e, 0x000014b2, 0x0000640f, 0xffff9bf1, 0x00000f64,
+ 0xfffff09c, 0x00006a6a, 0xffff9596, 0x000073f8, 0xffff8c08, 0xfffff874, 0x0000078c, 0x00004ec1,
+ 0xffffb13f, 0xffffc14f, 0x00003eb1, 0x000068cd, 0xffff9733, 0xffffcd69, 0x00003297, 0x00007788,
+ 0xffff8878, 0x00002b2b, 0xffffd4d5, 0x00005050, 0xffffafb0, 0x00000000, 0x07070000, 0xf8f90000,
+ 0x09fd0000, 0xf6030000, 0xfd0a0000, 0x02f60000, 0x10100000, 0xeff00000, 0x12050000, 0xedfb0000,
+ 0x05120000, 0x00000707, 0x07070707, 0xf8f90707, 0x09fd0707, 0xf6030707, 0xfd0a0707, 0x02f60707,
+ 0x10100707, 0xeff00707, 0x12050707, 0xedfb0707, 0x05120707, 0xfffff8f9, 0x0706f8f9, 0xf8f8f8f9,
+ 0x09fcf8f9, 0xf602f8f9, 0xfd09f8f9, 0x02f5f8f9, 0x100ff8f9, 0xefeff8f9, 0x1204f8f9, 0xedfaf8f9,
+ 0x0511f8f9, 0x000009fd, 0x070709fd, 0xf8f909fd, 0x09fd09fd, 0xf60309fd, 0xfd0a09fd, 0x02f609fd,
+ 0x101009fd, 0xeff009fd, 0x120509fd, 0xedfb09fd, 0x051209fd, 0xfffff603, 0x0706f603, 0xf8f8f603,
+ 0x09fcf603, 0xf602f603, 0xfd09f603, 0x02f5f603, 0x100ff603, 0xefeff603, 0x1204f603, 0xedfaf603,
+ 0x0511f603, 0xfffffd0a, 0x0706fd0a, 0xf8f8fd0a, 0x09fcfd0a, 0xf602fd0a, 0xfd09fd0a, 0x02f5fd0a,
+ 0x100ffd0a, 0xefeffd0a, 0x1204fd0a, 0xedfafd0a, 0x0511fd0a, 0x000002f6, 0x070702f6, 0xf8f902f6,
+ 0x09fd02f6, 0xf60302f6, 0xfd0a02f6, 0x02f602f6, 0x101002f6, 0xeff002f6, 0x120502f6, 0xedfb02f6,
+ 0x051202f6, 0x00001010, 0x07071010, 0xf8f91010, 0x09fd1010, 0xf6031010, 0xfd0a1010, 0x02f61010,
+ 0x10101010, 0xeff01010, 0x12051010, 0xedfb1010, 0x05121010, 0xffffeff0, 0x0706eff0, 0xf8f8eff0,
+ 0x09fceff0, 0xf602eff0, 0xfd09eff0, 0x02f5eff0, 0x100feff0, 0xefefeff0, 0x1204eff0, 0xedfaeff0,
+ 0x0511eff0, 0x00001205, 0x07071205, 0xf8f91205, 0x09fd1205, 0xf6031205, 0xfd0a1205, 0x02f61205,
+ 0x10101205, 0xeff01205, 0x12051205, 0xedfb1205, 0x05121205, 0xffffedfb, 0x0706edfb, 0xf8f8edfb,
+ 0x09fcedfb, 0xf602edfb, 0xfd09edfb, 0x02f5edfb, 0x100fedfb, 0xefefedfb, 0x1204edfb, 0xedfaedfb,
+ 0x0511edfb, 0x00000512, 0x07070512, 0xf8f90512, 0x09fd0512, 0xf6030512, 0xfd0a0512, 0x02f60512,
+ 0x10100512, 0xeff00512, 0x12050512, 0xedfb0512, 0x05120512, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000808, 0xfffff7f8, 0x00000afd, 0xfffff503, 0xfffffd0b, 0x000002f5, 0x00001212,
+ 0xffffedee, 0x00001405, 0xffffebfb, 0x00000514, 0xfffffaec, 0x00000ef1, 0xfffff10f, 0x000017f9,
+ 0xffffe807, 0xfffff918, 0x000006e8, 0x00002311, 0xffffdcef, 0x00001123, 0xffffeedd, 0x00002222,
+ 0xffffddde, 0x00002603, 0xffffd9fd, 0x00000326, 0xfffffcda, 0x00001fea, 0xffffe016, 0xffffea20,
+ 0x000015e0, 0x00003d25, 0xffffc2db, 0x0000253d, 0xffffdac3, 0x00002ef3, 0xffffd10d, 0xfffff32f,
+ 0x00000cd1, 0x00003f11, 0xffffc0ef, 0x0000113f, 0xffffeec1, 0x00004141, 0xffffbebf, 0x000047ff,
+ 0xffffb801, 0xffffff48, 0x000000b8, 0x00002dd2, 0xffffd22e, 0x00003edd, 0xffffc123, 0xffffdd3f,
+ 0x000022c1, 0x00006b2b, 0xffff94d5, 0x00002b6b, 0xffffd495, 0x00006e4b, 0xffff91b5, 0x00004b6e,
+ 0xffffb492, 0x000058e8, 0xffffa718, 0xffffe859, 0x000017a7, 0x00007211, 0xffff8def, 0x00001172,
+ 0xffffee8e, 0x00007979, 0xffff8687, 0x00005ab8, 0xffffa548, 0xffffb85b, 0x000047a5, 0x000077c6,
+ 0xffff883a, 0xffffc678, 0x00003988, 0x00003131, 0xffffcecf, 0x00005c5c, 0xffffa3a4, 0x00000000,
+ 0x08080000, 0xf7f80000, 0x0afd0000, 0xf5030000, 0xfd0b0000, 0x02f50000, 0x12120000, 0xedee0000,
+ 0x14050000, 0xebfb0000, 0x05140000, 0x00000808, 0x08080808, 0xf7f80808, 0x0afd0808, 0xf5030808,
+ 0xfd0b0808, 0x02f50808, 0x12120808, 0xedee0808, 0x14050808, 0xebfb0808, 0x05140808, 0xfffff7f8,
+ 0x0807f7f8, 0xf7f7f7f8, 0x0afcf7f8, 0xf502f7f8, 0xfd0af7f8, 0x02f4f7f8, 0x1211f7f8, 0xededf7f8,
+ 0x1404f7f8, 0xebfaf7f8, 0x0513f7f8, 0x00000afd, 0x08080afd, 0xf7f80afd, 0x0afd0afd, 0xf5030afd,
+ 0xfd0b0afd, 0x02f50afd, 0x12120afd, 0xedee0afd, 0x14050afd, 0xebfb0afd, 0x05140afd, 0xfffff503,
+ 0x0807f503, 0xf7f7f503, 0x0afcf503, 0xf502f503, 0xfd0af503, 0x02f4f503, 0x1211f503, 0xededf503,
+ 0x1404f503, 0xebfaf503, 0x0513f503, 0xfffffd0b, 0x0807fd0b, 0xf7f7fd0b, 0x0afcfd0b, 0xf502fd0b,
+ 0xfd0afd0b, 0x02f4fd0b, 0x1211fd0b, 0xededfd0b, 0x1404fd0b, 0xebfafd0b, 0x0513fd0b, 0x000002f5,
+ 0x080802f5, 0xf7f802f5, 0x0afd02f5, 0xf50302f5, 0xfd0b02f5, 0x02f502f5, 0x121202f5, 0xedee02f5,
+ 0x140502f5, 0xebfb02f5, 0x051402f5, 0x00001212, 0x08081212, 0xf7f81212, 0x0afd1212, 0xf5031212,
+ 0xfd0b1212, 0x02f51212, 0x12121212, 0xedee1212, 0x14051212, 0xebfb1212, 0x05141212, 0xffffedee,
+ 0x0807edee, 0xf7f7edee, 0x0afcedee, 0xf502edee, 0xfd0aedee, 0x02f4edee, 0x1211edee, 0xedededee,
+ 0x1404edee, 0xebfaedee, 0x0513edee, 0x00001405, 0x08081405, 0xf7f81405, 0x0afd1405, 0xf5031405,
+ 0xfd0b1405, 0x02f51405, 0x12121405, 0xedee1405, 0x14051405, 0xebfb1405, 0x05141405, 0xffffebfb,
+ 0x0807ebfb, 0xf7f7ebfb, 0x0afcebfb, 0xf502ebfb, 0xfd0aebfb, 0x02f4ebfb, 0x1211ebfb, 0xededebfb,
+ 0x1404ebfb, 0xebfaebfb, 0x0513ebfb, 0x00000514, 0x08080514, 0xf7f80514, 0x0afd0514, 0xf5030514,
+ 0xfd0b0514, 0x02f50514, 0x12120514, 0xedee0514, 0x14050514, 0xebfb0514, 0x05140514, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000909, 0xfffff6f7, 0x00000bfd, 0xfffff403, 0xfffffd0c, 0x000002f4, 0x00001414,
+ 0xffffebec, 0x00001706, 0xffffe8fa, 0x00000617, 0xfffff9e9, 0x000010ef, 0xffffef11, 0x00001af9,
+ 0xffffe507, 0xfffff91b, 0x000006e5, 0x00002713, 0xffffd8ed, 0x00001327, 0xffffecd9, 0x00002727,
+ 0xffffd8d9, 0x00002b03, 0xffffd4fd, 0x0000032b, 0xfffffcd5, 0x000023e8, 0xffffdc18, 0xffffe824,
+ 0x000017dc, 0x0000452a, 0xffffbad6, 0x00002a45, 0xffffd5bb, 0x000034f2, 0xffffcb0e, 0xfffff235,
+ 0x00000dcb, 0x00004713, 0xffffb8ed, 0x00001347, 0xffffecb9, 0x00004949, 0xffffb6b7, 0x00004ffe,
+ 0xffffb002, 0xfffffe50, 0x000001b0, 0x000033cc, 0xffffcc34, 0x000045d9, 0xffffba27, 0xffffd946,
+ 0x000026ba, 0x00007930, 0xffff86d0, 0x00003079, 0xffffcf87, 0x00007c54, 0xffff83ac, 0x0000547c,
+ 0xffffab84, 0x000063e5, 0xffff9c1b, 0xffffe564, 0x00001a9c, 0x000065af, 0xffff9a51, 0xffffaf66,
+ 0x0000509a, 0x00003737, 0xffffc8c9, 0x00006868, 0xffff9798, 0x00000000, 0x09090000, 0xf6f70000,
+ 0x0bfd0000, 0xf4030000, 0xfd0c0000, 0x02f40000, 0x14140000, 0xebec0000, 0x17060000, 0xe8fa0000,
+ 0x06170000, 0xf9e90000, 0x00000909, 0x09090909, 0xf6f70909, 0x0bfd0909, 0xf4030909, 0xfd0c0909,
+ 0x02f40909, 0x14140909, 0xebec0909, 0x17060909, 0xe8fa0909, 0x06170909, 0xf9e90909, 0xfffff6f7,
+ 0x0908f6f7, 0xf6f6f6f7, 0x0bfcf6f7, 0xf402f6f7, 0xfd0bf6f7, 0x02f3f6f7, 0x1413f6f7, 0xebebf6f7,
+ 0x1705f6f7, 0xe8f9f6f7, 0x0616f6f7, 0xf9e8f6f7, 0x00000bfd, 0x09090bfd, 0xf6f70bfd, 0x0bfd0bfd,
+ 0xf4030bfd, 0xfd0c0bfd, 0x02f40bfd, 0x14140bfd, 0xebec0bfd, 0x17060bfd, 0xe8fa0bfd, 0x06170bfd,
+ 0xf9e90bfd, 0xfffff403, 0x0908f403, 0xf6f6f403, 0x0bfcf403, 0xf402f403, 0xfd0bf403, 0x02f3f403,
+ 0x1413f403, 0xebebf403, 0x1705f403, 0xe8f9f403, 0x0616f403, 0xf9e8f403, 0xfffffd0c, 0x0908fd0c,
+ 0xf6f6fd0c, 0x0bfcfd0c, 0xf402fd0c, 0xfd0bfd0c, 0x02f3fd0c, 0x1413fd0c, 0xebebfd0c, 0x1705fd0c,
+ 0xe8f9fd0c, 0x0616fd0c, 0xf9e8fd0c, 0x000002f4, 0x090902f4, 0xf6f702f4, 0x0bfd02f4, 0xf40302f4,
+ 0xfd0c02f4, 0x02f402f4, 0x141402f4, 0xebec02f4, 0x170602f4, 0xe8fa02f4, 0x061702f4, 0xf9e902f4,
+ 0x00001414, 0x09091414, 0xf6f71414, 0x0bfd1414, 0xf4031414, 0xfd0c1414, 0x02f41414, 0x14141414,
+ 0xebec1414, 0x17061414, 0xe8fa1414, 0x06171414, 0xf9e91414, 0xffffebec, 0x0908ebec, 0xf6f6ebec,
+ 0x0bfcebec, 0xf402ebec, 0xfd0bebec, 0x02f3ebec, 0x1413ebec, 0xebebebec, 0x1705ebec, 0xe8f9ebec,
+ 0x0616ebec, 0xf9e8ebec, 0x00001706, 0x09091706, 0xf6f71706, 0x0bfd1706, 0xf4031706, 0xfd0c1706,
+ 0x02f41706, 0x14141706, 0xebec1706, 0x17061706, 0xe8fa1706, 0x06171706, 0xf9e91706, 0xffffe8fa,
+ 0x0908e8fa, 0xf6f6e8fa, 0x0bfce8fa, 0xf402e8fa, 0xfd0be8fa, 0x02f3e8fa, 0x1413e8fa, 0xebebe8fa,
+ 0x1705e8fa, 0xe8f9e8fa, 0x0616e8fa, 0xf9e8e8fa, 0x00000617, 0x09090617, 0xf6f70617, 0x0bfd0617,
+ 0xf4030617, 0xfd0c0617, 0x02f40617, 0x14140617, 0xebec0617, 0x17060617, 0xe8fa0617, 0x06170617,
+ 0xf9e90617, 0xfffff9e9, 0x0908f9e9, 0xf6f6f9e9, 0x0bfcf9e9, 0xf402f9e9, 0xfd0bf9e9, 0x02f3f9e9,
+ 0x1413f9e9, 0xebebf9e9, 0x1705f9e9, 0xe8f9f9e9, 0x0616f9e9, 0xf9e8f9e9, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000202, 0xfffffdfe, 0x00000200, 0xfffffe00, 0x00000002, 0xfffffffe, 0x00000404,
+ 0xfffffbfc, 0x00000400, 0xfffffc00, 0x00000004, 0xfffffffc, 0x000003fc, 0xfffffc04, 0x000005fe,
+ 0xfffffa02, 0xfffffe06, 0x000001fa, 0x00000804, 0xfffff7fc, 0x00000408, 0xfffffbf8, 0x00000808,
+ 0xfffff7f8, 0x00000a00, 0xfffff600, 0x0000000a, 0xfffffff6, 0x000007fc, 0xfffff804, 0xfffffc08,
+ 0x000003f8, 0x00000e08, 0xfffff1f8, 0x0000080e, 0xfffff7f2, 0x00000bfe, 0xfffff402, 0xfffffe0c,
+ 0x000001f4, 0x00001004, 0xffffeffc, 0x00000410, 0xfffffbf0, 0x00001010, 0xffffeff0, 0x00001200,
+ 0xffffee00, 0x00000012, 0xffffffee, 0x00000bf4, 0xfffff40c, 0x00000ff8, 0xfffff008, 0xfffff810,
+ 0x000007f0, 0x00001a0a, 0xffffe5f6, 0x00000a1a, 0xfffff5e6, 0x00001c12, 0xffffe3ee, 0x0000121c,
+ 0xffffede4, 0x000015fa, 0xffffea06, 0xfffffa16, 0x000005ea, 0x00001c04, 0xffffe3fc, 0x0000041c,
+ 0xfffffbe4, 0x00001e1e, 0xffffe1e2, 0x00001ffe, 0xffffe002, 0xfffffe20, 0x000001e0, 0x000015ee,
+ 0xffffea12, 0xffffee16, 0x000011ea, 0x00001df2, 0xffffe20e, 0xfffff21e, 0x00000de2, 0x00002e16,
+ 0xffffd1ea, 0x0000162e, 0xffffe9d2, 0x00002e0c, 0xffffd1f4, 0x00000c2e, 0xfffff3d2, 0x00003022,
+ 0xffffcfde, 0x00002230, 0xffffddd0, 0x000027f6, 0xffffd80a, 0xfffff628, 0x000009d8, 0x00003204,
+ 0xffffcdfc, 0x00000432, 0xfffffbce, 0x00003636, 0xffffc9ca, 0x000021de, 0xffffde22, 0x000029e4,
+ 0xffffd61c, 0xffffe42a, 0x00001bd6, 0x00003bfa, 0xffffc406, 0xfffffa3c, 0x000005c4, 0x00004c1a,
+ 0xffffb3e6, 0x00001a4c, 0xffffe5b4, 0x00004c2a, 0xffffb3d6, 0x00002a4c, 0xffffd5b4, 0x000035e8,
+ 0xffffca18, 0xffffe836, 0x000017ca, 0x00004e0e, 0xffffb1f2, 0x00000e4e, 0xfffff1b2, 0x0000523e,
+ 0xffffadc2, 0x00003e52, 0xffffc1ae, 0x000049ec, 0xffffb614, 0xffffec4a, 0x000013b6, 0x00005802,
+ 0xffffa7fe, 0x00000258, 0xfffffda8, 0x00005c5c, 0xffffa3a4, 0x00003bcc, 0xffffc434, 0xffffcc3c,
+ 0x000033c4, 0x00007634, 0xffff89cc, 0x00003476, 0xffffcb8a, 0x000049d4, 0xffffb62c, 0xffffd44a,
+ 0x00002bb6, 0x0000764a, 0xffff89b6, 0x00004a76, 0xffffb58a, 0x00007620, 0xffff89e0, 0x00002076,
+ 0xffffdf8a, 0x000065f4, 0xffff9a0c, 0xfffff466, 0x00000b9a, 0x00005fd8, 0xffffa028, 0xffffd860,
+ 0x000027a0, 0x000075de, 0xffff8a22, 0xffffde76, 0x0000218a, 0x000057a8, 0xffffa858, 0x000067b2,
+ 0xffff984e, 0xffffb268, 0x00004d98, 0x00000c0c, 0xfffff3f4, 0x00001616, 0xffffe9ea, 0x00002a2a,
+ 0xffffd5d6, 0x00004848, 0xffffb7b8, 0x00000000, 0x02020000, 0xfdfe0000, 0x02000000, 0xfe000000,
+ 0x00020000, 0xfffe0000, 0x00000202, 0x02020202, 0xfdfe0202, 0x02000202, 0xfe000202, 0x00020202,
+ 0xfffe0202, 0xfffffdfe, 0x0201fdfe, 0xfdfdfdfe, 0x01fffdfe, 0xfdfffdfe, 0x0001fdfe, 0xfffdfdfe,
+ 0x00000200, 0x02020200, 0xfdfe0200, 0x02000200, 0xfe000200, 0x00020200, 0xfffe0200, 0xfffffe00,
+ 0x0201fe00, 0xfdfdfe00, 0x01fffe00, 0xfdfffe00, 0x0001fe00, 0xfffdfe00, 0x00000002, 0x02020002,
+ 0xfdfe0002, 0x02000002, 0xfe000002, 0x00020002, 0xfffe0002, 0xfffffffe, 0x0201fffe, 0xfdfdfffe,
+ 0x01fffffe, 0xfdfffffe, 0x0001fffe, 0xfffdfffe, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000303, 0xfffffcfd, 0x00000300, 0xfffffd00, 0x00000003, 0xfffffffd, 0x00000606,
+ 0xfffff9fa, 0x00000903, 0xfffff6fd, 0x00000309, 0xfffffcf7, 0x000008fd, 0xfffff703, 0xfffffd09,
+ 0x000002f7, 0x000005fa, 0xfffffa06, 0x00000c06, 0xfffff3fa, 0x0000060c, 0xfffff9f4, 0x00000c0c,
+ 0xfffff3f4, 0x00000f00, 0xfffff100, 0x0000000f, 0xfffffff1, 0x00000bf7, 0xfffff409, 0xfffff70c,
+ 0x000008f4, 0x0000180f, 0xffffe7f1, 0x00000f18, 0xfffff0e8, 0x000011fa, 0xffffee06, 0xfffffa12,
+ 0x000005ee, 0x00001806, 0xffffe7fa, 0x00000618, 0xfffff9e8, 0x00001818, 0xffffe7e8, 0x00001b00,
+ 0xffffe500, 0x0000001b, 0xffffffe5, 0x000011ee, 0xffffee12, 0x000017f4, 0xffffe80c, 0xfffff418,
+ 0x00000be8, 0x0000270f, 0xffffd8f1, 0x00000f27, 0xfffff0d9, 0x00002a1b, 0xffffd5e5, 0x00001b2a,
+ 0xffffe4d6, 0x000020f7, 0xffffdf09, 0xfffff721, 0x000008df, 0x00002a06, 0xffffd5fa, 0x0000062a,
+ 0xfffff9d6, 0x00002d2d, 0xffffd2d3, 0x000032fd, 0xffffcd03, 0xfffffd33, 0x000002cd, 0x000020e5,
+ 0xffffdf1b, 0xffffe521, 0x00001adf, 0x00002ceb, 0xffffd315, 0xffffeb2d, 0x000014d3, 0x00004521,
+ 0xffffbadf, 0x00002145, 0xffffdebb, 0x00004512, 0xffffbaee, 0x00001245, 0xffffedbb, 0x00004836,
+ 0xffffb7ca, 0x00003648, 0xffffc9b8, 0x00003eee, 0xffffc112, 0xffffee3f, 0x000011c1, 0x00004e06,
+ 0xffffb1fa, 0x0000064e, 0xfffff9b2, 0x00005151, 0xffffaeaf, 0x000032cd, 0xffffcd33, 0x00003ed6,
+ 0xffffc12a, 0xffffd63f, 0x000029c1, 0x000059f7, 0xffffa609, 0xfffff75a, 0x000008a6, 0x0000722a,
+ 0xffff8dd6, 0x00002a72, 0xffffd58e, 0x0000753f, 0xffff8ac1, 0x00003f75, 0xffffc08b, 0x000050dc,
+ 0xffffaf24, 0xffffdc51, 0x000023af, 0x00007815, 0xffff87eb, 0x00001578, 0xffffea88, 0x00007b60,
+ 0xffff84a0, 0x0000607b, 0xffff9f85, 0x00006ee2, 0xffff911e, 0xffffe26f, 0x00001d91, 0x00005cb2,
+ 0xffffa34e, 0xffffb25d, 0x00004da3, 0x000071bb, 0xffff8e45, 0xffffbb72, 0x0000448e, 0x00001212,
+ 0xffffedee, 0x00002121, 0xffffdedf, 0x00003f3f, 0xffffc0c1, 0x00006c6c, 0xffff9394, 0x00000000,
+ 0x03030000, 0xfcfd0000, 0x03000000, 0xfd000000, 0x00030000, 0xfffd0000, 0x06060000, 0xf9fa0000,
+ 0x00000303, 0x03030303, 0xfcfd0303, 0x03000303, 0xfd000303, 0x00030303, 0xfffd0303, 0x06060303,
+ 0xf9fa0303, 0xfffffcfd, 0x0302fcfd, 0xfcfcfcfd, 0x02fffcfd, 0xfcfffcfd, 0x0002fcfd, 0xfffcfcfd,
+ 0x0605fcfd, 0xf9f9fcfd, 0x00000300, 0x03030300, 0xfcfd0300, 0x03000300, 0xfd000300, 0x00030300,
+ 0xfffd0300, 0x06060300, 0xf9fa0300, 0xfffffd00, 0x0302fd00, 0xfcfcfd00, 0x02fffd00, 0xfcfffd00,
+ 0x0002fd00, 0xfffcfd00, 0x0605fd00, 0xf9f9fd00, 0x00000003, 0x03030003, 0xfcfd0003, 0x03000003,
+ 0xfd000003, 0x00030003, 0xfffd0003, 0x06060003, 0xf9fa0003, 0xfffffffd, 0x0302fffd, 0xfcfcfffd,
+ 0x02fffffd, 0xfcfffffd, 0x0002fffd, 0xfffcfffd, 0x0605fffd, 0xf9f9fffd, 0x00000606, 0x03030606,
+ 0xfcfd0606, 0x03000606, 0xfd000606, 0x00030606, 0xfffd0606, 0x06060606, 0xf9fa0606, 0xfffff9fa,
+ 0x0302f9fa, 0xfcfcf9fa, 0x02fff9fa, 0xfcfff9fa, 0x0002f9fa, 0xfffcf9fa, 0x0605f9fa, 0xf9f9f9fa,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000404, 0xfffffbfc, 0x00000400, 0xfffffc00, 0x00000004, 0xfffffffc, 0x00000804,
+ 0xfffff7fc, 0x00000408, 0xfffffbf8, 0x00000808, 0xfffff7f8, 0x000007f8, 0xfffff808, 0x00000bfc,
+ 0xfffff404, 0xfffffc0c, 0x000003f4, 0x00001008, 0xffffeff8, 0x00000810, 0xfffff7f0, 0x00001010,
+ 0xffffeff0, 0x00001400, 0xffffec00, 0x00000014, 0xffffffec, 0x00000ff4, 0xfffff00c, 0xfffff410,
+ 0x00000bf0, 0x000017fc, 0xffffe804, 0xfffffc18, 0x000003e8, 0x00002010, 0xffffdff0, 0x00001020,
+ 0xffffefe0, 0x00002008, 0xffffdff8, 0x00000820, 0xfffff7e0, 0x00002020, 0xffffdfe0, 0x00002400,
+ 0xffffdc00, 0x00000024, 0xffffffdc, 0x000017e8, 0xffffe818, 0x00001ff0, 0xffffe010, 0xfffff020,
+ 0x00000fe0, 0x00003414, 0xffffcbec, 0x00001434, 0xffffebcc, 0x00003824, 0xffffc7dc, 0x00002438,
+ 0xffffdbc8, 0x00002bf4, 0xffffd40c, 0xfffff42c, 0x00000bd4, 0x00003808, 0xffffc7f8, 0x00000838,
+ 0xfffff7c8, 0x00003c3c, 0xffffc3c4, 0x00003ffc, 0xffffc004, 0xfffffc40, 0x000003c0, 0x00002bdc,
+ 0xffffd424, 0xffffdc2c, 0x000023d4, 0x00003be4, 0xffffc41c, 0xffffe43c, 0x00001bc4, 0x00005c2c,
+ 0xffffa3d4, 0x00002c5c, 0xffffd3a4, 0x00005c18, 0xffffa3e8, 0x0000185c, 0xffffe7a4, 0x00006048,
+ 0xffff9fb8, 0x00004860, 0xffffb7a0, 0x000053ec, 0xffffac14, 0xffffec54, 0x000013ac, 0x00006408,
+ 0xffff9bf8, 0x00000864, 0xfffff79c, 0x00006c6c, 0xffff9394, 0x000043bc, 0xffffbc44, 0x000053c8,
+ 0xffffac38, 0xffffc854, 0x000037ac, 0x000077f4, 0xffff880c, 0xfffff478, 0x00000b88, 0x00006bd0,
+ 0xffff9430, 0xffffd06c, 0x00002f94, 0x00007b98, 0xffff8468, 0xffff987c, 0x00006784, 0x00001818,
+ 0xffffe7e8, 0x00002c2c, 0xffffd3d4, 0x00005454, 0xffffabac, 0x00000000, 0x04040000, 0xfbfc0000,
+ 0x04000000, 0xfc000000, 0x00040000, 0xfffc0000, 0x08040000, 0xf7fc0000, 0x04080000, 0x00000404,
+ 0x04040404, 0xfbfc0404, 0x04000404, 0xfc000404, 0x00040404, 0xfffc0404, 0x08040404, 0xf7fc0404,
+ 0x04080404, 0xfffffbfc, 0x0403fbfc, 0xfbfbfbfc, 0x03fffbfc, 0xfbfffbfc, 0x0003fbfc, 0xfffbfbfc,
+ 0x0803fbfc, 0xf7fbfbfc, 0x0407fbfc, 0x00000400, 0x04040400, 0xfbfc0400, 0x04000400, 0xfc000400,
+ 0x00040400, 0xfffc0400, 0x08040400, 0xf7fc0400, 0x04080400, 0xfffffc00, 0x0403fc00, 0xfbfbfc00,
+ 0x03fffc00, 0xfbfffc00, 0x0003fc00, 0xfffbfc00, 0x0803fc00, 0xf7fbfc00, 0x0407fc00, 0x00000004,
+ 0x04040004, 0xfbfc0004, 0x04000004, 0xfc000004, 0x00040004, 0xfffc0004, 0x08040004, 0xf7fc0004,
+ 0x04080004, 0xfffffffc, 0x0403fffc, 0xfbfbfffc, 0x03fffffc, 0xfbfffffc, 0x0003fffc, 0xfffbfffc,
+ 0x0803fffc, 0xf7fbfffc, 0x0407fffc, 0x00000804, 0x04040804, 0xfbfc0804, 0x04000804, 0xfc000804,
+ 0x00040804, 0xfffc0804, 0x08040804, 0xf7fc0804, 0x04080804, 0xfffff7fc, 0x0403f7fc, 0xfbfbf7fc,
+ 0x03fff7fc, 0xfbfff7fc, 0x0003f7fc, 0xfffbf7fc, 0x0803f7fc, 0xf7fbf7fc, 0x0407f7fc, 0x00000408,
+ 0x04040408, 0xfbfc0408, 0x04000408, 0xfc000408, 0x00040408, 0xfffc0408, 0x08040408, 0xf7fc0408,
+ 0x04080408, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000505, 0xfffffafb, 0x00000500, 0xfffffb00, 0x00000005, 0xfffffffb, 0x00000a0a,
+ 0xfffff5f6, 0x00000f05, 0xfffff0fb, 0x0000050f, 0xfffffaf1, 0x000009f6, 0xfffff60a, 0x00000efb,
+ 0xfffff105, 0xfffffb0f, 0x000004f1, 0x0000140a, 0xffffebf6, 0x00000a14, 0xfffff5ec, 0x00001414,
+ 0xffffebec, 0x00001900, 0xffffe700, 0x00000019, 0xffffffe7, 0x000013f1, 0xffffec0f, 0xfffff114,
+ 0x00000eec, 0x00002819, 0xffffd7e7, 0x00001928, 0xffffe6d8, 0x00001df6, 0xffffe20a, 0xfffff61e,
+ 0x000009e2, 0x0000280a, 0xffffd7f6, 0x00000a28, 0xfffff5d8, 0x00002828, 0xffffd7d8, 0x00002d00,
+ 0xffffd300, 0x0000002d, 0xffffffd3, 0x00001de2, 0xffffe21e, 0x000027ec, 0xffffd814, 0xffffec28,
+ 0x000013d8, 0x00004119, 0xffffbee7, 0x00001941, 0xffffe6bf, 0x0000462d, 0xffffb9d3, 0x00002d46,
+ 0xffffd2ba, 0x000036f1, 0xffffc90f, 0xfffff137, 0x00000ec9, 0x0000460a, 0xffffb9f6, 0x00000a46,
+ 0xfffff5ba, 0x00004b4b, 0xffffb4b5, 0x000054fb, 0xffffab05, 0xfffffb55, 0x000004ab, 0x000036d3,
+ 0xffffc92d, 0xffffd337, 0x00002cc9, 0x00004add, 0xffffb523, 0xffffdd4b, 0x000022b5, 0x00007337,
+ 0xffff8cc9, 0x00003773, 0xffffc88d, 0x0000731e, 0xffff8ce2, 0x00001e73, 0xffffe18d, 0x0000785a,
+ 0xffff87a6, 0x00005a78, 0xffffa588, 0x000068e2, 0xffff971e, 0xffffe269, 0x00001d97, 0x000054ab,
+ 0xffffab55, 0x000068ba, 0xffff9746, 0xffffba69, 0x00004597, 0x00001e1e, 0xffffe1e2, 0x00003c3c,
+ 0xffffc3c4, 0x00006969, 0xffff9697, 0x00000000, 0x05050000, 0xfafb0000, 0x05000000, 0xfb000000,
+ 0x00050000, 0xfffb0000, 0x0a0a0000, 0xf5f60000, 0x0f050000, 0xf0fb0000, 0x00000505, 0x05050505,
+ 0xfafb0505, 0x05000505, 0xfb000505, 0x00050505, 0xfffb0505, 0x0a0a0505, 0xf5f60505, 0x0f050505,
+ 0xf0fb0505, 0xfffffafb, 0x0504fafb, 0xfafafafb, 0x04fffafb, 0xfafffafb, 0x0004fafb, 0xfffafafb,
+ 0x0a09fafb, 0xf5f5fafb, 0x0f04fafb, 0xf0fafafb, 0x00000500, 0x05050500, 0xfafb0500, 0x05000500,
+ 0xfb000500, 0x00050500, 0xfffb0500, 0x0a0a0500, 0xf5f60500, 0x0f050500, 0xf0fb0500, 0xfffffb00,
+ 0x0504fb00, 0xfafafb00, 0x04fffb00, 0xfafffb00, 0x0004fb00, 0xfffafb00, 0x0a09fb00, 0xf5f5fb00,
+ 0x0f04fb00, 0xf0fafb00, 0x00000005, 0x05050005, 0xfafb0005, 0x05000005, 0xfb000005, 0x00050005,
+ 0xfffb0005, 0x0a0a0005, 0xf5f60005, 0x0f050005, 0xf0fb0005, 0xfffffffb, 0x0504fffb, 0xfafafffb,
+ 0x04fffffb, 0xfafffffb, 0x0004fffb, 0xfffafffb, 0x0a09fffb, 0xf5f5fffb, 0x0f04fffb, 0xf0fafffb,
+ 0x00000a0a, 0x05050a0a, 0xfafb0a0a, 0x05000a0a, 0xfb000a0a, 0x00050a0a, 0xfffb0a0a, 0x0a0a0a0a,
+ 0xf5f60a0a, 0x0f050a0a, 0xf0fb0a0a, 0xfffff5f6, 0x0504f5f6, 0xfafaf5f6, 0x04fff5f6, 0xfafff5f6,
+ 0x0004f5f6, 0xfffaf5f6, 0x0a09f5f6, 0xf5f5f5f6, 0x0f04f5f6, 0xf0faf5f6, 0x00000f05, 0x05050f05,
+ 0xfafb0f05, 0x05000f05, 0xfb000f05, 0x00050f05, 0xfffb0f05, 0x0a0a0f05, 0xf5f60f05, 0x0f050f05,
+ 0xf0fb0f05, 0xfffff0fb, 0x0504f0fb, 0xfafaf0fb, 0x04fff0fb, 0xfafff0fb, 0x0004f0fb, 0xfffaf0fb,
+ 0x0a09f0fb, 0xf5f5f0fb, 0x0f04f0fb, 0xf0faf0fb, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000606, 0xfffff9fa, 0x00000600, 0xfffffa00, 0x00000006, 0xfffffffa, 0x00000c0c,
+ 0xfffff3f4, 0x00000c06, 0xfffff3fa, 0x0000060c, 0xfffff9f4, 0x00000bf4, 0xfffff40c, 0x000011fa,
+ 0xffffee06, 0xfffffa12, 0x000005ee, 0x0000180c, 0xffffe7f4, 0x00000c18, 0xfffff3e8, 0x00001818,
+ 0xffffe7e8, 0x00001e00, 0xffffe200, 0x0000001e, 0xffffffe2, 0x000017ee, 0xffffe812, 0xffffee18,
+ 0x000011e8, 0x0000301e, 0xffffcfe2, 0x00001e30, 0xffffe1d0, 0x000023fa, 0xffffdc06, 0xfffffa24,
+ 0x000005dc, 0x0000300c, 0xffffcff4, 0x00000c30, 0xfffff3d0, 0x00003030, 0xffffcfd0, 0x00003600,
+ 0xffffca00, 0x00000036, 0xffffffca, 0x000023dc, 0xffffdc24, 0x00002fe8, 0xffffd018, 0xffffe830,
+ 0x000017d0, 0x00004e1e, 0xffffb1e2, 0x00001e4e, 0xffffe1b2, 0x00005436, 0xffffabca, 0x00003654,
+ 0xffffc9ac, 0x000041ee, 0xffffbe12, 0xffffee42, 0x000011be, 0x0000540c, 0xffffabf4, 0x00000c54,
+ 0xfffff3ac, 0x00005a5a, 0xffffa5a6, 0x00005ffa, 0xffffa006, 0xfffffa60, 0x000005a0, 0x000041ca,
+ 0xffffbe36, 0xffffca42, 0x000035be, 0x000059d6, 0xffffa62a, 0xffffd65a, 0x000029a6, 0x00007de2,
+ 0xffff821e, 0xffffe27e, 0x00001d82, 0x0000659a, 0xffff9a66, 0x00007dac, 0xffff8254, 0xffffac7e,
+ 0x00005382, 0x00002424, 0xffffdbdc, 0x00004242, 0xffffbdbe, 0x00000000, 0x06060000, 0xf9fa0000,
+ 0x06000000, 0xfa000000, 0x00060000, 0xfffa0000, 0x0c0c0000, 0xf3f40000, 0x0c060000, 0xf3fa0000,
+ 0x060c0000, 0x00000606, 0x06060606, 0xf9fa0606, 0x06000606, 0xfa000606, 0x00060606, 0xfffa0606,
+ 0x0c0c0606, 0xf3f40606, 0x0c060606, 0xf3fa0606, 0x060c0606, 0xfffff9fa, 0x0605f9fa, 0xf9f9f9fa,
+ 0x05fff9fa, 0xf9fff9fa, 0x0005f9fa, 0xfff9f9fa, 0x0c0bf9fa, 0xf3f3f9fa, 0x0c05f9fa, 0xf3f9f9fa,
+ 0x060bf9fa, 0x00000600, 0x06060600, 0xf9fa0600, 0x06000600, 0xfa000600, 0x00060600, 0xfffa0600,
+ 0x0c0c0600, 0xf3f40600, 0x0c060600, 0xf3fa0600, 0x060c0600, 0xfffffa00, 0x0605fa00, 0xf9f9fa00,
+ 0x05fffa00, 0xf9fffa00, 0x0005fa00, 0xfff9fa00, 0x0c0bfa00, 0xf3f3fa00, 0x0c05fa00, 0xf3f9fa00,
+ 0x060bfa00, 0x00000006, 0x06060006, 0xf9fa0006, 0x06000006, 0xfa000006, 0x00060006, 0xfffa0006,
+ 0x0c0c0006, 0xf3f40006, 0x0c060006, 0xf3fa0006, 0x060c0006, 0xfffffffa, 0x0605fffa, 0xf9f9fffa,
+ 0x05fffffa, 0xf9fffffa, 0x0005fffa, 0xfff9fffa, 0x0c0bfffa, 0xf3f3fffa, 0x0c05fffa, 0xf3f9fffa,
+ 0x060bfffa, 0x00000c0c, 0x06060c0c, 0xf9fa0c0c, 0x06000c0c, 0xfa000c0c, 0x00060c0c, 0xfffa0c0c,
+ 0x0c0c0c0c, 0xf3f40c0c, 0x0c060c0c, 0xf3fa0c0c, 0x060c0c0c, 0xfffff3f4, 0x0605f3f4, 0xf9f9f3f4,
+ 0x05fff3f4, 0xf9fff3f4, 0x0005f3f4, 0xfff9f3f4, 0x0c0bf3f4, 0xf3f3f3f4, 0x0c05f3f4, 0xf3f9f3f4,
+ 0x060bf3f4, 0x00000c06, 0x06060c06, 0xf9fa0c06, 0x06000c06, 0xfa000c06, 0x00060c06, 0xfffa0c06,
+ 0x0c0c0c06, 0xf3f40c06, 0x0c060c06, 0xf3fa0c06, 0x060c0c06, 0xfffff3fa, 0x0605f3fa, 0xf9f9f3fa,
+ 0x05fff3fa, 0xf9fff3fa, 0x0005f3fa, 0xfff9f3fa, 0x0c0bf3fa, 0xf3f3f3fa, 0x0c05f3fa, 0xf3f9f3fa,
+ 0x060bf3fa, 0x0000060c, 0x0606060c, 0xf9fa060c, 0x0600060c, 0xfa00060c, 0x0006060c, 0xfffa060c,
+ 0x0c0c060c, 0xf3f4060c, 0x0c06060c, 0xf3fa060c, 0x060c060c, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000707, 0xfffff8f9, 0x00000700, 0xfffff900, 0x00000007, 0xfffffff9, 0x00000e0e,
+ 0xfffff1f2, 0x00001507, 0xffffeaf9, 0x00000715, 0xfffff8eb, 0x00000df2, 0xfffff20e, 0x000014f9,
+ 0xffffeb07, 0xfffff915, 0x000006eb, 0x00001c0e, 0xffffe3f2, 0x00000e1c, 0xfffff1e4, 0x00001c1c,
+ 0xffffe3e4, 0x00002300, 0xffffdd00, 0x00000023, 0xffffffdd, 0x00001beb, 0xffffe415, 0xffffeb1c,
+ 0x000014e4, 0x00003823, 0xffffc7dd, 0x00002338, 0xffffdcc8, 0x000029f2, 0xffffd60e, 0xfffff22a,
+ 0x00000dd6, 0x0000380e, 0xffffc7f2, 0x00000e38, 0xfffff1c8, 0x00003838, 0xffffc7c8, 0x00003f00,
+ 0xffffc100, 0x0000003f, 0xffffffc1, 0x000029d6, 0xffffd62a, 0x000037e4, 0xffffc81c, 0xffffe438,
+ 0x00001bc8, 0x00005b23, 0xffffa4dd, 0x0000235b, 0xffffdca5, 0x0000623f, 0xffff9dc1, 0x00003f62,
+ 0xffffc09e, 0x00004ceb, 0xffffb315, 0xffffeb4d, 0x000014b3, 0x0000620e, 0xffff9df2, 0x00000e62,
+ 0xfffff19e, 0x00006969, 0xffff9697, 0x000076f9, 0xffff8907, 0xfffff977, 0x00000689, 0x00004cc1,
+ 0xffffb33f, 0xffffc14d, 0x00003eb3, 0x000068cf, 0xffff9731, 0xffffcf69, 0x00003097, 0x00007689,
+ 0xffff8977, 0x00002a2a, 0xffffd5d6, 0x00004d4d, 0xffffb2b3, 0x00000000, 0x07070000, 0xf8f90000,
+ 0x07000000, 0xf9000000, 0x00070000, 0xfff90000, 0x0e0e0000, 0xf1f20000, 0x15070000, 0xeaf90000,
+ 0x07150000, 0x00000707, 0x07070707, 0xf8f90707, 0x07000707, 0xf9000707, 0x00070707, 0xfff90707,
+ 0x0e0e0707, 0xf1f20707, 0x15070707, 0xeaf90707, 0x07150707, 0xfffff8f9, 0x0706f8f9, 0xf8f8f8f9,
+ 0x06fff8f9, 0xf8fff8f9, 0x0006f8f9, 0xfff8f8f9, 0x0e0df8f9, 0xf1f1f8f9, 0x1506f8f9, 0xeaf8f8f9,
+ 0x0714f8f9, 0x00000700, 0x07070700, 0xf8f90700, 0x07000700, 0xf9000700, 0x00070700, 0xfff90700,
+ 0x0e0e0700, 0xf1f20700, 0x15070700, 0xeaf90700, 0x07150700, 0xfffff900, 0x0706f900, 0xf8f8f900,
+ 0x06fff900, 0xf8fff900, 0x0006f900, 0xfff8f900, 0x0e0df900, 0xf1f1f900, 0x1506f900, 0xeaf8f900,
+ 0x0714f900, 0x00000007, 0x07070007, 0xf8f90007, 0x07000007, 0xf9000007, 0x00070007, 0xfff90007,
+ 0x0e0e0007, 0xf1f20007, 0x15070007, 0xeaf90007, 0x07150007, 0xfffffff9, 0x0706fff9, 0xf8f8fff9,
+ 0x06fffff9, 0xf8fffff9, 0x0006fff9, 0xfff8fff9, 0x0e0dfff9, 0xf1f1fff9, 0x1506fff9, 0xeaf8fff9,
+ 0x0714fff9, 0x00000e0e, 0x07070e0e, 0xf8f90e0e, 0x07000e0e, 0xf9000e0e, 0x00070e0e, 0xfff90e0e,
+ 0x0e0e0e0e, 0xf1f20e0e, 0x15070e0e, 0xeaf90e0e, 0x07150e0e, 0xfffff1f2, 0x0706f1f2, 0xf8f8f1f2,
+ 0x06fff1f2, 0xf8fff1f2, 0x0006f1f2, 0xfff8f1f2, 0x0e0df1f2, 0xf1f1f1f2, 0x1506f1f2, 0xeaf8f1f2,
+ 0x0714f1f2, 0x00001507, 0x07071507, 0xf8f91507, 0x07001507, 0xf9001507, 0x00071507, 0xfff91507,
+ 0x0e0e1507, 0xf1f21507, 0x15071507, 0xeaf91507, 0x07151507, 0xffffeaf9, 0x0706eaf9, 0xf8f8eaf9,
+ 0x06ffeaf9, 0xf8ffeaf9, 0x0006eaf9, 0xfff8eaf9, 0x0e0deaf9, 0xf1f1eaf9, 0x1506eaf9, 0xeaf8eaf9,
+ 0x0714eaf9, 0x00000715, 0x07070715, 0xf8f90715, 0x07000715, 0xf9000715, 0x00070715, 0xfff90715,
+ 0x0e0e0715, 0xf1f20715, 0x15070715, 0xeaf90715, 0x07150715, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000808, 0xfffff7f8, 0x00000800, 0xfffff800, 0x00000008, 0xfffffff8, 0x00001010,
+ 0xffffeff0, 0x00001008, 0xffffeff8, 0x00000810, 0xfffff7f0, 0x00000ff0, 0xfffff010, 0x000017f8,
+ 0xffffe808, 0xfffff818, 0x000007e8, 0x00002010, 0xffffdff0, 0x00001020, 0xffffefe0, 0x00002020,
+ 0xffffdfe0, 0x00002800, 0xffffd800, 0x00000028, 0xffffffd8, 0x00001fe8, 0xffffe018, 0xffffe820,
+ 0x000017e0, 0x00004028, 0xffffbfd8, 0x00002840, 0xffffd7c0, 0x00002ff0, 0xffffd010, 0xfffff030,
+ 0x00000fd0, 0x00004010, 0xffffbff0, 0x00001040, 0xffffefc0, 0x00004040, 0xffffbfc0, 0x00004800,
+ 0xffffb800, 0x00000048, 0xffffffb8, 0x00002fd0, 0xffffd030, 0x00003fe0, 0xffffc020, 0xffffe040,
+ 0x00001fc0, 0x00006828, 0xffff97d8, 0x00002868, 0xffffd798, 0x00007048, 0xffff8fb8, 0x00004870,
+ 0xffffb790, 0x000057e8, 0xffffa818, 0xffffe858, 0x000017a8, 0x00007010, 0xffff8ff0, 0x00001070,
+ 0xffffef90, 0x00007878, 0xffff8788, 0x000057b8, 0xffffa848, 0xffffb858, 0x000047a8, 0x000077c8,
+ 0xffff8838, 0xffffc878, 0x00003788, 0x00003030, 0xffffcfd0, 0x00005858, 0xffffa7a8, 0x00000000,
+ 0x08080000, 0xf7f80000, 0x08000000, 0xf8000000, 0x00080000, 0xfff80000, 0x10100000, 0xeff00000,
+ 0x10080000, 0xeff80000, 0x08100000, 0x00000808, 0x08080808, 0xf7f80808, 0x08000808, 0xf8000808,
+ 0x00080808, 0xfff80808, 0x10100808, 0xeff00808, 0x10080808, 0xeff80808, 0x08100808, 0xfffff7f8,
+ 0x0807f7f8, 0xf7f7f7f8, 0x07fff7f8, 0xf7fff7f8, 0x0007f7f8, 0xfff7f7f8, 0x100ff7f8, 0xefeff7f8,
+ 0x1007f7f8, 0xeff7f7f8, 0x080ff7f8, 0x00000800, 0x08080800, 0xf7f80800, 0x08000800, 0xf8000800,
+ 0x00080800, 0xfff80800, 0x10100800, 0xeff00800, 0x10080800, 0xeff80800, 0x08100800, 0xfffff800,
+ 0x0807f800, 0xf7f7f800, 0x07fff800, 0xf7fff800, 0x0007f800, 0xfff7f800, 0x100ff800, 0xefeff800,
+ 0x1007f800, 0xeff7f800, 0x080ff800, 0x00000008, 0x08080008, 0xf7f80008, 0x08000008, 0xf8000008,
+ 0x00080008, 0xfff80008, 0x10100008, 0xeff00008, 0x10080008, 0xeff80008, 0x08100008, 0xfffffff8,
+ 0x0807fff8, 0xf7f7fff8, 0x07fffff8, 0xf7fffff8, 0x0007fff8, 0xfff7fff8, 0x100ffff8, 0xefeffff8,
+ 0x1007fff8, 0xeff7fff8, 0x080ffff8, 0x00001010, 0x08081010, 0xf7f81010, 0x08001010, 0xf8001010,
+ 0x00081010, 0xfff81010, 0x10101010, 0xeff01010, 0x10081010, 0xeff81010, 0x08101010, 0xffffeff0,
+ 0x0807eff0, 0xf7f7eff0, 0x07ffeff0, 0xf7ffeff0, 0x0007eff0, 0xfff7eff0, 0x100feff0, 0xefefeff0,
+ 0x1007eff0, 0xeff7eff0, 0x080feff0, 0x00001008, 0x08081008, 0xf7f81008, 0x08001008, 0xf8001008,
+ 0x00081008, 0xfff81008, 0x10101008, 0xeff01008, 0x10081008, 0xeff81008, 0x08101008, 0xffffeff8,
+ 0x0807eff8, 0xf7f7eff8, 0x07ffeff8, 0xf7ffeff8, 0x0007eff8, 0xfff7eff8, 0x100feff8, 0xefefeff8,
+ 0x1007eff8, 0xeff7eff8, 0x080feff8, 0x00000810, 0x08080810, 0xf7f80810, 0x08000810, 0xf8000810,
+ 0x00080810, 0xfff80810, 0x10100810, 0xeff00810, 0x10080810, 0xeff80810, 0x08100810, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000909, 0xfffff6f7, 0x00000900, 0xfffff700, 0x00000009, 0xfffffff7, 0x00001212,
+ 0xffffedee, 0x00001b09, 0xffffe4f7, 0x0000091b, 0xfffff6e5, 0x000011ee, 0xffffee12, 0x00001af7,
+ 0xffffe509, 0xfffff71b, 0x000008e5, 0x00002412, 0xffffdbee, 0x00001224, 0xffffeddc, 0x00002424,
+ 0xffffdbdc, 0x00002d00, 0xffffd300, 0x0000002d, 0xffffffd3, 0x000023e5, 0xffffdc1b, 0xffffe524,
+ 0x00001adc, 0x0000482d, 0xffffb7d3, 0x00002d48, 0xffffd2b8, 0x000035ee, 0xffffca12, 0xffffee36,
+ 0x000011ca, 0x00004812, 0xffffb7ee, 0x00001248, 0xffffedb8, 0x00004848, 0xffffb7b8, 0x00005100,
+ 0xffffaf00, 0x00000051, 0xffffffaf, 0x000035ca, 0xffffca36, 0x000047dc, 0xffffb824, 0xffffdc48,
+ 0x000023b8, 0x0000752d, 0xffff8ad3, 0x00002d75, 0xffffd28b, 0x00007e51, 0xffff81af, 0x0000517e,
+ 0xffffae82, 0x000062e5, 0xffff9d1b, 0xffffe563, 0x00001a9d, 0x000062af, 0xffff9d51, 0xffffaf63,
+ 0x0000509d, 0x00003636, 0xffffc9ca, 0x00006c6c, 0xffff9394, 0x00000000, 0x09090000, 0xf6f70000,
+ 0x09000000, 0xf7000000, 0x00090000, 0xfff70000, 0x12120000, 0xedee0000, 0x1b090000, 0xe4f70000,
+ 0x091b0000, 0xf6e50000, 0x00000909, 0x09090909, 0xf6f70909, 0x09000909, 0xf7000909, 0x00090909,
+ 0xfff70909, 0x12120909, 0xedee0909, 0x1b090909, 0xe4f70909, 0x091b0909, 0xf6e50909, 0xfffff6f7,
+ 0x0908f6f7, 0xf6f6f6f7, 0x08fff6f7, 0xf6fff6f7, 0x0008f6f7, 0xfff6f6f7, 0x1211f6f7, 0xededf6f7,
+ 0x1b08f6f7, 0xe4f6f6f7, 0x091af6f7, 0xf6e4f6f7, 0x00000900, 0x09090900, 0xf6f70900, 0x09000900,
+ 0xf7000900, 0x00090900, 0xfff70900, 0x12120900, 0xedee0900, 0x1b090900, 0xe4f70900, 0x091b0900,
+ 0xf6e50900, 0xfffff700, 0x0908f700, 0xf6f6f700, 0x08fff700, 0xf6fff700, 0x0008f700, 0xfff6f700,
+ 0x1211f700, 0xededf700, 0x1b08f700, 0xe4f6f700, 0x091af700, 0xf6e4f700, 0x00000009, 0x09090009,
+ 0xf6f70009, 0x09000009, 0xf7000009, 0x00090009, 0xfff70009, 0x12120009, 0xedee0009, 0x1b090009,
+ 0xe4f70009, 0x091b0009, 0xf6e50009, 0xfffffff7, 0x0908fff7, 0xf6f6fff7, 0x08fffff7, 0xf6fffff7,
+ 0x0008fff7, 0xfff6fff7, 0x1211fff7, 0xededfff7, 0x1b08fff7, 0xe4f6fff7, 0x091afff7, 0xf6e4fff7,
+ 0x00001212, 0x09091212, 0xf6f71212, 0x09001212, 0xf7001212, 0x00091212, 0xfff71212, 0x12121212,
+ 0xedee1212, 0x1b091212, 0xe4f71212, 0x091b1212, 0xf6e51212, 0xffffedee, 0x0908edee, 0xf6f6edee,
+ 0x08ffedee, 0xf6ffedee, 0x0008edee, 0xfff6edee, 0x1211edee, 0xedededee, 0x1b08edee, 0xe4f6edee,
+ 0x091aedee, 0xf6e4edee, 0x00001b09, 0x09091b09, 0xf6f71b09, 0x09001b09, 0xf7001b09, 0x00091b09,
+ 0xfff71b09, 0x12121b09, 0xedee1b09, 0x1b091b09, 0xe4f71b09, 0x091b1b09, 0xf6e51b09, 0xffffe4f7,
+ 0x0908e4f7, 0xf6f6e4f7, 0x08ffe4f7, 0xf6ffe4f7, 0x0008e4f7, 0xfff6e4f7, 0x1211e4f7, 0xedede4f7,
+ 0x1b08e4f7, 0xe4f6e4f7, 0x091ae4f7, 0xf6e4e4f7, 0x0000091b, 0x0909091b, 0xf6f7091b, 0x0900091b,
+ 0xf700091b, 0x0009091b, 0xfff7091b, 0x1212091b, 0xedee091b, 0x1b09091b, 0xe4f7091b, 0x091b091b,
+ 0xf6e5091b, 0xfffff6e5, 0x0908f6e5, 0xf6f6f6e5, 0x08fff6e5, 0xf6fff6e5, 0x0008f6e5, 0xfff6f6e5,
+ 0x1211f6e5, 0xededf6e5, 0x1b08f6e5, 0xe4f6f6e5, 0x091af6e5, 0xf6e4f6e5, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000202, 0xfffffdfe, 0x00000300, 0xfffffd00, 0x00000003, 0xfffffffd, 0x00000606,
+ 0xfffff9fa, 0x00000700, 0xfffff900, 0x00000007, 0xfffffff9, 0x000004fb, 0xfffffb05, 0xfffffb05,
+ 0x000004fb, 0x00000b06, 0xfffff4fa, 0x0000060b, 0xfffff9f5, 0x00000800, 0xfffff800, 0x00000008,
+ 0xfffffff8, 0x00000b0b, 0xfffff4f5, 0x00000c00, 0xfffff400, 0x0000000c, 0xfffffff4, 0x0000110c,
+ 0xffffeef4, 0x00000c11, 0xfffff3ef, 0x00001111, 0xffffeeef, 0x00001206, 0xffffedfa, 0x00000612,
+ 0xfffff9ee, 0x00000af8, 0xfffff508, 0xfffff80b, 0x000007f5, 0x00000f00, 0xfffff100, 0x0000000f,
+ 0xfffffff1, 0x00001400, 0xffffec00, 0x00000014, 0xffffffec, 0x00001912, 0xffffe6ee, 0x00001219,
+ 0xffffede7, 0x0000190b, 0xffffe6f5, 0x00000b19, 0xfffff4e7, 0x00001919, 0xffffe6e7, 0x00000df2,
+ 0xfffff20e, 0xfffff20e, 0x00000df2, 0x00001a00, 0xffffe600, 0x0000001a, 0xffffffe6, 0x000011f5,
+ 0xffffee0b, 0xfffff512, 0x00000aee, 0x000015f9, 0xffffea07, 0xfffff916, 0x000006ea, 0x0000221a,
+ 0xffffdde6, 0x00001a22, 0xffffe5de, 0x00002212, 0xffffddee, 0x00001222, 0xffffedde, 0x00002222,
+ 0xffffddde, 0x0000230b, 0xffffdcf5, 0x00000b23, 0xfffff4dd, 0x00001d00, 0xffffe300, 0x0000001d,
+ 0xffffffe3, 0x000015ed, 0xffffea13, 0xffffed16, 0x000012ea, 0x000019f1, 0xffffe60f, 0xfffff11a,
+ 0x00000ee6, 0x00002500, 0xffffdb00, 0x00000025, 0xffffffdb, 0x00002c1b, 0xffffd3e5, 0x00001b2c,
+ 0xffffe4d4, 0x00002c24, 0xffffd3dc, 0x0000242c, 0xffffdbd4, 0x00002c12, 0xffffd3ee, 0x0000122c,
+ 0xffffedd4, 0x000020f6, 0xffffdf0a, 0xfffff621, 0x000009df, 0x00002d2d, 0xffffd2d3, 0x00000000,
+ 0x00000000, 0x00000202, 0xfffffdfe, 0x00000300, 0xfffffd00, 0x00000003, 0xfffffffd, 0x00000606,
+ 0xfffff9fa, 0x00000700, 0xfffff900, 0x02020000, 0x02020202, 0x0201fdfe, 0x02020300, 0x0201fd00,
+ 0x02020003, 0x0201fffd, 0x02020606, 0x0201f9fa, 0x02020700, 0x0201f900, 0xfdfe0000, 0xfdfe0202,
+ 0xfdfdfdfe, 0xfdfe0300, 0xfdfdfd00, 0xfdfe0003, 0xfdfdfffd, 0xfdfe0606, 0xfdfdf9fa, 0xfdfe0700,
+ 0xfdfdf900, 0x03000000, 0x03000202, 0x02fffdfe, 0x03000300, 0x02fffd00, 0x03000003, 0x02fffffd,
+ 0x03000606, 0x02fff9fa, 0x03000700, 0x02fff900, 0xfd000000, 0xfd000202, 0xfcfffdfe, 0xfd000300,
+ 0xfcfffd00, 0xfd000003, 0xfcfffffd, 0xfd000606, 0xfcfff9fa, 0xfd000700, 0xfcfff900, 0x00030000,
+ 0x00030202, 0x0002fdfe, 0x00030300, 0x0002fd00, 0x00030003, 0x0002fffd, 0x00030606, 0x0002f9fa,
+ 0x00030700, 0x0002f900, 0xfffd0000, 0xfffd0202, 0xfffcfdfe, 0xfffd0300, 0xfffcfd00, 0xfffd0003,
+ 0xfffcfffd, 0xfffd0606, 0xfffcf9fa, 0xfffd0700, 0xfffcf900, 0x06060000, 0x06060202, 0x0605fdfe,
+ 0x06060300, 0x0605fd00, 0x06060003, 0x0605fffd, 0x06060606, 0x0605f9fa, 0x06060700, 0x0605f900,
+ 0xf9fa0000, 0xf9fa0202, 0xf9f9fdfe, 0xf9fa0300, 0xf9f9fd00, 0xf9fa0003, 0xf9f9fffd, 0xf9fa0606,
+ 0xf9f9f9fa, 0xf9fa0700, 0xf9f9f900, 0x07000000, 0x07000202, 0x06fffdfe, 0x07000300, 0x06fffd00,
+ 0x07000003, 0x06fffffd, 0x07000606, 0x06fff9fa, 0x07000700, 0x06fff900, 0xf9000000, 0xf9000202,
+ 0xf8fffdfe, 0xf9000300, 0xf8fffd00, 0xf9000003, 0xf8fffffd, 0xf9000606, 0xf8fff9fa, 0xf9000700,
+ 0xf8fff900, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000200, 0xfffffe00, 0x00000002, 0xfffffffe, 0x00000202, 0xfffffdfe, 0x00000606,
+ 0xfffff9fa, 0x00000600, 0xfffffa00, 0x00000006, 0xfffffffa, 0x000003fc, 0xfffffc04, 0xfffffa0a,
+ 0x000005f6, 0xfffff400, 0x00000c00, 0xfffff3fa, 0xfffff406, 0x00000bfa, 0x00000c06, 0xfffffff2,
+ 0x0000000e, 0x00000c0c, 0xfffff3f4, 0xffffee00, 0x00001200, 0xfffff40e, 0x00000bf2, 0xfffff9ee,
+ 0xfffffa12, 0x000005ee, 0x00000612, 0xffffedf6, 0xffffee0a, 0x000011f6, 0x0000120a, 0xffffffea,
+ 0x00000016, 0xffffe800, 0x00001800, 0xfffff3ea, 0xfffff416, 0x00000bea, 0x00000c16, 0xffffe7f8,
+ 0xffffe808, 0x000017f8, 0x00001808, 0xfffff9e6, 0xfffffa1a, 0x000005e6, 0x0000061a, 0xffffffe4,
+ 0x0000001c, 0x00001414, 0xffffebec, 0xffffe5f2, 0x00001a0e, 0xfffff3e2, 0x00000c1e, 0xffffdff6,
+ 0x0000200a, 0xffffdfee, 0x00002012, 0xffffe5e6, 0x00001a1a, 0xffffebde, 0x00001422, 0xfffff3da,
+ 0x00000c26, 0xffffdfe0, 0x00002020, 0x00002020, 0xffffd7ea, 0xffffddde, 0x00002222, 0x00000000,
+ 0x00000200, 0xfffffe00, 0x00000002, 0xfffffffe, 0x00000202, 0xfffffdfe, 0x00000606, 0xfffff9fa,
+ 0x00000600, 0xfffffa00, 0x00000006, 0xfffffffa, 0x02000000, 0x02000200, 0x01fffe00, 0x02000002,
+ 0x01fffffe, 0x02000202, 0x01fffdfe, 0x02000606, 0x01fff9fa, 0x02000600, 0x01fffa00, 0x02000006,
+ 0x01fffffa, 0xfe000000, 0xfe000200, 0xfdfffe00, 0xfe000002, 0xfdfffffe, 0xfe000202, 0xfdfffdfe,
+ 0xfe000606, 0xfdfff9fa, 0xfe000600, 0xfdfffa00, 0xfe000006, 0xfdfffffa, 0x00020000, 0x00020200,
+ 0x0001fe00, 0x00020002, 0x0001fffe, 0x00020202, 0x0001fdfe, 0x00020606, 0x0001f9fa, 0x00020600,
+ 0x0001fa00, 0x00020006, 0x0001fffa, 0xfffe0000, 0xfffe0200, 0xfffdfe00, 0xfffe0002, 0xfffdfffe,
+ 0xfffe0202, 0xfffdfdfe, 0xfffe0606, 0xfffdf9fa, 0xfffe0600, 0xfffdfa00, 0xfffe0006, 0xfffdfffa,
+ 0x02020000, 0x02020200, 0x0201fe00, 0x02020002, 0x0201fffe, 0x02020202, 0x0201fdfe, 0x02020606,
+ 0x0201f9fa, 0x02020600, 0x0201fa00, 0x02020006, 0x0201fffa, 0xfdfe0000, 0xfdfe0200, 0xfdfdfe00,
+ 0xfdfe0002, 0xfdfdfffe, 0xfdfe0202, 0xfdfdfdfe, 0xfdfe0606, 0xfdfdf9fa, 0xfdfe0600, 0xfdfdfa00,
+ 0xfdfe0006, 0xfdfdfffa, 0x06060000, 0x06060200, 0x0605fe00, 0x06060002, 0x0605fffe, 0x06060202,
+ 0x0605fdfe, 0x06060606, 0x0605f9fa, 0x06060600, 0x0605fa00, 0x06060006, 0x0605fffa, 0xf9fa0000,
+ 0xf9fa0200, 0xf9f9fe00, 0xf9fa0002, 0xf9f9fffe, 0xf9fa0202, 0xf9f9fdfe, 0xf9fa0606, 0xf9f9f9fa,
+ 0xf9fa0600, 0xf9f9fa00, 0xf9fa0006, 0xf9f9fffa, 0x06000000, 0x06000200, 0x05fffe00, 0x06000002,
+ 0x05fffffe, 0x06000202, 0x05fffdfe, 0x06000606, 0x05fff9fa, 0x06000600, 0x05fffa00, 0x06000006,
+ 0x05fffffa, 0xfa000000, 0xfa000200, 0xf9fffe00, 0xfa000002, 0xf9fffffe, 0xfa000202, 0xf9fffdfe,
+ 0xfa000606, 0xf9fff9fa, 0xfa000600, 0xf9fffa00, 0xfa000006, 0xf9fffffa, 0x00060000, 0x00060200,
+ 0x0005fe00, 0x00060002, 0x0005fffe, 0x00060202, 0x0005fdfe, 0x00060606, 0x0005f9fa, 0x00060600,
+ 0x0005fa00, 0x00060006, 0x0005fffa, 0xfffa0000, 0xfffa0200, 0xfff9fe00, 0xfffa0002, 0xfff9fffe,
+ 0xfffa0202, 0xfff9fdfe, 0xfffa0606, 0xfff9f9fa, 0xfffa0600, 0xfff9fa00, 0xfffa0006, 0xfff9fffa,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000200, 0xfffffe00, 0x00000002, 0xfffffffe, 0x00000404, 0xfffffbfc, 0x00000a0a,
+ 0xfffff5f6, 0x00000a00, 0xfffff600, 0x0000000a, 0xfffffff6, 0x000005fa, 0xfffffa06, 0xfffff80e,
+ 0x000007f2, 0xffffffee, 0x00000012, 0xfffff00a, 0x00000ff6, 0xffffe800, 0x00001800, 0xfffff7e8,
+ 0xfffff818, 0x000007e8, 0x00000818, 0x00001212, 0xffffedee, 0xfffff014, 0x00000fec, 0xffffe5f2,
+ 0xffffe60e, 0x000019f2, 0x00001a0e, 0xffffffe2, 0x0000001e, 0xffffde00, 0x00002200, 0xfffff7de,
+ 0xfffff822, 0x000007de, 0x00000822, 0xffffede2, 0xffffee1e, 0x000011e2, 0x0000121e, 0xffffddf6,
+ 0xffffde0a, 0x000021f6, 0x0000220a, 0xffffddec, 0x00002214, 0xffffffd8, 0x00000028, 0x00001e1e,
+ 0xffffe1e2, 0xffffedd8, 0x00001228, 0xffffd400, 0x00002c00, 0xffffd3f0, 0x00002c10, 0xffffdbdc,
+ 0xffffdbdc, 0x00002424, 0xffffd3e6, 0x00002c1a, 0xffffe5d2, 0x00001a2e, 0xffffedcc, 0x00001234,
+ 0xffffc9ec, 0xffffd3d4, 0x00002c2c, 0xffffc9e0, 0xffffd1d2, 0xffffd1d2, 0x00002e2e, 0x00000000,
+ 0x00000200, 0xfffffe00, 0x00000002, 0xfffffffe, 0x00000404, 0xfffffbfc, 0x00000a0a, 0xfffff5f6,
+ 0x00000a00, 0xfffff600, 0x0000000a, 0xfffffff6, 0x02000000, 0x02000200, 0x01fffe00, 0x02000002,
+ 0x01fffffe, 0x02000404, 0x01fffbfc, 0x02000a0a, 0x01fff5f6, 0x02000a00, 0x01fff600, 0x0200000a,
+ 0x01fffff6, 0xfe000000, 0xfe000200, 0xfdfffe00, 0xfe000002, 0xfdfffffe, 0xfe000404, 0xfdfffbfc,
+ 0xfe000a0a, 0xfdfff5f6, 0xfe000a00, 0xfdfff600, 0xfe00000a, 0xfdfffff6, 0x00020000, 0x00020200,
+ 0x0001fe00, 0x00020002, 0x0001fffe, 0x00020404, 0x0001fbfc, 0x00020a0a, 0x0001f5f6, 0x00020a00,
+ 0x0001f600, 0x0002000a, 0x0001fff6, 0xfffe0000, 0xfffe0200, 0xfffdfe00, 0xfffe0002, 0xfffdfffe,
+ 0xfffe0404, 0xfffdfbfc, 0xfffe0a0a, 0xfffdf5f6, 0xfffe0a00, 0xfffdf600, 0xfffe000a, 0xfffdfff6,
+ 0x04040000, 0x04040200, 0x0403fe00, 0x04040002, 0x0403fffe, 0x04040404, 0x0403fbfc, 0x04040a0a,
+ 0x0403f5f6, 0x04040a00, 0x0403f600, 0x0404000a, 0x0403fff6, 0xfbfc0000, 0xfbfc0200, 0xfbfbfe00,
+ 0xfbfc0002, 0xfbfbfffe, 0xfbfc0404, 0xfbfbfbfc, 0xfbfc0a0a, 0xfbfbf5f6, 0xfbfc0a00, 0xfbfbf600,
+ 0xfbfc000a, 0xfbfbfff6, 0x0a0a0000, 0x0a0a0200, 0x0a09fe00, 0x0a0a0002, 0x0a09fffe, 0x0a0a0404,
+ 0x0a09fbfc, 0x0a0a0a0a, 0x0a09f5f6, 0x0a0a0a00, 0x0a09f600, 0x0a0a000a, 0x0a09fff6, 0xf5f60000,
+ 0xf5f60200, 0xf5f5fe00, 0xf5f60002, 0xf5f5fffe, 0xf5f60404, 0xf5f5fbfc, 0xf5f60a0a, 0xf5f5f5f6,
+ 0xf5f60a00, 0xf5f5f600, 0xf5f6000a, 0xf5f5fff6, 0x0a000000, 0x0a000200, 0x09fffe00, 0x0a000002,
+ 0x09fffffe, 0x0a000404, 0x09fffbfc, 0x0a000a0a, 0x09fff5f6, 0x0a000a00, 0x09fff600, 0x0a00000a,
+ 0x09fffff6, 0xf6000000, 0xf6000200, 0xf5fffe00, 0xf6000002, 0xf5fffffe, 0xf6000404, 0xf5fffbfc,
+ 0xf6000a0a, 0xf5fff5f6, 0xf6000a00, 0xf5fff600, 0xf600000a, 0xf5fffff6, 0x000a0000, 0x000a0200,
+ 0x0009fe00, 0x000a0002, 0x0009fffe, 0x000a0404, 0x0009fbfc, 0x000a0a0a, 0x0009f5f6, 0x000a0a00,
+ 0x0009f600, 0x000a000a, 0x0009fff6, 0xfff60000, 0xfff60200, 0xfff5fe00, 0xfff60002, 0xfff5fffe,
+ 0xfff60404, 0xfff5fbfc, 0xfff60a0a, 0xfff5f5f6, 0xfff60a00, 0xfff5f600, 0xfff6000a, 0xfff5fff6,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000400, 0xfffffc00, 0x00000004, 0xfffffffc, 0x00000404, 0xfffffbfc, 0x00000c0c,
+ 0xfffff3f4, 0x00000c00, 0xfffff400, 0x0000000c, 0xfffffff4, 0x000007f8, 0xfffff808, 0xfffff008,
+ 0x00000ff8, 0xffffe800, 0x00001800, 0xfffff7e8, 0xfffff818, 0x000007e8, 0x00000818, 0xfffff014,
+ 0x00000fec, 0xffffffe4, 0x0000001c, 0xffffe7f0, 0xffffe810, 0x000017f0, 0x00001810, 0xffffe000,
+ 0x00002000, 0xffffefe4, 0xfffff01c, 0x00000fe4, 0x0000101c, 0xffffdff8, 0xffffe008, 0xfffff7e0,
+ 0xfffff820, 0x000007e0, 0x00000820, 0x00001ff8, 0x00002008, 0x00001818, 0xffffe7e8, 0xffffe818,
+ 0x000017e8, 0xffffdfec, 0x00002014, 0xffffffd8, 0x00000028, 0xffffefd8, 0x00001028, 0xffffd400,
+ 0xffffd400, 0xffffffd4, 0x0000002c, 0x00002c00, 0x00002c00, 0xffffdfe0, 0x00002020, 0xffffd3f0,
+ 0x00002c10, 0xffffd3e8, 0xffffe7d4, 0x0000182c, 0x00002c18, 0xffffefd0, 0x00001030, 0xffffdbdc,
+ 0xffffdbdc, 0x00002424, 0x00002424, 0xffffcbec, 0x00002828, 0xffffd7d8, 0xffffcbe0, 0x00000000,
+ 0x00000400, 0xfffffc00, 0x00000004, 0xfffffffc, 0x00000404, 0xfffffbfc, 0x00000c0c, 0xfffff3f4,
+ 0x00000c00, 0xfffff400, 0x0000000c, 0xfffffff4, 0x04000000, 0x04000400, 0x03fffc00, 0x04000004,
+ 0x03fffffc, 0x04000404, 0x03fffbfc, 0x04000c0c, 0x03fff3f4, 0x04000c00, 0x03fff400, 0x0400000c,
+ 0x03fffff4, 0xfc000000, 0xfc000400, 0xfbfffc00, 0xfc000004, 0xfbfffffc, 0xfc000404, 0xfbfffbfc,
+ 0xfc000c0c, 0xfbfff3f4, 0xfc000c00, 0xfbfff400, 0xfc00000c, 0xfbfffff4, 0x00040000, 0x00040400,
+ 0x0003fc00, 0x00040004, 0x0003fffc, 0x00040404, 0x0003fbfc, 0x00040c0c, 0x0003f3f4, 0x00040c00,
+ 0x0003f400, 0x0004000c, 0x0003fff4, 0xfffc0000, 0xfffc0400, 0xfffbfc00, 0xfffc0004, 0xfffbfffc,
+ 0xfffc0404, 0xfffbfbfc, 0xfffc0c0c, 0xfffbf3f4, 0xfffc0c00, 0xfffbf400, 0xfffc000c, 0xfffbfff4,
+ 0x04040000, 0x04040400, 0x0403fc00, 0x04040004, 0x0403fffc, 0x04040404, 0x0403fbfc, 0x04040c0c,
+ 0x0403f3f4, 0x04040c00, 0x0403f400, 0x0404000c, 0x0403fff4, 0xfbfc0000, 0xfbfc0400, 0xfbfbfc00,
+ 0xfbfc0004, 0xfbfbfffc, 0xfbfc0404, 0xfbfbfbfc, 0xfbfc0c0c, 0xfbfbf3f4, 0xfbfc0c00, 0xfbfbf400,
+ 0xfbfc000c, 0xfbfbfff4, 0x0c0c0000, 0x0c0c0400, 0x0c0bfc00, 0x0c0c0004, 0x0c0bfffc, 0x0c0c0404,
+ 0x0c0bfbfc, 0x0c0c0c0c, 0x0c0bf3f4, 0x0c0c0c00, 0x0c0bf400, 0x0c0c000c, 0x0c0bfff4, 0xf3f40000,
+ 0xf3f40400, 0xf3f3fc00, 0xf3f40004, 0xf3f3fffc, 0xf3f40404, 0xf3f3fbfc, 0xf3f40c0c, 0xf3f3f3f4,
+ 0xf3f40c00, 0xf3f3f400, 0xf3f4000c, 0xf3f3fff4, 0x0c000000, 0x0c000400, 0x0bfffc00, 0x0c000004,
+ 0x0bfffffc, 0x0c000404, 0x0bfffbfc, 0x0c000c0c, 0x0bfff3f4, 0x0c000c00, 0x0bfff400, 0x0c00000c,
+ 0x0bfffff4, 0xf4000000, 0xf4000400, 0xf3fffc00, 0xf4000004, 0xf3fffffc, 0xf4000404, 0xf3fffbfc,
+ 0xf4000c0c, 0xf3fff3f4, 0xf4000c00, 0xf3fff400, 0xf400000c, 0xf3fffff4, 0x000c0000, 0x000c0400,
+ 0x000bfc00, 0x000c0004, 0x000bfffc, 0x000c0404, 0x000bfbfc, 0x000c0c0c, 0x000bf3f4, 0x000c0c00,
+ 0x000bf400, 0x000c000c, 0x000bfff4, 0xfff40000, 0xfff40400, 0xfff3fc00, 0xfff40004, 0xfff3fffc,
+ 0xfff40404, 0xfff3fbfc, 0xfff40c0c, 0xfff3f3f4, 0xfff40c00, 0xfff3f400, 0xfff4000c, 0xfff3fff4,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000202, 0xfffffdfe, 0x00000606, 0xfffff9fa, 0x00000c0c, 0xfffff3f4, 0x00001414,
+ 0xffffebec, 0x00002020, 0xffffdfe0, 0x00002e2e, 0xffffd1d2, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000202, 0xfffffdfe, 0x00000606, 0xfffff9fa, 0x00000c0c, 0xfffff3f4, 0x00001414, 0xffffebec,
+ 0x00002020, 0xffffdfe0, 0x00002e2e, 0xffffd1d2, 0x02020000, 0x02020202, 0x0201fdfe, 0x02020606,
+ 0x0201f9fa, 0x02020c0c, 0x0201f3f4, 0x02021414, 0x0201ebec, 0x02022020, 0x0201dfe0, 0x02022e2e,
+ 0x0201d1d2, 0xfdfe0000, 0xfdfe0202, 0xfdfdfdfe, 0xfdfe0606, 0xfdfdf9fa, 0xfdfe0c0c, 0xfdfdf3f4,
+ 0xfdfe1414, 0xfdfdebec, 0xfdfe2020, 0xfdfddfe0, 0xfdfe2e2e, 0xfdfdd1d2, 0x06060000, 0x06060202,
+ 0x0605fdfe, 0x06060606, 0x0605f9fa, 0x06060c0c, 0x0605f3f4, 0x06061414, 0x0605ebec, 0x06062020,
+ 0x0605dfe0, 0x06062e2e, 0x0605d1d2, 0xf9fa0000, 0xf9fa0202, 0xf9f9fdfe, 0xf9fa0606, 0xf9f9f9fa,
+ 0xf9fa0c0c, 0xf9f9f3f4, 0xf9fa1414, 0xf9f9ebec, 0xf9fa2020, 0xf9f9dfe0, 0xf9fa2e2e, 0xf9f9d1d2,
+ 0x0c0c0000, 0x0c0c0202, 0x0c0bfdfe, 0x0c0c0606, 0x0c0bf9fa, 0x0c0c0c0c, 0x0c0bf3f4, 0x0c0c1414,
+ 0x0c0bebec, 0x0c0c2020, 0x0c0bdfe0, 0x0c0c2e2e, 0x0c0bd1d2, 0xf3f40000, 0xf3f40202, 0xf3f3fdfe,
+ 0xf3f40606, 0xf3f3f9fa, 0xf3f40c0c, 0xf3f3f3f4, 0xf3f41414, 0xf3f3ebec, 0xf3f42020, 0xf3f3dfe0,
+ 0xf3f42e2e, 0xf3f3d1d2, 0x14140000, 0x14140202, 0x1413fdfe, 0x14140606, 0x1413f9fa, 0x14140c0c,
+ 0x1413f3f4, 0x14141414, 0x1413ebec, 0x14142020, 0x1413dfe0, 0x14142e2e, 0x1413d1d2, 0xebec0000,
+ 0xebec0202, 0xebebfdfe, 0xebec0606, 0xebebf9fa, 0xebec0c0c, 0xebebf3f4, 0xebec1414, 0xebebebec,
+ 0xebec2020, 0xebebdfe0, 0xebec2e2e, 0xebebd1d2, 0x20200000, 0x20200202, 0x201ffdfe, 0x20200606,
+ 0x201ff9fa, 0x20200c0c, 0x201ff3f4, 0x20201414, 0x201febec, 0x20202020, 0x201fdfe0, 0x20202e2e,
+ 0x201fd1d2, 0xdfe00000, 0xdfe00202, 0xdfdffdfe, 0xdfe00606, 0xdfdff9fa, 0xdfe00c0c, 0xdfdff3f4,
+ 0xdfe01414, 0xdfdfebec, 0xdfe02020, 0xdfdfdfe0, 0xdfe02e2e, 0xdfdfd1d2, 0x2e2e0000, 0x2e2e0202,
+ 0x2e2dfdfe, 0x2e2e0606, 0x2e2df9fa, 0x2e2e0c0c, 0x2e2df3f4, 0x2e2e1414, 0x2e2debec, 0x2e2e2020,
+ 0x2e2ddfe0, 0x2e2e2e2e, 0x2e2dd1d2, 0xd1d20000, 0xd1d20202, 0xd1d1fdfe, 0xd1d20606, 0xd1d1f9fa,
+ 0xd1d20c0c, 0xd1d1f3f4, 0xd1d21414, 0xd1d1ebec, 0xd1d22020, 0xd1d1dfe0, 0xd1d22e2e, 0xd1d1d1d2,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000202, 0xfffffdfe, 0x00000606, 0xfffff9fa, 0x00000c0c, 0xfffff3f4, 0x00001414,
+ 0xffffebec, 0x00002020, 0xffffdfe0, 0x00002e2e, 0xffffd1d2, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000202, 0xfffffdfe, 0x00000606, 0xfffff9fa, 0x00000c0c, 0xfffff3f4, 0x00001414, 0xffffebec,
+ 0x00002020, 0xffffdfe0, 0x00002e2e, 0xffffd1d2, 0x02020000, 0x02020202, 0x0201fdfe, 0x02020606,
+ 0x0201f9fa, 0x02020c0c, 0x0201f3f4, 0x02021414, 0x0201ebec, 0x02022020, 0x0201dfe0, 0x02022e2e,
+ 0x0201d1d2, 0xfdfe0000, 0xfdfe0202, 0xfdfdfdfe, 0xfdfe0606, 0xfdfdf9fa, 0xfdfe0c0c, 0xfdfdf3f4,
+ 0xfdfe1414, 0xfdfdebec, 0xfdfe2020, 0xfdfddfe0, 0xfdfe2e2e, 0xfdfdd1d2, 0x06060000, 0x06060202,
+ 0x0605fdfe, 0x06060606, 0x0605f9fa, 0x06060c0c, 0x0605f3f4, 0x06061414, 0x0605ebec, 0x06062020,
+ 0x0605dfe0, 0x06062e2e, 0x0605d1d2, 0xf9fa0000, 0xf9fa0202, 0xf9f9fdfe, 0xf9fa0606, 0xf9f9f9fa,
+ 0xf9fa0c0c, 0xf9f9f3f4, 0xf9fa1414, 0xf9f9ebec, 0xf9fa2020, 0xf9f9dfe0, 0xf9fa2e2e, 0xf9f9d1d2,
+ 0x0c0c0000, 0x0c0c0202, 0x0c0bfdfe, 0x0c0c0606, 0x0c0bf9fa, 0x0c0c0c0c, 0x0c0bf3f4, 0x0c0c1414,
+ 0x0c0bebec, 0x0c0c2020, 0x0c0bdfe0, 0x0c0c2e2e, 0x0c0bd1d2, 0xf3f40000, 0xf3f40202, 0xf3f3fdfe,
+ 0xf3f40606, 0xf3f3f9fa, 0xf3f40c0c, 0xf3f3f3f4, 0xf3f41414, 0xf3f3ebec, 0xf3f42020, 0xf3f3dfe0,
+ 0xf3f42e2e, 0xf3f3d1d2, 0x14140000, 0x14140202, 0x1413fdfe, 0x14140606, 0x1413f9fa, 0x14140c0c,
+ 0x1413f3f4, 0x14141414, 0x1413ebec, 0x14142020, 0x1413dfe0, 0x14142e2e, 0x1413d1d2, 0xebec0000,
+ 0xebec0202, 0xebebfdfe, 0xebec0606, 0xebebf9fa, 0xebec0c0c, 0xebebf3f4, 0xebec1414, 0xebebebec,
+ 0xebec2020, 0xebebdfe0, 0xebec2e2e, 0xebebd1d2, 0x20200000, 0x20200202, 0x201ffdfe, 0x20200606,
+ 0x201ff9fa, 0x20200c0c, 0x201ff3f4, 0x20201414, 0x201febec, 0x20202020, 0x201fdfe0, 0x20202e2e,
+ 0x201fd1d2, 0xdfe00000, 0xdfe00202, 0xdfdffdfe, 0xdfe00606, 0xdfdff9fa, 0xdfe00c0c, 0xdfdff3f4,
+ 0xdfe01414, 0xdfdfebec, 0xdfe02020, 0xdfdfdfe0, 0xdfe02e2e, 0xdfdfd1d2, 0x2e2e0000, 0x2e2e0202,
+ 0x2e2dfdfe, 0x2e2e0606, 0x2e2df9fa, 0x2e2e0c0c, 0x2e2df3f4, 0x2e2e1414, 0x2e2debec, 0x2e2e2020,
+ 0x2e2ddfe0, 0x2e2e2e2e, 0x2e2dd1d2, 0xd1d20000, 0xd1d20202, 0xd1d1fdfe, 0xd1d20606, 0xd1d1f9fa,
+ 0xd1d20c0c, 0xd1d1f3f4, 0xd1d21414, 0xd1d1ebec, 0xd1d22020, 0xd1d1dfe0, 0xd1d22e2e, 0xd1d1d1d2,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000202, 0xfffffdfe, 0x00000606, 0xfffff9fa, 0x00000c0c, 0xfffff3f4, 0x00001414,
+ 0xffffebec, 0x00002020, 0xffffdfe0, 0x00002e2e, 0xffffd1d2, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000202, 0xfffffdfe, 0x00000606, 0xfffff9fa, 0x00000c0c, 0xfffff3f4, 0x00001414, 0xffffebec,
+ 0x00002020, 0xffffdfe0, 0x00002e2e, 0xffffd1d2, 0x02020000, 0x02020202, 0x0201fdfe, 0x02020606,
+ 0x0201f9fa, 0x02020c0c, 0x0201f3f4, 0x02021414, 0x0201ebec, 0x02022020, 0x0201dfe0, 0x02022e2e,
+ 0x0201d1d2, 0xfdfe0000, 0xfdfe0202, 0xfdfdfdfe, 0xfdfe0606, 0xfdfdf9fa, 0xfdfe0c0c, 0xfdfdf3f4,
+ 0xfdfe1414, 0xfdfdebec, 0xfdfe2020, 0xfdfddfe0, 0xfdfe2e2e, 0xfdfdd1d2, 0x06060000, 0x06060202,
+ 0x0605fdfe, 0x06060606, 0x0605f9fa, 0x06060c0c, 0x0605f3f4, 0x06061414, 0x0605ebec, 0x06062020,
+ 0x0605dfe0, 0x06062e2e, 0x0605d1d2, 0xf9fa0000, 0xf9fa0202, 0xf9f9fdfe, 0xf9fa0606, 0xf9f9f9fa,
+ 0xf9fa0c0c, 0xf9f9f3f4, 0xf9fa1414, 0xf9f9ebec, 0xf9fa2020, 0xf9f9dfe0, 0xf9fa2e2e, 0xf9f9d1d2,
+ 0x0c0c0000, 0x0c0c0202, 0x0c0bfdfe, 0x0c0c0606, 0x0c0bf9fa, 0x0c0c0c0c, 0x0c0bf3f4, 0x0c0c1414,
+ 0x0c0bebec, 0x0c0c2020, 0x0c0bdfe0, 0x0c0c2e2e, 0x0c0bd1d2, 0xf3f40000, 0xf3f40202, 0xf3f3fdfe,
+ 0xf3f40606, 0xf3f3f9fa, 0xf3f40c0c, 0xf3f3f3f4, 0xf3f41414, 0xf3f3ebec, 0xf3f42020, 0xf3f3dfe0,
+ 0xf3f42e2e, 0xf3f3d1d2, 0x14140000, 0x14140202, 0x1413fdfe, 0x14140606, 0x1413f9fa, 0x14140c0c,
+ 0x1413f3f4, 0x14141414, 0x1413ebec, 0x14142020, 0x1413dfe0, 0x14142e2e, 0x1413d1d2, 0xebec0000,
+ 0xebec0202, 0xebebfdfe, 0xebec0606, 0xebebf9fa, 0xebec0c0c, 0xebebf3f4, 0xebec1414, 0xebebebec,
+ 0xebec2020, 0xebebdfe0, 0xebec2e2e, 0xebebd1d2, 0x20200000, 0x20200202, 0x201ffdfe, 0x20200606,
+ 0x201ff9fa, 0x20200c0c, 0x201ff3f4, 0x20201414, 0x201febec, 0x20202020, 0x201fdfe0, 0x20202e2e,
+ 0x201fd1d2, 0xdfe00000, 0xdfe00202, 0xdfdffdfe, 0xdfe00606, 0xdfdff9fa, 0xdfe00c0c, 0xdfdff3f4,
+ 0xdfe01414, 0xdfdfebec, 0xdfe02020, 0xdfdfdfe0, 0xdfe02e2e, 0xdfdfd1d2, 0x2e2e0000, 0x2e2e0202,
+ 0x2e2dfdfe, 0x2e2e0606, 0x2e2df9fa, 0x2e2e0c0c, 0x2e2df3f4, 0x2e2e1414, 0x2e2debec, 0x2e2e2020,
+ 0x2e2ddfe0, 0x2e2e2e2e, 0x2e2dd1d2, 0xd1d20000, 0xd1d20202, 0xd1d1fdfe, 0xd1d20606, 0xd1d1f9fa,
+ 0xd1d20c0c, 0xd1d1f3f4, 0xd1d21414, 0xd1d1ebec, 0xd1d22020, 0xd1d1dfe0, 0xd1d22e2e, 0xd1d1d1d2,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000202, 0xfffffdfe, 0x00000606, 0xfffff9fa, 0x00000c0c, 0xfffff3f4, 0x00001414,
+ 0xffffebec, 0x00002020, 0xffffdfe0, 0x00002e2e, 0xffffd1d2, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000202, 0xfffffdfe, 0x00000606, 0xfffff9fa, 0x00000c0c, 0xfffff3f4, 0x00001414, 0xffffebec,
+ 0x00002020, 0xffffdfe0, 0x00002e2e, 0xffffd1d2, 0x02020000, 0x02020202, 0x0201fdfe, 0x02020606,
+ 0x0201f9fa, 0x02020c0c, 0x0201f3f4, 0x02021414, 0x0201ebec, 0x02022020, 0x0201dfe0, 0x02022e2e,
+ 0x0201d1d2, 0xfdfe0000, 0xfdfe0202, 0xfdfdfdfe, 0xfdfe0606, 0xfdfdf9fa, 0xfdfe0c0c, 0xfdfdf3f4,
+ 0xfdfe1414, 0xfdfdebec, 0xfdfe2020, 0xfdfddfe0, 0xfdfe2e2e, 0xfdfdd1d2, 0x06060000, 0x06060202,
+ 0x0605fdfe, 0x06060606, 0x0605f9fa, 0x06060c0c, 0x0605f3f4, 0x06061414, 0x0605ebec, 0x06062020,
+ 0x0605dfe0, 0x06062e2e, 0x0605d1d2, 0xf9fa0000, 0xf9fa0202, 0xf9f9fdfe, 0xf9fa0606, 0xf9f9f9fa,
+ 0xf9fa0c0c, 0xf9f9f3f4, 0xf9fa1414, 0xf9f9ebec, 0xf9fa2020, 0xf9f9dfe0, 0xf9fa2e2e, 0xf9f9d1d2,
+ 0x0c0c0000, 0x0c0c0202, 0x0c0bfdfe, 0x0c0c0606, 0x0c0bf9fa, 0x0c0c0c0c, 0x0c0bf3f4, 0x0c0c1414,
+ 0x0c0bebec, 0x0c0c2020, 0x0c0bdfe0, 0x0c0c2e2e, 0x0c0bd1d2, 0xf3f40000, 0xf3f40202, 0xf3f3fdfe,
+ 0xf3f40606, 0xf3f3f9fa, 0xf3f40c0c, 0xf3f3f3f4, 0xf3f41414, 0xf3f3ebec, 0xf3f42020, 0xf3f3dfe0,
+ 0xf3f42e2e, 0xf3f3d1d2, 0x14140000, 0x14140202, 0x1413fdfe, 0x14140606, 0x1413f9fa, 0x14140c0c,
+ 0x1413f3f4, 0x14141414, 0x1413ebec, 0x14142020, 0x1413dfe0, 0x14142e2e, 0x1413d1d2, 0xebec0000,
+ 0xebec0202, 0xebebfdfe, 0xebec0606, 0xebebf9fa, 0xebec0c0c, 0xebebf3f4, 0xebec1414, 0xebebebec,
+ 0xebec2020, 0xebebdfe0, 0xebec2e2e, 0xebebd1d2, 0x20200000, 0x20200202, 0x201ffdfe, 0x20200606,
+ 0x201ff9fa, 0x20200c0c, 0x201ff3f4, 0x20201414, 0x201febec, 0x20202020, 0x201fdfe0, 0x20202e2e,
+ 0x201fd1d2, 0xdfe00000, 0xdfe00202, 0xdfdffdfe, 0xdfe00606, 0xdfdff9fa, 0xdfe00c0c, 0xdfdff3f4,
+ 0xdfe01414, 0xdfdfebec, 0xdfe02020, 0xdfdfdfe0, 0xdfe02e2e, 0xdfdfd1d2, 0x2e2e0000, 0x2e2e0202,
+ 0x2e2dfdfe, 0x2e2e0606, 0x2e2df9fa, 0x2e2e0c0c, 0x2e2df3f4, 0x2e2e1414, 0x2e2debec, 0x2e2e2020,
+ 0x2e2ddfe0, 0x2e2e2e2e, 0x2e2dd1d2, 0xd1d20000, 0xd1d20202, 0xd1d1fdfe, 0xd1d20606, 0xd1d1f9fa,
+ 0xd1d20c0c, 0xd1d1f3f4, 0xd1d21414, 0xd1d1ebec, 0xd1d22020, 0xd1d1dfe0, 0xd1d22e2e, 0xd1d1d1d2,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
+};
+
+
+const uint32 Indeo3::correctionloworder[] = {
+ 0x00000000, 0x02020202, 0xfdfdfdfe, 0x0302feff, 0xfcfd0101, 0xfeff0303, 0x0100fcfd, 0x04040404,
+ 0xfbfbfbfc, 0x05050101, 0xfafafeff, 0x01010505, 0xfefefafb, 0x0403fbfc, 0xfbfc0404, 0x0605fdfe,
+ 0xf9fa0202, 0xfdfe0606, 0x0201f9fa, 0x09090404, 0xf6f6fbfc, 0x04040909, 0xfbfbf6f7, 0x09090909,
+ 0xf6f6f6f7, 0x0a0a0101, 0xf5f5feff, 0x01010a0a, 0xfefef5f6, 0x0807fafb, 0xf7f80505, 0xfafb0808,
+ 0x0504f7f8, 0x0f0f0909, 0xf0f0f6f7, 0x09090f0f, 0xf6f6f0f1, 0x0c0bfcfd, 0xf3f40303, 0xfcfd0c0c,
+ 0x0302f3f4, 0x10100404, 0xefeffbfc, 0x04041010, 0xfbfbeff0, 0x10101010, 0xefefeff0, 0x12120000,
+ 0xedee0000, 0x00001212, 0xffffedee, 0x0c0bf3f4, 0xf3f40c0c, 0x100ff6f7, 0xeff00909, 0xf6f71010,
+ 0x0908eff0, 0x1b1b0b0b, 0xe4e4f4f5, 0x0b0b1b1b, 0xf4f4e4e5, 0x1c1c1313, 0xe3e3eced, 0x13131c1c,
+ 0xecece3e4, 0x1615f9fa, 0xe9ea0606, 0xf9fa1616, 0x0605e9ea, 0x1d1d0404, 0xe2e2fbfc, 0x04041d1d,
+ 0xfbfbe2e3, 0x1e1e1e1e, 0xe1e1e1e2, 0x2120fdfe, 0xdedf0202, 0xfdfe2121, 0x0201dedf, 0x1716edee,
+ 0xe8e91212, 0xedee1717, 0x1211e8e9, 0x1e1df0f1, 0xe1e20f0f, 0xf0f11e1e, 0x0f0ee1e2, 0x2e2e1616,
+ 0xd1d1e9ea, 0x16162e2e, 0xe9e9d1d2, 0x2f2f0d0d, 0xd0d0f2f3, 0x0d0d2f2f, 0xf2f2d0d1, 0x31312323,
+ 0xcecedcdd, 0x23233131, 0xdcdccecf, 0x2928f4f5, 0xd6d70b0b, 0xf4f52929, 0x0b0ad6d7, 0x33330404,
+ 0xccccfbfc, 0x04043333, 0xfbfbcccd, 0x36363636, 0xc9c9c9ca, 0x2221ddde, 0xddde2222, 0x2a29e2e3,
+ 0xd5d61d1d, 0xe2e32a2a, 0x1d1cd5d6, 0x3c3bf9fa, 0xc3c40606, 0xf9fa3c3c, 0x0605c3c4, 0x4c4c1b1b,
+ 0xb3b3e4e5, 0x1b1b4c4c, 0xe4e4b3b4, 0x4d4d2b2b, 0xb2b2d4d5, 0x2b2b4d4d, 0xd4d4b2b3, 0x3736e7e8,
+ 0xc8c91818, 0xe7e83737, 0x1817c8c9, 0x4f4f0e0e, 0xb0b0f1f2, 0x0e0e4f4f, 0xf1f1b0b1, 0x53533f3f,
+ 0xacacc0c1, 0x3f3f5353, 0xc0c0acad, 0x4a49ebec, 0xb5b61414, 0xebec4a4a, 0x1413b5b6, 0x58580202,
+ 0xa7a7fdfe, 0x02025858, 0xfdfda7a8, 0x5d5d5d5d, 0xa2a2a2a3, 0x3d3ccbcc, 0xc2c33434, 0xcbcc3d3d,
+ 0x3433c2c3, 0x78783434, 0x8787cbcc, 0x34347878, 0xcbcb8788, 0x4b4ad2d3, 0xb4b52d2d, 0xd2d34b4b,
+ 0x2d2cb4b5, 0x7d7d4b4b, 0x8282b4b5, 0x4b4b7d7d, 0xb4b48283, 0x7a7a2121, 0x8585dedf, 0x21217a7a,
+ 0xdede8586, 0x6766f2f3, 0x98990d0d, 0xf2f36767, 0x0d0c9899, 0x605fd7d8, 0x9fa02828, 0xd7d86060,
+ 0x28279fa0, 0x7f7eddde, 0x80812222, 0xddde7f7f, 0x22218081, 0x5958a6a7, 0xa6a75959, 0x6968b1b2,
+ 0x96974e4e, 0xb1b26969, 0x4e4d9697, 0x0c0c0c0c, 0xf3f3f3f4, 0x17171717, 0xe8e8e8e9, 0x2a2a2a2a,
+ 0xd5d5d5d6, 0x49494949, 0xb6b6b6b7, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202,
+ 0x02020202, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe,
+ 0x0302feff, 0x0302feff, 0x0302feff, 0x0302feff, 0x0302feff, 0x0302feff, 0x0302feff, 0xfcfd0101,
+ 0xfcfd0101, 0xfcfd0101, 0xfcfd0101, 0xfcfd0101, 0xfcfd0101, 0xfcfd0101, 0xfeff0303, 0xfeff0303,
+ 0xfeff0303, 0xfeff0303, 0xfeff0303, 0xfeff0303, 0xfeff0303, 0x0100fcfd, 0x0100fcfd, 0x0100fcfd,
+ 0x0100fcfd, 0x0100fcfd, 0x0100fcfd, 0x0100fcfd, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x03030303, 0xfcfcfcfd, 0x0403feff, 0xfbfc0101, 0xfeff0404, 0x0100fbfc, 0x07070707,
+ 0xf8f8f8f9, 0x08080202, 0xf7f7fdfe, 0x02020808, 0xfdfdf7f8, 0x0908fdfe, 0xf6f70202, 0xfdfe0909,
+ 0x0201f6f7, 0x0605f9fa, 0xf9fa0606, 0x0d0d0606, 0xf2f2f9fa, 0x06060d0d, 0xf9f9f2f3, 0x0d0d0d0d,
+ 0xf2f2f2f3, 0x0e0e0101, 0xf1f1feff, 0x01010e0e, 0xfefef1f2, 0x0c0bf7f8, 0xf3f40808, 0xf7f80c0c,
+ 0x0807f3f4, 0x17170e0e, 0xe8e8f1f2, 0x0e0e1717, 0xf1f1e8e9, 0x1211fafb, 0xedee0505, 0xfafb1212,
+ 0x0504edee, 0x18180606, 0xe7e7f9fa, 0x06061818, 0xf9f9e7e8, 0x18181818, 0xe7e7e7e8, 0x1b1afeff,
+ 0xe4e50101, 0xfeff1b1b, 0x0100e4e5, 0x1110eeef, 0xeeef1111, 0x1716f2f3, 0xe8e90d0d, 0xf2f31717,
+ 0x0d0ce8e9, 0x28281010, 0xd7d7eff0, 0x10102828, 0xefefd7d8, 0x29291c1c, 0xd6d6e3e4, 0x1c1c2929,
+ 0xe3e3d6d7, 0x2120f6f7, 0xdedf0909, 0xf6f72121, 0x0908dedf, 0x2b2b0606, 0xd4d4f9fa, 0x06062b2b,
+ 0xf9f9d4d5, 0x2e2e2e2e, 0xd1d1d1d2, 0x3231fbfc, 0xcdce0404, 0xfbfc3232, 0x0403cdce, 0x2221e4e5,
+ 0xddde1b1b, 0xe4e52222, 0x1b1addde, 0x2d2ce9ea, 0xd2d31616, 0xe9ea2d2d, 0x1615d2d3, 0x45452222,
+ 0xbabaddde, 0x22224545, 0xddddbabb, 0x46461313, 0xb9b9eced, 0x13134646, 0xececb9ba, 0x49493535,
+ 0xb6b6cacb, 0x35354949, 0xcacab6b7, 0x3e3deeef, 0xc1c21111, 0xeeef3e3e, 0x1110c1c2, 0x4d4d0505,
+ 0xb2b2fafb, 0x05054d4d, 0xfafab2b3, 0x52525252, 0xadadadae, 0x3332cccd, 0xcccd3333, 0x403fd4d5,
+ 0xbfc02b2b, 0xd4d54040, 0x2b2abfc0, 0x5a59f5f6, 0xa5a60a0a, 0xf5f65a5a, 0x0a09a5a6, 0x72722929,
+ 0x8d8dd6d7, 0x29297272, 0xd6d68d8e, 0x74744040, 0x8b8bbfc0, 0x40407474, 0xbfbf8b8c, 0x5251dadb,
+ 0xadae2525, 0xdadb5252, 0x2524adae, 0x77771616, 0x8888e9ea, 0x16167777, 0xe9e98889, 0x7c7c5f5f,
+ 0x8383a0a1, 0x5f5f7c7c, 0xa0a08384, 0x6f6ee1e2, 0x90911e1e, 0xe1e26f6f, 0x1e1d9091, 0x5c5bb1b2,
+ 0xa3a44e4e, 0xb1b25c5c, 0x4e4da3a4, 0x7170bbbc, 0x8e8f4444, 0xbbbc7171, 0x44438e8f, 0x12121212,
+ 0xedededee, 0x22222222, 0xddddddde, 0x3f3f3f3f, 0xc0c0c0c1, 0x6d6d6d6d, 0x92929293, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x03030303, 0x03030303, 0x03030303, 0x03030303, 0x03030303, 0x03030303, 0x03030303, 0x03030303,
+ 0x03030303, 0xfcfcfcfd, 0xfcfcfcfd, 0xfcfcfcfd, 0xfcfcfcfd, 0xfcfcfcfd, 0xfcfcfcfd, 0xfcfcfcfd,
+ 0xfcfcfcfd, 0xfcfcfcfd, 0x0403feff, 0x0403feff, 0x0403feff, 0x0403feff, 0x0403feff, 0x0403feff,
+ 0x0403feff, 0x0403feff, 0x0403feff, 0xfbfc0101, 0xfbfc0101, 0xfbfc0101, 0xfbfc0101, 0xfbfc0101,
+ 0xfbfc0101, 0xfbfc0101, 0xfbfc0101, 0xfbfc0101, 0xfeff0404, 0xfeff0404, 0xfeff0404, 0xfeff0404,
+ 0xfeff0404, 0xfeff0404, 0xfeff0404, 0xfeff0404, 0xfeff0404, 0x0100fbfc, 0x0100fbfc, 0x0100fbfc,
+ 0x0100fbfc, 0x0100fbfc, 0x0100fbfc, 0x0100fbfc, 0x0100fbfc, 0x0100fbfc, 0x07070707, 0x07070707,
+ 0x07070707, 0x07070707, 0x07070707, 0x07070707, 0x07070707, 0x07070707, 0x07070707, 0xf8f8f8f9,
+ 0xf8f8f8f9, 0xf8f8f8f9, 0xf8f8f8f9, 0xf8f8f8f9, 0xf8f8f8f9, 0xf8f8f8f9, 0xf8f8f8f9, 0xf8f8f8f9,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x04040404, 0xfbfbfbfc, 0x0504feff, 0xfafb0101, 0xfeff0505, 0x0100fafb, 0x0a0a0303,
+ 0xf5f5fcfd, 0x03030a0a, 0xfcfcf5f6, 0x09090909, 0xf6f6f6f7, 0x0706f8f9, 0xf8f90707, 0x0c0bfcfd,
+ 0xf3f40303, 0xfcfd0c0c, 0x0302f3f4, 0x11110808, 0xeeeef7f8, 0x08081111, 0xf7f7eeef, 0x11111111,
+ 0xeeeeeeef, 0x13130101, 0xececfeff, 0x01011313, 0xfefeeced, 0x100ff4f5, 0xeff00b0b, 0xf4f51010,
+ 0x0b0aeff0, 0x1716f9fa, 0xe8e90606, 0xf9fa1717, 0x0605e8e9, 0x1f1f1212, 0xe0e0edee, 0x12121f1f,
+ 0xedede0e1, 0x20200808, 0xdfdff7f8, 0x08082020, 0xf7f7dfe0, 0x21212121, 0xdedededf, 0x2423feff,
+ 0xdbdc0101, 0xfeff2424, 0x0100dbdc, 0x1716e8e9, 0xe8e91717, 0x1f1eeeef, 0xe0e11111, 0xeeef1f1f,
+ 0x1110e0e1, 0x36361515, 0xc9c9eaeb, 0x15153636, 0xeaeac9ca, 0x37372525, 0xc8c8dadb, 0x25253737,
+ 0xdadac8c9, 0x2c2bf3f4, 0xd3d40c0c, 0xf3f42c2c, 0x0c0bd3d4, 0x39390808, 0xc6c6f7f8, 0x08083939,
+ 0xf7f7c6c7, 0x3d3d3d3d, 0xc2c2c2c3, 0x4241fafb, 0xbdbe0505, 0xfafb4242, 0x0504bdbe, 0x2d2cdbdc,
+ 0xd2d32424, 0xdbdc2d2d, 0x2423d2d3, 0x3c3be2e3, 0xc3c41d1d, 0xe2e33c3c, 0x1d1cc3c4, 0x5c5c2d2d,
+ 0xa3a3d2d3, 0x2d2d5c5c, 0xd2d2a3a4, 0x5d5d1919, 0xa2a2e6e7, 0x19195d5d, 0xe6e6a2a3, 0x61614747,
+ 0x9e9eb8b9, 0x47476161, 0xb8b89e9f, 0x5352e9ea, 0xacad1616, 0xe9ea5353, 0x1615acad, 0x66660707,
+ 0x9999f8f9, 0x07076666, 0xf8f8999a, 0x6d6d6d6d, 0x92929293, 0x4443bbbc, 0xbbbc4444, 0x5554c6c7,
+ 0xaaab3939, 0xc6c75555, 0x3938aaab, 0x7877f2f3, 0x87880d0d, 0xf2f37878, 0x0d0c8788, 0x6e6dcecf,
+ 0x91923131, 0xcecf6e6e, 0x31309192, 0x7b7a9798, 0x84856868, 0x97987b7b, 0x68678485, 0x18181818,
+ 0xe7e7e7e8, 0x2e2e2e2e, 0xd1d1d1d2, 0x54545454, 0xabababac, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04040404,
+ 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404,
+ 0x04040404, 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc,
+ 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc, 0x0504feff, 0x0504feff, 0x0504feff, 0x0504feff, 0x0504feff,
+ 0x0504feff, 0x0504feff, 0x0504feff, 0x0504feff, 0x0504feff, 0xfafb0101, 0xfafb0101, 0xfafb0101,
+ 0xfafb0101, 0xfafb0101, 0xfafb0101, 0xfafb0101, 0xfafb0101, 0xfafb0101, 0xfafb0101, 0xfeff0505,
+ 0xfeff0505, 0xfeff0505, 0xfeff0505, 0xfeff0505, 0xfeff0505, 0xfeff0505, 0xfeff0505, 0xfeff0505,
+ 0xfeff0505, 0x0100fafb, 0x0100fafb, 0x0100fafb, 0x0100fafb, 0x0100fafb, 0x0100fafb, 0x0100fafb,
+ 0x0100fafb, 0x0100fafb, 0x0100fafb, 0x0a0a0303, 0x0a0a0303, 0x0a0a0303, 0x0a0a0303, 0x0a0a0303,
+ 0x0a0a0303, 0x0a0a0303, 0x0a0a0303, 0x0a0a0303, 0x0a0a0303, 0xf5f5fcfd, 0xf5f5fcfd, 0xf5f5fcfd,
+ 0xf5f5fcfd, 0xf5f5fcfd, 0xf5f5fcfd, 0xf5f5fcfd, 0xf5f5fcfd, 0xf5f5fcfd, 0xf5f5fcfd, 0x03030a0a,
+ 0x03030a0a, 0x03030a0a, 0x03030a0a, 0x03030a0a, 0x03030a0a, 0x03030a0a, 0x03030a0a, 0x03030a0a,
+ 0x03030a0a, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x05050505, 0xfafafafb, 0x0706fdfe, 0xf8f90202, 0xfdfe0707, 0x0201f8f9, 0x0b0b0b0b,
+ 0xf4f4f4f5, 0x0d0d0303, 0xf2f2fcfd, 0x03030d0d, 0xfcfcf2f3, 0x0908f6f7, 0xf6f70909, 0x0f0efbfc,
+ 0xf0f10404, 0xfbfc0f0f, 0x0403f0f1, 0x16160b0b, 0xe9e9f4f5, 0x0b0b1616, 0xf4f4e9ea, 0x15151515,
+ 0xeaeaeaeb, 0x18180202, 0xe7e7fdfe, 0x02021818, 0xfdfde7e8, 0x1413f1f2, 0xebec0e0e, 0xf1f21414,
+ 0x0e0debec, 0x26261717, 0xd9d9e8e9, 0x17172626, 0xe8e8d9da, 0x1d1cf7f8, 0xe2e30808, 0xf7f81d1d,
+ 0x0807e2e3, 0x27270b0b, 0xd8d8f4f5, 0x0b0b2727, 0xf4f4d8d9, 0x29292929, 0xd6d6d6d7, 0x2d2cfeff,
+ 0xd2d30101, 0xfeff2d2d, 0x0100d2d3, 0x1d1ce2e3, 0xe2e31d1d, 0x2726e9ea, 0xd8d91616, 0xe9ea2727,
+ 0x1615d8d9, 0x43431b1b, 0xbcbce4e5, 0x1b1b4343, 0xe4e4bcbd, 0x45452f2f, 0xbabad0d1, 0x2f2f4545,
+ 0xd0d0babb, 0x3837f0f1, 0xc7c80f0f, 0xf0f13838, 0x0f0ec7c8, 0x47470b0b, 0xb8b8f4f5, 0x0b0b4747,
+ 0xf4f4b8b9, 0x4c4c4c4c, 0xb3b3b3b4, 0x5352f9fa, 0xacad0606, 0xf9fa5353, 0x0605acad, 0x3938d2d3,
+ 0xc6c72d2d, 0xd2d33939, 0x2d2cc6c7, 0x4b4adbdc, 0xb4b52424, 0xdbdc4b4b, 0x2423b4b5, 0x73733838,
+ 0x8c8cc7c8, 0x38387373, 0xc7c78c8d, 0x75751f1f, 0x8a8ae0e1, 0x1f1f7575, 0xe0e08a8b, 0x7a7a5858,
+ 0x8585a7a8, 0x58587a7a, 0xa7a78586, 0x6867e3e4, 0x97981c1c, 0xe3e46868, 0x1c1b9798, 0x5554aaab,
+ 0xaaab5555, 0x6a69b7b8, 0x95964848, 0xb7b86a6a, 0x48479596, 0x1e1e1e1e, 0xe1e1e1e2, 0x3a3a3a3a,
+ 0xc5c5c5c6, 0x69696969, 0x96969697, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x05050505, 0x05050505,
+ 0x05050505, 0x05050505, 0x05050505, 0x05050505, 0x05050505, 0x05050505, 0x05050505, 0x05050505,
+ 0x05050505, 0xfafafafb, 0xfafafafb, 0xfafafafb, 0xfafafafb, 0xfafafafb, 0xfafafafb, 0xfafafafb,
+ 0xfafafafb, 0xfafafafb, 0xfafafafb, 0xfafafafb, 0x0706fdfe, 0x0706fdfe, 0x0706fdfe, 0x0706fdfe,
+ 0x0706fdfe, 0x0706fdfe, 0x0706fdfe, 0x0706fdfe, 0x0706fdfe, 0x0706fdfe, 0x0706fdfe, 0xf8f90202,
+ 0xf8f90202, 0xf8f90202, 0xf8f90202, 0xf8f90202, 0xf8f90202, 0xf8f90202, 0xf8f90202, 0xf8f90202,
+ 0xf8f90202, 0xf8f90202, 0xfdfe0707, 0xfdfe0707, 0xfdfe0707, 0xfdfe0707, 0xfdfe0707, 0xfdfe0707,
+ 0xfdfe0707, 0xfdfe0707, 0xfdfe0707, 0xfdfe0707, 0xfdfe0707, 0x0201f8f9, 0x0201f8f9, 0x0201f8f9,
+ 0x0201f8f9, 0x0201f8f9, 0x0201f8f9, 0x0201f8f9, 0x0201f8f9, 0x0201f8f9, 0x0201f8f9, 0x0201f8f9,
+ 0x0b0b0b0b, 0x0b0b0b0b, 0x0b0b0b0b, 0x0b0b0b0b, 0x0b0b0b0b, 0x0b0b0b0b, 0x0b0b0b0b, 0x0b0b0b0b,
+ 0x0b0b0b0b, 0x0b0b0b0b, 0x0b0b0b0b, 0xf4f4f4f5, 0xf4f4f4f5, 0xf4f4f4f5, 0xf4f4f4f5, 0xf4f4f4f5,
+ 0xf4f4f4f5, 0xf4f4f4f5, 0xf4f4f4f5, 0xf4f4f4f5, 0xf4f4f4f5, 0xf4f4f4f5, 0x0d0d0303, 0x0d0d0303,
+ 0x0d0d0303, 0x0d0d0303, 0x0d0d0303, 0x0d0d0303, 0x0d0d0303, 0x0d0d0303, 0x0d0d0303, 0x0d0d0303,
+ 0x0d0d0303, 0xf2f2fcfd, 0xf2f2fcfd, 0xf2f2fcfd, 0xf2f2fcfd, 0xf2f2fcfd, 0xf2f2fcfd, 0xf2f2fcfd,
+ 0xf2f2fcfd, 0xf2f2fcfd, 0xf2f2fcfd, 0xf2f2fcfd, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x06060606, 0xf9f9f9fa, 0x0807fdfe, 0xf7f80202, 0xfdfe0808, 0x0201f7f8, 0x0d0d0d0d,
+ 0xf2f2f2f3, 0x0f0f0404, 0xf0f0fbfc, 0x04040f0f, 0xfbfbf0f1, 0x0b0af4f5, 0xf4f50b0b, 0x1211fafb,
+ 0xedee0505, 0xfafb1212, 0x0504edee, 0x1a1a0d0d, 0xe5e5f2f3, 0x0d0d1a1a, 0xf2f2e5e6, 0x1a1a1a1a,
+ 0xe5e5e5e6, 0x1d1d0202, 0xe2e2fdfe, 0x02021d1d, 0xfdfde2e3, 0x1817eff0, 0xe7e81010, 0xeff01818,
+ 0x100fe7e8, 0x2e2e1c1c, 0xd1d1e3e4, 0x1c1c2e2e, 0xe3e3d1d2, 0x2322f6f7, 0xdcdd0909, 0xf6f72323,
+ 0x0908dcdd, 0x2f2f0d0d, 0xd0d0f2f3, 0x0d0d2f2f, 0xf2f2d0d1, 0x31313131, 0xcecececf, 0x3635feff,
+ 0xc9ca0101, 0xfeff3636, 0x0100c9ca, 0x2322dcdd, 0xdcdd2323, 0x2f2ee5e6, 0xd0d11a1a, 0xe5e62f2f,
+ 0x1a19d0d1, 0x51512020, 0xaeaedfe0, 0x20205151, 0xdfdfaeaf, 0x53533838, 0xacacc7c8, 0x38385353,
+ 0xc7c7acad, 0x4342edee, 0xbcbd1212, 0xedee4343, 0x1211bcbd, 0x56560d0d, 0xa9a9f2f3, 0x0d0d5656,
+ 0xf2f2a9aa, 0x5b5b5b5b, 0xa4a4a4a5, 0x6362f8f9, 0x9c9d0707, 0xf8f96363, 0x07069c9d, 0x4443c9ca,
+ 0xbbbc3636, 0xc9ca4444, 0x3635bbbc, 0x5a59d3d4, 0xa5a62c2c, 0xd3d45a5a, 0x2c2ba5a6, 0x7c7bdedf,
+ 0x83842121, 0xdedf7c7c, 0x21208384, 0x67669899, 0x98996767, 0x7f7ea9aa, 0x80815656, 0xa9aa7f7f,
+ 0x56558081, 0x25252525, 0xdadadadb, 0x45454545, 0xbabababb, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606,
+ 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa,
+ 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa,
+ 0xf9f9f9fa, 0x0807fdfe, 0x0807fdfe, 0x0807fdfe, 0x0807fdfe, 0x0807fdfe, 0x0807fdfe, 0x0807fdfe,
+ 0x0807fdfe, 0x0807fdfe, 0x0807fdfe, 0x0807fdfe, 0x0807fdfe, 0xf7f80202, 0xf7f80202, 0xf7f80202,
+ 0xf7f80202, 0xf7f80202, 0xf7f80202, 0xf7f80202, 0xf7f80202, 0xf7f80202, 0xf7f80202, 0xf7f80202,
+ 0xf7f80202, 0xfdfe0808, 0xfdfe0808, 0xfdfe0808, 0xfdfe0808, 0xfdfe0808, 0xfdfe0808, 0xfdfe0808,
+ 0xfdfe0808, 0xfdfe0808, 0xfdfe0808, 0xfdfe0808, 0xfdfe0808, 0x0201f7f8, 0x0201f7f8, 0x0201f7f8,
+ 0x0201f7f8, 0x0201f7f8, 0x0201f7f8, 0x0201f7f8, 0x0201f7f8, 0x0201f7f8, 0x0201f7f8, 0x0201f7f8,
+ 0x0201f7f8, 0x0d0d0d0d, 0x0d0d0d0d, 0x0d0d0d0d, 0x0d0d0d0d, 0x0d0d0d0d, 0x0d0d0d0d, 0x0d0d0d0d,
+ 0x0d0d0d0d, 0x0d0d0d0d, 0x0d0d0d0d, 0x0d0d0d0d, 0x0d0d0d0d, 0xf2f2f2f3, 0xf2f2f2f3, 0xf2f2f2f3,
+ 0xf2f2f2f3, 0xf2f2f2f3, 0xf2f2f2f3, 0xf2f2f2f3, 0xf2f2f2f3, 0xf2f2f2f3, 0xf2f2f2f3, 0xf2f2f2f3,
+ 0xf2f2f2f3, 0x0f0f0404, 0x0f0f0404, 0x0f0f0404, 0x0f0f0404, 0x0f0f0404, 0x0f0f0404, 0x0f0f0404,
+ 0x0f0f0404, 0x0f0f0404, 0x0f0f0404, 0x0f0f0404, 0x0f0f0404, 0xf0f0fbfc, 0xf0f0fbfc, 0xf0f0fbfc,
+ 0xf0f0fbfc, 0xf0f0fbfc, 0xf0f0fbfc, 0xf0f0fbfc, 0xf0f0fbfc, 0xf0f0fbfc, 0xf0f0fbfc, 0xf0f0fbfc,
+ 0xf0f0fbfc, 0x04040f0f, 0x04040f0f, 0x04040f0f, 0x04040f0f, 0x04040f0f, 0x04040f0f, 0x04040f0f,
+ 0x04040f0f, 0x04040f0f, 0x04040f0f, 0x04040f0f, 0x04040f0f, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x07070707, 0xf8f8f8f9, 0x0a09fcfd, 0xf5f60303, 0xfcfd0a0a, 0x0302f5f6, 0x10101010,
+ 0xefefeff0, 0x12120505, 0xededfafb, 0x05051212, 0xfafaedee, 0x0d0cf2f3, 0xf2f30d0d, 0x1514f9fa,
+ 0xeaeb0606, 0xf9fa1515, 0x0605eaeb, 0x1e1e0f0f, 0xe1e1f0f1, 0x0f0f1e1e, 0xf0f0e1e2, 0x1e1e1e1e,
+ 0xe1e1e1e2, 0x22220202, 0xddddfdfe, 0x02022222, 0xfdfdddde, 0x1c1beced, 0xe3e41313, 0xeced1c1c,
+ 0x1312e3e4, 0x36362020, 0xc9c9dfe0, 0x20203636, 0xdfdfc9ca, 0x2928f4f5, 0xd6d70b0b, 0xf4f52929,
+ 0x0b0ad6d7, 0x37370f0f, 0xc8c8f0f1, 0x0f0f3737, 0xf0f0c8c9, 0x39393939, 0xc6c6c6c7, 0x3f3efeff,
+ 0xc0c10101, 0xfeff3f3f, 0x0100c0c1, 0x2827d7d8, 0xd7d82828, 0x3736e1e2, 0xc8c91e1e, 0xe1e23737,
+ 0x1e1dc8c9, 0x5e5e2525, 0xa1a1dadb, 0x25255e5e, 0xdadaa1a2, 0x60604141, 0x9f9fbebf, 0x41416060,
+ 0xbebe9fa0, 0x4e4deaeb, 0xb1b21515, 0xeaeb4e4e, 0x1514b1b2, 0x64640f0f, 0x9b9bf0f1, 0x0f0f6464,
+ 0xf0f09b9c, 0x6a6a6a6a, 0x95959596, 0x7473f7f8, 0x8b8c0808, 0xf7f87474, 0x08078b8c, 0x4f4ec0c1,
+ 0xb0b13f3f, 0xc0c14f4f, 0x3f3eb0b1, 0x6968cccd, 0x96973333, 0xcccd6969, 0x33329697, 0x78778788,
+ 0x87887878, 0x2b2b2b2b, 0xd4d4d4d5, 0x50505050, 0xafafafb0, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x07070707, 0x07070707, 0x07070707, 0x07070707, 0x07070707, 0x07070707, 0x07070707,
+ 0x07070707, 0x07070707, 0x07070707, 0x07070707, 0x07070707, 0xf8f8f8f9, 0xf8f8f8f9, 0xf8f8f8f9,
+ 0xf8f8f8f9, 0xf8f8f8f9, 0xf8f8f8f9, 0xf8f8f8f9, 0xf8f8f8f9, 0xf8f8f8f9, 0xf8f8f8f9, 0xf8f8f8f9,
+ 0xf8f8f8f9, 0x0a09fcfd, 0x0a09fcfd, 0x0a09fcfd, 0x0a09fcfd, 0x0a09fcfd, 0x0a09fcfd, 0x0a09fcfd,
+ 0x0a09fcfd, 0x0a09fcfd, 0x0a09fcfd, 0x0a09fcfd, 0x0a09fcfd, 0xf5f60303, 0xf5f60303, 0xf5f60303,
+ 0xf5f60303, 0xf5f60303, 0xf5f60303, 0xf5f60303, 0xf5f60303, 0xf5f60303, 0xf5f60303, 0xf5f60303,
+ 0xf5f60303, 0xfcfd0a0a, 0xfcfd0a0a, 0xfcfd0a0a, 0xfcfd0a0a, 0xfcfd0a0a, 0xfcfd0a0a, 0xfcfd0a0a,
+ 0xfcfd0a0a, 0xfcfd0a0a, 0xfcfd0a0a, 0xfcfd0a0a, 0xfcfd0a0a, 0x0302f5f6, 0x0302f5f6, 0x0302f5f6,
+ 0x0302f5f6, 0x0302f5f6, 0x0302f5f6, 0x0302f5f6, 0x0302f5f6, 0x0302f5f6, 0x0302f5f6, 0x0302f5f6,
+ 0x0302f5f6, 0x10101010, 0x10101010, 0x10101010, 0x10101010, 0x10101010, 0x10101010, 0x10101010,
+ 0x10101010, 0x10101010, 0x10101010, 0x10101010, 0x10101010, 0xefefeff0, 0xefefeff0, 0xefefeff0,
+ 0xefefeff0, 0xefefeff0, 0xefefeff0, 0xefefeff0, 0xefefeff0, 0xefefeff0, 0xefefeff0, 0xefefeff0,
+ 0xefefeff0, 0x12120505, 0x12120505, 0x12120505, 0x12120505, 0x12120505, 0x12120505, 0x12120505,
+ 0x12120505, 0x12120505, 0x12120505, 0x12120505, 0x12120505, 0xededfafb, 0xededfafb, 0xededfafb,
+ 0xededfafb, 0xededfafb, 0xededfafb, 0xededfafb, 0xededfafb, 0xededfafb, 0xededfafb, 0xededfafb,
+ 0xededfafb, 0x05051212, 0x05051212, 0x05051212, 0x05051212, 0x05051212, 0x05051212, 0x05051212,
+ 0x05051212, 0x05051212, 0x05051212, 0x05051212, 0x05051212, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x08080808, 0xf7f7f7f8, 0x0b0afcfd, 0xf4f50303, 0xfcfd0b0b, 0x0302f4f5, 0x12121212,
+ 0xedededee, 0x14140505, 0xebebfafb, 0x05051414, 0xfafaebec, 0x0f0ef0f1, 0xf0f10f0f, 0x1817f8f9,
+ 0xe7e80707, 0xf8f91818, 0x0706e7e8, 0x23231111, 0xdcdceeef, 0x11112323, 0xeeeedcdd, 0x22222222,
+ 0xddddddde, 0x26260303, 0xd9d9fcfd, 0x03032626, 0xfcfcd9da, 0x201fe9ea, 0xdfe01616, 0xe9ea2020,
+ 0x1615dfe0, 0x3d3d2525, 0xc2c2dadb, 0x25253d3d, 0xdadac2c3, 0x2f2ef2f3, 0xd0d10d0d, 0xf2f32f2f,
+ 0x0d0cd0d1, 0x3f3f1111, 0xc0c0eeef, 0x11113f3f, 0xeeeec0c1, 0x41414141, 0xbebebebf, 0x4847feff,
+ 0xb7b80101, 0xfeff4848, 0x0100b7b8, 0x2e2dd1d2, 0xd1d22e2e, 0x3f3edcdd, 0xc0c12323, 0xdcdd3f3f,
+ 0x2322c0c1, 0x6b6b2b2b, 0x9494d4d5, 0x2b2b6b6b, 0xd4d49495, 0x6e6e4b4b, 0x9191b4b5, 0x4b4b6e6e,
+ 0xb4b49192, 0x5958e7e8, 0xa6a71818, 0xe7e85959, 0x1817a6a7, 0x72721111, 0x8d8deeef, 0x11117272,
+ 0xeeee8d8e, 0x79797979, 0x86868687, 0x5b5ab7b8, 0xa4a54848, 0xb7b85b5b, 0x4847a4a5, 0x7877c5c6,
+ 0x87883a3a, 0xc5c67878, 0x3a398788, 0x31313131, 0xcecececf, 0x5c5c5c5c, 0xa3a3a3a4, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x08080808, 0x08080808, 0x08080808, 0x08080808, 0x08080808,
+ 0x08080808, 0x08080808, 0x08080808, 0x08080808, 0x08080808, 0x08080808, 0x08080808, 0xf7f7f7f8,
+ 0xf7f7f7f8, 0xf7f7f7f8, 0xf7f7f7f8, 0xf7f7f7f8, 0xf7f7f7f8, 0xf7f7f7f8, 0xf7f7f7f8, 0xf7f7f7f8,
+ 0xf7f7f7f8, 0xf7f7f7f8, 0xf7f7f7f8, 0x0b0afcfd, 0x0b0afcfd, 0x0b0afcfd, 0x0b0afcfd, 0x0b0afcfd,
+ 0x0b0afcfd, 0x0b0afcfd, 0x0b0afcfd, 0x0b0afcfd, 0x0b0afcfd, 0x0b0afcfd, 0x0b0afcfd, 0xf4f50303,
+ 0xf4f50303, 0xf4f50303, 0xf4f50303, 0xf4f50303, 0xf4f50303, 0xf4f50303, 0xf4f50303, 0xf4f50303,
+ 0xf4f50303, 0xf4f50303, 0xf4f50303, 0xfcfd0b0b, 0xfcfd0b0b, 0xfcfd0b0b, 0xfcfd0b0b, 0xfcfd0b0b,
+ 0xfcfd0b0b, 0xfcfd0b0b, 0xfcfd0b0b, 0xfcfd0b0b, 0xfcfd0b0b, 0xfcfd0b0b, 0xfcfd0b0b, 0x0302f4f5,
+ 0x0302f4f5, 0x0302f4f5, 0x0302f4f5, 0x0302f4f5, 0x0302f4f5, 0x0302f4f5, 0x0302f4f5, 0x0302f4f5,
+ 0x0302f4f5, 0x0302f4f5, 0x0302f4f5, 0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212,
+ 0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212, 0xedededee,
+ 0xedededee, 0xedededee, 0xedededee, 0xedededee, 0xedededee, 0xedededee, 0xedededee, 0xedededee,
+ 0xedededee, 0xedededee, 0xedededee, 0x14140505, 0x14140505, 0x14140505, 0x14140505, 0x14140505,
+ 0x14140505, 0x14140505, 0x14140505, 0x14140505, 0x14140505, 0x14140505, 0x14140505, 0xebebfafb,
+ 0xebebfafb, 0xebebfafb, 0xebebfafb, 0xebebfafb, 0xebebfafb, 0xebebfafb, 0xebebfafb, 0xebebfafb,
+ 0xebebfafb, 0xebebfafb, 0xebebfafb, 0x05051414, 0x05051414, 0x05051414, 0x05051414, 0x05051414,
+ 0x05051414, 0x05051414, 0x05051414, 0x05051414, 0x05051414, 0x05051414, 0x05051414, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x09090909, 0xf6f6f6f7, 0x0c0bfcfd, 0xf3f40303, 0xfcfd0c0c, 0x0302f3f4, 0x14141414,
+ 0xebebebec, 0x17170606, 0xe8e8f9fa, 0x06061717, 0xf9f9e8e9, 0x1110eeef, 0xeeef1111, 0x1b1af8f9,
+ 0xe4e50707, 0xf8f91b1b, 0x0706e4e5, 0x27271313, 0xd8d8eced, 0x13132727, 0xececd8d9, 0x27272727,
+ 0xd8d8d8d9, 0x2b2b0303, 0xd4d4fcfd, 0x03032b2b, 0xfcfcd4d5, 0x2423e7e8, 0xdbdc1818, 0xe7e82424,
+ 0x1817dbdc, 0x45452a2a, 0xbabad5d6, 0x2a2a4545, 0xd5d5babb, 0x3534f1f2, 0xcacb0e0e, 0xf1f23535,
+ 0x0e0dcacb, 0x47471313, 0xb8b8eced, 0x13134747, 0xececb8b9, 0x49494949, 0xb6b6b6b7, 0x504ffdfe,
+ 0xafb00202, 0xfdfe5050, 0x0201afb0, 0x3433cbcc, 0xcbcc3434, 0x4645d8d9, 0xb9ba2727, 0xd8d94646,
+ 0x2726b9ba, 0x79793030, 0x8686cfd0, 0x30307979, 0xcfcf8687, 0x7c7c5454, 0x8383abac, 0x54547c7c,
+ 0xabab8384, 0x6463e4e5, 0x9b9c1b1b, 0xe4e56464, 0x1b1a9b9c, 0x6665aeaf, 0x999a5151, 0xaeaf6666,
+ 0x5150999a, 0x37373737, 0xc8c8c8c9, 0x68686868, 0x97979798, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x09090909, 0x09090909, 0x09090909, 0x09090909, 0x09090909, 0x09090909,
+ 0x09090909, 0x09090909, 0x09090909, 0x09090909, 0x09090909, 0x09090909, 0x09090909, 0xf6f6f6f7,
+ 0xf6f6f6f7, 0xf6f6f6f7, 0xf6f6f6f7, 0xf6f6f6f7, 0xf6f6f6f7, 0xf6f6f6f7, 0xf6f6f6f7, 0xf6f6f6f7,
+ 0xf6f6f6f7, 0xf6f6f6f7, 0xf6f6f6f7, 0xf6f6f6f7, 0x0c0bfcfd, 0x0c0bfcfd, 0x0c0bfcfd, 0x0c0bfcfd,
+ 0x0c0bfcfd, 0x0c0bfcfd, 0x0c0bfcfd, 0x0c0bfcfd, 0x0c0bfcfd, 0x0c0bfcfd, 0x0c0bfcfd, 0x0c0bfcfd,
+ 0x0c0bfcfd, 0xf3f40303, 0xf3f40303, 0xf3f40303, 0xf3f40303, 0xf3f40303, 0xf3f40303, 0xf3f40303,
+ 0xf3f40303, 0xf3f40303, 0xf3f40303, 0xf3f40303, 0xf3f40303, 0xf3f40303, 0xfcfd0c0c, 0xfcfd0c0c,
+ 0xfcfd0c0c, 0xfcfd0c0c, 0xfcfd0c0c, 0xfcfd0c0c, 0xfcfd0c0c, 0xfcfd0c0c, 0xfcfd0c0c, 0xfcfd0c0c,
+ 0xfcfd0c0c, 0xfcfd0c0c, 0xfcfd0c0c, 0x0302f3f4, 0x0302f3f4, 0x0302f3f4, 0x0302f3f4, 0x0302f3f4,
+ 0x0302f3f4, 0x0302f3f4, 0x0302f3f4, 0x0302f3f4, 0x0302f3f4, 0x0302f3f4, 0x0302f3f4, 0x0302f3f4,
+ 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414,
+ 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0xebebebec, 0xebebebec, 0xebebebec,
+ 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec,
+ 0xebebebec, 0xebebebec, 0x17170606, 0x17170606, 0x17170606, 0x17170606, 0x17170606, 0x17170606,
+ 0x17170606, 0x17170606, 0x17170606, 0x17170606, 0x17170606, 0x17170606, 0x17170606, 0xe8e8f9fa,
+ 0xe8e8f9fa, 0xe8e8f9fa, 0xe8e8f9fa, 0xe8e8f9fa, 0xe8e8f9fa, 0xe8e8f9fa, 0xe8e8f9fa, 0xe8e8f9fa,
+ 0xe8e8f9fa, 0xe8e8f9fa, 0xe8e8f9fa, 0xe8e8f9fa, 0x06061717, 0x06061717, 0x06061717, 0x06061717,
+ 0x06061717, 0x06061717, 0x06061717, 0x06061717, 0x06061717, 0x06061717, 0x06061717, 0x06061717,
+ 0x06061717, 0xf9f9e8e9, 0xf9f9e8e9, 0xf9f9e8e9, 0xf9f9e8e9, 0xf9f9e8e9, 0xf9f9e8e9, 0xf9f9e8e9,
+ 0xf9f9e8e9, 0xf9f9e8e9, 0xf9f9e8e9, 0xf9f9e8e9, 0xf9f9e8e9, 0xf9f9e8e9, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x02020202, 0xfdfdfdfe, 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe, 0x04040404,
+ 0xfbfbfbfc, 0x04040000, 0xfbfc0000, 0x00000404, 0xfffffbfc, 0x0403fbfc, 0xfbfc0404, 0x0605fdfe,
+ 0xf9fa0202, 0xfdfe0606, 0x0201f9fa, 0x08080404, 0xf7f7fbfc, 0x04040808, 0xfbfbf7f8, 0x08080808,
+ 0xf7f7f7f8, 0x0a0a0000, 0xf5f60000, 0x00000a0a, 0xfffff5f6, 0x0807fbfc, 0xf7f80404, 0xfbfc0808,
+ 0x0403f7f8, 0x0e0e0808, 0xf1f1f7f8, 0x08080e0e, 0xf7f7f1f2, 0x0c0bfdfe, 0xf3f40202, 0xfdfe0c0c,
+ 0x0201f3f4, 0x10100404, 0xefeffbfc, 0x04041010, 0xfbfbeff0, 0x10101010, 0xefefeff0, 0x12120000,
+ 0xedee0000, 0x00001212, 0xffffedee, 0x0c0bf3f4, 0xf3f40c0c, 0x100ff7f8, 0xeff00808, 0xf7f81010,
+ 0x0807eff0, 0x1a1a0a0a, 0xe5e5f5f6, 0x0a0a1a1a, 0xf5f5e5e6, 0x1c1c1212, 0xe3e3edee, 0x12121c1c,
+ 0xedede3e4, 0x1615f9fa, 0xe9ea0606, 0xf9fa1616, 0x0605e9ea, 0x1c1c0404, 0xe3e3fbfc, 0x04041c1c,
+ 0xfbfbe3e4, 0x1e1e1e1e, 0xe1e1e1e2, 0x201ffdfe, 0xdfe00202, 0xfdfe2020, 0x0201dfe0, 0x1615edee,
+ 0xe9ea1212, 0xedee1616, 0x1211e9ea, 0x1e1df1f2, 0xe1e20e0e, 0xf1f21e1e, 0x0e0de1e2, 0x2e2e1616,
+ 0xd1d1e9ea, 0x16162e2e, 0xe9e9d1d2, 0x2e2e0c0c, 0xd1d1f3f4, 0x0c0c2e2e, 0xf3f3d1d2, 0x30302222,
+ 0xcfcfddde, 0x22223030, 0xddddcfd0, 0x2827f5f6, 0xd7d80a0a, 0xf5f62828, 0x0a09d7d8, 0x32320404,
+ 0xcdcdfbfc, 0x04043232, 0xfbfbcdce, 0x36363636, 0xc9c9c9ca, 0x2221ddde, 0xddde2222, 0x2a29e3e4,
+ 0xd5d61c1c, 0xe3e42a2a, 0x1c1bd5d6, 0x3c3bf9fa, 0xc3c40606, 0xf9fa3c3c, 0x0605c3c4, 0x4c4c1a1a,
+ 0xb3b3e5e6, 0x1a1a4c4c, 0xe5e5b3b4, 0x4c4c2a2a, 0xb3b3d5d6, 0x2a2a4c4c, 0xd5d5b3b4, 0x3635e7e8,
+ 0xc9ca1818, 0xe7e83636, 0x1817c9ca, 0x4e4e0e0e, 0xb1b1f1f2, 0x0e0e4e4e, 0xf1f1b1b2, 0x52523e3e,
+ 0xadadc1c2, 0x3e3e5252, 0xc1c1adae, 0x4a49ebec, 0xb5b61414, 0xebec4a4a, 0x1413b5b6, 0x58580202,
+ 0xa7a7fdfe, 0x02025858, 0xfdfda7a8, 0x5c5c5c5c, 0xa3a3a3a4, 0x3c3bcbcc, 0xc3c43434, 0xcbcc3c3c,
+ 0x3433c3c4, 0x76763434, 0x8989cbcc, 0x34347676, 0xcbcb898a, 0x4a49d3d4, 0xb5b62c2c, 0xd3d44a4a,
+ 0x2c2bb5b6, 0x76764a4a, 0x8989b5b6, 0x4a4a7676, 0xb5b5898a, 0x76762020, 0x8989dfe0, 0x20207676,
+ 0xdfdf898a, 0x6665f3f4, 0x999a0c0c, 0xf3f46666, 0x0c0b999a, 0x605fd7d8, 0x9fa02828, 0xd7d86060,
+ 0x28279fa0, 0x7675ddde, 0x898a2222, 0xddde7676, 0x2221898a, 0x5857a7a8, 0xa7a85858, 0x6867b1b2,
+ 0x97984e4e, 0xb1b26868, 0x4e4d9798, 0x0c0c0c0c, 0xf3f3f3f4, 0x16161616, 0xe9e9e9ea, 0x2a2a2a2a,
+ 0xd5d5d5d6, 0x48484848, 0xb7b7b7b8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202,
+ 0x02020202, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe,
+ 0x02020000, 0x02020000, 0x02020000, 0x02020000, 0x02020000, 0x02020000, 0x02020000, 0xfdfe0000,
+ 0xfdfe0000, 0xfdfe0000, 0xfdfe0000, 0xfdfe0000, 0xfdfe0000, 0xfdfe0000, 0x00000202, 0x00000202,
+ 0x00000202, 0x00000202, 0x00000202, 0x00000202, 0x00000202, 0xfffffdfe, 0xfffffdfe, 0xfffffdfe,
+ 0xfffffdfe, 0xfffffdfe, 0xfffffdfe, 0xfffffdfe, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x03030303, 0xfcfcfcfd, 0x03030000, 0xfcfd0000, 0x00000303, 0xfffffcfd, 0x06060606,
+ 0xf9f9f9fa, 0x09090303, 0xf6f6fcfd, 0x03030909, 0xfcfcf6f7, 0x0908fcfd, 0xf6f70303, 0xfcfd0909,
+ 0x0302f6f7, 0x0605f9fa, 0xf9fa0606, 0x0c0c0606, 0xf3f3f9fa, 0x06060c0c, 0xf9f9f3f4, 0x0c0c0c0c,
+ 0xf3f3f3f4, 0x0f0f0000, 0xf0f10000, 0x00000f0f, 0xfffff0f1, 0x0c0bf6f7, 0xf3f40909, 0xf6f70c0c,
+ 0x0908f3f4, 0x18180f0f, 0xe7e7f0f1, 0x0f0f1818, 0xf0f0e7e8, 0x1211f9fa, 0xedee0606, 0xf9fa1212,
+ 0x0605edee, 0x18180606, 0xe7e7f9fa, 0x06061818, 0xf9f9e7e8, 0x18181818, 0xe7e7e7e8, 0x1b1b0000,
+ 0xe4e50000, 0x00001b1b, 0xffffe4e5, 0x1211edee, 0xedee1212, 0x1817f3f4, 0xe7e80c0c, 0xf3f41818,
+ 0x0c0be7e8, 0x27270f0f, 0xd8d8f0f1, 0x0f0f2727, 0xf0f0d8d9, 0x2a2a1b1b, 0xd5d5e4e5, 0x1b1b2a2a,
+ 0xe4e4d5d6, 0x2120f6f7, 0xdedf0909, 0xf6f72121, 0x0908dedf, 0x2a2a0606, 0xd5d5f9fa, 0x06062a2a,
+ 0xf9f9d5d6, 0x2d2d2d2d, 0xd2d2d2d3, 0x3332fcfd, 0xcccd0303, 0xfcfd3333, 0x0302cccd, 0x2120e4e5,
+ 0xdedf1b1b, 0xe4e52121, 0x1b1adedf, 0x2d2ceaeb, 0xd2d31515, 0xeaeb2d2d, 0x1514d2d3, 0x45452121,
+ 0xbabadedf, 0x21214545, 0xdedebabb, 0x45451212, 0xbabaedee, 0x12124545, 0xededbabb, 0x48483636,
+ 0xb7b7c9ca, 0x36364848, 0xc9c9b7b8, 0x3f3eedee, 0xc0c11212, 0xedee3f3f, 0x1211c0c1, 0x4e4e0606,
+ 0xb1b1f9fa, 0x06064e4e, 0xf9f9b1b2, 0x51515151, 0xaeaeaeaf, 0x3332cccd, 0xcccd3333, 0x3f3ed5d6,
+ 0xc0c12a2a, 0xd5d63f3f, 0x2a29c0c1, 0x5a59f6f7, 0xa5a60909, 0xf6f75a5a, 0x0908a5a6, 0x72722a2a,
+ 0x8d8dd5d6, 0x2a2a7272, 0xd5d58d8e, 0x75753f3f, 0x8a8ac0c1, 0x3f3f7575, 0xc0c08a8b, 0x5150dbdc,
+ 0xaeaf2424, 0xdbdc5151, 0x2423aeaf, 0x78781515, 0x8787eaeb, 0x15157878, 0xeaea8788, 0x7b7b6060,
+ 0x84849fa0, 0x60607b7b, 0x9f9f8485, 0x6f6ee1e2, 0x90911e1e, 0xe1e26f6f, 0x1e1d9091, 0x5d5cb1b2,
+ 0xa2a34e4e, 0xb1b25d5d, 0x4e4da2a3, 0x7271babb, 0x8d8e4545, 0xbabb7272, 0x45448d8e, 0x12121212,
+ 0xedededee, 0x21212121, 0xdedededf, 0x3f3f3f3f, 0xc0c0c0c1, 0x6c6c6c6c, 0x93939394, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x03030303, 0x03030303, 0x03030303, 0x03030303, 0x03030303, 0x03030303, 0x03030303, 0x03030303,
+ 0x03030303, 0xfcfcfcfd, 0xfcfcfcfd, 0xfcfcfcfd, 0xfcfcfcfd, 0xfcfcfcfd, 0xfcfcfcfd, 0xfcfcfcfd,
+ 0xfcfcfcfd, 0xfcfcfcfd, 0x03030000, 0x03030000, 0x03030000, 0x03030000, 0x03030000, 0x03030000,
+ 0x03030000, 0x03030000, 0x03030000, 0xfcfd0000, 0xfcfd0000, 0xfcfd0000, 0xfcfd0000, 0xfcfd0000,
+ 0xfcfd0000, 0xfcfd0000, 0xfcfd0000, 0xfcfd0000, 0x00000303, 0x00000303, 0x00000303, 0x00000303,
+ 0x00000303, 0x00000303, 0x00000303, 0x00000303, 0x00000303, 0xfffffcfd, 0xfffffcfd, 0xfffffcfd,
+ 0xfffffcfd, 0xfffffcfd, 0xfffffcfd, 0xfffffcfd, 0xfffffcfd, 0xfffffcfd, 0x06060606, 0x06060606,
+ 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0xf9f9f9fa,
+ 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x04040404, 0xfbfbfbfc, 0x04040000, 0xfbfc0000, 0x00000404, 0xfffffbfc, 0x08080404,
+ 0xf7f7fbfc, 0x04040808, 0xfbfbf7f8, 0x08080808, 0xf7f7f7f8, 0x0807f7f8, 0xf7f80808, 0x0c0bfbfc,
+ 0xf3f40404, 0xfbfc0c0c, 0x0403f3f4, 0x10100808, 0xefeff7f8, 0x08081010, 0xf7f7eff0, 0x10101010,
+ 0xefefeff0, 0x14140000, 0xebec0000, 0x00001414, 0xffffebec, 0x100ff3f4, 0xeff00c0c, 0xf3f41010,
+ 0x0c0beff0, 0x1817fbfc, 0xe7e80404, 0xfbfc1818, 0x0403e7e8, 0x20201010, 0xdfdfeff0, 0x10102020,
+ 0xefefdfe0, 0x20200808, 0xdfdff7f8, 0x08082020, 0xf7f7dfe0, 0x20202020, 0xdfdfdfe0, 0x24240000,
+ 0xdbdc0000, 0x00002424, 0xffffdbdc, 0x1817e7e8, 0xe7e81818, 0x201feff0, 0xdfe01010, 0xeff02020,
+ 0x100fdfe0, 0x34341414, 0xcbcbebec, 0x14143434, 0xebebcbcc, 0x38382424, 0xc7c7dbdc, 0x24243838,
+ 0xdbdbc7c8, 0x2c2bf3f4, 0xd3d40c0c, 0xf3f42c2c, 0x0c0bd3d4, 0x38380808, 0xc7c7f7f8, 0x08083838,
+ 0xf7f7c7c8, 0x3c3c3c3c, 0xc3c3c3c4, 0x403ffbfc, 0xbfc00404, 0xfbfc4040, 0x0403bfc0, 0x2c2bdbdc,
+ 0xd3d42424, 0xdbdc2c2c, 0x2423d3d4, 0x3c3be3e4, 0xc3c41c1c, 0xe3e43c3c, 0x1c1bc3c4, 0x5c5c2c2c,
+ 0xa3a3d3d4, 0x2c2c5c5c, 0xd3d3a3a4, 0x5c5c1818, 0xa3a3e7e8, 0x18185c5c, 0xe7e7a3a4, 0x60604848,
+ 0x9f9fb7b8, 0x48486060, 0xb7b79fa0, 0x5453ebec, 0xabac1414, 0xebec5454, 0x1413abac, 0x64640808,
+ 0x9b9bf7f8, 0x08086464, 0xf7f79b9c, 0x6c6c6c6c, 0x93939394, 0x4443bbbc, 0xbbbc4444, 0x5453c7c8,
+ 0xabac3838, 0xc7c85454, 0x3837abac, 0x7877f3f4, 0x87880c0c, 0xf3f47878, 0x0c0b8788, 0x6c6bcfd0,
+ 0x93943030, 0xcfd06c6c, 0x302f9394, 0x7c7b9798, 0x83846868, 0x97987c7c, 0x68678384, 0x18181818,
+ 0xe7e7e7e8, 0x2c2c2c2c, 0xd3d3d3d4, 0x54545454, 0xabababac, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04040404,
+ 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404,
+ 0x04040404, 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc,
+ 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc, 0x04040000, 0x04040000, 0x04040000, 0x04040000, 0x04040000,
+ 0x04040000, 0x04040000, 0x04040000, 0x04040000, 0x04040000, 0xfbfc0000, 0xfbfc0000, 0xfbfc0000,
+ 0xfbfc0000, 0xfbfc0000, 0xfbfc0000, 0xfbfc0000, 0xfbfc0000, 0xfbfc0000, 0xfbfc0000, 0x00000404,
+ 0x00000404, 0x00000404, 0x00000404, 0x00000404, 0x00000404, 0x00000404, 0x00000404, 0x00000404,
+ 0x00000404, 0xfffffbfc, 0xfffffbfc, 0xfffffbfc, 0xfffffbfc, 0xfffffbfc, 0xfffffbfc, 0xfffffbfc,
+ 0xfffffbfc, 0xfffffbfc, 0xfffffbfc, 0x08080404, 0x08080404, 0x08080404, 0x08080404, 0x08080404,
+ 0x08080404, 0x08080404, 0x08080404, 0x08080404, 0x08080404, 0xf7f7fbfc, 0xf7f7fbfc, 0xf7f7fbfc,
+ 0xf7f7fbfc, 0xf7f7fbfc, 0xf7f7fbfc, 0xf7f7fbfc, 0xf7f7fbfc, 0xf7f7fbfc, 0xf7f7fbfc, 0x04040808,
+ 0x04040808, 0x04040808, 0x04040808, 0x04040808, 0x04040808, 0x04040808, 0x04040808, 0x04040808,
+ 0x04040808, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x05050505, 0xfafafafb, 0x05050000, 0xfafb0000, 0x00000505, 0xfffffafb, 0x0a0a0a0a,
+ 0xf5f5f5f6, 0x0f0f0505, 0xf0f0fafb, 0x05050f0f, 0xfafaf0f1, 0x0a09f5f6, 0xf5f60a0a, 0x0f0efafb,
+ 0xf0f10505, 0xfafb0f0f, 0x0504f0f1, 0x14140a0a, 0xebebf5f6, 0x0a0a1414, 0xf5f5ebec, 0x14141414,
+ 0xebebebec, 0x19190000, 0xe6e70000, 0x00001919, 0xffffe6e7, 0x1413f0f1, 0xebec0f0f, 0xf0f11414,
+ 0x0f0eebec, 0x28281919, 0xd7d7e6e7, 0x19192828, 0xe6e6d7d8, 0x1e1df5f6, 0xe1e20a0a, 0xf5f61e1e,
+ 0x0a09e1e2, 0x28280a0a, 0xd7d7f5f6, 0x0a0a2828, 0xf5f5d7d8, 0x28282828, 0xd7d7d7d8, 0x2d2d0000,
+ 0xd2d30000, 0x00002d2d, 0xffffd2d3, 0x1e1de1e2, 0xe1e21e1e, 0x2827ebec, 0xd7d81414, 0xebec2828,
+ 0x1413d7d8, 0x41411919, 0xbebee6e7, 0x19194141, 0xe6e6bebf, 0x46462d2d, 0xb9b9d2d3, 0x2d2d4646,
+ 0xd2d2b9ba, 0x3736f0f1, 0xc8c90f0f, 0xf0f13737, 0x0f0ec8c9, 0x46460a0a, 0xb9b9f5f6, 0x0a0a4646,
+ 0xf5f5b9ba, 0x4b4b4b4b, 0xb4b4b4b5, 0x5554fafb, 0xaaab0505, 0xfafb5555, 0x0504aaab, 0x3736d2d3,
+ 0xc8c92d2d, 0xd2d33737, 0x2d2cc8c9, 0x4b4adcdd, 0xb4b52323, 0xdcdd4b4b, 0x2322b4b5, 0x73733737,
+ 0x8c8cc8c9, 0x37377373, 0xc8c88c8d, 0x73731e1e, 0x8c8ce1e2, 0x1e1e7373, 0xe1e18c8d, 0x78785a5a,
+ 0x8787a5a6, 0x5a5a7878, 0xa5a58788, 0x6968e1e2, 0x96971e1e, 0xe1e26969, 0x1e1d9697, 0x5554aaab,
+ 0xaaab5555, 0x6968b9ba, 0x96974646, 0xb9ba6969, 0x46459697, 0x1e1e1e1e, 0xe1e1e1e2, 0x3c3c3c3c,
+ 0xc3c3c3c4, 0x69696969, 0x96969697, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x05050505, 0x05050505,
+ 0x05050505, 0x05050505, 0x05050505, 0x05050505, 0x05050505, 0x05050505, 0x05050505, 0x05050505,
+ 0x05050505, 0xfafafafb, 0xfafafafb, 0xfafafafb, 0xfafafafb, 0xfafafafb, 0xfafafafb, 0xfafafafb,
+ 0xfafafafb, 0xfafafafb, 0xfafafafb, 0xfafafafb, 0x05050000, 0x05050000, 0x05050000, 0x05050000,
+ 0x05050000, 0x05050000, 0x05050000, 0x05050000, 0x05050000, 0x05050000, 0x05050000, 0xfafb0000,
+ 0xfafb0000, 0xfafb0000, 0xfafb0000, 0xfafb0000, 0xfafb0000, 0xfafb0000, 0xfafb0000, 0xfafb0000,
+ 0xfafb0000, 0xfafb0000, 0x00000505, 0x00000505, 0x00000505, 0x00000505, 0x00000505, 0x00000505,
+ 0x00000505, 0x00000505, 0x00000505, 0x00000505, 0x00000505, 0xfffffafb, 0xfffffafb, 0xfffffafb,
+ 0xfffffafb, 0xfffffafb, 0xfffffafb, 0xfffffafb, 0xfffffafb, 0xfffffafb, 0xfffffafb, 0xfffffafb,
+ 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a,
+ 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a, 0xf5f5f5f6, 0xf5f5f5f6, 0xf5f5f5f6, 0xf5f5f5f6, 0xf5f5f5f6,
+ 0xf5f5f5f6, 0xf5f5f5f6, 0xf5f5f5f6, 0xf5f5f5f6, 0xf5f5f5f6, 0xf5f5f5f6, 0x0f0f0505, 0x0f0f0505,
+ 0x0f0f0505, 0x0f0f0505, 0x0f0f0505, 0x0f0f0505, 0x0f0f0505, 0x0f0f0505, 0x0f0f0505, 0x0f0f0505,
+ 0x0f0f0505, 0xf0f0fafb, 0xf0f0fafb, 0xf0f0fafb, 0xf0f0fafb, 0xf0f0fafb, 0xf0f0fafb, 0xf0f0fafb,
+ 0xf0f0fafb, 0xf0f0fafb, 0xf0f0fafb, 0xf0f0fafb, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x06060606, 0xf9f9f9fa, 0x06060000, 0xf9fa0000, 0x00000606, 0xfffff9fa, 0x0c0c0c0c,
+ 0xf3f3f3f4, 0x0c0c0606, 0xf3f3f9fa, 0x06060c0c, 0xf9f9f3f4, 0x0c0bf3f4, 0xf3f40c0c, 0x1211f9fa,
+ 0xedee0606, 0xf9fa1212, 0x0605edee, 0x18180c0c, 0xe7e7f3f4, 0x0c0c1818, 0xf3f3e7e8, 0x18181818,
+ 0xe7e7e7e8, 0x1e1e0000, 0xe1e20000, 0x00001e1e, 0xffffe1e2, 0x1817edee, 0xe7e81212, 0xedee1818,
+ 0x1211e7e8, 0x30301e1e, 0xcfcfe1e2, 0x1e1e3030, 0xe1e1cfd0, 0x2423f9fa, 0xdbdc0606, 0xf9fa2424,
+ 0x0605dbdc, 0x30300c0c, 0xcfcff3f4, 0x0c0c3030, 0xf3f3cfd0, 0x30303030, 0xcfcfcfd0, 0x36360000,
+ 0xc9ca0000, 0x00003636, 0xffffc9ca, 0x2423dbdc, 0xdbdc2424, 0x302fe7e8, 0xcfd01818, 0xe7e83030,
+ 0x1817cfd0, 0x4e4e1e1e, 0xb1b1e1e2, 0x1e1e4e4e, 0xe1e1b1b2, 0x54543636, 0xababc9ca, 0x36365454,
+ 0xc9c9abac, 0x4241edee, 0xbdbe1212, 0xedee4242, 0x1211bdbe, 0x54540c0c, 0xababf3f4, 0x0c0c5454,
+ 0xf3f3abac, 0x5a5a5a5a, 0xa5a5a5a6, 0x605ff9fa, 0x9fa00606, 0xf9fa6060, 0x06059fa0, 0x4241c9ca,
+ 0xbdbe3636, 0xc9ca4242, 0x3635bdbe, 0x5a59d5d6, 0xa5a62a2a, 0xd5d65a5a, 0x2a29a5a6, 0x7e7de1e2,
+ 0x81821e1e, 0xe1e27e7e, 0x1e1d8182, 0x6665999a, 0x999a6666, 0x7e7dabac, 0x81825454, 0xabac7e7e,
+ 0x54538182, 0x24242424, 0xdbdbdbdc, 0x42424242, 0xbdbdbdbe, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606,
+ 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa,
+ 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa,
+ 0xf9f9f9fa, 0x06060000, 0x06060000, 0x06060000, 0x06060000, 0x06060000, 0x06060000, 0x06060000,
+ 0x06060000, 0x06060000, 0x06060000, 0x06060000, 0x06060000, 0xf9fa0000, 0xf9fa0000, 0xf9fa0000,
+ 0xf9fa0000, 0xf9fa0000, 0xf9fa0000, 0xf9fa0000, 0xf9fa0000, 0xf9fa0000, 0xf9fa0000, 0xf9fa0000,
+ 0xf9fa0000, 0x00000606, 0x00000606, 0x00000606, 0x00000606, 0x00000606, 0x00000606, 0x00000606,
+ 0x00000606, 0x00000606, 0x00000606, 0x00000606, 0x00000606, 0xfffff9fa, 0xfffff9fa, 0xfffff9fa,
+ 0xfffff9fa, 0xfffff9fa, 0xfffff9fa, 0xfffff9fa, 0xfffff9fa, 0xfffff9fa, 0xfffff9fa, 0xfffff9fa,
+ 0xfffff9fa, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c,
+ 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4,
+ 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4,
+ 0xf3f3f3f4, 0x0c0c0606, 0x0c0c0606, 0x0c0c0606, 0x0c0c0606, 0x0c0c0606, 0x0c0c0606, 0x0c0c0606,
+ 0x0c0c0606, 0x0c0c0606, 0x0c0c0606, 0x0c0c0606, 0x0c0c0606, 0xf3f3f9fa, 0xf3f3f9fa, 0xf3f3f9fa,
+ 0xf3f3f9fa, 0xf3f3f9fa, 0xf3f3f9fa, 0xf3f3f9fa, 0xf3f3f9fa, 0xf3f3f9fa, 0xf3f3f9fa, 0xf3f3f9fa,
+ 0xf3f3f9fa, 0x06060c0c, 0x06060c0c, 0x06060c0c, 0x06060c0c, 0x06060c0c, 0x06060c0c, 0x06060c0c,
+ 0x06060c0c, 0x06060c0c, 0x06060c0c, 0x06060c0c, 0x06060c0c, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x07070707, 0xf8f8f8f9, 0x07070000, 0xf8f90000, 0x00000707, 0xfffff8f9, 0x0e0e0e0e,
+ 0xf1f1f1f2, 0x15150707, 0xeaeaf8f9, 0x07071515, 0xf8f8eaeb, 0x0e0df1f2, 0xf1f20e0e, 0x1514f8f9,
+ 0xeaeb0707, 0xf8f91515, 0x0706eaeb, 0x1c1c0e0e, 0xe3e3f1f2, 0x0e0e1c1c, 0xf1f1e3e4, 0x1c1c1c1c,
+ 0xe3e3e3e4, 0x23230000, 0xdcdd0000, 0x00002323, 0xffffdcdd, 0x1c1beaeb, 0xe3e41515, 0xeaeb1c1c,
+ 0x1514e3e4, 0x38382323, 0xc7c7dcdd, 0x23233838, 0xdcdcc7c8, 0x2a29f1f2, 0xd5d60e0e, 0xf1f22a2a,
+ 0x0e0dd5d6, 0x38380e0e, 0xc7c7f1f2, 0x0e0e3838, 0xf1f1c7c8, 0x38383838, 0xc7c7c7c8, 0x3f3f0000,
+ 0xc0c10000, 0x00003f3f, 0xffffc0c1, 0x2a29d5d6, 0xd5d62a2a, 0x3837e3e4, 0xc7c81c1c, 0xe3e43838,
+ 0x1c1bc7c8, 0x5b5b2323, 0xa4a4dcdd, 0x23235b5b, 0xdcdca4a5, 0x62623f3f, 0x9d9dc0c1, 0x3f3f6262,
+ 0xc0c09d9e, 0x4d4ceaeb, 0xb2b31515, 0xeaeb4d4d, 0x1514b2b3, 0x62620e0e, 0x9d9df1f2, 0x0e0e6262,
+ 0xf1f19d9e, 0x69696969, 0x96969697, 0x7776f8f9, 0x88890707, 0xf8f97777, 0x07068889, 0x4d4cc0c1,
+ 0xb2b33f3f, 0xc0c14d4d, 0x3f3eb2b3, 0x6968cecf, 0x96973131, 0xcecf6969, 0x31309697, 0x77768889,
+ 0x88897777, 0x2a2a2a2a, 0xd5d5d5d6, 0x4d4d4d4d, 0xb2b2b2b3, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x07070707, 0x07070707, 0x07070707, 0x07070707, 0x07070707, 0x07070707, 0x07070707,
+ 0x07070707, 0x07070707, 0x07070707, 0x07070707, 0x07070707, 0xf8f8f8f9, 0xf8f8f8f9, 0xf8f8f8f9,
+ 0xf8f8f8f9, 0xf8f8f8f9, 0xf8f8f8f9, 0xf8f8f8f9, 0xf8f8f8f9, 0xf8f8f8f9, 0xf8f8f8f9, 0xf8f8f8f9,
+ 0xf8f8f8f9, 0x07070000, 0x07070000, 0x07070000, 0x07070000, 0x07070000, 0x07070000, 0x07070000,
+ 0x07070000, 0x07070000, 0x07070000, 0x07070000, 0x07070000, 0xf8f90000, 0xf8f90000, 0xf8f90000,
+ 0xf8f90000, 0xf8f90000, 0xf8f90000, 0xf8f90000, 0xf8f90000, 0xf8f90000, 0xf8f90000, 0xf8f90000,
+ 0xf8f90000, 0x00000707, 0x00000707, 0x00000707, 0x00000707, 0x00000707, 0x00000707, 0x00000707,
+ 0x00000707, 0x00000707, 0x00000707, 0x00000707, 0x00000707, 0xfffff8f9, 0xfffff8f9, 0xfffff8f9,
+ 0xfffff8f9, 0xfffff8f9, 0xfffff8f9, 0xfffff8f9, 0xfffff8f9, 0xfffff8f9, 0xfffff8f9, 0xfffff8f9,
+ 0xfffff8f9, 0x0e0e0e0e, 0x0e0e0e0e, 0x0e0e0e0e, 0x0e0e0e0e, 0x0e0e0e0e, 0x0e0e0e0e, 0x0e0e0e0e,
+ 0x0e0e0e0e, 0x0e0e0e0e, 0x0e0e0e0e, 0x0e0e0e0e, 0x0e0e0e0e, 0xf1f1f1f2, 0xf1f1f1f2, 0xf1f1f1f2,
+ 0xf1f1f1f2, 0xf1f1f1f2, 0xf1f1f1f2, 0xf1f1f1f2, 0xf1f1f1f2, 0xf1f1f1f2, 0xf1f1f1f2, 0xf1f1f1f2,
+ 0xf1f1f1f2, 0x15150707, 0x15150707, 0x15150707, 0x15150707, 0x15150707, 0x15150707, 0x15150707,
+ 0x15150707, 0x15150707, 0x15150707, 0x15150707, 0x15150707, 0xeaeaf8f9, 0xeaeaf8f9, 0xeaeaf8f9,
+ 0xeaeaf8f9, 0xeaeaf8f9, 0xeaeaf8f9, 0xeaeaf8f9, 0xeaeaf8f9, 0xeaeaf8f9, 0xeaeaf8f9, 0xeaeaf8f9,
+ 0xeaeaf8f9, 0x07071515, 0x07071515, 0x07071515, 0x07071515, 0x07071515, 0x07071515, 0x07071515,
+ 0x07071515, 0x07071515, 0x07071515, 0x07071515, 0x07071515, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x08080808, 0xf7f7f7f8, 0x08080000, 0xf7f80000, 0x00000808, 0xfffff7f8, 0x10101010,
+ 0xefefeff0, 0x10100808, 0xefeff7f8, 0x08081010, 0xf7f7eff0, 0x100feff0, 0xeff01010, 0x1817f7f8,
+ 0xe7e80808, 0xf7f81818, 0x0807e7e8, 0x20201010, 0xdfdfeff0, 0x10102020, 0xefefdfe0, 0x20202020,
+ 0xdfdfdfe0, 0x28280000, 0xd7d80000, 0x00002828, 0xffffd7d8, 0x201fe7e8, 0xdfe01818, 0xe7e82020,
+ 0x1817dfe0, 0x40402828, 0xbfbfd7d8, 0x28284040, 0xd7d7bfc0, 0x302feff0, 0xcfd01010, 0xeff03030,
+ 0x100fcfd0, 0x40401010, 0xbfbfeff0, 0x10104040, 0xefefbfc0, 0x40404040, 0xbfbfbfc0, 0x48480000,
+ 0xb7b80000, 0x00004848, 0xffffb7b8, 0x302fcfd0, 0xcfd03030, 0x403fdfe0, 0xbfc02020, 0xdfe04040,
+ 0x201fbfc0, 0x68682828, 0x9797d7d8, 0x28286868, 0xd7d79798, 0x70704848, 0x8f8fb7b8, 0x48487070,
+ 0xb7b78f90, 0x5857e7e8, 0xa7a81818, 0xe7e85858, 0x1817a7a8, 0x70701010, 0x8f8feff0, 0x10107070,
+ 0xefef8f90, 0x78787878, 0x87878788, 0x5857b7b8, 0xa7a84848, 0xb7b85858, 0x4847a7a8, 0x7877c7c8,
+ 0x87883838, 0xc7c87878, 0x38378788, 0x30303030, 0xcfcfcfd0, 0x58585858, 0xa7a7a7a8, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x08080808, 0x08080808, 0x08080808, 0x08080808, 0x08080808,
+ 0x08080808, 0x08080808, 0x08080808, 0x08080808, 0x08080808, 0x08080808, 0x08080808, 0xf7f7f7f8,
+ 0xf7f7f7f8, 0xf7f7f7f8, 0xf7f7f7f8, 0xf7f7f7f8, 0xf7f7f7f8, 0xf7f7f7f8, 0xf7f7f7f8, 0xf7f7f7f8,
+ 0xf7f7f7f8, 0xf7f7f7f8, 0xf7f7f7f8, 0x08080000, 0x08080000, 0x08080000, 0x08080000, 0x08080000,
+ 0x08080000, 0x08080000, 0x08080000, 0x08080000, 0x08080000, 0x08080000, 0x08080000, 0xf7f80000,
+ 0xf7f80000, 0xf7f80000, 0xf7f80000, 0xf7f80000, 0xf7f80000, 0xf7f80000, 0xf7f80000, 0xf7f80000,
+ 0xf7f80000, 0xf7f80000, 0xf7f80000, 0x00000808, 0x00000808, 0x00000808, 0x00000808, 0x00000808,
+ 0x00000808, 0x00000808, 0x00000808, 0x00000808, 0x00000808, 0x00000808, 0x00000808, 0xfffff7f8,
+ 0xfffff7f8, 0xfffff7f8, 0xfffff7f8, 0xfffff7f8, 0xfffff7f8, 0xfffff7f8, 0xfffff7f8, 0xfffff7f8,
+ 0xfffff7f8, 0xfffff7f8, 0xfffff7f8, 0x10101010, 0x10101010, 0x10101010, 0x10101010, 0x10101010,
+ 0x10101010, 0x10101010, 0x10101010, 0x10101010, 0x10101010, 0x10101010, 0x10101010, 0xefefeff0,
+ 0xefefeff0, 0xefefeff0, 0xefefeff0, 0xefefeff0, 0xefefeff0, 0xefefeff0, 0xefefeff0, 0xefefeff0,
+ 0xefefeff0, 0xefefeff0, 0xefefeff0, 0x10100808, 0x10100808, 0x10100808, 0x10100808, 0x10100808,
+ 0x10100808, 0x10100808, 0x10100808, 0x10100808, 0x10100808, 0x10100808, 0x10100808, 0xefeff7f8,
+ 0xefeff7f8, 0xefeff7f8, 0xefeff7f8, 0xefeff7f8, 0xefeff7f8, 0xefeff7f8, 0xefeff7f8, 0xefeff7f8,
+ 0xefeff7f8, 0xefeff7f8, 0xefeff7f8, 0x08081010, 0x08081010, 0x08081010, 0x08081010, 0x08081010,
+ 0x08081010, 0x08081010, 0x08081010, 0x08081010, 0x08081010, 0x08081010, 0x08081010, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x09090909, 0xf6f6f6f7, 0x09090000, 0xf6f70000, 0x00000909, 0xfffff6f7, 0x12121212,
+ 0xedededee, 0x1b1b0909, 0xe4e4f6f7, 0x09091b1b, 0xf6f6e4e5, 0x1211edee, 0xedee1212, 0x1b1af6f7,
+ 0xe4e50909, 0xf6f71b1b, 0x0908e4e5, 0x24241212, 0xdbdbedee, 0x12122424, 0xededdbdc, 0x24242424,
+ 0xdbdbdbdc, 0x2d2d0000, 0xd2d30000, 0x00002d2d, 0xffffd2d3, 0x2423e4e5, 0xdbdc1b1b, 0xe4e52424,
+ 0x1b1adbdc, 0x48482d2d, 0xb7b7d2d3, 0x2d2d4848, 0xd2d2b7b8, 0x3635edee, 0xc9ca1212, 0xedee3636,
+ 0x1211c9ca, 0x48481212, 0xb7b7edee, 0x12124848, 0xededb7b8, 0x48484848, 0xb7b7b7b8, 0x51510000,
+ 0xaeaf0000, 0x00005151, 0xffffaeaf, 0x3635c9ca, 0xc9ca3636, 0x4847dbdc, 0xb7b82424, 0xdbdc4848,
+ 0x2423b7b8, 0x75752d2d, 0x8a8ad2d3, 0x2d2d7575, 0xd2d28a8b, 0x7e7e5151, 0x8181aeaf, 0x51517e7e,
+ 0xaeae8182, 0x6362e4e5, 0x9c9d1b1b, 0xe4e56363, 0x1b1a9c9d, 0x6362aeaf, 0x9c9d5151, 0xaeaf6363,
+ 0x51509c9d, 0x36363636, 0xc9c9c9ca, 0x6c6c6c6c, 0x93939394, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x09090909, 0x09090909, 0x09090909, 0x09090909, 0x09090909, 0x09090909,
+ 0x09090909, 0x09090909, 0x09090909, 0x09090909, 0x09090909, 0x09090909, 0x09090909, 0xf6f6f6f7,
+ 0xf6f6f6f7, 0xf6f6f6f7, 0xf6f6f6f7, 0xf6f6f6f7, 0xf6f6f6f7, 0xf6f6f6f7, 0xf6f6f6f7, 0xf6f6f6f7,
+ 0xf6f6f6f7, 0xf6f6f6f7, 0xf6f6f6f7, 0xf6f6f6f7, 0x09090000, 0x09090000, 0x09090000, 0x09090000,
+ 0x09090000, 0x09090000, 0x09090000, 0x09090000, 0x09090000, 0x09090000, 0x09090000, 0x09090000,
+ 0x09090000, 0xf6f70000, 0xf6f70000, 0xf6f70000, 0xf6f70000, 0xf6f70000, 0xf6f70000, 0xf6f70000,
+ 0xf6f70000, 0xf6f70000, 0xf6f70000, 0xf6f70000, 0xf6f70000, 0xf6f70000, 0x00000909, 0x00000909,
+ 0x00000909, 0x00000909, 0x00000909, 0x00000909, 0x00000909, 0x00000909, 0x00000909, 0x00000909,
+ 0x00000909, 0x00000909, 0x00000909, 0xfffff6f7, 0xfffff6f7, 0xfffff6f7, 0xfffff6f7, 0xfffff6f7,
+ 0xfffff6f7, 0xfffff6f7, 0xfffff6f7, 0xfffff6f7, 0xfffff6f7, 0xfffff6f7, 0xfffff6f7, 0xfffff6f7,
+ 0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212,
+ 0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212, 0xedededee, 0xedededee, 0xedededee,
+ 0xedededee, 0xedededee, 0xedededee, 0xedededee, 0xedededee, 0xedededee, 0xedededee, 0xedededee,
+ 0xedededee, 0xedededee, 0x1b1b0909, 0x1b1b0909, 0x1b1b0909, 0x1b1b0909, 0x1b1b0909, 0x1b1b0909,
+ 0x1b1b0909, 0x1b1b0909, 0x1b1b0909, 0x1b1b0909, 0x1b1b0909, 0x1b1b0909, 0x1b1b0909, 0xe4e4f6f7,
+ 0xe4e4f6f7, 0xe4e4f6f7, 0xe4e4f6f7, 0xe4e4f6f7, 0xe4e4f6f7, 0xe4e4f6f7, 0xe4e4f6f7, 0xe4e4f6f7,
+ 0xe4e4f6f7, 0xe4e4f6f7, 0xe4e4f6f7, 0xe4e4f6f7, 0x09091b1b, 0x09091b1b, 0x09091b1b, 0x09091b1b,
+ 0x09091b1b, 0x09091b1b, 0x09091b1b, 0x09091b1b, 0x09091b1b, 0x09091b1b, 0x09091b1b, 0x09091b1b,
+ 0x09091b1b, 0xf6f6e4e5, 0xf6f6e4e5, 0xf6f6e4e5, 0xf6f6e4e5, 0xf6f6e4e5, 0xf6f6e4e5, 0xf6f6e4e5,
+ 0xf6f6e4e5, 0xf6f6e4e5, 0xf6f6e4e5, 0xf6f6e4e5, 0xf6f6e4e5, 0xf6f6e4e5, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x02020202, 0xfdfdfdfe, 0x03030000, 0xfcfd0000, 0x00000303, 0xfffffcfd, 0x06060606,
+ 0xf9f9f9fa, 0x07070000, 0xf8f90000, 0x00000707, 0xfffff8f9, 0x0504fafb, 0xfafb0505, 0xfafb0505,
+ 0x0504fafb, 0x0b0b0606, 0xf4f4f9fa, 0x06060b0b, 0xf9f9f4f5, 0x08080000, 0xf7f80000, 0x00000808,
+ 0xfffff7f8, 0x0b0b0b0b, 0xf4f4f4f5, 0x0c0c0000, 0xf3f40000, 0x00000c0c, 0xfffff3f4, 0x11110c0c,
+ 0xeeeef3f4, 0x0c0c1111, 0xf3f3eeef, 0x11111111, 0xeeeeeeef, 0x12120606, 0xededf9fa, 0x06061212,
+ 0xf9f9edee, 0x0b0af7f8, 0xf4f50808, 0xf7f80b0b, 0x0807f4f5, 0x0f0f0000, 0xf0f10000, 0x00000f0f,
+ 0xfffff0f1, 0x14140000, 0xebec0000, 0x00001414, 0xffffebec, 0x19191212, 0xe6e6edee, 0x12121919,
+ 0xedede6e7, 0x19190b0b, 0xe6e6f4f5, 0x0b0b1919, 0xf4f4e6e7, 0x19191919, 0xe6e6e6e7, 0x0e0df1f2,
+ 0xf1f20e0e, 0xf1f20e0e, 0x0e0df1f2, 0x1a1a0000, 0xe5e60000, 0x00001a1a, 0xffffe5e6, 0x1211f4f5,
+ 0xedee0b0b, 0xf4f51212, 0x0b0aedee, 0x1615f8f9, 0xe9ea0707, 0xf8f91616, 0x0706e9ea, 0x22221a1a,
+ 0xdddde5e6, 0x1a1a2222, 0xe5e5ddde, 0x22221212, 0xddddedee, 0x12122222, 0xededddde, 0x22222222,
+ 0xddddddde, 0x23230b0b, 0xdcdcf4f5, 0x0b0b2323, 0xf4f4dcdd, 0x1d1d0000, 0xe2e30000, 0x00001d1d,
+ 0xffffe2e3, 0x1615eced, 0xe9ea1313, 0xeced1616, 0x1312e9ea, 0x1a19f0f1, 0xe5e60f0f, 0xf0f11a1a,
+ 0x0f0ee5e6, 0x25250000, 0xdadb0000, 0x00002525, 0xffffdadb, 0x2c2c1b1b, 0xd3d3e4e5, 0x1b1b2c2c,
+ 0xe4e4d3d4, 0x2c2c2424, 0xd3d3dbdc, 0x24242c2c, 0xdbdbd3d4, 0x2c2c1212, 0xd3d3edee, 0x12122c2c,
+ 0xededd3d4, 0x2120f5f6, 0xdedf0a0a, 0xf5f62121, 0x0a09dedf, 0x2d2d2d2d, 0xd2d2d2d3, 0x00000000,
+ 0x00000000, 0x02020202, 0xfdfdfdfe, 0x03030000, 0xfcfd0000, 0x00000303, 0xfffffcfd, 0x06060606,
+ 0xf9f9f9fa, 0x07070000, 0xf8f90000, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x03030000, 0xfcfd0000,
+ 0x00000303, 0xfffffcfd, 0x06060606, 0xf9f9f9fa, 0x07070000, 0xf8f90000, 0x00000000, 0x02020202,
+ 0xfdfdfdfe, 0x03030000, 0xfcfd0000, 0x00000303, 0xfffffcfd, 0x06060606, 0xf9f9f9fa, 0x07070000,
+ 0xf8f90000, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x03030000, 0xfcfd0000, 0x00000303, 0xfffffcfd,
+ 0x06060606, 0xf9f9f9fa, 0x07070000, 0xf8f90000, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x03030000,
+ 0xfcfd0000, 0x00000303, 0xfffffcfd, 0x06060606, 0xf9f9f9fa, 0x07070000, 0xf8f90000, 0x00000000,
+ 0x02020202, 0xfdfdfdfe, 0x03030000, 0xfcfd0000, 0x00000303, 0xfffffcfd, 0x06060606, 0xf9f9f9fa,
+ 0x07070000, 0xf8f90000, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x03030000, 0xfcfd0000, 0x00000303,
+ 0xfffffcfd, 0x06060606, 0xf9f9f9fa, 0x07070000, 0xf8f90000, 0x00000000, 0x02020202, 0xfdfdfdfe,
+ 0x03030000, 0xfcfd0000, 0x00000303, 0xfffffcfd, 0x06060606, 0xf9f9f9fa, 0x07070000, 0xf8f90000,
+ 0x00000000, 0x02020202, 0xfdfdfdfe, 0x03030000, 0xfcfd0000, 0x00000303, 0xfffffcfd, 0x06060606,
+ 0xf9f9f9fa, 0x07070000, 0xf8f90000, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x03030000, 0xfcfd0000,
+ 0x00000303, 0xfffffcfd, 0x06060606, 0xf9f9f9fa, 0x07070000, 0xf8f90000, 0x00000000, 0x02020202,
+ 0xfdfdfdfe, 0x03030000, 0xfcfd0000, 0x00000303, 0xfffffcfd, 0x06060606, 0xf9f9f9fa, 0x07070000,
+ 0xf8f90000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe, 0x02020202, 0xfdfdfdfe, 0x06060606,
+ 0xf9f9f9fa, 0x06060000, 0xf9fa0000, 0x00000606, 0xfffff9fa, 0x0403fbfc, 0xfbfc0404, 0xf9fa0a0a,
+ 0x0605f5f6, 0xf3f40000, 0x0c0c0000, 0xf3f3f9fa, 0xf3f40606, 0x0c0bf9fa, 0x0c0c0606, 0xfffff1f2,
+ 0x00000e0e, 0x0c0c0c0c, 0xf3f3f3f4, 0xedee0000, 0x12120000, 0xf3f40e0e, 0x0c0bf1f2, 0xf9f9edee,
+ 0xf9fa1212, 0x0605edee, 0x06061212, 0xededf5f6, 0xedee0a0a, 0x1211f5f6, 0x12120a0a, 0xffffe9ea,
+ 0x00001616, 0xe7e80000, 0x18180000, 0xf3f3e9ea, 0xf3f41616, 0x0c0be9ea, 0x0c0c1616, 0xe7e7f7f8,
+ 0xe7e80808, 0x1817f7f8, 0x18180808, 0xf9f9e5e6, 0xf9fa1a1a, 0x0605e5e6, 0x06061a1a, 0xffffe3e4,
+ 0x00001c1c, 0x14141414, 0xebebebec, 0xe5e5f1f2, 0x1a1a0e0e, 0xf3f3e1e2, 0x0c0c1e1e, 0xdfdff5f6,
+ 0x20200a0a, 0xdfdfedee, 0x20201212, 0xe5e5e5e6, 0x1a1a1a1a, 0xebebddde, 0x14142222, 0xf3f3d9da,
+ 0x0c0c2626, 0xdfdfdfe0, 0x20202020, 0x20202020, 0xd7d7e9ea, 0xddddddde, 0x22222222, 0x00000000,
+ 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa,
+ 0x06060000, 0xf9fa0000, 0x00000606, 0xfffff9fa, 0x00000000, 0x02020000, 0xfdfe0000, 0x00000202,
+ 0xfffffdfe, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x06060000, 0xf9fa0000, 0x00000606,
+ 0xfffff9fa, 0x00000000, 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe, 0x02020202, 0xfdfdfdfe,
+ 0x06060606, 0xf9f9f9fa, 0x06060000, 0xf9fa0000, 0x00000606, 0xfffff9fa, 0x00000000, 0x02020000,
+ 0xfdfe0000, 0x00000202, 0xfffffdfe, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x06060000,
+ 0xf9fa0000, 0x00000606, 0xfffff9fa, 0x00000000, 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe,
+ 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x06060000, 0xf9fa0000, 0x00000606, 0xfffff9fa,
+ 0x00000000, 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe, 0x02020202, 0xfdfdfdfe, 0x06060606,
+ 0xf9f9f9fa, 0x06060000, 0xf9fa0000, 0x00000606, 0xfffff9fa, 0x00000000, 0x02020000, 0xfdfe0000,
+ 0x00000202, 0xfffffdfe, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x06060000, 0xf9fa0000,
+ 0x00000606, 0xfffff9fa, 0x00000000, 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe, 0x02020202,
+ 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x06060000, 0xf9fa0000, 0x00000606, 0xfffff9fa, 0x00000000,
+ 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa,
+ 0x06060000, 0xf9fa0000, 0x00000606, 0xfffff9fa, 0x00000000, 0x02020000, 0xfdfe0000, 0x00000202,
+ 0xfffffdfe, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x06060000, 0xf9fa0000, 0x00000606,
+ 0xfffff9fa, 0x00000000, 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe, 0x02020202, 0xfdfdfdfe,
+ 0x06060606, 0xf9f9f9fa, 0x06060000, 0xf9fa0000, 0x00000606, 0xfffff9fa, 0x00000000, 0x02020000,
+ 0xfdfe0000, 0x00000202, 0xfffffdfe, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x06060000,
+ 0xf9fa0000, 0x00000606, 0xfffff9fa, 0x00000000, 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe,
+ 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x06060000, 0xf9fa0000, 0x00000606, 0xfffff9fa,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe, 0x04040404, 0xfbfbfbfc, 0x0a0a0a0a,
+ 0xf5f5f5f6, 0x0a0a0000, 0xf5f60000, 0x00000a0a, 0xfffff5f6, 0x0605f9fa, 0xf9fa0606, 0xf7f80e0e,
+ 0x0807f1f2, 0xffffedee, 0x00001212, 0xeff00a0a, 0x100ff5f6, 0xe7e80000, 0x18180000, 0xf7f7e7e8,
+ 0xf7f81818, 0x0807e7e8, 0x08081818, 0x12121212, 0xedededee, 0xeff01414, 0x100febec, 0xe5e5f1f2,
+ 0xe5e60e0e, 0x1a19f1f2, 0x1a1a0e0e, 0xffffe1e2, 0x00001e1e, 0xddde0000, 0x22220000, 0xf7f7ddde,
+ 0xf7f82222, 0x0807ddde, 0x08082222, 0xedede1e2, 0xedee1e1e, 0x1211e1e2, 0x12121e1e, 0xddddf5f6,
+ 0xddde0a0a, 0x2221f5f6, 0x22220a0a, 0xddddebec, 0x22221414, 0xffffd7d8, 0x00002828, 0x1e1e1e1e,
+ 0xe1e1e1e2, 0xededd7d8, 0x12122828, 0xd3d40000, 0x2c2c0000, 0xd3d3eff0, 0x2c2c1010, 0xdbdbdbdc,
+ 0xdbdbdbdc, 0x24242424, 0xd3d3e5e6, 0x2c2c1a1a, 0xe5e5d1d2, 0x1a1a2e2e, 0xededcbcc, 0x12123434,
+ 0xc9c9ebec, 0xd3d3d3d4, 0x2c2c2c2c, 0xc9c9dfe0, 0xd1d1d1d2, 0xd1d1d1d2, 0x2e2e2e2e, 0x00000000,
+ 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe, 0x04040404, 0xfbfbfbfc, 0x0a0a0a0a, 0xf5f5f5f6,
+ 0x0a0a0000, 0xf5f60000, 0x00000a0a, 0xfffff5f6, 0x00000000, 0x02020000, 0xfdfe0000, 0x00000202,
+ 0xfffffdfe, 0x04040404, 0xfbfbfbfc, 0x0a0a0a0a, 0xf5f5f5f6, 0x0a0a0000, 0xf5f60000, 0x00000a0a,
+ 0xfffff5f6, 0x00000000, 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe, 0x04040404, 0xfbfbfbfc,
+ 0x0a0a0a0a, 0xf5f5f5f6, 0x0a0a0000, 0xf5f60000, 0x00000a0a, 0xfffff5f6, 0x00000000, 0x02020000,
+ 0xfdfe0000, 0x00000202, 0xfffffdfe, 0x04040404, 0xfbfbfbfc, 0x0a0a0a0a, 0xf5f5f5f6, 0x0a0a0000,
+ 0xf5f60000, 0x00000a0a, 0xfffff5f6, 0x00000000, 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe,
+ 0x04040404, 0xfbfbfbfc, 0x0a0a0a0a, 0xf5f5f5f6, 0x0a0a0000, 0xf5f60000, 0x00000a0a, 0xfffff5f6,
+ 0x00000000, 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe, 0x04040404, 0xfbfbfbfc, 0x0a0a0a0a,
+ 0xf5f5f5f6, 0x0a0a0000, 0xf5f60000, 0x00000a0a, 0xfffff5f6, 0x00000000, 0x02020000, 0xfdfe0000,
+ 0x00000202, 0xfffffdfe, 0x04040404, 0xfbfbfbfc, 0x0a0a0a0a, 0xf5f5f5f6, 0x0a0a0000, 0xf5f60000,
+ 0x00000a0a, 0xfffff5f6, 0x00000000, 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe, 0x04040404,
+ 0xfbfbfbfc, 0x0a0a0a0a, 0xf5f5f5f6, 0x0a0a0000, 0xf5f60000, 0x00000a0a, 0xfffff5f6, 0x00000000,
+ 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe, 0x04040404, 0xfbfbfbfc, 0x0a0a0a0a, 0xf5f5f5f6,
+ 0x0a0a0000, 0xf5f60000, 0x00000a0a, 0xfffff5f6, 0x00000000, 0x02020000, 0xfdfe0000, 0x00000202,
+ 0xfffffdfe, 0x04040404, 0xfbfbfbfc, 0x0a0a0a0a, 0xf5f5f5f6, 0x0a0a0000, 0xf5f60000, 0x00000a0a,
+ 0xfffff5f6, 0x00000000, 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe, 0x04040404, 0xfbfbfbfc,
+ 0x0a0a0a0a, 0xf5f5f5f6, 0x0a0a0000, 0xf5f60000, 0x00000a0a, 0xfffff5f6, 0x00000000, 0x02020000,
+ 0xfdfe0000, 0x00000202, 0xfffffdfe, 0x04040404, 0xfbfbfbfc, 0x0a0a0a0a, 0xf5f5f5f6, 0x0a0a0000,
+ 0xf5f60000, 0x00000a0a, 0xfffff5f6, 0x00000000, 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe,
+ 0x04040404, 0xfbfbfbfc, 0x0a0a0a0a, 0xf5f5f5f6, 0x0a0a0000, 0xf5f60000, 0x00000a0a, 0xfffff5f6,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x04040000, 0xfbfc0000, 0x00000404, 0xfffffbfc, 0x04040404, 0xfbfbfbfc, 0x0c0c0c0c,
+ 0xf3f3f3f4, 0x0c0c0000, 0xf3f40000, 0x00000c0c, 0xfffff3f4, 0x0807f7f8, 0xf7f80808, 0xeff00808,
+ 0x100ff7f8, 0xe7e80000, 0x18180000, 0xf7f7e7e8, 0xf7f81818, 0x0807e7e8, 0x08081818, 0xeff01414,
+ 0x100febec, 0xffffe3e4, 0x00001c1c, 0xe7e7eff0, 0xe7e81010, 0x1817eff0, 0x18181010, 0xdfe00000,
+ 0x20200000, 0xefefe3e4, 0xeff01c1c, 0x100fe3e4, 0x10101c1c, 0xdfdff7f8, 0xdfe00808, 0xf7f7dfe0,
+ 0xf7f82020, 0x0807dfe0, 0x08082020, 0x201ff7f8, 0x20200808, 0x18181818, 0xe7e7e7e8, 0xe7e81818,
+ 0x1817e7e8, 0xdfdfebec, 0x20201414, 0xffffd7d8, 0x00002828, 0xefefd7d8, 0x10102828, 0xd3d40000,
+ 0xd3d40000, 0xffffd3d4, 0x00002c2c, 0x2c2c0000, 0x2c2c0000, 0xdfdfdfe0, 0x20202020, 0xd3d3eff0,
+ 0x2c2c1010, 0xd3d3e7e8, 0xe7e7d3d4, 0x18182c2c, 0x2c2c1818, 0xefefcfd0, 0x10103030, 0xdbdbdbdc,
+ 0xdbdbdbdc, 0x24242424, 0x24242424, 0xcbcbebec, 0x28282828, 0xd7d7d7d8, 0xcbcbdfe0, 0x00000000,
+ 0x04040000, 0xfbfc0000, 0x00000404, 0xfffffbfc, 0x04040404, 0xfbfbfbfc, 0x0c0c0c0c, 0xf3f3f3f4,
+ 0x0c0c0000, 0xf3f40000, 0x00000c0c, 0xfffff3f4, 0x00000000, 0x04040000, 0xfbfc0000, 0x00000404,
+ 0xfffffbfc, 0x04040404, 0xfbfbfbfc, 0x0c0c0c0c, 0xf3f3f3f4, 0x0c0c0000, 0xf3f40000, 0x00000c0c,
+ 0xfffff3f4, 0x00000000, 0x04040000, 0xfbfc0000, 0x00000404, 0xfffffbfc, 0x04040404, 0xfbfbfbfc,
+ 0x0c0c0c0c, 0xf3f3f3f4, 0x0c0c0000, 0xf3f40000, 0x00000c0c, 0xfffff3f4, 0x00000000, 0x04040000,
+ 0xfbfc0000, 0x00000404, 0xfffffbfc, 0x04040404, 0xfbfbfbfc, 0x0c0c0c0c, 0xf3f3f3f4, 0x0c0c0000,
+ 0xf3f40000, 0x00000c0c, 0xfffff3f4, 0x00000000, 0x04040000, 0xfbfc0000, 0x00000404, 0xfffffbfc,
+ 0x04040404, 0xfbfbfbfc, 0x0c0c0c0c, 0xf3f3f3f4, 0x0c0c0000, 0xf3f40000, 0x00000c0c, 0xfffff3f4,
+ 0x00000000, 0x04040000, 0xfbfc0000, 0x00000404, 0xfffffbfc, 0x04040404, 0xfbfbfbfc, 0x0c0c0c0c,
+ 0xf3f3f3f4, 0x0c0c0000, 0xf3f40000, 0x00000c0c, 0xfffff3f4, 0x00000000, 0x04040000, 0xfbfc0000,
+ 0x00000404, 0xfffffbfc, 0x04040404, 0xfbfbfbfc, 0x0c0c0c0c, 0xf3f3f3f4, 0x0c0c0000, 0xf3f40000,
+ 0x00000c0c, 0xfffff3f4, 0x00000000, 0x04040000, 0xfbfc0000, 0x00000404, 0xfffffbfc, 0x04040404,
+ 0xfbfbfbfc, 0x0c0c0c0c, 0xf3f3f3f4, 0x0c0c0000, 0xf3f40000, 0x00000c0c, 0xfffff3f4, 0x00000000,
+ 0x04040000, 0xfbfc0000, 0x00000404, 0xfffffbfc, 0x04040404, 0xfbfbfbfc, 0x0c0c0c0c, 0xf3f3f3f4,
+ 0x0c0c0000, 0xf3f40000, 0x00000c0c, 0xfffff3f4, 0x00000000, 0x04040000, 0xfbfc0000, 0x00000404,
+ 0xfffffbfc, 0x04040404, 0xfbfbfbfc, 0x0c0c0c0c, 0xf3f3f3f4, 0x0c0c0000, 0xf3f40000, 0x00000c0c,
+ 0xfffff3f4, 0x00000000, 0x04040000, 0xfbfc0000, 0x00000404, 0xfffffbfc, 0x04040404, 0xfbfbfbfc,
+ 0x0c0c0c0c, 0xf3f3f3f4, 0x0c0c0000, 0xf3f40000, 0x00000c0c, 0xfffff3f4, 0x00000000, 0x04040000,
+ 0xfbfc0000, 0x00000404, 0xfffffbfc, 0x04040404, 0xfbfbfbfc, 0x0c0c0c0c, 0xf3f3f3f4, 0x0c0c0000,
+ 0xf3f40000, 0x00000c0c, 0xfffff3f4, 0x00000000, 0x04040000, 0xfbfc0000, 0x00000404, 0xfffffbfc,
+ 0x04040404, 0xfbfbfbfc, 0x0c0c0c0c, 0xf3f3f3f4, 0x0c0c0000, 0xf3f40000, 0x00000c0c, 0xfffff3f4,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414,
+ 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec,
+ 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606,
+ 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e,
+ 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4,
+ 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202,
+ 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020,
+ 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa,
+ 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2,
+ 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414,
+ 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe,
+ 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0,
+ 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c,
+ 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000,
+ 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec,
+ 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606,
+ 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e,
+ 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4,
+ 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202,
+ 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020,
+ 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa,
+ 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414,
+ 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec,
+ 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606,
+ 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e,
+ 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4,
+ 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202,
+ 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020,
+ 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa,
+ 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2,
+ 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414,
+ 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe,
+ 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0,
+ 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c,
+ 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000,
+ 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec,
+ 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606,
+ 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e,
+ 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4,
+ 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202,
+ 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020,
+ 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa,
+ 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414,
+ 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec,
+ 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606,
+ 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e,
+ 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4,
+ 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202,
+ 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020,
+ 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa,
+ 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2,
+ 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414,
+ 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe,
+ 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0,
+ 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c,
+ 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000,
+ 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec,
+ 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606,
+ 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e,
+ 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4,
+ 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202,
+ 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020,
+ 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa,
+ 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414,
+ 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec,
+ 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606,
+ 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e,
+ 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4,
+ 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202,
+ 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020,
+ 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa,
+ 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2,
+ 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414,
+ 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe,
+ 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0,
+ 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c,
+ 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000,
+ 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec,
+ 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606,
+ 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e,
+ 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4,
+ 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202,
+ 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020,
+ 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x06060606, 0xf9f9f9fa,
+ 0x0c0c0c0c, 0xf3f3f3f4, 0x14141414, 0xebebebec, 0x20202020, 0xdfdfdfe0, 0x2e2e2e2e, 0xd1d1d1d2,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
+};
+
+
+const uint32 Indeo3::correctionhighorder[] = {
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x0302feff, 0xfcfd0101,
+ 0xfeff0303, 0x0100fcfd, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x0302feff, 0xfcfd0101, 0xfeff0303,
+ 0x0100fcfd, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x0302feff, 0xfcfd0101, 0xfeff0303, 0x0100fcfd,
+ 0x00000000, 0x02020202, 0xfdfdfdfe, 0x0302feff, 0xfcfd0101, 0xfeff0303, 0x0100fcfd, 0x00000000,
+ 0x02020202, 0xfdfdfdfe, 0x0302feff, 0xfcfd0101, 0xfeff0303, 0x0100fcfd, 0x00000000, 0x02020202,
+ 0xfdfdfdfe, 0x0302feff, 0xfcfd0101, 0xfeff0303, 0x0100fcfd, 0x00000000, 0x02020202, 0xfdfdfdfe,
+ 0x0302feff, 0xfcfd0101, 0xfeff0303, 0x0100fcfd, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00000000,
+ 0x03030303, 0xfcfcfcfd, 0x0403feff, 0xfbfc0101, 0xfeff0404, 0x0100fbfc, 0x07070707, 0xf8f8f8f9,
+ 0x00000000, 0x03030303, 0xfcfcfcfd, 0x0403feff, 0xfbfc0101, 0xfeff0404, 0x0100fbfc, 0x07070707,
+ 0xf8f8f8f9, 0x00000000, 0x03030303, 0xfcfcfcfd, 0x0403feff, 0xfbfc0101, 0xfeff0404, 0x0100fbfc,
+ 0x07070707, 0xf8f8f8f9, 0x00000000, 0x03030303, 0xfcfcfcfd, 0x0403feff, 0xfbfc0101, 0xfeff0404,
+ 0x0100fbfc, 0x07070707, 0xf8f8f8f9, 0x00000000, 0x03030303, 0xfcfcfcfd, 0x0403feff, 0xfbfc0101,
+ 0xfeff0404, 0x0100fbfc, 0x07070707, 0xf8f8f8f9, 0x00000000, 0x03030303, 0xfcfcfcfd, 0x0403feff,
+ 0xfbfc0101, 0xfeff0404, 0x0100fbfc, 0x07070707, 0xf8f8f8f9, 0x00000000, 0x03030303, 0xfcfcfcfd,
+ 0x0403feff, 0xfbfc0101, 0xfeff0404, 0x0100fbfc, 0x07070707, 0xf8f8f8f9, 0x00000000, 0x03030303,
+ 0xfcfcfcfd, 0x0403feff, 0xfbfc0101, 0xfeff0404, 0x0100fbfc, 0x07070707, 0xf8f8f8f9, 0x00000000,
+ 0x03030303, 0xfcfcfcfd, 0x0403feff, 0xfbfc0101, 0xfeff0404, 0x0100fbfc, 0x07070707, 0xf8f8f8f9,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00000000, 0x04040404, 0xfbfbfbfc,
+ 0x0504feff, 0xfafb0101, 0xfeff0505, 0x0100fafb, 0x0a0a0303, 0xf5f5fcfd, 0x03030a0a, 0x00000000,
+ 0x04040404, 0xfbfbfbfc, 0x0504feff, 0xfafb0101, 0xfeff0505, 0x0100fafb, 0x0a0a0303, 0xf5f5fcfd,
+ 0x03030a0a, 0x00000000, 0x04040404, 0xfbfbfbfc, 0x0504feff, 0xfafb0101, 0xfeff0505, 0x0100fafb,
+ 0x0a0a0303, 0xf5f5fcfd, 0x03030a0a, 0x00000000, 0x04040404, 0xfbfbfbfc, 0x0504feff, 0xfafb0101,
+ 0xfeff0505, 0x0100fafb, 0x0a0a0303, 0xf5f5fcfd, 0x03030a0a, 0x00000000, 0x04040404, 0xfbfbfbfc,
+ 0x0504feff, 0xfafb0101, 0xfeff0505, 0x0100fafb, 0x0a0a0303, 0xf5f5fcfd, 0x03030a0a, 0x00000000,
+ 0x04040404, 0xfbfbfbfc, 0x0504feff, 0xfafb0101, 0xfeff0505, 0x0100fafb, 0x0a0a0303, 0xf5f5fcfd,
+ 0x03030a0a, 0x00000000, 0x04040404, 0xfbfbfbfc, 0x0504feff, 0xfafb0101, 0xfeff0505, 0x0100fafb,
+ 0x0a0a0303, 0xf5f5fcfd, 0x03030a0a, 0x00000000, 0x04040404, 0xfbfbfbfc, 0x0504feff, 0xfafb0101,
+ 0xfeff0505, 0x0100fafb, 0x0a0a0303, 0xf5f5fcfd, 0x03030a0a, 0x00000000, 0x04040404, 0xfbfbfbfc,
+ 0x0504feff, 0xfafb0101, 0xfeff0505, 0x0100fafb, 0x0a0a0303, 0xf5f5fcfd, 0x03030a0a, 0x00000000,
+ 0x04040404, 0xfbfbfbfc, 0x0504feff, 0xfafb0101, 0xfeff0505, 0x0100fafb, 0x0a0a0303, 0xf5f5fcfd,
+ 0x03030a0a, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00000000, 0x05050505, 0xfafafafb, 0x0706fdfe, 0xf8f90202,
+ 0xfdfe0707, 0x0201f8f9, 0x0b0b0b0b, 0xf4f4f4f5, 0x0d0d0303, 0xf2f2fcfd, 0x00000000, 0x05050505,
+ 0xfafafafb, 0x0706fdfe, 0xf8f90202, 0xfdfe0707, 0x0201f8f9, 0x0b0b0b0b, 0xf4f4f4f5, 0x0d0d0303,
+ 0xf2f2fcfd, 0x00000000, 0x05050505, 0xfafafafb, 0x0706fdfe, 0xf8f90202, 0xfdfe0707, 0x0201f8f9,
+ 0x0b0b0b0b, 0xf4f4f4f5, 0x0d0d0303, 0xf2f2fcfd, 0x00000000, 0x05050505, 0xfafafafb, 0x0706fdfe,
+ 0xf8f90202, 0xfdfe0707, 0x0201f8f9, 0x0b0b0b0b, 0xf4f4f4f5, 0x0d0d0303, 0xf2f2fcfd, 0x00000000,
+ 0x05050505, 0xfafafafb, 0x0706fdfe, 0xf8f90202, 0xfdfe0707, 0x0201f8f9, 0x0b0b0b0b, 0xf4f4f4f5,
+ 0x0d0d0303, 0xf2f2fcfd, 0x00000000, 0x05050505, 0xfafafafb, 0x0706fdfe, 0xf8f90202, 0xfdfe0707,
+ 0x0201f8f9, 0x0b0b0b0b, 0xf4f4f4f5, 0x0d0d0303, 0xf2f2fcfd, 0x00000000, 0x05050505, 0xfafafafb,
+ 0x0706fdfe, 0xf8f90202, 0xfdfe0707, 0x0201f8f9, 0x0b0b0b0b, 0xf4f4f4f5, 0x0d0d0303, 0xf2f2fcfd,
+ 0x00000000, 0x05050505, 0xfafafafb, 0x0706fdfe, 0xf8f90202, 0xfdfe0707, 0x0201f8f9, 0x0b0b0b0b,
+ 0xf4f4f4f5, 0x0d0d0303, 0xf2f2fcfd, 0x00000000, 0x05050505, 0xfafafafb, 0x0706fdfe, 0xf8f90202,
+ 0xfdfe0707, 0x0201f8f9, 0x0b0b0b0b, 0xf4f4f4f5, 0x0d0d0303, 0xf2f2fcfd, 0x00000000, 0x05050505,
+ 0xfafafafb, 0x0706fdfe, 0xf8f90202, 0xfdfe0707, 0x0201f8f9, 0x0b0b0b0b, 0xf4f4f4f5, 0x0d0d0303,
+ 0xf2f2fcfd, 0x00000000, 0x05050505, 0xfafafafb, 0x0706fdfe, 0xf8f90202, 0xfdfe0707, 0x0201f8f9,
+ 0x0b0b0b0b, 0xf4f4f4f5, 0x0d0d0303, 0xf2f2fcfd, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00000000, 0x06060606, 0xf9f9f9fa,
+ 0x0807fdfe, 0xf7f80202, 0xfdfe0808, 0x0201f7f8, 0x0d0d0d0d, 0xf2f2f2f3, 0x0f0f0404, 0xf0f0fbfc,
+ 0x04040f0f, 0x00000000, 0x06060606, 0xf9f9f9fa, 0x0807fdfe, 0xf7f80202, 0xfdfe0808, 0x0201f7f8,
+ 0x0d0d0d0d, 0xf2f2f2f3, 0x0f0f0404, 0xf0f0fbfc, 0x04040f0f, 0x00000000, 0x06060606, 0xf9f9f9fa,
+ 0x0807fdfe, 0xf7f80202, 0xfdfe0808, 0x0201f7f8, 0x0d0d0d0d, 0xf2f2f2f3, 0x0f0f0404, 0xf0f0fbfc,
+ 0x04040f0f, 0x00000000, 0x06060606, 0xf9f9f9fa, 0x0807fdfe, 0xf7f80202, 0xfdfe0808, 0x0201f7f8,
+ 0x0d0d0d0d, 0xf2f2f2f3, 0x0f0f0404, 0xf0f0fbfc, 0x04040f0f, 0x00000000, 0x06060606, 0xf9f9f9fa,
+ 0x0807fdfe, 0xf7f80202, 0xfdfe0808, 0x0201f7f8, 0x0d0d0d0d, 0xf2f2f2f3, 0x0f0f0404, 0xf0f0fbfc,
+ 0x04040f0f, 0x00000000, 0x06060606, 0xf9f9f9fa, 0x0807fdfe, 0xf7f80202, 0xfdfe0808, 0x0201f7f8,
+ 0x0d0d0d0d, 0xf2f2f2f3, 0x0f0f0404, 0xf0f0fbfc, 0x04040f0f, 0x00000000, 0x06060606, 0xf9f9f9fa,
+ 0x0807fdfe, 0xf7f80202, 0xfdfe0808, 0x0201f7f8, 0x0d0d0d0d, 0xf2f2f2f3, 0x0f0f0404, 0xf0f0fbfc,
+ 0x04040f0f, 0x00000000, 0x06060606, 0xf9f9f9fa, 0x0807fdfe, 0xf7f80202, 0xfdfe0808, 0x0201f7f8,
+ 0x0d0d0d0d, 0xf2f2f2f3, 0x0f0f0404, 0xf0f0fbfc, 0x04040f0f, 0x00000000, 0x06060606, 0xf9f9f9fa,
+ 0x0807fdfe, 0xf7f80202, 0xfdfe0808, 0x0201f7f8, 0x0d0d0d0d, 0xf2f2f2f3, 0x0f0f0404, 0xf0f0fbfc,
+ 0x04040f0f, 0x00000000, 0x06060606, 0xf9f9f9fa, 0x0807fdfe, 0xf7f80202, 0xfdfe0808, 0x0201f7f8,
+ 0x0d0d0d0d, 0xf2f2f2f3, 0x0f0f0404, 0xf0f0fbfc, 0x04040f0f, 0x00000000, 0x06060606, 0xf9f9f9fa,
+ 0x0807fdfe, 0xf7f80202, 0xfdfe0808, 0x0201f7f8, 0x0d0d0d0d, 0xf2f2f2f3, 0x0f0f0404, 0xf0f0fbfc,
+ 0x04040f0f, 0x00000000, 0x06060606, 0xf9f9f9fa, 0x0807fdfe, 0xf7f80202, 0xfdfe0808, 0x0201f7f8,
+ 0x0d0d0d0d, 0xf2f2f2f3, 0x0f0f0404, 0xf0f0fbfc, 0x04040f0f, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00000000, 0x07070707, 0xf8f8f8f9,
+ 0x0a09fcfd, 0xf5f60303, 0xfcfd0a0a, 0x0302f5f6, 0x10101010, 0xefefeff0, 0x12120505, 0xededfafb,
+ 0x05051212, 0x00000000, 0x07070707, 0xf8f8f8f9, 0x0a09fcfd, 0xf5f60303, 0xfcfd0a0a, 0x0302f5f6,
+ 0x10101010, 0xefefeff0, 0x12120505, 0xededfafb, 0x05051212, 0x00000000, 0x07070707, 0xf8f8f8f9,
+ 0x0a09fcfd, 0xf5f60303, 0xfcfd0a0a, 0x0302f5f6, 0x10101010, 0xefefeff0, 0x12120505, 0xededfafb,
+ 0x05051212, 0x00000000, 0x07070707, 0xf8f8f8f9, 0x0a09fcfd, 0xf5f60303, 0xfcfd0a0a, 0x0302f5f6,
+ 0x10101010, 0xefefeff0, 0x12120505, 0xededfafb, 0x05051212, 0x00000000, 0x07070707, 0xf8f8f8f9,
+ 0x0a09fcfd, 0xf5f60303, 0xfcfd0a0a, 0x0302f5f6, 0x10101010, 0xefefeff0, 0x12120505, 0xededfafb,
+ 0x05051212, 0x00000000, 0x07070707, 0xf8f8f8f9, 0x0a09fcfd, 0xf5f60303, 0xfcfd0a0a, 0x0302f5f6,
+ 0x10101010, 0xefefeff0, 0x12120505, 0xededfafb, 0x05051212, 0x00000000, 0x07070707, 0xf8f8f8f9,
+ 0x0a09fcfd, 0xf5f60303, 0xfcfd0a0a, 0x0302f5f6, 0x10101010, 0xefefeff0, 0x12120505, 0xededfafb,
+ 0x05051212, 0x00000000, 0x07070707, 0xf8f8f8f9, 0x0a09fcfd, 0xf5f60303, 0xfcfd0a0a, 0x0302f5f6,
+ 0x10101010, 0xefefeff0, 0x12120505, 0xededfafb, 0x05051212, 0x00000000, 0x07070707, 0xf8f8f8f9,
+ 0x0a09fcfd, 0xf5f60303, 0xfcfd0a0a, 0x0302f5f6, 0x10101010, 0xefefeff0, 0x12120505, 0xededfafb,
+ 0x05051212, 0x00000000, 0x07070707, 0xf8f8f8f9, 0x0a09fcfd, 0xf5f60303, 0xfcfd0a0a, 0x0302f5f6,
+ 0x10101010, 0xefefeff0, 0x12120505, 0xededfafb, 0x05051212, 0x00000000, 0x07070707, 0xf8f8f8f9,
+ 0x0a09fcfd, 0xf5f60303, 0xfcfd0a0a, 0x0302f5f6, 0x10101010, 0xefefeff0, 0x12120505, 0xededfafb,
+ 0x05051212, 0x00000000, 0x07070707, 0xf8f8f8f9, 0x0a09fcfd, 0xf5f60303, 0xfcfd0a0a, 0x0302f5f6,
+ 0x10101010, 0xefefeff0, 0x12120505, 0xededfafb, 0x05051212, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00000000,
+ 0x08080808, 0xf7f7f7f8, 0x0b0afcfd, 0xf4f50303, 0xfcfd0b0b, 0x0302f4f5, 0x12121212, 0xedededee,
+ 0x14140505, 0xebebfafb, 0x05051414, 0x00000000, 0x08080808, 0xf7f7f7f8, 0x0b0afcfd, 0xf4f50303,
+ 0xfcfd0b0b, 0x0302f4f5, 0x12121212, 0xedededee, 0x14140505, 0xebebfafb, 0x05051414, 0x00000000,
+ 0x08080808, 0xf7f7f7f8, 0x0b0afcfd, 0xf4f50303, 0xfcfd0b0b, 0x0302f4f5, 0x12121212, 0xedededee,
+ 0x14140505, 0xebebfafb, 0x05051414, 0x00000000, 0x08080808, 0xf7f7f7f8, 0x0b0afcfd, 0xf4f50303,
+ 0xfcfd0b0b, 0x0302f4f5, 0x12121212, 0xedededee, 0x14140505, 0xebebfafb, 0x05051414, 0x00000000,
+ 0x08080808, 0xf7f7f7f8, 0x0b0afcfd, 0xf4f50303, 0xfcfd0b0b, 0x0302f4f5, 0x12121212, 0xedededee,
+ 0x14140505, 0xebebfafb, 0x05051414, 0x00000000, 0x08080808, 0xf7f7f7f8, 0x0b0afcfd, 0xf4f50303,
+ 0xfcfd0b0b, 0x0302f4f5, 0x12121212, 0xedededee, 0x14140505, 0xebebfafb, 0x05051414, 0x00000000,
+ 0x08080808, 0xf7f7f7f8, 0x0b0afcfd, 0xf4f50303, 0xfcfd0b0b, 0x0302f4f5, 0x12121212, 0xedededee,
+ 0x14140505, 0xebebfafb, 0x05051414, 0x00000000, 0x08080808, 0xf7f7f7f8, 0x0b0afcfd, 0xf4f50303,
+ 0xfcfd0b0b, 0x0302f4f5, 0x12121212, 0xedededee, 0x14140505, 0xebebfafb, 0x05051414, 0x00000000,
+ 0x08080808, 0xf7f7f7f8, 0x0b0afcfd, 0xf4f50303, 0xfcfd0b0b, 0x0302f4f5, 0x12121212, 0xedededee,
+ 0x14140505, 0xebebfafb, 0x05051414, 0x00000000, 0x08080808, 0xf7f7f7f8, 0x0b0afcfd, 0xf4f50303,
+ 0xfcfd0b0b, 0x0302f4f5, 0x12121212, 0xedededee, 0x14140505, 0xebebfafb, 0x05051414, 0x00000000,
+ 0x08080808, 0xf7f7f7f8, 0x0b0afcfd, 0xf4f50303, 0xfcfd0b0b, 0x0302f4f5, 0x12121212, 0xedededee,
+ 0x14140505, 0xebebfafb, 0x05051414, 0x00000000, 0x08080808, 0xf7f7f7f8, 0x0b0afcfd, 0xf4f50303,
+ 0xfcfd0b0b, 0x0302f4f5, 0x12121212, 0xedededee, 0x14140505, 0xebebfafb, 0x05051414, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00000000, 0x09090909, 0xf6f6f6f7,
+ 0x0c0bfcfd, 0xf3f40303, 0xfcfd0c0c, 0x0302f3f4, 0x14141414, 0xebebebec, 0x17170606, 0xe8e8f9fa,
+ 0x06061717, 0xf9f9e8e9, 0x00000000, 0x09090909, 0xf6f6f6f7, 0x0c0bfcfd, 0xf3f40303, 0xfcfd0c0c,
+ 0x0302f3f4, 0x14141414, 0xebebebec, 0x17170606, 0xe8e8f9fa, 0x06061717, 0xf9f9e8e9, 0x00000000,
+ 0x09090909, 0xf6f6f6f7, 0x0c0bfcfd, 0xf3f40303, 0xfcfd0c0c, 0x0302f3f4, 0x14141414, 0xebebebec,
+ 0x17170606, 0xe8e8f9fa, 0x06061717, 0xf9f9e8e9, 0x00000000, 0x09090909, 0xf6f6f6f7, 0x0c0bfcfd,
+ 0xf3f40303, 0xfcfd0c0c, 0x0302f3f4, 0x14141414, 0xebebebec, 0x17170606, 0xe8e8f9fa, 0x06061717,
+ 0xf9f9e8e9, 0x00000000, 0x09090909, 0xf6f6f6f7, 0x0c0bfcfd, 0xf3f40303, 0xfcfd0c0c, 0x0302f3f4,
+ 0x14141414, 0xebebebec, 0x17170606, 0xe8e8f9fa, 0x06061717, 0xf9f9e8e9, 0x00000000, 0x09090909,
+ 0xf6f6f6f7, 0x0c0bfcfd, 0xf3f40303, 0xfcfd0c0c, 0x0302f3f4, 0x14141414, 0xebebebec, 0x17170606,
+ 0xe8e8f9fa, 0x06061717, 0xf9f9e8e9, 0x00000000, 0x09090909, 0xf6f6f6f7, 0x0c0bfcfd, 0xf3f40303,
+ 0xfcfd0c0c, 0x0302f3f4, 0x14141414, 0xebebebec, 0x17170606, 0xe8e8f9fa, 0x06061717, 0xf9f9e8e9,
+ 0x00000000, 0x09090909, 0xf6f6f6f7, 0x0c0bfcfd, 0xf3f40303, 0xfcfd0c0c, 0x0302f3f4, 0x14141414,
+ 0xebebebec, 0x17170606, 0xe8e8f9fa, 0x06061717, 0xf9f9e8e9, 0x00000000, 0x09090909, 0xf6f6f6f7,
+ 0x0c0bfcfd, 0xf3f40303, 0xfcfd0c0c, 0x0302f3f4, 0x14141414, 0xebebebec, 0x17170606, 0xe8e8f9fa,
+ 0x06061717, 0xf9f9e8e9, 0x00000000, 0x09090909, 0xf6f6f6f7, 0x0c0bfcfd, 0xf3f40303, 0xfcfd0c0c,
+ 0x0302f3f4, 0x14141414, 0xebebebec, 0x17170606, 0xe8e8f9fa, 0x06061717, 0xf9f9e8e9, 0x00000000,
+ 0x09090909, 0xf6f6f6f7, 0x0c0bfcfd, 0xf3f40303, 0xfcfd0c0c, 0x0302f3f4, 0x14141414, 0xebebebec,
+ 0x17170606, 0xe8e8f9fa, 0x06061717, 0xf9f9e8e9, 0x00000000, 0x09090909, 0xf6f6f6f7, 0x0c0bfcfd,
+ 0xf3f40303, 0xfcfd0c0c, 0x0302f3f4, 0x14141414, 0xebebebec, 0x17170606, 0xe8e8f9fa, 0x06061717,
+ 0xf9f9e8e9, 0x00000000, 0x09090909, 0xf6f6f6f7, 0x0c0bfcfd, 0xf3f40303, 0xfcfd0c0c, 0x0302f3f4,
+ 0x14141414, 0xebebebec, 0x17170606, 0xe8e8f9fa, 0x06061717, 0xf9f9e8e9, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x02020000, 0xfdfe0000,
+ 0x00000202, 0xfffffdfe, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x02020000, 0xfdfe0000, 0x00000202,
+ 0xfffffdfe, 0x00000000, 0x02020202, 0xfdfdfdfe, 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe,
+ 0x00000000, 0x02020202, 0xfdfdfdfe, 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe, 0x00000000,
+ 0x02020202, 0xfdfdfdfe, 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe, 0x00000000, 0x02020202,
+ 0xfdfdfdfe, 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe, 0x00000000, 0x02020202, 0xfdfdfdfe,
+ 0x02020000, 0xfdfe0000, 0x00000202, 0xfffffdfe, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00000000,
+ 0x03030303, 0xfcfcfcfd, 0x03030000, 0xfcfd0000, 0x00000303, 0xfffffcfd, 0x06060606, 0xf9f9f9fa,
+ 0x00000000, 0x03030303, 0xfcfcfcfd, 0x03030000, 0xfcfd0000, 0x00000303, 0xfffffcfd, 0x06060606,
+ 0xf9f9f9fa, 0x00000000, 0x03030303, 0xfcfcfcfd, 0x03030000, 0xfcfd0000, 0x00000303, 0xfffffcfd,
+ 0x06060606, 0xf9f9f9fa, 0x00000000, 0x03030303, 0xfcfcfcfd, 0x03030000, 0xfcfd0000, 0x00000303,
+ 0xfffffcfd, 0x06060606, 0xf9f9f9fa, 0x00000000, 0x03030303, 0xfcfcfcfd, 0x03030000, 0xfcfd0000,
+ 0x00000303, 0xfffffcfd, 0x06060606, 0xf9f9f9fa, 0x00000000, 0x03030303, 0xfcfcfcfd, 0x03030000,
+ 0xfcfd0000, 0x00000303, 0xfffffcfd, 0x06060606, 0xf9f9f9fa, 0x00000000, 0x03030303, 0xfcfcfcfd,
+ 0x03030000, 0xfcfd0000, 0x00000303, 0xfffffcfd, 0x06060606, 0xf9f9f9fa, 0x00000000, 0x03030303,
+ 0xfcfcfcfd, 0x03030000, 0xfcfd0000, 0x00000303, 0xfffffcfd, 0x06060606, 0xf9f9f9fa, 0x00000000,
+ 0x03030303, 0xfcfcfcfd, 0x03030000, 0xfcfd0000, 0x00000303, 0xfffffcfd, 0x06060606, 0xf9f9f9fa,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00000000, 0x04040404, 0xfbfbfbfc,
+ 0x04040000, 0xfbfc0000, 0x00000404, 0xfffffbfc, 0x08080404, 0xf7f7fbfc, 0x04040808, 0x00000000,
+ 0x04040404, 0xfbfbfbfc, 0x04040000, 0xfbfc0000, 0x00000404, 0xfffffbfc, 0x08080404, 0xf7f7fbfc,
+ 0x04040808, 0x00000000, 0x04040404, 0xfbfbfbfc, 0x04040000, 0xfbfc0000, 0x00000404, 0xfffffbfc,
+ 0x08080404, 0xf7f7fbfc, 0x04040808, 0x00000000, 0x04040404, 0xfbfbfbfc, 0x04040000, 0xfbfc0000,
+ 0x00000404, 0xfffffbfc, 0x08080404, 0xf7f7fbfc, 0x04040808, 0x00000000, 0x04040404, 0xfbfbfbfc,
+ 0x04040000, 0xfbfc0000, 0x00000404, 0xfffffbfc, 0x08080404, 0xf7f7fbfc, 0x04040808, 0x00000000,
+ 0x04040404, 0xfbfbfbfc, 0x04040000, 0xfbfc0000, 0x00000404, 0xfffffbfc, 0x08080404, 0xf7f7fbfc,
+ 0x04040808, 0x00000000, 0x04040404, 0xfbfbfbfc, 0x04040000, 0xfbfc0000, 0x00000404, 0xfffffbfc,
+ 0x08080404, 0xf7f7fbfc, 0x04040808, 0x00000000, 0x04040404, 0xfbfbfbfc, 0x04040000, 0xfbfc0000,
+ 0x00000404, 0xfffffbfc, 0x08080404, 0xf7f7fbfc, 0x04040808, 0x00000000, 0x04040404, 0xfbfbfbfc,
+ 0x04040000, 0xfbfc0000, 0x00000404, 0xfffffbfc, 0x08080404, 0xf7f7fbfc, 0x04040808, 0x00000000,
+ 0x04040404, 0xfbfbfbfc, 0x04040000, 0xfbfc0000, 0x00000404, 0xfffffbfc, 0x08080404, 0xf7f7fbfc,
+ 0x04040808, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00000000, 0x05050505, 0xfafafafb, 0x05050000, 0xfafb0000,
+ 0x00000505, 0xfffffafb, 0x0a0a0a0a, 0xf5f5f5f6, 0x0f0f0505, 0xf0f0fafb, 0x00000000, 0x05050505,
+ 0xfafafafb, 0x05050000, 0xfafb0000, 0x00000505, 0xfffffafb, 0x0a0a0a0a, 0xf5f5f5f6, 0x0f0f0505,
+ 0xf0f0fafb, 0x00000000, 0x05050505, 0xfafafafb, 0x05050000, 0xfafb0000, 0x00000505, 0xfffffafb,
+ 0x0a0a0a0a, 0xf5f5f5f6, 0x0f0f0505, 0xf0f0fafb, 0x00000000, 0x05050505, 0xfafafafb, 0x05050000,
+ 0xfafb0000, 0x00000505, 0xfffffafb, 0x0a0a0a0a, 0xf5f5f5f6, 0x0f0f0505, 0xf0f0fafb, 0x00000000,
+ 0x05050505, 0xfafafafb, 0x05050000, 0xfafb0000, 0x00000505, 0xfffffafb, 0x0a0a0a0a, 0xf5f5f5f6,
+ 0x0f0f0505, 0xf0f0fafb, 0x00000000, 0x05050505, 0xfafafafb, 0x05050000, 0xfafb0000, 0x00000505,
+ 0xfffffafb, 0x0a0a0a0a, 0xf5f5f5f6, 0x0f0f0505, 0xf0f0fafb, 0x00000000, 0x05050505, 0xfafafafb,
+ 0x05050000, 0xfafb0000, 0x00000505, 0xfffffafb, 0x0a0a0a0a, 0xf5f5f5f6, 0x0f0f0505, 0xf0f0fafb,
+ 0x00000000, 0x05050505, 0xfafafafb, 0x05050000, 0xfafb0000, 0x00000505, 0xfffffafb, 0x0a0a0a0a,
+ 0xf5f5f5f6, 0x0f0f0505, 0xf0f0fafb, 0x00000000, 0x05050505, 0xfafafafb, 0x05050000, 0xfafb0000,
+ 0x00000505, 0xfffffafb, 0x0a0a0a0a, 0xf5f5f5f6, 0x0f0f0505, 0xf0f0fafb, 0x00000000, 0x05050505,
+ 0xfafafafb, 0x05050000, 0xfafb0000, 0x00000505, 0xfffffafb, 0x0a0a0a0a, 0xf5f5f5f6, 0x0f0f0505,
+ 0xf0f0fafb, 0x00000000, 0x05050505, 0xfafafafb, 0x05050000, 0xfafb0000, 0x00000505, 0xfffffafb,
+ 0x0a0a0a0a, 0xf5f5f5f6, 0x0f0f0505, 0xf0f0fafb, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00000000, 0x06060606, 0xf9f9f9fa,
+ 0x06060000, 0xf9fa0000, 0x00000606, 0xfffff9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x0c0c0606, 0xf3f3f9fa,
+ 0x06060c0c, 0x00000000, 0x06060606, 0xf9f9f9fa, 0x06060000, 0xf9fa0000, 0x00000606, 0xfffff9fa,
+ 0x0c0c0c0c, 0xf3f3f3f4, 0x0c0c0606, 0xf3f3f9fa, 0x06060c0c, 0x00000000, 0x06060606, 0xf9f9f9fa,
+ 0x06060000, 0xf9fa0000, 0x00000606, 0xfffff9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x0c0c0606, 0xf3f3f9fa,
+ 0x06060c0c, 0x00000000, 0x06060606, 0xf9f9f9fa, 0x06060000, 0xf9fa0000, 0x00000606, 0xfffff9fa,
+ 0x0c0c0c0c, 0xf3f3f3f4, 0x0c0c0606, 0xf3f3f9fa, 0x06060c0c, 0x00000000, 0x06060606, 0xf9f9f9fa,
+ 0x06060000, 0xf9fa0000, 0x00000606, 0xfffff9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x0c0c0606, 0xf3f3f9fa,
+ 0x06060c0c, 0x00000000, 0x06060606, 0xf9f9f9fa, 0x06060000, 0xf9fa0000, 0x00000606, 0xfffff9fa,
+ 0x0c0c0c0c, 0xf3f3f3f4, 0x0c0c0606, 0xf3f3f9fa, 0x06060c0c, 0x00000000, 0x06060606, 0xf9f9f9fa,
+ 0x06060000, 0xf9fa0000, 0x00000606, 0xfffff9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x0c0c0606, 0xf3f3f9fa,
+ 0x06060c0c, 0x00000000, 0x06060606, 0xf9f9f9fa, 0x06060000, 0xf9fa0000, 0x00000606, 0xfffff9fa,
+ 0x0c0c0c0c, 0xf3f3f3f4, 0x0c0c0606, 0xf3f3f9fa, 0x06060c0c, 0x00000000, 0x06060606, 0xf9f9f9fa,
+ 0x06060000, 0xf9fa0000, 0x00000606, 0xfffff9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x0c0c0606, 0xf3f3f9fa,
+ 0x06060c0c, 0x00000000, 0x06060606, 0xf9f9f9fa, 0x06060000, 0xf9fa0000, 0x00000606, 0xfffff9fa,
+ 0x0c0c0c0c, 0xf3f3f3f4, 0x0c0c0606, 0xf3f3f9fa, 0x06060c0c, 0x00000000, 0x06060606, 0xf9f9f9fa,
+ 0x06060000, 0xf9fa0000, 0x00000606, 0xfffff9fa, 0x0c0c0c0c, 0xf3f3f3f4, 0x0c0c0606, 0xf3f3f9fa,
+ 0x06060c0c, 0x00000000, 0x06060606, 0xf9f9f9fa, 0x06060000, 0xf9fa0000, 0x00000606, 0xfffff9fa,
+ 0x0c0c0c0c, 0xf3f3f3f4, 0x0c0c0606, 0xf3f3f9fa, 0x06060c0c, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00000000, 0x07070707, 0xf8f8f8f9,
+ 0x07070000, 0xf8f90000, 0x00000707, 0xfffff8f9, 0x0e0e0e0e, 0xf1f1f1f2, 0x15150707, 0xeaeaf8f9,
+ 0x07071515, 0x00000000, 0x07070707, 0xf8f8f8f9, 0x07070000, 0xf8f90000, 0x00000707, 0xfffff8f9,
+ 0x0e0e0e0e, 0xf1f1f1f2, 0x15150707, 0xeaeaf8f9, 0x07071515, 0x00000000, 0x07070707, 0xf8f8f8f9,
+ 0x07070000, 0xf8f90000, 0x00000707, 0xfffff8f9, 0x0e0e0e0e, 0xf1f1f1f2, 0x15150707, 0xeaeaf8f9,
+ 0x07071515, 0x00000000, 0x07070707, 0xf8f8f8f9, 0x07070000, 0xf8f90000, 0x00000707, 0xfffff8f9,
+ 0x0e0e0e0e, 0xf1f1f1f2, 0x15150707, 0xeaeaf8f9, 0x07071515, 0x00000000, 0x07070707, 0xf8f8f8f9,
+ 0x07070000, 0xf8f90000, 0x00000707, 0xfffff8f9, 0x0e0e0e0e, 0xf1f1f1f2, 0x15150707, 0xeaeaf8f9,
+ 0x07071515, 0x00000000, 0x07070707, 0xf8f8f8f9, 0x07070000, 0xf8f90000, 0x00000707, 0xfffff8f9,
+ 0x0e0e0e0e, 0xf1f1f1f2, 0x15150707, 0xeaeaf8f9, 0x07071515, 0x00000000, 0x07070707, 0xf8f8f8f9,
+ 0x07070000, 0xf8f90000, 0x00000707, 0xfffff8f9, 0x0e0e0e0e, 0xf1f1f1f2, 0x15150707, 0xeaeaf8f9,
+ 0x07071515, 0x00000000, 0x07070707, 0xf8f8f8f9, 0x07070000, 0xf8f90000, 0x00000707, 0xfffff8f9,
+ 0x0e0e0e0e, 0xf1f1f1f2, 0x15150707, 0xeaeaf8f9, 0x07071515, 0x00000000, 0x07070707, 0xf8f8f8f9,
+ 0x07070000, 0xf8f90000, 0x00000707, 0xfffff8f9, 0x0e0e0e0e, 0xf1f1f1f2, 0x15150707, 0xeaeaf8f9,
+ 0x07071515, 0x00000000, 0x07070707, 0xf8f8f8f9, 0x07070000, 0xf8f90000, 0x00000707, 0xfffff8f9,
+ 0x0e0e0e0e, 0xf1f1f1f2, 0x15150707, 0xeaeaf8f9, 0x07071515, 0x00000000, 0x07070707, 0xf8f8f8f9,
+ 0x07070000, 0xf8f90000, 0x00000707, 0xfffff8f9, 0x0e0e0e0e, 0xf1f1f1f2, 0x15150707, 0xeaeaf8f9,
+ 0x07071515, 0x00000000, 0x07070707, 0xf8f8f8f9, 0x07070000, 0xf8f90000, 0x00000707, 0xfffff8f9,
+ 0x0e0e0e0e, 0xf1f1f1f2, 0x15150707, 0xeaeaf8f9, 0x07071515, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00000000,
+ 0x08080808, 0xf7f7f7f8, 0x08080000, 0xf7f80000, 0x00000808, 0xfffff7f8, 0x10101010, 0xefefeff0,
+ 0x10100808, 0xefeff7f8, 0x08081010, 0x00000000, 0x08080808, 0xf7f7f7f8, 0x08080000, 0xf7f80000,
+ 0x00000808, 0xfffff7f8, 0x10101010, 0xefefeff0, 0x10100808, 0xefeff7f8, 0x08081010, 0x00000000,
+ 0x08080808, 0xf7f7f7f8, 0x08080000, 0xf7f80000, 0x00000808, 0xfffff7f8, 0x10101010, 0xefefeff0,
+ 0x10100808, 0xefeff7f8, 0x08081010, 0x00000000, 0x08080808, 0xf7f7f7f8, 0x08080000, 0xf7f80000,
+ 0x00000808, 0xfffff7f8, 0x10101010, 0xefefeff0, 0x10100808, 0xefeff7f8, 0x08081010, 0x00000000,
+ 0x08080808, 0xf7f7f7f8, 0x08080000, 0xf7f80000, 0x00000808, 0xfffff7f8, 0x10101010, 0xefefeff0,
+ 0x10100808, 0xefeff7f8, 0x08081010, 0x00000000, 0x08080808, 0xf7f7f7f8, 0x08080000, 0xf7f80000,
+ 0x00000808, 0xfffff7f8, 0x10101010, 0xefefeff0, 0x10100808, 0xefeff7f8, 0x08081010, 0x00000000,
+ 0x08080808, 0xf7f7f7f8, 0x08080000, 0xf7f80000, 0x00000808, 0xfffff7f8, 0x10101010, 0xefefeff0,
+ 0x10100808, 0xefeff7f8, 0x08081010, 0x00000000, 0x08080808, 0xf7f7f7f8, 0x08080000, 0xf7f80000,
+ 0x00000808, 0xfffff7f8, 0x10101010, 0xefefeff0, 0x10100808, 0xefeff7f8, 0x08081010, 0x00000000,
+ 0x08080808, 0xf7f7f7f8, 0x08080000, 0xf7f80000, 0x00000808, 0xfffff7f8, 0x10101010, 0xefefeff0,
+ 0x10100808, 0xefeff7f8, 0x08081010, 0x00000000, 0x08080808, 0xf7f7f7f8, 0x08080000, 0xf7f80000,
+ 0x00000808, 0xfffff7f8, 0x10101010, 0xefefeff0, 0x10100808, 0xefeff7f8, 0x08081010, 0x00000000,
+ 0x08080808, 0xf7f7f7f8, 0x08080000, 0xf7f80000, 0x00000808, 0xfffff7f8, 0x10101010, 0xefefeff0,
+ 0x10100808, 0xefeff7f8, 0x08081010, 0x00000000, 0x08080808, 0xf7f7f7f8, 0x08080000, 0xf7f80000,
+ 0x00000808, 0xfffff7f8, 0x10101010, 0xefefeff0, 0x10100808, 0xefeff7f8, 0x08081010, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00000000, 0x09090909, 0xf6f6f6f7,
+ 0x09090000, 0xf6f70000, 0x00000909, 0xfffff6f7, 0x12121212, 0xedededee, 0x1b1b0909, 0xe4e4f6f7,
+ 0x09091b1b, 0xf6f6e4e5, 0x00000000, 0x09090909, 0xf6f6f6f7, 0x09090000, 0xf6f70000, 0x00000909,
+ 0xfffff6f7, 0x12121212, 0xedededee, 0x1b1b0909, 0xe4e4f6f7, 0x09091b1b, 0xf6f6e4e5, 0x00000000,
+ 0x09090909, 0xf6f6f6f7, 0x09090000, 0xf6f70000, 0x00000909, 0xfffff6f7, 0x12121212, 0xedededee,
+ 0x1b1b0909, 0xe4e4f6f7, 0x09091b1b, 0xf6f6e4e5, 0x00000000, 0x09090909, 0xf6f6f6f7, 0x09090000,
+ 0xf6f70000, 0x00000909, 0xfffff6f7, 0x12121212, 0xedededee, 0x1b1b0909, 0xe4e4f6f7, 0x09091b1b,
+ 0xf6f6e4e5, 0x00000000, 0x09090909, 0xf6f6f6f7, 0x09090000, 0xf6f70000, 0x00000909, 0xfffff6f7,
+ 0x12121212, 0xedededee, 0x1b1b0909, 0xe4e4f6f7, 0x09091b1b, 0xf6f6e4e5, 0x00000000, 0x09090909,
+ 0xf6f6f6f7, 0x09090000, 0xf6f70000, 0x00000909, 0xfffff6f7, 0x12121212, 0xedededee, 0x1b1b0909,
+ 0xe4e4f6f7, 0x09091b1b, 0xf6f6e4e5, 0x00000000, 0x09090909, 0xf6f6f6f7, 0x09090000, 0xf6f70000,
+ 0x00000909, 0xfffff6f7, 0x12121212, 0xedededee, 0x1b1b0909, 0xe4e4f6f7, 0x09091b1b, 0xf6f6e4e5,
+ 0x00000000, 0x09090909, 0xf6f6f6f7, 0x09090000, 0xf6f70000, 0x00000909, 0xfffff6f7, 0x12121212,
+ 0xedededee, 0x1b1b0909, 0xe4e4f6f7, 0x09091b1b, 0xf6f6e4e5, 0x00000000, 0x09090909, 0xf6f6f6f7,
+ 0x09090000, 0xf6f70000, 0x00000909, 0xfffff6f7, 0x12121212, 0xedededee, 0x1b1b0909, 0xe4e4f6f7,
+ 0x09091b1b, 0xf6f6e4e5, 0x00000000, 0x09090909, 0xf6f6f6f7, 0x09090000, 0xf6f70000, 0x00000909,
+ 0xfffff6f7, 0x12121212, 0xedededee, 0x1b1b0909, 0xe4e4f6f7, 0x09091b1b, 0xf6f6e4e5, 0x00000000,
+ 0x09090909, 0xf6f6f6f7, 0x09090000, 0xf6f70000, 0x00000909, 0xfffff6f7, 0x12121212, 0xedededee,
+ 0x1b1b0909, 0xe4e4f6f7, 0x09091b1b, 0xf6f6e4e5, 0x00000000, 0x09090909, 0xf6f6f6f7, 0x09090000,
+ 0xf6f70000, 0x00000909, 0xfffff6f7, 0x12121212, 0xedededee, 0x1b1b0909, 0xe4e4f6f7, 0x09091b1b,
+ 0xf6f6e4e5, 0x00000000, 0x09090909, 0xf6f6f6f7, 0x09090000, 0xf6f70000, 0x00000909, 0xfffff6f7,
+ 0x12121212, 0xedededee, 0x1b1b0909, 0xe4e4f6f7, 0x09091b1b, 0xf6f6e4e5, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202,
+ 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0xfdfdfdfe, 0xfdfdfdfe,
+ 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe,
+ 0xfdfdfdfe, 0x03030000, 0x03030000, 0x03030000, 0x03030000, 0x03030000, 0x03030000, 0x03030000,
+ 0x03030000, 0x03030000, 0x03030000, 0x03030000, 0xfcfd0000, 0xfcfd0000, 0xfcfd0000, 0xfcfd0000,
+ 0xfcfd0000, 0xfcfd0000, 0xfcfd0000, 0xfcfd0000, 0xfcfd0000, 0xfcfd0000, 0xfcfd0000, 0x00000303,
+ 0x00000303, 0x00000303, 0x00000303, 0x00000303, 0x00000303, 0x00000303, 0x00000303, 0x00000303,
+ 0x00000303, 0x00000303, 0xfffffcfd, 0xfffffcfd, 0xfffffcfd, 0xfffffcfd, 0xfffffcfd, 0xfffffcfd,
+ 0xfffffcfd, 0xfffffcfd, 0xfffffcfd, 0xfffffcfd, 0xfffffcfd, 0x06060606, 0x06060606, 0x06060606,
+ 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606,
+ 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa,
+ 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0x07070000, 0x07070000, 0x07070000, 0x07070000, 0x07070000,
+ 0x07070000, 0x07070000, 0x07070000, 0x07070000, 0x07070000, 0x07070000, 0xf8f90000, 0xf8f90000,
+ 0xf8f90000, 0xf8f90000, 0xf8f90000, 0xf8f90000, 0xf8f90000, 0xf8f90000, 0xf8f90000, 0xf8f90000,
+ 0xf8f90000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02020000, 0x02020000, 0x02020000, 0x02020000,
+ 0x02020000, 0x02020000, 0x02020000, 0x02020000, 0x02020000, 0x02020000, 0x02020000, 0x02020000,
+ 0x02020000, 0xfdfe0000, 0xfdfe0000, 0xfdfe0000, 0xfdfe0000, 0xfdfe0000, 0xfdfe0000, 0xfdfe0000,
+ 0xfdfe0000, 0xfdfe0000, 0xfdfe0000, 0xfdfe0000, 0xfdfe0000, 0xfdfe0000, 0x00000202, 0x00000202,
+ 0x00000202, 0x00000202, 0x00000202, 0x00000202, 0x00000202, 0x00000202, 0x00000202, 0x00000202,
+ 0x00000202, 0x00000202, 0x00000202, 0xfffffdfe, 0xfffffdfe, 0xfffffdfe, 0xfffffdfe, 0xfffffdfe,
+ 0xfffffdfe, 0xfffffdfe, 0xfffffdfe, 0xfffffdfe, 0xfffffdfe, 0xfffffdfe, 0xfffffdfe, 0xfffffdfe,
+ 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202,
+ 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe,
+ 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe,
+ 0xfdfdfdfe, 0xfdfdfdfe, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606,
+ 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0xf9f9f9fa,
+ 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa,
+ 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0x06060000, 0x06060000, 0x06060000, 0x06060000,
+ 0x06060000, 0x06060000, 0x06060000, 0x06060000, 0x06060000, 0x06060000, 0x06060000, 0x06060000,
+ 0x06060000, 0xf9fa0000, 0xf9fa0000, 0xf9fa0000, 0xf9fa0000, 0xf9fa0000, 0xf9fa0000, 0xf9fa0000,
+ 0xf9fa0000, 0xf9fa0000, 0xf9fa0000, 0xf9fa0000, 0xf9fa0000, 0xf9fa0000, 0x00000606, 0x00000606,
+ 0x00000606, 0x00000606, 0x00000606, 0x00000606, 0x00000606, 0x00000606, 0x00000606, 0x00000606,
+ 0x00000606, 0x00000606, 0x00000606, 0xfffff9fa, 0xfffff9fa, 0xfffff9fa, 0xfffff9fa, 0xfffff9fa,
+ 0xfffff9fa, 0xfffff9fa, 0xfffff9fa, 0xfffff9fa, 0xfffff9fa, 0xfffff9fa, 0xfffff9fa, 0xfffff9fa,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02020000, 0x02020000, 0x02020000, 0x02020000,
+ 0x02020000, 0x02020000, 0x02020000, 0x02020000, 0x02020000, 0x02020000, 0x02020000, 0x02020000,
+ 0x02020000, 0xfdfe0000, 0xfdfe0000, 0xfdfe0000, 0xfdfe0000, 0xfdfe0000, 0xfdfe0000, 0xfdfe0000,
+ 0xfdfe0000, 0xfdfe0000, 0xfdfe0000, 0xfdfe0000, 0xfdfe0000, 0xfdfe0000, 0x00000202, 0x00000202,
+ 0x00000202, 0x00000202, 0x00000202, 0x00000202, 0x00000202, 0x00000202, 0x00000202, 0x00000202,
+ 0x00000202, 0x00000202, 0x00000202, 0xfffffdfe, 0xfffffdfe, 0xfffffdfe, 0xfffffdfe, 0xfffffdfe,
+ 0xfffffdfe, 0xfffffdfe, 0xfffffdfe, 0xfffffdfe, 0xfffffdfe, 0xfffffdfe, 0xfffffdfe, 0xfffffdfe,
+ 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404,
+ 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc,
+ 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc,
+ 0xfbfbfbfc, 0xfbfbfbfc, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a,
+ 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a, 0x0a0a0a0a, 0xf5f5f5f6,
+ 0xf5f5f5f6, 0xf5f5f5f6, 0xf5f5f5f6, 0xf5f5f5f6, 0xf5f5f5f6, 0xf5f5f5f6, 0xf5f5f5f6, 0xf5f5f5f6,
+ 0xf5f5f5f6, 0xf5f5f5f6, 0xf5f5f5f6, 0xf5f5f5f6, 0x0a0a0000, 0x0a0a0000, 0x0a0a0000, 0x0a0a0000,
+ 0x0a0a0000, 0x0a0a0000, 0x0a0a0000, 0x0a0a0000, 0x0a0a0000, 0x0a0a0000, 0x0a0a0000, 0x0a0a0000,
+ 0x0a0a0000, 0xf5f60000, 0xf5f60000, 0xf5f60000, 0xf5f60000, 0xf5f60000, 0xf5f60000, 0xf5f60000,
+ 0xf5f60000, 0xf5f60000, 0xf5f60000, 0xf5f60000, 0xf5f60000, 0xf5f60000, 0x00000a0a, 0x00000a0a,
+ 0x00000a0a, 0x00000a0a, 0x00000a0a, 0x00000a0a, 0x00000a0a, 0x00000a0a, 0x00000a0a, 0x00000a0a,
+ 0x00000a0a, 0x00000a0a, 0x00000a0a, 0xfffff5f6, 0xfffff5f6, 0xfffff5f6, 0xfffff5f6, 0xfffff5f6,
+ 0xfffff5f6, 0xfffff5f6, 0xfffff5f6, 0xfffff5f6, 0xfffff5f6, 0xfffff5f6, 0xfffff5f6, 0xfffff5f6,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04040000, 0x04040000, 0x04040000, 0x04040000,
+ 0x04040000, 0x04040000, 0x04040000, 0x04040000, 0x04040000, 0x04040000, 0x04040000, 0x04040000,
+ 0x04040000, 0xfbfc0000, 0xfbfc0000, 0xfbfc0000, 0xfbfc0000, 0xfbfc0000, 0xfbfc0000, 0xfbfc0000,
+ 0xfbfc0000, 0xfbfc0000, 0xfbfc0000, 0xfbfc0000, 0xfbfc0000, 0xfbfc0000, 0x00000404, 0x00000404,
+ 0x00000404, 0x00000404, 0x00000404, 0x00000404, 0x00000404, 0x00000404, 0x00000404, 0x00000404,
+ 0x00000404, 0x00000404, 0x00000404, 0xfffffbfc, 0xfffffbfc, 0xfffffbfc, 0xfffffbfc, 0xfffffbfc,
+ 0xfffffbfc, 0xfffffbfc, 0xfffffbfc, 0xfffffbfc, 0xfffffbfc, 0xfffffbfc, 0xfffffbfc, 0xfffffbfc,
+ 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404,
+ 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0x04040404, 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc,
+ 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc, 0xfbfbfbfc,
+ 0xfbfbfbfc, 0xfbfbfbfc, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c,
+ 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0xf3f3f3f4,
+ 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4,
+ 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0x0c0c0000, 0x0c0c0000, 0x0c0c0000, 0x0c0c0000,
+ 0x0c0c0000, 0x0c0c0000, 0x0c0c0000, 0x0c0c0000, 0x0c0c0000, 0x0c0c0000, 0x0c0c0000, 0x0c0c0000,
+ 0x0c0c0000, 0xf3f40000, 0xf3f40000, 0xf3f40000, 0xf3f40000, 0xf3f40000, 0xf3f40000, 0xf3f40000,
+ 0xf3f40000, 0xf3f40000, 0xf3f40000, 0xf3f40000, 0xf3f40000, 0xf3f40000, 0x00000c0c, 0x00000c0c,
+ 0x00000c0c, 0x00000c0c, 0x00000c0c, 0x00000c0c, 0x00000c0c, 0x00000c0c, 0x00000c0c, 0x00000c0c,
+ 0x00000c0c, 0x00000c0c, 0x00000c0c, 0xfffff3f4, 0xfffff3f4, 0xfffff3f4, 0xfffff3f4, 0xfffff3f4,
+ 0xfffff3f4, 0xfffff3f4, 0xfffff3f4, 0xfffff3f4, 0xfffff3f4, 0xfffff3f4, 0xfffff3f4, 0xfffff3f4,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02020202, 0x02020202, 0x02020202, 0x02020202,
+ 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202,
+ 0x02020202, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe,
+ 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0x06060606, 0x06060606,
+ 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606,
+ 0x06060606, 0x06060606, 0x06060606, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa,
+ 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa,
+ 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c,
+ 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4,
+ 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4,
+ 0xf3f3f3f4, 0xf3f3f3f4, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414,
+ 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0xebebebec,
+ 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec,
+ 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0x20202020, 0x20202020, 0x20202020, 0x20202020,
+ 0x20202020, 0x20202020, 0x20202020, 0x20202020, 0x20202020, 0x20202020, 0x20202020, 0x20202020,
+ 0x20202020, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0,
+ 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0x2e2e2e2e, 0x2e2e2e2e,
+ 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e,
+ 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2,
+ 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02020202, 0x02020202, 0x02020202, 0x02020202,
+ 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202,
+ 0x02020202, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe,
+ 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0x06060606, 0x06060606,
+ 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606,
+ 0x06060606, 0x06060606, 0x06060606, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa,
+ 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa,
+ 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c,
+ 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4,
+ 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4,
+ 0xf3f3f3f4, 0xf3f3f3f4, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414,
+ 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0xebebebec,
+ 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec,
+ 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0x20202020, 0x20202020, 0x20202020, 0x20202020,
+ 0x20202020, 0x20202020, 0x20202020, 0x20202020, 0x20202020, 0x20202020, 0x20202020, 0x20202020,
+ 0x20202020, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0,
+ 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0x2e2e2e2e, 0x2e2e2e2e,
+ 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e,
+ 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2,
+ 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02020202, 0x02020202, 0x02020202, 0x02020202,
+ 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202,
+ 0x02020202, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe,
+ 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0x06060606, 0x06060606,
+ 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606,
+ 0x06060606, 0x06060606, 0x06060606, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa,
+ 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa,
+ 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c,
+ 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4,
+ 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4,
+ 0xf3f3f3f4, 0xf3f3f3f4, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414,
+ 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0xebebebec,
+ 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec,
+ 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0x20202020, 0x20202020, 0x20202020, 0x20202020,
+ 0x20202020, 0x20202020, 0x20202020, 0x20202020, 0x20202020, 0x20202020, 0x20202020, 0x20202020,
+ 0x20202020, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0,
+ 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0x2e2e2e2e, 0x2e2e2e2e,
+ 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e,
+ 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2,
+ 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef,
+ 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02020202, 0x02020202, 0x02020202, 0x02020202,
+ 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202, 0x02020202,
+ 0x02020202, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe,
+ 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0xfdfdfdfe, 0x06060606, 0x06060606,
+ 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606,
+ 0x06060606, 0x06060606, 0x06060606, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa,
+ 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa, 0xf9f9f9fa,
+ 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c,
+ 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4,
+ 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4, 0xf3f3f3f4,
+ 0xf3f3f3f4, 0xf3f3f3f4, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414,
+ 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0x14141414, 0xebebebec,
+ 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec,
+ 0xebebebec, 0xebebebec, 0xebebebec, 0xebebebec, 0x20202020, 0x20202020, 0x20202020, 0x20202020,
+ 0x20202020, 0x20202020, 0x20202020, 0x20202020, 0x20202020, 0x20202020, 0x20202020, 0x20202020,
+ 0x20202020, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0,
+ 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0xdfdfdfe0, 0x2e2e2e2e, 0x2e2e2e2e,
+ 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e,
+ 0x2e2e2e2e, 0x2e2e2e2e, 0x2e2e2e2e, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2,
+ 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2, 0xd1d1d1d2,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
+};
+
+} // End of namespace Graphics
+
+#endif // USE_INDEO3
diff --git a/graphics/video/coktelvideo/indeo3.h b/graphics/video/coktelvideo/indeo3.h
new file mode 100644
index 0000000000..af6ef26449
--- /dev/null
+++ b/graphics/video/coktelvideo/indeo3.h
@@ -0,0 +1,126 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/scummsys.h"
+
+#ifdef USE_INDEO3
+
+/* Intel Indeo 3 decompressor, derived from ffmpeg.
+ *
+ * Original copyright note:
+ * Intel Indeo 3 (IV31, IV32, etc.) video decoder for ffmpeg
+ * written, produced, and directed by Alan Smithee
+ */
+
+#ifndef GRAPHICS_VIDEO_INDEO3_H
+#define GRAPHICS_VIDEO_INDEO3_H
+
+#include "common/stream.h"
+
+namespace Graphics {
+ class PaletteLUT;
+ class SierraLight;
+}
+
+namespace Graphics {
+
+class Indeo3 {
+public:
+ enum DitherAlgorithm {
+ kDitherNone = 0,
+ kDitherSierraLight
+ };
+
+ Indeo3(int16 width, int16 height, Graphics::PaletteLUT *palLUT);
+ ~Indeo3();
+
+ static bool isIndeo3(byte *data, uint32 dataLen);
+
+ void setDither(DitherAlgorithm dither);
+
+ bool decompressFrame(byte *inData, uint32 dataLen,
+ byte *outData, uint16 width, uint16 height);
+
+private:
+ static const int _corrector_type_0[24];
+ static const int _corrector_type_2[8];
+ static const uint32 correction[];
+ static const uint32 correctionloworder[];
+ static const uint32 correctionhighorder[];
+
+ struct YUVBufs {
+ byte *Ybuf;
+ byte *Ubuf;
+ byte *Vbuf;
+ byte *the_buf;
+ uint32 the_buf_size;
+ uint16 y_w, y_h;
+ uint16 uv_w, uv_h;
+ };
+
+ int16 _width;
+ int16 _height;
+ YUVBufs _iv_frame[2];
+ YUVBufs *_cur_frame;
+ YUVBufs *_ref_frame;
+
+ byte *_ModPred;
+ uint16 *_corrector_type;
+
+ Graphics::PaletteLUT *_palLUT;
+
+ DitherAlgorithm _dither;
+ Graphics::SierraLight *_ditherSL;
+
+ struct BlitState {
+ uint32 curX, curY;
+ uint16 widthY, widthUV;
+ uint16 heightY, heightUV;
+ uint16 uwidthUV, uwidthOut;
+ uint16 uheightUV, uheightOut;
+ uint16 scaleWYUV, scaleWYOut;
+ uint16 scaleHYUV, scaleHYOut;
+ uint16 lineWidthOut, lineHeightOut;
+ byte *bufY, *bufU, *bufV, *bufOut;
+ };
+
+ void buildModPred();
+ void allocFrames();
+
+ void decodeChunk(byte *cur, byte *ref, int width, int height,
+ const byte *buf1, uint32 fflags2, const byte *hdr,
+ const byte *buf2, int min_width_160);
+
+ void blitFrame(BlitState &s);
+
+ void blitLine(BlitState &s);
+ void blitLineDither(BlitState &s);
+};
+
+} // End of namespace Graphics
+
+#endif // GRAPHICS_VIDEO_INDEO3_H
+
+#endif // USE_INDEO3
diff --git a/gui/about.cpp b/gui/about.cpp
index 3caab084ca..ea326eb71e 100644
--- a/gui/about.cpp
+++ b/gui/about.cpp
@@ -82,10 +82,31 @@ AboutDialog::AboutDialog()
: Dialog(10, 20, 300, 174),
_scrollPos(0), _scrollTime(0), _willClose(false) {
- reflowLayout();
-
int i;
+ const int screenW = g_system->getOverlayWidth();
+ const int screenH = g_system->getOverlayHeight();
+
+ _xOff = g_gui.xmlEval()->getVar("Globals.About.XOffset", 5);
+ _yOff = g_gui.xmlEval()->getVar("Globals.About.YOffset", 5);
+ int outerBorder = g_gui.xmlEval()->getVar("Globals.About.OuterBorder");
+
+ _w = screenW - 2 * outerBorder;
+ _h = screenH - 2 * outerBorder;
+
+ _lineHeight = g_gui.getFontHeight() + 3;
+
+ // Heuristic to compute 'optimal' dialog width
+ int maxW = _w - 2*_xOff;
+ _w = 0;
+ for (i = 0; i < ARRAYSIZE(credits); i++) {
+ int tmp = g_gui.getStringWidth(credits[i] + 5);
+ if (_w < tmp && tmp <= maxW) {
+ _w = tmp;
+ }
+ }
+ _w += 2*_xOff;
+
for (i = 0; i < 1; i++)
_lines.push_back("");
@@ -134,6 +155,10 @@ AboutDialog::AboutDialog()
for (i = 0; i < ARRAYSIZE(credits); i++)
addLine(credits[i]);
+
+ // Center the dialog
+ _x = (screenW - _w) / 2;
+ _y = (screenH - _h) / 2;
}
void AboutDialog::addLine(const char *str) {
@@ -273,7 +298,6 @@ void AboutDialog::handleKeyUp(Common::KeyState state) {
void AboutDialog::reflowLayout() {
Dialog::reflowLayout();
- int i;
const int screenW = g_system->getOverlayWidth();
const int screenH = g_system->getOverlayHeight();
@@ -289,7 +313,7 @@ void AboutDialog::reflowLayout() {
// Heuristic to compute 'optimal' dialog width
int maxW = _w - 2*_xOff;
_w = 0;
- for (i = 0; i < ARRAYSIZE(credits); i++) {
+ for (int i = 0; i < ARRAYSIZE(credits); i++) {
int tmp = g_gui.getStringWidth(credits[i] + 5);
if (_w < tmp && tmp <= maxW) {
_w = tmp;
@@ -297,7 +321,8 @@ void AboutDialog::reflowLayout() {
}
_w += 2*_xOff;
- // Center the dialog
+ _lineHeight = g_gui.getFontHeight() + 3;
+
_x = (screenW - _w) / 2;
_y = (screenH - _h) / 2;
}
diff --git a/gui/editable.cpp b/gui/editable.cpp
index 755e34e380..92faad5bb3 100644
--- a/gui/editable.cpp
+++ b/gui/editable.cpp
@@ -65,7 +65,7 @@ void EditableWidget::setEditString(const String &str) {
// TODO: We probably should filter the input string here,
// e.g. using tryInsertChar.
_editString = str;
- _caretPos = 0;
+ _caretPos = _editString.size();
}
bool EditableWidget::tryInsertChar(byte c, int pos) {
diff --git a/gui/launcher.cpp b/gui/launcher.cpp
index d50e7ce578..bc5debd9cd 100644
--- a/gui/launcher.cpp
+++ b/gui/launcher.cpp
@@ -733,7 +733,7 @@ void LauncherDialog::addGame() {
// ...so let's determine a list of candidates, games that
// could be contained in the specified directory.
GameList candidates(EngineMan.detectGames(files));
-
+
int idx;
if (candidates.empty()) {
// No game was found in the specified directory
@@ -874,7 +874,12 @@ void LauncherDialog::loadGame(int item) {
gameId = _domains[item];
const EnginePlugin *plugin = 0;
+
+#if defined(NEW_PLUGIN_DESIGN_FIRST_REFINEMENT) && defined(DYNAMIC_MODULES)
+ EngineMan.findGameOnePlugAtATime(gameId, &plugin);
+#else
EngineMan.findGame(gameId, &plugin);
+#endif
String target = _domains[item];
target.toLowercase();
diff --git a/gui/themes/scummclassic/classic_layout.stx b/gui/themes/scummclassic/classic_layout.stx
index 74b8bf4b2c..78941003ef 100644
--- a/gui/themes/scummclassic/classic_layout.stx
+++ b/gui/themes/scummclassic/classic_layout.stx
@@ -635,10 +635,6 @@
width = '150'
height = 'Globals.Button.Height'
/>
- <widget name = 'Help'
- width = '150'
- height = 'Globals.Button.Height'
- />
<widget name = 'About'
width = '150'
height = 'Globals.Button.Height'
@@ -655,7 +651,36 @@
</layout>
</dialog>
- <dialog name = 'GlobalConfig' overlays = 'screen_center'>
+ <dialog name = 'ScummMain' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8'>
+ <widget name = 'Resume'
+ type = 'Button'
+ />
+ <space size = '15'/>
+ <widget name = 'Load'
+ type = 'Button'
+ />
+ <widget name = 'Save'
+ type = 'Button'
+ />
+ <space size = '15'/>
+ <widget name = 'Options'
+ type = 'Button'
+ />
+ <widget name = 'Help'
+ type = 'Button'
+ />
+ <widget name = 'About'
+ type = 'Button'
+ />
+ <space size = '15'/>
+ <widget name = 'Quit'
+ type = 'Button'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummConfig' overlays = 'screen_center'>
<layout type = 'vertical' padding = '8, 8, 8, 8'>
<layout type = 'horizontal' padding = '0, 0, 0, 0'>
<layout type = 'vertical' padding = '0, 0, 0, 0' center = 'true'>
diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx
index 65083f4bce..e7cc7b6279 100644
--- a/gui/themes/scummclassic/classic_layout_lowres.stx
+++ b/gui/themes/scummclassic/classic_layout_lowres.stx
@@ -620,7 +620,7 @@
</dialog>
<dialog name = 'GlobalMenu' overlays = 'screen_center'>
- <layout type = 'vertical' padding = '2, 2, 4, 6' center = 'true' spacing='6'>
+ <layout type = 'vertical' padding = '8, 8, 4, 6' center = 'true'>
<widget name = 'Title'
width = '160'
height = '4'
@@ -643,10 +643,6 @@
width = '120'
height = '12'
/>
- <widget name = 'Help'
- width = '120'
- height = '12'
- />
<widget name = 'About'
width = '120'
height = '12'
@@ -667,7 +663,43 @@
</layout>
</dialog>
- <dialog name = 'GlobalConfig' overlays = 'screen_center'>
+ <dialog name = 'ScummMain' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8'>
+ <widget name = 'Resume'
+ width = 'Globals.Button.Width'
+ height = '14'
+ />
+ <space size = '2'/>
+ <widget name = 'Load'
+ width = 'Globals.Button.Width'
+ height = '14'
+ />
+ <widget name = 'Save'
+ width = 'Globals.Button.Width'
+ height = '14'
+ />
+ <space size = '2'/>
+ <widget name = 'Options'
+ width = 'Globals.Button.Width'
+ height = '14'
+ />
+ <widget name = 'Help'
+ width = 'Globals.Button.Width'
+ height = '14'
+ />
+ <widget name = 'About'
+ width = 'Globals.Button.Width'
+ height = '14'
+ />
+ <space size = '2'/>
+ <widget name = 'Quit'
+ width = 'Globals.Button.Width'
+ height = '14'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummConfig' overlays = 'screen_center'>
<layout type = 'vertical' padding = '8, 8, 8, 8'>
<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' center = 'true'>
<widget name = 'vcMusicText'
diff --git a/gui/themes/scummmodern/scummmodern_layout.stx b/gui/themes/scummmodern/scummmodern_layout.stx
index 484dd15429..3464619cf3 100644
--- a/gui/themes/scummmodern/scummmodern_layout.stx
+++ b/gui/themes/scummmodern/scummmodern_layout.stx
@@ -650,10 +650,6 @@
width = '150'
height = 'Globals.Button.Height'
/>
- <widget name = 'Help'
- width = '150'
- height = 'Globals.Button.Height'
- />
<widget name = 'About'
width = '150'
height = 'Globals.Button.Height'
@@ -670,7 +666,36 @@
</layout>
</dialog>
- <dialog name = 'GlobalConfig' overlays = 'screen_center'>
+ <dialog name = 'ScummMain' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '8, 8, 8, 8'>
+ <widget name = 'Resume'
+ type = 'Button'
+ />
+ <space size = '15'/>
+ <widget name = 'Load'
+ type = 'Button'
+ />
+ <widget name = 'Save'
+ type = 'Button'
+ />
+ <space size = '15'/>
+ <widget name = 'Options'
+ type = 'Button'
+ />
+ <widget name = 'Help'
+ type = 'Button'
+ />
+ <widget name = 'About'
+ type = 'Button'
+ />
+ <space size = '15'/>
+ <widget name = 'Quit'
+ type = 'Button'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummConfig' overlays = 'screen_center'>
<layout type = 'vertical' padding = '8, 8, 8, 8' spacing = '8'>
<layout type = 'horizontal' padding = '0, 0, 0, 0'>
<layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '8' center = 'true'>
diff --git a/gui/themes/scummmodern/scummmodern_layout_lowres.stx b/gui/themes/scummmodern/scummmodern_layout_lowres.stx
index 5998c50b60..f869956300 100644
--- a/gui/themes/scummmodern/scummmodern_layout_lowres.stx
+++ b/gui/themes/scummmodern/scummmodern_layout_lowres.stx
@@ -618,7 +618,7 @@
</dialog>
<dialog name = 'GlobalMenu' overlays = 'screen_center'>
- <layout type = 'vertical' padding = '4, 4, 4, 4' center = 'true' spacing='2'>
+ <layout type = 'vertical' padding = '4, 4, 4, 4' center = 'true'>
<widget name = 'Title'
width = '160'
height = 'Globals.Line.Height'
@@ -641,10 +641,6 @@
width = '120'
height = 'Globals.Button.Height'
/>
- <widget name = 'Help'
- width = '120'
- height = 'Globals.Button.Height'
- />
<widget name = 'About'
width = '120'
height = 'Globals.Button.Height'
@@ -665,7 +661,36 @@
</layout>
</dialog>
- <dialog name = 'GlobalConfig' overlays = 'screen_center'>
+ <dialog name = 'ScummMain' overlays = 'screen_center'>
+ <layout type = 'vertical' padding = '4, 4, 4, 4'>
+ <widget name = 'Resume'
+ type = 'Button'
+ />
+ <space size = '8'/>
+ <widget name = 'Load'
+ type = 'Button'
+ />
+ <widget name = 'Save'
+ type = 'Button'
+ />
+ <space size = '8'/>
+ <widget name = 'Options'
+ type = 'Button'
+ />
+ <widget name = 'Help'
+ type = 'Button'
+ />
+ <widget name = 'About'
+ type = 'Button'
+ />
+ <space size = '8'/>
+ <widget name = 'Quit'
+ type = 'Button'
+ />
+ </layout>
+ </dialog>
+
+ <dialog name = 'ScummConfig' overlays = 'screen_center'>
<layout type = 'vertical' padding = '8, 8, 8, 8'>
<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' center = 'true'>
<widget name = 'vcMusicText'
diff --git a/ports.mk b/ports.mk
index 0a7f6c4d92..226052713e 100644
--- a/ports.mk
+++ b/ports.mk
@@ -44,9 +44,7 @@ bundle: scummvm-static
cp $(srcdir)/icons/scummvm.icns $(bundle_name)/Contents/Resources/
cp $(DIST_FILES_DOCS) $(bundle_name)/
cp $(DIST_FILES_THEMES) $(bundle_name)/Contents/Resources/
-ifdef DIST_FILES_ENGINEDATA
cp $(DIST_FILES_ENGINEDATA) $(bundle_name)/Contents/Resources/
-endif
$(srcdir)/tools/credits.pl --rtf > $(bundle_name)/Contents/Resources/Credits.rtf
chmod 644 $(bundle_name)/Contents/Resources/*
cp scummvm-static $(bundle_name)/Contents/MacOS/scummvm
@@ -58,9 +56,7 @@ iphonebundle: iphone
cp $(srcdir)/dists/iphone/Info.plist $(bundle_name)/
cp $(DIST_FILES_DOCS) $(bundle_name)/
cp $(DIST_FILES_THEMES) $(bundle_name)/
-ifdef DIST_FILES_ENGINEDATA
cp $(DIST_FILES_ENGINEDATA) $(bundle_name)/
-endif
$(STRIP) scummvm
ldid -S scummvm
chmod 755 scummvm
@@ -161,9 +157,7 @@ win32dist: $(EXECUTABLE)
mkdir -p $(WIN32PATH)
$(STRIP) $(EXECUTABLE) -o $(WIN32PATH)/$(EXECUTABLE)
cp $(DIST_FILES_THEMES) $(WIN32PATH)
-ifdef DIST_FILES_ENGINEDATA
cp $(DIST_FILES_ENGINEDATA) $(WIN32PATH)
-endif
cp $(srcdir)/AUTHORS $(WIN32PATH)/AUTHORS.txt
cp $(srcdir)/COPYING $(WIN32PATH)/COPYING.txt
cp $(srcdir)/COPYING.LGPL $(WIN32PATH)/COPYING.LGPL.txt
@@ -184,9 +178,7 @@ aos4dist: $(EXECUTABLE)
$(STRIP) $(EXECUTABLE) -o $(AOS4PATH)/$(EXECUTABLE)
cp icons/scummvm.info $(AOS4PATH)/$(EXECUTABLE).info
cp $(DIST_FILES_THEMES) $(AOS4PATH)/themes/
-ifdef DIST_FILES_ENGINEDATA
cp $(DIST_FILES_ENGINEDATA) $(AOS4PATH)/extras/
-endif
cp $(srcdir)/AUTHORS $(AOS4PATH)/AUTHORS.txt
cp $(srcdir)/COPYING $(AOS4PATH)/COPYING.txt
cp $(srcdir)/COPYING.LGPL $(AOS4PATH)/COPYING.LGPL.txt
diff --git a/sound/decoders/adpcm.cpp b/sound/decoders/adpcm.cpp
index c8a907d13e..7a85bc24d5 100644
--- a/sound/decoders/adpcm.cpp
+++ b/sound/decoders/adpcm.cpp
@@ -724,10 +724,6 @@ int16 Ima_ADPCMStream::decodeIMA(byte code, int channel) {
}
RewindableAudioStream *makeADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, typesADPCM type, int rate, int channels, uint32 blockAlign) {
- // If size is 0, report the entire size of the stream
- if (!size)
- size = stream->size();
-
switch (type) {
case kADPCMOki:
return new Oki_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign);
diff --git a/sound/mods/rjp1.cpp b/sound/mods/rjp1.cpp
index be376d61a4..fc1b49e9e9 100644
--- a/sound/mods/rjp1.cpp
+++ b/sound/mods/rjp1.cpp
@@ -422,7 +422,7 @@ void Rjp1::setupNote(Rjp1Channel *channel, int16 period) {
channel->envelopeMode = 4;
channel->data = channel->waveData;
channel->pos = READ_BE_UINT16(note + 16);
- channel->len = channel->pos + READ_BE_UINT16(note + 18);
+ channel->len = READ_BE_UINT16(note + 18);
channel->setupNewNote = true;
}
}
diff --git a/test/common/str.h b/test/common/str.h
index 6581c37cdb..16fb0859db 100644
--- a/test/common/str.h
+++ b/test/common/str.h
@@ -118,30 +118,6 @@ class StringTestSuite : public CxxTest::TestSuite
TS_ASSERT_EQUALS(foo3, "fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd""fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd");
}
- void test_refCount5() {
- // using external storage
- Common::String foo1("HelloHelloHelloHelloAndHi");
- Common::String foo2(foo1);
-
- for (Common::String::iterator i = foo2.begin(); i != foo2.end(); ++i)
- *i = 'h';
-
- TS_ASSERT_EQUALS(foo1, "HelloHelloHelloHelloAndHi");
- TS_ASSERT_EQUALS(foo2, "hhhhhhhhhhhhhhhhhhhhhhhhh");
- }
-
- void test_refCount6() {
- // using internal storage
- Common::String foo1("Hello");
- Common::String foo2(foo1);
-
- for (Common::String::iterator i = foo2.begin(); i != foo2.end(); ++i)
- *i = 'h';
-
- TS_ASSERT_EQUALS(foo1, "Hello");
- TS_ASSERT_EQUALS(foo2, "hhhhh");
- }
-
void test_self_asignment() {
Common::String foo1("12345678901234567890123456789012");
foo1 = foo1.c_str() + 2;
diff --git a/tools/create_msvc/create_msvc.cpp b/tools/create_msvc/create_msvc.cpp
index 1c395b01aa..fcae638c50 100644
--- a/tools/create_msvc/create_msvc.cpp
+++ b/tools/create_msvc/create_msvc.cpp
@@ -512,6 +512,8 @@ int main(int argc, char *argv[]) {
// 4103 (alignment changed after including header, may be due to missing #pragma pack(pop))
// used by pack-start / pack-end
//
+ // 4121 (alignment of a member was sensitive to packing)
+ //
// 4127 (conditional expression is constant)
// used in a lot of engines
//
@@ -565,6 +567,7 @@ int main(int argc, char *argv[]) {
projectWarnings["lure"] = "4189;4355";
projectWarnings["kyra"] = "4355";
projectWarnings["m4"] = "4355";
+ projectWarnings["mohawk"] = "4121";
ProjectProvider *provider = NULL;
diff --git a/tools/md5table.c b/tools/md5table.c
index 7d76b7541d..cb2959ed88 100644
--- a/tools/md5table.c
+++ b/tools/md5table.c
@@ -222,7 +222,7 @@ int main(int argc, char *argv[])
const int entrySize = 256;
int numEntries = 0, maxEntries = 1;
- char *entriesBuffer = (char *)malloc(maxEntries * entrySize);
+ char *entriesBuffer = malloc(maxEntries * entrySize);
typedef enum {
kCPPOutput,
@@ -295,7 +295,7 @@ int main(int argc, char *argv[])
} else if (entry.md5) {
if (numEntries >= maxEntries) {
maxEntries *= 2;
- entriesBuffer = (char *)realloc(entriesBuffer, maxEntries * entrySize);
+ entriesBuffer = realloc(entriesBuffer, maxEntries * entrySize);
}
if (0 == strcmp(entry.variant, "-"))
entry.variant = "";
diff --git a/tools/module.mk b/tools/module.mk
index 2c62e427ea..5248454382 100644
--- a/tools/module.mk
+++ b/tools/module.mk
@@ -36,15 +36,15 @@ clean-tools:
tools/convbdf$(EXEEXT): $(srcdir)/tools/convbdf.c
$(QUIET)$(MKDIR) tools/$(DEPDIR)
- $(QUIET_LINK)$(LD) $(CFLAGS) -Wall -o $@ $<
+ $(QUIET_LINK)$(CC) $(CFLAGS) -Wall -o $@ $<
tools/md5table$(EXEEXT): $(srcdir)/tools/md5table.c
$(QUIET)$(MKDIR) tools/$(DEPDIR)
- $(QUIET_LINK)$(LD) $(CFLAGS) -Wall -o $@ $<
+ $(QUIET_LINK)$(CC) $(CFLAGS) -Wall -o $@ $<
tools/make-scumm-fontdata$(EXEEXT): $(srcdir)/tools/make-scumm-fontdata.c
$(QUIET)$(MKDIR) tools/$(DEPDIR)
- $(QUIET_LINK)$(LD) $(CFLAGS) -Wall -o $@ $<
+ $(QUIET_LINK)$(CC) $(CFLAGS) -Wall -o $@ $<
#
# Rules to explicitly rebuild the credits / MD5 tables.
diff --git a/tools/scumm-md5.txt b/tools/scumm-md5.txt
index c3e48d6c5a..b379bc837e 100644
--- a/tools/scumm-md5.txt
+++ b/tools/scumm-md5.txt
@@ -591,7 +591,6 @@ catalog Humongous Interactive Catalog
airport Let's Explore the Airport with Buzzy
d6334a5a9b61afe18c368540fdf522ca -1 en Mac - - - Joachim Eberhard
07433205acdca3bc553d0e731588b35f -1 en Windows - - - Kirben
- 3e861421f494711bc6f619d4aba60285 93231 ru Windows - - - sev
7ea2da67ebabea4ac20cee9f4f9d2934 -1 en Mac - Demo - khalek
8ffd618a776a4c0d8922bb28b09f8ce8 -1 en Windows - Demo - khalek
@@ -603,7 +602,6 @@ farm Let's Explore the Farm with Buzzy
a5c5388da9bf0e6662fdca8813a79d13 86962 en Windows - - - George Kormendi
a85856675429fe88051744f755b72f93 -1 en Windows - - - Kirben
a2386da005672cbd5136f4f27a626c5f 87061 nl Windows - - - George Kormendi
- 5dda73606533d66a4c3f4f9ea6e842af 87061 ru Windows - - - sev
39fd6db10d0222d817025c4d3346e3b4 -1 en Mac - Demo - Joachim Eberhard
bf8b52fdd9a69c67f34e8e9fec72661c -1 en Windows HE 71 Demo - khalek, sev
@@ -715,7 +713,6 @@ puttmoon Putt-Putt Goes to the Moon
697c9b7c55a05d8199c48b48e379d2c8 -1 he DOS - - - sev
9dc02577bf50d4cfaf3de3fbac06fbe2 -1 en Mac - - - khalek
9c92eeaf517a31b7221ec2546ab669fd -1 en Windows HE 70 - - khalek
- 3c4c471342bd95505a42334367d8f127 12161 ru Windows HE 70 - - sev
aa6a91b7f6f119d1b7b1f2a4c9e24d59 6233 en DOS - Demo -
4af4a6b248103c1fe9edef619677f540 -1 en Mac - Demo - khalek