changeset 812:1e5cf1144f36

Move library source under src/ subdirectory.
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 16 May 2014 03:22:39 +0300
parents aebc2f8b2c2d
children b0cd28b6c9f3
files Makefile.gen dmargs.c dmargs.h dmargs_int.c dmblit.c dmblitfunc.h dmbstr.c dmbstr.h dmdrawline.h dmengine.c dmengine.h dmeval.c dmeval.h dmevalw.c dmfft.c dmfft.h dmfile.c dmfile.h dmfiletmpl.h dmgfx.c dmimage.c dmimage.h dmlerp.c dmlib.c dmlib.h dmline.c dmlineclip.h dmlinefunc.h dmmutex.h dmpack.c dmpack.h dmpackutil.c dmpackutil.h dmperlin.c dmq3d.c dmq3d.h dmres.c dmres.h dmresw.c dmresw.h dmscaledblit.h dmsimple.c dmstring.c dmtext.h dmtext_bm.c dmtext_ttf.c dmtimeline.c dmtimelinew.c dmunscaledblit.h dmvecmat.c dmvecmat.h dmwav.c dmwav.h lib64gfx.c lib64gfx.h libgfx.c libgfx.h setupfont.h setupimage.h setupmenubar.h src/dmargs.c src/dmargs.h src/dmargs_int.c src/dmblit.c src/dmblitfunc.h src/dmbstr.c src/dmbstr.h src/dmdrawline.h src/dmengine.c src/dmengine.h src/dmeval.c src/dmeval.h src/dmevalw.c src/dmfft.c src/dmfft.h src/dmfile.c src/dmfile.h src/dmfiletmpl.h src/dmgfx.c src/dmimage.c src/dmimage.h src/dmlerp.c src/dmlib.c src/dmlib.h src/dmline.c src/dmlineclip.h src/dmlinefunc.h src/dmmutex.h src/dmpack.c src/dmpack.h src/dmpackutil.c src/dmpackutil.h src/dmperlin.c src/dmq3d.c src/dmq3d.h src/dmres.c src/dmres.h src/dmresw.c src/dmresw.h src/dmscaledblit.h src/dmsimple.c src/dmstring.c src/dmtext.h src/dmtext_bm.c src/dmtext_ttf.c src/dmtimeline.c src/dmtimelinew.c src/dmunscaledblit.h src/dmvecmat.c src/dmvecmat.h src/dmwav.c src/dmwav.h src/lib64gfx.c src/lib64gfx.h src/libgfx.c src/libgfx.h src/setupfont.h src/setupimage.h src/setupmenubar.h src/stb_image.c stb_image.c
diffstat 121 files changed, 19698 insertions(+), 19696 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.gen	Fri May 16 03:01:51 2014 +0300
+++ b/Makefile.gen	Fri May 16 03:22:39 2014 +0300
@@ -8,8 +8,9 @@
 TOOL_BINPATH ?= $(DMLIB)tools/
 TESTS_BINPATH ?= $(DMLIB)tests/
 
+DMLIBSRC = $(DMLIB)src/
 
-DM_CFLAGS += -I$(DMLIB)
+DM_CFLAGS += -I$(DMLIBSRC)
 ifeq ($(EXTRA_CFLAGS),)
 EXTRA_CFLAGS=-O3 -march=core2 -DDM_DEVEL
 endif
@@ -283,7 +284,7 @@
 ###
 ### Generic rules
 ###
-$(OBJPATH)%.d: $(DMLIB)%.c
+$(OBJPATH)%.d: $(DMLIBSRC)%.c
 	@echo > $@
 	@grep '#\s*include\s*\"' $< | sed 's/#\s*include\s\s*"\(.*\)"/\1/' | \
 	while read i; do if test -e "$$i"; then echo "$$i" >> $@; fi; done
@@ -317,14 +318,15 @@
 
 
 
-$(OBJPATH)%.o: $(DMLIB)%.c $(DMLIB)%.h
+$(OBJPATH)%.o: $(DMLIBSRC)%.c $(DMLIBSRC)%.h
 	@echo " CC $<"
 	@$(CC) $(CFLAGS) -c -o $@ $< $(DM_CFLAGS)
 
-$(OBJPATH)%.o: $(DMLIB)%.c
+$(OBJPATH)%.o: $(DMLIBSRC)%.c
 	@echo " CC $<"
 	@$(CC) $(CFLAGS) -c -o $@ $< $(DM_CFLAGS)
 
+
 $(OBJPATH)%.o: %.c %.h
 	@echo " CC $<"
 	@$(CC) $(CFLAGS) -c -o $@ $< $(DM_CFLAGS)
@@ -341,7 +343,7 @@
 $(MINIJSS)jmix_c.c: $(MINIJSS)jmix_c_in.c $(MINIJSS)jmixtmpl_c.h $(MINIJSS)jmix_post_c.h
 	(echo "#include \"jssmix.h\"" && cpp $< $(DM_CFLAGS)) | sed "s/^# .*//g" > $@
 
-$(OBJPATH)dmimage.o: $(DMLIB)dmimage.c $(DMLIB)stb_image.c $(DMLIB)dmimage.h
+$(OBJPATH)dmimage.o: $(DMLIBSRC)dmimage.c $(DMLIBSRC)stb_image.c $(DMLIBSRC)dmimage.h
 	@echo " CC $+"
 	@$(CC) $(CFLAGS) -c -o $@ $< $(DM_CFLAGS)
 
@@ -358,19 +360,19 @@
 	@echo " CC $+"
 	@$(CC) $(CFLAGS) -c -o $@ $< $(DM_CFLAGS)
 
-$(OBJPATH)dmblit.o: $(DMLIB)dmblit.c $(DMLIB)dmscaledblit.h $(DMLIB)dmunscaledblit.h $(DMLIB)dmblitfunc.h $(DMLIB)dmlib.h
+$(OBJPATH)dmblit.o: $(DMLIBSRC)dmblit.c $(DMLIBSRC)dmscaledblit.h $(DMLIBSRC)dmunscaledblit.h $(DMLIBSRC)dmblitfunc.h $(DMLIBSRC)dmlib.h
 	@echo " CC $+"
 	@$(CC) $(CFLAGS) -c -o $@ $< $(DM_CFLAGS)
 
-$(OBJPATH)dmline.o: $(DMLIB)dmline.c $(DMLIB)dmdrawline.h $(DMLIB)dmlinefunc.h $(DMLIB)dmlineclip.h $(DMLIB)dmlib.h
+$(OBJPATH)dmline.o: $(DMLIBSRC)dmline.c $(DMLIBSRC)dmdrawline.h $(DMLIBSRC)dmlinefunc.h $(DMLIBSRC)dmlineclip.h $(DMLIBSRC)dmlib.h
 	@echo " CC $+"
 	@$(CC) $(CFLAGS) -c -o $@ $< $(DM_CFLAGS)
 
-$(OBJPATH)dmargs.o: $(DMLIB)dmargs.c $(DMLIB)dmargs.h $(DMLIB)dmargs_int.c $(DMLIB)dmlib.h
+$(OBJPATH)dmargs.o: $(DMLIBSRC)dmargs.c $(DMLIBSRC)dmargs.h $(DMLIBSRC)dmargs_int.c $(DMLIBSRC)dmlib.h
 	@echo " CC $+"
 	@$(CC) $(CFLAGS) -c -o $@ $< $(DM_CFLAGS)
 
-$(OBJPATH)libgfx.o: $(DMLIB)libgfx.c $(DMLIB)libgfx.h
+$(OBJPATH)libgfx.o: $(DMLIBSRC)libgfx.c $(DMLIBSRC)libgfx.h
 	@echo " CC $+"
 	@$(CC) $(CFLAGS) -c -o $@ $< $(DM_CFLAGS) $(LIBPNG_CFLAGS)
 
@@ -378,19 +380,19 @@
 $(DMLIB)assets/SetupFont.dmf: $(DMLIB)assets/SetupFont.fnt
 	$(FONTCONV_BIN) -o $@ $<
 
-$(DMLIB)setupfont.h: $(DMLIB)assets/SetupFont.dmf
+$(DMLIBSRC)setupfont.h: $(DMLIB)assets/SetupFont.dmf
 	$(DATA2INC_BIN) -q -C -n engineSetupFont -t Uint8 $< $@
 
-$(DMLIB)setupimage.h: $(DMLIB)assets/SetupImage.png
+$(DMLIBSRC)setupimage.h: $(DMLIB)assets/SetupImage.png
 	$(DATA2INC_BIN) -q -C -n engineSetupImage -t Uint8 $< $@
 
-$(DMLIB)setupmenubar.h: $(DMLIB)assets/SetupMenuBar.png
+$(DMLIBSRC)setupmenubar.h: $(DMLIB)assets/SetupMenuBar.png
 	$(DATA2INC_BIN) -q -C -n engineSetupMenuBar -t Uint8 $< $@
 
 
-$(OBJPATH)dmsimple.o: $(DMLIB)dmsimple.c $(DMLIB)dmengine.h \
-	$(DMLIB)setupmenubar.h $(DMLIB)setupfont.h \
-	$(DMLIB)setupimage.h $(DMLIB)dmsimple.c
+$(OBJPATH)dmsimple.o: $(DMLIBSRC)dmsimple.c $(DMLIBSRC)dmengine.h \
+	$(DMLIBSRC)setupmenubar.h $(DMLIBSRC)setupfont.h \
+	$(DMLIBSRC)setupimage.h $(DMLIBSRC)dmsimple.c
 	@echo " CC $+"
 	@$(CC) $(CFLAGS) -c -o $@ $< $(DM_CFLAGS)
 
@@ -457,7 +459,7 @@
 	@echo " LINK $+"
 	@$(CC) -o $@ $(filter %.o %.a,$+) $(DM_LDFLAGS)
 
-$(TOOL_BINPATH)ppl$(EXEEXT): $(DMLIB)setupfont.h $(OBJPATH)ppl.o $(DMLIB_A) 
+$(TOOL_BINPATH)ppl$(EXEEXT): $(DMLIBSRC)setupfont.h $(OBJPATH)ppl.o $(DMLIB_A) 
 	@echo " LINK $+"
 	@$(CC) -o $@ $(filter %.o %.a,$+) $(DM_LDFLAGS) $(SDL_LDFLAGS)
 
--- a/dmargs.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-#include "dmargs.h"
-#define TH_EXTERNAL 1
-#define optarg_t DMOptArg
-#define th_args_process dmArgsProcess
-#define th_args_help dmArgsPrintHelp
-
-#define THERR dmError
-#define th_calloc dmCalloc
-#define th_malloc dmMalloc
-#define th_free dmFree
-
-#include "dmargs_int.c"
--- a/dmargs.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Simple commandline argument processing functions
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2002-2008 Tecnic Software productions (TNSP)
- *
- * Please read file 'COPYING' for information on license and distribution.
- */
-#ifndef DMARGS_H
-#define DMARGS_H
-
-#include "dmlib.h"
-#include <stdio.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Option flags
- */
-#define OPT_NONE       (0)    // Simple option with no arguments
-#define OPT_ARGREQ     (1)    // Option's argument is required
-#define OPT_ARGOPT     (3)    // Option's argument is optional
-#define OPT_ARGMASK    (3)    // Mask for option argument flags
-#define OPT_REQUIRED   (4)    // This option is required to be given
-
-typedef struct {
-    int id;
-    char optShort;
-    char *optLong;
-    char *desc;
-    int flags;
-} DMOptArg;
-
-BOOL dmArgsProcess(int argc, char *argv[],
-     DMOptArg argList[], int argListN,
-     BOOL (*handleOpt)(int, char *, char *),
-     BOOL (*handleFile)(char *), BOOL);
-
-void dmArgsPrintHelp(FILE *, DMOptArg optList[], int optListN);
-
-#ifdef __cplusplus
-}
-#endif
-#endif // DMARGS_H
--- a/dmargs_int.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,418 +0,0 @@
-/*
- * Simple commandline argument processing
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2002-2008 Tecnic Software productions (TNSP)
- *
- * Please read file 'COPYING' for information on license and distribution.
- */
-/*
-Description
-===========
-Structures and functions for simple commandline argument processing,
-option argument handling (short and long forms supported).
-
-Output function for printing out short on-line help for said options
-and program commandline usage.
-
-
-Format for typical commandline:
-
-$ program -a -b -c --long-d -e argument-for-e --long-f="argument for f"
-
-where -a, -b and -c are short options without required arguments;
---long-d is a long option without argument; -e is short option with
-argument and finally --long-f is long option with argument.
-
-
-Introduction
-============
-Handling of commandline options in th_args_process() has various
-options, which effect how an option is handled. Also the error
-situations (unknown option/no required argument) can be handled
-in different ways.
-
-Typically th_args_process() is called as follows:
-
-BOOL optionHandlerCallback(int optionNumber, char *optionArgument, char *optionName)
-{
-  if (option is OK)
-    return TRUE;
-  else
-    return FALSE;
-}
-
-BOOL nonoptionHandlerCallback(char *argumentString)
-{
-  // return value same as in optionHandlerCallback
-}
-
-
-int main(int argc, char *argv[])
-{
-  if (th_args_process(argc, argv, optList, optListN,
-      optionHandlerCallback, nonoptionHandlerCallback)) {
-    ... arguments OK ...
-  } else {
-    ... arguments invalid or required arguments missing ...
-  }
-}
-
-
-NOTICE!
--------
-The return value from handler callbacks affects the return value of
-th_args_process(). Additionally, a failure in callback (returns FALSE)
-effects the argument processing if bailOut argument of th_args_process()
-is TRUE!
-
-If bailOut is TRUE, any error/failure in argument processing (including
-callbacks) immediately stops the argument processing and FALSE is
-returned from th_args_process().
-
-If bailOut is FALSE, most errors are "ignored", but FALSE is still returned
-if any errors occured.
-
-
-NOTICE #2!
-----------
-A small temporary buffer of N*sizeof(BOOL) (where N is number of
-options in optList[]) is allocated for processing required options.
-If this allocation fails, the program is immediately exited with
-code 128.
-
-
-Examples
-========
-Example of different options, in a fictional optionlist struct:
-
-optarg_t optList[] = {
-  // Option without arguments
-  { 0, '?', "help",      "Show this help",                    OPT_NONE },
-
-  // Option with a required argument
-  { 1, 'o', "output",    "Output file name",                  OPT_ARGREQ },
-  
-  // Option with optional argument
-  { 2, 'f', "foobar",    "Use foobar, with optional string",  OPT_ARGOPT },
-
-  // This option is required to be given, though without other flags
-  // it may not make much sense.
-  { 4, 'S', "stupid",     "You must give this option",        OPT_REQUIRED },
-
-  // The flags can be combined with OR operator: this option is both
-  // required to be specified, and also requires argument (the filename)
-  { 5, 'i', "input",     "Input file name",                   OPT_REQUIRED | OPT_ARGREQ },
-
-
-  // Option with only long form
-  { 0, 0,   "only-long", "Long option",                       OPT_NONE },
-
-  // Option with only short form
-  { 0, 's', NULL,        "Short option",                      OPT_NONE },
-
-};
-
-const int optListN = (sizeof(optList) / sizeof(optarg_t));
-
-
-*/
-#ifndef TH_EXTERNAL
-#include "th_util.h"
-#include "th_args.h"
-#include "th_string.h"
-#endif
-
-
-/* Check if option requires an argument
- */
-static BOOL th_args_check_arg(const optarg_t *o, const char *optArg)
-{
-    if ((o->flags & OPT_ARGMASK) == OPT_ARGREQ && optArg == NULL)
-    {
-        if (o->optShort != 0 && o->optLong != NULL)
-        {
-            THERR("Option '-%c ARG' (--%s=ARG) requires an argument!\n",
-                  o->optShort, o->optLong);
-        }
-        else if (o->optShort != 0)
-        {
-            THERR("Option '-%c ARG' requires an argument!\n", o->optShort);
-        }
-        else if (o->optLong != NULL)
-        {
-            THERR("Option --%s=ARG requires an argument!\n", o->optLong);
-        }
-
-        return FALSE;
-    }
-    else
-        return TRUE;
-}
-
-
-/* Handle short options
- */
-static BOOL th_args_process_short(char *currArg, int *newArgIndex,
-    BOOL *wasGiven, int argc, char *argv[],
-    optarg_t optList[], int optListN,
-    BOOL (*handleOpt)(int, char *, char *))
-{
-    char *tmpArg = currArg, *optArg;
-    int optN;
-    BOOL isFound;
-
-    // Short options can be combined: -a -b -c == -abc
-    while (*tmpArg)
-    {
-        for (optN = 0, isFound = FALSE; (optN < optListN) && !isFound; optN++)
-            if (*tmpArg == optList[optN].optShort)
-            {
-                // Get possible option argument, if needed
-                if ((optList[optN].flags & OPT_ARGMASK) != 0
-                    && (++(*newArgIndex) < argc))
-                    optArg = argv[*newArgIndex];
-                else
-                    optArg = NULL;
-
-                // Check if option argument is required
-                if (!th_args_check_arg(&optList[optN], optArg))
-                    return FALSE;
-                else
-                {
-                    char tmpStr[2] = { 0, 0 };
-
-                    // Option was given succesfully, try to handle it
-                    wasGiven[optN] = TRUE;
-
-                    tmpStr[0] = *tmpArg;
-
-                    if (!handleOpt(optList[optN].id, optArg, tmpStr))
-                        return FALSE;
-                }
-
-                isFound = TRUE;
-            }
-
-        if (!isFound)
-        {
-            THERR("Unknown short option '%c' in argument '-%s'\n",
-                  *tmpArg, currArg);
-            return FALSE;
-        }
-
-        tmpArg++;
-    }
-
-    return TRUE;
-}
-
-
-/* Handle long options
- */
-static BOOL th_args_process_long(char *currArg, int *newArgIndex,
-    BOOL *wasGiven, int argc, char *argv[],
-    optarg_t optList[], int optListN,
-    BOOL (*handleOpt)(int, char *, char *))
-{
-    int optN, optLen, i;
-    char *optArg;
-
-    (void) argc;
-    (void) argv;
-    (void) newArgIndex;
-
-    // Long option
-    for (optN = -1, optLen = i = 0; i < optListN && optN < 0; i++)
-        if (optList[i].optLong)
-        {
-            optLen = strlen(optList[i].optLong);
-            if (strcmp(currArg, optList[i].optLong) == 0)
-                optN = i;
-        }
-
-    // Get possible option argument, if needed
-    if (optN >= 0)
-    {
-        if ((optList[optN].flags & OPT_ARGMASK) != 0)
-        {
-            if (currArg[optLen] == '=')
-                optArg = &currArg[optLen + 1];
-            else
-                optArg = NULL;
-        }
-        else
-            optArg = NULL;
-
-        // Check if option argument is required
-        if (!th_args_check_arg(&optList[optN], optArg))
-            return FALSE;
-        else
-        {
-            // Option was given succesfully, try to handle it
-            wasGiven[optN] = TRUE;
-            if (!handleOpt(optList[optN].id, optArg, currArg))
-                return FALSE;
-        }
-    }
-    else
-    {
-        THERR("Unknown long option '--%s'\n", currArg);
-        return FALSE;
-    }
-
-    return TRUE;
-}
-
-
-/* Process arguments, handling short and long options by
- * calling the given callback functions.
- */
-BOOL th_args_process(int argc, char *argv[],
-                     optarg_t optList[], int optListN,
-                     BOOL(*handleOpt) (int, char *, char *),
-                     BOOL(*handleNonOption) (char *), BOOL bailOut)
-{
-    BOOL endOptions, optionsOK;
-    int argIndex, newArgIndex, i;
-    char *currArg;
-    BOOL *wasGiven;
-
-    // Allocate wasGiven
-    wasGiven = (BOOL *) th_calloc(optListN, sizeof(BOOL));
-    if (!wasGiven)
-    {
-        THERR("FATAL ERROR! Could not allocate wasGiven in th_args_process()!\n");
-        exit(128);
-    }
-
-    // Parse arguments
-    argIndex = 1;
-    optionsOK = TRUE;
-    endOptions = FALSE;
-    while (argIndex < argc)
-    {
-        currArg = argv[argIndex];
-        if ((currArg[0] == '-') && !endOptions)
-        {
-            newArgIndex = argIndex;
-            currArg++;
-            if (*currArg == '-')
-            {
-                // Check for "--", which ends the options-list
-                currArg++;
-                if (*currArg == 0)
-                {
-                    endOptions = TRUE;
-                    continue;
-                }
-
-                // Long options
-                if (!th_args_process_long(currArg, &newArgIndex,
-                                          wasGiven, argc, argv, optList,
-                                          optListN, handleOpt))
-                    optionsOK = FALSE;
-            }
-            else
-            {
-                // Short options
-                if (!th_args_process_short(currArg, &newArgIndex,
-                                           wasGiven, argc, argv, optList,
-                                           optListN, handleOpt))
-                    optionsOK = FALSE;
-            }
-
-            argIndex = newArgIndex;
-        }
-        else
-        {
-            // Was not option argument
-            if (handleNonOption == NULL
-                || (handleNonOption != NULL && !handleNonOption(currArg)))
-            {
-                THERR("Invalid argument '%s'\n", currArg);
-                optionsOK = FALSE;
-            }
-        }
-
-        // Check if we bail out on invalid argument
-        if (!optionsOK && bailOut)
-        {
-            th_free(wasGiven);
-            return FALSE;
-        }
-
-        argIndex++;
-    }
-
-    // Check wasGiven by isRequired
-    for (i = 0; i < optListN; i++)
-        if ((optList[i].flags & OPT_REQUIRED) != 0 && !wasGiven[i])
-        {
-            THERR("Option -%s (--%s) is required.\n",
-                  optList[i].optShort, optList[i].optLong);
-
-            optionsOK = FALSE;
-            if (bailOut)
-                break;
-        }
-
-    th_free(wasGiven);
-    return optionsOK;
-}
-
-
-/* Print help for commandline arguments/options
- */
-void th_args_help(FILE *outFile, optarg_t optList[], int optListN)
-{
-    int i, nrequired;
-
-    for (i = nrequired = 0; i < optListN; i++)
-    {
-        optarg_t *o = &optList[i];
-
-        // Print short option
-        if (o->optShort != 0)
-            fprintf(outFile, "  -%c,  ", o->optShort);
-        else
-            fprintf(outFile, "       ");
-
-        // Print long option
-        if (o->optLong)
-        {
-            char tmpStr[64], *p;
-
-            if ((o->flags & OPT_ARGMASK) == OPT_ARGOPT)
-            {
-                snprintf(tmpStr, sizeof(tmpStr), "%s[=ARG]",
-                         optList[i].optLong);
-                p = tmpStr;
-            }
-            else if ((o->flags & OPT_ARGMASK) == OPT_ARGREQ)
-            {
-                snprintf(tmpStr, sizeof(tmpStr), "%s=ARG",
-                         optList[i].optLong);
-                p = tmpStr;
-            }
-            else
-                p = o->optLong;
-
-            fprintf(outFile, "--%-15s", p);
-        }
-        else
-            fprintf(outFile, "                 ");
-
-        fprintf(outFile, "  %s.", optList[i].desc);
-
-        if (o->flags & OPT_REQUIRED)
-        {
-            fprintf(outFile, " [*]\n");
-            nrequired++;
-        }
-        else
-            fprintf(outFile, "\n");
-    }
-
-    if (nrequired > 0)
-        fprintf(outFile, "(Options marked with [*] are required)\n");
-}
--- a/dmblit.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,251 +0,0 @@
-/*
- * DMLib
- * -- Sprite / surface blitting functions
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2011 Tecnic Software productions (TNSP)
- */
-#include "dmlib.h"
-
-//#define DM_CLIP_DEBUG
-
-typedef struct
-{
-    int v0, v1, voffs, vadd;
-    DMFixedPoint32 vdelta;
-} DMQValue;
-
-
-int dmScaledClipCoord(DMQValue *pv, int v0, int v1, int v2, int clipMin, int clipMax)
-{
-    DMFixedPoint32 a, b;
-
-    // Basic bounds check
-    if (v1 < 1 || v2 < 1 || v0 + v2 < clipMin || v0 >= clipMax)
-    {
-#ifdef DM_CLIPDEBUG
-        printf("out of bounds\n");
-#endif
-        return -1;
-    }
-
-    // Calculate delta
-    FP_SETHL(a, v1, 0);
-    FP_CONV(b, v2);
-    FP_DIV_R(pv->vdelta, a, b);
-
-    // Perform clipping
-    if (v0 + v2 >= clipMax)
-    {
-        pv->vadd = v0;
-        pv->v1 = clipMax;
-    }
-    else
-    {
-        pv->vadd = clipMax - v2;
-        pv->v1 = v0 + v2;
-    }
-    
-    if (v0 < clipMin)
-    {
-        pv->voffs = clipMin - v0;
-        pv->v0 = clipMin;
-        pv->vadd -= v0 + clipMin;
-    }
-    else
-    {
-        pv->voffs = 0;
-        pv->v0 = v0;
-    }
-    
-#ifdef DM_CLIP_DEBUG
-    printf("dmClipCoord(%d, (%d, %d), [%d, %d]): vdelta=",
-        v0, v1, v2, clipMin, clipMax);
-    FP_PRINTF(pv->vdelta);
-    printf(", v0=%d, v1=%d, voffs=%d, vadd=%d\n",
-        pv->v0, pv->v1, pv->voffs, pv->vadd);
-#endif
-
-    return 0;
-}
-
-
-int dmUnscaledClipCoord(DMQValue *pv, int v0, int v1, int clipMin, int clipMax)
-{
-    // Basic bounds check
-    if (v1 < 1 || v0 + v1 < clipMin || v0 >= clipMax)
-        return -1;
-
-    // Perform clipping
-    if (v0 + v1 >= clipMax)
-    {
-        pv->vadd = v0;
-        pv->v1 = clipMax;
-    }
-    else
-    {
-        pv->vadd = clipMax - v1;
-        pv->v1 = v0 + v1;
-    }
-    
-    if (v0 < clipMin)
-    {
-        pv->voffs = clipMin - v0;
-        pv->v0 = clipMin;
-        pv->vadd -= v0 + clipMin;
-    }
-    else
-    {
-        pv->voffs = 0;
-        pv->v0 = v0;
-    }
-    
-    return 0;
-}
-
-
-#include "dmblitfunc.h"
-
-
-static const DMScaledBlitFunc dmScaledBlitTable[DMD_NMODES][DMD_NBITDEPTHS][DMD_NBITDEPTHS] =
-{
-    // DMD_NONE
-    {
-        { dmScaledBlitSurface8to8             , dmScaledBlitSurface8to32 },
-        { NULL                                , dmScaledBlitSurface32to32 },
-    },
-    // DMD_TRANSPARENT
-    {
-        { dmScaledBlitSurface8to8Transparent  , dmScaledBlitSurface8to32Transparent },
-        { NULL                                , dmScaledBlitSurface32to32Transparent },
-    },
-    // DMD_SATURATE
-    {
-        { dmScaledBlitSurface8to8Saturate     , dmScaledBlitSurface8to32Saturate },
-        { NULL                                , dmScaledBlitSurface32to32Saturate },
-    },
-#if 0
-    // DMD_NONE | DMD_ANTIALIAS
-    {
-        { dmScaledBlitSurface8to8Antialias    , dmScaledBlitSurface8to32Antialias },
-        { NULL                                , dmScaledBlitSurface32to32Antialias },
-    },
-    // DMD_TRANSPARENT | DMD_ANTIALIAS
-    {
-        { dmScaledBlitSurface8to8AATransp     , dmScaledBlitSurface8to32AATransparent },
-        { NULL                                , dmScaledBlitSurface32to32AATransparent },
-    },
-    // DMD_SATURATE | DMD_ANTIALIAS
-    {
-        { dmScaledBlitSurface8to8AASaturate   , dmScaledBlitSurface8to32AASaturate },
-        { NULL                                , dmScaledBlitSurface32to32AASaturate },
-    },
-#endif
-};
-
-static const int ndmScaledBlitTable = sizeof(dmScaledBlitTable) / sizeof(dmScaledBlitTable[0]);
-
-
-DMScaledBlitFunc dmGetScaledBlitFunc(SDL_PixelFormat *src, SDL_PixelFormat *dst, int mode)
-{
-    int isrc, idst;
-    if (src == NULL || dst == NULL || mode < 0 || mode >= ndmScaledBlitTable)
-        return NULL;
-
-    isrc = dmBitsPerPixel2Index(src->BitsPerPixel);
-    idst = dmBitsPerPixel2Index(dst->BitsPerPixel);
-    if (isrc < 0 || idst < 0)
-        return NULL;
-    
-    return dmScaledBlitTable[mode][isrc][idst];
-}
-
-
-int dmScaledBlitSurfaceAny(SDL_Surface *src, const int x0, const int y0, const int dwidth, const int dheight, SDL_Surface *dst, int mode)
-{
-    DMScaledBlitFunc bfunc = dmGetScaledBlitFunc(src->format, dst->format, mode);
-    
-    if (bfunc == NULL)
-        return -15;
-
-    return bfunc(src, x0, y0, dwidth, dheight, dst);
-}
-
-
-static const DMUnscaledBlitFunc dmUnscaledBlitTable[DMD_NMODES][DMD_NBITDEPTHS][DMD_NBITDEPTHS] =
-{
-    // DMD_NONE
-    {
-        { dmUnscaledBlitSurface8to8           , dmUnscaledBlitSurface8to32 },
-        { NULL                                , dmUnscaledBlitSurface32to32 },
-    },
-    // DMD_TRANSPARENT
-    {
-        { dmUnscaledBlitSurface8to8Transparent, dmUnscaledBlitSurface8to32Transparent },
-        { NULL                                , dmUnscaledBlitSurface32to32Transparent },
-    },
-    // DMD_SATURATE
-    {
-        { dmUnscaledBlitSurface8to8Saturate   , dmUnscaledBlitSurface8to32Saturate },
-        { NULL                                , dmUnscaledBlitSurface32to32Saturate },
-    },
-#if 0
-    // DMD_NONE | DMD_ANTIALIAS
-    {
-        { dmUnscaledBlitSurface8to8Antialias  , dmUnscaledBlitSurface8to32Antialias },
-        { NULL                                , dmUnscaledBlitSurface32to32Antialias },
-    },
-    // DMD_TRANSPARENT | DMD_ANTIALIAS
-    {
-        { dmUnscaledBlitSurface8to8AATransp   , dmUnscaledBlitSurface8to32AATransparent },
-        { NULL                                , dmUnscaledBlitSurface32to32AATransparent },
-    },
-    // DMD_SATURATE | DMD_ANTIALIAS
-    {
-        { dmUnscaledBlitSurface8to8AASaturate , dmUnscaledBlitSurface8to32AASaturate },
-        { NULL                                , dmUnscaledBlitSurface32to32AASaturate },
-    },
-#endif
-};
-
-static const int ndmUnscaledBlitTable = sizeof(dmUnscaledBlitTable) / sizeof(dmUnscaledBlitTable[0]);
-
-
-
-DMUnscaledBlitFunc dmGetUnscaledBlitFunc(SDL_PixelFormat *src, SDL_PixelFormat *dst, int mode)
-{
-    int isrc, idst;
-    if (src == NULL || dst == NULL || mode < 0 || mode >= ndmUnscaledBlitTable)
-        return NULL;
-
-    isrc = dmBitsPerPixel2Index(src->BitsPerPixel);
-    idst = dmBitsPerPixel2Index(dst->BitsPerPixel);
-    if (isrc < 0 || idst < 0)
-        return NULL;
-    
-    return dmUnscaledBlitTable[mode][isrc][idst];
-}
-
-
-int dmUnscaledBlitSurfaceAny(SDL_Surface *src, const int x0, const int y0, SDL_Surface *dst, int mode)
-{
-    DMUnscaledBlitFunc bfunc = dmGetUnscaledBlitFunc(src->format, dst->format, mode);
-    
-    if (bfunc == NULL)
-        return -15;
-
-    return bfunc(src, x0, y0, dst);
-}
-
-
-SDL_Surface *dmConvertScaledSurface(SDL_Surface *src, SDL_PixelFormat *fmt, Uint32 flags, const int dwidth, const int dheight)
-{
-    // Create the target surface
-    SDL_Surface *result = SDL_CreateRGBSurface(flags, dwidth, dheight, fmt->BitsPerPixel, fmt->Rmask, fmt->Gmask, fmt->Bmask, fmt->Amask);
-    if (result == NULL)
-        return NULL;
-    
-    // Use scaled blitting to convert the scaled image ..
-    dmScaledBlitSurfaceAny(src, 0, 0, dwidth, dheight, result, DMD_NONE);
-
-    return result;
-}
--- a/dmblitfunc.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,558 +0,0 @@
-/*
- * DMLib
- * -- Sprite / surface blitting functions
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2011-2012 Tecnic Software productions (TNSP)
- */
-
-// =======================================================================
-// DMD_NONE
-// =======================================================================
-
-#define DM_BLITFUNC_NAME dmScaledBlitSurface8to8
-#define DM_BLITFUNC_SRC_BYTES 1
-#define DM_BLITFUNC_DST_BYTES 1
-#define DM_BLITFUNC_SRC_TYPE Uint8
-#define DM_BLITFUNC_DST_TYPE Uint8
-
-#define DM_BLITFUNC_INNER *dp++ = sp[FP_GETH16(xv)];
-
-#include "dmscaledblit.h"
-
-// -----------------------------------------------------------------------
-
-#define DM_BLITFUNC_NAME dmScaledBlitSurface8to32
-#define DM_BLITFUNC_SRC_BYTES 1
-#define DM_BLITFUNC_DST_BYTES 4
-#define DM_BLITFUNC_SRC_TYPE Uint8
-#define DM_BLITFUNC_DST_TYPE Uint32
-
-#define DM_BLITFUNC_VARS const Uint32 *pal;
-#define DM_BLITFUNC_INIT \
-    if (src->format->palette == NULL || src->format->palette->ncolors < 256) return -2;	\
-    pal = (Uint32 *) src->format->palette->colors;
-
-#define DM_BLITFUNC_INNER *dp++ = pal[sp[FP_GETH16(xv)]];
-
-#include "dmscaledblit.h"
-
-// -----------------------------------------------------------------------
-
-#define DM_BLITFUNC_NAME dmScaledBlitSurface32to32
-#define DM_BLITFUNC_SRC_BYTES 4
-#define DM_BLITFUNC_DST_BYTES 4
-#define DM_BLITFUNC_SRC_TYPE Uint32
-#define DM_BLITFUNC_DST_TYPE Uint32
-#define DM_BLITFUNC_INIT
-#define DM_BLITFUNC_INNER *dp++ = sp[FP_GETH16(xv)];
-
-#include "dmscaledblit.h"
-
-
-// =======================================================================
-// DMD_TRANSPARENT
-// =======================================================================
-
-#define DM_BLITFUNC_NAME dmScaledBlitSurface8to8Transparent
-#define DM_BLITFUNC_SRC_BYTES 1
-#define DM_BLITFUNC_DST_BYTES 1
-#define DM_BLITFUNC_SRC_TYPE Uint8
-#define DM_BLITFUNC_DST_TYPE Uint8
-
-#define DM_BLITFUNC_INNER \
-    *dp = sp[FP_GETH16(xv)] ? sp[FP_GETH16(xv)] : *dp; dp++;
-
-#include "dmscaledblit.h"
-
-// -----------------------------------------------------------------------
-
-#define DM_BLITFUNC_NAME dmScaledBlitSurface8to32Transparent
-#define DM_BLITFUNC_SRC_BYTES 1
-#define DM_BLITFUNC_DST_BYTES 4
-#define DM_BLITFUNC_SRC_TYPE Uint8
-#define DM_BLITFUNC_DST_TYPE DMRGBA32
-#define DM_BLITFUNC_VARS const DMRGBA32 *pal;
-#define DM_BLITFUNC_INIT \
-    if (src->format->palette == NULL || src->format->palette->ncolors < 256) return -2;	\
-    pal = (DMRGBA32 *) src->format->palette->colors;
-
-#define DM_BLITFUNC_INNER \
-    const DMRGBA32 q = pal[sp[FP_GETH16(xv)]]; \
-    dp->r += ((q.r - dp->r) * q.a) >> 8; \
-    dp->g += ((q.g - dp->g) * q.a) >> 8; \
-    dp->b += ((q.b - dp->b) * q.a) >> 8; \
-    dp->a  = q.a; \
-    dp++;
-
-#include "dmscaledblit.h"
-
-
-// -----------------------------------------------------------------------
-
-#define DM_BLITFUNC_NAME dmScaledBlitSurface32to32Transparent
-#define DM_BLITFUNC_SRC_BYTES 4
-#define DM_BLITFUNC_DST_BYTES 4
-
-#ifdef DM_USE_SIMD
-#define DM_BLITFUNC_VARS \
-    const Uint32 qpdmask =       0xff000000; \
-    const Uint64 qpdrm   = 0xff00ff00ff00ffULL;
-    
-#define DM_BLITFUNC_SRC_TYPE Uint32
-#define DM_BLITFUNC_DST_TYPE Uint32
-#define DM_BLITFUNC_INNER			\
-    asm(					\
-        "movd        %2,     %%mm1\n"		\
-        \
-        "movd        %3,     %%mm2\n"		\
-        "movq        %%mm1,  %%mm5\n"		\
-        "pand        %%mm2,  %%mm5\n"		\
-        "psrlw       $8,     %%mm5\n"		\
-        "punpcklwd   %%mm5,  %%mm5\n"		\
-        "punpckhwd   %%mm5,  %%mm5\n"		\
-        \
-        "pxor        %%mm2,  %%mm2\n"		\
-        "movd        %1,     %%mm3\n"		\
-        "punpcklbw   %%mm2,  %%mm1\n"		\
-        "punpcklbw   %%mm2,  %%mm3\n"		\
-        \
-        "psubw       %%mm3,  %%mm1\n"		\
-        "pmullw      %%mm5,  %%mm1\n"		\
-        "psraw       $8,     %%mm1\n"		\
-        "paddw       %%mm3,  %%mm1\n"		\
-        "pand        %4,     %%mm1\n"		\
-        "packuswb    %%mm2,  %%mm1\n"		\
-        "movd        %%mm1,  %0\n"		\
-        : "=m" (*dp)				\
-        : "m" (*dp), "m" (sp[FP_GETH16(xv)]), "m" (qpdmask), "m" (qpdrm)	\
-        : "memory", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5" ); dp++;
-
-#define DM_BLITFUNC_FINISH asm("emms\n");
-
-#else
-
-#define DM_BLITFUNC_SRC_TYPE DMRGBA32
-#define DM_BLITFUNC_DST_TYPE DMRGBA32
-#define DM_BLITFUNC_INNER \
-    const DMRGBA32 q = sp[FP_GETH16(xv)]; \
-    dp->r += ((q.r - dp->r) * q.a) >> 8; \
-    dp->g += ((q.g - dp->g) * q.a) >> 8; \
-    dp->b += ((q.b - dp->b) * q.a) >> 8; \
-    dp->a  = q.a; \
-    dp++;
-#endif
-
-#include "dmscaledblit.h"
-
-// -----------------------------------------------------------------------
-
-#define DM_BLITFUNC_NAME dmScaledBlitSurface32to32TransparentX
-#define DM_BLITFUNC_SRC_BYTES 4
-#define DM_BLITFUNC_DST_BYTES 4
-#define DM_BLITFUNC_SRC_TYPE DMRGBA32
-#define DM_BLITFUNC_DST_TYPE DMRGBA32
-#define DM_BLITFUNC_INIT
-
-#define DM_BLITFUNC_INNER \
-    const DMRGBA32 q = sp[FP_GETH16(xv)]; \
-    dp->r = (q.r * q.a + dp->r * dp->a) >> 8; \
-    dp->g = (q.g * q.a + dp->g * dp->a) >> 8; \
-    dp->b = (q.b * q.a + dp->b * dp->a) >> 8; \
-    dp->a = q.a ? q.a : dp->a; \
-    dp++;
-
-#include "dmscaledblit.h"
-
-
-// -----------------------------------------------------------------------
-
-#define DM_BLITFUNC_NAME dmScaledBlitSurface32to32TransparentGA
-#define DM_BLITFUNC_SRC_BYTES 4
-#define DM_BLITFUNC_DST_BYTES 4
-#define DM_BLITFUNC_ARGS , Uint32 alpha
-
-#ifdef DM_USE_SIMD
-#define DM_BLITFUNC_VARS \
-    const Uint32 qpdmask =       0xff000000; \
-    const Uint64 qpdrm   = 0xff00ff00ff00ffULL;
-
-#define DM_BLITFUNC_SRC_TYPE Uint32
-#define DM_BLITFUNC_DST_TYPE Uint32
-#define DM_BLITFUNC_INNER_INIT \
-    asm(					\
-        "movd        %0,     %%mm4\n"		\
-        "punpcklwd   %%mm4,  %%mm4\n"		\
-        "punpckldq   %%mm4,  %%mm4\n"		\
-        : 					\
-        : "m" (alpha)				\
-        : "%mm4" );
-
-#define DM_BLITFUNC_INNER			\
-    asm(					\
-        "movd        %2,     %%mm1\n"		\
-        \
-        "movd        %3,     %%mm2\n"		\
-        "movq        %%mm1,  %%mm5\n"		\
-        "pand        %%mm2,  %%mm5\n"		\
-        "psrlw       $8,     %%mm5\n"		\
-        "punpcklwd   %%mm5,  %%mm5\n"		\
-        "punpckhwd   %%mm5,  %%mm5\n"		\
-        \
-        "pmullw      %%mm4,  %%mm5\n"		\
-        "psrlw       $8,     %%mm5\n"		\
-        \
-        "pxor        %%mm2,  %%mm2\n"		\
-        "movd        %1,     %%mm3\n"		\
-        "punpcklbw   %%mm2,  %%mm1\n"		\
-        "punpcklbw   %%mm2,  %%mm3\n"		\
-        \
-        "psubw       %%mm3,  %%mm1\n"		\
-        "pmullw      %%mm5,  %%mm1\n"		\
-        "psraw       $8,     %%mm1\n"		\
-        "paddw       %%mm3,  %%mm1\n"		\
-        "pand        %4,     %%mm1\n"		\
-        "packuswb    %%mm2,  %%mm1\n"		\
-        "movd        %%mm1,  %0\n"		\
-        : "=m" (*dp)				\
-        : "m" (*dp), "m" (sp[FP_GETH16(xv)]), "m" (qpdmask), "m" (qpdrm)	\
-        : "memory", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5" ); dp++;
-
-#define DM_BLITFUNC_FINISH asm("emms\n");
-
-#else
-
-#define DM_BLITFUNC_SRC_TYPE DMRGBA32
-#define DM_BLITFUNC_DST_TYPE DMRGBA32
-#define DM_BLITFUNC_INNER \
-    const DMRGBA32 q = sp[FP_GETH16(xv)]; \
-    const int a = (alpha * q.a) >> 8; \
-    dp->r += ((q.r - dp->r) * a) >> 8; \
-    dp->g += ((q.g - dp->g) * a) >> 8; \
-    dp->b += ((q.b - dp->b) * a) >> 8; \
-    dp->a  = a;
-    dp++;
-#endif
-
-#include "dmscaledblit.h"
-
-// =======================================================================
-// DMD_SATURATE
-// =======================================================================
-
-#define DM_BLITFUNC_NAME dmScaledBlitSurface8to8Saturate
-#define DM_BLITFUNC_SRC_BYTES 1
-#define DM_BLITFUNC_DST_BYTES 1
-#define DM_BLITFUNC_SRC_TYPE Uint8
-#define DM_BLITFUNC_DST_TYPE Uint8
-#define DM_BLITFUNC_INNER \
-    const int q = sp[FP_GETH16(xv)] + *dp; \
-    *(dp++) = q < 256 ? q : 255;
-
-#include "dmscaledblit.h"
-
-// -----------------------------------------------------------------------
-
-#define DM_BLITFUNC_NAME dmScaledBlitSurface8to32Saturate
-#define DM_BLITFUNC_SRC_BYTES 1
-#define DM_BLITFUNC_DST_BYTES 4
-#define DM_BLITFUNC_SRC_TYPE Uint8
-#define DM_BLITFUNC_DST_TYPE DMRGBA32
-#define DM_BLITFUNC_VARS const DMRGBA32 *pal;
-#define DM_BLITFUNC_INIT \
-    if (src->format->palette == NULL || src->format->palette->ncolors < 256) return -2;	\
-    pal = (DMRGBA32 *) src->format->palette->colors;
-
-#ifdef DM_USE_SIMD
-#define DM_BLITFUNC_INNER				\
-    asm("movd        %2,     %%mm1\n"		\
-        "movd        %1,     %%mm2\n"		\
-        "paddusb     %%mm2,  %%mm1\n"		\
-        "movd        %%mm1,  %0\n"		\
-        : "=m" (*dp)				\
-        : "m" (*dp), "m" (pal[sp[FP_GETH16(xv)]])	\
-        : "memory", "%mm1", "%mm2" ); dp++;
-
-#define DM_BLITFUNC_FINISH asm("emms\n");
-#else
-#define DM_BLITFUNC_INNER \
-    const DMRGBA32 q = pal[sp[FP_GETH16(xv)]]; \
-    const int qr = dp->r + q.r, qg = dp->g + q.g, qb = dp->b + q.b; \
-    dp->r = qr < 256 ? qr : 255; \
-    dp->g = qg < 256 ? qg : 255; \
-    dp->b = qb < 256 ? qb : 255; \
-    dp->a = q.a; \
-    dp++;
-#endif
-
-#include "dmscaledblit.h"
-
-// -----------------------------------------------------------------------
-
-#define DM_BLITFUNC_NAME dmScaledBlitSurface32to32Saturate
-#define DM_BLITFUNC_SRC_BYTES 4
-#define DM_BLITFUNC_DST_BYTES 4
-#define DM_BLITFUNC_INIT
-
-#ifdef DM_USE_SIMD
-#define DM_BLITFUNC_SRC_TYPE Uint32
-#define DM_BLITFUNC_DST_TYPE Uint32
-#define DM_BLITFUNC_INNER				\
-    asm("movd        %2,     %%mm1\n"		\
-        "movd        %1,     %%mm2\n"		\
-        "paddusb     %%mm2,  %%mm1\n"		\
-        "movd        %%mm1,  %0\n"		\
-        : "=m" (*dp)				\
-        : "m" (*dp), "m" (sp[FP_GETH16(xv)])	\
-        : "memory", "%mm1", "%mm2" ); dp++;
-
-#define DM_BLITFUNC_FINISH asm("emms\n");
-#else
-#define DM_BLITFUNC_SRC_TYPE DMRGBA32
-#define DM_BLITFUNC_DST_TYPE DMRGBA32
-#define DM_BLITFUNC_INNER \
-    const DMRGBA32 q = sp[FP_GETH16(xv)]; \
-    const int qr = dp->r + q.r, qg = dp->g + q.g, qb = dp->b + q.b; \
-    dp->r = qr < 256 ? qr : 255; \
-    dp->g = qg < 256 ? qg : 255; \
-    dp->b = qb < 256 ? qb : 255; \
-    dp->a = q.a; \
-    dp++;
-#endif
-
-#include "dmscaledblit.h"
-
-
-
-// =======================================================================
-// =======================================================================
-
-
-
-// =======================================================================
-// DMD_NONE
-// =======================================================================
-
-#define DM_BLITFUNC_NAME dmUnscaledBlitSurface8to8
-#define DM_BLITFUNC_SRC_BYTES 1
-#define DM_BLITFUNC_DST_BYTES 1
-#define DM_BLITFUNC_SRC_TYPE Uint8
-#define DM_BLITFUNC_DST_TYPE Uint8
-
-#define DM_BLITFUNC_INNER *dp++ = sp[xv];
-
-#include "dmunscaledblit.h"
-
-// -----------------------------------------------------------------------
-
-#define DM_BLITFUNC_NAME dmUnscaledBlitSurface8to32
-#define DM_BLITFUNC_SRC_BYTES 1
-#define DM_BLITFUNC_DST_BYTES 4
-#define DM_BLITFUNC_SRC_TYPE Uint8
-#define DM_BLITFUNC_DST_TYPE Uint32
-
-#define DM_BLITFUNC_VARS const Uint32 *pal;
-#define DM_BLITFUNC_INIT \
-    if (src->format->palette == NULL || src->format->palette->ncolors < 256) return -2;	\
-    pal = (Uint32 *) src->format->palette->colors;
-
-#define DM_BLITFUNC_INNER *dp++ = pal[sp[xv]];
-
-#include "dmunscaledblit.h"
-
-// -----------------------------------------------------------------------
-
-#define DM_BLITFUNC_NAME dmUnscaledBlitSurface32to32
-#define DM_BLITFUNC_SRC_BYTES 4
-#define DM_BLITFUNC_DST_BYTES 4
-#define DM_BLITFUNC_SRC_TYPE Uint32
-#define DM_BLITFUNC_DST_TYPE Uint32
-#define DM_BLITFUNC_INIT
-#define DM_BLITFUNC_INNER *dp++ = sp[xv];
-
-#include "dmunscaledblit.h"
-
-
-// =======================================================================
-// DMD_TRANSPARENT
-// =======================================================================
-
-#define DM_BLITFUNC_NAME dmUnscaledBlitSurface8to8Transparent
-#define DM_BLITFUNC_SRC_BYTES 1
-#define DM_BLITFUNC_DST_BYTES 1
-#define DM_BLITFUNC_SRC_TYPE Uint8
-#define DM_BLITFUNC_DST_TYPE Uint8
-
-#define DM_BLITFUNC_INNER \
-    *dp = sp[xv] ? sp[xv] : *dp; dp++;
-
-#include "dmunscaledblit.h"
-
-// -----------------------------------------------------------------------
-
-#define DM_BLITFUNC_NAME dmUnscaledBlitSurface8to32Transparent
-#define DM_BLITFUNC_SRC_BYTES 1
-#define DM_BLITFUNC_DST_BYTES 4
-#define DM_BLITFUNC_SRC_TYPE Uint8
-#define DM_BLITFUNC_DST_TYPE DMRGBA32
-#define DM_BLITFUNC_VARS const DMRGBA32 *pal;
-#define DM_BLITFUNC_INIT \
-    if (src->format->palette == NULL || src->format->palette->ncolors < 256) return -2;	\
-    pal = (DMRGBA32 *) src->format->palette->colors;
-
-#define DM_BLITFUNC_INNER \
-    const DMRGBA32 q = pal[sp[xv]]; \
-    dp->r += ((q.r - dp->r) * q.a) >> 8; \
-    dp->g += ((q.g - dp->g) * q.a) >> 8; \
-    dp->b += ((q.b - dp->b) * q.a) >> 8; \
-    dp->a  = q.a; \
-    dp++;
-
-#include "dmunscaledblit.h"
-
-
-// -----------------------------------------------------------------------
-
-#define DM_BLITFUNC_NAME dmUnscaledBlitSurface32to32Transparent
-#define DM_BLITFUNC_SRC_BYTES 4
-#define DM_BLITFUNC_DST_BYTES 4
-
-#ifdef DM_USE_SIMD
-#define DM_BLITFUNC_VARS \
-    const Uint32 qpdmask =       0xff000000; \
-    const Uint64 qpdrm   = 0xff00ff00ff00ffULL;
-    
-#define DM_BLITFUNC_SRC_TYPE Uint32
-#define DM_BLITFUNC_DST_TYPE Uint32
-#define DM_BLITFUNC_INNER				\
-    asm(					\
-        "movd        %2,     %%mm1\n"		\
-        \
-        "movd        %3,     %%mm2\n"		\
-        "movq        %%mm1,  %%mm5\n"		\
-        "pand        %%mm2,  %%mm5\n"		\
-        "psrlw       $8,     %%mm5\n"		\
-        "punpcklwd   %%mm5,  %%mm5\n"		\
-        "punpckhwd   %%mm5,  %%mm5\n"		\
-        \
-        "pxor        %%mm2,  %%mm2\n"		\
-        "movd        %1,     %%mm3\n"		\
-        "punpcklbw   %%mm2,  %%mm1\n"		\
-        "punpcklbw   %%mm2,  %%mm3\n"		\
-        \
-        "psubw       %%mm3,  %%mm1\n"		\
-        "pmullw      %%mm5,  %%mm1\n"		\
-        "psraw       $8,     %%mm1\n"		\
-        "paddw       %%mm3,  %%mm1\n"		\
-        "pand        %4,     %%mm1\n"		\
-        "packuswb    %%mm2,  %%mm1\n"		\
-        "movd        %%mm1,  %0\n"		\
-        : "=m" (*dp)				\
-        : "m" (*dp), "m" (sp[xv]), "m" (qpdmask), "m" (qpdrm)	\
-        : "memory", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5" ); dp++;
-
-#define DM_BLITFUNC_FINISH asm("emms\n");
-
-#else
-
-#define DM_BLITFUNC_SRC_TYPE DMRGBA32
-#define DM_BLITFUNC_DST_TYPE DMRGBA32
-#define DM_BLITFUNC_INNER \
-    const DMRGBA32 q = sp[xv]; \
-    dp->r += ((q.r - dp->r) * q.a) >> 8; \
-    dp->g += ((q.g - dp->g) * q.a) >> 8; \
-    dp->b += ((q.b - dp->b) * q.a) >> 8; \
-    dp->a  = q.a; \
-    dp++;
-#endif
-
-#include "dmunscaledblit.h"
-
-
-// =======================================================================
-// DMD_SATURATE
-// =======================================================================
-
-#define DM_BLITFUNC_NAME dmUnscaledBlitSurface8to8Saturate
-#define DM_BLITFUNC_SRC_BYTES 1
-#define DM_BLITFUNC_DST_BYTES 1
-#define DM_BLITFUNC_SRC_TYPE Uint8
-#define DM_BLITFUNC_DST_TYPE Uint8
-#define DM_BLITFUNC_INNER \
-    const int q = sp[xv] + *dp; \
-    *(dp++) = q < 256 ? q : 255;
-
-#include "dmunscaledblit.h"
-
-// -----------------------------------------------------------------------
-
-#define DM_BLITFUNC_NAME dmUnscaledBlitSurface8to32Saturate
-#define DM_BLITFUNC_SRC_BYTES 1
-#define DM_BLITFUNC_DST_BYTES 4
-#define DM_BLITFUNC_SRC_TYPE Uint8
-#define DM_BLITFUNC_DST_TYPE DMRGBA32
-#define DM_BLITFUNC_VARS const DMRGBA32 *pal;
-#define DM_BLITFUNC_INIT \
-    if (src->format->palette == NULL || src->format->palette->ncolors < 256) return -2;	\
-    pal = (DMRGBA32 *) src->format->palette->colors;
-
-#ifdef DM_USE_SIMD
-#define DM_BLITFUNC_INNER				\
-    asm("movd        %2,     %%mm1\n"		\
-        "movd        %1,     %%mm2\n"		\
-        "paddusb     %%mm2,  %%mm1\n"		\
-        "movd        %%mm1,  %0\n"		\
-        : "=m" (*dp)				\
-        : "m" (*dp), "m" (pal[sp[xv]])	\
-        : "memory", "%mm1", "%mm2" ); dp++;
-
-#define DM_BLITFUNC_FINISH asm("emms\n");
-#else
-#define DM_BLITFUNC_INNER \
-    const DMRGBA32 q = pal[sp[xv]]; \
-    const int qr = dp->r + q.r, qg = dp->g + q.g, qb = dp->b + q.b; \
-    dp->r = qr < 256 ? qr : 255; \
-    dp->g = qg < 256 ? qg : 255; \
-    dp->b = qb < 256 ? qb : 255; \
-    dp->a = q.a; \
-    dp++;
-#endif
-
-#include "dmunscaledblit.h"
-
-// -----------------------------------------------------------------------
-
-#define DM_BLITFUNC_NAME dmUnscaledBlitSurface32to32Saturate
-#define DM_BLITFUNC_SRC_BYTES 4
-#define DM_BLITFUNC_DST_BYTES 4
-#define DM_BLITFUNC_INIT
-
-#ifdef DM_USE_SIMD
-#define DM_BLITFUNC_SRC_TYPE Uint32
-#define DM_BLITFUNC_DST_TYPE Uint32
-#define DM_BLITFUNC_INNER			\
-    asm("movd        %2,     %%mm1\n"		\
-        "movd        %1,     %%mm2\n"		\
-        "paddusb     %%mm2,  %%mm1\n"		\
-        "movd        %%mm1,  %0\n"		\
-        : "=m" (*dp)				\
-        : "m" (*dp), "m" (sp[xv])	\
-        : "memory", "%mm1", "%mm2" ); dp++;
-
-#define DM_BLITFUNC_FINISH asm("emms\n");
-#else
-#define DM_BLITFUNC_SRC_TYPE DMRGBA32
-#define DM_BLITFUNC_DST_TYPE DMRGBA32
-#define DM_BLITFUNC_INNER \
-    const DMRGBA32 q = sp[xv]; \
-    const int qr = dp->r + q.r, qg = dp->g + q.g, qb = dp->b + q.b; \
-    dp->r = qr < 256 ? qr : 255; \
-    dp->g = qg < 256 ? qg : 255; \
-    dp->b = qb < 256 ? qb : 255; \
-    dp->a = q.a; \
-    dp++;
-#endif
-
-#include "dmunscaledblit.h"
-
-
-// =======================================================================
--- a/dmbstr.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * DMLib
- * -- Simple bitstream I/O functions
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012 Tecnic Software productions (TNSP)
- */
-#include "dmbstr.h"
-
-
-static int dmPutByteFILE(DMBitStreamContext *ctx, Uint8 val)
-{
-    return fputc(val, (FILE *) ctx->fp);
-}
-
-
-void dmInitBitStreamContext(DMBitStreamContext *ctx)
-{
-    ctx->buf     = 0;
-    ctx->bytecnt = 0;
-    ctx->bitcnt  = 8;
-}
-
-
-int dmInitBitStreamFILE(DMBitStreamContext *ctx, FILE *fp)
-{
-    if (ctx == NULL || fp == NULL)
-        return DMERR_NULLPTR;
-
-    ctx->putByte = dmPutByteFILE;
-    ctx->fp      = (void *) fp;
-
-    dmInitBitStreamContext(ctx);
-
-    return DMERR_OK;
-}
-
-
-BOOL dmPutBits(DMBitStreamContext *ctx, const int val, const int n)
-{
-    int i;
-    unsigned int mask = 1 << (n - 1);
-
-    for (i = 0; i < n; i++)
-    {
-        ctx->buf <<= 1;
-
-        if (val & mask)
-          ctx->buf |= 1;
-
-        mask >>= 1;
-        ctx->bitcnt--;
-
-        if (ctx->bitcnt == 0)
-        {
-            if (ctx->putByte(ctx, (ctx->buf & 0xff)) == EOF)
-                return FALSE;
-
-            ctx->bitcnt = 8;
-            ctx->bytecnt++;
-        }
-    }
-
-    return TRUE;
-}
-
-
-int dmFlushBitStream(DMBitStreamContext *ctx)
-{
-  if (ctx == NULL)
-      return DMERR_NULLPTR;
-
-  if (ctx->bitcnt != 8)
-      dmPutBits(ctx, 0, ctx->bitcnt);
-  
-  return 0;
-}
--- a/dmbstr.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-/*
- * DMLib
- * -- Simple bitstream I/O functions
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012 Tecnic Software productions (TNSP)
- */
-#ifndef DMBSTR_H
-#define DMBSTR_H
-
-#include "dmlib.h"
-
-typedef struct _DMBitStreamContext
-{
-  void *fp;
-  int (*putByte)(struct _DMBitStreamContext *ctx, Uint8 val);
-
-  int buf, bitcnt, bytecnt;
-} DMBitStreamContext;
-
-
-void  dmInitBitStreamContext(DMBitStreamContext *ctx);
-BOOL  dmPutBits(DMBitStreamContext *ctx, const int val, const int n);
-int   dmFlushBitStream(DMBitStreamContext *ctx);
-
-int   dmInitBitStreamFILE(DMBitStreamContext *ctx, FILE *fp);
-
-
-#ifdef __cplusplus
-}
-#endif
-#endif // DMBSTR_H
--- a/dmdrawline.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,108 +0,0 @@
-/*
- * DMLib
- * -- Simple Bresenham's style line drawing
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2011-2012 Tecnic Software productions (TNSP)
- */
-
-int DM_DRAWLINE_NAME (SDL_Surface *screen, DMFloat fx0, DMFloat fy0, DMFloat fx1, DMFloat fy1, const Uint32 col
-#ifdef DM_DRAWLINE_ARGS
-    DM_DRAWLINE_ARGS
-#endif
-)
-#ifdef DM_HEADER
-;
-#else
-{
-    int dx, dy, xstep, ystep;
-    const int qpitch = screen->pitch / DM_DRAWLINE_DST_BYTES;
-    (void) qpitch;
-    (void) col;
-
-    // Clipping
-    if (dmClipLineCoordsFloat(screen, &fx0, &fy0, &fx1, &fy1) < 0)
-        return -1;
-
-    int x0 = fx0, y0 = fy0, x1 = fx1, y1 = fy1;
-
-    // Compute initial deltas
-    dx = (x1 - x0) * 2;
-    dy = (y1 - y0) * 2;
-
-
-    if (dx < 0)
-    {
-        dx = -dx;
-        xstep = -1;
-    }
-    else
-        xstep = 1;
-
-    if (dy < 0)
-    {
-        dy = -dy;
-        ystep = -1;
-    }
-    else
-        ystep = 1;
-
-#ifndef DM_DRAWLINE_SPEC
-    // Compute offsets
-    y0 *= qpitch;
-    y1 *= qpitch;
-    ystep *= qpitch;
-#endif
-
-#ifdef DM_DRAWLINE_INIT
-    DM_DRAWLINE_INIT
-#endif
-
-    DM_DRAWLINE_DST_TYPE *pix = (DM_DRAWLINE_DST_TYPE *) screen->pixels;
-    (void) pix;
-
-    // Continue based on which delta is larger
-    if (dx > dy)
-    {
-        int afrac = dy - (dx / 2.0);
-        while (x0 != x1)
-        {
-            if (afrac >= 0)
-            {
-                y0 += ystep;
-                afrac -= dx;
-            }
-
-            x0 += xstep;
-            afrac += dy;
-            
-            DM_DRAWLINE_INNER
-        }
-    }
-    else
-    {
-        int afrac = dx - (dy / 2.0);
-        while (y0 != y1)
-        {
-            if (afrac >= 0)
-            {
-                x0 += xstep;
-                afrac -= dy;
-            }
-
-            y0 += ystep;
-            afrac += dx;
-
-            DM_DRAWLINE_INNER
-        }
-    }
-
-    return 0;
-}
-#endif
-
-#undef DM_DRAWLINE_NAME
-#undef DM_DRAWLINE_ARGS
-#undef DM_DRAWLINE_DST_BYTES
-#undef DM_DRAWLINE_DST_TYPE
-#undef DM_DRAWLINE_INIT
-#undef DM_DRAWLINE_INNER
--- a/dmengine.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,458 +0,0 @@
-/*
- * dmlib
- * -- Demo engine / editor common code and definitions
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012-2013 Tecnic Software productions (TNSP)
- */
-#include "dmengine.h"
-#include "dmimage.h"
-
-
-#ifdef DM_USE_TREMOR
-#include <tremor/ivorbiscodec.h>
-#include <tremor/ivorbisfile.h>
-#endif
-
-
-DMEngineData engine;
-DMEffect *engineEffects = NULL;
-int nengineEffects = 0, nengineEffectsAlloc = 0;
-
-
-int engineRegisterEffect(const DMEffect *ef)
-{
-    if (ef == NULL)
-        return DMERR_NULLPTR;
-
-    // Allocate more space for effects
-    if (nengineEffects + 1 >= nengineEffectsAlloc)
-    {
-        nengineEffectsAlloc += 16;
-        engineEffects = dmRealloc(engineEffects, sizeof(DMEffect) * nengineEffectsAlloc);
-        if (engineEffects == NULL)
-        {
-            dmError("Could not expand effects structure.\n"); 
-            return DMERR_INIT_FAIL;
-        }
-    }
-
-    // Copy effects structure
-    memcpy(engineEffects + nengineEffects, ef, sizeof(DMEffect));
-    nengineEffects++;
-    
-    return DMERR_OK;
-}
-
-
-int engineInitializeEffects(DMEngineData *engine)
-{
-    int i, res;
-
-    dmFree(engine->effectData);
-    engine->effectData = dmCalloc(nengineEffectsAlloc, sizeof(void *));
-    if (engine->effectData == NULL)
-    {
-        dmError("Could not expand effects data structure.\n"); 
-        return DMERR_INIT_FAIL;
-    }
-
-    for (i = 0; i < nengineEffects; i++)
-    {
-        if (engineEffects[i].init != NULL &&
-            (res = engineEffects[i].init(engine, &(engine->effectData[i]))) != DMERR_OK)
-            return res;
-    }
-
-    return DMERR_OK;
-}
-
-
-void engineShutdownEffects(DMEngineData *engine)
-{
-    if (engine != NULL && engine->effectData != NULL)
-    {
-        int i;
-        for (i = 0; i < nengineEffects; i++)
-        {
-            if (engineEffects[i].shutdown != NULL)
-                engineEffects[i].shutdown(engine, engine->effectData[i]);
-        }
-        dmFree(engine->effectData);
-        engine->effectData = NULL;
-    }
-}
-
-
-DMEffect *engineFindEffect(const char *name, const int nparams)
-{
-    int i;
-    for (i = 0; i < nengineEffects; i++)
-    {
-        if (strcmp(engineEffects[i].name, name) == 0 &&
-            engineEffects[i].nparams == nparams)
-            return &engineEffects[i];
-    }
-    return NULL;
-}
-
-
-DMEffect *engineFindEffectByName(const char *name)
-{
-    int i;
-    for (i = 0; i < nengineEffects; i++)
-    {
-        if (strcmp(engineEffects[i].name, name) == 0)
-            return &engineEffects[i];
-    }
-    return NULL;
-}
-
-
-static int engineResImageLoad(DMResource *res)
-{
-    SDL_Surface *img = dmLoadImage(res);
-    if (res != NULL)
-    {
-        res->resData = img;
-        return DMERR_OK;
-    }
-    else
-        return dmferror(res);
-}
-
-
-static void engineResImageFree(DMResource *res)
-{
-    SDL_FreeSurface((SDL_Surface *)res->resData);
-}
-
-static BOOL engineResImageProbe(DMResource *res, const char *fext)
-{
-    (void) res;
-    return fext != NULL && (strcasecmp(fext, ".jpg") == 0 || strcasecmp(fext, ".png") == 0);
-}
-
-
-#ifdef JSS_SUP_XM
-static int engineResXMModuleLoad(DMResource *res)
-{
-    return jssLoadXM(res, (JSSModule **) &(res->resData), FALSE);
-}
-
-static void engineResXMModuleFree(DMResource *res)
-{
-    jssFreeModule((JSSModule *) res->resData);
-}
-
-static BOOL engineResXMModuleProbe(DMResource *res, const char *fext)
-{
-    (void) res;
-    return fext != NULL && strcasecmp(fext, ".xm") == 0;
-}
-#endif
-
-
-#ifdef JSS_SUP_JSSMOD
-static int engineResJSSModuleLoad(DMResource *res)
-{
-    return jssLoadJSSMOD(res, (JSSModule **) &(res->resData), FALSE);
-}
-
-static void engineResJSSModuleFree(DMResource *res)
-{
-    jssFreeModule((JSSModule *) res->resData);
-}
-
-static BOOL engineResJSSModuleProbe(DMResource *res, const char *fext)
-{
-    (void) res;
-    return fext != NULL &&
-        (strcasecmp(fext, ".jss") == 0 || strcasecmp(fext, ".jmod") == 0);
-}
-#endif
-
-
-#ifdef DM_USE_TREMOR
-static size_t vorbisFileRead(void *ptr, size_t size, size_t nmemb, void *datasource)
-{
-    return dmfread(ptr, size, nmemb, (DMResource *) datasource);
-}
-
-static int vorbisFileSeek(void *datasource, ogg_int64_t offset, int whence)
-{
-    return dmfseek((DMResource *) datasource, offset, whence);
-}
-
-static int vorbisFileClose(void *datasource)
-{
-    (void) datasource;
-    return 0;
-}
-
-static long vorbisFileTell(void *datasource)
-{
-    return dmftell((DMResource *) datasource);
-}
-      
-
-static ov_callbacks vorbisFileCBS =
-{
-    vorbisFileRead,
-    vorbisFileSeek,
-    vorbisFileClose,
-    vorbisFileTell
-};
-
-static int engineResVorbisLoad(DMResource *res)
-{
-    OggVorbis_File vf;
-
-    dmMsg(1, "vorbisfile '%s', %d bytes resource loading\n",
-        res->filename, res->rawSize);
-
-    if (ov_open_callbacks(res, &vf, NULL, 0, vorbisFileCBS) < 0)
-        return DMERR_FOPEN;
-
-    res->resSize = ov_pcm_total(&vf, -1) * 2 * 2;
-    if ((res->resData = dmMalloc(res->resSize + 16)) == NULL)
-    {
-        ov_clear(&vf);
-        return DMERR_MALLOC;
-    }
-
-    dmMsg(1, "rdataSize=%d bytes?\n", res->resSize);
-
-    BOOL eof = FALSE;
-    int left = res->resSize;
-    char *ptr = res->resData;
-    int current_section;
-    while (!eof && left > 0)
-    {
-        int ret = ov_read(&vf, ptr, left > 4096 ? 4096 : left, &current_section);
-        if (ret == 0)
-            eof = TRUE;
-        else
-        if (ret < 0)
-        {
-            ov_clear(&vf);
-            return DMERR_INVALID_DATA;
-        }
-        else
-        {
-            left -= ret;
-            ptr += ret;
-        }
-    }
-
-    ov_clear(&vf);
-    return DMERR_OK;
-}
-
-static void engineResVorbisFree(DMResource *res)
-{
-    dmFree(res->resData);
-}
-
-static BOOL engineResVorbisProbe(DMResource *res, const char *fext)
-{
-    (void) res;
-    return fext != NULL && (strcasecmp(fext, ".ogg") == 0);
-}
-#endif
-
-
-static DMResourceDataOps engineResOps[] =
-{
-    {
-        engineResImageProbe,
-        engineResImageLoad,
-        engineResImageFree
-    },
-
-#ifdef JSS_SUP_JSSMOD
-    {
-        engineResJSSModuleProbe,
-        engineResJSSModuleLoad,
-        engineResJSSModuleFree
-    },
-#endif
-
-#ifdef JSS_SUP_XM
-    {
-        engineResXMModuleProbe,
-        engineResXMModuleLoad,
-        engineResXMModuleFree
-    },
-#endif
-
-#ifdef DM_USE_TREMOR
-    {
-        engineResVorbisProbe,
-        engineResVorbisLoad,
-        engineResVorbisFree
-    },
-#endif
-
-};
-
-static const int nengineResOps = sizeof(engineResOps) / sizeof(engineResOps[0]);
-
-
-int engineClassifier(DMResource *res)
-{
-    int i;
-    char *fext;
-
-    if (res == NULL)
-        return DMERR_NULLPTR;
-    
-    fext = strrchr(res->filename, '.');
-    for (i = 0; i < nengineResOps; i++)
-    {
-        DMResourceDataOps *rops = &engineResOps[i];
-        if (rops->probe != NULL && rops->probe(res, fext))
-        {
-            res->rops = rops;
-            return DMERR_OK;
-        }
-    }
-    
-    return DMERR_OK;
-}
-
-
-void *engineGetResource(DMEngineData *eng, const char *name)
-{
-    DMResource *res;
-    if (eng != NULL &&
-        (res = dmResourceFind(eng->resources, name)) != NULL &&
-        res->resData != NULL)
-        return res->resData;
-    else
-    {
-        dmError("Could not find resource '%s'.\n", name);
-        return NULL;
-    }
-}
-
-
-#ifdef DM_USE_JSS
-void engineGetJSSInfo(DMEngineData *eng, BOOL *playing, int *order, JSSPattern **pat, int *npattern, int *row)
-{
-    JSS_LOCK(eng->jssPlr);
-
-    *playing  = eng->jssPlr->isPlaying;
-    *row      = eng->jssPlr->row;
-    *pat      = eng->jssPlr->pattern;
-    *npattern = eng->jssPlr->npattern;
-    *order    = eng->jssPlr->order;
-
-    JSS_UNLOCK(eng->jssPlr);
-}
-
-
-void engineGetJSSChannelInfo(DMEngineData *eng, const int channel, int *ninst, int *nextInst, int *freq, int *note)
-{
-    JSS_LOCK(eng->jssPlr);
-
-    JSSPlayerChannel *chn = &(eng->jssPlr->channels[channel]);
-    *ninst    = chn->ninstrument;
-    *nextInst = chn->nextInstrument;
-    *freq     = chn->freq;
-    *note     = chn->note;
-
-    JSS_UNLOCK(eng->jssPlr);
-}
-#endif
-
-
-int engineGetTick(DMEngineData *engine)
-{
-    return engine->frameTime - engine->startTime;
-}
-
-
-float engineGetTimeDT(DMEngineData *engine)
-{
-    return (float) engineGetTick(engine) / 1000.0f;
-}
-
-
-int engineGetTimeDTi(DMEngineData *engine)
-{
-    return (float) engineGetTick(engine) / 1000;
-}
-
-
-int engineGetTime(DMEngineData *engine, int t)
-{
-    return engineGetTick(engine) - (1000 * t);
-}
-
-
-int engineGetDT(DMEngineData *engine, int t)
-{
-    return engineGetTime(engine, t) / 1000;
-}
-
-
-void engineAudioCallback(void *userdata, Uint8 *stream, int len)
-{
-    (void) userdata;
-
-    dmMutexLock(engine.audioStreamMutex);
-    engine.audioStreamBuf  = stream;
-    engine.audioStreamLen  = len / engine.audioSampleSize;
-    engine.audioTimePos   += (1000 * engine.audioStreamLen) / engine.optAfmt.freq;
-
-    if (engine.paused)
-    {
-        memset(stream, 0, len);
-    }
-    else
-    switch (engine.optAudioSetup)
-    {
-#ifdef DM_USE_JSS
-        case DM_ASETUP_JSS:
-            if (engine.jssDev != NULL)
-                jvmRenderAudio(engine.jssDev, stream, len / engine.audioSampleSize);
-            break;
-#endif
-#ifdef DM_USE_TREMOR
-        case DM_ASETUP_TREMOR:
-            if (engine.audioPos + len >= engine.audioRes->resSize)
-                engine.exitFlag = TRUE;
-            else
-            {
-                memcpy(stream, engine.audioRes->resData + engine.audioPos, len);
-                engine.audioPos += len;
-            }
-            break;
-#endif
-
-        default:
-            break;
-    }
-
-    dmMutexUnlock(engine.audioStreamMutex);
-}
-
-
-void enginePauseAudio(int status)
-{
-    if (status)
-        engine.audioStatus = SDL_AUDIO_PAUSED;
-    else
-        engine.audioStatus = SDL_AUDIO_PLAYING;
-
-    SDL_PauseAudio(status);
-}
-
-
-int engineGetVideoAspect(int width, int height)
-{
-    if (width > 0 && height > 0)
-        return (width * 1000) / height;
-    else
-        return 1;
-}
--- a/dmengine.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,383 +0,0 @@
-/*
- * dmlib
- * -- Demo engine / editor common code and definitions
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012-2013 Tecnic Software productions (TNSP)
- */
-#ifndef DMENGINE_H
-#define DMENGINE_H
-
-#include "dmlib.h"
-#include <SDL_events.h>
-#include <SDL_audio.h>
-#include "dmres.h"
-#include "dmvecmat.h"
-
-#ifdef DM_USE_JSS
-#include "jss.h"
-#include "jssmod.h"
-#include "jssmix.h"
-#include "jssplr.h"
-#endif
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Video setup screen / window size
-#define DM_VSETUP_WIDTH       640
-#define DM_VSETUP_HEIGHT      480
-
-
-// Video setup type
-enum
-{
-    DM_VSETUP_NONE    = 0x00,  // No video setup, just set window/screen to what demo specifies
-    DM_VSETUP_ASPECT  = 0x01,  // Only modes that match the optVidAspect aspect ratio are ok
-    DM_VSETUP_ANY     = 0x02,  // Any available mode is okay, the code can adapt
-};
-
-// Audio setup type
-enum
-{
-    DM_ASETUP_NONE    = 0,
-    DM_ASETUP_JSS     = 1,
-    DM_ASETUP_TREMOR  = 2,
-};
-
-
-
-#define DT_MAGIC_ID           "SDMETLNE"
-#define DT_MAX_EFFECT_PARAMS  16
-#define DT_MAX_NAME_LENGTH    32
-#define DT_FLOAT_STORE_SIZE   16
-
-
-enum
-{
-    EFIT_SET,    // No interpolation, just "set" the value
-    EFIT_LINEAR, // Linear interpolation
-    EFIT_SMOOTH, // Smoothstep interpolation
-};
-
-enum
-{
-    EFPT_INT,
-    EFPT_FLOAT,
-    EFPT_STRING,
-    EFPT_VECTOR,
-    EFPT_MATRIX,
-};
-
-
-typedef struct
-{
-    int type;                // Interpolation type (EFIT_*) between this and next point
-    int time;                // Offsets to event start, -1 == attach to event start, -2 = event end (if event)
-
-    int vint;
-    DMFloat vfloat;
-    DMVector vector;
-    DMMatrix matrix;
-} DMTimelinePoint;
-
-
-typedef struct
-{
-    int npoints, nallocated;
-    DMTimelinePoint *points;
-} DMTimelinePoints;
-
-
-typedef struct
-{
-    char *name;              // Name / description of the parameter
-    int type;                // Type (EFPT_*)
-
-    DMTimelinePoints pts;
-    char *vstr;
-
-    // Current values (interpolated)
-    int vint;
-    DMFloat vfloat;
-    DMVector vvector;
-    DMMatrix vmatrix;
-} DMTimelineEventParam;
-
-
-typedef struct
-{
-    char name[DT_MAX_NAME_LENGTH];
-    Uint32 type;
-} DMFTimelineEventParam;
-
-
-struct DMEngineData;
-
-
-typedef struct
-{
-    char *  name;
-    int     type;
-    
-    int     (*init)(struct DMEngineData *, void **data);
-    void    (*shutdown)(struct DMEngineData *, void *data);
-    int     (*render)(SDL_Surface *screen, void *data, const DMTimelineEventParam *params, const int time);
-
-    int     nparams;
-    DMTimelineEventParam params[DT_MAX_EFFECT_PARAMS];
-} DMEffect;
-
-
-#ifdef DM_USE_TIMELINE
-
-
-typedef struct
-{
-    Uint32 start, duration;
-    char effectName[DT_MAX_NAME_LENGTH];
-    Uint32 nparams;
-} DMFTimelineEvent;
-
-
-typedef struct
-{
-    int start, duration;
-    DMEffect *effect;
-    int nparams;
-    DMTimelineEventParam *params;
-} DMTimelineEvent;
-
-
-typedef struct
-{
-    BOOL enabled;
-    DMTimelinePoints points;
-} DMTimelineCurve;
-
-
-typedef struct
-{
-    Uint32 index, layer;
-    char name[DT_MAX_NAME_LENGTH];
-    Uint8 enabled;
-    Uint32 nevents;
-} DMFTimelineTrack;
-
-
-typedef struct
-{
-    int index;         // Track index
-    int layer;         // Target render layer (0 = engine.screen in software rendering)
-    char *name;        // Name of the timeline track
-    BOOL enabled;      // Enabled?
-
-    int nevents, nallocated;    // Number of events
-    DMTimelineEvent **events;   // Events
-
-    DMTimelineCurve composite;  // Composite curve (transparency of the "layer")
-} DMTimelineTrack;
-
-
-typedef struct
-{
-    char   magic[8];
-    char   name[DT_MAX_NAME_LENGTH];
-    Uint32 ntracks;
-    Uint32 duration;
-} DMFTimeline;
-
-
-typedef struct
-{
-    char *name;
-    int ntracks, nallocated, duration;
-    DMTimelineTrack **tracks;
-} DMTimeline;
-
-
-typedef struct
-{
-    DMTimelineTrack *track;
-    DMTimelineEvent *event;
-} DMPreparedEvent;
-
-
-typedef struct _DMPreparedEventGroup
-{
-    int start, end, nevents, nallocated;
-    DMPreparedEvent *events;
-
-    struct _DMPreparedEventGroup *next, *prev;
-} DMPreparedEventGroup;
-
-
-typedef struct
-{
-    int duration, ngroups, pos;
-    DMPreparedEventGroup **groups;
-} DMPreparedTimeline;
-
-#endif
-
-
-typedef struct DMEngineData
-{
-    DMResourceLib *resources;
-    void **effectData;
-
-#ifdef DM_USE_TIMELINE
-    DMResource *timeline;
-    DMTimeline *tl;
-    DMPreparedTimeline *ptl;
-#endif
-
-    int frameTime, frameCount,
-        startTime, endTime,
-        pauseTime;
-
-    BOOL pauseFlag, paused, exitFlag;
-
-    SDL_Surface *screen;
-    SDL_Event event;
-
-    int optVidWidth, optVidHeight,
-        optVidDepth, optVFlags,
-        optVidAspect, optVidSetup;
-    BOOL optVidNative;
-
-    int optResFlags;
-    char *optDataPath, *optPackFilename;
-
-    // Audio related
-    SDL_AudioSpec optAfmt;
-    int optAudioSetup;
-
-    int audioStatus;            // Current status of audio output (SDL_AUDIO_PLAYING, etc.)
-    DMMutex *audioStreamMutex;
-    Uint8 * audioStreamBuf;
-    size_t audioStreamLen;      // Length in samples
-    Uint32 audioTimePos;        // Approximate audio time (in milliseconds)
-    int audioSampleSize;        // Size of one audio sample in bytes (incl. all channels)
-
-    // No-sound audio simulation thread stuff
-    SDL_Thread *audioSimThread;
-    Uint8 * audioSimBuf;
-    size_t audioSimBufSize;
-    BOOL audioSimDone;
-    int  audioSimDelay;
-
-#ifdef DM_USE_JSS
-    JSSMixer *jssDev;
-    JSSPlayer *jssPlr;
-    int jssFormat;
-#endif
-
-#ifdef DM_USE_TREMOR
-    DMResource *audioRes;
-    size_t audioPos;
-#endif
-
-    int    (*demoInit)(struct DMEngineData *);
-    int    (*demoInitPreVideo)(struct DMEngineData *);
-    int    (*demoInitPostVideo)(struct DMEngineData *);
-    int    (*demoRender)(struct DMEngineData *);
-    void   (*demoShutdown)(struct DMEngineData *);
-    void   (*demoQuit)(struct DMEngineData *);
-
-    // Setup specifics
-    DMVector setupMenuPos, setupMenuDim, setupText1Pos;
-    BOOL setupMenuCenter, setupTextCondensed;
-    char setupTextFullscreen[64], setupTextWindowed[64], setupTextPrefix[64];
-} DMEngineData;
-
-
-extern DMEffect *engineEffects;
-extern int nengineEffects, nengineEffectsAlloc;
-
-
-// Effect registration
-int       engineRegisterEffect(const DMEffect *ef);
-int       engineInitializeEffects(DMEngineData *);
-void      engineShutdownEffects(DMEngineData *);
-DMEffect *engineFindEffect(const char *name, const int nparams);
-DMEffect *engineFindEffectByName(const char *name);
-
-
-#ifdef DM_USE_TIMELINE
-// Basic timeline handling
-int  dmLoadTimeline(DMResource *res, DMTimeline **tl);
-void dmFreeTimeline(DMTimeline *tl);
-
-void dmFreeTimelinePoints(DMTimelinePoints *points);
-void dmFreeTimelineEventParam(DMTimelineEventParam *param);
-void dmFreeTimelineEvent(DMTimelineEvent *event);
-void dmFreeTimelineTrack(DMTimelineTrack *track);
-
-
-// Execution related
-int  dmPrepareTimeline(DMTimeline *tl, DMPreparedTimeline *ptl);
-void dmFreePreparedTimelineData(DMPreparedTimeline *ptl);
-
-int  dmSeekTimeline(DMPreparedTimeline *tl, int time);
-int  dmExecuteTimeline(DMPreparedTimeline *tl, SDL_Surface *screen, int time);
-
-
-// Editing/saving related functions
-int  dmCopyTimelinePoints(const DMTimelinePoints *src, DMTimelinePoints *dst);
-int  dmCopyTimelineEventParam(const DMTimelineEventParam *src, DMTimelineEventParam *dst);
-int  dmCopyTimelineEvent(const DMTimelineEvent *src, DMTimelineEvent **pdst);
-int  dmCopyTimelineCurve(const DMTimelineCurve *src, DMTimelineCurve *dst);
-int  dmCopyTimelineTrack(const DMTimelineTrack *src, DMTimelineTrack **pdst);
-int  dmCopyTimeline(const DMTimeline *src, DMTimeline **pdst);
-
-int  dmSaveTimeline(DMResource *res, DMTimeline *tl);
-
-int  dmTimelineNew(DMTimeline **tl, const char *name);
-int  dmTimelineAddTrack(DMTimeline *tl, DMTimelineTrack **track, const char *name);
-int  dmTimelineTrackAddEvent(DMTimelineTrack *track, int start, int duration, DMTimelineEvent **pev);
-int  dmTimelineEventSetEffect(DMTimelineEvent *event, DMEffect *ef);
-int  dmTimelineEventSetEffectByIndex(DMTimelineEvent *event, const int index);
-int  dmTimelineEventSetEffectByName(DMTimelineEvent *event, const char *name);
-
-#endif // DM_USE_TIMELINE
-
-
-// Resource helpers
-#define engineGetResImage(eng, x, name) \
-    do { \
-        if ((x = (SDL_Surface *) engineGetResource(eng, name)) == NULL) \
-            return DMERR_INIT_FAIL; \
-    } while (0)
-
-#define engineGetResModule(eng, x, name) \
-    do { \
-        if ((x = (JSSModule *) engineGetResource(eng, name)) == NULL) \
-            return DMERR_INIT_FAIL; \
-    } while (0)
-
-#define engineFindResource(eng, name) dmResourceFind((eng)->resources, name)
-
-
-int    engineClassifier(DMResource *res);
-void * engineGetResource(DMEngineData *eng, const char *name);
-int    engineGetTime(DMEngineData *eng, int t);
-int    engineGetTimeDTi(DMEngineData *eng);
-int    engineGetTick(DMEngineData *eng);
-float  engineGetTimeDT(DMEngineData *eng);
-
-void   engineAudioCallback(void *userdata, Uint8 *stream, int len);
-void   enginePauseAudio(int status);
-int    engineGetVideoAspect(int width, int height);
-
-
-// Implemented in actual demo code
-int    demoPreInit(DMEngineData *eng);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // DMENGINE_H
--- a/dmeval.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,765 +0,0 @@
-#include "dmeval.h"
-#include <math.h>
-
-#define DM_MAX_BUF     512
-
-
-/* Operators
- */
-const DMEvalOper dmEvalOpers[OP_NOPERS] =
-{
-    { "-"      , OT_UNARY , FALSE },
-    { "~"      , OT_UNARY , TRUE },
-    
-    { "+"      , OT_LEFT  , TRUE },
-    { "-"      , OT_LEFT  , TRUE },
-    { "*"      , OT_LEFT  , TRUE },
-    { "/"      , OT_LEFT  , TRUE },
-    { "%"      , OT_LEFT  , TRUE },
-
-
-    { "<<"     , OT_LEFT  , TRUE },
-    { ">>"     , OT_LEFT  , TRUE },
-
-    { "&"      , OT_LEFT  , TRUE },
-    { "|"      , OT_LEFT  , TRUE },
-    { "^"      , OT_LEFT  , TRUE },
-
-    { ">="     , OT_LEFT  , TRUE },
-    { "<="     , OT_LEFT  , TRUE },
-    { ">"      , OT_LEFT  , TRUE },
-    { "<"      , OT_LEFT  , TRUE },
-
-    { "FUNC"   , OT_NONE  , FALSE },
-    { "VAR"    , OT_NONE  , FALSE },
-    { "CONST"  , OT_NONE  , FALSE },
-
-    { "SUBEXPR", OT_NONE  , FALSE },
-};
-
-
-/* Function definitions
- */
-static DMValue func_int_clip(DMValue *v)
-{
-    return (*v < -1.0f) ? -1.0f : ((*v > 1.0f) ? 1.0f : *v);
-}
-
-
-static DMValue func_sin(DMValue *v)
-{
-    return sin(*v);
-}
-
-
-static DMValue func_cos(DMValue *v)
-{
-    return cos(*v);
-}
-
-
-static DMValue func_pow(DMValue *v)
-{
-    return pow(v[0], v[1]);
-}
-
-
-/* Some basic functions
- */
-static const DMEvalSymbol dmEvalBasicFuncs[] =
-{
-    { "sin",  SYM_FUNC , 1, func_sin, NULL, 0 },
-    { "cos",  SYM_FUNC , 1, func_cos, NULL, 0 },
-    { "clip", SYM_FUNC , 1, func_int_clip, NULL, 0 },
-    { "pow",  SYM_FUNC , 2, func_pow, NULL, 0 },
-
-    { "pi",   SYM_CONST, 0, NULL, NULL, DM_PI },
-    { "e",    SYM_CONST, 0, NULL, NULL, DM_E },
-};
-
-static const int ndmEvalBasicFuncs = sizeof(dmEvalBasicFuncs) / sizeof(dmEvalBasicFuncs[0]);
-
-
-void dmEvalErrorV(DMEvalContext *ev, const char *fmt, va_list ap)
-{
-    char *tmp = dm_strdup_vprintf(fmt, ap);
-    
-    ev->err = TRUE;
-
-    if (ev->errStr != NULL)
-    {
-        ev->errStr = dm_strdup_printf("%s%s", ev->errStr, tmp);
-        dmFree(tmp);
-    }
-    else
-        ev->errStr = tmp;
-}
-
-
-void dmEvalError(DMEvalContext *ev, const char *fmt, ...)
-{
-    va_list ap;
-    va_start(ap, fmt);
-    dmEvalErrorV(ev, fmt, ap);
-    va_end(ap);
-}
-
-
-DMEvalSymbol *dmEvalContextFindSymbol(DMEvalContext *ev, const char *name)
-{
-    int i;
-    if (ev->symbols == NULL)
-        return NULL;
-
-    for (i = 0; i < ev->nsymbols; i++)
-    {
-        if (strcmp(ev->symbols[i].name, name) == 0)
-            return &(ev->symbols[i]);
-    }
-    
-    return NULL;
-}
-
-
-// Add a new symbol to the evaluation context.
-// Return pointer to newly allocated symbol struct if successful.
-// If the symbol already exists or there was a memory allocation
-// error, NULL is returned.
-static DMEvalSymbol * dmEvalContextAddSymbol(DMEvalContext *ev, const char *name, const int type)
-{
-    DMEvalSymbol *symbol = dmEvalContextFindSymbol(ev, name);
-    if (symbol != NULL)
-        return NULL;
-
-    ev->symbols = dmRealloc(ev->symbols, sizeof(DMEvalSymbol) * (ev->nsymbols + 1));
-    if (ev->symbols == NULL)
-    {
-        dmEvalError(ev,
-            "Could not reallocate eval symbols array (#%d). Fatal error.\n",
-            ev->nsymbols + 1);
-        return NULL;
-    }
-    
-    symbol = &(ev->symbols[ev->nsymbols]);
-    ev->nsymbols++;
-
-    memset(symbol, 0, sizeof(DMEvalSymbol));
-    symbol->name = dm_strdup(name);
-    symbol->type = type;
-
-    return symbol;
-}
-
-
-DMEvalSymbol *dmEvalContextAddVar(DMEvalContext *ev, const char *name, DMValue *var)
-{
-    DMEvalSymbol *symbol = dmEvalContextAddSymbol(ev, name, SYM_VAR);
-    if (symbol == NULL)
-        return NULL;
-    
-    symbol->var = var;
-    return symbol;
-}
-
-
-DMEvalSymbol *dmEvalContextAddConst(DMEvalContext *ev, const char *name, DMValue value)
-{
-    DMEvalSymbol *symbol = dmEvalContextAddSymbol(ev, name, SYM_CONST);
-    if (symbol == NULL)
-        return NULL;
-    
-    symbol->cvalue = value;
-    return symbol;
-}
-
-
-DMEvalSymbol *dmEvalContextAddFunc(DMEvalContext *ev, const char *name, DMValue (*func)(DMValue *), int nargs)
-{
-    DMEvalSymbol *symbol = dmEvalContextAddSymbol(ev, name, SYM_VAR);
-    if (symbol == NULL)
-        return NULL;
-    
-    symbol->func  = func;
-    symbol->nargs = nargs;
-
-    return DMERR_OK;
-}
-
-
-DMEvalContext *dmEvalContextNew(void)
-{
-    int i;
-    DMEvalContext *ev = dmCalloc(1, sizeof(DMEvalContext));
-
-    if (ev == NULL)
-        return NULL;
-
-    for (i = 0; i < ndmEvalBasicFuncs; i++)
-    {
-        const DMEvalSymbol *symbol= &dmEvalBasicFuncs[i];
-        DMEvalSymbol *nsymbol = dmEvalContextAddSymbol(ev, symbol->name, symbol->type);
-        if (nsymbol != NULL)
-        {
-            nsymbol->nargs    = symbol->nargs;
-            nsymbol->func     = symbol->func;
-            nsymbol->var      = symbol->var;
-            nsymbol->cvalue   = symbol->cvalue;
-        }
-    }
-
-    return ev;
-}
-
-
-void dmEvalTreeFree(DMEvalNode *node)
-{
-    while (node != NULL)
-    {
-        DMEvalNode *next = node->next;
-        int i;
-
-        for (i = 0; i < DM_MAX_ARGS; i++)
-        {
-            dmEvalTreeFree(node->args[i]);
-            node->args[i] = NULL;
-        }
-
-        dmEvalTreeFree(node->subexpr);
-        node->subexpr = NULL;
-        dmFree(node);
-        node = next;
-    }
-}
-
-
-void dmEvalContextClear(DMEvalContext *ev)
-{
-    if (ev == NULL)
-        return;
-    
-    dmFree(ev->errStr);
-    ev->err = FALSE;
-    ev->errStr = NULL;
-}
-
-
-void dmEvalContextClose(DMEvalContext *ev)
-{
-    int i;
-
-    if (ev == NULL)
-        return;
-
-    for (i = 0; i < ev->nsymbols; i++)
-        dmFree(ev->symbols[i].name);
-
-    dmFree(ev->symbols);
-    dmEvalContextClear(ev);
-    dmFree(ev);
-}
-
-
-static DMEvalNode *dmEvalInsertNode(DMEvalNode **list, DMEvalNode *node)
-{
-    if (*list != NULL)
-    {
-        node->prev = (*list)->prev;
-        (*list)->prev->next = node;
-        (*list)->prev = node;
-    }
-    else
-    {
-        *list = node;
-        node->prev = *list;
-    }
-
-    node->next = NULL;
-    return node;
-}
-
-
-static DMEvalNode *dmEvalAddNode(DMEvalNode **list, const int op)
-{
-    DMEvalNode *node = dmCalloc(1, sizeof(DMEvalNode));
-    if (node == NULL)
-        return NULL;
-
-    node->op = op;
-
-    return dmEvalInsertNode(list, node);
-}
-
-
-enum
-{
-    PARSE_NONE          = 0x0000,
-    PARSE_START         = 0x1000,
-    PARSE_END           = 0x2000,
-    PARSE_ERROR         = 0x8000,
-
-    PARSE_IDENT         = 0x0001, // Any identifier (variable, function name)
-    PARSE_CONST         = 0x0002, // Constant value (n, n.nnn, etc)
-    PARSE_OPER          = 0x0004, // All operators
-    PARSE_OPER_UNARY    = 0x0008, // Unary operators ~, -
-    PARSE_SUBEXPR_START = 0x0010, // ( ...
-    PARSE_SUBEXPR_END   = 0x0020, // )
-    PARSE_ARGS          = 0x0040, // function args: (xxx[, yyy ...])
-
-    PARSE_NORMAL        = PARSE_CONST | PARSE_IDENT | PARSE_SUBEXPR_START | PARSE_OPER_UNARY,
-};
-
-#define DM_CHECK(x) { if (mode & PARSE_ ## x ) { if (str[0]) strcat(str, " or "); strcat(str, # x ); } }
-
-static char *dmEvalGetMode(int mode)
-{
-    char str[128] = "";
-
-    DM_CHECK(START);
-    DM_CHECK(END);
-    DM_CHECK(IDENT);
-    DM_CHECK(CONST);
-    DM_CHECK(OPER);
-    DM_CHECK(OPER_UNARY);
-    DM_CHECK(SUBEXPR_START);
-    DM_CHECK(SUBEXPR_END);
-    DM_CHECK(ARGS);
-            
-    return dm_strdup(str);
-}
-
-
-static void dmEvalSetMode(DMEvalContext *ev, const int mode)
-{
-    if (mode != PARSE_ERROR &&
-        mode != PARSE_START &&
-        ev->expect != PARSE_NONE &&
-        (mode & ev->expect) == 0)
-    {
-        char *tmp1 = dmEvalGetMode(ev->expect),
-             *tmp2 = dmEvalGetMode(mode);
-
-        dmEvalError(ev, "Expected [%s], got %s.\n", tmp1, tmp2);
-        dmFree(tmp1);
-        dmFree(tmp2);
-    }
-
-    ev->prev = ev->mode;
-    ev->mode = mode;
-}
-
-
-static BOOL dmEvalTokenizeExpr(DMEvalContext *ev, DMEvalNode **list, char **str, int depth)
-{
-    char *c = *str;
-    char tmpStr[DM_MAX_BUF + 2], *tmp;
-    int tmpStrLen = 0, argIndex, op;
-    DMEvalNode *node = NULL, *func = NULL;
-    BOOL first = FALSE, decimal = FALSE;
-
-    ev->expect = PARSE_NORMAL;
-    ev->mode = PARSE_START;
-    
-    while (ev->mode != PARSE_ERROR && ev->mode != PARSE_END)
-    switch (ev->mode)
-    {
-        case PARSE_START:
-            // Start
-            if (*c == 0)
-                dmEvalSetMode(ev, PARSE_END);
-
-            // Skip whitespace
-            else if (isspace(*c))
-                c++;
-
-            else if (*c == ')' || *c == ',')
-            {
-                if (depth > 0)
-                    dmEvalSetMode(ev, PARSE_END);
-                else
-                {
-                    dmEvalError(ev, "Invalid nesting near '%s' (depth %d).\n", c, depth);
-                    dmEvalSetMode(ev, PARSE_ERROR);
-                }
-                c++;
-            }
-            
-            else if (*c == '(')
-                dmEvalSetMode(ev, func != NULL ? PARSE_ARGS : PARSE_SUBEXPR_START);
-            
-            else if (*c == '-')
-                dmEvalSetMode(ev, (ev->prev == PARSE_START || ev->prev == PARSE_OPER || ev->prev == PARSE_OPER_UNARY) ? PARSE_OPER_UNARY : PARSE_OPER);
-            
-            else if (*c == '~')
-                dmEvalSetMode(ev, PARSE_OPER_UNARY);
-            
-            else if (strchr("+*/<>%&|!^", *c))
-                dmEvalSetMode(ev, PARSE_OPER);
-
-            else if (isdigit(*c) || *c == '.')
-                dmEvalSetMode(ev, PARSE_CONST);
-
-            else if (isalpha(*c) || *c == '_')
-                dmEvalSetMode(ev, PARSE_IDENT);
-            
-            else
-            {
-                dmEvalError(ev, "Syntax error near '%s' (depth %d).\n", c, depth);
-                dmEvalSetMode(ev, PARSE_ERROR);
-            }
-
-            first = TRUE;
-            break;
-        
-        case PARSE_SUBEXPR_START:
-            tmp = c + 1;
-
-            ev->expect = PARSE_NORMAL;
-
-            if ((node = dmEvalAddNode(list, OP_SUBEXPR)) == NULL)
-                dmEvalSetMode(ev, PARSE_ERROR);
-            else
-            if (dmEvalTokenizeExpr(ev, &(node->subexpr), &tmp, depth + 1) != 0)
-            {
-                dmEvalError(ev, "Subexpression starting at '%s' contained errors.\n", c);
-                dmEvalSetMode(ev, PARSE_ERROR);
-            }
-
-            if (ev->mode != PARSE_ERROR)
-            {
-                dmEvalSetMode(ev, PARSE_START);
-                ev->expect = PARSE_OPER | PARSE_SUBEXPR_END;
-                c = tmp;
-            }
-            break;
-
-        case PARSE_ARGS:
-            tmp = c + 1;
-            
-            for (argIndex = 0; argIndex < func->symbol->nargs; argIndex++)
-            {
-                if (dmEvalTokenizeExpr(ev, &(func->args[argIndex]), &tmp, depth + 1) != 0)
-                {
-                    dmEvalError(ev, "Function argument subexpression starting at '%s' contained errors.\n", c);
-                    dmEvalSetMode(ev, PARSE_ERROR);
-                }
-            }
-
-            func = NULL;
-
-            if (ev->mode != PARSE_ERROR)
-            {
-                dmEvalSetMode(ev, PARSE_START);
-                ev->expect = PARSE_OPER | PARSE_END;
-                c = tmp;
-            }
-            break;
-
-        case PARSE_CONST:
-            if (first)
-            {
-                first = FALSE;
-                decimal = FALSE;
-                tmpStrLen = 0;
-                
-                if (isdigit(*c) || *c == '-' || *c == '+' || *c == '.')
-                {
-                    if (*c == '.')
-                        decimal = TRUE;
-                    tmpStr[tmpStrLen++] = *c++;
-                }
-                else
-                {
-                    dmEvalError(ev, "Invalid constant expression near '%s'.\n", c);
-                    dmEvalSetMode(ev, PARSE_ERROR);
-                }
-            }
-            else
-            {
-                if (isdigit(*c))
-                {
-                    tmpStr[tmpStrLen++] = *c++;
-                }
-                else
-                if (*c == '.')
-                {
-                    if (!decimal)
-                    {
-                        tmpStr[tmpStrLen++] = *c++;
-                        decimal = TRUE;
-                    }
-                    else
-                    {
-                        dmEvalError(ev, "Invalid constant expression near '%s'.\n", c);
-                        dmEvalSetMode(ev, PARSE_ERROR);
-                    }
-                }
-                else
-                {
-                    tmpStr[tmpStrLen] = 0;
-
-                    if ((node = dmEvalAddNode(list, OP_VALUE)) == NULL)
-                    {
-                        dmEvalSetMode(ev, PARSE_ERROR);
-                    }
-                    else
-                    {
-                        node->val = atof(tmpStr);
-                        dmEvalSetMode(ev, PARSE_START);
-                        ev->expect = PARSE_OPER | PARSE_END;
-                    }
-                }
-            }
-            break;
-
-        case PARSE_OPER_UNARY:
-            {
-                int op = OP_INVALID;
-
-                switch (*c)
-                {
-                    case '-': op = OP_SUB_UNARY; c++; break;
-                    case '~': op = OP_BIT_COMPLEMENT; c++; break;
-                }
-
-                if (op != OP_INVALID)
-                {
-                    if ((node = dmEvalAddNode(list, op)) != NULL)
-                    {
-                        ev->expect = PARSE_NORMAL;
-                        dmEvalSetMode(ev, PARSE_START);
-                    }
-                    else
-                        dmEvalSetMode(ev, PARSE_ERROR);
-                }
-            }
-            break;
-
-        case PARSE_OPER:
-            op = OP_INVALID;
-
-            switch (*c)
-            {
-                case '+': op = OP_ADD; c++; break;
-                case '-': op = OP_SUB; c++; break;
-                case '*': op = OP_MUL; c++; break;
-                case '/': op = OP_DIV; c++; break;
-                case '%': op = OP_MOD; c++; break;
-                case '&': op = OP_BIT_AND; c++; break;
-                case '^': op = OP_BIT_XOR; c++; break;
-                case '|': op = OP_BIT_OR; c++; break;
-
-                case '>':
-                    if (c[1] == '>')
-                    {
-                        c += 2;
-                        op = OP_BIT_RSHIFT;
-                    }
-                    else
-                    {
-                        op = (c[1] == '=') ? OP_GT_EQ : OP_GT;
-                        c++;
-                    }
-                    break;
-                    
-                case '<':
-                    if (c[1] == '<')
-                    {
-                        c += 2;
-                        op = OP_BIT_LSHIFT;
-                    }
-                    else
-                    {
-                        op = (c[1] == '=') ? OP_LT_EQ : OP_LT;
-                        c++;
-                    }
-                    break;
-
-                default:
-                    dmEvalError(ev, "Unknown operator '%c' at %s\n", *c, c);
-                    dmEvalSetMode(ev, PARSE_ERROR);
-            }
-
-            if (op != OP_INVALID)
-            {
-                if ((node = dmEvalAddNode(list, op)) != NULL)
-                {
-                    ev->expect = PARSE_NORMAL | PARSE_OPER_UNARY;
-                    dmEvalSetMode(ev, PARSE_START);
-                }
-                else
-                    dmEvalSetMode(ev, PARSE_ERROR);
-            }
-            break;
-
-        case PARSE_IDENT:
-            if (isalnum(*c) || *c == '_')
-            {
-                if (first)
-                {
-                    tmpStrLen = 0;
-                    first = FALSE;
-                }
-
-                if (tmpStrLen < DM_MAX_BUF)
-                    tmpStr[tmpStrLen++] = *c++;
-                else
-                {
-                    tmpStr[tmpStrLen] = 0;
-                    dmEvalError(ev, "Identifier too long! ('%s') near %s\n", tmpStr, c);
-                }
-            }
-            else
-            {
-                tmpStr[tmpStrLen] = 0;
-                DMEvalSymbol *symbol = dmEvalContextFindSymbol(ev, tmpStr);
-                if (symbol != NULL)
-                {
-                    if ((node = dmEvalAddNode(list, symbol->type == SYM_FUNC ? OP_FUNC : OP_VAR)) != NULL)
-                    {
-                        node->symbol = symbol;
-                        if (symbol->type == SYM_FUNC)
-                        {
-                            func = node;
-                            ev->expect = PARSE_ARGS;
-                        }
-                        else
-                            ev->expect = PARSE_END | PARSE_OPER;
-
-                        dmEvalSetMode(ev, PARSE_START);
-                    }
-                    else
-                        dmEvalSetMode(ev, PARSE_ERROR);
-                }
-                else
-                {
-                    dmEvalError(ev, "No such identifier '%s'.\n", tmpStr);
-                    dmEvalSetMode(ev, PARSE_ERROR);
-                }
-            }
-            break;
-    }
-
-    *str = c;
-
-    return (ev->mode == PARSE_ERROR);
-}
-
-
-int dmEvalParseExpr(DMEvalContext *ev, char *expr, DMEvalNode **result)
-{
-    int ret;
-
-    if (ev == NULL || result == NULL)
-        return DMERR_NULLPTR;
-
-    ev->prev = PARSE_START;
-    ret = dmEvalTokenizeExpr(ev, result, &expr, 0);
-    
-    return ret;
-}
-
-
-
-
-BOOL dmEvalTreeExecute(DMEvalContext *ev, DMEvalNode *node, DMValue *presult)
-{
-    DMValue val1, val2;
-
-    if (node == NULL)
-        return FALSE;
-
-    switch (node->op)
-    {
-        case OP_VAR:
-            switch (node->symbol->type)
-            {
-                case SYM_CONST: *presult = node->symbol->cvalue; return TRUE;
-                case SYM_VAR  : *presult = *(node->symbol->var); return TRUE;
-            }
-            return FALSE;
-
-        case OP_VALUE:
-            *presult = node->val;
-            return TRUE;
-        
-        case OP_FUNC:
-            
-            return TRUE;
-        
-        case OP_SUBEXPR:
-            return dmEvalTreeExecute(ev, node->subexpr, presult);
-    
-        // Binary operators
-        case OP_BIT_LSHIFT:
-        case OP_BIT_RSHIFT:
-        
-        case OP_BIT_AND:
-        case OP_BIT_XOR:
-        case OP_BIT_OR:
-
-        case OP_ADD:
-        case OP_SUB:
-        case OP_MUL:
-        case OP_DIV:
-        case OP_MOD:
-            if (!dmEvalTreeExecute(ev, node->left, &val1) ||
-                !dmEvalTreeExecute(ev, node->right, &val2))
-                return FALSE;
-
-            switch (node->op)
-            {
-                case OP_DIV:
-                    if (val2 == 0)
-                    {
-                        dmEvalError(ev, "Division by zero.\n");
-                        return FALSE;
-                    }
-                    *presult = val1 / val2;
-                    break;
-
-
-                case OP_MOD:
-                    if (val2 == 0)
-                    {
-                        dmEvalError(ev, "Division by zero.\n");
-                        return FALSE;
-                    }
-                    *presult = DMCONVTYPE val1 % DMCONVTYPE val2;
-                    break;
-
-                case OP_BIT_LSHIFT:
-                    if (val2 > 31)
-                        dmEvalError(ev, "Left shift count >= width of type (%d << %d)\n", val1, val2);
-                    *presult = DMCONVTYPE val1 << DMCONVTYPE val2; break;
-
-                case OP_BIT_RSHIFT:
-                    if (val2 > 31)
-                        dmEvalError(ev, "Right shift count >= width of type (%d >> %d)\n", val1, val2);
-                    *presult = DMCONVTYPE val1 >> DMCONVTYPE val2; break;
-
-                case OP_MUL     : *presult = val1 * val2; break;
-                case OP_ADD     : *presult = val1 + val2; break;
-                case OP_SUB     : *presult = val1 - val2; break;
-                case OP_BIT_AND : *presult = DMCONVTYPE val1 & DMCONVTYPE val2; break;
-                case OP_BIT_OR  : *presult = DMCONVTYPE val1 | DMCONVTYPE val2; break;
-                case OP_BIT_XOR : *presult = DMCONVTYPE val1 ^ DMCONVTYPE val2; break;
-            }
-            return TRUE;
-
-        // Unary operators
-        case OP_SUB_UNARY:
-        case OP_BIT_COMPLEMENT:
-/*
-            switch (node->op)
-            {
-                case OP_SUB_UNARY: *presult -= tmp; break;
-                case OP_BIT_COMPLEMENT: *presult = DMCONVTYPE ~(DMCONVTYPE tmp); break;
-            }
-*/
-            return TRUE;
-
-        default:
-            dmEvalError(ev, "Invalid opcode %d in node %p.\n", node->op, node);
-            return FALSE;
-    }
-}
--- a/dmeval.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,136 +0,0 @@
-#ifndef DMEVAL_H
-#define DMEVAL_H
-
-#include "dmlib.h"
-#include <stdio.h>
-
-
-typedef double DMValue;
-#define DMCONVTYPE       (int)
-#define DM_MAX_ARGS      8
-
-
-enum
-{
-    OP_SUB_UNARY,
-    OP_BIT_COMPLEMENT,
-
-    OP_ADD,
-    OP_SUB,
-    OP_MUL,
-    OP_DIV,
-    OP_MOD,
-
-    OP_BIT_LSHIFT,
-    OP_BIT_RSHIFT,
-
-    OP_BIT_AND,
-    OP_BIT_OR,
-    OP_BIT_XOR,
-
-    OP_GT_EQ,
-    OP_LT_EQ,
-    OP_GT,
-    OP_LT,
-
-    // Special ops
-    OP_FUNC,
-    OP_VAR,
-    OP_VALUE,
-    OP_SUBEXPR,
-
-    // Total number of operators
-    OP_NOPERS,
-
-    OP_INVALID
-} DMEvalOperId;
-
-
-enum
-{
-    OT_NONE,
-
-    OT_LEFT,      // Left-associative
-    OT_RIGHT,     // Right-associative
-    OT_UNARY,
-} DMEvalOperAssoc;
-
-
-typedef struct
-{
-    char *name;     // Token
-    int   assoc;    // Associativity type (DMEvalOperAssoc)
-    BOOL  tokenize; // Automatically tokenize?
-} DMEvalOper;
-
-
-enum
-{
-    SYM_FUNC,
-    SYM_VAR,
-    SYM_CONST,
-} DMEvalSymbolType;
-
-
-typedef struct
-{
-    char *name;     // Name of the symbol
-    int type;       // Type (SYM_*)
-    int nargs;      // Number of arguments, if SYM_FUNC
-
-    DMValue (*func)(DMValue arg[DM_MAX_ARGS]);
-
-    DMValue *var;   // Pointer to variable value if SYM_VAR
-    DMValue cvalue; // Const value, if SYM_CVAR
-} DMEvalSymbol;
-
-
-typedef struct DMEvalNode
-{
-    int op;               // Operator/token type
-    DMValue val;          // Value, if immediate constant 
-    DMEvalSymbol *symbol; // Symbol pointer, if function/variable/constvar
-
-    struct DMEvalNode *args[DM_MAX_ARGS]; // Arguments, if function
-
-    struct DMEvalNode *subexpr, *left, *right, *next, *prev;
-} DMEvalNode;
-
-
-typedef struct
-{
-    BOOL err;
-    char *errStr;
-    
-    int nsymbols;
-    DMEvalSymbol *symbols;
-
-    int mode, prev, expect;
-} DMEvalContext;
-
-
-// Evaluation context management
-DMEvalContext * dmEvalContextNew(void);
-void            dmEvalContextClose(DMEvalContext *ev);
-void            dmEvalContextClear(DMEvalContext *ev);
-
-
-// Symbol management
-DMEvalSymbol *  dmEvalContextFindSymbol(DMEvalContext *ev, const char *name);
-DMEvalSymbol *  dmEvalContextAddVar(DMEvalContext *ev, const char *name, DMValue *var);
-DMEvalSymbol *  dmEvalContextAddConst(DMEvalContext *ev, const char *name, DMValue value);
-DMEvalSymbol *  dmEvalContextAddFunc(DMEvalContext *ev, const char *name, DMValue (*func)(DMValue *), int nargs);
-
-
-// Evaluation trees, tokenization, parsing
-int   dmEvalParseExpr(DMEvalContext *ev, char *expr, DMEvalNode **plist);
-int   dmEvalTreeExecute(DMEvalContext *ev, DMEvalNode *tree, DMValue *presult);
-void  dmEvalTreeFree(DMEvalNode *node);
-
-
-void dmEvalPrintOpTree(FILE *out, DMEvalContext *ev, DMEvalNode *node);
-
-
-extern const DMEvalOper dmEvalOpers[OP_NOPERS];
-
-#endif // DMEVAL_H
--- a/dmevalw.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-#include "dmeval.h"
-
-
-void dmDoEvalPrintOpTree(FILE *out, DMEvalContext *ev, DMEvalNode *node, int level)
-{
-    int i;
-    while (node != NULL)
-    {
-        switch (node->op)
-        {
-            case OP_FUNC:
-                fprintf(out, "%s(", node->symbol != NULL ? node->symbol->name : "?ERROR");
-                for (i = 0; i < node->symbol->nargs; i++)
-                {
-                    dmDoEvalPrintOpTree(out, ev, node->args[i], level + 1);
-                    if (i < node->symbol->nargs - 1)
-                        fprintf(out, ",");
-                }
-                fprintf(out, ")");
-                break;
-
-            case OP_VAR:
-                fprintf(out, "%s", node->symbol != NULL ? node->symbol->name : "?ERROR");
-                break;
-
-            case OP_VALUE:
-                fprintf(out, "%.1f", node->val);
-                break;
-
-            case OP_SUBEXPR:
-                fprintf(out, "(");
-                if (node->subexpr != NULL)
-                    dmDoEvalPrintOpTree(out, ev, node->subexpr, level + 1);
-                else
-                    fprintf(out, "?ERROR");
-                fprintf(out, ")");
-                break;
-
-            default:
-                if (node->op >= 0 && node->op < OP_NOPERS)
-                    fprintf(out, "%s", dmEvalOpers[node->op].name);
-                else
-                    fprintf(out, "ERROR!");
-                break;
-        }
-        node = node->next;
-    }
-}
-
-
-void dmEvalPrintOpTree(FILE *out, DMEvalContext *ev, DMEvalNode *node)
-{
-    dmDoEvalPrintOpTree(out, ev, node, 0);
-    fprintf(out, "\n");
-}
--- a/dmfft.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,258 +0,0 @@
-/*
- * Realfftf
- * Originally (C) Copyright 1993 Philib Van Baren
- * Cleaned up and refactored to be re-entrant by
- *     Matti 'ccr' Hamalainen <ccr@tnsp.org>, 2013
- *
- * Note: Output is BIT-REVERSED! so you must use the BitReversed to
- *       get legible output, (i.e. Real_i = buffer[ BitReversed[i] ]
- *                                 Imag_i = buffer[ BitReversed[i]+1 ] )
- *       Input is in normal order.
- */
-#include "dmfft.h"
-#include <math.h>
-
-
-int dmInitializeFFT(DMFFTContext * ctx, const int fftlen)
-{
-    int i;
-
-    if (ctx == NULL)
-        return DMERR_NULLPTR;
-
-    if (fftlen <= 16)
-        return DMERR_INVALID_ARGS;
-
-    // Allocate necessary tables
-    ctx->npoints = fftlen / 2;
-    ctx->sinTable = (DMFFTType *) dmMalloc(fftlen * sizeof(DMFFTType));
-    if (ctx->sinTable == NULL)
-        return DMERR_MALLOC;
-
-    // Bitreversion buffer
-    ctx->breversed = (int *) dmMalloc(ctx->npoints * sizeof(int));
-    if (ctx->breversed == NULL)
-    {
-        dmFree(ctx->sinTable);
-        return DMERR_MALLOC;
-    }
-
-    // Calculate data
-    for (i = 0; i < ctx->npoints; i++)
-    {
-        int mask, tmp;
-        for (tmp = 0, mask = ctx->npoints / 2; mask > 0; mask >>= 1)
-        {
-            tmp = (tmp >> 1) + ((i & mask) ? ctx->npoints : 0);
-        }
-
-        ctx->breversed[i] = tmp;
-    }
-
-    for (i = 0; i < ctx->npoints; i++)
-    {
-        ctx->sinTable[ctx->breversed[i]] = -sin((2.0f * DM_PI * i) / fftlen);
-        ctx->sinTable[ctx->breversed[i] + 1] =
-            -cos((2.0f * DM_PI * i) / fftlen);
-    }
-
-    return DMERR_OK;
-}
-
-
-void dmEndFFT(DMFFTContext * ctx)
-{
-    if (ctx != NULL)
-    {
-        dmFree(ctx->breversed);
-        dmFree(ctx->sinTable);
-        memset(ctx, 0, sizeof(DMFFTContext));
-    }
-}
-
-
-int dmRealFFT(DMFFTContext * ctx, DMFFTType * buffer)
-{
-    if (ctx == NULL || buffer == NULL)
-        return DMERR_NULLPTR;
-
-    int rounds = ctx->npoints / 2;
-    DMFFTType *endptr1 = buffer + ctx->npoints * 2;
-
-    while (rounds > 0)
-    {
-        DMFFTType *sptr = ctx->sinTable;
-        DMFFTType *A = buffer,
-                  *B = buffer + rounds * 2;
-
-        while (A < endptr1)
-        {
-            DMFFTType qsin = *sptr;
-            DMFFTType qcos = *(sptr + 1);
-            DMFFTType *endptr2 = B;
-
-            while (A < endptr2)
-            {
-                DMFFTType v1 = (*B) * qcos + (*(B + 1)) * qsin;
-                DMFFTType v2 = (*B) * qsin - (*(B + 1)) * qcos;
-                *B = (*A + v1) * 0.5;
-                *(A++) = *(B++) - v1;
-                *B = (*A - v2) * 0.5;
-                *(A++) = *(B++) + v2;
-            }
-            A = B;
-            B += rounds * 2;
-            sptr += 2;
-        }
-
-        rounds >>= 1;
-    }
-
-    /*
-     *  Massage output to get the output for a real input sequence.
-     */
-    const int *br1 = ctx->breversed + 1;
-    const int *br2 = ctx->breversed + ctx->npoints - 1;
-
-    while (br1 <= br2)
-    {
-        const DMFFTType vsin = ctx->sinTable[*br1];
-        const DMFFTType vcos = ctx->sinTable[*br1 + 1];
-        DMFFTType *A = buffer + *br1,
-                  *B = buffer + *br2,
-                  HRplus, HRminus,
-                  HIplus, HIminus,
-                  tmp1, tmp2;
-
-        HRminus  = *A - *B;
-        HRplus   = HRminus + (*B * 2);
-
-        HIminus  = *(A + 1) - *(B + 1);
-        HIplus   = HIminus + (*(B + 1) * 2);
-
-        tmp1     = (vsin * HRminus) - (vcos * HIplus);
-        tmp2     = (vcos * HRminus) + (vsin * HIplus);
-
-        *A       = (HRplus + tmp1) * 0.5f;
-        *B       = *A - tmp1;
-
-        *(A + 1) = (HIminus + tmp2) * 0.5f;
-        *(B + 1) = (*(A + 1)) - HIminus;
-
-        br1++;
-        br2--;
-    }
-
-    // Handle DC bin separately
-    buffer[0] += buffer[1];
-    buffer[1] = 0;
-
-    return DMERR_OK;
-}
-
-
-int dmConvertFFTtoFreqDomain(DMFFTContext *ctx, DMFFTType *buffer,
-    DMFFTType *real, DMFFTType *imag)
-{
-    int i;
-    if (ctx == NULL || buffer == NULL || real == NULL || imag == NULL)
-        return DMERR_NULLPTR;
-
-    // Convert from bitreversed form to normal frequency domain
-    const int *breversed = ctx->breversed;
-
-    for (i = 1; i < ctx->npoints; i++)
-    {
-        real[i] = buffer[breversed[i]  ];
-        imag[i] = buffer[breversed[i]+1];
-    }
-
-    // Make the ends meet
-    real[0]            = buffer[0];
-    imag[0]            = 0;
-    real[ctx->npoints] = buffer[1];
-    imag[ctx->npoints] = 0;
-
-    return DMERR_OK;
-}
-
-
-#define DM_PW(a, b, c) sqrt(a * a + b * b) * c
-
-
-int dmConvertFFTtoFreqAndPower(DMFFTContext *ctx, DMFFTType *buffer,
-    DMFFTType *real, DMFFTType *imag, DMFFTType *power, const DMFFTType scale)
-{
-    int i;
-    if (ctx == NULL || buffer == NULL || real == NULL || imag == NULL || power == NULL)
-        return DMERR_NULLPTR;
-
-    // Convert from bitreversed form to normal frequency domain
-    const int *breversed = ctx->breversed;
-
-    for (i = 1; i < ctx->npoints; i++)
-    {
-        DMFFTType fre = real[i] = buffer[breversed[i]  ],
-                  fim = imag[i] = buffer[breversed[i]+1];
-
-        power[i] = DM_PW(fre, fim, scale);
-    }
-
-    // Make the ends meet
-    real[0]             = buffer[0];
-    imag[0]             = 0;
-    power[0]            = DM_PW(buffer[0], 0, scale);
-    
-    real[ctx->npoints]  = buffer[1];
-    imag[ctx->npoints]  = 0;
-    power[ctx->npoints] = DM_PW(buffer[1], 0, scale);
-
-    return DMERR_OK;
-}
-
-
-int dmConvertFFTtoPowerAndSum(DMFFTContext *ctx, DMFFTType *buffer,
-    DMFFTType *power, const DMFFTType pscale, DMFFTType *sum, const DMFFTType sscale)
-{
-    int i;
-    if (ctx == NULL || buffer == NULL || power == NULL || sum == NULL)
-        return DMERR_NULLPTR;
-
-    // Convert from bitreversed form to normal frequency domain
-    const int *breversed = ctx->breversed;
-    DMFFTType psum = 0;
-
-    for (i = 1; i < ctx->npoints; i++)
-    {
-        DMFFTType fre = buffer[breversed[i]  ],
-                  fim = buffer[breversed[i]+1],
-                  fpw = sqrt(fre * fre + fim * fim);
-
-        power[i]  = fpw * pscale;
-        psum     += fpw * sscale;
-    }
-
-    // Make the ends meet
-    power[0]            = DM_PW(buffer[0], 0, pscale);
-    power[ctx->npoints] = DM_PW(buffer[1], 0, pscale);
-
-    *sum = psum;
-
-    return DMERR_OK;
-}
-
-
-int dmConvertFFTtoTimeDomain(DMFFTContext *ctx, DMFFTType *buffer, DMFFTType *tdom)
-{
-    int i, n;
-    if (ctx == NULL || buffer == NULL || tdom == NULL)
-        return DMERR_NULLPTR;
-
-    for (n = i = 0; i < ctx->npoints; i++, n += 2)
-    {
-        tdom[n  ] = buffer[ctx->breversed[i]  ];
-        tdom[n+1] = buffer[ctx->breversed[i]+1];
-    }
-
-    return DMERR_OK;
-}
--- a/dmfft.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-#ifndef DMFFT_H
-#define DMFFT_H 1
-
-#include "dmlib.h"
-
-
-typedef double DMFFTType;
-
-
-typedef struct
-{
-    int npoints;
-    DMFFTType *sinTable;
-    int *breversed;
-} DMFFTContext;
-
-
-int   dmInitializeFFT(DMFFTContext *, int);
-void  dmEndFFT(DMFFTContext *);
-int   dmRealFFT(DMFFTContext *, DMFFTType *);
-
-int   dmConvertFFTtoFreqDomain(DMFFTContext *ctx, DMFFTType *buffer,
-      DMFFTType *real, DMFFTType *imag);
-
-int   dmConvertFFTtoFreqAndPower(DMFFTContext *ctx, DMFFTType *buffer,
-      DMFFTType *real, DMFFTType *imag, DMFFTType *power, const DMFFTType scale);
-
-int   dmConvertFFTtoPowerAndSum(DMFFTContext *ctx, DMFFTType *buffer,
-      DMFFTType *power, const DMFFTType pscale, DMFFTType *sum, const DMFFTType sscale);
-
-int   dmConvertFFTtoTimeDomain(DMFFTContext *ctx, DMFFTType *buffer, DMFFTType *tdom);
-
-
-#endif // DMFFT_H
--- a/dmfile.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,130 +0,0 @@
-/*
- * DMLib
- * -- Standard I/O (stdio) file write/read endianess helpers
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2011 Tecnic Software productions (TNSP)
- */
-#include "dmfile.h"
-
-
-BOOL dm_fread_str(FILE *f, void *buf, const size_t len)
-{
-    return fread(buf, len, 1, f) == 1;
-}
-
-
-BOOL dm_fread_byte(FILE *f, Uint8 *val)
-{
-    int tmp = fgetc(f);
-    *val = tmp;
-    return tmp != EOF;
-}
-
-
-#define DM_DEFINE_FFUNC(xname, xtype, xmacro)         \
-BOOL dm_fread_ ## xname (FILE *f, xtype *v) {         \
-    xtype result;                                     \
-    if (fread(&result, sizeof( xtype ), 1, f) != 1)   \
-        return FALSE;                                 \
-    *v = DM_ ## xmacro ## _TO_NATIVE (result);        \
-    return TRUE;                                      \
-}
-
-#include "dmfiletmpl.h"
-
-
-#undef DM_DEFINE_FFUNC
-
-
-BOOL dm_fwrite_str(FILE *f, const void *buf, const size_t len)
-{
-    return fwrite(buf, len, 1, f) == 1;
-}
-
-
-BOOL dm_fwrite_byte(FILE *f, const Uint8 val)
-{
-    return fputc(val, f) == val;
-}
-
-
-#define DM_DEFINE_FFUNC(xname, xtype, xmacro)         \
-BOOL dm_fwrite_ ## xname (FILE *f, const xtype v) {   \
-    xtype result = DM_NATIVE_TO_ ## xmacro (v);       \
-    return fwrite(&result, sizeof( xtype ), 1, f) == 1;  \
-}
-
-#include "dmfiletmpl.h"
-
-#undef DM_DEFINE_FFUNC
-
-
-#define BUF_SIZE_INITIAL   (16*1024)
-#define BUF_SIZE_GROW      (4*1024)
-
-int dmReadDataFile(FILE *inFile, const char *filename, Uint8 **pbuf, size_t *pbufSize)
-{
-    FILE *f;
-    int res = DMERR_OK;
-    Uint8 *dataBuf = NULL;
-    size_t readSize, dataSize, dataRead, dataPos;
-    
-    if (inFile != NULL)
-        f = inFile;
-    else
-    if (filename != NULL)
-    {
-        if ((f = fopen(filename, "rb")) == NULL)
-        {
-            dmError("Could not open '%s' for reading.\n", filename);
-            return DMERR_FOPEN;
-        }
-    }
-    else
-    {
-        dmError("NULL filename and stream pointers.\n");
-        return DMERR_NULLPTR;
-    }
-
-    // Allocate initial data buffer
-    readSize = dataSize = BUF_SIZE_INITIAL;
-    if ((dataBuf = dmMalloc(dataSize)) == NULL)
-    {
-        dmError("Error allocating memory for data, %d bytes.\n", dataSize);
-        res = DMERR_MALLOC;
-        goto error;
-    }
-
-    dataPos = 0;
-    dataRead = 0;
-
-    while (!feof(f) && !ferror(f))
-    {
-        size_t read = fread(dataBuf + dataPos, 1, readSize, f);
-        dataPos += read;
-        dataRead += read;
-
-        if (dataRead >= dataSize)
-        {
-            readSize = BUF_SIZE_GROW;
-            dataSize += BUF_SIZE_GROW;
-            if ((dataBuf = dmRealloc(dataBuf, dataSize)) == NULL)
-            {
-                dmError("Error reallocating memory for data, %d bytes.\n", dataSize);
-                res = DMERR_MALLOC;
-                goto error;
-            }
-        }
-        else
-            break;
-    }
-
-    *pbufSize = dataRead;
-    *pbuf = dataBuf;
-
-error:
-    if (f != inFile)
-        fclose(f);
-    
-    return res;
-}
--- a/dmfile.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/*
- * DMLib
- * -- Standard I/O (stdio) file write/read endianess helpers
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2011 Tecnic Software productions (TNSP)
- */
-#ifndef DMFILE_H
-#define DMFILE_H
-
-#include "dmlib.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/* Plain file endianess functions
- */
-#define DM_DEFINE_FFUNC(xname, xtype, z)          \
-BOOL    dm_fread_ ## xname (FILE *f, xtype *v);  \
-BOOL    dm_fwrite_ ## xname (FILE *f, const xtype v);
-
-#include "dmfiletmpl.h"
-
-#undef DM_DEFINE_FFUNC
-
-BOOL    dm_fread_str(FILE *f, void *, const size_t);
-BOOL    dm_fwrite_str(FILE *f, const void *, const size_t);
-
-BOOL    dm_fread_byte(FILE *f, Uint8 *);
-BOOL    dm_fwrite_byte(FILE *f, const Uint8);
-
-
-int     dmReadDataFile(FILE *inFile, const char *filename, Uint8 **buf, size_t *size);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // DMFILE_H
--- a/dmfiletmpl.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-/*
- * DMLib
- * -- Plain streamed file I/O endianess functions
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2011 Tecnic Software productions (TNSP)
- */
-
-DM_DEFINE_FFUNC(le16, Uint16, LE16)
-DM_DEFINE_FFUNC(le32, Uint32, LE32)
-
-DM_DEFINE_FFUNC(be16, Uint16, BE16)
-DM_DEFINE_FFUNC(be32, Uint32, BE32)
-
-#ifdef DM_HAVE_64BIT
-DM_DEFINE_FFUNC(le64, Uint64, LE64)
-DM_DEFINE_FFUNC(be64, Uint64, BE64)
-#endif
--- a/dmgfx.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-#include "dmlib.h"
-
-
-void dmFillRect(SDL_Surface *screen, int x0, int y0, int x1, int y1, Uint32 col)
-{
-    SDL_Rect rc;
-    rc.x = x0;
-    rc.y = y0;
-    rc.w = x1 - x0 + 1;
-    rc.h = y1 - y0 + 1;
-    SDL_FillRect(screen, &rc, col);
-}
-
-
-void dmDrawHLine(SDL_Surface *screen, int x0, int x1, int yc, const Uint32 col)
-{
-    const int bpp = screen->format->BytesPerPixel,
-              cx0 = screen->clip_rect.x, cy0 = screen->clip_rect.y,
-              cx1 = screen->clip_rect.x + screen->clip_rect.w - 1,
-              cy1 = screen->clip_rect.y + screen->clip_rect.h - 1;
-    
-    DM_SWAP(int, x0, x1);
-    if (yc < cy0|| yc > cy1 || x1 < cx0 || x0 > cx1) return;
-    if (x0 < cx0) x0 = cx0;
-    if (x1 > cx1) x1 = cx1;
-    
-    int x = x1 - x0 + 1;
-    Uint8 *pix = screen->pixels + yc * screen->pitch + (x0 * bpp);
-    switch (screen->format->BitsPerPixel)
-    {
-        case 8:
-            while (x--)
-                *pix++ = col;
-            break;
-        
-        case 32:
-            {
-                Uint32 *p = (Uint32 *) pix;
-                while (x--)
-                    *p++ = col;
-            }
-            break;
-    }
-}
-
-
-void dmDrawVLine(SDL_Surface *screen, int y0, int y1, int xc, const Uint32 col)
-{
-    const int bpp = screen->format->BytesPerPixel,
-              pitch = screen->pitch / bpp,
-              cx0 = screen->clip_rect.x, cy0 = screen->clip_rect.y,
-              cx1 = screen->clip_rect.x + screen->clip_rect.w - 1,
-              cy1 = screen->clip_rect.y + screen->clip_rect.h - 1;
-
-    DM_SWAP(int, y0, y1);
-    if (xc < cx0 || xc > cx1 || y1 < cy0 || y0 > cy1) return;
-    if (y0 < cy0) y0 = cy0;
-    if (y1 > cy1) y1 = cy1;
-
-    int y = y1 - y0 + 1;
-    Uint8 *pix = screen->pixels + y0 * screen->pitch + (xc * bpp);
-    switch (screen->format->BitsPerPixel)
-    {
-        case 8:
-            while (y--)
-            {
-                *pix = col;
-                pix += pitch;
-            }
-            break;
-        
-        case 32:
-            {
-                Uint32 *p = (Uint32 *) pix;
-                while (y--)
-                {
-                    *p = col;
-                    p += pitch;
-                }
-            }
-            break;
-    }
-}
-
-
-void dmDrawBox3D(SDL_Surface *screen, int x0, int y0, int x1, int y1, Uint32 ucol, Uint32 dcol)
-{
-    dmDrawHLine(screen, x0    , x1 - 1, y0, ucol);
-    dmDrawHLine(screen, x0 + 1, x1    , y1, dcol);
-
-    dmDrawVLine(screen, y0    , y1 - 1, x0, ucol);
-    dmDrawVLine(screen, y0 + 1, y1    , x1, dcol);
-}
-
-
-void dmFillBox3D(SDL_Surface *screen, int x0, int y0, int x1, int y1, Uint32 bgcol, Uint32 ucol, Uint32 dcol)
-{
-    SDL_Rect rc;
-
-    rc.x = x0 + 1;
-    rc.y = y0 + 1;
-    rc.w = x1 - x0 - 1;
-    rc.h = y1 - y0 - 1;
-    SDL_FillRect(screen, &rc, bgcol);
-
-    dmDrawBox3D(screen, x0, y0, x1, y1, ucol, dcol);
-}
--- a/dmimage.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,169 +0,0 @@
-/*
- * DMLib
- * -- Bitmap image conversion and loading
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012 Tecnic Software productions (TNSP)
- */
-#include "dmimage.h"
-
-
-#define STBI_FAILURE_USERMSG 1
-#define STBI_NO_STDIO 1
-#define STBI_NO_HDR 1
-#include "stb_image.c"
-
-
-SDL_Surface *dmCreateRGBSurfaceFrom(void *data, const int width, const int height, const int depth, const int pitch, const int rmask, const int gmask, const int bmask, const int amask)
-{
-    // Create source surface from given data
-    SDL_Surface *tmp = SDL_CreateRGBSurfaceFrom(data, width, height, depth, pitch, bmask, gmask, rmask, amask);
-
-    // Result surface component orders as masks
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-    Uint32
-        Xrmask = 0xff000000,
-        Xgmask = 0x00ff0000,
-        Xbmask = 0x0000ff00,
-        Xamask = 0x000000ff;
-#else
-    Uint32
-        Xrmask = 0x000000ff,
-        Xgmask = 0x0000ff00,
-        Xbmask = 0x00ff0000,
-        Xamask = 0xff000000;
-#endif
-
-    // Create result conversion surface
-    SDL_Surface
-        *result = NULL,
-        *pixtmp = SDL_CreateRGBSurface(
-        SDL_SWSURFACE | SDL_SRCALPHA, 16, 16, 32, Xrmask, Xgmask, Xbmask, Xamask);
-
-    if (tmp != NULL && pixtmp != NULL)
-    {
-        // Convert surface
-        result = SDL_ConvertSurface(tmp, pixtmp->format, SDL_SWSURFACE | SDL_SRCALPHA);
-        SDL_FreeSurface(tmp);
-    }
-    if (pixtmp != NULL)
-        SDL_FreeSurface(pixtmp);
-    
-    return result;
-}
-
-
-SDL_Surface *dmCreatePaletteSurfaceFrom(void *data, const int width, const int height, const int pitch)
-{
-    int yc;
-    Uint8 *dst, *src;
-    SDL_Surface *result;
-    result = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 8, 0,0,0,0);
-    if (result == NULL)
-        return NULL;
-    
-    dst = result->pixels;
-    src = data;
-    for (yc = 0; yc < height; yc++)
-    {
-        memcpy(dst, src, width * sizeof(Uint8));
-        dst += result->pitch;
-        src += pitch;
-    }
-
-    return result;
-}
-
-
-
-static int dmSTBIread(void *user, char *data, int size)
-{
-    return dmfread(data, 1, size, (DMResource *) user);
-}
-
-
-static void dmSTBIskip(void *user, unsigned int n)
-{
-    dmfseek((DMResource *) user, n, SEEK_CUR);
-}
-
-
-static int dmSTBIeof(void *user)
-{
-    return dmfeof((DMResource *) user);
-}
-
-
-static const stbi_io_callbacks dmSTBICallbacks =
-{
-    dmSTBIread,
-    dmSTBIskip,
-    dmSTBIeof,
-};
-
-
-SDL_Surface *dmLoadImage(DMResource *file)
-{
-    Uint32 rmask, gmask, bmask, amask;
-    SDL_Surface *result = NULL;
-    int width, height, comp;
-    Uint8 *data;
-
-    data = stbi_load_from_callbacks(&dmSTBICallbacks, file, &width, &height, &comp, 0);
-
-    if (data == NULL)
-    {
-        dmError("Error decoding image resource %p '%s' [%d, %d, %d]: %s\n",
-            file, file->filename, width, height, comp, stbi_failure_reason());
-        return NULL;
-    }
-
-
-    switch (comp)
-    {
-        case 4:
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-            rmask = 0xff000000;
-            gmask = 0x00ff0000;
-            bmask = 0x0000ff00;
-            amask = 0x000000ff;
-#else
-            rmask = 0x000000ff;
-            gmask = 0x0000ff00;
-            bmask = 0x00ff0000;
-            amask = 0xff000000;
-#endif
-            result = dmCreateRGBSurfaceFrom(data, width, height, comp * 8,
-                width * comp, rmask, gmask, bmask, amask);
-            break;
-
-        case 3:
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-            rmask = 0x00ff0000;
-            gmask = 0x0000ff00;
-            bmask = 0x000000ff;
-            amask = 0x00000000;
-#else
-            rmask = 0x000000ff;
-            gmask = 0x0000ff00;
-            bmask = 0x00ff0000;
-            amask = 0x00000000;
-#endif
-            result = dmCreateRGBSurfaceFrom(data, width, height, comp * 8,
-                width * comp, rmask, gmask, bmask, amask);
-            break;
-
-        case 1:
-            result = dmCreatePaletteSurfaceFrom(data, width, height, width * comp);
-            break;
-    }
-    
-    stbi_image_free(data);
-
-    if (result == NULL)
-    {
-        dmError("Format conversion failed for image resource %p '%s' [%d, %d, %d].\n",
-            file, file->filename, width, height, comp);
-    }
-
-    return result;
-}
--- a/dmimage.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-/*
- * DMLib
- * -- Bitmap image conversion and loading
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012 Tecnic Software productions (TNSP)
- */
-#ifndef DMIMAGE_H
-#define DMIMAGE_H
-
-#include "dmlib.h"
-#include "dmres.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-SDL_Surface *dmCreateRGBSurfaceFrom(void *data, const int width, const int height, const int depth, const int pitch, const int rmask, const int gmask, const int bmask, const int amask);
-SDL_Surface *dmCreatePaletteSurfaceFrom(void *data, const int width, const int height, const int pitch);
-SDL_Surface *dmLoadImage(DMResource *file);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // DMIMAGE_H
--- a/dmlerp.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-#include "dmlib.h"
-
-void dmLerpInit(DMLerpContext *ctx, DMFloat start, DMFloat end, DMFloat nsteps)
-{
-    ctx->start = start;
-    ctx->end = end;
-    ctx->nsteps = nsteps;
-}
-
-
-DMFloat dmCatmullRom(const DMFloat t, const DMFloat p0, const DMFloat p1, const DMFloat p2, const DMFloat p3)
-{
-    const DMFloat q = t * t;
-    return (
-        (2 * p1) +
-        (-p0 + p2) * t +
-        (2 * p0 - 5 * p1 + 4 * p2 - p3) * q +
-        (   -p0 + 3 * p1 - 3 * p2 + p3) * q * t
-        ) * 0.5f;
-}
--- a/dmlib.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,321 +0,0 @@
-#include "dmlib.h"
-#include <errno.h>
-
-
-int      dmVerbosity = 0;
-char     *dmProgName = NULL,
-         *dmProgDesc = NULL,
-         *dmProgVersion = NULL,
-         *dmProgAuthor = NULL,
-         *dmProgLicense = NULL;
-
-
-void dmInitProg(char *name, char *desc, char *version, char *author, char *license)
-{
-    dmProgName     = name;
-    dmProgDesc     = desc;
-    dmProgVersion  = version;
-    dmProgAuthor   = author ? author : DM_PROG_AUTHOR;
-    dmProgLicense  = license ? license : DM_PROG_LICENSE;
-}
-
-
-void dmPrintBanner(FILE *outFile, const char *name, const char *usage)
-{
-    fprintf(outFile,
-        "\n%s v%s (%s)\n"
-        "%s\n"
-        "%s\n"
-        "Usage: %s %s\n",
-        dmProgName, dmProgVersion, dmProgDesc,
-        dmProgAuthor, dmProgLicense, name, usage);
-}
-
-
-void dmMsgVA(int level, const char *fmt, va_list ap)
-{
-    if (dmVerbosity >= level)
-    {
-        fprintf(stderr, "%s: ", dmProgName);
-        vfprintf(stderr, fmt, ap);
-    }
-}
-
-
-void dmPrintVA(int level, const char *fmt, va_list ap)
-{
-    if (dmVerbosity >= level)
-    {
-        vfprintf(stderr, fmt, ap);
-    }
-}
-
-
-void dmErrorVA(const char *fmt, va_list ap)
-{
-    fprintf(stderr, "%s: ", dmProgName);
-    vfprintf(stderr, fmt, ap);
-}
-
-
-void dmError(const char *fmt, ...)
-{
-    va_list ap;
-
-    va_start(ap, fmt);
-    dmErrorVA(fmt, ap);
-    va_end(ap);
-}
-
-
-void dmMsg(int level, const char *fmt, ...)
-{
-    va_list ap;
-
-    va_start(ap, fmt);
-    dmMsgVA(level, fmt, ap);
-    va_end(ap);
-}
-
-
-void dmPrint(int level, const char *fmt, ...)
-{
-    va_list ap;
-
-    va_start(ap, fmt);
-    dmPrintVA(level, fmt, ap);
-    va_end(ap);
-}
-
-
-/* Memory handling routines
- */
-void *dmMalloc(size_t l)
-{
-    return malloc(l);
-}
-
-
-void *dmMalloc0(size_t l)
-{
-    return calloc(1, l);
-}
-
-
-void *dmCalloc(size_t n, size_t l)
-{
-    return calloc(n, l);
-}
-
-
-void *dmRealloc(void *p, size_t l)
-{
-    return realloc(p, l);
-}
-
-
-void dmFree(void *p)
-{
-    /* Check for NULL pointers for portability due to some libc
-     * implementations not handling free(NULL) too well.
-     */
-    if (p) free(p);
-}
-
-
-BOOL dmGetIntVal(const char *s, int *i)
-{
-    if (s[0] == '$')
-    {
-        if (sscanf(&s[1], "%x", i) < 1)
-            return FALSE;
-    }
-    else if (s[0] == '0' && s[1] == 'x')
-    {
-        if (sscanf(&s[2], "%x", i) < 1)
-            return FALSE;
-    }
-    else
-    {
-        if (sscanf(s, "%u", i) < 1)
-            return FALSE;
-    }
-    return TRUE;
-}
-
-
-/* Error handling
- */
-#define DM_SYSTEM_ERRORS 100000
-
-int dmGetErrno()
-{
-    return DM_SYSTEM_ERRORS + errno;
-}
-
-
-const char *dmErrorStr(int error)
-{
-    if (error >= DM_SYSTEM_ERRORS)
-        return strerror(error - DM_SYSTEM_ERRORS);
-    
-    switch (error)
-    {
-        case DMERR_OK:             return "No error";
-        case DMERR_FOPEN:          return "File open error";
-        case DMERR_FREAD:          return "Read error";
-        case DMERR_FWRITE:         return "Write error";
-        case DMERR_FSEEK:          return "Seek error";
-        case DMERR_NOT_FOUND:      return "Resource not found";
-
-        case DMERR_INVALID_DATA:   return "Invalid data";
-        case DMERR_MALLOC:         return "Memory allocation failure";
-        case DMERR_ALREADY_INIT:   return "Already initialized";
-        case DMERR_INIT_FAIL:      return "Initialization failed";
-        case DMERR_INVALID_ARGS:   return "Invalid arguments";
-
-        case DMERR_NULLPTR:        return "NULL pointer";
-        case DMERR_NOT_SUPPORTED:  return "Operation not supported";
-        case DMERR_OUT_OF_DATA:    return "Out of data";
-        case DMERR_EXTRA_DATA:     return "Extra data";
-        case DMERR_BOUNDS:         return "Bounds check failed";
-
-        case DMERR_NOTPACK:        return "File is not a PACK";
-        case DMERR_VERSION:        return "Unsupported PACK version";
-        case DMERR_INVALID:        return "Invalid data, corrupted file";
-        case DMERR_COMPRESSION:    return "Error in compression";
-
-        default:                   return "Unknown error";
-    }
-}
-
-
-#ifdef DM_MUTEX_DEBUG
-
-static DMMutexLock * dmGetMutexThreadIDLock(DMMutex *mutex)
-{
-    Uint32 id = SDL_ThreadID();
-    int i;
-    for (i = 0; i < 8; i++)
-    {
-        DMMutexLock *lock = &(mutex->locks[i]);
-        if (lock->used && lock->id == id)
-            return lock;
-    }
-    return NULL;
-}
-
-static void dmPrintMutexLocks(DMMutex *mutex, const char *state, const char *file, const int line)
-{
-    int i;
-
-    fprintf(stderr,
-    "----------------------\n"
-    "%s --> %p @ %s:%d\n"
-    "Current thread: %d\n"
-    "Mutex         : %p (created @ %s:%d)\n",
-    state, mutex, file, line,
-    SDL_ThreadID(), mutex, mutex->cr_file, mutex->cr_line);
-
-    for (i = 0; i < 8; i++)
-    {
-        DMMutexLock *lock = &(mutex->locks[i]);
-        if (lock->used)
-        {
-            fprintf(stderr,
-            "Lock #%d: thread=%d, state=%d\n",
-            i, lock->id, lock->state);
-        }
-    }    
-}
-
-int dmDOMutexLock(DMMutex *mutex, const char *file, const int line)
-{
-    if (mutex != NULL)
-    {
-        dmPrintMutexLocks(mutex, "LOCKING", file, line);
-        
-        DMMutexLock *lock = dmGetMutexThreadIDLock(mutex);
-        if (lock != NULL)
-        {
-            int res;
-            if (lock->state == 0)
-                res = SDL_mutexP(mutex->m);
-            else
-                res = 1;
-            lock->state++;
-            fprintf(stderr, "LOCKING %p @ thread=%d done [1].\n", mutex, SDL_ThreadID());
-            return res;
-        }
-        else
-        {
-            int i;
-            for (i = 0; i < 8; i++)
-            {
-                DMMutexLock *lock = &(mutex->locks[i]);
-                if (!lock->used)
-                {
-                    int res;
-                    lock->used = TRUE;
-                    lock->id = SDL_ThreadID();
-                    lock->state++;
-                    res = SDL_mutexP(mutex->m);
-                    fprintf(stderr, "LOCKING %p @ thread=%d done [2].\n", mutex, SDL_ThreadID());
-                    return res;
-                }
-            }
-            return -2;
-        }
-    }
-    return -1;
-}
-
-
-int dmDOMutexUnlock(DMMutex *mutex, const char *file, const int line)
-{
-    if (mutex != NULL)
-    {
-        dmPrintMutexLocks(mutex, "UN-LOCKING", file, line);
-
-        DMMutexLock *lock = dmGetMutexThreadIDLock(mutex);
-        if (lock != NULL)
-        {
-            int res;
-            lock->state--;
-            if (lock->state == 0)
-                res = SDL_mutexV(mutex->m);
-            else
-                res = lock->state;
-            return res;
-        }
-        else
-        {
-            return -2;
-        }
-    }
-    return -1;
-}
-
-
-DMMutex * dmDOCreateMutex(const char *file, const int line)
-{
-    DMMutex *mutex = dmMalloc0(sizeof(DMMutex));
-    if (mutex == NULL)
-        return NULL;
-    mutex->cr_file = dm_strdup(file);
-    mutex->cr_line = line;
-    mutex->m = SDL_CreateMutex();
-    return mutex;
-}
-
-
-void dmDestroyMutex(DMMutex *mutex)
-{
-    if (mutex != NULL)
-    {
-        SDL_DestroyMutex(mutex->m);
-        dmFree(mutex);
-    }
-}
-
-#endif
--- a/dmlib.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,509 +0,0 @@
-/*
- * DMLib
- * -- Main header file
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2011-2014 Tecnic Software productions (TNSP)
- */
-#ifndef DMLIB_H
-#define DMLIB_H
-
-#include <SDL_config.h>
-#include <SDL_endian.h>
-#include <SDL_types.h>
-#include <SDL_mutex.h>
-#include <SDL_thread.h>
-#include <SDL_video.h>
-#include <stdarg.h>
-
-#ifdef DM_USE_ASSERTS
-#  include <assert.h>
-#else
-#  define assert(NEXPR) // stub
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Defaults
-#define DM_PROG_AUTHOR      "By Matti 'ccr' Hamalainen (C) Copyright 2014 TNSP"
-#define DM_PROG_LICENSE     "Et all, see README / COPYING for more information."
-
-/* Error codes
- */
-enum {
-    // General error codes
-    DMERR_OK = 0,
-    DMERR_PROGRESS,     // Status OK, but operation in progress
-	
-    DMERR_FOPEN,
-    DMERR_FREAD,
-    DMERR_FWRITE,
-    DMERR_FSEEK,
-    DMERR_NOT_FOUND,    // Resource/data not found
-
-    DMERR_INVALID_DATA, // Some data was invalid
-    DMERR_MALLOC,       // Memory allocation failure
-    DMERR_ALREADY_INIT, // Resource has already been initialized
-    DMERR_INIT_FAIL,    // General initialization failure
-    DMERR_INVALID_ARGS,
-
-    DMERR_NULLPTR,      // NULL pointer specified in critical argument
-    DMERR_NOT_SUPPORTED,// Operation not supported
-    DMERR_OUT_OF_DATA,
-    DMERR_EXTRA_DATA,
-    DMERR_BOUNDS,
-
-    DMERR_INTERNAL,
-
-    // PACK-file subsystem
-    DMERR_NOTPACK,
-    DMERR_VERSION,
-    DMERR_INVALID,
-    DMERR_COMPRESSION,
-};
-
-
-// Resource management defines
-#define DMRES_NAME_LEN  32
-#define DMRES_DATA_PACK	"data.pak"  // Name of the data-file
-#define DMRES_DATA_PATH	"data/"     // Sub-directory path
-#define DMRES_RES_FILE  "res.txt"   // Resource data file
-
-
-/* Define a boolean type
- */
-#if !defined(FALSE) && !defined(TRUE) && !defined(BOOL)
-typedef enum { FALSE = 0, TRUE = 1 } BOOL;
-#endif
-
-#ifndef BOOL
-#  ifdef bool
-#    define BOOL bool
-#  else
-#    define BOOL int
-#  endif
-#endif
-
-
-/* Math constants
- */
-#define DM_PI   3.14159265358f
-#define DM_PI2  6.28318530718f
-#define DM_E    2.71828182846f
-
-
-/* Fixed point math type
- */
-typedef union
-{
-    Sint64 dw;
-    Sint32 w[2];
-} DMFixedPoint;
-
-
-typedef union
-{
-    Sint32 dw;
-    Sint16 w[2];
-} DMFixedPoint32;
-
-
-/* Macros for fixed point math
- */
-#if __GNUC__ >= 3
-#  define FP_SET(a, k) a.dw = k ## ULL
-#else
-#  define FP_SET(a, k) a.dw = k
-#endif
-
-#define FP_CONV(a, k) a.dw = (k)
-
-#ifndef SDL_BYTEORDER
-#  error Undefined byteorder!
-#endif
-
-#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
-#  define FP_SETH(a, k) a.w[0] = (k)
-#  define FP_SETL(a, k) a.w[1] = (k)
-#  define FP_SETHL(a, h, l) { a.w[0] = (h); a.w[1] = (l); }
-#  define FP_GETH32(a) a.w[0]
-#  define FP_GETL32(a) a.w[1]
-#  define FP_GETH16(a) a.w[0]
-#  define FP_GETL16(a) a.w[1]
-#elif (SDL_BYTEORDER == SDL_LIL_ENDIAN)
-#  define FP_SETH(a, k) a.w[1] = (k)
-#  define FP_SETL(a, k) a.w[0] = (k)
-#  define FP_SETHL(a, h, l) { a.w[1] = (h); a.w[0] = (l); }
-#  define FP_GETH32(a) a.w[1]
-#  define FP_GETL32(a) a.w[0]
-#  define FP_GETH16(a) a.w[1]
-#  define FP_GETL16(a) a.w[0]
-#else
-#  error Unsupported byte order!
-#endif
-
-#define FP_PRINTF64(a) printf("%.8x:%.8x", FP_GETH32(a), FP_GETL32(a))
-#define FP_PRINTF32(a) printf("%.4x:%.4x", FP_GETH16(a), FP_GETL16(a))
-
-#define FP_ADD(a, b) a.dw += b.dw
-#define FP_SUB(a, b) a.dw -= b.dw
-#define FP_ADD_R(r, a, b) r.dw = a.dw + b.dw
-#define FP_SUB_R(r, a, b) r.dw = a.dw - b.dw
-#define FP_DIV(a, b) a.dw /= b.dw
-#define FP_MUL(a, b) a.dw *= b.dw
-#define FP_DIV_R(r, a, b) r.dw = (a.dw / b.dw)
-#define FP_MUL_R(r, a, b) r.dw = (a.dw * b.dw)
-
-
-/* Miscellaneous types
- */
-typedef struct
-{
-#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
-    Uint8 a,g,b,r;
-#elif (SDL_BYTEORDER == SDL_LIL_ENDIAN)
-    Uint8 r,g,b,a;
-#endif
-} DMRGBA32;
-
-
-typedef float DMFloat;
-
-
-// Macro for swapping two lvalues of same type
-#define DM_SWAP(T, A, B) { if ((B) < (A)) { T swtmp = (B); B = (A); A = swtmp; } }
-
-
-/* Drawing modes used by blitting and some other functions.
- */
-enum
-{
-    DMD_NONE        = 0x0000,
-    DMD_TRANSPARENT = 0x0001,
-    DMD_SATURATE    = 0x0002,
- 
-    DMD_ANTIALIAS   = 0x0004,
-    
-    DMD_NMODES      = 6
-};
-
-
-// Available bitdepths. Not all functions may support every one of these.
-enum
-{
-    DMD_8BIT = 0,
-    DMD_32BIT,
-    
-    DMD_NBITDEPTHS
-};
-
-
-static inline int dmBitsPerPixel2Index(int bpp)
-{
-    return (bpp == 8 ? 0 : (bpp == 32 ? 1 : -1));
-}
-
-
-/* Generic parameter interpolation
- */
-#define DMM_S_CURVE(t)     ((t) * (t) * (3.0f - 2.0f * (t)))
-#define DMM_LERP(t, a, b)  ((a) + (t) * ((b) - (a)))
-
-typedef struct
-{
-    DMFloat start, end, nsteps;
-} DMLerpContext;
-
-
-void       dmLerpInit(DMLerpContext *ctx, DMFloat start, DMFloat end, DMFloat nsteps);
-DMFloat    dmCatmullRom(const DMFloat t, const DMFloat p0, const DMFloat p1, const DMFloat p2, const DMFloat p3);
-
-
-static inline DMFloat dmClamp10(const DMFloat a)
-{
-    return (a < 0.0f ? 0.0f : (a > 1.0f ? 1.0f : a));
-}
-
-
-static inline int dmClamp(const int v, const int min, const int max)
-{
-    return (v < min ? min : (v > max ? max : v));
-}
-
-
-static inline DMFloat dmLerpSCurve(DMLerpContext *ctx, const DMFloat step)
-{
-    const DMFloat n = step / ctx->nsteps;
-    const DMFloat v = DMM_S_CURVE(n);
-    return DMM_LERP(v, ctx->start, ctx->end);
-}
-
-
-static inline DMFloat dmLerpSCurveClamp(DMLerpContext *ctx, const DMFloat step)
-{
-    const DMFloat n = dmClamp10(step / ctx->nsteps);
-    const DMFloat v = DMM_S_CURVE(n);
-    return DMM_LERP(v, ctx->start, ctx->end);
-}
-
-
-static inline DMFloat dmLerp1(DMLerpContext *ctx, const DMFloat step)
-{
-    const DMFloat v = step / ctx->nsteps;
-    return DMM_LERP(v, ctx->start, ctx->end);
-}
-
-
-static inline DMFloat dmLerp1Clamp(DMLerpContext *ctx, const DMFloat step)
-{
-    const DMFloat v = dmClamp10(step / ctx->nsteps);
-    return DMM_LERP(v, ctx->start, ctx->end);
-}
-
-
-static inline DMFloat dmCatmullRomClamp(const DMFloat t, const DMFloat p0, const DMFloat p1, const DMFloat p2, const DMFloat p3)
-{
-    return dmCatmullRom(dmClamp10(t), p0, p1, p2, p3);
-}
-
-
-/* Perlin noise
- */
-void       dmPerlinInit(void);
-DMFloat    dmPerlinNoise2D(DMFloat x, DMFloat y, DMFloat alpha, DMFloat beta, int n);
-
-
-/* Arbitrary line drawing
- */
-#ifdef DM_GFX_LINES
-#define DM_HEADER
-#include "dmlinefunc.h"
-
-enum
-{
-    CLIP_TOP     = 1,
-    CLIP_BOTTOM  = 2,
-    CLIP_RIGHT   = 4,
-    CLIP_LEFT    = 8
-};
-
-#define DM_CLIP_FUNC dmClipLineCoordsFloat
-#define DM_COORD_TYPE DMFloat
-#include "dmlineclip.h"
-
-#undef DM_HEADER
-#endif
-
-
-/* Various blitting functions
- */
-#ifdef DM_GFX_BLITS
-typedef int (*DMScaledBlitFunc)(SDL_Surface *src, const int x0, const int y0, const int dwidth, const int dheight, SDL_Surface *dst);
-DMScaledBlitFunc dmGetScaledBlitFunc(SDL_PixelFormat *src, SDL_PixelFormat *dst, int mode);
-int dmScaledBlitSurfaceAny(SDL_Surface *src, const int x0, const int y0, const int dwidth, const int dheight, SDL_Surface *dst, int mode);
-
-typedef int (*DMUnscaledBlitFunc)(SDL_Surface *src, const int x0, const int y0, SDL_Surface *dst);
-DMUnscaledBlitFunc dmGetUnscaledBlitFunc(SDL_PixelFormat *src, SDL_PixelFormat *dst, int mode);
-int dmUnscaledBlitSurfaceAny(SDL_Surface *src, const int x0, const int y0, SDL_Surface *dst, int mode);
-
-SDL_Surface *dmConvertScaledSurface(SDL_Surface *src, SDL_PixelFormat *fmt, Uint32 flags, const int dwidth, const int dheight);
-
-
-#define DM_HEADER
-#include "dmblitfunc.h"
-#undef DM_HEADER
-
-#endif // DM_GFX_BLITS
-
-
-/* Misc functions
- */
-#ifdef DM_GFX_MISC
-
-void       dmFillRect(SDL_Surface *screen, int x0, int y0, int x1, int y1, const Uint32 col);
-void       dmDrawHLine(SDL_Surface *screen, int x0, int x1, int yc, const Uint32 col);
-void       dmDrawVLine(SDL_Surface *screen, int y0, int y1, int xc, const Uint32 col);
-
-void       dmDrawBox3D(SDL_Surface *screen, int x0, int y0, int x1, int y1, Uint32 ucol, Uint32 dcol);
-void       dmFillBox3D(SDL_Surface *screen, int x0, int y0, int x1, int y1, Uint32 bgcol, Uint32 ucol, Uint32 dcol);
-
-#endif // DM_GFX_MISC
-
-
-static inline void dmClearSurface(SDL_Surface *screen, const Uint32 col)
-{
-    SDL_FillRect(screen, NULL, col);
-}
-
-
-static inline Uint32 dmMapRGB(SDL_Surface *screen, int r, int g, int b)
-{
-    return SDL_MapRGB(screen->format, r, g, b);
-}
-
-
-static inline Uint32 dmMapRGBA(SDL_Surface *screen, int r, int g, int b, int a)
-{
-    return SDL_MapRGBA(screen->format, r, g, b, a);
-}
-
-
-static inline int dmDirectBlitSurface(SDL_Surface *bmp, SDL_Surface *screen)
-{
-    return SDL_BlitSurface(bmp, NULL, screen, NULL);
-}
-
-
-static inline SDL_Surface *dmCopySurface(SDL_Surface *src)
-{
-    if (src != NULL)
-        return SDL_ConvertSurface(src, src->format, src->flags);
-    else
-        return NULL;
-}
-
-
-/* Global variables
- */
-extern char *dmProgName,
-            *dmProgDesc,
-            *dmProgVersion,
-            *dmProgAuthor,
-            *dmProgLicense;
-
-extern int dmVerbosity;
-void       dmInitProg(char *name, char *desc, char *version, char *author, char *license);
-void       dmPrintBanner(FILE *outFile, const char *name, const char *usage);
-
-void       dmMsgVA(int level, const char *fmt, va_list ap);
-void       dmMsg(int level, const char *fmt, ...);
-void       dmPrintVA(int level, const char *fmt, va_list ap);
-void       dmPrint(int level, const char *fmt, ...);
-void       dmErrorVA(const char *fmt, va_list);
-void       dmError(const char *fmt, ...);
-
-void *     dmMalloc(size_t);
-void *     dmMalloc0(size_t);
-void *     dmRealloc(void *, size_t);
-void *     dmCalloc(size_t, size_t);
-void       dmFree(void *);
-
-BOOL dmGetIntVal(const char *s, int *i);
-
-int         dmGetErrno();
-const char *dmErrorStr(int error);
-
-char *     dm_strdup(const char *);
-char *     dm_strndup(const char *, const size_t n);
-char *     dm_strdup_vprintf(const char *, va_list);
-char *     dm_strdup_printf(const char *, ...);
-
-
-/* Mutexes
- */
-#ifdef DM_MUTEX_DEBUG
-
-typedef struct
-{
-    BOOL used;
-    Uint32 id;
-    int state;
-} DMMutexLock;
-
-typedef struct
-{
-    char *cr_file;
-    int cr_line;
-    SDL_mutex *m;
-    DMMutexLock locks[8];
-} DMMutex;
-
-#define dmMutexLock(x) dmDOMutexLock(x, __FILE__, (int) __LINE__)
-#define dmMutexUnlock(x) dmDOMutexUnlock(x, __FILE__, (int) __LINE__)
-#define dmCreateMutex(x) dmDOCreateMutex(__FILE__, (int) __LINE__)
-
-int        dmDOMutexLock(DMMutex *mutex, const char *file, const int line);
-int        dmDOMutexUnlock(DMMutex *mutex, const char *file, const int line);
-DMMutex *  dmDOCreateMutex(const char *file, const int line);
-void       dmDestroyMutex(DMMutex *mutex);
-
-#else
-#define DMMutex SDL_mutex
-#define dmCreateMutex() SDL_CreateMutex()
-#define dmDestroyMutex(x) SDL_DestroyMutex(x)
-#define dmMutexLock(x) SDL_mutexP(x)
-#define dmMutexUnlock(x) SDL_mutexV(x)
-#endif
-
-/* Endianess swapping macros
- */
-#define DM_SWAP_16_LE_BE(value)    ((Uint16) (   \
-    (Uint16) ((Uint16) (value) >> 8) |      \
-    (Uint16) ((Uint16) (value) << 8)) )
-
-
-#define DM_SWAP_32_LE_BE(value) ((Uint32) (               \
-    (((Uint32) (value) & (Uint32) 0x000000ffU) << 24) | \
-    (((Uint32) (value) & (Uint32) 0x0000ff00U) <<  8) | \
-    (((Uint32) (value) & (Uint32) 0x00ff0000U) >>  8) | \
-    (((Uint32) (value) & (Uint32) 0xff000000U) >> 24)))
-
-#ifdef DM_HAVE_64BIT
-#define DM_SWAP_64_LE_BE(value) ((Uint64) (                           \
-    (((Uint64) (value) & (Uint64) 0x00000000000000ffULL) << 56) |   \
-    (((Uint64) (value) & (Uint64) 0x000000000000ff00ULL) << 40) |   \
-    (((Uint64) (value) & (Uint64) 0x0000000000ff0000ULL) << 24) |   \
-    (((Uint64) (value) & (Uint64) 0x00000000ff000000ULL) <<  8) |   \
-    (((Uint64) (value) & (Uint64) 0x000000ff00000000ULL) >>  8) |   \
-    (((Uint64) (value) & (Uint64) 0x0000ff0000000000ULL) >> 24) |   \
-    (((Uint64) (value) & (Uint64) 0x00ff000000000000ULL) >> 40) |   \
-    (((Uint64) (value) & (Uint64) 0xff00000000000000ULL) >> 56)))
-#endif
-
-/* Macros that swap only when needed ...
- */
-#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
-#  define DM_LE16_TO_NATIVE(value) DM_SWAP_16_LE_BE(value)
-#  define DM_LE32_TO_NATIVE(value) DM_SWAP_32_LE_BE(value)
-#  define DM_NATIVE_TO_LE16(value) DM_SWAP_16_LE_BE(value)
-#  define DM_NATIVE_TO_LE32(value) DM_SWAP_32_LE_BE(value)
-
-#  define DM_BE16_TO_NATIVE(value) ((Uint16) (value))
-#  define DM_BE32_TO_NATIVE(value) ((Uint32) (value))
-#  define DM_NATIVE_TO_BE16(value) ((Uint16) (value))
-#  define DM_NATIVE_TO_BE32(value) ((Uint32) (value))
-
-#  ifdef DM_HAVE_64BIT
-#    define DM_LE64_TO_NATIVE(value) DM_SWAP_64_LE_BE(value)
-#    define DM_NATIVE_TO_LE64(value) DM_SWAP_64_LE_BE(value)
-#    define DM_BE64_TO_NATIVE(value) ((Uint64) (value))
-#    define DM_NATIVE_TO_BE64(value) ((Uint64) (value))
-#  endif
-
-#elif (SDL_BYTEORDER == SDL_LIL_ENDIAN)
-
-#  define DM_LE16_TO_NATIVE(value) ((Uint16) (value))
-#  define DM_LE32_TO_NATIVE(value) ((Uint32) (value))
-#  define DM_NATIVE_TO_LE16(value) ((Uint16) (value))
-#  define DM_NATIVE_TO_LE32(value) ((Uint32) (value))
-
-#  define DM_BE16_TO_NATIVE(value) DM_SWAP_16_LE_BE(value)
-#  define DM_BE32_TO_NATIVE(value) DM_SWAP_32_LE_BE(value)
-#  define DM_NATIVE_TO_BE16(value) DM_SWAP_16_LE_BE(value)
-#  define DM_NATIVE_TO_BE32(value) DM_SWAP_32_LE_BE(value)
-
-#  ifdef DM_HAVE_64BIT
-#    define DM_LE64_TO_NATIVE(value) ((Uint64) (value))
-#    define DM_NATIVE_TO_LE64(value) ((Uint64) (value))
-#    define DM_BE64_TO_NATIVE(value) DM_SWAP_64_LE_BE(value)
-#    define DM_NATIVE_TO_BE64(value) DM_SWAP_64_LE_BE(value)
-#  endif
-#endif
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // DMLIB_H
--- a/dmline.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-/*
- * DMLib
- * -- Arbitrary line drawing functions
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2011 Tecnic Software productions (TNSP)
- */
-#include "dmlib.h"
-
-/* Clip line coordinates. Return value:
- * = 0  : No clipping needed.
- * > 0  : Clipped. Line partially inside the clipping area.
- * < 0  : Line completely outside the clipping area.
- */
-#define DM_CLIP_FUNC dmClipLineCoordsFloat
-#define DM_COORD_TYPE DMFloat
-#include "dmlineclip.h"
-
-
-#include "dmlinefunc.h"
--- a/dmlineclip.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,309 +0,0 @@
-/* Clip line coordinates. Return value:
- * = 0  : No clipping needed.
- * > 0  : Clipped. Line partially inside the clipping area.
- * < 0  : Line completely outside the clipping area.
- */
-
-#ifndef DM_HEADER
-#define DM_CLIP_BITS(QB, QX, QY)		\
-    do {					\
-        QB = 0;					\
-        if (QX < clipX0) QB |= CLIP_LEFT;	\
-        else					\
-        if (QX > clipX1) QB |= CLIP_RIGHT;	\
-                                                \
-        if (QY < clipY0) QB |= CLIP_TOP;	\
-        else					\
-        if (QY > clipY1) QB |= CLIP_BOTTOM;	\
-    } while (0)
-
-#define xA (fx0)
-#define xB (fx1)
-#define yA (fy0)
-#define yB (fy1)
-#endif
-
-#ifdef DM_CLIP_DEBUG
-#define CLIPDEB(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
-#else
-#define CLIPDEB(fmt, ...)
-#endif
-
-int DM_CLIP_FUNC (SDL_Surface *screen, DM_COORD_TYPE *x0, DM_COORD_TYPE *y0, DM_COORD_TYPE *x1, DM_COORD_TYPE *y1)
-#ifdef DM_HEADER
-;
-#else
-{
-    const DM_COORD_TYPE
-        clipX0 = screen->clip_rect.x,
-        clipY0 = screen->clip_rect.y,
-        clipX1 = clipX0 + screen->clip_rect.w - 1,
-        clipY1 = clipY0 + screen->clip_rect.h - 1;
-    double fx0 = *x0, fy0 = *y0, fx1 = *x1, fy1 = *y1;
-    int clipA, clipB;
-
-    DM_CLIP_BITS(clipA, xA, yA);
-    DM_CLIP_BITS(clipB, xB, yB);
-
-    CLIPDEB("-- clip [%1.3f, %1.3f - %1.3f, %1.3f] --\n", xA, yA, xB, yB);
-
-#if 1
-    // Cohen-Sutherland clipping method
-    do
-    {
-        const int c = clipA ? clipA : clipB;
-        DM_COORD_TYPE x, y;
-        
-        // The segment is inside?
-        if ((clipA | clipB) == 0)
-        {
-            *x0 = fx0;
-            *y0 = fy0;
-            *x1 = fx1;
-            *y1 = fy1;
-            return 0;
-        }
-
-        // The line segment is outside of the clip region
-        if (clipA & clipB)
-            return -1;
-
-#ifdef DM_CLIP_DEBUG
-        CLIPDEB    "CLIP   : ");
-        if (c == clipA)
-            CLIPDEB("A [%1.3f, %1.3f]\n", xA, yA);
-        else
-            CLIPDEB("B [%1.3f, %1.3f]\n", xB, yB);
-#endif
-        if (c & CLIP_TOP)
-        {
-            if (yB - yA != 0)
-                x = xA + ((clipY0 - yA) * (xB - xA)) / (yB - yA);
-            else
-                x = xA;
-            y = clipY0;
-            CLIPDEB("TOP    : %1.3f, %1.3f\n", x, y);
-        }
-        else
-        if (c & CLIP_BOTTOM)
-        {
-            if (yB - yA != 0)
-                x = xA + ((clipY1 - yA) * (xB - xA)) / (yB - yA);
-            else
-                x = xA;
-            y = clipY1;
-            CLIPDEB("BOTTOM : %1.3f, %1.3f\n", x, y);
-        }
-        else
-        if (c & CLIP_RIGHT)
-        {
-            if (xB - xA != 0)
-                y = yA + ((clipX1 - xA) * (yB - yA)) / (xB - xA);
-            else
-                y = yA;
-            x = clipX1;
-            CLIPDEB("RIGHT  : %1.3f, %1.3f\n", x, y);
-        }
-        else
-        {
-            if (xB - xA != 0)
-                y = yA + ((clipX0 - xA) * (yB - yA)) / (xB - xA);
-            else
-                y = yA;
-            x = clipX0;
-            CLIPDEB("LEFT   : %1.3f, %1.3f\n", x, y);
-        }
-
-        if (c == clipA)
-        {
-            xA = x;
-            yA = y;
-            DM_CLIP_BITS(clipA, xA, yA);
-        }
-        else
-        {
-            xB = x;
-            yB = y;
-            DM_CLIP_BITS(clipB, xB, yB);
-        }
-        
-    } while (1);
-#else
-    // Buyu-Skala clipping method
-    const DM_COORD_TYPE dx = xB - xA;
-    const DM_COORD_TYPE dy = yB - yA;
-    float k, m;
-    int z;
-
-    switch (clipA + clipB)
-    {
-        case 1:
-            if (clipA == 1)
-            {
-                xA = clipX0;
-                yA = (clipX0 - xB) * dy / dx + yB;
-            }
-            else
-            {
-                xB = clipX0;
-                yB = (clipX0 - xA) * dy / dx + yA;
-            }
-            break;
-
-        case 3:
-            k = dy / dx;
-            yA = (clipX0 - xA) * k + yA;
-            xA = clipX0;
-            yB = (clipX1 - xB) * k + yB;
-            xB = clipX1;
-            break;
-
-        case 5:
-            k = dy / dx;
-            z = (clipX0 - xA) * k + yA;
-            if (z < clipY0)
-            {
-                switch (clipA)
-                {
-                    case 0:
-                        xB = xB + (clipY0 - yB) / k;
-                        yB = clipY0;
-                        break;
-                    case 5:
-                        xA = xA + (clipY0 - yA) / k;
-                        yA = clipY0;
-                        break;
-
-                    default:
-                        return -1;  /* the line segment is outside */
-                }
-            }
-            else
-            {
-                switch (clipA)
-                {
-                    case 0:
-                        xB = clipX0;
-                        yB = z;
-                        break;
-                    case 1:
-                        xB = xB + (clipY0 - yB) / k;
-                        yB = clipY0;
-                        xA = clipX0;
-                        yA = z;
-                        break;
-                    case 4:
-                        xA = xA + (clipY0 - yA) / k;
-                        yA = clipY0;
-                        xB = clipX0;
-                        yB = z;
-                        break;
-                    case 5:
-                        xA = clipX0;
-                        yA = z;
-                        break;
-                }
-            }
-            break;
-
-        case 7:
-            switch (clipA)
-            {
-                case 1:
-                    k = dy / dx;
-                    yA = (clipX0 - xB) * k + yB;
-                    if (yA < clipY0)
-                        return -1;  /* the line segment is outside */
-                    xA = clipX0;
-                    yB = (clipX1 - clipX0) * k + yA;
-                    if (yB < clipY0)
-                    {
-                        xB = (clipY0 - yB) / k + clipX1;
-                        yB = clipY0;
-                    }
-                    else
-                        xB = clipX1;
-                    break;
-
-                    /* similarly for cases clipA == 2, 5, 6 */
-            }
-        case 15:
-            switch (clipA)
-            {
-            case 5:
-                if (dy * (clipX1 - clipX0) < dx * (clipY1 - clipY0))
-                {
-                    k = dy / dx;
-                    yA = (clipX0 - xB) * k + yB;
-                    if (yA > clipY1)
-                        return -1;  /* the line segment is outside */
-                    yB = (clipX1 - clipX0) * k + yA;
-                    if (yB < clipY0)
-                        return -1;  /* the line segment is outside */
-                    if (yA < clipY0)
-                    {
-                        xA = (clipY0 - yA) / k + clipX0;
-                        yA = clipY0;
-                        xB = clipX1;
-                    }
-                    else
-                    {
-                        xA = clipX0;
-                        if (yB > clipY1)
-                        {
-                            xB = (clipY1 - yB) / k + clipX1;
-                            yB = clipY1;
-                        }
-                        else
-                            xB = clipX1;
-                    }
-                }
-                else
-                {
-                    m = dx / dy;
-                    xA = (clipY0 - yB) * m + xB;
-                    if (xA > clipX1)
-                        return -1;  /* the line segment is outside */
-                    xB = (clipY1 - clipY0) * m + xA;
-                    if (xB < clipX0)
-                        return -1;  /* the line segment is outside */
-                    if (xA < clipX0)
-                    {
-                        yA = (clipX0 - xA) / m + clipY0;
-                        xA = clipX0;
-                        yB = clipY1;
-                    }
-                    else
-                    {
-                        yA = clipY0;
-                        if (xB > clipX1)
-                        {
-                            yB = (clipX1 - xB) / m + clipY1;
-                            xB = clipX1;
-                        }
-                        else
-                            yB = clipY1;
-                    }
-                }
-
-                /* similarly for cases clipA == 6, 9, 10 */
-            }
-
-            /* cases 2, 4, 8 are similar as case 1, cases 6, 9, 10 are similar as case 5 */
-            /* cases 11, 13, 14 are similar as case 7, case 12 is similar case 3 */
-    }                           /* of case clipA + clipB */
-#endif
-
-    return 1;
-}
-
-#undef DM_CLIP_BITS
-#undef xA
-#undef xB
-#undef yA
-#undef yB
-#undef CLIPDEB
-#endif
-
-#undef DM_CLIP_FUNC
-#undef DM_COORD_TYPE
--- a/dmlinefunc.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-
-#define DM_DRAWLINE_NAME dmDrawLine8
-#define DM_DRAWLINE_DST_BYTES 1
-#define DM_DRAWLINE_DST_TYPE Uint8
-#define DM_DRAWLINE_INNER pix[y0 + x0] = col;
-#include "dmdrawline.h"
-
-
-#define DM_DRAWLINE_NAME dmDrawLine32
-#define DM_DRAWLINE_DST_BYTES 4
-#define DM_DRAWLINE_DST_TYPE Uint32
-#define DM_DRAWLINE_INNER pix[y0 + x0] = col;
-#include "dmdrawline.h"
-
-
-#define DM_DRAWLINE_NAME dmDrawLine8Transparent
-#define DM_DRAWLINE_DST_BYTES 1
-#define DM_DRAWLINE_DST_TYPE Uint8
-#define DM_DRAWLINE_INNER \
-  pix[y0 + x0] = ((int)pix[y0 + x0] + col) >> 1;
-#include "dmdrawline.h"
-
-
-#define DM_DRAWLINE_NAME dmDrawLine32Transparent
-#define DM_DRAWLINE_DST_BYTES 4
-#define DM_DRAWLINE_DST_TYPE DMRGBA32
-#define DM_DRAWLINE_INIT const DMRGBA32 *c = (DMRGBA32*) &col;
-#define DM_DRAWLINE_INNER \
-  const DMRGBA32 q = pix[y0 + x0]; \
-  const int qr = (q.r + c->r) >> 1, qg = (q.g + c->g) >> 1, qb = (q.b + c->b) >> 1;  \
-  pix[y0 + x0].r = qr; \
-  pix[y0 + x0].g = qg; \
-  pix[y0 + x0].b = qb;
-#include "dmdrawline.h"
-
-
-
-
-#define DM_DRAWLINE_NAME dmDrawLine8Saturate
-#define DM_DRAWLINE_DST_BYTES 1
-#define DM_DRAWLINE_DST_TYPE Uint8
-#define DM_DRAWLINE_INNER \
-  const int q = pix[y0 + x0] + col; \
-  pix[y0 + x0] = q < 255 ? q : 255;
-#include "dmdrawline.h"
-
-
-#define DM_DRAWLINE_NAME dmDrawLine32Saturate
-#define DM_DRAWLINE_DST_BYTES 4
-#define DM_DRAWLINE_DST_TYPE DMRGBA32
-#define DM_DRAWLINE_INIT const DMRGBA32 *c = (DMRGBA32*) &col;
-#define DM_DRAWLINE_INNER \
-  const DMRGBA32 q = pix[y0 + x0]; \
-  const int qr = q.r + c->r, qg = q.g + c->g, qb = q.b + c->b;  \
-  pix[y0 + x0].r = qr < 255 ? qr : 255; \
-  pix[y0 + x0].g = qg < 255 ? qg : 255; \
-  pix[y0 + x0].b = qb < 255 ? qb : 255;
-#include "dmdrawline.h"
-
--- a/dmmutex.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/*
- * DMLib
- * -- Bogus implementations of SDL mutex functions
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012 Tecnic Software productions (TNSP)
- */
-
-Uint32 SDL_ThreadID()
-{
-    return 0;
-}
-
-int SDL_mutexP(SDL_mutex *p)
-{
-    (void) p;
-    return 0;
-}
-
-int SDL_mutexV(SDL_mutex *p)
-{
-    (void) p;
-    return 0;
-}
-
-SDL_mutex * SDL_CreateMutex()
-{
-    return NULL;
-}
-
-void SDL_DestroyMutex(SDL_mutex *p)
-{
-    (void) p;
-}
--- a/dmpack.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,191 +0,0 @@
-/*
- * DMLib
- * -- PACK-file handling
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2011 Tecnic Software productions (TNSP)
- */
-#include "dmpack.h"
-#include "dmfile.h"
-
-
-DMPackEntry *dmPackEntryNew()
-{
-    return (DMPackEntry *) dmMalloc0(sizeof(DMPackEntry));
-}
-
-
-void dmPackEntryFree(DMPackEntry * node)
-{
-    dmFree(node);
-}
-
-
-void dmPackEntryInsert(DMPackEntry ** packDir, DMPackEntry * node)
-{
-    if (*packDir != NULL)
-    {
-        node->prev = (*packDir)->prev;
-        (*packDir)->prev->next = node;
-        (*packDir)->prev = node;
-    }
-    else
-    {
-        *packDir = node->prev = node;
-    }
-    
-    node->next = NULL;
-}
-
-
-void dmPackEntryDelete(DMPackEntry ** packDir, DMPackEntry * node)
-{
-    if (node->prev)
-        node->prev->next = node->next;
-
-    if (node->next)
-        node->next->prev = node->prev;
-    else
-        (*packDir)->prev = node->prev;
-
-    node->prev = node->next = NULL;
-}
-
-
-DMPackEntry *dmPackFind(DMPackEntry *list, const char *filename)
-{
-    DMPackEntry *node;
-
-    for (node = list; node != NULL; node = node->next)
-    {
-        if (strcmp(node->filename, filename) == 0)
-            return node;
-    }
-
-    return NULL;
-}
-
-
-/*
- * OPEN a packfile
- */
-int dmPackOpen(const char *filename, DMPackFile ** ppPack, BOOL readOnly)
-{
-    unsigned int i;
-    DMPackFile *pack;
-    DMPackFileHeader hdr;
-
-    *ppPack = NULL;
-
-    // Allocate packfile-structure
-    pack = (DMPackFile *) dmMalloc0(sizeof(DMPackFile));
-    if (pack == NULL)
-        return DMERR_MALLOC;
-
-    // Open the file
-    pack->file = fopen(filename, readOnly ? "rb" : "r+b");
-    if (pack->file == NULL)
-    {
-        dmFree(pack);
-        return DMERR_FOPEN;
-    }
-
-    pack->filename = dm_strdup(filename);
-
-    // Read PACK header
-    fseek(pack->file, 0L, SEEK_SET);
-    if (!dm_fread_str(pack->file, (Uint8 *) &hdr.ident, sizeof(hdr.ident)) ||
-        !dm_fread_le16(pack->file, &hdr.version) ||
-        !dm_fread_le32(pack->file, &hdr.dirEntries) ||
-        !dm_fread_le32(pack->file, &hdr.dirOffset))
-    {
-        dmPackClose(pack);
-        return DMERR_FREAD;
-    }
-
-    // Check information
-    if (memcmp(&hdr.ident, DPACK_IDENT, sizeof(hdr.ident)) != 0)
-    {
-        dmPackClose(pack);
-        return DMERR_NOTPACK;
-    }
-
-    if (hdr.version != DPACK_VERSION)
-    {
-        dmPackClose(pack);
-        return DMERR_VERSION;
-    }
-
-    // Read directory
-    if (fseek(pack->file, hdr.dirOffset, SEEK_SET) != 0)
-    {
-        dmPackClose(pack);
-        return DMERR_INVALID;
-    }
-
-    for (i = 0; i < hdr.dirEntries; i++)
-    {
-        // Allocate and read directory entry
-        DMPackEntry *entry = dmPackEntryNew();
-
-        if (entry == NULL)
-        {
-            dmPackClose(pack);
-            return DMERR_MALLOC;
-        }
-
-        if (!dm_fread_str(pack->file, (Uint8 *) &entry->filename, sizeof(entry->filename)) ||
-            !dm_fread_le32(pack->file, &entry->size) ||
-            !dm_fread_le32(pack->file, &entry->offset) ||
-            !dm_fread_le32(pack->file, &entry->length) ||
-            !dm_fread_le32(pack->file, &entry->flags))
-        {
-            *ppPack = pack;
-            return DMERR_FREAD;
-        }
-
-        // Insert into list
-        dmPackEntryInsert(&pack->entries, entry);
-    }
-
-    // Set the result
-    *ppPack = pack;
-    return DMERR_OK;
-}
-
-
-/*
- * CLOSE the packfile
- */
-int dmPackClose(DMPackFile * pack)
-{
-    DMPackEntry *node;
-
-    if (pack == NULL)
-        return DMERR_OK;
-
-    // Write the directory
-    node = pack->entries;
-    while (node != NULL)
-    {
-        DMPackEntry *next = node->next;
-        dmPackEntryFree(node);
-        node = next;
-    }
-
-    // Close the file
-    if (pack->file != NULL)
-    {
-        fclose(pack->file);
-        pack->file = NULL;
-    }
-
-    // Free structures
-    dmFree(pack->filename);
-    pack->filename = NULL;
-
-    // Free packfile
-    pack->entries = NULL;
-    dmFree(pack);
-
-    return DMERR_OK;
-}
--- a/dmpack.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*
- * DMLib
- * -- PACK-file routines
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2011 Tecnic Software productions (TNSP)
- */
-#ifndef DMPACK_H
-#define DMPACK_H
-#include "dmlib.h"
-
-
-#define	DPACK_IDENT     "TNSPDPCK"      // Magic ident
-#define	DPACK_VERSION   (0x0120)        // Version
-#define	DPACK_TMPSIZE   (128 * 1024)
-
-
-typedef struct _DMPackEntry
-{
-    char    filename[DMRES_NAME_LEN];
-    Uint32  size;              // Size (UNCOMPRESSED)
-    Uint32  offset;            // Offset in pack file
-    Uint32  length;            // (Compressed) data length
-
-    Uint32  flags, privFlags;
-    
-    struct _DMPackEntry *next, *prev;
-} DMPackEntry;
-
-
-typedef struct
-{
-    DMPackEntry *entries;
-    char *  filename;          // Filename & path
-    FILE *  file;              // File
-} DMPackFile;
-
-
-typedef struct
-{
-    char    ident[8];          // Magic identifier
-    Uint16  version;           // Version
-    Uint32  dirEntries;        // Number of entries
-    Uint32  dirOffset;         // Offset of the directory
-} DMPackFileHeader;
-
-
-DMPackEntry *  dmPackEntryNew();
-void           dmPackEntryFree(DMPackEntry *);
-void           dmPackEntryInsert(DMPackEntry **, DMPackEntry *);
-void           dmPackEntryDelete(DMPackEntry **, DMPackEntry *);
-
-DMPackEntry *  dmPackFind(DMPackEntry *list, const char *filename);
-
-int            dmPackOpen(const char *, DMPackFile **, BOOL);
-int            dmPackClose(DMPackFile *);
-int            dmPackRead(DMPackFile *, const char *, Uint8 **, size_t *);
-
-
-#endif // DMPACK_H
--- a/dmpackutil.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,313 +0,0 @@
-/*
- * DMLib
- * -- PACK-file additional utility routines
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2011 Tecnic Software productions (TNSP)
- */
-#include "dmpackutil.h"
-#include <zlib.h>
-#include "dmfile.h"
-
-
-DMPackEntry *dmPackEntryCopy(const DMPackEntry *src)
-{
-    DMPackEntry *node = dmPackEntryNew();
-    if (node == NULL)
-        return NULL;
-
-    strncpy(node->filename, src->filename, sizeof(node->filename));
-    node->filename[sizeof(node->filename) - 1] = 0;
-
-    node->size     = src->size;
-    node->offset   = src->offset;
-    node->length   = src->length;
-    node->flags    = src->flags;
-
-    return node;
-}
-
-
-/*
- * CLOSE/WRITE the packfile
- */
-int dmPackWrite(DMPackFile * pack)
-{
-    DMPackEntry *node;
-    DMPackFileHeader hdr;
-
-    if (pack == NULL)
-        return DMERR_OK;
-
-    if (pack->file == NULL)
-        return DMERR_FOPEN;
-
-    // Compute directory offset and number of entries
-    memcpy(&hdr.ident, DPACK_IDENT, sizeof(hdr.ident));
-    hdr.version = DPACK_VERSION;
-    hdr.dirEntries = 0;
-    hdr.dirOffset =
-        sizeof(hdr.ident) + sizeof(hdr.version) +
-        sizeof(hdr.dirEntries) + sizeof(hdr.dirOffset);
-
-    node = pack->entries;
-    while (node != NULL)
-    {
-        hdr.dirEntries++;
-        hdr.dirOffset += node->length;
-        node = node->next;
-    }
-
-    // Write PACK header
-    if (fseek(pack->file, 0L, SEEK_SET) != 0)
-        return DMERR_FSEEK;
-
-    if (!dm_fwrite_str(pack->file, (Uint8 *) & hdr.ident, sizeof(hdr.ident)) ||
-        !dm_fwrite_le16(pack->file, hdr.version) ||
-        !dm_fwrite_le32(pack->file, hdr.dirEntries) ||
-        !dm_fwrite_le32(pack->file, hdr.dirOffset))
-        return DMERR_FWRITE;
-
-    // Write the directory
-    if (fseek(pack->file, hdr.dirOffset, SEEK_SET) != 0)
-        return DMERR_FSEEK;
-
-    node = pack->entries;
-    while (node != NULL)
-    {
-        // Write one entry
-        if (!dm_fwrite_str(pack->file, node->filename, sizeof(node->filename)) ||
-            !dm_fwrite_le32(pack->file, node->size) ||
-            !dm_fwrite_le32(pack->file, node->offset) ||
-            !dm_fwrite_le32(pack->file, node->length) ||
-            !dm_fwrite_le32(pack->file, node->flags))
-            return DMERR_FWRITE;
-
-        node = node->next;
-    }
-
-    return DMERR_OK;
-}
-
-
-/*
- * CREATE a packfile, for writing
- */
-int dmPackCreate(const char *filename, DMPackFile ** pack)
-{
-    // Allocate packfile-structure
-    *pack = (DMPackFile *) dmCalloc(1, sizeof(DMPackFile));
-    if (*pack == NULL)
-        return DMERR_MALLOC;
-
-    // Open the file
-    (*pack)->file = fopen(filename, "wb");
-    if ((*pack)->file == NULL)
-    {
-        dmFree(*pack);
-        return DMERR_FOPEN;
-    }
-
-    (*pack)->filename = dm_strdup(filename);
-
-    // Set the result
-    return DMERR_OK;
-}
-
-
-/*
- * ADD a file into the PACK
- */
-int dmPackAddFile(DMPackFile * pack, const char *filename,
-    BOOL doCompress, const Uint32 flags, DMPackEntry ** ppEntry)
-{
-    z_stream zstr;
-    off_t startOffs;
-    unsigned int zstrSize;
-    FILE *inFile;
-    Uint8 *inBuffer, *outBuffer;
-    DMPackEntry entry, *node;
-    int result;
-
-    *ppEntry = NULL;
-
-    if (pack == NULL)
-        return DMERR_OK;
-
-    if (pack->file == NULL)
-        return DMERR_FOPEN;
-
-    // Compute starting offset
-    startOffs = sizeof(DMPackFileHeader);
-    node = pack->entries;
-    while (node != NULL)
-    {
-        startOffs += node->length;
-        node = node->next;
-    }
-
-    // Seek to the position
-    if (fseek(pack->file, startOffs, SEEK_SET) != 0)
-        return DMERR_INVALID;
-
-    // Read file data
-    if ((inFile = fopen(filename, "rb")) == NULL)
-        return -1;
-
-    // Allocate temporary buffer
-    inBuffer = (Uint8 *) dmMalloc(DPACK_TMPSIZE);
-    if (!inBuffer)
-    {
-        fclose(inFile);
-        return DMERR_MALLOC;
-    }
-
-    outBuffer = (Uint8 *) dmMalloc(DPACK_TMPSIZE);
-    if (!outBuffer)
-    {
-        dmFree(inBuffer);
-        fclose(inFile);
-        return DMERR_MALLOC;
-    }
-
-    // Read (and possibly compress) the data
-    zstrSize = 0;
-    zstr.zalloc = (alloc_func) Z_NULL;
-    zstr.zfree = (free_func) Z_NULL;
-    zstr.opaque = (voidpf) Z_NULL;
-    result = deflateInit(&zstr, (doCompress) ? Z_DEFAULT_COMPRESSION : 0);
-    if (result != Z_OK)
-    {
-        dmFree(inBuffer);
-        dmFree(outBuffer);
-        fclose(inFile);
-        return DMERR_COMPRESSION;
-    }
-
-    // Initialize compression streams
-    result = Z_OK;
-    while (!feof(inFile) && result == Z_OK)
-    {
-        zstr.avail_in = fread(inBuffer, sizeof(Uint8), DPACK_TMPSIZE, inFile);
-        zstr.next_in = inBuffer;
-        zstr.next_out = outBuffer;
-        zstr.avail_out = DPACK_TMPSIZE;
-        zstr.total_out = 0;
-        result = deflate(&zstr, Z_FULL_FLUSH);
-
-        if (result == Z_OK && zstr.total_out > 0)
-        {
-            zstrSize += zstr.total_out;
-            fwrite(outBuffer, sizeof(Uint8), zstr.total_out, pack->file);
-        }
-    }
-
-    // Create directory entry
-    strncpy(entry.filename, filename, sizeof(entry.filename));
-    entry.filename[sizeof(entry.filename) - 1] = 0;
-    entry.size   = zstr.total_in;
-    entry.offset = startOffs;
-    entry.length = zstrSize;
-    entry.flags  = flags;
-
-    // Cleanup
-    deflateEnd(&zstr);
-    dmFree(inBuffer);
-    dmFree(outBuffer);
-    fclose(inFile);
-
-    // Add directory entry
-    if ((*ppEntry = dmPackEntryCopy(&entry)) == NULL)
-        return DMERR_MALLOC;
-
-    dmPackEntryInsert(&pack->entries, *ppEntry);
-
-    return DMERR_OK;
-}
-
-
-/*
- * EXTRACT a file from the PACK
- */
-int dmPackExtractFile(DMPackFile *pack, DMPackEntry * entry)
-{
-    z_stream zstr;
-    FILE *outFile;
-    Uint8 *inBuffer, *outBuffer;
-    size_t inDataLeft;
-    int ret;
-
-    if (pack == NULL)
-        return DMERR_OK;
-
-    if (pack->file == NULL)
-        return DMERR_FOPEN;
-
-    // Seek to the position
-    if (fseek(pack->file, entry->offset, SEEK_SET) != 0)
-        return DMERR_INVALID;
-
-    // Open destination file
-    if ((outFile = fopen(entry->filename, "wb")) == NULL)
-        return -1;
-
-    // Allocate temporary buffer
-    if ((inBuffer = (Uint8 *) dmMalloc(DPACK_TMPSIZE)) == NULL)
-    {
-        fclose(outFile);
-        return DMERR_MALLOC;
-    }
-
-    if ((outBuffer = (Uint8 *) dmMalloc(DPACK_TMPSIZE)) == NULL)
-    {
-        dmFree(inBuffer);
-        fclose(outFile);
-        return DMERR_MALLOC;
-    }
-
-    // Read and uncompress the data
-    zstr.zalloc = (alloc_func) Z_NULL;
-    zstr.zfree = (free_func) Z_NULL;
-    zstr.opaque = (voidpf) Z_NULL;
-    ret = inflateInit(&zstr);
-    if (ret != Z_OK)
-    {
-        dmFree(inBuffer);
-        dmFree(outBuffer);
-        fclose(outFile);
-        return DMERR_COMPRESSION;
-    }
-
-    // Initialize compression streams
-    inDataLeft = entry->length;
-    ret = Z_OK;
-    while (inDataLeft > 0 && ret == Z_OK)
-    {
-        if (inDataLeft >= DPACK_TMPSIZE)
-            zstr.avail_in = fread(inBuffer, sizeof(Uint8), DPACK_TMPSIZE, pack->file);
-        else
-            zstr.avail_in = fread(inBuffer, sizeof(Uint8), inDataLeft, pack->file);
-
-        inDataLeft -= zstr.avail_in;
-        zstr.next_in = inBuffer;
-
-        while (zstr.avail_in > 0 && ret == Z_OK)
-        {
-            zstr.next_out = outBuffer;
-            zstr.avail_out = DPACK_TMPSIZE;
-            zstr.total_out = 0;
-            ret = inflate(&zstr, Z_FULL_FLUSH);
-            if (zstr.total_out > 0)
-            {
-                fwrite(outBuffer, sizeof(Uint8), zstr.total_out, outFile);
-            }
-        }
-    }
-
-    // Cleanup
-    inflateEnd(&zstr);
-    dmFree(inBuffer);
-    dmFree(outBuffer);
-    fclose(outFile);
-
-    return DMERR_OK;
-}
--- a/dmpackutil.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-/*
- * DMLib
- * -- PACK-file additional utility routines
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2011 Tecnic Software productions (TNSP)
- */
-#ifndef DMPACKUTIL_H
-#define DMPACKUTIL_H
-#include "dmpack.h"
-
-DMPackEntry *  dmPackEntryCopy(const DMPackEntry *);
-int            dmPackWrite(DMPackFile *);
-int            dmPackCreate(const char *, DMPackFile **);
-int            dmPackAddFile(DMPackFile *, const char *, BOOL, const Uint32 flags, DMPackEntry **);
-int            dmPackExtractFile(DMPackFile *, DMPackEntry *);
-
-#endif // DMPACKUTIL_H
--- a/dmperlin.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,134 +0,0 @@
-/*
- * Coherent noise function over 1 or 2 dimensions.
- */
-#include "dmlib.h"
-#include <math.h>
-
-#define B	(0x100)
-#define BM	(0x0ff)
-#define NP	(12)
-#define N	(0x1000)
-#define NM 	(0x0fff)
-
-
-#define DM_PERLIN_SETUP(i, b0, b1, r0, r1) \
-{				\
-    t = (vec[i] + N);		\
-    b0 = (((int) t) & BM);	\
-    b1 = ((b0 + 1) & BM);	\
-    r0 = (t - ((int) t));	\
-    r1 = (r0 - 1.0f);		\
-}
-        
-
-#define DM_PERLIN_AT2(rx,ry) ((rx) * q[0] + (ry) * q[1])
-
-
-static int p[B + B + 2];
-static DMFloat g2[B + B + 2][2];
-static DMFloat g1[B + B + 2];
-
-
-static DMFloat dmPerlinDoNoise2(DMFloat vec[2])
-{
-    int bx0, bx1, by0, by1, b00, b10, b01, b11;
-    DMFloat rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v;
-    int i, j;
-
-    DM_PERLIN_SETUP(0, bx0, bx1, rx0, rx1);
-    DM_PERLIN_SETUP(1, by0, by1, ry0, ry1);
-
-    i = p[bx0];
-    j = p[bx1];
-
-    b00 = p[i + by0];
-    b10 = p[j + by0];
-    b01 = p[i + by1];
-    b11 = p[j + by1];
-
-    sx = DMM_S_CURVE(rx0);
-    sy = DMM_S_CURVE(ry0);
-
-    q = g2[b00];
-    u = DM_PERLIN_AT2(rx0, ry0);
-    q = g2[b10];
-    v = DM_PERLIN_AT2(rx1, ry0);
-    a = DMM_LERP(sx, u, v);
-
-    q = g2[b01];
-    u = DM_PERLIN_AT2(rx0, ry1);
-    q = g2[b11];
-    v = DM_PERLIN_AT2(rx1, ry1);
-    b = DMM_LERP(sx, u, v);
-
-    return DMM_LERP(sy, a, b);
-}
-
-
-static void dmPerlinNormalize2(DMFloat v[2])
-{
-    DMFloat s = sqrt(v[0] * v[0] + v[1] * v[1]);
-    v[0] /= s;
-    v[1] /= s;
-}
-
-
-void dmPerlinInit(void)
-{
-    int i, j, k;
-
-    srand(32);
-    
-    for (i = 0; i < B; i++)
-    {
-        p[i] = i;
-        g1[i] = (DMFloat) ((rand() % (B + B)) - B) / B;
-
-        for (j = 0; j < 2; j++)
-            g2[i][j] = (DMFloat) ((rand() % (B + B)) - B) / B;
-
-        dmPerlinNormalize2(g2[i]);
-    }
-
-    while (--i)
-    {
-        k = p[i];
-        p[i] = p[j = rand() % B];
-        p[j] = k;
-    }
-
-    for (i = 0; i < B + 2; i++)
-    {
-        p[B + i] = p[i];
-        g1[B + i] = g1[i];
-
-        for (j = 0; j < 2; j++)
-            g2[B + i][j] = g2[i][j];
-    }
-}
-
-
-/* Harmonic summing functions - PDB
- * In what follows "alpha" is the weight when the sum is formed.
- * Typically it is 2, As this approaches 1 the function is noisier.
- * "beta" is the harmonic scaling/spacing, typically 2.
- */
-DMFloat dmPerlinNoise2D(DMFloat x, DMFloat y, DMFloat alpha, DMFloat beta, int n)
-{
-    int i;
-    DMFloat val, sum = 0;
-    DMFloat p[2], scale = 1;
-
-    p[0] = x;
-    p[1] = y;
-    for (i = 0; i < n; i++)
-    {
-        val = dmPerlinDoNoise2(p);
-        sum += val / scale;
-        scale *= alpha;
-        p[0] *= beta;
-        p[1] *= beta;
-    }
-
-    return sum;
-}
--- a/dmq3d.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,408 +0,0 @@
-#include "dmlib.h"
-#include "dmq3d.h"
-#include "dmimage.h"
-
-
-#define DM_DRAWLINE_NAME dmDrawLineSpec
-#define DM_DRAWLINE_DST_BYTES 4
-#define DM_DRAWLINE_DST_TYPE DMRGBA32
-#define DM_DRAWLINE_ARGS , SDL_Surface *bmp
-#define DM_DRAWLINE_INIT const int px = bmp->w / 2, py = bmp->h / 2;
-#define DM_DRAWLINE_INNER \
-     dmUnscaledBlitSurface32to32Transparent(bmp, x0-px, y0-py, screen);
-#define DM_DRAWLINE_SPEC
-#include "dmdrawline.h"
-
-
-static int dmFind3DBitmap(int nitems, DM3DBitmap *items, DM3DBitmap *item)
-{
-    int i;
-    for (i = 0; i < nitems; i++)
-    if (strcmp(item->name, items[i].name) == 0)
-        return i;
-    return -1;
-}
-
-#define DM_FIND_ITEM_FUNC(NAME, TYPE) \
-static int dmFind3D ## NAME (int nitems, TYPE *items, TYPE *item) \
-{ \
-    int i; \
-    for (i = 0; i < nitems; i++) \
-    if (memcmp(item, items+i, sizeof(TYPE)) == 0) \
-        return i; \
-    return -1; \
-}
-
-#define DM_ADD_ITEM_FUNC(NAME, TYPE) \
-static int dmAdd3D ## NAME (int *nitems, int *nalloc, TYPE **items, TYPE *item, int *res) \
-{ \
-    int tmp; \
-    if ((tmp = dmFind3D ## NAME (*nitems, *items, item)) >= 0) \
-    { \
-        if (res != NULL) *res = tmp; \
-        return DMERR_OK; \
-    } \
-    if ((*nitems) + 1 >= *nalloc) \
-    { \
-        (*nalloc) += 16; \
-        if ((*items = dmRealloc(*items, *nalloc * sizeof(TYPE))) == NULL) \
-        { \
-            dmError("Error allocating memory for " # TYPE ".\n"); \
-            return DMERR_MALLOC; \
-        } \
-    } \
-    memcpy((*items) + (*nitems), item, sizeof(TYPE)); \
-    if (res != NULL) *res = *nitems; \
-    (*nitems)++; \
-    return DMERR_OK; \
-}
-
-DM_FIND_ITEM_FUNC(Vertex, DMVector)
-DM_FIND_ITEM_FUNC(Vector, DM3DVector)
-DM_FIND_ITEM_FUNC(Sprite, DM3DSprite)
-
-DM_ADD_ITEM_FUNC(Vertex, DMVector)
-DM_ADD_ITEM_FUNC(Vector, DM3DVector)
-DM_ADD_ITEM_FUNC(Sprite, DM3DSprite)
-DM_ADD_ITEM_FUNC(Bitmap, DM3DBitmap)
-
-
-int dmAdd3DVectorSpriteModelVertex(DM3DVectorSpriteModel *model, DMVector *v, int *index)
-{
-    return dmAdd3DVertex(&model->nvertices, &model->nvertexalloc,
-         &model->vertices, v, index);
-}
-
-int dmAdd3DVectorSpriteModelVector(DM3DVectorSpriteModel *model, DM3DVector *v, int *index)
-{
-    return dmAdd3DVector(&model->nlines, &model->nlinesalloc,
-         &model->lines, v, index);
-}
-
-int dmAdd3DVectorSpriteModelSprite(DM3DVectorSpriteModel *model, DM3DSprite *v, int *index)
-{
-    return dmAdd3DSprite(&model->nsprites, &model->nspritesalloc,
-         &model->sprites, v, index);
-}
-
-int dmAdd3DVectorSpriteModelBitmap(DM3DVectorSpriteModel *model, DM3DBitmap *v, int *index)
-{
-    return dmAdd3DBitmap(&model->nbitmaps, &model->nbitmapsalloc,
-         &model->bitmaps, v, index);
-}
-
-
-static inline DMFloat dmPX(int cx, DMVector p)
-{
-    return cx + (p.x * 250.0f) / p.z;
-}
-
-
-static inline DMFloat dmPY(int cy, DMVector p)
-{
-    return cy + (p.y * 250.0f) / p.z;
-}
-
-
-void dmDraw3DVectorSpriteModel(SDL_Surface *screen, const DM3DVectorSpriteModel *model, const DMVector *pos, const DMMatrix *mat, SDL_Surface *fbmap, const Uint32 lcol)
-{
-    int i;
-    int cx = screen->w / 2, cy = screen->h / 2;
-    for (i = 0; i < model->nlines; i++)
-    {
-        DM3DVector *line = &model->lines[i];
-        DMVector pv[2];
-        dm_vector_copy(&pv[0], &model->vertices[line->v1]);
-        dm_vector_copy(&pv[1], &model->vertices[line->v2]);
-        dm_vector_mul_by_mat_n(pv, 2, mat);
-        dm_vector_add(&pv[0], pos);
-        dm_vector_add(&pv[1], pos);
-        
-        if (pv[0].z <= 0 && pv[1].z <= 0)
-            continue;
-
-        if (line->type > 1)
-            dmDrawLineSpec(screen, dmPX(cx, pv[0]), dmPY(cy, pv[0]), dmPX(cx, pv[1]), dmPY(cy, pv[1]), lcol, fbmap);
-        else
-            dmDrawLine32(screen, dmPX(cx, pv[0]), dmPY(cy, pv[0]), dmPX(cx, pv[1]), dmPY(cy, pv[1]), lcol);
-    }
-
-    for (i = 0; i < model->nsprites; i++)
-    {
-        DM3DSprite *sprite = &model->sprites[i];
-        DM3DBitmap *bmp = &model->bitmaps[sprite->bitmap];
-        DMVector pv;
-        dm_vector_mul_by_mat(&pv, &model->vertices[sprite->v], mat);
-        dm_vector_add(&pv, pos);
-        if (pv.z <= 0)
-            continue;
-        dmUnscaledBlitSurface32to32Transparent(bmp->img, dmPX(cx, pv), dmPY(cy, pv), screen);
-    }
-}
-
-
-static char *dmSkipWhitespace(char *line, BOOL invert)
-{
-    if (invert)
-        for (; *line && !isspace(*line); line++);
-    else
-        for (; *line && isspace(*line); line++);
-    return line;
-}
-
-
-static char *dmSkipUntil(char *line, char ch)
-{
-    for (; *line && *line != ch; line++);
-    return line;
-}
-
-
-static BOOL dmReadCoordinate(const char *orig, char **line, float *value, BOOL next)
-{
-    *line = dmSkipWhitespace(*line, FALSE);
-    if (sscanf(*line, "%f", value) != 1)
-    {
-        dmError("Expected floating point value @ %d:\n%s\n", (*line - orig), orig);
-        return FALSE;
-    }
-    if (next)
-    {
-        *line = dmSkipUntil(*line, ',');
-        if (**line != ',')
-        {
-            dmError("Expected comma @ %d:\n%s\n", (*line - orig), orig);
-            return FALSE;
-        }
-        *(*line)++;
-    }
-    else
-        *line = dmSkipWhitespace(*line, TRUE);
-
-    return TRUE;
-}
-
-
-static BOOL dmReadVectorSegments(char *line, DM3DVectorSpriteModel *model, BOOL relative, const DMVector *pt)
-{
-    DMVector v, p, *t;
-    int nvertices, vertex, type;
-    int *indices = NULL;
-    char *ptr = line;
-    
-    if (sscanf(ptr+1, "%d", &nvertices) != 1)
-    {
-        dmError("No # of segments @ '%s'\n", ptr);
-        goto error;
-    }
-    
-    if ((indices = dmMalloc(sizeof(int) * (nvertices+1))) == NULL)
-        goto error;
-    
-    ptr = dmSkipWhitespace(ptr, TRUE);
-    dm_vector_copy(&v, pt);
-    for (vertex = 0; vertex <= nvertices; vertex++)
-    {
-        if (*ptr == 'Z')
-        {
-            indices[vertex] = indices[0];
-            ptr++;
-        }
-        else
-        {
-            if (!dmReadCoordinate(line, &ptr, &p.x, TRUE)) return FALSE;
-            if (!dmReadCoordinate(line, &ptr, &p.y, TRUE)) return FALSE;
-            if (!dmReadCoordinate(line, &ptr, &p.z, FALSE)) return FALSE;
-            if (relative)
-            {
-                dm_vector_add(&v, &p);
-                t = &v;
-            }
-            else
-            {
-                dm_vector_add_r(&v, &p, pt);
-                t = &v;
-            }
-
-            if (dmAdd3DVectorSpriteModelVertex(model, t, &indices[vertex]) != DMERR_OK)
-                goto error;
-        }
-
-        ptr = dmSkipWhitespace(ptr, FALSE);
-    }
-    
-    if (sscanf(ptr, "%d", &type) != 1)
-    {
-        dmError("No line type @ '%s'\n", ptr);
-        goto error;
-    }
-    
-    for (vertex = 1; vertex <= nvertices; vertex++)
-    {
-        DM3DVector vec;
-        vec.v1 = indices[vertex - 1];
-        vec.v2 = indices[vertex];
-        vec.type = type;
-        if (dmAdd3DVectorSpriteModelVector(model, &vec, NULL) != DMERR_OK)
-            goto error;
-    }
-
-    return TRUE;
-
-error:
-    dmFree(indices);
-    return FALSE;
-}
-
-
-static BOOL dmReadSprite(char *line, DM3DVectorSpriteModel *model, DMVector *pos)
-{
-    DMVector pt;
-    DM3DSprite spr;
-    char *ptr = line;
-
-    ptr++;
-    if (!dmReadCoordinate(line, &ptr, &pt.x, TRUE)) return FALSE;
-    if (!dmReadCoordinate(line, &ptr, &pt.y, TRUE)) return FALSE;
-    if (!dmReadCoordinate(line, &ptr, &pt.z, FALSE)) return FALSE;
-    ptr = dmSkipWhitespace(ptr, FALSE);
-    if (*ptr != 'B')
-    {
-        dmError("No bitmap definition found for sprite.\n");
-        return FALSE;
-    }
-
-    spr.bitmap = atoi(ptr + 1);
-
-    dm_vector_add(&pt, pos);
-    if (dmAdd3DVectorSpriteModelVertex(model, &pt, &spr.v) != DMERR_OK)
-        return FALSE;
-
-    if (dmAdd3DVectorSpriteModelSprite(model, &spr, NULL) != DMERR_OK)
-        return FALSE;
-
-    return TRUE;
-}
-
-static BOOL dmReadBitmap(char *line, DM3DVectorSpriteModel *model, DMResourceLib *lib)
-{
-    DM3DBitmap bmp, *rbmp;
-    int index;
-    char *ptr = line;
-
-    strncpy(bmp.name, ptr + 1, sizeof(bmp.name));
-    bmp.img = NULL;
-
-    if (dmAdd3DVectorSpriteModelBitmap(model, &bmp, &index) != DMERR_OK)
-        return FALSE;
-
-    rbmp = &(model->bitmaps[index]);
-    if (rbmp->img == NULL)
-    {
-        DMResource *fh;
-        int res;
-        if ((res = dmf_open(lib, rbmp->name, &fh)) != DMERR_OK)
-        {
-            dmError("Could not open resource file '%s', #%d: %s.\n",
-                rbmp->name, res, dmErrorStr(res));
-            return FALSE;
-        }
-        rbmp->img = dmLoadImage(fh);
-        dmf_close(fh);
-        if (rbmp->img == NULL)
-        {
-            dmError("Could not load image file '%s'.\n", rbmp->name);
-            return FALSE;
-        }
-    }
-
-    return TRUE;
-}
-
-
-static int dmDoRead3DVectorSpriteModel(DMResource *f, DM3DVectorSpriteModel *model, DMVector *pos)
-{
-    char line[8192];
-
-    while (dmfgets(line, sizeof(line), f) != NULL)
-    {
-        char *start = dmSkipWhitespace(line, FALSE);
-        switch (*start)
-        {
-            case 0:
-            case '#':
-                break;
-            
-            case 'G':
-                {
-                int res;
-                DMVector pt;
-                start++;
-                if (!dmReadCoordinate(line, &start, &pt.x, TRUE)) return DMERR_INVALID_DATA;
-                if (!dmReadCoordinate(line, &start, &pt.y, TRUE)) return DMERR_INVALID_DATA;
-                if (!dmReadCoordinate(line, &start, &pt.z, FALSE)) return DMERR_INVALID_DATA;
-                dm_vector_add_r(&pt, pos, &pt);
-                if ((res = dmDoRead3DVectorSpriteModel(f, model, &pt)) != DMERR_OK)
-                    return res;
-                }
-                break;
-            
-            case 'E':
-                return DMERR_OK;
-
-            case 'B':
-                if (!dmReadBitmap(start, model, f->lib))
-                    return DMERR_INVALID_DATA;
-                break;
-
-            case 'L':
-                if (!dmReadVectorSegments(start, model, FALSE, pos))
-                    return DMERR_INVALID_DATA;
-                break;
-
-            case 'R':
-                if (!dmReadVectorSegments(start, model, TRUE, pos))
-                    return DMERR_INVALID_DATA;
-                break;
-            
-            case 'S':
-                if (!dmReadSprite(start, model, pos))
-                    return DMERR_INVALID_DATA;
-                break;
-            
-            default:
-                break;
-        }
-    }
-    return DMERR_OK;
-}
-
-
-int dmRead3DVectorSpriteModel(DMResource *f, DM3DVectorSpriteModel **model)
-{
-    DMVector pos;
-
-    if ((*model = dmMalloc0(sizeof(DM3DVectorSpriteModel))) == NULL)
-        return DMERR_MALLOC;
-
-    memset(&pos, 0, sizeof(pos));
-    
-    return dmDoRead3DVectorSpriteModel(f, *model, &pos);
-}
-
-
-void dmFree3DVectorSpriteModel(DM3DVectorSpriteModel *model)
-{
-    int i;
-    for (i = 0; i < model->nbitmaps; i++)
-    {
-        if (model->bitmaps[i].img != NULL)
-            SDL_FreeSurface(model->bitmaps[i].img);
-    }
-
-    dmFree(model->bitmaps);
-    dmFree(model->vertices);
-    dmFree(model->lines);
-    dmFree(model->sprites);
-    dmFree(model);
-}
--- a/dmq3d.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/*
- * DMLib
- * -- Whatever
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012 Tecnic Software productions (TNSP)
- */
-#ifndef DMQ3D_H
-#define DMQ3D_H
-
-#include "dmlib.h"
-#include "dmvecmat.h"
-#include "dmres.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-typedef struct
-{
-    int v1, v2, type;
-} DM3DVector;
-
-
-typedef struct
-{
-    int v, bitmap;
-} DM3DSprite;
-
-
-typedef struct
-{
-    char name[64];
-    SDL_Surface *img;
-} DM3DBitmap;
-
-
-typedef struct
-{
-    int nvertices, nvertexalloc;
-    DMVector *vertices;
-
-    int nlines, nlinesalloc;
-    DM3DVector *lines;
-
-    int nbitmaps, nbitmapsalloc;
-    DM3DBitmap *bitmaps;
-    
-    int nsprites, nspritesalloc;
-    DM3DSprite *sprites;
-} DM3DVectorSpriteModel;
-
-
-int dmAdd3DVectorSpriteModelVertex(DM3DVectorSpriteModel *model, DMVector *v, int *index);
-int dmAdd3DVectorSpriteModelVector(DM3DVectorSpriteModel *model, DM3DVector *v, int *index);
-int dmAdd3DVectorSpriteModelSprite(DM3DVectorSpriteModel *model, DM3DSprite *v, int *index);
-int dmAdd3DVectorSpriteModelBitmap(DM3DVectorSpriteModel *model, DM3DBitmap *v, int *index);
-
-int dmRead3DVectorSpriteModel(DMResource *f, DM3DVectorSpriteModel **model);
-void dmFree3DVectorSpriteModel(DM3DVectorSpriteModel *model);
-
-void dmDraw3DVectorSpriteModel(SDL_Surface *screen, const DM3DVectorSpriteModel *model, const DMVector *pos, const DMMatrix *mat, SDL_Surface *fbmap, const Uint32 lcol);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // DMQ3D_H
--- a/dmres.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1177 +0,0 @@
-/*
- * dmlib
- * -- Resource management
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2003-2013 Tecnic Software productions (TNSP)
- */
-#include "dmres.h"
-#include <time.h>
-
-#ifdef DM_USE_PACKFS
-#include <zlib.h>
-#endif
-
-#ifdef DM_USE_STDIO
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <dirent.h>
-#endif
-
-
-DMResource *dmResourceNew(DMResourceLib *lib, const char *filename, const size_t size)
-{
-    DMResource *node = dmMalloc0(sizeof(DMResource));
-    if (node == NULL)
-        return NULL;
-    
-    node->lib = lib;
-    node->filename = dm_strdup(filename);
-    node->rawSize = size;
-    
-    return node;
-}
-
-
-void dmResourceFreeResData(DMResource *node)
-{
-    if (node->resData != NULL &&
-        node->rops != NULL &&
-        node->rops->free != NULL)
-    {
-        node->rops->free(node);
-    }
-
-    node->resData = NULL;
-    node->flags &= ~DMF_LOADED_RES;
-}
-
-
-void dmResourceFreeRawData(DMResource *node)
-{
-    if ((node->flags & DMF_UNALLOCATED) == 0)
-    {
-        dmFree(node->rawData);
-        node->rawData = NULL;
-        node->flags &= ~DMF_LOADED_RAW;
-    }
-}
-
-
-void dmResourceFree(DMResource *node)
-{
-    if (node != NULL)
-    {
-        dmResourceFreeResData(node);
-        dmResourceFreeRawData(node);
-        dmFree(node->filename);
-        dmFree(node);
-    }
-}
-
-
-void dmResourceInsert(DMResourceLib *lib, DMResource * node)
-{
-    if (lib == NULL || node == NULL)
-        return;
-    
-    node->lib = lib;
-
-    if (lib->resources != NULL)
-    {
-        node->prev = lib->resources->prev;
-        lib->resources->prev->next = node;
-        lib->resources->prev = node;
-    }
-    else
-    {
-        lib->resources = node->prev = node;
-    }
-    
-    node->next = NULL;
-}
-
-
-void dmResourceDelete(DMResourceLib *lib, DMResource * node)
-{
-    if (lib == NULL)
-        return;
-
-    if (node->prev)
-        node->prev->next = node->next;
-
-    if (node->next)
-        node->next->prev = node->prev;
-    else
-        lib->resources->prev = node->prev;
-
-    node->prev = node->next = NULL;
-}
-
-
-DMResource * dmResourceFind(DMResourceLib *lib, const char *filename)
-{
-    DMResource *node, *found = NULL;
-
-    if (lib == NULL)
-        return NULL;
-
-    dmMutexLock(lib->mutex);
-
-    for (node = lib->resources; node != NULL; node = node->next)
-    {
-        if (strcmp(node->filename, filename) == 0)
-        {
-            found = node;
-            break;
-        }
-    }
-
-    dmMutexUnlock(lib->mutex);
-
-    return found;
-}
-
-
-#ifdef DM_USE_STDIO
-/* Basic stdio file routines
- */
-static int dm_stdio_fopen(DMResource *handle)
-{
-    char *rfilename = dm_strdup_printf("%s%s", DMRES_DATA_PATH, handle->filename);
-    if (rfilename == NULL)
-        return DMERR_MALLOC;
-
-    handle->fh = fopen(rfilename, "rb");
-    dmFree(rfilename);
-
-    handle->error = dmGetErrno();
-    return (handle->fh != NULL) ? DMERR_OK : DMERR_FOPEN;
-}
-
-
-static void dm_stdio_fclose(DMResource * f)
-{
-    if (f->fh != NULL)
-    {
-        fclose(f->fh);
-        f->fh = NULL;
-    }
-}
-
-
-static int dm_stdio_ferror(DMResource * f)
-{
-    return f->error;
-}
-
-
-static int dm_stdio_fseek(DMResource *f, const off_t pos, const int whence)
-{
-    int ret = fseek(f->fh, pos, whence);
-    f->error = dmGetErrno();
-    return ret;
-}
-
-
-static int dm_stdio_freset(DMResource * f)
-{
-    if (f->fh != NULL)
-        return dm_stdio_fseek(f, 0L, SEEK_SET);
-    else
-        return DMERR_OK;
-}
-
-
-static off_t dm_stdio_fsize(DMResource *f)
-{
-    off_t savePos, fileSize;
-
-    // Check if the size is cached
-    if (f->rawSize != 0)
-        return f->rawSize;
-
-    // Get file size
-    savePos = ftello(f->fh);
-    if (fseeko(f->fh, 0L, SEEK_END) != 0)
-    {
-        f->error = dmGetErrno();
-        return -1;
-    }
-
-    fileSize = ftello(f->fh);
-    if (fseeko(f->fh, savePos, SEEK_SET) != 0)
-    {
-        f->error = dmGetErrno();
-        return -1;
-    }
-
-    f->rawSize = fileSize;
-    return fileSize;
-}
-
-
-static off_t dm_stdio_ftell(DMResource * f)
-{
-    return ftell(f->fh);
-}
-
-
-static BOOL dm_stdio_feof(DMResource * f)
-{
-    return feof(f->fh);
-}
-
-
-static int dm_stdio_fgetc(DMResource * f)
-{
-    int ret = fgetc(f->fh);
-    f->error = dmGetErrno();
-    return ret;
-}
-
-
-static int dm_stdio_fputc(int v, DMResource * f)
-{
-    int ret = fputc(v, f->fh);
-    f->error = dmGetErrno();
-    return ret;
-}
-
-
-static size_t dm_stdio_fread(void *ptr, size_t size, size_t nmemb, DMResource * f)
-{
-    size_t ret = fread(ptr, size, nmemb, f->fh);
-    f->error = dmGetErrno();
-    return ret;
-}
-
-
-static size_t dm_stdio_fwrite(void *ptr, size_t size, size_t nmemb, DMResource * f)
-{
-    size_t ret = fwrite(ptr, size, nmemb, f->fh);
-    f->error = dmGetErrno();
-    return ret;
-}
-
-
-static int dm_stdio_preload(DMResource *handle)
-{
-    int ret = dm_stdio_fopen(handle);
-    if (ret != DMERR_OK)
-        return ret;
-    
-    dm_stdio_fsize(handle);
-    
-    handle->rawData = dmMalloc(handle->rawSize);
-    if (handle->rawData == NULL)
-        return DMERR_MALLOC;
-    
-    if (dm_stdio_fread(handle->rawData, sizeof(Uint8), handle->rawSize, handle) != handle->rawSize)
-        return DMERR_FREAD;
-    
-    return DMERR_OK;
-}
-
-
-DMResourceOps dfStdioFileOps =
-{
-    "Stdio",
-
-    dm_stdio_freset,
-    dm_stdio_ferror,
-    dm_stdio_fseek,
-    dm_stdio_fsize,
-    dm_stdio_ftell,
-    dm_stdio_feof,
-    dm_stdio_fgetc,
-    dm_stdio_fputc,
-    dm_stdio_fread,
-    dm_stdio_fwrite,
-
-    dm_stdio_fopen,
-    dm_stdio_fclose,
-    dm_stdio_preload
-};
-
-DMResourceOps dfStdioFHOps =
-{
-    "StdioFH",
-
-    dm_stdio_freset,
-    dm_stdio_ferror,
-    dm_stdio_fseek,
-    dm_stdio_fsize,
-    dm_stdio_ftell,
-    dm_stdio_feof,
-    dm_stdio_fgetc,
-    dm_stdio_fputc,
-    dm_stdio_fread,
-    dm_stdio_fwrite,
-
-    NULL,
-    NULL,
-    NULL
-};
-#endif
-
-
-// Some mingw/windows headers define these as macros, which is bad for us
-#ifdef __WIN32
-#undef ferror
-#undef feof
-#endif
-
-
-/*
- * PACK file routines
- */
-#ifdef DM_USE_PACKFS
-static int dm_pack_preload(DMResource *handle)
-{
-    DMPackEntry *node;
-    int res = DMERR_OK, cres, cdataLeft;
-    z_stream cstream;
-    Uint8 *  cbuffer = NULL;
-
-    if (handle->lib == NULL || handle->lib->packFile == NULL)
-        return DMERR_NULLPTR;
-
-    // Search PACK nodelist for file
-    if ((node = dmPackFind(handle->lib->packFile->entries, handle->filename)) == NULL)
-    {
-        dmError("Entry '%s' not found in PACK file.\n", handle->filename);
-        res = DMERR_NOT_FOUND;
-        goto error;
-    }
-
-    // Seek to entry
-    if (fseek(handle->lib->packFile->file, node->offset, SEEK_SET) == -1)
-    {
-        dmError("Could not seek node position in PACK file.\n");
-        res = DMERR_FSEEK;
-        goto error;
-    }
-
-    // Allocate a structures and buffers
-    cbuffer = (Uint8 *) dmMalloc(DPACK_TMPSIZE);
-    if (cbuffer == NULL)
-    {
-        res = DMERR_MALLOC;
-        goto error;
-    }
-
-    // Initialize fields
-    handle->rawOffset = 0;
-    handle->rawSize = node->size;
-    handle->rawData = (Uint8 *) dmMalloc(node->size);
-    if (handle->rawData == NULL)
-    {
-        res = DMERR_MALLOC;
-        goto error;
-    }
-
-    // Initialize decompression
-    cstream.zalloc = (alloc_func) Z_NULL;
-    cstream.zfree = (free_func) Z_NULL;
-    cstream.opaque = (voidpf) Z_NULL;
-    cstream.next_out = handle->rawData;
-    cstream.avail_out = handle->rawSize;
-    cdataLeft = node->length;
-    cres = inflateInit(&(cstream));
-    if (cres != Z_OK)
-    {
-        dmError("Could not initialize zlib stream inflation.\n");
-        res = DMERR_INIT_FAIL;
-        goto error;
-    }
-
-    // Uncompress the data
-    while (cdataLeft > 0 &&
-           cstream.avail_out > 0 && cres == Z_OK)
-    {
-        cstream.avail_in = fread(
-            cbuffer, sizeof(Uint8),
-            (cdataLeft >= DPACK_TMPSIZE) ? DPACK_TMPSIZE : cdataLeft,
-            handle->lib->packFile->file);
-
-        cdataLeft -= cstream.avail_in;
-        cstream.next_in = cbuffer;
-        cres = inflate(&cstream, Z_FULL_FLUSH);
-    }
-
-    // Cleanup
-    inflateEnd(&(cstream));
-
-error:
-    dmFree(cbuffer);
-    return res;
-}
-
-
-static int dm_pack_fopen(DMResource * f)
-{
-    if ((f->flags & DMF_LOADED_RAW) == 0)
-    {
-        int res = dm_pack_preload(f);
-        if (res == DMERR_OK)
-            f->flags |= DMF_LOADED_RAW;
-
-        return res;
-    }
-    else
-        return DMERR_OK;
-}
-
-
-static void dm_pack_fclose(DMResource * f)
-{
-    if ((f->flags & DMF_PERSIST) == 0)
-        dmResourceFreeRawData(f);
-}
-#endif
-
-
-static int dm_mem_freset(DMResource * f)
-{
-    f->rawOffset = 0;
-    return DMERR_OK;
-}
-
-
-static int dm_mem_ferror(DMResource * f)
-{
-    return f->error;
-}
-
-
-static int dm_mem_fseek(DMResource * f, const off_t offset, const int whence)
-{
-    off_t newPos;
-
-    // Calculate the new position
-    switch (whence)
-    {
-        case SEEK_SET:
-            newPos = offset;
-            break;
-
-        case SEEK_CUR:
-            newPos = f->rawOffset + offset;
-            break;
-
-        case SEEK_END:
-            newPos = f->rawSize + offset;
-            break;
-
-        default:
-            return -1;
-    }
-
-    // Set the new position
-    f->rawOffset = newPos;
-
-    // Check the new position
-    if (newPos < 0 && (size_t) newPos >= f->rawSize)
-        return -1;
-
-    return 0;
-}
-
-
-static off_t dm_mem_fsize(DMResource * f)
-{
-    return f->rawSize;
-}
-
-
-static off_t dm_mem_ftell(DMResource * f)
-{
-    return f->rawOffset;
-}
-
-
-static BOOL dm_mem_feof(DMResource * f)
-{
-    // Check for EOF
-    if ((size_t) f->rawOffset <= f->rawSize)
-        return FALSE;
-    else
-        return TRUE;
-}
-
-
-static int dm_mem_fgetc(DMResource * f)
-{
-    // Check for EOF
-    if ((size_t) f->rawOffset < f->rawSize)
-        return f->rawData[f->rawOffset++];
-    else
-        return EOF;
-}
-
-
-static size_t dm_mem_fread(void *buf, size_t size, size_t nmemb, DMResource * f)
-{
-    size_t length = (size * nmemb);
-
-    // Check if we can read the whole chunk
-    if (((size_t) f->rawOffset + length) >= f->rawSize)
-    {
-        nmemb = (f->rawSize - f->rawOffset) / size;
-        length = size * nmemb;
-    }
-
-    memcpy(buf, f->rawData + f->rawOffset, length);
-    f->rawOffset += length;
-    return nmemb;
-}
-
-
-static int dm_mem_fputc(int ch, DMResource * f)
-{
-    // Check for EOF
-    if ((size_t) f->rawOffset < f->rawSize)
-    {
-        f->rawData[f->rawOffset++] = ch;
-        return ch;
-    }
-    else
-        return EOF;
-}
-
-
-static size_t dm_mem_fwrite(void *buf, size_t size, size_t nmemb, DMResource * f)
-{
-    size_t length = (size * nmemb);
-
-    // Check if we can write the whole chunk
-    if (((size_t) f->rawOffset + length) >= f->rawSize)
-    {
-        nmemb = (f->rawSize - f->rawOffset) / size;
-        length = size * nmemb;
-    }
-
-    if (length > 0)
-    {
-        memcpy(f->rawData + f->rawOffset, buf, length);
-        f->rawOffset += length;
-    }
-    return nmemb;
-}
-
-
-#ifdef DM_USE_PACKFS
-DMResourceOps dfPackFileOps =
-{
-    "PackFS",
-
-    dm_mem_freset,
-    dm_mem_ferror,
-    dm_mem_fseek,
-    dm_mem_fsize,
-    dm_mem_ftell,
-    dm_mem_feof,
-    dm_mem_fgetc,
-    NULL,
-    dm_mem_fread,
-    NULL,
-    
-    dm_pack_fopen,
-    dm_pack_fclose,
-    dm_pack_preload,
-};
-#endif
-
-
-DMResourceOps dfMemIOFileOps =
-{
-    "MemIO",
-
-    dm_mem_freset,
-    dm_mem_ferror,
-    dm_mem_fseek,
-    dm_mem_fsize,
-    dm_mem_ftell,
-    dm_mem_feof,
-    dm_mem_fgetc,
-    dm_mem_fputc,
-    dm_mem_fread,
-    dm_mem_fwrite,
-    
-    NULL,
-    dmResourceFree,
-    NULL
-};
-
-
-/* FS file handling functions. These functions call the actual
- * functions depending on where the file is located.
- */
-static int dmResourcePreload(DMResource *handle)
-{
-    int ret = DMERR_OK;
-
-    // Check if we want to preload raw data?
-    if ((handle->lib->flags & DRF_PRELOAD_RAW) ||
-        handle->rops == NULL || handle->rops->load == NULL)
-    {
-        if (handle->flags & DMF_LOADED_RAW)
-            ret = DMERR_OK;
-        else
-        if (handle->fops->preload != NULL)
-        {
-            ret = handle->fops->preload(handle);
-            if (ret == DMERR_OK)
-                handle->flags |= DMF_LOADED_RAW | DMF_PERSIST;
-        }
-        else
-            ret = DMERR_INIT_FAIL;
-
-        dmfreset(handle);
-    }
-
-    // Check if resource data is to be preloaded
-    if (handle->lib->flags & DRF_PRELOAD_RES)
-    {
-        if (handle->flags & DMF_LOADED_RES)
-            ret = DMERR_OK;
-        else
-        if (handle->rops != NULL &&
-            handle->rops->load != NULL)
-        {
-            if ((ret = handle->fops->fopen(handle)) == DMERR_OK)
-            {
-                ret = handle->rops->load(handle);
-                handle->fops->fclose(handle);
-            }
-            
-            if (ret == DMERR_OK)
-                handle->flags |= DMF_LOADED_RES;
-        }
-
-        dmfreset(handle);
-    }
-
-    return ret;
-}
-
-
-int dmf_open(DMResourceLib *lib, const char *filename, DMResource **phandle)
-{
-    DMResource *handle;
-    int res;
-
-    // Check master directory for resource
-    if ((*phandle = handle = dmResourceFind(lib, filename)) == NULL)
-    {
-#ifdef DM_USE_STDIO
-        if (lib->flags & DRF_USE_STDIO)
-        {
-            // Hmm.. does not exist? Fall back to a stdio file
-            *phandle = handle = dmResourceNew(lib, filename, 0);
-            if (handle == NULL)
-                return DMERR_MALLOC;
-
-            handle->fops   = &dfStdioFileOps;
-        }
-        else
-            return DMERR_INIT_FAIL;
-#else
-        // Stdio not enabled, fail
-        return DMERR_INIT_FAIL;
-#endif
-    }
-
-    // Check if the data is preloaded
-    if ((res = handle->fops->fopen(handle)) == DMERR_OK)
-    {
-        dmResourceRef(handle);
-        if (handle->flags & DMF_TEMPORARY)
-        {
-            handle->flags &= ~DMF_TEMPORARY;
-            dmResourceInsert(lib, handle);
-        }
-    }
-    else
-    if (handle->flags & DMF_TEMPORARY)
-    {
-        dmResourceFree(handle);
-        *phandle = handle = NULL;
-    }
-
-    dmfreset(handle);
-    return res;
-}
-
-
-int dmf_create_memio(DMResourceLib *lib, const char *filename,
-    Uint8 *buf, const size_t size, DMResource **phandle)
-{
-    DMResource *handle;
-
-    // Check master directory for resource
-    if ((*phandle = handle = dmResourceFind(lib, filename)) == NULL)
-    {
-        if ((*phandle = handle = dmResourceNew(lib, filename, size)) == NULL)
-            return DMERR_MALLOC;
-
-        handle->flags   = DMF_LOADED_RAW | DMF_UNALLOCATED;
-        handle->fops    = &dfMemIOFileOps;
-        handle->rawData = buf;
-        dmResourceInsert(lib, handle);
-    }
-
-    // Increase refcount
-    dmResourceRef(handle);
-    dmfreset(handle);
-    return DMERR_OK;
-}
-
-
-#ifdef DM_USE_STDIO
-int dmf_create_stdio(const char *filename, const char *mode, DMResource **phandle)
-{
-    DMResource *handle;
-    if ((*phandle = handle = dmResourceNew(NULL, filename, 0)) == NULL)
-        return DMERR_MALLOC;
-
-    handle->fops  = &dfStdioFileOps;
-    handle->fh    = fopen(filename, mode);
-    handle->error = dmGetErrno();
-    
-    if (handle->fh == NULL)
-    {
-        dmResourceFree(handle);
-        return handle->error;
-    }
-
-    dmResourceRef(handle);
-    return DMERR_OK;
-}
-
-
-int dmf_create_stdio_stream(FILE *fh, DMResource **phandle)
-{
-    DMResource *handle;
-    if ((*phandle = handle = dmResourceNew(NULL, "", 0)) == NULL)
-        return DMERR_MALLOC;
-
-    handle->fops = &dfStdioFHOps;
-    handle->fh   = fh;
-    dmResourceRef(handle);
-    return DMERR_OK;
-}
-#endif
-
-
-void dmf_close(DMResource * f)
-{
-    if (f == NULL)
-        return;
-
-    if (f->fops->fclose != NULL)
-        f->fops->fclose(f);
-
-    dmResourceUnref(f);
-}
-
-
-int dmfreset(DMResource *f)
-{
-    if (f == NULL)
-        return DMERR_NULLPTR;
-    
-    if (f->fops == NULL || f->fops->freset == NULL)
-        return DMERR_OK;
-    
-    return f->fops->freset(f);
-}
-
-int dmferror(DMResource * f)
-{
-    f->atime = time(NULL);
-    return f->fops->ferror(f);
-}
-
-int dmfseek(DMResource * f, off_t offset, int whence)
-{
-    f->atime = time(NULL);
-    return f->fops->fseek(f, offset, whence);
-}
-
-off_t dmfsize(DMResource * f)
-{
-    f->atime = time(NULL);
-    return f->fops->fsize(f);
-}
-
-off_t dmftell(DMResource * f)
-{
-    f->atime = time(NULL);
-    return f->fops->ftell(f);
-}
-
-BOOL dmfeof(DMResource * f)
-{
-    f->atime = time(NULL);
-    return f->fops->feof(f);
-}
-
-int dmfgetc(DMResource * f)
-{
-    f->atime = time(NULL);
-    return f->fops->fgetc(f);
-}
-
-int dmfputc(int v, DMResource * f)
-{
-    f->atime = time(NULL);
-    return f->fops->fputc(v, f);
-}
-
-size_t dmfread(void *ptr, size_t size, size_t nmemb, DMResource * f)
-{
-    f->atime = time(NULL);
-    return f->fops->fread(ptr, size, nmemb, f);
-}
-
-size_t dmfwrite(void *ptr, size_t size, size_t nmemb, DMResource * f)
-{
-    f->atime = time(NULL);
-    return f->fops->fwrite(ptr, size, nmemb, f);
-}
-
-char *dmfgets(char *s, int size, DMResource * f)
-{
-    char *p = s, c;
-    int n = 0;
-
-    while ((c = f->fops->fgetc(f)) != EOF)
-    {
-        n++;
-        if (c == '\n')
-            break;
-        else
-        if (n < size - 1)
-            *p++ = c;
-    }
-    *p = 0;
-    
-    return (n > 0) ? s : NULL;
-}
-
-
-int dmResourceRef(DMResource *node)
-{
-    if (node->lib != NULL) dmMutexLock(node->lib->mutex);
-    node->atime = time(NULL);
-    node->refcount++;
-    if (node->lib != NULL) dmMutexUnlock(node->lib->mutex);
-
-    return node->refcount;
-}
-
-
-int dmResourceUnref(DMResource *node)
-{
-    if (node->lib != NULL) dmMutexLock(node->lib->mutex);
-    node->refcount--;
-    if (node->lib != NULL) dmMutexUnlock(node->lib->mutex);
-
-    return node->refcount;
-}
-
-
-#ifdef DM_USE_STDIO
-static int dmResourcesLoadDirectory(DMResourceLib *lib, const char *path)
-{
-    int res = DMERR_OK;
-    struct dirent *dh;
-    DIR *hdir = opendir(path);
-    if (hdir == NULL)
-        return dmGetErrno();
-
-    dmMutexLock(lib->mutex);
-
-    do
-    {
-        DMResource *node = NULL;
-        dh = readdir(hdir);
-        if (dh != NULL)
-        {
-            struct stat sbuf;
-            char *fname = dm_strdup_printf("%s/%s", path, dh->d_name);
-            if (stat(fname, &sbuf) == -1)
-            {
-                res = dmGetErrno();
-                dmError("Could not stat() %s, #%d: %s\n",
-                    fname, res, dmErrorStr(res));
-                dmFree(fname);
-                goto out;
-            }
-
-            if (S_ISREG(sbuf.st_mode))
-                node = dmResourceNew(lib, dh->d_name, sbuf.st_size);
-        }
-
-        if (node != NULL)
-        {
-            node->fops = &dfStdioFileOps;
-            dmResourceInsert(lib, node);
-        }
-    } while (dh != NULL);
-
-out:
-    dmMutexUnlock(lib->mutex);
-
-#ifdef __WIN32
-#else
-    closedir(hdir);
-#endif
-
-    return res;
-}
-#endif
-
-
-/* Resources subsystem initialization and shutdown routines
- */
-int dmResourcesInit(DMResourceLib **plib, const char *filename, const char *path, const int flags, int (*classifier)(DMResource *))
-{
-    DMResourceLib *lib;
-    BOOL initialized = FALSE;
-
-    // Allocate the resource library structure
-    if ((*plib = lib = dmMalloc0(sizeof(DMResourceLib))) == NULL)
-        return DMERR_MALLOC;
-
-    // Basic data
-    lib->mutex    = dmCreateMutex();
-    lib->flags    = flags; 
-    lib->resPath  = dm_strdup((path != NULL) ? path : DMRES_DATA_PATH);
-
-
-#ifdef DM_USE_PACKFS
-    if (flags & DRF_USE_PACK)
-    {
-        int ret;
-        DMPackEntry *node;
-
-        lib->packFilename = dm_strdup((filename != NULL) ? filename : DMRES_DATA_PACK);
-
-        // Initialize PACK, open as read-only
-        ret = dmPackOpen(lib->packFilename, &lib->packFile, TRUE);
-        if (ret != DMERR_OK)
-        {
-            if ((flags & DRF_USE_STDIO) == 0)
-            {
-                dmError("Error opening PACK file '%s', #%d: %s\n",
-                lib->packFilename, ret, dmErrorStr(ret));
-
-                return DMERR_INIT_FAIL;
-            }
-            else
-                dmError("Failed to open PACK, falling back to STDIO, '%s' %d: %s\n",
-                lib->packFilename, ret, dmErrorStr(ret));
-        }
-        else
-        {
-            // Initialize resources from a PACK file
-            for (node = lib->packFile->entries; node != NULL; node = node->next)
-            {
-                DMResource *res = dmResourceNew(lib, node->filename, node->size);
-                if (res == NULL)
-                {
-                    dmError("Could not allocate memory for resource node '%s' [0x%08x], %d.\n",
-                        node->filename, node->flags, node->size);
-                    return DMERR_INIT_FAIL;
-                }
-
-                res->fops = &dfPackFileOps;
-                dmResourceInsert(lib, res);
-            }
-            
-            initialized = TRUE;
-        }
-    }
-#endif
-
-#ifdef DM_USE_STDIO
-    if (!initialized && (flags & DRF_USE_STDIO))
-    {
-        // Initialize resources from a resource directory
-        int ret = dmResourcesLoadDirectory(lib, lib->resPath);
-        if (ret != DMERR_OK)
-            return ret;
-        initialized = TRUE;
-    }
-#endif
-
-    if (!initialized)
-        return DMERR_INIT_FAIL;
-
-    // Okay, classify resources
-    if (lib->resources != NULL && classifier != NULL)
-    {
-        DMResource *node;
-        for (node = lib->resources; node != NULL; node = node->next)
-        {
-            int ret = classifier(node);
-            if (ret != DMERR_OK)
-                return ret;
-        }
-    }
-
-    // Initialization complete
-    return DMERR_OK;
-}
-
-
-int dmResourcesClose(DMResourceLib *lib)
-{
-    DMResource *node;
-    
-    if (lib == NULL)
-        return DMERR_NULLPTR;
-    
-    dmMutexLock(lib->mutex);
-
-    // Shutdown possible subsystems
-#ifdef DM_USE_PACKFS
-    if (lib->flags & DRF_USE_PACK)
-    {
-        int res = dmPackClose(lib->packFile);
-        if (res != DMERR_OK)
-        {
-            dmError("Error closing PACK, #%i: %s\n",
-                res, dmErrorStr(res));
-        }
-
-        dmFree(lib->packFilename);
-    }
-#endif
-
-    // Free resource entries
-    node = lib->resources;
-    while (node != NULL)
-    {
-        DMResource *next = node->next;
-        dmResourceFree(node);
-        node = next;
-    }
-
-    // Etc.
-    dmFree(lib->resPath);
-    dmMutexUnlock(lib->mutex);
-    dmDestroyMutex(lib->mutex);
-    return DMERR_OK;
-}
-
-
-int dmResourcesPreload(DMResourceLib *lib, BOOL start, int *loaded, int *total)
-{
-    int ret = DMERR_OK;
-
-    dmMutexLock(lib->mutex);
-    
-    // Initialize preloading 
-    if (lib->preload == NULL || start)
-    {
-        DMResource *node;
-        
-        lib->preload = lib->resources;
-        *loaded = 0;
-        *total = 0;
-
-        // Calculate total number of resources to be preloaded
-        if (lib->flags & (DRF_PRELOAD_RAW | DRF_PRELOAD_RES))
-        {
-            for (node = lib->resources; node != NULL; node = node->next)
-                (*total)++;
-        }
-    }
-    else
-    if (lib->preload != NULL)
-    {
-        // Attempt to preload the resource
-        if ((ret = dmResourcePreload(lib->preload)) != DMERR_OK)
-        {
-            dmError("Error preloading '%s', %d: %s\n",
-                lib->preload->filename, ret, dmErrorStr(ret));
-            goto error;
-        }
-
-        (*loaded)++;
-        lib->preload = lib->preload->next;
-    }
-
-    dmMutexUnlock(lib->mutex);
-    return (lib->preload == NULL) ? DMERR_OK : DMERR_PROGRESS;
-
-error:
-    dmMutexUnlock(lib->mutex);
-    return ret;
-}
-
-
-void dmResourcePrune(DMResourceLib *lib, const int agems, int const flags)
-{
-    DMResource *node;
-    const int stamp = time(NULL);
-    dmMutexLock(lib->mutex);
-
-    for (node = lib->resources; node != NULL; node = node->next)
-    {
-        // Check if node has refcount of 0 and is
-        // not marked as persistent resource
-        if (node->refcount == 0 &&
-            (node->flags & DMF_PERSIST) == 0 &&
-            (node->flags & (DMF_LOADED_RES | DMF_LOADED_RAW)))
-        {
-            if (((flags & DMPRUNE_ATIME) && stamp - node->atime >= agems) ||
-                ((flags & DMPRUNE_MTIME) && stamp - node->mtime >= agems))
-            {
-                dmResourceFreeResData(node);
-                dmResourceFreeRawData(node);
-            }
-        }
-    }
-
-    dmMutexUnlock(lib->mutex);
-}
-
-
-/* Helper resource access routines
- */
-int dmf_read_str(DMResource *f, void *s, size_t l)
-{
-    return dmfread(s, 1, l, f) == l;
-}
-
-BOOL dmf_read_byte(DMResource *f, Uint8 *val)
-{
-    int tmp = dmfgetc(f);
-    *val = tmp;
-    return tmp != EOF;
-}
-
-#define DM_DEFINE_FUNC(xname, xtype, xmacro)          \
-BOOL dmf_read_ ## xname (DMResource *f, xtype *v) {      \
-    xtype result;                                     \
-    if (dmfread(&result, sizeof( xtype ), 1, f) != 1) \
-        return FALSE;                                 \
-    *v = DM_ ## xmacro ## _TO_NATIVE (result);        \
-    return TRUE;                                      \
-}
-
-DM_DEFINE_FUNC(le16, Uint16, LE16)
-DM_DEFINE_FUNC(le32, Uint32, LE32)
-
-DM_DEFINE_FUNC(be16, Uint16, BE16)
-DM_DEFINE_FUNC(be32, Uint32, BE32)
-
-#ifdef DM_HAVE_64BIT
-DM_DEFINE_FUNC(le64, Uint64, LE64)
-DM_DEFINE_FUNC(be64, Uint64, BE64)
-#endif
--- a/dmres.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,190 +0,0 @@
-/*
- * DMLib
- * -- Resource management
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2011-2012 Tecnic Software productions (TNSP)
- */
-#ifndef DMRES_H
-#define DMRES_H
-
-#include "dmlib.h"
-
-#ifdef DM_USE_PACKFS
-#include "dmpack.h"
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/* Constants
- */
-enum
-{
-    DMPRUNE_ATIME   = 0x0001,
-    DMPRUNE_MTIME   = 0x0002,
-};
-
-enum
-{
-    DRF_USE_PACK    = 0x0001,
-    DRF_USE_STDIO   = 0x0002,
-    DRF_PRELOAD_RAW = 0x0004,
-    DRF_PRELOAD_RES = 0x0008,
-};
-
-enum
-{
-    DMF_PERSIST     = 0x0001, // Persist loaded RAW resource
-    DMF_TEMPORARY   = 0x0002,
-    DMF_UNALLOCATED = 0x0004, // The raw data is not allocated, so do not free it
-    DMF_LOADED_RAW  = 0x1000, // Raw data has been loaded
-    DMF_LOADED_RES  = 0x2000, // Resource has been loaded
-};
-
-
-/* Typedefs and structures
- */
-struct DMResourceLib;
-struct DMResourceDataOps;
-struct DMResourceOps;
-struct DMResource;
-
-typedef struct DMResource
-{
-    // Timestamps (in seconds from time())
-    int    mtime,              // When resource was loaded
-           atime;              // Last accessed (dmResourceRef()/unref)
-    int    refcount;           // Reference count
-
-    int    flags;              // Resource flags (DMF_*)
-    char   *filename;
-
-    // Raw data (or mem data)
-    size_t rawSize;            // Size of data
-    off_t  rawOffset;          // Current offset in data
-    Uint8 *rawData;            // Pointer to data
-
-    // Decoded resource data
-    void   *resData;
-    size_t resSize;
-    struct DMResourceDataOps *rops;
-
-    int    error;              // Error code
-
-#ifdef DM_USE_STDIO
-    FILE * fh;                 // File handle for stdio
-#endif
-
-    struct DMResourceOps *fops;    // Pointer to file handling functions struct
-    struct DMResourceLib *lib;     // Pointer to the resource library
-    struct DMResource *next, *prev;
-} DMResource;
-
-
-typedef struct DMResourceDataOps
-{
-    BOOL   (*probe)(DMResource *res, const char *fext);
-    int    (*load)(DMResource *res);
-    void   (*free)(DMResource *res);
-} DMResourceDataOps;
-
-
-typedef struct DMResourceLib
-{
-    int  flags;
-    char *resPath;
-
-    DMResource *resources, *preload;
-    DMMutex *mutex;
-
-#ifdef DM_USE_PACKFS
-    char *packFilename;
-    DMPackFile *packFile;
-#endif
-} DMResourceLib;
-
-
-typedef struct DMResourceOps
-{
-    char    *name;
-
-    int     (*freset)(DMResource *);
-    int     (*ferror)(DMResource *);
-    int     (*fseek)(DMResource *, const off_t, const int);
-    off_t   (*fsize)(DMResource *);
-    off_t   (*ftell)(DMResource *);
-    BOOL    (*feof)(DMResource *);
-    int     (*fgetc)(DMResource *);
-    int     (*fputc)(int, DMResource *);
-    size_t  (*fread)(void *, const size_t, const size_t, DMResource *);
-    size_t  (*fwrite)(void *, const size_t, const size_t, DMResource *);
-
-    int     (*fopen)(DMResource *);
-    void    (*fclose)(DMResource *);
-    int     (*preload)(DMResource *);
-} DMResourceOps;
-
-
-/* Functions
- */
-int          dmResourcesInit(DMResourceLib **lib, const char *filename, const char *path, const int flags, int (*classifier)(DMResource *));
-int          dmResourcesClose(DMResourceLib *lib);
-
-void         dmResourcesPrune(DMResourceLib *lib, const int agems, int const flags);
-int          dmResourcesPreload(DMResourceLib *lib, BOOL start, int *loaded, int *total);
-
-DMResource * dmResourceNew(DMResourceLib *lib, const char *filename, const size_t size);
-void         dmResourceFree(DMResource *node);
-void         dmResourceInsert(DMResourceLib *lib, DMResource * node);
-void         dmResourceDelete(DMResourceLib *lib, DMResource * node);
-DMResource * dmResourceFind(DMResourceLib *lib, const char *filename);
-int          dmResourceRef(DMResource *);
-int          dmResourceUnref(DMResource *);
-
-
-// Opening and closing resources
-int          dmf_open(DMResourceLib *lib, const char *, DMResource **handle);
-int          dmf_create_memio(DMResourceLib *lib, const char *, Uint8 *buf, size_t len, DMResource **phandle);
-#ifdef DM_USE_STDIO
-int          dmf_create_stdio(const char *filename, const char *mode, DMResource **phandle);
-int          dmf_create_stdio_stream(FILE *, DMResource **phandle);
-#endif
-void         dmf_close(DMResource *);
-
-
-// Basic resource access functions
-int          dmfreset(DMResource *);
-int          dmferror(DMResource *);
-int          dmfseek(DMResource *, const off_t, const int);
-off_t        dmfsize(DMResource *);
-off_t        dmftell(DMResource *);
-BOOL         dmfeof(DMResource *);
-int          dmfgetc(DMResource *);
-int          dmfputc(int, DMResource *);
-size_t       dmfread(void *, const size_t, const size_t, DMResource *);
-size_t       dmfwrite(void *, const size_t, const size_t, DMResource *);
-char *       dmfgets(char *s, int size, DMResource * f);
-
-
-// Helper functions for endianess based reading etc
-int          dmf_read_str(DMResource *, void *, size_t);
-BOOL         dmf_read_byte(DMResource *, Uint8 *);
-
-BOOL         dmf_read_be16(DMResource *, Uint16 *);
-BOOL         dmf_read_be32(DMResource *, Uint32 *);
-BOOL         dmf_read_le16(DMResource *, Uint16 *);
-BOOL         dmf_read_le32(DMResource *, Uint32 *);
-
-#ifdef DM_HAVE_64BIT
-BOOL         dmf_read_be64(DMResource *, Uint64 *);
-BOOL         dmf_read_le64(DMResource *, Uint64 *);
-#endif
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // DMRES_H
--- a/dmresw.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
- * DMLib
- * -- Resource management
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2011-2012 Tecnic Software productions (TNSP)
- */
-#include "dmresw.h"
-
-int dmf_write_str(DMResource *f, void *s, size_t l)
-{
-    return dmfwrite(s, 1, l, f) == l;
-}
-
-
-BOOL dmf_write_byte(DMResource *f, const Uint8 val)
-{
-    return dmfputc(val, f) == val;
-}
-
-
-#define DM_DEFINE_FUNC(xname, xtype, xmacro)            \
-BOOL dmf_write_ ## xname (DMResource *f, xtype v) {     \
-    xtype result = DM_NATIVE_TO_ ## xmacro (v);         \
-    if (dmfwrite(&result, sizeof( xtype ), 1, f) != 1)  \
-        return FALSE;                                   \
-    return TRUE;                                        \
-}
-
-DM_DEFINE_FUNC(le16, Uint16, LE16)
-DM_DEFINE_FUNC(le32, Uint32, LE32)
-
-DM_DEFINE_FUNC(be16, Uint16, BE16)
-DM_DEFINE_FUNC(be32, Uint32, BE32)
-
-#ifdef DM_HAVE_64BIT
-DM_DEFINE_FUNC(le64, Uint64, LE64)
-DM_DEFINE_FUNC(be64, Uint64, BE64)
-#endif
--- a/dmresw.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
- * DMLib
- * -- Resource management write helpers
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2011-2012 Tecnic Software productions (TNSP)
- */
-#ifndef DMRESW_H
-#define DMRESW_H
-
-#include "dmres.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int          dmf_write_str(DMResource *, void *, size_t);
-BOOL         dmf_write_byte(DMResource *, const Uint8);
-
-BOOL         dmf_write_be16(DMResource *, Uint16);
-BOOL         dmf_write_be32(DMResource *, Uint32);
-BOOL         dmf_write_le16(DMResource *, Uint16);
-BOOL         dmf_write_le32(DMResource *, Uint32);
-
-#ifdef DM_HAVE_64BIT
-BOOL         dmf_write_be64(DMResource *, Uint64);
-BOOL         dmf_write_le64(DMResource *, Uint64);
-#endif
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // DMRESW_H
--- a/dmscaledblit.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-/*
- * DMLib
- * -- Scaled sprite / surface blitting function template
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2011-2012 Tecnic Software productions (TNSP)
- */
-
-
-int DM_BLITFUNC_NAME (SDL_Surface *src,
-    const int x0, const int y0,
-    const int dwidth, const int dheight,
-    SDL_Surface *dst
-#ifdef DM_BLITFUNC_ARGS
-    DM_BLITFUNC_ARGS
-#endif
-    )
-#ifdef DM_HEADER
-;
-#else
-{
-    int yc;
-    DMFixedPoint32 xv, yv, dx, dy;
-    DMQValue xr, yr;
-
-#ifdef DM_BLITFUNC_VARS
-    DM_BLITFUNC_VARS
-#endif
-    
-    // Clip coordinates
-    if (dmScaledClipCoord(&xr, x0, src->w, dwidth, 
-        dst->clip_rect.x, dst->clip_rect.x + dst->clip_rect.w)
-        ||
-        dmScaledClipCoord(&yr, y0, src->h, dheight,
-        dst->clip_rect.y, dst->clip_rect.y + dst->clip_rect.h))
-        return -1;
-
-#ifdef DM_BLITFUNC_INIT
-    DM_BLITFUNC_INIT
-#endif
-
-    // Calculate "final" initial source bitmap offsets
-    FP_CONV(dy, yr.voffs);
-    FP_MUL_R(yv, dy, yr.vdelta);
-
-    FP_CONV(dx, xr.voffs);
-    FP_MUL_R(dx, dx, xr.vdelta);
-
-    // Take pitch into account
-    const int dstadd = xr.vadd - dst->clip_rect.w + dst->clip_rect.x + (dst->pitch / DM_BLITFUNC_DST_BYTES);
-
-    // Blit scaled
-    DM_BLITFUNC_DST_TYPE * dp = ((DM_BLITFUNC_DST_TYPE *) dst->pixels) + (yr.v0 * dst->pitch) / DM_BLITFUNC_DST_BYTES + xr.v0;
-    for (yc = yr.v0; yc < yr.v1; yc++)
-    {
-        const DM_BLITFUNC_SRC_TYPE * sp = ((DM_BLITFUNC_SRC_TYPE *) src->pixels) + (FP_GETH16(yv) * src->pitch) / DM_BLITFUNC_SRC_BYTES;
-        int xc;
-
-#ifdef DM_BLITFUNC_INNER_INIT
-        DM_BLITFUNC_INNER_INIT
-#endif
-
-        for (xv.dw = dx.dw, xc = xr.v0; xc < xr.v1; xc++)
-        {
-            DM_BLITFUNC_INNER
-            FP_ADD(xv, xr.vdelta);
-        }
-        FP_ADD(yv, yr.vdelta);
-        dp += dstadd;
-    }
-
-#ifdef DM_BLITFUNC_FINISH
-    DM_BLITFUNC_FINISH
-#endif
-
-    return 0;
-}
-#endif
-
-#undef DM_BLITFUNC_NAME
-#undef DM_BLITFUNC_ARGS
-#undef DM_BLITFUNC_SRC_BYTES
-#undef DM_BLITFUNC_DST_BYTES
-#undef DM_BLITFUNC_SRC_TYPE
-#undef DM_BLITFUNC_DST_TYPE
-#undef DM_BLITFUNC_VARS
-#undef DM_BLITFUNC_INIT
-#undef DM_BLITFUNC_INNER_INIT
-#undef DM_BLITFUNC_INNER
-#undef DM_BLITFUNC_FINISH
--- a/dmsimple.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,924 +0,0 @@
-/*
- * dmlib
- * -- Demo engine "player" code
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012-2013 Tecnic Software productions (TNSP)
- */
-#include <SDL.h>
-#include "dmengine.h"
-#include "dmargs.h"
-#include "dmtext.h"
-#include "dmimage.h"
-#include "setupfont.h"
-#include "setupimage.h"
-#include "setupmenubar.h"
-
-static const char *engineSetupDataName = "SetupData.txt";
-static const char *engineSetupImageName = "SetupImage.png";
-static const char *engineSetupMenuBarName = "SetupMenuBar.png";
-static const char *engineSetupFontName = "SetupFont.dmf";
-
-static DMEngineData engine;
-
-static DMOptArg optList[] =
-{
-    { 0, '?', "help",       "Show this help", OPT_NONE },
-    { 1, 'v', "verbose",    "Be more verbose", OPT_NONE },
-};
-
-const int optListN = sizeof(optList) / sizeof(optList[0]);
-
-
-
-static void argShowHelp()
-{
-    dmPrintBanner(stdout, dmProgName, "[options]");
-    dmArgsPrintHelp(stdout, optList, optListN);
-}
-
-
-static BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
-{
-    (void) optArg;
-
-    switch (optN)
-    {
-        case 0:
-            argShowHelp();
-            exit(0);
-            break;
-
-        case 1:
-            dmVerbosity++;
-            break;
-        
-        default:
-            dmError("Unknown option '%s'.\n", currArg);
-            return FALSE;
-    }
-    
-    return TRUE;
-}
-
-
-static int engineAudioThreadFunc(void *userdata)
-{
-    do
-    {
-        if (engine.audioStatus == SDL_AUDIO_PLAYING)
-        {
-            engineAudioCallback(userdata, engine.audioSimBuf, engine.audioSimBufSize);
-        }
-
-        SDL_Delay(engine.audioSimDelay);
-    } while (!engine.audioSimDone);
-
-    return 0;
-}
-
-
-static int engineShowProgress(int loaded, int total)
-{
-    int dx = 60,
-        dh = 20,
-        dw = engine.screen->w - (2 * dx),
-        dy = (engine.screen->h - dh) / 2;
-    
-    if (SDL_MUSTLOCK(engine.screen) != 0 && SDL_LockSurface(engine.screen) != 0)
-        return DMERR_INIT_FAIL;
-    
-    // Draw the progress bar
-    dmClearSurface(engine.screen, dmMapRGBA(engine.screen, 0,0,0,0));
-    dmFillRect(engine.screen, dx, dy, dx+dw, dy+dh, dmMapRGB(engine.screen, 255,255,255));
-    dmFillRect(engine.screen, dx+1, dy+1, dx+dw-1, dy+dh-1, dmMapRGB(engine.screen, 0,0,0));
-
-    if (total > 0)
-    {
-        dmFillRect(engine.screen,
-            dx+3, dy+3,
-            dx + 3 + ((dw - 3) * loaded) / total,
-            dy + dh - 3,
-            dmMapRGB(engine.screen, 200,200,200));
-    }
-
-    // Flip screen
-    if (SDL_MUSTLOCK(engine.screen) != 0)
-        SDL_UnlockSurface(engine.screen);
-
-    SDL_Flip(engine.screen);
-    return DMERR_OK;
-}
-
-
-static int engineLoadResources()
-{
-    int err, loaded = 0, total = 0;
-    BOOL first = TRUE;
-
-    do
-    {
-        // Show a nice progress bar while loading
-        if ((err = engineShowProgress(loaded, total)) != DMERR_OK)
-            return err;
-
-        err = dmResourcesPreload(engine.resources, first, &loaded, &total);
-        first = FALSE;
-    }
-    while (err == DMERR_PROGRESS);
-    
-    return err;
-}
-
-
-static BOOL engineGenInitializeVideo(int width, int height, int depth, Uint32 flags)
-{
-    dmPrint(1, "Initializing SDL video %d x %d x %dbpp, flags=0x%08x\n",
-        width, height, depth, flags);
-
-    SDL_FreeSurface(engine.screen);
-
-    engine.screen = SDL_SetVideoMode(width, height, depth, flags);
-    if (engine.screen == NULL)
-    {
-        dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError());
-        return FALSE;
-    }
-
-    SDL_WM_SetCaption(dmProgDesc, dmProgName);
-
-    return TRUE;
-}
-
-
-static BOOL engineInitializeVideo()
-{
-    return engineGenInitializeVideo(engine.optVidWidth, engine.optVidHeight,
-        engine.optVidDepth, engine.optVFlags);
-}
-
-
-typedef struct
-{
-    int w, h, aspect;
-} DMModeEntry;
-
-
-DMModeEntry *engineModeList = NULL;
-int nengineModeList = 0, aengineModeList = 0;
-
-
-static int engineModeSort(const void *pa, const void *pb)
-{
-    DMModeEntry
-        *va = (DMModeEntry *) pa,
-        *vb = (DMModeEntry *) pb;
-
-    return (va->w - vb->w);
-}
-
-
-int engineAddModeToList(int w, int h)
-{
-    DMModeEntry *mode;
-    int i, aspect = engineGetVideoAspect(w, h);
-    
-    dmPrint(2, " - Proposed %d x %d\n", w, h);
-    if (aspect <= 0)
-        return DMERR_INVALID_ARGS;
-    
-    // Check if the mode is already in our list
-    for (i = 0; i < nengineModeList; i++)
-    {
-        mode = &engineModeList[i];
-        if (mode->w == w && mode->h == h)
-            return DMERR_OK;
-    }
-
-    // Check if the mode fits our criteria
-    switch (engine.optVidSetup)
-    {
-        case DM_VSETUP_ASPECT:
-            if (aspect != engine.optVidAspect)
-                return DMERR_OK;
-            break;
-        
-        case DM_VSETUP_ANY:
-            break;
-    }
-
-    // Reallocate array if needed
-    if (nengineModeList + 1 >= aengineModeList)
-    {
-        aengineModeList += 16;
-        engineModeList = dmRealloc(engineModeList, sizeof(DMModeEntry) * aengineModeList);
-        if (engineModeList == NULL)
-            return DMERR_MALLOC;
-    }
-    
-    // Store
-    mode = &engineModeList[nengineModeList];
-    mode->w = w;
-    mode->h = h;
-    mode->aspect = engineGetVideoAspect(w, h);
-    dmPrint(2, " - %d x %d, %d\n", w, h, mode->aspect);
-    
-    nengineModeList++;
-    
-    return DMERR_OK;
-}
-
-
-int engineParseSetupConfig(const char *filename)
-{
-    DMResource *file = NULL;
-    int res;
-    char buf[128];
-
-    if ((res = dmf_open(engine.resources, filename, &file)) != DMERR_OK)
-        return res;
-
-    while (dmfgets(buf, sizeof(buf), file) != NULL)
-    {
-        ssize_t pos;
-        // Trim line ending
-        for (pos = strlen(buf) - 1; pos >= 0 && isspace(buf[pos]); pos--)
-            buf[pos] = 0;
-
-        // Find start of the line
-        for (pos = 0; isspace(buf[pos]); pos++);
-        
-        // Skip empty lines and comments
-        if (buf[pos] == 0 || buf[pos] == '#')
-            continue;
-
-        char *str = buf+pos;
-        if (sscanf(str, "menuPos %f %f",
-            &engine.setupMenuPos.x, &engine.setupMenuPos.y) != 2 &&
-            sscanf(str, "menuDim %f %f",
-            &engine.setupMenuDim.x, &engine.setupMenuDim.y) != 2 &&
-            sscanf(str, "text1Pos %f %f",
-            &engine.setupText1Pos.x, &engine.setupText1Pos.y) != 2 &&
-            sscanf(str, "menuCenter %d", &engine.setupMenuCenter) != 1 &&
-            sscanf(str, "textCondensed %d", &engine.setupTextCondensed) != 1 &&
-            sscanf(str, "textFullscreen %s", engine.setupTextFullscreen) != 1 &&
-            sscanf(str, "textWindowed %s", engine.setupTextWindowed) != 1 &&
-            sscanf(str, "textPrefix %s", engine.setupTextPrefix) != 1
-            )
-        {
-            dmError("Syntax error in configuration:\n%s\n", buf);
-            res = DMERR_INVALID_DATA;
-            goto out;
-        }
-    }
-
-out:
-    dmf_close(file);
-    return res;
-}
-
-
-static inline DMFloat vsX(DMVector vec)
-{
-    return (DMFloat) engine.screen->w * vec.x;
-}
-
-
-static inline DMFloat vsY(DMVector vec)
-{
-    return (DMFloat) engine.screen->h * vec.y;
-}
-
-
-int engineVideoSetup()
-{
-    DMBitmapFont *menuFont = NULL;
-    DMResource *file = NULL;
-    SDL_Surface *menuBgImage = NULL, *menuBarImage = NULL;
-    int result, menuState = -1;
-    BOOL menuFullScreen = TRUE;
-
-    // Compute a list of valid modes
-    if (!engineGenInitializeVideo(DM_VSETUP_WIDTH, DM_VSETUP_HEIGHT, engine.optVidDepth, engine.optVFlags))
-        goto out;
-
-    SDL_Rect **modes = SDL_ListModes(engine.screen->format, engine.screen->flags | SDL_FULLSCREEN);
-    if (modes == (SDL_Rect**) 0)
-    {
-        dmError("No compatible video resolutions/depths available at all. Bailing out.\n");
-        goto out;
-    }
-    
-    if (modes != (SDL_Rect**) -1)
-    {
-        int i;
-        dmPrint(1, "Enumerating modes.\n");
-        for (i = 0; modes[i] != NULL; i++)
-            engineAddModeToList(modes[i]->w, modes[i]->h);
-    }
-
-    if (nengineModeList == 0)
-    {
-        dmError("Umm, no modes found.\n");
-        goto out;
-    }
-
-    qsort(engineModeList, nengineModeList, sizeof(engineModeList[0]), engineModeSort);
-
-    // Open video temporarily
-    if (!engineGenInitializeVideo(DM_VSETUP_WIDTH, DM_VSETUP_HEIGHT, 32, SDL_SWSURFACE | SDL_DOUBLEBUF))
-        goto out;
-
-    // Get setup data
-    engine.setupMenuPos.x = 0.18750f;
-    engine.setupMenuPos.y = 0.41666f;
-    engine.setupMenuDim.x = 0.625f;
-    engine.setupMenuDim.y = 0.41666f;
-
-    engine.setupText1Pos.x = 0.3f;
-    engine.setupText1Pos.y = 0.7f;
-
-    strcpy(engine.setupTextFullscreen , "FULLSCREEN");
-    strcpy(engine.setupTextWindowed   , " WINDOWED ");
-    strcpy(engine.setupTextPrefix     , "USE LEFT/RIGHT ARROW TO TOGGLE : ");
-
-    if (engineParseSetupConfig(engineSetupDataName) != DMERR_OK)
-        goto out;
-
-    // Fetch and decompress setup image, try regular resources first
-    if ((result = dmf_open(engine.resources, engineSetupImageName, &file)) == DMERR_OK ||
-        (result = dmf_create_memio(NULL, engineSetupImageName, engineSetupImage, sizeof(engineSetupImage), &file)) == DMERR_OK)
-    {
-        menuBgImage = dmLoadImage(file);
-        dmf_close(file);
-    }
-
-    if ((result = dmf_open(engine.resources, engineSetupMenuBarName, &file)) == DMERR_OK ||
-        (result = dmf_create_memio(NULL, engineSetupMenuBarName, engineSetupMenuBar, sizeof(engineSetupMenuBar), &file)) == DMERR_OK)
-    {
-        menuBarImage = dmLoadImage(file);
-        dmf_close(file);
-    }
-
-    if (menuBgImage == NULL || menuBarImage == NULL)
-    {
-        dmError("Could not instantiate setup screen images, %d: %s\n",
-            result, dmErrorStr(result));
-        goto out;
-    }
-    
-    if (menuBgImage->w != DM_VSETUP_WIDTH ||
-        menuBgImage->h != DM_VSETUP_HEIGHT)
-    {
-        dmError("Setup screen background image does not match "
-            "required dimensions (%dx%d vs %dx%d)\n",
-            menuBgImage->w, menuBgImage->h,
-            DM_VSETUP_WIDTH, DM_VSETUP_HEIGHT);
-        goto out;
-    }
-
-
-    // Load up the bitmap font
-    if ((result = dmf_open(engine.resources, engineSetupFontName, &file)) == DMERR_OK ||
-        (result = dmf_create_memio(NULL, engineSetupFontName, engineSetupFont, sizeof(engineSetupFont), &file)) == DMERR_OK)
-    {
-        result = dmLoadBitmapFont(file, &menuFont);
-        dmf_close(file);
-    }
-    if (result != DMERR_OK)
-    {
-        dmError("Could not instantiate setup screen font, %d: %s\n",
-            result, dmErrorStr(result));
-        goto out;
-    }
-
-    SDL_Surface *tmp = dmConvertScaledSurface(menuBgImage,
-        engine.screen->format, engine.screen->flags,
-        engine.screen->w, engine.screen->h);
-    if (tmp == NULL)
-    {
-        dmError("Could not convert setup screen background image.\n");
-        goto out;
-    }
-
-    SDL_FreeSurface(menuBgImage);
-    menuBgImage = tmp;
-
-    SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
-
-
-    // Enter the main loop of the menu
-    char menuStr[256];
-    int menuOffset = 0,
-        menuIndex = 0,
-        menuEntryHeight = menuFont->height + 2,
-        menuHeight = vsY(engine.setupMenuDim) / menuEntryHeight;
-
-    menuState = 0;
-
-    engine.startTime = SDL_GetTicks();
-
-    while (!menuState)
-    {
-        while (SDL_PollEvent(&engine.event))
-        switch (engine.event.type)
-        {
-            case SDL_KEYDOWN:
-                switch (engine.event.key.keysym.sym)
-                {
-                    case SDLK_ESCAPE:
-                        menuState = -1;
-                        break;
-
-                    case SDLK_RETURN:
-                        menuState = 1;
-                        break;
-
-                    case SDLK_UP:
-                        if (menuIndex > 0)
-                            menuIndex--;
-                        else
-                        if (menuOffset > 0)
-                            menuOffset--;
-                        break;
-
-                    case SDLK_DOWN:
-                        if (menuIndex < menuHeight - 1 && menuOffset + menuIndex < nengineModeList - 1)
-                            menuIndex++;
-                        else
-                        if (menuOffset + menuIndex < nengineModeList - 1)
-                            menuOffset++;
-                        break;
-
-                    case SDLK_LEFT:
-                        menuFullScreen = FALSE;
-                        break;
-
-                    case SDLK_RIGHT:
-                        menuFullScreen = TRUE;
-                        break;
-
-                    case SDLK_SPACE:
-                        menuFullScreen = !menuFullScreen;
-                        break;
-
-                    default:
-                        break;
-                }
-
-                break;
-
-            case SDL_QUIT:
-                menuState = -1;
-                break;
-        }
-
-        // Draw frame
-        engine.frameTime = SDL_GetTicks();
-        if (SDL_MUSTLOCK(engine.screen) != 0 && SDL_LockSurface(engine.screen) != 0)
-        {
-            dmError("Can't lock surface.\n");
-            goto out;
-        }
-
-        // Render the menu
-        dmDirectBlitSurface(menuBgImage, engine.screen);
-        
-        // XXX/TODO: Some hardcoded bits here ...
-        float t = engineGetTimeDT(&engine);
-        int index, entry;
-
-        for (index = 0, entry = menuOffset; entry < nengineModeList && index < menuHeight; index++, entry++)
-        {
-            DMModeEntry *mode = &engineModeList[entry];
-
-            if (entry == menuOffset + menuIndex)
-            {
-                dmScaledBlitSurface32to32TransparentGA(menuBarImage,
-                    vsX(engine.setupMenuPos),
-                    vsY(engine.setupMenuPos) + (index * menuEntryHeight),
-                    vsX(engine.setupMenuDim),
-                    menuEntryHeight + 4,
-                    engine.screen,
-                    200 + sin(t * 10.0) * 50);
-            }
-
-            snprintf(menuStr, sizeof(menuStr),
-                "%4d X %-4d  - %d:%d",
-                mode->w, mode->h,
-                mode->aspect / 1000,
-                mode->aspect % 1000);
-
-            DMFloat posX = engine.setupMenuCenter ?
-                2.0f + (vsX(engine.setupMenuDim) - menuFont->width * strlen(menuStr)) / 2.0f :
-                2.0f;
-            
-            dmDrawBMTextConst(
-                engine.screen, menuFont,
-                engine.setupTextCondensed, DMD_TRANSPARENT,
-                vsX(engine.setupMenuPos) + posX,
-                vsY(engine.setupMenuPos) + (index * menuEntryHeight),
-                menuStr);
-        }
-        
-        snprintf(menuStr, sizeof(menuStr),
-            "%s%s",
-            engine.setupTextPrefix,
-            menuFullScreen ? engine.setupTextFullscreen : engine.setupTextWindowed);
-
-        dmDrawBMTextConst(
-            engine.screen, menuFont,
-            engine.setupTextCondensed, DMD_TRANSPARENT,
-            vsX(engine.setupText1Pos),
-            vsY(engine.setupText1Pos),
-            menuStr);
-
-        // Flip screen
-        if (SDL_MUSTLOCK(engine.screen) != 0)
-            SDL_UnlockSurface(engine.screen);
-
-        SDL_Flip(engine.screen);
-        SDL_Delay(25);
-    }
-
-    // Okay, we accepted the selection
-    if (menuState == 1)
-    {
-        DMModeEntry *mode = &engineModeList[menuOffset + menuIndex];
-        engine.optVidNative =
-            mode->w == engine.optVidWidth &&
-            mode->h == engine.optVidHeight;
-
-        engine.optVidWidth = mode->w;
-        engine.optVidHeight = mode->h;
-        engine.optVidAspect = mode->aspect;
-        if (menuFullScreen)
-            engine.optVFlags |= SDL_FULLSCREEN;
-
-    }
-
-out:
-    SDL_FreeSurface(menuBgImage);
-    SDL_FreeSurface(menuBarImage);
-    dmFreeBitmapFont(menuFont);
-    
-    return menuState;
-}
-
-
-int main(int argc, char *argv[])
-{
-    int err;
-    BOOL initSDL = FALSE;
-
-    memset(&engine, 0, sizeof(engine));
-
-    // Pre-initialization
-    if ((err = demoPreInit(&engine)) != DMERR_OK)
-        goto error_exit;
-
-    if (!dmArgsProcess(argc, argv, optList, optListN,
-        argHandleOpt, NULL, FALSE))
-        return DMERR_INIT_FAIL;
-
-    dmPrint(0,
-    "%s\n"
-    "%s\n",
-    dmProgDesc, dmProgAuthor);
-
-    dmPrint(0,
-    "Using libSDL, "
-#ifdef DM_USE_PACKFS
-    "zlib, "
-#endif
-#ifdef DM_USE_TREMOR
-    "Tremor Vorbis codec"
-#endif
-    " and modified stb_image.\n"
-    "See README.txt for more information.\n");
-
-    // Initialize resource subsystem
-    dmPrint(1, "Initializing resources subsystem.\n");
-    if ((err = dmResourcesInit(&engine.resources, engine.optPackFilename,
-        engine.optDataPath, engine.optResFlags, engineClassifier)) != DMERR_OK)
-    {
-        dmError("Could not initialize resource manager, #%d: %s.\n", err, dmErrorStr(err));
-        goto error_exit;
-    }
-
-    // Initialize SDL components
-    dmPrint(1, "Initializing libSDL.\n");
-    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) != 0)
-    {
-        dmError("Could not initialize SDL: %s\n", SDL_GetError());
-        goto error_exit;
-    }
-    initSDL = TRUE;
-
-
-    // Present video mode selector
-    if (engine.optVidAspect <= 0)
-        engine.optVidAspect = engineGetVideoAspect(engine.optVidWidth, engine.optVidHeight);
-
-    if (engine.optVidSetup)
-    {
-        if ((err = engineVideoSetup()) <= 0)
-            goto error_exit;
-    }
-
-    // Initialize audio parts
-    if (engine.optAfmt.freq == 0 && engine.optAfmt.channels == 0)
-    {
-        engine.optAfmt.freq     = 44100;
-        engine.optAfmt.format   = AUDIO_S16SYS;
-        engine.optAfmt.channels = 2;
-    }
-    
-    if (engine.optAfmt.samples == 0)
-        engine.optAfmt.samples = engine.optAfmt.freq / 50;
-
-    switch (engine.optAudioSetup)
-    {
-        case DM_ASETUP_JSS:
-#ifdef DM_USE_JSS
-            jssInit();
-
-            switch (engine.optAfmt.format)
-            {
-                case AUDIO_S16SYS: engine.jssFormat = JSS_AUDIO_S16; break;
-                case AUDIO_U16SYS: engine.jssFormat = JSS_AUDIO_U16; break;
-                case AUDIO_S8:     engine.jssFormat = JSS_AUDIO_S8; break;
-                case AUDIO_U8:     engine.jssFormat = JSS_AUDIO_U8; break;
-            }
-
-            dmPrint(1, "Initializing miniJSS mixer with fmt=%d, chn=%d, freq=%d\n",
-                engine.jssFormat, engine.optAfmt.channels, engine.optAfmt.freq);
-
-            if ((engine.jssDev = jvmInit(engine.jssFormat, engine.optAfmt.channels, engine.optAfmt.freq, JMIX_AUTO)) == NULL)
-            {
-                dmError("jvmInit() returned NULL, voi perkele.\n");
-                goto error_exit;
-            }
-
-            if ((engine.jssPlr = jmpInit(engine.jssDev)) == NULL)
-            {
-                dmError("jmpInit() returned NULL\n");
-                goto error_exit;
-            }
-#else
-            dmError("miniJSS support not included.\n");
-#endif
-            break;
-
-        case DM_ASETUP_TREMOR:
-#ifndef DM_USE_TREMOR
-            dmError("Tremor support not included.\n");
-#endif
-            break;
-    }
-
-    // Initialize SDL audio
-    dmPrint(1, "Trying to init SDL audio with: fmt=%d, chn=%d, freq=%d, samples=%d\n",
-        engine.optAfmt.format, engine.optAfmt.channels,
-        engine.optAfmt.freq, engine.optAfmt.samples);
-
-    engine.audioStatus      = SDL_AUDIO_STOPPED;
-    engine.optAfmt.callback = engineAudioCallback;
-    engine.audioStreamMutex = dmCreateMutex();
-
-    engine.audioSampleSize  = engine.optAfmt.channels;
-    switch (engine.optAfmt.format)
-    {
-        case AUDIO_S16SYS:
-        case AUDIO_U16SYS: engine.audioSampleSize *= 2; break;
-    }
-    
-    if (SDL_OpenAudio(&engine.optAfmt, NULL) < 0)
-    {
-        // We'll let this pass, as we want to support no-sound.
-        dmError("Couldn't open SDL audio, falling back to no sound: %s\n", SDL_GetError());
-
-        // Set up simulated audio thread
-        engine.audioSimDelay   = 1000 / 45;
-        engine.audioSimBufSize = (engine.optAfmt.freq / 45) * engine.audioSampleSize;
-        engine.audioSimBuf     = dmMalloc(engine.audioSimBufSize);
-        engine.audioSimDone    = FALSE;
-        engine.audioSimThread  = SDL_CreateThread(engineAudioThreadFunc, NULL);
-    }
-
-    // Initialize SDL video
-    if (engine.demoInitPreVideo != NULL &&
-       (err = engine.demoInitPreVideo(&engine)) != DMERR_OK)
-    {
-        dmError("demoInitPreVideo() failed, #%d: %s\n", err, dmErrorStr(err));
-        goto error_exit;
-    }
-
-    if (!engineInitializeVideo())
-        goto error_exit;
-
-    if (engine.demoInitPostVideo != NULL &&
-       (err = engine.demoInitPostVideo(&engine)) != DMERR_OK)
-    {
-        dmError("demoInitPostVideo() failed, #%d: %s\n", err, dmErrorStr(err));
-        goto error_exit;
-    }
-
-    // Hide cursor
-    SDL_ShowCursor(SDL_DISABLE);
-
-    // Load resources
-    dmPrint(1, "Loading resources, please wait...\n");
-    if ((err = engineLoadResources()) != DMERR_OK)
-    {
-        dmError("Error loading resources, #%d: %s.\n",
-            err, dmErrorStr(err));
-        goto error_exit;
-    }
-
-    // Final initializations
-    if ((err = engine.demoInit(&engine)) != DMERR_OK)
-    {
-        dmError("Failure in demoInit(), #%d: %s\n",
-            err, dmErrorStr(err));
-        goto error_exit;
-    }
-
-    // Initialize effects
-    if ((err = engineInitializeEffects(&engine)) != DMERR_OK)
-    {
-        dmError("Effects initialization failed, #%d: %s\n",
-            err, dmErrorStr(err));
-        goto error_exit;
-    }
-
-    // Use a timeline, if set
-#ifdef DM_USE_TIMELINE
-    if (engine.timeline != NULL)
-    {
-        if ((err = dmLoadTimeline(engine.timeline, &engine.tl)) != DMERR_OK)
-        {
-            dmError("Error loading timeline, #%d: %s\n", err,
-                dmErrorStr(err));
-            goto error_exit;
-        }
-
-        if ((err = dmPrepareTimeline(engine.tl, engine.ptl)) != DMERR_OK)
-        {
-            dmError("Error creating prepared timeline, #%d: %s\n",
-                err, dmErrorStr(err));
-            goto error_exit;
-        }
-    }
-#endif
-
-    dmPrint(1, "Starting up.\n");
-
-    SDL_LockAudio();
-    enginePauseAudio(0);
-    SDL_UnlockAudio();
-
-    engine.startTime = SDL_GetTicks();
-
-    while (!engine.exitFlag)
-    {
-        while (SDL_PollEvent(&engine.event))
-        switch (engine.event.type)
-        {
-            case SDL_KEYDOWN:
-                switch (engine.event.key.keysym.sym)
-                {
-                    case SDLK_ESCAPE:
-                        engine.exitFlag = TRUE;
-                        break;
-                    
-                    case SDLK_SPACE:
-                        engine.pauseFlag = !engine.pauseFlag;
-                        break;
-
-                    case SDLK_f:
-                        engine.optVFlags ^= SDL_FULLSCREEN;
-                        if (!engineInitializeVideo())
-                            goto error_exit;
-                        break;
-
-                    case SDLK_RETURN:
-                        if (engine.event.key.keysym.mod & KMOD_ALT)
-                        {
-                            engine.optVFlags ^= SDL_FULLSCREEN;
-                            if (!engineInitializeVideo())
-                                goto error_exit;
-                        }
-                        break;
-
-                    default:
-                        break;
-                }
-
-                break;
-
-            case SDL_VIDEOEXPOSE:
-                break;
-
-            case SDL_QUIT:
-                engine.exitFlag = TRUE;
-                break;
-        }
-
-        // Draw frame
-        engine.frameTime = SDL_GetTicks();
-        if (engine.pauseFlag != engine.paused)
-        {
-            engine.paused = engine.pauseFlag;
-            engine.pauseTime = engineGetTick(&engine);
-        }
-        
-        if (engine.paused)
-        {
-            engine.startTime = engine.frameTime - engine.pauseTime;
-        }
-
-        if (SDL_MUSTLOCK(engine.screen) != 0 && SDL_LockSurface(engine.screen) != 0)
-        {
-            dmError("Can't lock surface.\n");
-            goto error_exit;
-        }
-
-        // Call main tick
-        if (engine.demoRender != NULL)
-        {
-            if ((err = engine.demoRender(&engine)) != DMERR_OK)
-                goto error_exit;
-        }
-#ifdef DM_USE_TIMELINE
-        else
-        {
-            if ((err = dmExecuteTimeline(engine.ptl, engine.screen, engineGetTick(&engine))) != DMERR_OK)
-                goto error_exit;
-        }
-#endif
-
-        // Flip screen
-        if (SDL_MUSTLOCK(engine.screen) != 0)
-            SDL_UnlockSurface(engine.screen);
-
-        SDL_Flip(engine.screen);
-        SDL_Delay(engine.paused ? 100 : 20);
-
-        engine.frameCount++;
-    }
-
-    // Print benchmark results
-    engine.endTime = SDL_GetTicks();
-    dmPrint(1, "%d frames in %d ms, fps = %1.3f\n",
-        engine.frameCount, engine.endTime - engine.startTime,
-        (float) (engine.frameCount * 1000.0f) / (float) (engine.endTime - engine.startTime));
-
-
-error_exit:
-
-    dmPrint(1, "Shutting down.\n");
-    SDL_ShowCursor(SDL_ENABLE);
-
-    SDL_LockAudio();
-    enginePauseAudio(1);
-#ifdef DM_USE_JSS
-    if (engine.optAudioSetup == DM_ASETUP_JSS)
-    {
-        jmpClose(engine.jssPlr);
-        jvmClose(engine.jssDev);
-        jssClose();
-    }
-#endif
-
-    if (engine.audioSimThread != NULL)
-    {
-        dmMutexLock(engine.audioStreamMutex);
-        engine.audioSimDone = TRUE;
-        dmMutexUnlock(engine.audioStreamMutex);
-        SDL_WaitThread(engine.audioSimThread, NULL);
-    }
-
-    SDL_UnlockAudio();
-    
-    if (engine.audioStreamMutex != NULL)
-        dmDestroyMutex(engine.audioStreamMutex);
-
-#ifdef DM_USE_TIMELINE
-    dmFreeTimeline(engine.tl);
-    dmFreePreparedTimelineData(engine.ptl);
-#endif
-
-    engineShutdownEffects(&engine);
-    dmResourcesClose(engine.resources);
-
-    if (engine.demoShutdown != NULL)
-        engine.demoShutdown(&engine);
-
-    if (initSDL)
-        SDL_Quit();
-
-    if (engine.demoQuit != NULL)
-        engine.demoQuit(&engine);
-    
-    return 0;
-}
--- a/dmstring.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-#include "dmlib.h"
-#include <stdarg.h>
-
-/* Implementation of strdup() with a NULL check
- */
-char *dm_strdup(const char *s)
-{
-    char *res;
-    if (s == NULL)
-        return NULL;
-
-    if ((res = dmMalloc(strlen(s) + 1)) == NULL)
-        return NULL;
-
-    strcpy(res, s);
-    return res;
-}
-
-
-/* Implementation of strndup() with NULL check
- */
-char *dm_strndup(const char *s, const size_t n)
-{
-    char *res;
-    if (s == NULL)
-        return NULL;
-
-    size_t len = strlen(s);
-    if (len > n)
-        len = n;
-
-    if ((res = dmMalloc(len + 1)) == NULL)
-        return NULL;
-
-    memcpy(res, s, len);
-    res[len] = 0;
-
-    return res;
-}
-
-
-/* Simulate a sprintf() that allocates memory
- */
-char *dm_strdup_vprintf(const char *fmt, va_list args)
-{
-    int size = 64;
-    char *buf;
-
-    if ((buf = dmMalloc(size)) == NULL)
-        return NULL;
-
-    while (1)
-    {
-        int n;
-        va_list ap;
-        va_copy(ap, args);
-        n = vsnprintf(buf, size, fmt, ap);
-        va_end(ap);
-
-        if (n > -1 && n < size)
-            return buf;
-        if (n > -1)
-            size = n + 1;
-        else
-            size *= 2;
-
-        if ((buf = dmRealloc(buf, size)) == NULL)
-            return NULL;
-    }
-}
-
-
-char *dm_strdup_printf(const char *fmt, ...)
-{
-    char *res;
-    va_list ap;
-
-    va_start(ap, fmt);
-    res = dm_strdup_vprintf(fmt, ap);
-    va_end(ap);
-
-    return res;
-}
--- a/dmtext.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-/*
- * DMLib
- * -- Bitmap font support
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012 Tecnic Software productions (TNSP)
- */
-#ifndef DMFONT_H
-#define DMFONT_H
-
-#include "dmlib.h"
-#include "dmres.h"
-
-#ifdef DM_GFX_TTF_TEXT
-#include <SDL_ttf.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Bitmapped fonts and text
- */
-#ifdef DM_GFX_BM_TEXT
-
-// DMFONT format constants
-#define DMFONT_MAGIC         "DMFONT"
-#define DMFONT_VERSION       0x0100
-
-#define DMFONT_MIN_WIDTH     3
-#define DMFONT_MIN_HEIGHT    3
-#define DMFONT_MAX_WIDTH     128
-#define DMFONT_MAX_HEIGHT    128
-#define DMFONT_MAX_GLYPHS    1024
-
-#define DMFONT_NPALETTE      256
-
-// Legacy TSFONT loading support
-#define TSFONT_MAGIC         "TSFONT"
-#define TSFONT_VERSION       0x0205
-
-
-typedef struct
-{
-    int width, height;     // Dimensions
-    int nglyphs;           // Size of glyphs array
-    SDL_Surface **glyphs;  // NOTE! Not all glyphs may be allocated
-} DMBitmapFont;
-
-
-DMBitmapFont *dmNewBitmapFont(int nglyphs, int width, int height);
-int dmFreeBitmapFont(DMBitmapFont *font);
-int dmLoadBitmapFont(DMResource *res, DMBitmapFont **pfont);
-int dmSaveBitmapFont(DMResource *res, DMBitmapFont *font);
-int dmSetBitmapFontPalette(DMBitmapFont *font, SDL_Color *pal, int start, int size);
-
-void dmDrawBMTextConst(SDL_Surface *screen, DMBitmapFont *font, BOOL condensed, int mode, int xc, int yc, const char *str);
-void dmDrawBMTextVA(SDL_Surface *screen, DMBitmapFont *font, BOOL condensed, int mode, int xc, int yc, const char *fmt, va_list ap);
-void dmDrawBMText(SDL_Surface *screen, DMBitmapFont *font, BOOL condensed, int mode, int xc, int yc, const char *fmt, ...);
-
-
-static inline SDL_Surface *dmGetBMGlyph(DMBitmapFont *font, int ch)
-{
-    if (ch < 0 || ch >= font->nglyphs || ch == '\n' || ch == '\r')
-        ch = 32;
-
-    return font->glyphs[ch];
-}
-#endif
-
-
-/* TTF text drawing
- */
-#ifdef DM_GFX_TTF_TEXT
-void dmDrawTTFTextConst(SDL_Surface *screen, TTF_Font *font, SDL_Color col, int x, int y, const char *fmt);
-void dmDrawTTFTextVA(SDL_Surface *screen, TTF_Font *font, SDL_Color col, int x, int y, const char *fmt, va_list ap);
-void dmDrawTTFText(SDL_Surface *screen, TTF_Font *font, SDL_Color col, int x, int y, const char *fmt, ...);
-#endif
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // DMFONT_H
--- a/dmtext_bm.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,295 +0,0 @@
-/*
- * DMLib
- * -- Bitmap and TTF text & font support
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012 Tecnic Software productions (TNSP)
- */
-#include "dmtext.h"
-
-
-void dmDrawBMTextConst(SDL_Surface *screen, DMBitmapFont *font, BOOL condensed, int mode, int xc, int yc, const char *fmt)
-{
-    const char *ptr = fmt;
-    DMUnscaledBlitFunc blit = NULL;
-
-    while (*ptr)
-    {
-        int ch = *ptr++;
-        SDL_Surface *glyph;
-
-        if (ch >= 0 && ch < font->nglyphs && (glyph = font->glyphs[ch]) != NULL)
-        {
-            if (blit == NULL)
-                blit = dmGetUnscaledBlitFunc(glyph->format, screen->format, mode);
-            
-            blit(glyph, xc, yc, screen);
-
-            xc += condensed ? glyph->w : font->width;
-        }
-        else
-            xc += font->width;
-    }
-}
-
-
-void dmDrawBMTextVA(SDL_Surface *screen, DMBitmapFont *font, BOOL condensed, int mode, int xc, int yc, const char *fmt, va_list ap)
-{
-    char tmp[512];
-    vsnprintf(tmp, sizeof(tmp), fmt, ap);
-    dmDrawBMTextConst(screen, font, condensed, mode, xc, yc, tmp);
-    dmFree(tmp);
-}
-
-
-void dmDrawBMText(SDL_Surface *screen, DMBitmapFont *font, BOOL condensed, int mode, int xc, int yc, const char *fmt, ...)
-{
-    va_list ap;
-    
-    va_start(ap, fmt);
-    dmDrawBMTextVA(screen, font, condensed, mode, xc, yc, fmt, ap);
-    va_end(ap);
-}
-
-
-DMBitmapFont *dmNewBitmapFont(int nglyphs, int width, int height)
-{
-    DMBitmapFont *font = dmMalloc0(sizeof(DMBitmapFont));
-    if (font == NULL)
-        return NULL;
-    
-    font->width = width;
-    font->height = height;
-    font->nglyphs = nglyphs;
-    font->glyphs = dmCalloc(nglyphs, sizeof(SDL_Surface *));
-    if (font->glyphs == NULL)
-    {
-        dmFree(font);
-        return NULL;
-    }
-
-    return font;
-}
-
-
-int dmFreeBitmapFont(DMBitmapFont *font)
-{
-    int i;
-
-    if (font == NULL)
-        return DMERR_NULLPTR;
-    
-    for (i = 0; i < font->nglyphs; i++)
-    {
-        if (font->glyphs[i] != NULL)
-        {
-            SDL_FreeSurface(font->glyphs[i]);
-            font->glyphs[i] = NULL;
-        }
-    }
-
-    dmFree(font);
-    return DMERR_OK;
-}
-
-
-/* Set the palette for each glyph. While the function allows you to
- * specify 'start' and 'end' indices and palette array freely, you should
- * typically use DMFONT_NPALETTE size palette starting at index 0.
- */
-int dmSetBitmapFontPalette(DMBitmapFont *font, SDL_Color *pal, int start, int size)
-{
-    int i;
-
-    if (font == NULL)
-        return DMERR_NULLPTR;
-    
-    if (start < 0 || size < 1)
-        return DMERR_INVALID_ARGS;
-    
-    for (i = 0; i < font->nglyphs; i++)
-    {
-        SDL_Surface *glyph = font->glyphs[i];
-        if (glyph != NULL)
-        {
-            SDL_SetColors(glyph, pal, start, size);
-        }
-    }
-
-    return DMERR_OK;
-}
-
-//#define FN_DEBUG
-
-int dmLoadBitmapFont(DMResource *res, DMBitmapFont **pfont)
-{
-    DMBitmapFont *font;
-    char magic[8];
-    Uint16 version, nglyphs, maxglyph;
-    int width, height;
-    BOOL tsfont = FALSE;
-    
-    // Check magic and version
-    dmf_read_str(res, (Uint8 *) &magic, 6);
-    dmf_read_le16(res, &version);
-    
-    // Check if it is a legacy TSFONT file
-    if (memcmp(magic, TSFONT_MAGIC, 6) == 0)
-    {
-        // Yep, we handle these a bit differently
-        int encoding = dmfgetc(res);
-        tsfont = TRUE;
-
-        if (version > TSFONT_VERSION)
-            return DMERR_VERSION;
-
-#ifdef FN_DEBUG
-        fprintf(stderr, "TSFONT v%d.%d (0x%04x), encoding=%d\n", version >> 8, version & 0xff, version, encoding);
-#endif
-        
-        // There were only two encodings, 0 = none and 1 = RLE
-        // of which RLE was never actually used ... derp.
-        if (encoding != 0)
-            return DMERR_NOT_SUPPORTED;
-    }
-    else
-    {
-        if (memcmp(magic, DMFONT_MAGIC, 6) != 0)
-            return DMERR_INVALID;
-
-        if (version > DMFONT_VERSION)
-            return DMERR_VERSION;
-    }
-    
-    // Read other header data
-    if (tsfont)
-    {
-        // TSFONT only has number of glyphs stored in the file
-        nglyphs = dmfgetc(res);
-        
-        // Maximum glyph number
-        maxglyph = 256;
-    }
-    else
-    {
-        dmf_read_le16(res, &nglyphs);
-        dmf_read_le16(res, &maxglyph);
-    }
-    
-    width = dmfgetc(res);
-    height = dmfgetc(res);
-
-#ifdef FN_DEBUG
-    fprintf(stderr, "nglyphs=%d (0x%02x), maxglyph=%d (0x%02x) width=%d, height=%d\n",
-        nglyphs, nglyphs, maxglyph, maxglyph, width, height);
-#endif
-
-    if (tsfont)
-    {
-        // TSFONT color assignments (boolean) .. we discard this.
-        dmfgetc(res);
-        
-        // Very old TSFONTs have some extra data that is not used
-        // .. can't actually even remember what it was for.
-        if (version == 0x0200)
-        {
-            int i;
-            for (i = 0; i < 32; i++)
-                dmfgetc(res);
-        }
-    }
-
-    if (width < DMFONT_MIN_WIDTH ||
-        height < DMFONT_MIN_HEIGHT ||
-        width > DMFONT_MAX_WIDTH ||
-        height > DMFONT_MAX_HEIGHT ||
-        nglyphs > DMFONT_MAX_GLYPHS ||
-        maxglyph > DMFONT_MAX_GLYPHS ||
-        maxglyph < 1)
-        return DMERR_INVALID_DATA;
-
-    // Allocate font
-    if ((*pfont = font = dmNewBitmapFont(maxglyph, width, height)) == NULL)
-        return DMERR_MALLOC;
-
-    // Read glyph data, if any
-    if (nglyphs > 0)
-    {
-        int n, i;
-        Uint32 BitsPerPixel, Rmask, Gmask, Bmask, Amask;
-        SDL_Color pal[DMFONT_NPALETTE];
-
-        // Setup palette for 8bpp fonts
-        for (n = 0; n < DMFONT_NPALETTE; n++)
-        {
-            pal[n].r = pal[n].g = pal[n].b = 0;
-            pal[n].unused = n > 0 ? 255 : 0;
-        }
-
-        if (tsfont)
-        {
-            BitsPerPixel = 8;
-            Rmask = Gmask = Bmask = Amask = 0;
-        }
-        else
-        {
-            BitsPerPixel = dmfgetc(res);
-            dmf_read_le32(res, &Rmask);
-            dmf_read_le32(res, &Gmask);
-            dmf_read_le32(res, &Bmask);
-            dmf_read_le32(res, &Amask);
-        }
-
-        for (i = 0; i < nglyphs; i++)
-        {
-            int y;
-            Uint16 index;
-            Uint8 *pixels;
-            SDL_Surface *glyph;
-
-            // TSFONT format has only byte sized index
-            if (tsfont)
-                index = dmfgetc(res);
-            else
-                dmf_read_le16(res, &index);
-
-            // Read dimensions
-            width = dmfgetc(res);
-            height = dmfgetc(res);
-
-#ifdef FN_DEBUG
-            fprintf(stderr, "#%d @ %d - w=%d, h=%d\n", i, index, width, height);
-#endif
-
-            if (width < DMFONT_MIN_WIDTH ||
-                height < DMFONT_MIN_HEIGHT ||
-                width > DMFONT_MAX_WIDTH ||
-                height > DMFONT_MAX_HEIGHT ||
-                index >= maxglyph)
-                return DMERR_INVALID_DATA;
-
-            // Allocate bitmap
-            font->glyphs[index] = glyph = SDL_CreateRGBSurface(
-                SDL_SWSURFACE, width, height,
-                BitsPerPixel, Rmask, Gmask,
-                Bmask,
-                Amask);
-
-            if (glyph == NULL)
-                return DMERR_MALLOC;
-
-            if (BitsPerPixel == 8)
-                SDL_SetColors(glyph, pal, 0, DMFONT_NPALETTE);
-
-            // Read pixel data
-            pixels = glyph->pixels;
-            for (y = 0; y < glyph->h; y++)
-            {
-                if (dmfread(pixels, glyph->format->BytesPerPixel, glyph->w, res) != (size_t) glyph->w)
-                    return DMERR_FREAD;
-                pixels += glyph->pitch;
-            }
-        }
-    }
-
-    return DMERR_OK;
-}
--- a/dmtext_ttf.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * DMLib
- * -- Bitmap and TTF text & font support
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012 Tecnic Software productions (TNSP)
- */
-#include "dmtext.h"
-
-
-void dmDrawTTFTextConst(SDL_Surface *screen, TTF_Font *font, SDL_Color col, int xc, int yc, const char *fmt)
-{
-    SDL_Surface *text = TTF_RenderText_Blended(font, fmt, col);
-    if (text)
-    {
-        SDL_Rect rect;
-        rect.x = xc;
-        rect.y = yc;
-        rect.w = text->w;
-        rect.h = text->h;
-        SDL_BlitSurface(text, NULL, screen, &rect);
-        SDL_FreeSurface(text);
-    }
-}
-
-void dmDrawTTFTextVA(SDL_Surface *screen, TTF_Font *font, SDL_Color col, int xc, int yc, const char *fmt, va_list ap)
-{
-    char *tmp = dm_strdup_vprintf(fmt, ap);
-    if (tmp != NULL)
-    {
-        dmDrawTTFTextConst(screen, font, col, xc, yc, tmp);
-        dmFree(tmp);
-    }
-}
-
-void dmDrawTTFText(SDL_Surface *screen, TTF_Font *font, SDL_Color col, int xc, int yc, const char *fmt, ...)
-{
-    va_list ap;
-    
-    va_start(ap, fmt);
-    dmDrawTTFTextVA(screen, font, col, xc, yc, fmt, ap);
-    va_end(ap);
-}
--- a/dmtimeline.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,434 +0,0 @@
-/*
- * dmlib
- * -- Timeline file loading and timeline processing/execution
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012-2013 Tecnic Software productions (TNSP)
- */
-#include "dmengine.h"
-
-
-static BOOL dmLoadFloatValue(DMResource *res, DMFloat *val)
-{
-    char tmp[DT_FLOAT_STORE_SIZE + 1];
-    if (!dmf_read_str(res, &tmp, DT_FLOAT_STORE_SIZE))
-        return FALSE;
-
-    tmp[DT_FLOAT_STORE_SIZE] = 0;
-    *val = atof(tmp);
-    return TRUE;
-}
-
-
-static int dmLoadTimelinePoints(DMResource *res, DMTimelinePoints *points, int type)
-{
-    int point;
-    Uint32 npoints;
-
-    // Get number of points
-    if (!dmf_read_le32(res, &npoints))
-        return DMERR_FREAD;
-
-    // Calculate and allocate space
-    points->npoints = npoints;
-    points->nallocated = ((npoints / 16) + 1) * 16;
-    
-    points->points = dmCalloc(points->nallocated, sizeof(DMTimelinePoint));
-    if (points->points == NULL)
-        return DMERR_MALLOC;
-    
-    // Read points
-    for (point = 0; point < points->npoints; point++)
-    {
-        DMTimelinePoint *pt = &(points->points[point]);
-        Uint32 ptype, ptime;
-        if (!dmf_read_le32(res, &ptype) ||
-            !dmf_read_le32(res, &ptime))
-            return DMERR_FREAD;
-        
-        switch (type)
-        {
-            case EFPT_INT:
-                {
-                    Uint32 tmp;
-                    if (!dmf_read_le32(res, &tmp))
-                        return DMERR_FREAD;
-                    pt->vint = tmp;
-                }
-                break;
-
-            case EFPT_FLOAT:
-                if (!dmLoadFloatValue(res, &pt->vfloat))
-                    return DMERR_FREAD;
-                break;
-            
-            case EFPT_VECTOR:
-                if (!dmLoadFloatValue(res, &pt->vector.x) ||
-                    !dmLoadFloatValue(res, &pt->vector.y) ||
-                    !dmLoadFloatValue(res, &pt->vector.z) ||
-                    !dmLoadFloatValue(res, &pt->vector.W))
-                    return DMERR_FREAD;
-                break;
-
-            case EFPT_MATRIX:
-                {
-                    int x, y;
-                    for (y = 0; y < DM_MATRIX_SIZE; y++)
-                    for (x = 0; x < DM_MATRIX_SIZE; x++)
-                    {
-                        if (!dmLoadFloatValue(res, &(pt->matrix.m[y][x])))
-                            return DMERR_FREAD;
-                    }
-                }
-                break;
-        }
-        
-        pt->type = ptype;
-        pt->time = ptime;
-    }
-    return DMERR_OK;
-}
-
-
-static int dmLoadTimelineEventParam(DMResource *res, DMTimelineEventParam *param)
-{
-    int err;
-    DMFTimelineEventParam hdr;
-    Uint16 len;
-
-    if (!dmf_read_str(res, &hdr.name, sizeof(hdr.name)) ||
-        !dmf_read_le32(res, &hdr.type))
-        return DMERR_FREAD;
-
-    hdr.name[sizeof(hdr.name) - 1] = 0;
-
-    param->name = dm_strdup(hdr.name);
-    param->type = hdr.type;
-
-    switch (param->type)
-    {
-        case EFPT_INT:
-        case EFPT_FLOAT:
-        case EFPT_VECTOR:
-        case EFPT_MATRIX:
-            if ((err = dmLoadTimelinePoints(res, &param->pts, param->type)) != DMERR_OK)
-                return err;
-            break;
-
-        case EFPT_STRING:
-            if (!dmf_read_le16(res, &len))
-                return DMERR_FREAD;
-
-            param->vstr = dmMalloc((unsigned int)len + 1);
-            if (!dmf_read_str(res, param->vstr, len))
-                return DMERR_FREAD;
-
-            param->vstr[len] = 0;
-            break;
-    }
-
-    return DMERR_OK;
-}
-
-
-static int dmLoadTimelineEvent(DMResource *res, DMTimelineEvent **pevent)
-{
-    int param;
-    DMFTimelineEvent hdr;
-    DMTimelineEvent *event;
-    if ((*pevent = event = dmMalloc0(sizeof(DMTimelineEvent))) == NULL)
-        return DMERR_MALLOC;
-
-    // Get basic event data
-    if (!dmf_read_le32(res, &hdr.start) ||
-        !dmf_read_le32(res, &hdr.duration) ||
-        !dmf_read_str(res, &hdr.effectName, sizeof(hdr.effectName)) ||
-        !dmf_read_le32(res, &hdr.nparams))
-        return DMERR_FREAD;
-
-    hdr.effectName[sizeof(hdr.effectName) - 1] = 0;
-    
-    if (hdr.nparams > DT_MAX_EFFECT_PARAMS)
-    {
-        dmError("Invalid number of parameters, %d > %d ('%s' @ %d:%d)\n",
-            hdr.nparams, DT_MAX_EFFECT_PARAMS, hdr.effectName, hdr.start, hdr.duration);
-        return DMERR_INVALID_DATA;
-    }
-
-    event->start     = hdr.start;
-    event->duration  = hdr.duration;
-    event->nparams   = hdr.nparams;
-    event->effect    = engineFindEffect(hdr.effectName, hdr.nparams);
-    if (event->effect == NULL)
-    {
-        dmError("No matching registered effect found for '%s'.\n", hdr.effectName);
-        return DMERR_INVALID_DATA;
-    }
-
-    event->params    = dmCalloc(event->nparams, sizeof(DMTimelineEventParam));
-    if (event->params == NULL)
-    {
-        dmError("Could not allocate memory for timeline event parameters.\n");
-        return DMERR_MALLOC;
-    }
-
-    for (param = 0; param < event->nparams; param++)
-    {
-        int err;
-        if ((err = dmLoadTimelineEventParam(res, &(event->params[param]))) != DMERR_OK)
-            return err;
-    }
-
-    return DMERR_OK;
-}
-
-
-static int dmLoadTimelineCurve(DMResource *res, DMTimelineCurve *curve)
-{
-    int err;
-
-    curve->enabled = dmfgetc(res);
-    if ((err = dmLoadTimelinePoints(res, &(curve->points), EFPT_FLOAT)) != DMERR_OK)
-        return err;
-    
-    return DMERR_OK;
-}
-
-
-static int dmLoadTimelineTrack(DMResource *res, DMTimelineTrack **ptrack)
-{
-    int event, err;
-    DMFTimelineTrack hdr;
-    DMTimelineTrack *track;
-    if ((*ptrack = track = dmMalloc0(sizeof(DMTimelineTrack))) == NULL)
-        return DMERR_MALLOC;
-
-    if (!dmf_read_le32(res, &hdr.index) ||
-        !dmf_read_le32(res, &hdr.layer) ||
-        !dmf_read_str(res, &hdr.name, sizeof(hdr.name)) ||
-        !dmf_read_byte(res, &hdr.enabled) ||
-        !dmf_read_le32(res, &hdr.nevents))
-        return DMERR_FREAD;
-
-    if (hdr.nevents >= 4096)
-        return DMERR_INVALID_DATA;
-
-    if ((track->events = dmCalloc(hdr.nevents, sizeof(DMTimelineEvent *))) == NULL)
-        return DMERR_MALLOC;
-
-    hdr.name[sizeof(hdr.name) - 1] = 0;
-    track->name    = dm_strdup(hdr.name);
-    track->enabled = hdr.enabled;
-    track->nevents = hdr.nevents;
-
-    for (event = 0; event < track->nevents; event++)
-    {
-        if ((err = dmLoadTimelineEvent(res, &(track->events[event]))) != DMERR_OK)
-            return err;
-    }
-
-    if ((err = dmLoadTimelineCurve(res, &(track->composite))) != DMERR_OK)
-        return err;
-
-    return DMERR_OK;
-}
-
-
-int dmLoadTimeline(DMResource *res, DMTimeline **ptl)
-{
-    int track, err;
-    DMFTimeline hdr;
-    DMTimeline *tl;
-    if ((*ptl = tl = dmMalloc0(sizeof(DMTimeline))) == NULL)
-        return DMERR_MALLOC;
-
-    // Read and check header
-    if (!dmf_read_str(res, &hdr.magic, sizeof(hdr.magic)))
-        return DMERR_FREAD;
-
-    if (memcmp(hdr.magic, DT_MAGIC_ID, sizeof(hdr.magic)) != 0)
-        return DMERR_INVALID_DATA;
-
-    if (!dmf_read_str(res, &hdr.name, sizeof(hdr.name)) ||
-        !dmf_read_le32(res, &hdr.ntracks) ||
-        !dmf_read_le32(res, &hdr.duration))
-        return DMERR_FREAD;
-
-    if (hdr.ntracks >= 64)
-        return DMERR_INVALID_DATA;
-
-    // Allocate track pointers
-    tl->tracks = (DMTimelineTrack **) dmCalloc(hdr.ntracks, sizeof(DMTimelineTrack *));
-    if (tl->tracks == NULL)
-        return DMERR_MALLOC;
-
-    // Copy rest
-    hdr.name[sizeof(hdr.name) - 1] = 0;
-    tl->name     = dm_strdup(hdr.name);
-    tl->duration = hdr.duration;
-    tl->ntracks  = hdr.ntracks;
-
-    // Read tracks
-    for (track = 0; track < tl->ntracks; track++)
-    {
-        if ((err = dmLoadTimelineTrack(res, &(tl->tracks[track]))) != DMERR_OK)
-            return err;
-    }
-    
-    return DMERR_OK;
-}
-
-
-void dmFreeTimelinePoints(DMTimelinePoints *points)
-{
-    dmFree(points->points);
-    points->points = NULL;
-    points->npoints = points->nallocated = 0;
-}
-
-
-void dmFreeTimelineEventParam(DMTimelineEventParam *param)
-{
-    dmFree(param->name);
-    dmFree(param->vstr);
-    dmFreeTimelinePoints(&(param->pts));
-}
-
-
-void dmFreeTimelineEvent(DMTimelineEvent *event)
-{
-    if (event != NULL)
-    {
-        int param;
-        for (param = 0; param < event->nparams; param++)
-            dmFreeTimelineEventParam(&(event->params[param]));
-        dmFree(event->params);
-    }
-}
-
-
-void dmFreeTimelineTrack(DMTimelineTrack *track)
-{
-    if (track != NULL)
-    {
-        int event;
-
-        dmFree(track->name);
-
-        for (event = 0; event < track->nevents; event++)
-            dmFreeTimelineEvent(track->events[event]);
-        dmFree(track->events);
-
-        dmFreeTimelinePoints(&(track->composite.points));
-    }
-}
-
-
-void dmFreeTimeline(DMTimeline *tl)
-{
-    if (tl != NULL)
-    {
-        int i;
-        for (i = 0; i < tl->ntracks; i++)
-            dmFreeTimelineTrack(tl->tracks[i]);
-
-        dmFree(tl->tracks);
-        dmFree(tl->name);
-    }
-}
-
-
-static void dmFreePreparedEventGroup(DMPreparedEventGroup *group)
-{
-    if (group != NULL)
-    {
-        dmFree(group->events);
-        dmFree(group);
-    }
-}
-
-
-void dmFreePreparedTimelineData(DMPreparedTimeline *ptl)
-{
-    if (ptl != NULL)
-    {
-        int group;
-        for (group = 0; group < ptl->ngroups; group++)
-        {
-            dmFreePreparedEventGroup(ptl->groups[group]);
-            ptl->groups[group] = NULL;
-        }
-
-        dmFree(ptl->groups);
-        ptl->groups = NULL;
-    }
-}
-
-
-/* Prepare a loaded timeline for execution. Creates the "stacked" structure
- * of timeline data for efficient rendering.
- */
-int dmAddSplitPreparedEventGroup(DMPreparedEventGroup **groups, DMTimelineTrack *track, DMTimelineEvent *event)
-{
-    DMPreparedEventGroup *node;
-    
-    for (node = *groups; node != NULL; node = node->next)
-    {
-    }
-    
-    return DMERR_OK;
-}
-
-
-int dmPrepareTimeline(DMTimeline *tl, DMPreparedTimeline *ptl)
-{
-    int group, ntrack, event, err;
-    DMPreparedEventGroup *groups = NULL, *node;
-
-    // Free previous data
-    dmFreePreparedTimelineData(ptl);
-
-    // Process tracks
-    for (ntrack = 0; ntrack < tl->ntracks; ntrack++)
-    {
-        DMTimelineTrack *track = tl->tracks[ntrack];
-        for (event = 0; event < track->nevents; event++)
-        {
-            if ((err = dmAddSplitPreparedEventGroup(&groups, track, track->events[event])) != DMERR_OK)
-                return err;
-        }
-    }
-    
-    // Compute number of groups
-    ptl->ngroups = 0;
-    for (node = groups; node != NULL; node = node->next)
-        ptl->ngroups++;
-
-    // Allocate linear array for fast access
-    ptl->groups = dmMalloc(sizeof(DMPreparedEventGroup) * ptl->ngroups);
-    if (ptl->groups == NULL)
-        return DMERR_MALLOC;
-
-    // Store pointers in the array
-    for (group = 0, node = groups; node != NULL; node = node->next)
-        ptl->groups[group++] = node;
-    
-    return DMERR_OK;
-}
-
-
-/* Seeks to specified position in the timeline. The execution function
- * only handles monotonously increasing time, going backwards will not work
- * there correctly, thus to seek freely this function must be used.
- */
-int dmSeekTimeline(DMPreparedTimeline *tl, int time)
-{
-    return DMERR_OK;
-}
-
-
-/* "Executes", or rather renders a frame on the specified timeline position.
- */
-int dmExecuteTimeline(DMPreparedTimeline *tl, SDL_Surface *screen, int time)
-{
-    return DMERR_OK;
-}
--- a/dmtimelinew.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,430 +0,0 @@
-/*
- * dmlib
- * -- Timeline file writing
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012-2013 Tecnic Software productions (TNSP)
- */
-#include "dmengine.h"
-#include "dmresw.h"
-
-
-static BOOL dmSaveFloatValue(DMResource *res, DMFloat val)
-{
-    char tmp[DT_FLOAT_STORE_SIZE];
-    snprintf(tmp, DT_FLOAT_STORE_SIZE, "%f", val);
-    return !dmf_write_str(res, tmp, DT_FLOAT_STORE_SIZE);
-}
-
-
-static int dmSaveTimelinePoints(DMResource *res, DMTimelinePoints *points, int type)
-{
-    int point;
-    Uint32 npoints;
-
-    // Save number of points
-    npoints = points->npoints;
-    if (!dmf_write_le32(res, npoints))
-        return DMERR_FWRITE;
-    
-    // Save points
-    for (point = 0; point < points->npoints; point++)
-    {
-        DMTimelinePoint *pt = &(points->points[point]);
-        Uint32 ptype, ptime;
-        ptype = pt->type;
-        ptime = pt->time;
-        if (!dmf_write_le32(res, ptype) ||
-            !dmf_write_le32(res, ptime))
-            return DMERR_FWRITE;
-
-        switch (type)
-        {
-            case EFPT_INT:
-                if (!dmf_write_le32(res, pt->vint))
-                    return DMERR_FWRITE;
-                break;
-
-            case EFPT_FLOAT:
-                if (!dmSaveFloatValue(res, pt->vfloat))
-                    return DMERR_FWRITE;
-                break;
-            
-            case EFPT_VECTOR:
-                if (!dmSaveFloatValue(res, pt->vector.x) ||
-                    !dmSaveFloatValue(res, pt->vector.y) ||
-                    !dmSaveFloatValue(res, pt->vector.z) ||
-                    !dmSaveFloatValue(res, pt->vector.W))
-                    return DMERR_FWRITE;
-                break;
-
-            case EFPT_MATRIX:
-                {
-                    int x, y;
-                    for (y = 0; y < DM_MATRIX_SIZE; y++)
-                    for (x = 0; x < DM_MATRIX_SIZE; x++)
-                    {
-                        if (!dmSaveFloatValue(res, pt->matrix.m[y][x]))
-                            return DMERR_FWRITE;
-                    }
-                }
-                break;
-        }
-    }
-    return DMERR_OK;
-}
-
-
-static int dmSaveTimelineCurve(DMResource *res, DMTimelineCurve *curve)
-{
-    int err;
-
-    if (!dmf_write_byte(res, curve->enabled))
-        return DMERR_FWRITE;
-
-    if ((err = dmSaveTimelinePoints(res, &(curve->points), EFPT_FLOAT)) != DMERR_OK)
-        return err;
-    
-    return DMERR_OK;
-}
-
-
-static int dmSaveTimelineEventParam(DMResource *res, DMTimelineEventParam *param)
-{
-    int err;
-    DMFTimelineEventParam hdr;
-    Uint16 len;
-
-    strncpy(hdr.name, param->name, sizeof(hdr.name));
-    hdr.type = param->type;
-
-    if (!dmf_write_str(res, hdr.name, sizeof(hdr.name)) ||
-        !dmf_write_le32(res, hdr.type))
-        return DMERR_FWRITE;
-
-    switch (param->type)
-    {
-        case EFPT_INT:
-        case EFPT_FLOAT:
-        case EFPT_VECTOR:
-        case EFPT_MATRIX:
-            if ((err = dmSaveTimelinePoints(res, &param->pts, param->type)) != DMERR_OK)
-                return err;
-            break;
-
-        case EFPT_STRING:
-            len = strlen(param->vstr);
-            if (!dmf_write_le16(res, len))
-                return DMERR_FWRITE;
-
-            if (!dmf_write_str(res, param->vstr, len))
-                return DMERR_FWRITE;
-            break;
-    }
-
-    return DMERR_OK;
-}
-
-
-static int dmSaveTimelineEvent(DMResource *res, DMTimelineEvent *event)
-{
-    int param, err;
-    DMFTimelineEvent hdr;
-
-    strncpy(hdr.effectName, event->effect->name, sizeof(hdr.effectName));
-    hdr.start    = event->start;
-    hdr.duration = event->duration;
-    hdr.nparams  = event->nparams;
-
-    if (!dmf_write_le32(res, hdr.start) ||
-        !dmf_write_le32(res, hdr.duration) ||
-        !dmf_write_str(res, hdr.effectName, sizeof(hdr.effectName)) ||
-        !dmf_write_le32(res, hdr.nparams))
-        return DMERR_FWRITE;
-
-    for (param = 0; param < event->nparams; param++)
-    {
-        if ((err = dmSaveTimelineEventParam(res, &(event->params[param]))) != DMERR_OK)
-            return err;
-    }
-
-    return DMERR_OK;
-}
-
-
-static int dmSaveTimelineTrack(DMResource *res, DMTimelineTrack *track)
-{
-    int event, err;
-    DMFTimelineTrack hdr;
-    
-    strncpy(hdr.name, track->name, sizeof(hdr.name));
-
-    if (!dmf_write_le32(res, track->index) ||
-        !dmf_write_le32(res, track->layer) ||
-        !dmf_write_str(res, hdr.name, sizeof(hdr.name)) ||
-        !dmf_write_byte(res, track->enabled) ||
-        !dmf_write_le32(res, track->nevents))
-        return DMERR_FWRITE;
-
-    for (event = 0; event < track->nevents; event++)
-    {
-        if ((err = dmSaveTimelineEvent(res, track->events[event])) != DMERR_OK)
-            return err;
-    }
-
-    if ((err = dmSaveTimelineCurve(res, &(track->composite))) != DMERR_OK)
-        return err;
-
-    return DMERR_OK;
-}
-
-
-int dmSaveTimeline(DMResource *res, DMTimeline *tl)
-{
-    int track, err;
-    DMFTimeline hdr;
-
-    memcpy(&hdr.magic, DT_MAGIC_ID, sizeof(hdr.magic));
-    strncpy(hdr.name, tl->name, sizeof(hdr.name));
-    hdr.ntracks = tl->ntracks;
-    hdr.duration = tl->duration;
-    
-    if (!dmf_write_str(res, hdr.magic, sizeof(hdr.magic)) ||
-        !dmf_write_str(res, hdr.name, sizeof(hdr.name)) ||
-        !dmf_write_le32(res, hdr.ntracks) ||
-        !dmf_write_le32(res, hdr.duration))
-        return DMERR_FWRITE;
-
-    for (track = 0; track < tl->ntracks; track++)
-    {
-        if ((err = dmSaveTimelineTrack(res, tl->tracks[track])) != DMERR_OK)
-            return err;
-    }
-
-    return DMERR_OK;
-}
-
-
-int dmTimelineNew(DMTimeline **ptl, const char *name)
-{
-    DMTimeline *tl;
-    if ((*ptl = tl = dmMalloc0(sizeof(DMTimeline))) == NULL)
-        return DMERR_MALLOC;
-
-    tl->name = dm_strdup(name);
-    
-    return DMERR_OK;
-}
-
-
-int dmTimelineAddTrack(DMTimeline *tl, DMTimelineTrack **ptrack, const char *name)
-{
-    DMTimelineTrack *track;
-    
-    if ((*ptrack = track = dmMalloc0(sizeof(DMTimelineTrack))) == NULL)
-        return DMERR_MALLOC;
-    
-    track->name = dm_strdup(name);
-    track->enabled = TRUE;
-
-    if (tl->ntracks + 1 >= tl->nallocated)
-    {
-        tl->nallocated += 16;
-        tl->tracks = dmRealloc(tl->tracks, sizeof(DMTimelineTrack *) * tl->nallocated);
-        if (tl->tracks == NULL)
-            return DMERR_MALLOC;
-    }
-    
-    tl->tracks[tl->ntracks] = track;
-    tl->ntracks++;
-    
-    return DMERR_OK;
-}
-
-
-int dmTimelineTrackAddEvent(DMTimelineTrack *track, int start, int duration, DMTimelineEvent **pev)
-{
-    DMTimelineEvent *ev;
-    
-    if ((*pev = ev = dmMalloc0(sizeof(DMTimelineEvent))) == NULL)
-        return DMERR_MALLOC;
-    
-    ev->start    = start;
-    ev->duration = duration;
-    
-    if (track->nevents + 1 >= track->nallocated)
-    {
-        track->nallocated += 16;
-        track->events = dmRealloc(track->events, sizeof(DMTimelineEvent *) * track->nallocated);
-        if (track->events == NULL)
-            return DMERR_MALLOC;
-    }
-    
-    track->events[track->nevents] = ev;
-    track->nevents++;
-    
-    return DMERR_OK;
-}
-
-
-int dmTimelineEventSetEffect(DMTimelineEvent *event, DMEffect *ef)
-{
-    int param;
-    if (ef == NULL)
-        return DMERR_INVALID_DATA;
-
-    event->effect = ef;
-    event->nparams = ef->nparams;
-    event->params = dmCalloc(ef->nparams, sizeof(DMTimelineEventParam));
-    if (event->params == NULL)
-        return DMERR_MALLOC;
-    
-    for (param = 0; param < ef->nparams; param++)
-    {
-        DMTimelineEventParam *psrc = &ef->params[param],
-                             *pdst = &event->params[param];
-
-        pdst->name   = dm_strdup(psrc->name);
-        pdst->type   = psrc->type;
-        pdst->vstr   = dm_strdup(psrc->vstr);
-
-        if (psrc->pts.points != NULL && psrc->pts.npoints > 0)
-        {
-            pdst->pts.npoints    = psrc->pts.npoints;
-            pdst->pts.nallocated = psrc->pts.nallocated;
-            pdst->pts.points     = dmMalloc(psrc->pts.nallocated * sizeof(DMTimelinePoint));
-            if (pdst->pts.points == NULL)
-                return DMERR_MALLOC;
-
-            memcpy(pdst->pts.points, psrc->pts.points, pdst->pts.npoints * sizeof(DMTimelinePoint));
-        }
-    }
-    
-    return DMERR_OK;
-}
-
-
-int dmTimelineEventSetEffectByIndex(DMTimelineEvent *event, const int index)
-{
-    if (index < 0 || index >= nengineEffects)
-        return DMERR_INVALID_DATA;
-
-    return dmTimelineEventSetEffect(event, &engineEffects[index]);
-}
-
-
-int dmTimelineEventSetEffectByName(DMTimelineEvent *event, const char *name)
-{
-    return dmTimelineEventSetEffect(event, engineFindEffectByName(name));
-}
-
-
-int dmCopyTimelinePoints(const DMTimelinePoints *src, DMTimelinePoints *dst)
-{
-    if (src->points == NULL || src->npoints <= 0 || src->nallocated <= 0)
-        return DMERR_OK;
-
-    dst->npoints    = src->npoints;
-    dst->nallocated = src->nallocated;
-    dst->points     = dmCalloc(src->nallocated, sizeof(DMTimelinePoint));
-    if (dst->points == NULL)
-        return DMERR_MALLOC;
-
-    memcpy(dst->points, src->points, sizeof(DMTimelinePoint) * src->npoints);
-    
-    return DMERR_OK;
-}
-
-
-int dmCopyTimelineEventParam(const DMTimelineEventParam *src, DMTimelineEventParam *dst)
-{
-    dst->name = dm_strdup(src->name);
-    dst->type = src->type;
-    dst->vstr = dm_strdup(src->vstr);
-
-    return dmCopyTimelinePoints(&src->pts, &dst->pts);
-}
-
-
-int dmCopyTimelineEvent(const DMTimelineEvent *src, DMTimelineEvent **pdst)
-{
-    int param;
-    DMTimelineEvent *dst;
-    if ((*pdst = dst = dmMalloc0(sizeof(DMTimelineEvent))) == NULL)
-        return DMERR_MALLOC;
-    
-    dst->start     = src->start;
-    dst->duration  = src->duration;
-    dst->nparams   = src->nparams;
-    dst->effect    = src->effect;
-    dst->params    = dmCalloc(src->nparams, sizeof(DMTimelineEventParam));
-    if (dst->params == NULL)
-        return DMERR_MALLOC;
-
-    for (param = 0; param < src->nparams; param++)
-    {
-        int err;
-        if ((err = dmCopyTimelineEventParam(&(src->params[param]), &(dst->params[param]))) != DMERR_OK)
-            return err;
-    }
-
-    return DMERR_OK;
-}
-
-
-int dmCopyTimelineCurve(const DMTimelineCurve *src, DMTimelineCurve *dst)
-{
-    dst->enabled = src->enabled;
-    return dmCopyTimelinePoints(&(src->points), &(dst->points));
-}
-
-
-int dmCopyTimelineTrack(const DMTimelineTrack *src, DMTimelineTrack **pdst)
-{
-    int event, err;
-    DMTimelineTrack *dst;
-    if ((*pdst = dst = dmMalloc0(sizeof(DMTimelineTrack))) == NULL)
-        return DMERR_MALLOC;
-
-    if ((dst->events = dmCalloc(src->nevents, sizeof(DMTimelineEvent *))) == NULL)
-        return DMERR_MALLOC;
-    
-    dst->name    = dm_strdup(src->name);
-    dst->enabled = src->enabled;
-    dst->nevents = src->nevents;
-
-    for (event = 0; event < src->nevents; event++)
-    {
-        if ((err = dmCopyTimelineEvent(src->events[event], &(dst->events[event]))) != DMERR_OK)
-            return err;
-    }
-
-    if ((err = dmCopyTimelineCurve(&(src->composite), &(dst->composite))) != DMERR_OK)
-        return err;
-
-    return DMERR_OK;
-}
-
-
-int dmCopyTimeline(const DMTimeline *src, DMTimeline **pdst)
-{
-    int track, err;
-    DMTimeline *dst;
-    if ((*pdst = dst = dmMalloc0(sizeof(DMTimeline))) == NULL)
-        return DMERR_MALLOC;
-    
-    dst->tracks = (DMTimelineTrack **) dmCalloc(src->ntracks, sizeof(DMTimelineTrack *));
-    if (dst->tracks == NULL)
-        return DMERR_MALLOC;
-
-    dst->name     = dm_strdup(src->name);
-    dst->duration = src->duration;
-    dst->ntracks  = src->ntracks;
-
-    for (track = 0; track < src->ntracks; track++)
-    {
-        if ((err = dmCopyTimelineTrack(src->tracks[track], &(dst->tracks[track]))) != DMERR_OK)
-            return err;
-    }
-    
-    return DMERR_OK;
-}
--- a/dmunscaledblit.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * DMLib
- * -- Unscaled sprite / surface blitting function template
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012 Tecnic Software productions (TNSP)
- */
-
-int DM_BLITFUNC_NAME (SDL_Surface *src,
-    const int x0, const int y0,
-    SDL_Surface *dst
-#ifdef DM_BLITFUNC_ARGS
-    DM_BLITFUNC_ARGS
-#endif
-    )
-#ifdef DM_HEADER
-;
-#else
-{
-    int yc;
-    DMQValue xr, yr;
-#ifdef DM_BLITFUNC_VARS
-    DM_BLITFUNC_VARS
-#endif
-    
-    // Clip coordinates
-    if (dmUnscaledClipCoord(&xr, x0, src->w,
-        dst->clip_rect.x, dst->clip_rect.x + dst->clip_rect.w)
-        ||
-        dmUnscaledClipCoord(&yr, y0, src->h,
-        dst->clip_rect.y, dst->clip_rect.y + dst->clip_rect.h))
-        return -1;
-
-#ifdef DM_BLITFUNC_INIT
-    DM_BLITFUNC_INIT
-#endif
-    const int srcadd = src->pitch / DM_BLITFUNC_SRC_BYTES;
-    const int dstadd = xr.vadd - dst->clip_rect.w + dst->clip_rect.x + (dst->pitch / DM_BLITFUNC_DST_BYTES);
-
-    DM_BLITFUNC_SRC_TYPE * sp = ((DM_BLITFUNC_SRC_TYPE *) src->pixels) + (yr.voffs * src->pitch) / DM_BLITFUNC_SRC_BYTES;
-    DM_BLITFUNC_DST_TYPE * dp = ((DM_BLITFUNC_DST_TYPE *) dst->pixels) + (yr.v0 * dst->pitch) / DM_BLITFUNC_DST_BYTES + xr.v0;
-
-    for (yc = yr.v0; yc < yr.v1; yc++)
-    {
-        int xv, xc;
-
-#ifdef DM_BLITFUNC_INNER_INIT
-        DM_BLITFUNC_INNER_INIT
-#endif
-
-        for (xv = xr.voffs, xc = xr.v0; xc < xr.v1; xc++, xv++)
-        {
-            DM_BLITFUNC_INNER
-        }
-        sp += srcadd;
-        dp += dstadd;
-    }
-
-#ifdef DM_BLITFUNC_FINISH
-    DM_BLITFUNC_FINISH
-#endif
-    return 0;
-}
-#endif
-
-
-#undef DM_BLITFUNC_NAME
-#undef DM_BLITFUNC_ARGS
-#undef DM_BLITFUNC_SRC_BYTES
-#undef DM_BLITFUNC_DST_BYTES
-#undef DM_BLITFUNC_SRC_TYPE
-#undef DM_BLITFUNC_DST_TYPE
-#undef DM_BLITFUNC_VARS
-#undef DM_BLITFUNC_INIT
-#undef DM_BLITFUNC_INNER_INIT
-#undef DM_BLITFUNC_INNER
-#undef DM_BLITFUNC_FINISH
--- a/dmvecmat.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,451 +0,0 @@
-/*
- * DMLib
- * -- Vector and matrix functions
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2011-2012 Tecnic Software productions (TNSP)
- */
-#include "dmvecmat.h"
-
-
-void dm_vector_add_n(DMVector *dst, const DMVector *src, const int nlist)
-{
-    int i;
-    for (i = 0; i < nlist; i++)
-    {
-#ifdef DM_USE_SIMD
-    asm("movups      %2,     %%xmm1\n"
-        "movups      %1,     %%xmm2\n"
-        "addps       %%xmm2, %%xmm1\n"
-        "movups      %%xmm1, %0\n"
-        : "=m" (dst[i])
-        : "m" (dst[i]), "m" (src[i])
-        : "memory", "%xmm1", "%xmm2");
-#else
-        dm_vector_add(dst + i, src + i);
-#endif
-    }
-}
-
-
-void dm_vector_add_r_n(DMVector *dst, const DMVector *src1, const DMVector *src2, const int nlist)
-{
-    int i;
-    for (i = 0; i < nlist; i++)
-    {
-#ifdef DM_USE_SIMD
-    asm("movups      %2,     %%xmm1\n"
-        "movups      %1,     %%xmm2\n"
-        "addps       %%xmm2, %%xmm1\n"
-        "movups      %%xmm1, %0\n"
-        : "=m" (dst[i])
-        : "m" (src1[i]), "m" (src2[i])
-        : "memory", "%xmm1", "%xmm2");
-#else
-        dm_vector_add_r(dst + i, src1 + i, src2 + i);
-#endif
-    }
-}
-
-
-void dm_vector_sub_n(DMVector *dst, const DMVector *src, const int nlist)
-{
-    int i;
-    for (i = 0; i < nlist; i++)
-    {
-#ifdef DM_USE_SIMD
-    asm("movups      %2,     %%xmm1\n"
-        "movups      %1,     %%xmm2\n"
-        "subps       %%xmm2, %%xmm1\n"
-        "movups      %%xmm1, %0\n"
-        : "=m" (dst[i])
-        : "m" (dst[i]), "m" (src[i])
-        : "memory", "%xmm1", "%xmm2");
-#else
-        dm_vector_add(dst + i, src + i);
-#endif
-    }
-}
-
-
-void dm_vector_sub_r_n(DMVector *dst, const DMVector *src1, const DMVector *src2, const int nlist)
-{
-    int i;
-    for (i = 0; i < nlist; i++)
-    {
-#ifdef DM_USE_SIMD
-    asm("movups      %2,     %%xmm1\n"
-        "movups      %1,     %%xmm2\n"
-        "subps       %%xmm2, %%xmm1\n"
-        "movups      %%xmm1, %0\n"
-        : "=m" (dst[i])
-        : "m" (src1[i]), "m" (src2[i])
-        : "memory", "%xmm1", "%xmm2");
-#else
-        dm_vector_sub_r(dst + i, src1 + i, src2 + i);
-#endif
-    }
-}
-
-
-/* Multiply given vector with a matrix
- */
-void dm_vector_mul_by_mat(DMVector *vd, const DMVector *vs, const DMMatrix *mat)
-{
-#ifdef DM_USE_SIMD
-    asm volatile(
-        "mov           %1,        %%edx\n"
-        "movups        (%%edx),   %%xmm4\n"
-        "movups      16(%%edx),   %%xmm5\n"
-        "movups      32(%%edx),   %%xmm6\n"
-        "movups      48(%%edx),   %%xmm7\n"
-
-        // vector -> xmm0
-        "movups      %2,     %%xmm0\n"
-        
-        // zero final result in xmm2
-        "xorps       %%xmm2, %%xmm2\n"
-
-        // perform shuffle and multiply and add whole "column" "X"
-        "movups      %%xmm0, %%xmm1\n"
-        "shufps      $0x00,  %%xmm1, %%xmm1\n"
-        "mulps       %%xmm4, %%xmm1\n"
-        "addps       %%xmm1, %%xmm2\n"
-
-        // Y
-        "movups      %%xmm0, %%xmm1\n"
-        "shufps      $0x55,  %%xmm1, %%xmm1\n"
-        "mulps       %%xmm5, %%xmm1\n"
-        "addps       %%xmm1, %%xmm2\n"
-
-        // Z
-        "movups      %%xmm0, %%xmm1\n"
-        "shufps      $0xAA,  %%xmm1, %%xmm1\n"
-        "mulps       %%xmm6, %%xmm1\n"
-        "addps       %%xmm1, %%xmm2\n"
-
-        // W
-        "movups      %%xmm0, %%xmm1\n"
-        "shufps      $0xFF,  %%xmm1, %%xmm1\n"
-        "mulps       %%xmm7, %%xmm1\n"
-        "addps       %%xmm1, %%xmm2\n"
-
-        // Result ->
-        "movups      %%xmm2, %0\n"
-        : "=m" (vd)
-        : "m" (mat), "m" (vs)
-        : "memory", "%edx", "%xmm0", "%xmm1", "%xmm2", "%xmm4", "%xmm5", "%xmm6", "%xmm7"
-        );
-#else
-    vd->x = (vs->x * mat->m[0][0]) + (vs->y * mat->m[1][0]) + (vs->z * mat->m[2][0]);
-    vd->y = (vs->x * mat->m[0][1]) + (vs->y * mat->m[1][1]) + (vs->z * mat->m[2][1]);
-    vd->z = (vs->x * mat->m[0][2]) + (vs->y * mat->m[1][2]) + (vs->z * mat->m[2][2]);
-#endif
-}
-
-
-/* Multiply list of given vectors with given matrix.
- */
-void dm_vector_mul_by_mat_n(DMVector *list, const int nlist, const DMMatrix *mat)
-{
-    int i;
-
-#ifdef DM_USE_SIMD
-    asm volatile(
-        "mov           %0,        %%edx\n"
-        "movups        (%%edx),   %%xmm4\n"
-        "movups      16(%%edx),   %%xmm5\n"
-        "movups      32(%%edx),   %%xmm6\n"
-        "movups      48(%%edx),   %%xmm7\n"
-        :
-        : "m" (mat)
-        : "%edx", "%xmm4", "%xmm5", "%xmm6", "%xmm7"
-        );
-#endif
-
-    for (i = 0; i < nlist; i++)
-    {
-#ifdef DM_USE_SIMD
-        asm volatile
-            (
-            // list[i] -> xmm0
-            "movups      %1,     %%xmm0\n"
-            
-            // zero final result in xmm2
-            "xorps       %%xmm2, %%xmm2\n"
-
-            // perform shuffle and multiply and add whole "column" "X"
-            "movups      %%xmm0, %%xmm1\n"
-            "shufps      $0x00,  %%xmm1, %%xmm1\n"
-            "mulps       %%xmm4, %%xmm1\n"
-            "addps       %%xmm1, %%xmm2\n"
-
-            // Y
-            "movups      %%xmm0, %%xmm1\n"
-            "shufps      $0x55,  %%xmm1, %%xmm1\n"
-            "mulps       %%xmm5, %%xmm1\n"
-            "addps       %%xmm1, %%xmm2\n"
-
-            // Z
-            "movups      %%xmm0, %%xmm1\n"
-            "shufps      $0xAA,  %%xmm1, %%xmm1\n"
-            "mulps       %%xmm6, %%xmm1\n"
-            "addps       %%xmm1, %%xmm2\n"
-
-            // W
-            "movups      %%xmm0, %%xmm1\n"
-            "shufps      $0xFF,  %%xmm1, %%xmm1\n"
-            "mulps       %%xmm7, %%xmm1\n"
-            "addps       %%xmm1, %%xmm2\n"
-
-            // Result ->
-            "movups      %%xmm2, %0\n"
-            : "=m" (list[i])
-            : "m" (list[i])
-            : "memory", "%xmm0", "%xmm1", "%xmm2", "%xmm4", "%xmm5", "%xmm6", "%xmm7");
-#else
-        DMVector q;
-        memcpy(&q, &list[i], sizeof(DMVector));
-
-        list[i].x = (q.x * mat->m[0][0]) + (q.y * mat->m[1][0]) + (q.z * mat->m[2][0]);
-        list[i].y = (q.x * mat->m[0][1]) + (q.y * mat->m[1][1]) + (q.z * mat->m[2][1]);
-        list[i].z = (q.x * mat->m[0][2]) + (q.y * mat->m[1][2]) + (q.z * mat->m[2][2]);
-#endif
-    }
-}
-
-
-/* Set matrix to unit-matrix
- */
-void dm_matrix_unit(DMMatrix *mat)
-{
-    memset(mat, 0, sizeof(DMMatrix));
-    mat->m[0][0] = 1.0f;
-    mat->m[1][1] = 1.0f;
-    mat->m[2][2] = 1.0f;
-    mat->m[3][3] = 1.0f;
-}
-
-
-/* Transpose the matrix mat2 to mat1
- */
-void dm_matrix_transpose(DMMatrix *mat1, const DMMatrix *mat2)
-{
-    int i, j;
-
-    for (i = 0; i < DM_MATRIX_SIZE; i++)
-        for (j = 0; j < DM_MATRIX_SIZE; j++)
-            mat1->m[i][j] = mat2->m[j][i];
-}
-
-
-/* Multiply matrices mat1 and mat2, putting result into mat1
- */
-void dm_matrix_mul_r(DMMatrix *dst, const DMMatrix *mat1, const DMMatrix *mat2)
-{
-#ifdef DM_USE_SIMD
-    asm volatile(
-        "mov           %1,        %%ebx\n"
-        "mov           %2,        %%edx\n"
-
-        // --------------------------------------------------
-
-        // 0
-        "movups        (%%ebx),   %%xmm0\n" // mat1[0]
-        "movups        (%%edx),   %%xmm1\n" // mat2[0]
-        "shufps        $0x00, %%xmm1, %%xmm1\n" // mat2[0][0]
-        "mulps         %%xmm0,    %%xmm1\n"
-        "movups        %%xmm1,    %%xmm3\n"
-        
-        // 1
-        "movups        16(%%ebx), %%xmm0\n" // mat1[0]
-        "movups        (%%edx),   %%xmm1\n" // mat2[0]
-        "shufps        $0x55, %%xmm1, %%xmm1\n" // mat2[0][1]
-        "mulps         %%xmm0,    %%xmm1\n"
-        "addps         %%xmm1,    %%xmm3\n"
-
-        // 2
-        "movups        32(%%ebx), %%xmm0\n" // mat1[0]
-        "movups        (%%edx),   %%xmm1\n" // mat2[0]
-        "shufps        $0xAA, %%xmm1, %%xmm1\n" // mat2[0][2]
-        "mulps         %%xmm0,    %%xmm1\n"
-        "addps         %%xmm1,    %%xmm3\n"
-
-        // 3
-        "movups        48(%%ebx), %%xmm0\n" // mat1[0]
-        "movups        (%%edx),   %%xmm1\n" // mat2[0]
-        "shufps        $0xFF, %%xmm1, %%xmm1\n" // mat2[0][3]
-        "mulps         %%xmm0,    %%xmm1\n"
-        "addps         %%xmm1,    %%xmm3\n"
-
-        "mov           %0,        %%ebx\n"
-        "movups        %%xmm3,    (%%ebx)\n"
-
-        // --------------------------------------------------
-
-        "mov           %1,        %%ebx\n"
-
-        // 0
-        "movups        (%%ebx),   %%xmm0\n" // mat1[0]
-        "movups        16(%%edx), %%xmm1\n" // mat2[1]
-        "shufps        $0x00, %%xmm1, %%xmm1\n" // mat2[0][0]
-        "mulps         %%xmm0,    %%xmm1\n"
-        "movups        %%xmm1,    %%xmm3\n"
-        
-        // 1
-        "movups        16(%%ebx), %%xmm0\n" // mat1[0]
-        "movups        16(%%edx), %%xmm1\n" // mat2[1]
-        "shufps        $0x55, %%xmm1, %%xmm1\n" // mat2[0][1]
-        "mulps         %%xmm0,    %%xmm1\n"
-        "addps         %%xmm1,    %%xmm3\n"
-
-        // 2
-        "movups        32(%%ebx), %%xmm0\n" // mat1[0]
-        "movups        16(%%edx), %%xmm1\n" // mat2[1]
-        "shufps        $0xAA, %%xmm1, %%xmm1\n" // mat2[0][2]
-        "mulps         %%xmm0,    %%xmm1\n"
-        "addps         %%xmm1,    %%xmm3\n"
-
-        // 3
-        "movups        48(%%ebx), %%xmm0\n" // mat1[0]
-        "movups        16(%%edx), %%xmm1\n" // mat2[1]
-        "shufps        $0xFF, %%xmm1, %%xmm1\n" // mat2[0][3]
-        "mulps         %%xmm0,    %%xmm1\n"
-        "addps         %%xmm1,    %%xmm3\n"
-
-        "mov           %0,        %%ebx\n"
-        "movups        %%xmm3,    16(%%ebx)\n"
-
-        // --------------------------------------------------
-
-        "mov           %1,        %%ebx\n"
-
-        // 0
-        "movups        (%%ebx),   %%xmm0\n" // mat1[0]
-        "movups        32(%%edx), %%xmm1\n" // mat2[1]
-        "shufps        $0x00, %%xmm1, %%xmm1\n" // mat2[0][0]
-        "mulps         %%xmm0,    %%xmm1\n"
-        "movups        %%xmm1,    %%xmm3\n"
-        
-        // 1
-        "movups        16(%%ebx), %%xmm0\n" // mat1[0]
-        "movups        32(%%edx), %%xmm1\n" // mat2[1]
-        "shufps        $0x55, %%xmm1, %%xmm1\n" // mat2[0][1]
-        "mulps         %%xmm0,    %%xmm1\n"
-        "addps         %%xmm1,    %%xmm3\n"
-
-        // 2
-        "movups        32(%%ebx), %%xmm0\n" // mat1[0]
-        "movups        32(%%edx), %%xmm1\n" // mat2[1]
-        "shufps        $0xAA, %%xmm1, %%xmm1\n" // mat2[0][2]
-        "mulps         %%xmm0,    %%xmm1\n"
-        "addps         %%xmm1,    %%xmm3\n"
-
-        // 3
-        "movups        48(%%ebx), %%xmm0\n" // mat1[0]
-        "movups        32(%%edx), %%xmm1\n" // mat2[1]
-        "shufps        $0xFF, %%xmm1, %%xmm1\n" // mat2[0][3]
-        "mulps         %%xmm0,    %%xmm1\n"
-        "addps         %%xmm1,    %%xmm3\n"
-
-        "mov           %0,        %%ebx\n"
-        "movups        %%xmm3,    32(%%ebx)\n"
-
-        // --------------------------------------------------
-
-        "mov           %1,        %%ebx\n"
-
-        // 0
-        "movups        (%%ebx),   %%xmm0\n" // mat1[0]
-        "movups        48(%%edx), %%xmm1\n" // mat2[1]
-        "shufps        $0x00, %%xmm1, %%xmm1\n" // mat2[0][0]
-        "mulps         %%xmm0,    %%xmm1\n"
-        "movups        %%xmm1,    %%xmm3\n"
-        
-        // 1
-        "movups        16(%%ebx), %%xmm0\n" // mat1[0]
-        "movups        48(%%edx), %%xmm1\n" // mat2[1]
-        "shufps        $0x55, %%xmm1, %%xmm1\n" // mat2[0][1]
-        "mulps         %%xmm0,    %%xmm1\n"
-        "addps         %%xmm1,    %%xmm3\n"
-
-        // 2
-        "movups        32(%%ebx), %%xmm0\n" // mat1[0]
-        "movups        48(%%edx), %%xmm1\n" // mat2[1]
-        "shufps        $0xAA, %%xmm1, %%xmm1\n" // mat2[0][2]
-        "mulps         %%xmm0,    %%xmm1\n"
-        "addps         %%xmm1,    %%xmm3\n"
-
-        // 3
-        "movups        48(%%ebx), %%xmm0\n" // mat1[0]
-        "movups        48(%%edx), %%xmm1\n" // mat2[1]
-        "shufps        $0xFF, %%xmm1, %%xmm1\n" // mat2[0][3]
-        "mulps         %%xmm0,    %%xmm1\n"
-        "addps         %%xmm1,    %%xmm3\n"
-
-        "mov           %0,        %%ebx\n"
-        "movups        %%xmm3,    48(%%ebx)\n"
-
-        : "=m" (dst)
-        : "m" (mat1), "m" (mat2)
-        : "memory", "%edx", "%ebx", "%xmm0", "%xmm2", "%xmm3"
-        );
-#else
-    int i, j;
-    for (i = 0; i < DM_MATRIX_SIZE; i++)
-        for (j = 0; j < DM_MATRIX_SIZE; j++)
-            dst->m[i][j] =
-                (mat1->m[i][0] * mat2->m[0][j]) +
-                (mat1->m[i][1] * mat2->m[1][j]) +
-                (mat1->m[i][2] * mat2->m[2][j]);
-#endif
-}
-
-
-void dm_matrix_mul(DMMatrix *mat1, const DMMatrix *mat2)
-{
-    DMMatrix tmpM;
-    dm_matrix_mul_r(&tmpM, mat1, mat2);
-    memcpy(mat1, &tmpM, sizeof(DMMatrix));
-}
-
-
-/* Multiply given list of matrices (size of nMatrices units) with given matrix.
- */
-void dm_matrix_mul_n(DMMatrix * list, const int nlist, const DMMatrix *mat)
-{
-    int i;
-    for (i = 0; i < nlist; i++)
-        dm_matrix_mul(&list[i], mat);
-}
-
-
-/* Optimized rotation matrix creation
- */
-void dm_matrix_rot(DMMatrix *mat,
-    const DMFloat sx, const DMFloat sy, const DMFloat sz,
-    const DMFloat cx, const DMFloat cy, const DMFloat cz)
-{
-    const DMFloat
-        q = cx * sz,
-        l = cx * cz,
-        i = sx * sz,
-        j = sx * cz;
-
-    memset(mat, 0, sizeof(DMMatrix));
-
-    mat->m[0][0] = cy * cz;
-    mat->m[0][1] = cy * sz;
-    mat->m[0][2] = -sy;
-
-
-    mat->m[1][0] = (sy * j) - q;
-    mat->m[1][1] = (sy * i) + l;
-    mat->m[1][2] = sx * cy;
-
-
-    mat->m[2][0] = (sy * l) + i;
-    mat->m[2][1] = (sy * q) - j;
-    mat->m[2][2] = cx * cy;
-
-    mat->m[3][3] = 1.0f;
-}
--- a/dmvecmat.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,153 +0,0 @@
-/*
- * DMLib
- * -- Vector and matrix functions
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2011-2012 Tecnic Software productions (TNSP)
- */
-#ifndef DMVECMAT_H
-#define DMVECMAT_H
-#include "dmlib.h"
-
-#include <math.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define DM_MATRIX_SIZE	(4)
-
-typedef struct
-{
-    DMFloat x, y, z, W;
-} DMVector;
-
-typedef	struct
-{
-    DMFloat m[DM_MATRIX_SIZE][DM_MATRIX_SIZE];
-} DMMatrix;
-
-
-void    dm_vector_add_n(DMVector *dst, const DMVector *src, const int nlist);
-void    dm_vector_add_r_n(DMVector *dst, const DMVector *src1, const DMVector *src2, const int nlist);
-void    dm_vector_sub_n(DMVector *dst, const DMVector *src, const int nlist);
-void    dm_vector_sub_r_n(DMVector *dst, const DMVector *src1, const DMVector *src2, const int nlist);
-
-void    dm_vector_mul_by_mat(DMVector *vd, const DMVector *vs, const DMMatrix *mat);
-void    dm_vector_mul_by_mat_n(DMVector *list, const int nlist, const DMMatrix *mat);
-
-void    dm_matrix_unit(DMMatrix *mat);
-void    dm_matrix_transpose(DMMatrix *mat1, const DMMatrix *mat2);
-
-void    dm_matrix_mul(DMMatrix *mat1, const DMMatrix *mat2);
-void    dm_matrix_mul_r(DMMatrix *dst, const DMMatrix *mat1, const DMMatrix *mat2);
-void    dm_matrix_mul_n(DMMatrix *list, const int nlist, const DMMatrix *mat);
-
-void    dm_matrix_rot(DMMatrix *mat,
-        const DMFloat sx, const DMFloat sy, const DMFloat sz,
-        const DMFloat cx, const DMFloat cy, const DMFloat cz);
-
-
-/* Basic vector operations
- */
-static inline void dm_vector_copy(DMVector *vd, const DMVector *vs)
-{
-    memcpy(vd, vs, sizeof(DMVector));
-}
-
-
-static inline void dm_vector_add(DMVector *vr, const DMVector *v2)
-{
-    vr->x += v2->x;
-    vr->y += v2->y;
-    vr->z += v2->z;
-}
-
-
-static inline void dm_vector_add_r(DMVector *vr, const DMVector *v1, const DMVector *v2)
-{
-    vr->x = v1->x + v2->x;
-    vr->y = v1->y + v2->y;
-    vr->z = v1->z + v2->z;
-}
-
-
-static inline void dm_vector_sub(DMVector *vr, const DMVector *v2)
-{
-    vr->x -= v2->x;
-    vr->y -= v2->y;
-    vr->z -= v2->z;
-}
-
-
-static inline void dm_vector_sub_r(DMVector *vr, const DMVector *v1, const DMVector *v2)
-{
-    vr->x = v1->x - v2->x;
-    vr->y = v1->y - v2->y;
-    vr->z = v1->z - v2->z;
-}
-
-
-/* Returns dot-product of two given vectors
- */
-static inline DMFloat dm_vector_dot(const DMVector *v1, const DMVector *v2)
-{
-    return (v1->x * v2->x) + (v1->y * v2->y) + (v1->z * v2->z);
-}
-
-
-/* Return vector length
- */
-static inline DMFloat dm_vector_length(const DMVector *vs)
-{
-    return sqrt((vs->x * vs->x) + (vs->y * vs->y) + (vs->z * vs->z));
-}
-
-
-/* Normalize vector
- */
-static inline void dm_vector_normalize(DMVector *vec)
-{
-    DMFloat l = dm_vector_length(vec);
-
-    if (l > 0.0f)
-    {
-        l = 1.0f / l;
-        vec->x *= l;
-        vec->y *= l;
-        vec->z *= l;
-    }
-}
-
-
-/* Scale given vector
- */
-static inline void dm_vector_scale(DMVector * vec, const DMFloat k)
-{
-    vec->x *= k;
-    vec->y *= k;
-    vec->z *= k;
-}
-
-
-/* Returns cross-product of two given vectors
- */
-static inline void dm_vector_cross(DMVector *vr, const DMVector *v1, const DMVector *v2)
-{
-    vr->x = (v1->y * v2->z) - (v1->z * v2->y);
-    vr->y = (v1->z * v2->x) - (v1->x * v2->z);
-    vr->z = (v1->x * v2->y) - (v1->y * v2->x);
-}
-
-
-/* Make rotation matrix from given angles (radians)
- */
-static inline void dm_matrix_rot_a(DMMatrix *mat, const DMFloat ax, const DMFloat ay, const DMFloat az)
-{
-    dm_matrix_rot(mat, sin(ax), sin(ay), sin(az), cos(ax), cos(ay), cos(az));
-}
-
-
-#ifdef __cplusplus
-}
-#endif
-#endif // DMVECMAT_H
--- a/dmwav.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/*
- * DMLib
- * -- Wav file writing
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012 Tecnic Software productions (TNSP)
- */
-#include "dmwav.h"
-#include "dmfile.h"
-
-
-BOOL dmWriteWAVChunk(FILE * f, DMWaveChunk *ch)
-{
-    return dm_fwrite_str(f, ch->chunkID, 4) && dm_fwrite_le32(f, ch->chunkSize);
-}
-
-
-void dmMakeWAVChunk(DMWaveChunk *ch, const char *chunkID, const Uint32 chunkSize)
-{
-    memcpy(&(ch->chunkID), (const void *) chunkID, 4);
-    ch->chunkSize = chunkSize;
-}
-
-
-void dmWriteWAVHeader(FILE *outFile, int sampBits, int sampFreq, int sampChn, size_t sampLen)
-{
-    DMWaveFile wav;
-    
-    // PCM WAVE chunk
-    dmMakeWAVChunk(&wav.chFormat, DM_WAVE_FMT_ID, (2 + 2 + 4 + 4 + 2 + 2));
-
-    wav.wFormatTag = DM_WAVE_FORMAT_PCM;
-    wav.nChannels = sampChn;
-    wav.nSamplesPerSec = sampFreq;
-    wav.nAvgBytesPerSec = (sampBits * sampChn * sampFreq) / 8;
-    wav.nBlockAlign = (sampBits * sampChn) / 8;
-    wav.wBitsPerSample = sampBits;
-
-    // Data chunk
-    dmMakeWAVChunk(&wav.chData, DM_WAVE_DATA_ID, (sampLen * wav.nBlockAlign));
-
-    // RIFF header
-    memcpy(&wav.riffID, (const void *) DM_WAVE_RIFF_ID, 4);
-    memcpy(&wav.riffType, (const void *) DM_WAVE_WAVE_ID, 4);
-    wav.fileSize = ((4 + 4 + 4) + wav.chFormat.chunkSize + wav.chData.chunkSize);
-
-    // Write header
-    dm_fwrite_str(outFile, wav.riffID, sizeof(wav.riffID));
-    dm_fwrite_le32(outFile, wav.fileSize);
-    
-    dm_fwrite_str(outFile, wav.riffType, sizeof(wav.riffType));
-    dmWriteWAVChunk(outFile, &wav.chFormat);
-    
-    dm_fwrite_le16(outFile, wav.wFormatTag);
-    dm_fwrite_le16(outFile, wav.nChannels);
-    dm_fwrite_le32(outFile, wav.nSamplesPerSec);
-    dm_fwrite_le32(outFile, wav.nAvgBytesPerSec);
-    dm_fwrite_le16(outFile, wav.nBlockAlign);
-    dm_fwrite_le16(outFile, wav.wBitsPerSample);
-    
-    dmWriteWAVChunk(outFile, &wav.chData);
-}
--- a/dmwav.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
- * DMLib
- * -- Wav file writing
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012 Tecnic Software productions (TNSP)
- */
-#ifndef DMWAV_H
-#define DMWAV_H
-
-#include "dmlib.h"
-#include <stdio.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define DM_WAVE_FORMAT_PCM     (1)
-#define DM_WAVE_RIFF_ID        "RIFF"
-#define DM_WAVE_WAVE_ID        "WAVE"
-#define DM_WAVE_FMT_ID         "fmt "
-#define DM_WAVE_DATA_ID        "data"
-
-
-typedef struct
-{
-    Uint8     chunkID[4];
-    Uint32    chunkSize;
-} DMWaveChunk; 
-
-
-typedef struct
-{
-    Uint8     riffID[4];
-    Uint32    fileSize;
-    Uint8     riffType[4];
-
-    DMWaveChunk chFormat;
-
-    Uint16    wFormatTag;
-    Uint16    nChannels;
-    Uint32    nSamplesPerSec;
-    Uint32    nAvgBytesPerSec;
-    Uint16    nBlockAlign;
-    Uint16    wBitsPerSample;
-
-    DMWaveChunk chData;
-    // Data follows here
-} DMWaveFile;
-
-
-BOOL dmWriteWAVChunk(FILE * f, DMWaveChunk *ch);
-void dmMakeWAVChunk(DMWaveChunk *ch, const char *chunkID, const Uint32 chunkSize);
-void dmWriteWAVHeader(FILE *outFile, int sampBits, int sampFreq, int sampChn, size_t sampLen);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // DMWAV_H
--- a/lib64gfx.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,864 +0,0 @@
-/*
- * Functions for reading and converting various restricted
- * C64/etc and/or indexed/paletted graphics formats.
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012 Tecnic Software productions (TNSP)
- *
- * Please read file 'COPYING' for information on license and distribution.
- */
-#include "lib64gfx.h"
-
-#define BUF_SIZE_INITIAL   (16*1024)
-#define BUF_SIZE_GROW      (4*1024)
-
-
-char * dmC64GetImageTypeString(char *buf, const size_t len, const int type)
-{
-    snprintf(buf, len,
-        "%s%s%s",
-        (type & D64_FMT_FLI) ? "FLI " : "",
-        (type & D64_FMT_MC) ? "MCol" : "HiRes",
-        (type & D64_FMT_ILACE) ? " Ilace" : ""
-        );
-
-    return buf;
-}
-
-
-// Based on Pepto's palette, stolen from VICE
-DMColor dmC64Palette[C64_NCOLORS] =
-{
-    { 0x00, 0x00, 0x00, 0xff },
-    { 0xFF, 0xFF, 0xFF, 0xff },
-    { 0x68, 0x37, 0x2B, 0xff },
-    { 0x70, 0xA4, 0xB2, 0xff },
-    { 0x6F, 0x3D, 0x86, 0xff },
-    { 0x58, 0x8D, 0x43, 0xff },
-    { 0x35, 0x28, 0x79, 0xff },
-    { 0xB8, 0xC7, 0x6F, 0xff },
-    { 0x6F, 0x4F, 0x25, 0xff },
-    { 0x43, 0x39, 0x00, 0xff },
-    { 0x9A, 0x67, 0x59, 0xff },
-    { 0x44, 0x44, 0x44, 0xff },
-    { 0x6C, 0x6C, 0x6C, 0xff },
-    { 0x9A, 0xD2, 0x84, 0xff },
-    { 0x6C, 0x5E, 0xB5, 0xff },
-    { 0x95, 0x95, 0x95, 0xff },
-};
-
-
-const size_t dmC64DefaultSizes[DT_LAST] =
-{
-    C64_SCR_COLOR_SIZE,
-    C64_SCR_BITMAP_SIZE,
-    C64_SCR_SCREEN_SIZE,
-    1,
-    C64_SCR_EXTRADATA,
-};
-
-
-#define DM_GET_ADDR_LO(addr) ((addr) & 0xff)
-#define DM_GET_ADDR_HI(addr) (((addr) >> 8) & 0xff)
-
-
-static BOOL dmCompareAddr16(const Uint8 *buf, const size_t offs, const Uint16 addr)
-{
-    return buf[offs] == DM_GET_ADDR_LO(addr) &&
-           buf[offs + 1] == DM_GET_ADDR_HI(addr);
-}
-
-
-int dmC64ConvertCSData(DMImage *img,
-    int xoffs, int yoffs, const Uint8 *buf,
-    int width, int height, BOOL multicolor, int *colors)
-{
-    int yc, widthpx = width * 8;
-    Uint8 *dp;
-
-    if (img == NULL)
-        return DMERR_NULLPTR;
-
-    if (xoffs < 0 || yoffs < 0 ||
-        xoffs > img->width - widthpx ||
-        yoffs > img->height - height)
-        return DMERR_INVALID_ARGS;
-
-    dp = img->data + (yoffs * img->pitch) + xoffs;
-
-    if (multicolor)
-    {
-        for (yc = 0; yc < height; yc++)
-        {
-            const int offs = yc * width;
-            int xc;
-            Uint8 *d = dp;
-
-            for (xc = 0; xc < widthpx / 2; xc++)
-            {
-                const int b = buf[offs + (xc / 4)];
-                const int v = 6 - ((xc * 2) & 6);
-                const Uint8 c = colors[(b >> v) & 3];
-                
-                *d++ = c;
-                *d++ = c;
-            }
-
-            dp += img->pitch;
-        }
-    }
-    else
-    {
-        for (yc = 0; yc < height; yc++)
-        {
-            const int offs = yc * width;
-            int xc;
-            Uint8 *d = dp;
-
-            for (xc = 0; xc < widthpx; xc++)
-            {
-                const int b = buf[offs + (xc / 8)];
-                const int v = 7 - (xc & 7);
-                const Uint8 c = colors[(b >> v) & 1];
-                
-                *d++ = c;
-            }
-
-            dp += img->pitch;
-        }
-    }
-    
-    return DMERR_OK;
-}
-
-
-static int fmtProbeDrazPaint20Packed(const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt)
-{
-    const char *ident = (const char *) buf + 2;
-
-    if (len > 22 &&
-        dmCompareAddr16(buf, 0, fmt->addr) &&
-        strncmp(ident, "DRAZPAINT ", 10) == 0 &&
-        ident[11] == '.' && (
-        (ident[10] == '1' && ident[12] == '4') ||
-        (ident[10] == '2' && ident[12] == '0')
-        ))
-        return DM_PROBE_SCORE_MAX;
-
-    return DM_PROBE_SCORE_FALSE;
-}
-
-
-static int dmDecodeGenericRLE(Uint8 **mem, Uint8 **pdstEnd, const Uint8 *src, const Uint8 *srcEnd, const Uint8 rleMarker)
-{
-    Uint8 *dst, *dstEnd;
-
-    if ((*mem = dmMalloc(C64_RAM_SIZE)) == NULL)
-        return DMERR_MALLOC;
-    
-    dst       = *mem;
-    dstEnd    = *mem + C64_RAM_SIZE;
-
-    while (src <= srcEnd && dst <= dstEnd)
-    {
-        int c = *src++;
-        if (c == rleMarker && src + 2 <= srcEnd)
-        {
-            int cnt = *src++;
-            c = *src++;
-            while (cnt-- && dst <= dstEnd)
-                *dst++ = c;
-        }
-        else
-            *dst++ = c;
-    }
-
-    *pdstEnd = dst;
-
-    return DMERR_OK;
-}
-
-
-static int fmtDecodeDrazPaintPacked(DMC64Image *img, const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt)
-{
-    int res;
-    Uint8 *mem = NULL, *dstEnd;
-
-    if ((res = dmDecodeGenericRLE(&mem, &dstEnd, buf + 0x0e, buf + len, *(buf + 0x0d))) != DMERR_OK)
-        goto out;
-
-    res = dmC64DecodeGenericBMP(img, mem, dstEnd - mem + 1, fmt);
-
-out:
-    dmFree(mem);
-    return res;
-}
-
-
-static int fmtProbeDrazLace10Packed(const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt)
-{
-    const char *ident = (const char *) buf + 2;
-    if (len > 22 &&
-        dmCompareAddr16(buf, 0, fmt->addr) &&
-        strncmp(ident, "DRAZLACE! 1.0", 13) == 0)
-        return DM_PROBE_SCORE_MAX;
-    
-    return DM_PROBE_SCORE_FALSE;
-}
-
-
-static BOOL fmtDrazLaceSetLaceType(DMC64Image *img, const struct _DMC64EncDecOp *op, const Uint8 *buf, const size_t len)
-{
-    (void) len;
-
-    img->laceType = buf[op->offs] ? D64_ILACE_RES : D64_ILACE_COLOR;
-    img->laceBank1 = img->laceBank2 = 0;
-    return TRUE;
-}
-
-
-#define AMICA_DM_PROBE_SIZE 2048
-static int fmtProbeAmicaPaintPacked(const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt)
-{
-    size_t i, n;
-    if (len < AMICA_DM_PROBE_SIZE || !dmCompareAddr16(buf, 0, fmt->addr))
-        return DM_PROBE_SCORE_FALSE;
-    
-    // Interpaint Hi-Res gives a false positive
-    if (len == 9002)
-        return DM_PROBE_SCORE_FALSE;
-    
-    for (n = 0, i = 2; i < len; i++)
-        if (buf[i] == 0xC2) n++;
-    
-    if (n > 50)
-        return DM_PROBE_SCORE_GOOD;
-    if (n > 25)
-        return DM_PROBE_SCORE_AVG;
-    if (n > 10)
-        return DM_PROBE_SCORE_MAYBE;
-    return DM_PROBE_SCORE_FALSE;
-}
-
-
-static int fmtDecodeAmicaPaintPacked(DMC64Image *img, const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt)
-{
-    int res;
-    Uint8 *mem = NULL, *dstEnd;
-
-    if ((res = dmDecodeGenericRLE(&mem, &dstEnd, buf, buf + len, 0xC2)) != DMERR_OK)
-        goto out;
-
-    res = dmC64DecodeGenericBMP(img, mem, dstEnd - mem + 1, fmt);
-    
-out:
-    dmFree(mem);
-    return res;
-}
-
-
-static BOOL fmtTruePaintSetLaceType(DMC64Image *img, const struct _DMC64EncDecOp *op, const Uint8 *buf, const size_t len)
-{
-    (void) op;
-    (void) buf;
-    (void) len;
-    img->laceType = D64_ILACE_RES;
-    img->laceBank1 = 0;
-    img->laceBank2 = 1;
-    return TRUE;
-}
-
-
-static BOOL fmtSetFLIType(DMC64Image *img, const struct _DMC64EncDecOp *op, const Uint8 *buf, const size_t len)
-{
-    (void) buf;
-    (void) len;
-    img->fliType = op->bank;
-    return TRUE;
-}
-
-
-const DMC64ImageFormat dmC64ImageFormats[] =
-{
-    {
-        D64_FMT_MC, "d2p", "DrazPaint 2.0 (packed)", 0x5800, -1,
-        fmtProbeDrazPaint20Packed, fmtDecodeDrazPaintPacked,
-        NULL, NULL, NULL,
-        4,
-        {
-            { DT_COLOR_RAM,    0x0000, 0,  0, NULL, NULL },
-            { DT_BITMAP,       0x0800, 0,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x0400, 0,  0, NULL, NULL },
-            { DT_BGCOLOR,      0x2740, 0,  0, NULL, NULL },
-        }
-    },
-
-    {
-        D64_FMT_MC | D64_FMT_ILACE, "dlp", "DrazLace 1.0 (packed)", 0x5800, -1,
-        fmtProbeDrazLace10Packed, fmtDecodeDrazPaintPacked,
-        NULL, NULL, NULL,
-        6,
-        {
-            { DT_COLOR_RAM,    0x0000, 0,  0, NULL, NULL },
-            { DT_BITMAP,       0x0800, 0,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x0400, 0,  0, NULL, NULL },
-            { DT_BGCOLOR,      0x2740, 0,  0, NULL, NULL },
-            { DT_BITMAP,       0x2800, 1,  0, NULL, NULL },
-            { DT_DEC_FUNCTION, 0x2742, 0,  1, fmtDrazLaceSetLaceType, NULL },
-        }
-    },
-    
-    {
-        D64_FMT_MC, "drp", "DrazPaint (unpacked)", 0x5800, 10051,
-        NULL, NULL,
-        NULL, NULL, NULL,
-        4,
-        {
-            { DT_COLOR_RAM,    0x0000, 0,  0, NULL, NULL },
-            { DT_BITMAP,       0x0800, 0,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x0400, 0,  0, NULL, NULL },
-            { DT_BGCOLOR,      0x2740, 0,  0, NULL, NULL },
-        }
-    },
-
-    {
-        D64_FMT_MC | D64_FMT_ILACE, "drl", "DrazLace 1.0 (unpacked)", 0x5800, 18242,
-        NULL, NULL,
-        NULL, NULL, NULL,
-        6,
-        {
-            { DT_COLOR_RAM,    0x0000, 0,  0, NULL, NULL },
-            { DT_BITMAP,       0x0800, 0,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x0400, 0,  0, NULL, NULL },
-            { DT_BGCOLOR,      0x2740, 0,  0, NULL, NULL },
-            { DT_BITMAP,       0x2800, 1,  0, NULL, NULL },
-            { DT_DEC_FUNCTION, 0x2742, 0,  1, fmtDrazLaceSetLaceType, NULL },
-        }
-    },
-    
-    {
-        D64_FMT_MC | D64_FMT_ILACE, "mci", "Truepaint (unpacked)", 0x9c00, 19434,
-        NULL, NULL,
-        NULL, NULL, NULL,
-        6,
-        {
-            { DT_SCREEN_RAM,   0x0000, 0,  0, NULL, NULL },
-            { DT_BGCOLOR,      0x03e8, 0,  0, NULL, NULL },
-            { DT_BITMAP,       0x0400, 0,  0, NULL, NULL },
-            { DT_BITMAP,       0x2400, 1,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x4400, 1,  0, NULL, NULL },
-            { DT_COLOR_RAM,    0x4800, 0,  0, NULL, NULL },
-            { DT_DEC_FUNCTION, 0x0000, 0,  0, fmtTruePaintSetLaceType, NULL },
-        }
-    },
-    
-    {
-        D64_FMT_MC, "kla", "Koala Paint (unpacked)", 0x6000, 10003,
-        NULL, NULL,
-        NULL, NULL, NULL,
-        4,
-        {
-            { DT_BITMAP,       0x0000, 0,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x1f40, 0,  0, NULL, NULL },
-            { DT_COLOR_RAM,    0x2328, 0,  0, NULL, NULL },
-            { DT_BGCOLOR,      0x2710, 0,  0, NULL, NULL },
-        }
-    },
-
-    {
-        D64_FMT_MC, "ocp", "Advanced Art Studio (unpacked)", 0x2000, 10018,
-        NULL, NULL,
-        NULL, NULL, NULL,
-        4,
-        {
-            { DT_BITMAP,       0x0000, 0,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x1f40, 0,  0, NULL, NULL },
-            { DT_COLOR_RAM,    0x2338, 0,  0, NULL, NULL },
-            { DT_BGCOLOR,      0x2329, 0,  0, NULL, NULL },
-        }
-    },
-
-    {
-        D64_FMT_MC, "ami", "Amica Paint (packed)", 0x4000, -1,
-        fmtProbeAmicaPaintPacked, fmtDecodeAmicaPaintPacked,
-        NULL, NULL, NULL,
-        4,
-        {
-            { DT_COLOR_RAM,    0x2328, 0,  0, NULL, NULL },
-            { DT_BITMAP,       0x0000, 0,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x1f40, 0,  0, NULL, NULL },
-            { DT_BGCOLOR,      0x2710, 0,  0, NULL, NULL },
-        }
-    },
-
-    {
-        D64_FMT_MC, "rpm", "Run Paint (unpacked)", 0x6000, 10006,
-        NULL, NULL,
-        NULL, NULL, NULL,
-        4,
-        {
-            { DT_COLOR_RAM,    0x2328, 0,  0, NULL, NULL },
-            { DT_BITMAP,       0x0000, 0,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x1f40, 0,  0, NULL, NULL },
-            { DT_BGCOLOR,      0x2710, 0,  0, NULL, NULL },
-        }
-    },
-
-    {
-        D64_FMT_HIRES, "art", "Art Studio (unpacked)", 0x2000, 9009,
-        NULL, NULL,
-        NULL, NULL, NULL,
-        2,
-        {
-            { DT_BITMAP,       0x0000, 0,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x1f40, 0,  0, NULL, NULL },
-        }
-    },
-
-    {
-        D64_FMT_HIRES, "iph", "Interpaint (unpacked)", 0x4000, 9002,
-        NULL, NULL,
-        NULL, NULL, NULL,
-        2,
-        {
-            { DT_BITMAP,       0x0000, 0,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x1f40, 0,  0, NULL, NULL },
-        }
-    },
-
-    {
-        D64_FMT_HIRES, "dd", "Doodle (unpacked)", 0x1c00, 9218,
-        NULL, NULL,
-        NULL, NULL, NULL,
-        2,
-        {
-            { DT_SCREEN_RAM,   0x0000, 0,  0, NULL, NULL },
-            { DT_BITMAP,       0x0400, 0,  0, NULL, NULL },
-        }
-    },
-    
-    {
-        D64_FMT_MC | D64_FMT_FLI, "bml", "Blackmail FLI (unpacked)", 0x3b00, 17474,
-        NULL, NULL,
-        NULL, NULL, NULL,
-        11,
-        {
-            { DT_COLOR_RAM,    0x0100, 0,  0, NULL, NULL },
-
-            { DT_SCREEN_RAM,   0x0500, 0,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x0900, 1,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x0d00, 2,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x1100, 3,  0, NULL, NULL },
-
-            { DT_SCREEN_RAM,   0x1500, 4,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x1900, 5,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x1d00, 6,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x2100, 7,  0, NULL, NULL },
-
-            { DT_BITMAP,       0x2500, 0,  0, NULL, NULL },
-            { DT_DEC_FUNCTION, 0x0000, D64_FLI_8BANK,  0, fmtSetFLIType, NULL },
-        }
-    },
-
-    {
-        D64_FMT_MC | D64_FMT_FLI, "fli", "FLI Designer (unpacked)", 0x3c00, 17409,
-        NULL, NULL,
-        NULL, NULL, NULL,
-        11,
-        {
-            { DT_COLOR_RAM,    0x0000, 0,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x0400, 0,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x0800, 1,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x0c00, 2,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x1000, 3,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x1400, 4,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x1800, 5,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x1c00, 6,  0, NULL, NULL },
-            { DT_SCREEN_RAM,   0x2000, 7,  0, NULL, NULL },
-            { DT_BITMAP,       0x2400, 0,  0, NULL, NULL },
-            { DT_DEC_FUNCTION, 0x0000, D64_FLI_8BANK,  0, fmtSetFLIType, NULL },
-        }
-    },
-
-};
-
-const int ndmC64ImageFormats = sizeof(dmC64ImageFormats) / sizeof(dmC64ImageFormats[0]);
-
-
-// Perform probing of the given data buffer, trying to determine
-// if it contains a supported "C64" image format. Returns the
-// "probe score", see libgfx.h for list of values. If a match
-// is found, pointer to format description is set to *pfmt.
-int dmC64ProbeBMP(const Uint8 *buf, const size_t len, const DMC64ImageFormat **pfmt)
-{
-    int i, scoreMax = DM_PROBE_SCORE_FALSE, scoreIndex = -1;
-
-    for (i = 0; i < ndmC64ImageFormats; i++)
-    {
-        const DMC64ImageFormat *fmt = &dmC64ImageFormats[i];
-        int score = DM_PROBE_SCORE_FALSE;
-        if (fmt->probe == NULL && fmt->size > 0 && fmt->addr > 0)
-        {
-            // Generic probe just checks matching size and load address
-            if (len == fmt->size && dmCompareAddr16(buf, 0, fmt->addr))
-                score = DM_PROBE_SCORE_GOOD;
-        }
-        else
-            score = fmt->probe(buf, len, fmt);
-
-        if (score > scoreMax)
-        {
-            scoreMax = score;
-            scoreIndex = i;
-        }
-    }
-
-    if (scoreIndex >= 0)
-    {
-        *pfmt = &dmC64ImageFormats[scoreIndex];
-        return scoreMax;
-    }
-    else
-        return DM_PROBE_SCORE_FALSE;
-}
-
-
-static int dmC64SanityCheckEncDecOp(const int i, const DMC64EncDecOp *op)
-{
-    if (op->bank < 0 || op->bank >= C64_SCR_MAX_BANK)
-    {
-        dmError("Invalid bank %d definition in generic encode/decode operator %d @ #%d.\n",
-            op->bank, op->type, i);
-        return DMERR_INTERNAL;
-    }
-
-    if (op->type < 0 || op->type >= DT_LAST)
-    {
-        dmError("Invalid encode/decode operator type %d @ #%d.\n",
-            op->type, i);
-        return DMERR_INTERNAL;
-    }
-
-    return DMERR_OK;
-}
-
-
-int dmC64DecodeGenericBMP(DMC64Image *img, const Uint8 *buf,
-    const size_t len, const DMC64ImageFormat *fmt)
-{
-    int i;
-
-    if (buf == NULL || img == NULL || fmt == NULL)
-        return DMERR_NULLPTR;
-
-    // Clear the image structure
-    memset(img, 0, sizeof(*img));
-    img->type = fmt->type;
-
-    // Perform decoding
-    for (i = 0; i < fmt->nencdecOps; i++)
-    {
-        const DMC64EncDecOp *op = &fmt->encdecOps[i];
-        const Uint8 *src;
-        size_t size;
-        int res;
-
-        // Check operation validity
-        if ((res = dmC64SanityCheckEncDecOp(i, op)) != DMERR_OK)
-            return res;
-        
-        // Check size
-        size = (op->size == 0) ? dmC64DefaultSizes[op->type] : op->size;
-
-        // Do we need to reallocate some more space?
-        if (op->offs + size > len)
-        {
-            dmError("Decode out of bounds, op #%d type=%d, offs=%d ($%04x), "
-                "bank=%d, size=%d ($%04x) @ %d ($%04x)\n",
-                i, op->type, op->offs, op->offs, op->bank, size, size, len, len);
-            return DMERR_INVALID_DATA;
-        }
-
-        src = buf + op->offs;
-
-        // Perform operation
-        switch (op->type)
-        {
-            case DT_COLOR_RAM:   memcpy(img->color[op->bank], src, size); break;
-            case DT_BITMAP:      memcpy(img->bitmap[op->bank], src, size); break;
-            case DT_SCREEN_RAM:  memcpy(img->screen[op->bank], src, size); break;
-            case DT_BGCOLOR:     img->bgcolor = *src; break;
-            case DT_EXTRADATA:   memcpy(img->extradata, src, size); break;
-            case DT_DEC_FUNCTION:
-                if (op->decfunction == NULL)
-                {
-                    dmError("Decode op is a function, but function ptr is NULL: "
-                        "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n",
-                        i, op->offs, op->offs, op->bank, size, size, len, len);
-                    return DMERR_INTERNAL;
-                }
-                if (!op->decfunction(img, op, buf, len))
-                {
-                    dmError("Decode op custom function failed: op #%d, "
-                        "offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n",
-                        i, op->offs, op->offs, op->bank, size, size, len, len);
-                    return DMERR_INTERNAL;
-                }
-                break;
-        }
-    }
-    
-    return DMERR_OK;
-}
-
-
-int dmC64EncodeGenericBMP(Uint8 **pbuf, size_t *plen, const DMC64Image *img, const DMC64ImageFormat *fmt)
-{
-    int i, res = DMERR_OK;
-    Uint8 *buf;
-    size_t allocated;
-
-    if (pbuf == NULL || plen == NULL || img == NULL || fmt == NULL)
-        return DMERR_NULLPTR;
-
-    // Allocate the output buffer
-    *plen = 0;
-    if (fmt->size > 0)
-        *plen = allocated = fmt->size;
-    else
-        allocated = 8 * 1024;
-
-    if ((buf = dmMalloc(allocated)) == NULL)
-    {
-        dmError("Could not allocate %d bytes of memory for C64 image encoding buffer.\n",
-            allocated);
-        res = DMERR_MALLOC;
-        goto error;
-    }
-
-    // Perform encoding
-    for (i = 0; i < fmt->nencdecOps; i++)
-    {
-        const DMC64EncDecOp *op = &fmt->encdecOps[i];
-        Uint8 *dst = 2 + buf + op->offs;
-        size_t size;
-
-        // Check operation validity
-        if ((res = dmC64SanityCheckEncDecOp(i, op)) != DMERR_OK)
-            goto error;
-
-        // Check size
-        size = (op->size == 0) ? dmC64DefaultSizes[op->type] : op->size;
-
-        // Do we need to reallocate some more space?
-        if (2 + op->offs + size > allocated)
-        {
-            if ((buf = dmRealloc(buf, allocated)) == NULL)
-            {
-                size_t diff = allocated - (op->offs + size + 2),
-                       grow = (diff / (BUF_SIZE_GROW - 1)) * BUF_SIZE_GROW;
-                allocated = allocated + grow;
-                dmError("Could not re-allocate %d bytes of memory for C64 image encoding buffer.\n",
-                    allocated);
-                res = DMERR_MALLOC;
-                goto error;
-            }
-        }
-
-        if (fmt->size == 0 && op->offs + size + 2 > *plen)
-            *plen = op->offs + size + 2;
-
-        // Perform operation
-        switch (op->type)
-        {
-            case DT_COLOR_RAM:   memcpy(dst, img->color[op->bank], size); break;
-            case DT_BITMAP:      memcpy(dst, img->bitmap[op->bank], size); break;
-            case DT_SCREEN_RAM:  memcpy(dst, img->screen[op->bank], size); break;
-            case DT_BGCOLOR:     *dst = img->bgcolor; break;
-            case DT_EXTRADATA:   memcpy(dst, img->extradata, size); break;
-            case DT_ENC_FUNCTION:
-                break;
-        }
-    }
-
-    buf[0] = DM_GET_ADDR_LO(fmt->addr);
-    buf[1] = DM_GET_ADDR_HI(fmt->addr);
-
-    *pbuf = buf;
-    return DMERR_OK;
-
-error:
-    dmFree(buf);
-    *pbuf = NULL;
-    *plen = 0;
-    return res;
-}
-
-
-static inline Uint8 dmC64GetMCColor(const DMC64Image *img, const int bits, const int cbank, const int vbank, const int scroffs)
-{
-    switch (bits)
-    {
-        case  0: return img->bgcolor; break;
-        case  1: return img->screen[vbank][scroffs] >> 4; break;
-        case  2: return img->screen[vbank][scroffs] & 15; break;
-        default: return img->color[cbank][scroffs] & 15; break;
-    }
-}
-
-
-// Convert a generic "C64" format bitmap in DMC64Image struct to
-// a indexed/paletted bitmap image.
-int dmC64ConvertGenericBMP2Image(DMImage *dst, const DMC64Image *src, const BOOL doubleMC)
-{
-    Uint8 *dp = dst->data;
-    int yc;
-
-    // Sanity check arguments
-    if (dst == NULL || src == NULL)
-        return DMERR_NULLPTR;
-
-    if (dst->width < 8)
-        return DMERR_INVALID_ARGS;
-
-    // Perform generic conversion
-    for (yc = 0; yc < dst->height; yc++)
-    {
-        Uint8 *d = dp;
-        const int y = yc / 8, yb = yc & 7;
-        const int scroffsy = y * C64_SCR_CH_WIDTH;
-        const int bmoffsy = y * C64_SCR_WIDTH;
-        int xc;
-
-        if ((src->type & D64_FMT_MC) == D64_FMT_HIRES)
-        {
-            // Hi-res bitmap
-            for (xc = 0; xc < dst->width; xc++)
-            {
-                const int x = xc / 8;
-                const int scroffs = scroffsy + x;
-                const int bmoffs = bmoffsy + (x * 8) + yb;
-                const int v = 7 - (xc & 7);
-
-                if ((src->bitmap[0][bmoffs] >> v) & 1)
-                    *d++ = src->screen[0][scroffs] >> 4;
-                else
-                    *d++ = src->screen[0][scroffs] & 15;
-            }
-        }
-        else
-        {
-            // Multicolor variants
-            const int
-                wdivisor = doubleMC ? 2 : 1,
-                divisor  = doubleMC ? 4 : 8;
-
-            for (xc = 0; xc < dst->width / wdivisor; xc++)
-            {
-                const int x = xc / divisor;
-                const int scroffs = scroffsy + x;
-                const int bmoffs = bmoffsy + (x * 8) + yb;
-                const int v = 6 - ((xc * 2) & 6);
-                Uint8 c;
-
-                if (src->type & D64_FMT_FLI)
-                {
-                    int vbank = 0;
-                    switch (src->fliType)
-                    {
-                        case D64_FLI_2BANK:
-                            vbank = yb / 4;
-                            break;
-                        case D64_FLI_4BANK:
-                            vbank = yb / 2;
-                            break;
-                        case D64_FLI_8BANK:
-                            vbank = yb;
-                            break;
-                    }
-                    c = dmC64GetMCColor(src, (src->bitmap[0][bmoffs] >> v) & 3, 0, vbank, scroffs);
-                    *d++ = c;
-                    if (doubleMC)
-                        *d++ = c;
-                }
-                else
-                if (src->type & D64_FMT_ILACE)
-                {
-                    *d++ = dmC64GetMCColor(src, (src->bitmap[0][bmoffs] >> v) & 3, 0, src->laceBank1, scroffs);
-                    if (doubleMC)
-                        *d++ = dmC64GetMCColor(src, (src->bitmap[1][bmoffs] >> v) & 3, 0, src->laceBank2, scroffs);
-                }
-                else
-                {
-                    c = dmC64GetMCColor(src, (src->bitmap[0][bmoffs] >> v) & 3, 0, 0, scroffs);
-                    *d++ = c;
-                    if (doubleMC)
-                        *d++ = c;
-                }
-            }
-        }
-        dp += dst->pitch;
-    }
-
-    return DMERR_OK;
-}
-
-
-int dmC64ConvertBMP2Image(DMImage **pdst, const DMC64Image *src, const DMC64ImageFormat *fmt, const BOOL doubleMC)
-{
-    int width, res;
-    DMImage *dst;
-
-    if (pdst == NULL || src == NULL)
-        return DMERR_NULLPTR;
-
-    // Calculate output image width
-    if ((src->type & D64_FMT_MC) && !doubleMC)
-        width = C64_SCR_WIDTH / 2;
-    else
-        width = C64_SCR_WIDTH;
-
-    // Allocate image structure
-    if ((*pdst = dst = dmImageAlloc(width, C64_SCR_HEIGHT)) == NULL)
-        return DMERR_MALLOC;
-
-    // Set palette
-    dst->pal      = (DMColor *) &dmC64Palette;
-    dst->ncolors  = C64_NCOLORS;
-    dst->constpal = TRUE;
-
-    // Convert
-    if (fmt->convertFrom != NULL)
-        res = fmt->convertFrom(dst, src, doubleMC);
-    else
-        res = dmC64ConvertGenericBMP2Image(dst, src, doubleMC);
-
-    return res;
-}
-
-
-int dmC64DecodeBMP(DMC64Image *img, const Uint8 *buf, const size_t len,
-    const size_t probeOffs, const size_t loadOffs,
-    const DMC64ImageFormat **fmt, const DMC64ImageFormat *forced)
-{
-    // Check for forced format
-    if (forced != NULL)
-        *fmt = forced;
-    else
-    {
-        // Nope, perform a generic probe
-        if (probeOffs >= len)
-            return -200;
-
-        if (dmC64ProbeBMP(buf + probeOffs, len - probeOffs, fmt) == DM_PROBE_SCORE_FALSE)
-            return -201;
-    }
-
-    if (loadOffs >= len)
-        return -203;
-
-    // Decode the bitmap to memory layout
-    if ((*fmt)->decode != NULL)
-        return (*fmt)->decode(img, buf + loadOffs, len - loadOffs, *fmt);
-    else
-        return dmC64DecodeGenericBMP(img, buf + loadOffs, len - loadOffs, *fmt);
-}
--- a/lib64gfx.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,194 +0,0 @@
-/*
- * Functions for reading and converting various restricted
- * C64/etc and/or indexed/paletted graphics formats.
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012 Tecnic Software productions (TNSP)
- *
- * Please read file 'COPYING' for information on license and distribution.
- */
-#ifndef LIB64GFX_H
-#define LIB64GFX_H 1
-
-#include "libgfx.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-// Bitmap constants
-#define C64_SCR_WIDTH          320
-#define C64_SCR_HEIGHT         200
-#define C64_SCR_CH_WIDTH       (C64_SCR_WIDTH/8)
-#define C64_SCR_CH_HEIGHT      (C64_SCR_HEIGHT/8)
-#define C64_SCR_COLOR_SIZE     (C64_SCR_CH_WIDTH * C64_SCR_CH_HEIGHT)
-#define C64_SCR_SCREEN_SIZE    (C64_SCR_CH_WIDTH * C64_SCR_CH_HEIGHT)
-#define C64_SCR_BITMAP_SIZE    (C64_SCR_WIDTH * C64_SCR_HEIGHT/8)
-#define C64_SCR_EXTRADATA      1024
-#define C64_SCR_MAX_BANK       8
-
-// C64 video screen pixel aspect ratio on PAL
-#define C64_SCR_PAR_XY         (0.9365f)
-
-// Sprite constants
-#define C64_SPR_WIDTH          3 // bytes
-#define C64_SPR_HEIGHT         21 // lines
-#define C64_SPR_WIDTH_PX       (8 * C64_SPR_WIDTH)
-#define C64_SPR_SIZE           ((C64_SPR_WIDTH * C64_SPR_HEIGHT) + 1)
-
-// Character constants
-#define C64_CHR_WIDTH          1 // bytes
-#define C64_CHR_HEIGHT         8 // lines
-#define C64_CHR_WIDTH_PX       (8 * C64_CHR_WIDTH)
-#define C64_CHR_SIZE           (C64_CHR_WIDTH * C64_CHR_HEIGHT)
-
-// Etc.
-#define C64_RAM_SIZE           (64*1024)
-#define C64_NCOLORS            16
-#define C64_MAX_COLORS         16
-#define C64_VIDBANK_SIZE       (16*1024)
-#define C64_MAX_SPRITES        (C64_VIDBANK_SIZE / C64_SPR_SIZE)
-#define C64_MAX_CHARS          256
-
-// Different supported C64 bitmap "modes"
-enum
-{
-    D64_FMT_HIRES        = 0x0000,
-    D64_FMT_MC           = 0x0001,
-    D64_FMT_ILACE        = 0x0002,
-    D64_FMT_FLI          = 0x0004,
-
-    D64_FMT_MODE_MASK    = 0x000f,
-
-};
-
-enum
-{
-    D64_FLI_2BANK,
-    D64_FLI_4BANK,
-    D64_FLI_8BANK,
-};
-
-enum
-{
-    D64_ILACE_COLOR,
-    D64_ILACE_RES,
-};
-
-typedef struct
-{
-    BOOL multicolor, xexpand, yexpand;
-    int color, xc, yc;
-    Uint8 data[C64_SPR_HEIGHT][C64_SPR_WIDTH];
-} DMC64Sprite;
-
-enum
-{
-    D64_CHR_GLOBAL,		// use font-global setting
-    D64_CHR_MULTICOLOR,	// character is multicolor
-    D64_CHR_HIRES,
-};
-
-typedef struct
-{
-    int mode, color;
-    Uint8 data[C64_CHR_HEIGHT];
-} DMC64Char;
-
-
-typedef struct
-{
-    BOOL multicolor;
-    int colbg, color, col1, col2;
-    int nglyphs;
-    DMC64Char *glyphs;
-} DMC64Font;
-
-
-
-typedef struct
-{
-    int type,     // Image type (D64_FMT_*)
-        fliType,  // FLI type (if FLI used)
-        laceType, // Interlace type (D64_ILACE_*)
-        laceBank1,
-        laceBank2;
-
-    Uint8 color[C64_SCR_MAX_BANK][C64_SCR_COLOR_SIZE],
-            bitmap[C64_SCR_MAX_BANK][C64_SCR_BITMAP_SIZE],
-            screen[C64_SCR_MAX_BANK][C64_SCR_SCREEN_SIZE],
-            extradata[C64_SCR_EXTRADATA],
-            d020, bgcolor, d022, d023, d024;
-
-    Uint8 charset[C64_MAX_CHARS][C64_CHR_HEIGHT * C64_CHR_WIDTH];
-    DMC64Sprite sprites[C64_MAX_SPRITES];
-} DMC64Image;
-
-
-enum
-{
-    DT_COLOR_RAM,
-    DT_BITMAP,
-    DT_SCREEN_RAM,
-    DT_BGCOLOR,
-    DT_EXTRADATA,
-    
-    DT_DEC_FUNCTION,
-    DT_ENC_FUNCTION,
-    
-    DT_LAST,
-};
-
-
-typedef struct _DMC64EncDecOp
-{
-    int    type;
-    size_t offs;
-    int    bank;
-    size_t size;
-    BOOL   (*decfunction)(DMC64Image *img, const struct _DMC64EncDecOp *op, const Uint8 *buf, const size_t len);
-    BOOL   (*encfunction)(const struct _DMC64EncDecOp *op, Uint8 **buf, size_t *len, const DMC64Image *img);
-} DMC64EncDecOp;
-
-
-typedef struct _DMC64ImageFormat
-{
-    int  type;
-    char *fext;
-    char *name;
-    size_t addr; // Loading address (0 if no loading address)
-    size_t size; // Size, including loading address. Only used in encoding, if even there (0 if no static size)
-    int  (*probe)(const Uint8 *buf, const size_t len, const struct _DMC64ImageFormat *fmt);
-    int  (*decode)(DMC64Image *img, const Uint8 *buf, const size_t len, const struct _DMC64ImageFormat *fmt);
-    int  (*encode)(DMC64Image *img, Uint8 **buf, size_t *len, const struct _DMC64ImageFormat *fmt);
-    int  (*convertFrom)(DMImage *, const DMC64Image *, const BOOL doubleMC);
-    int  (*convertTo)(DMImage *, DMC64Image *);
-
-    int nencdecOps;
-    DMC64EncDecOp encdecOps[16];
-} DMC64ImageFormat;
-
-
-extern const size_t      dmC64DefaultSizes[DT_LAST];
-extern DMColor           dmC64Palette[C64_NCOLORS];
-extern const DMC64ImageFormat  dmC64ImageFormats[];
-extern const int         ndmC64ImageFormats;
-
-
-char *    dmC64GetImageTypeString(char *buf, const size_t len, const int type);
-int       dmC64ConvertCSData(DMImage *img, int xoffs, int yoffs, const Uint8 *inBuf, int width, int height, BOOL multicolor, int *colors);
-
-int       dmC64DecodeGenericBMP(DMC64Image *img, const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt);
-int       dmC64EncodeGenericBMP(Uint8 **pbuf, size_t *plen, const DMC64Image *img, const DMC64ImageFormat *fmt);
-int       dmC64ConvertGenericBMP2Image(DMImage *dst, const DMC64Image *src, const BOOL doubleMC);
-
-int       dmC64ConvertBMP2Image(DMImage **pdst, const DMC64Image *src, const DMC64ImageFormat *fmt, const BOOL doubleMC);
-int       dmC64ProbeBMP(const Uint8 *buf, const size_t len, const DMC64ImageFormat **fmt);
-int       dmC64DecodeBMP(DMC64Image *img, const Uint8 *buf, const size_t len, const size_t probeOffs, const size_t loadOffs, const DMC64ImageFormat **fmt, const DMC64ImageFormat *forced);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // LIB64GFX_H
--- a/libgfx.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1811 +0,0 @@
-/*
- * Functions for reading and converting various restricted
- * C64/etc and/or indexed/paletted graphics formats.
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012 Tecnic Software productions (TNSP)
- *
- * Please read file 'COPYING' for information on license and distribution.
- */
-#include "libgfx.h"
-#include "dmfile.h"
-#include "dmbstr.h"
-
-#ifdef DM_USE_LIBPNG
-#include <png.h>
-#endif
-
-
-BOOL dmCompareColor(const DMColor *c1, const DMColor *c2, BOOL alpha)
-{
-    if (c1->r == c2->r &&
-        c1->g == c2->g &&
-        c1->b == c2->b)
-        return alpha ? (c1->a == c2->a) : TRUE;
-    else
-        return FALSE;
-}
-
-
-DMImage * dmImageAlloc(int width, int height)
-{
-    DMImage *img = dmCalloc(1, sizeof(DMImage));
-    if (img == NULL)
-        return NULL;
-    
-    img->width = img->pitch = width;
-    img->height = height;
-    img->data = dmMalloc(width * height * sizeof(Uint8));
-    if (img->data == NULL)
-    {
-        dmFree(img);
-        return NULL;
-    }
-    
-    return img;
-}
-
-
-void dmImageFree(DMImage *img)
-{
-    if (img != NULL)
-    {
-        if (!img->constpal)
-        {
-            dmFree(img->pal);
-        }
-        dmFree(img->data);
-        dmFree(img);
-    }
-}
-
-
-BOOL dmPaletteAlloc(DMColor **ppal, int ncolors, int ctransp)
-{
-    int i;
-
-    if (ppal == NULL)
-        return FALSE;
-
-    // Allocate desired amount of palette
-    if ((*ppal = dmCalloc(ncolors, sizeof(DMColor))) == NULL)
-        return FALSE;
-
-    // Set alpha values to max, except for transparent color
-    for (i = 0; i < ncolors; i++)
-    {
-        (*ppal)[i].a = (i == ctransp) ? 0 : 255;
-    }
-
-    return TRUE;
-}
-
-
-BOOL dmImageAllocPalette(DMImage *img, int ncolors, int ctransp)
-{
-    if (img == NULL)
-        return FALSE;
-    
-    img->ncolors = ncolors;
-    img->ctransp = ctransp;
-    return dmPaletteAlloc(&(img->pal), ncolors, ctransp);
-}
-
-
-int dmImageGetBytesPerPixel(int format)
-{
-    switch (format)
-    {
-        case DM_IFMT_PALETTE   : return 1;
-
-        case DM_IFMT_RGB_PLANE :
-        case DM_IFMT_RGB       : return 3;
-
-        case DM_IFMT_RGBA      : return 4;
-
-        default:                 return 0;
-    }
-}
-
-
-static BOOL dmReadPaletteData(FILE *fp, DMColor *pal, int ncolors)
-{
-    int i;
-    
-    for (i = 0; i < ncolors; i++)
-    {
-        Uint8 colR, colG, colB;
-        if (!dm_fread_byte(fp, &colR) ||
-            !dm_fread_byte(fp, &colG) ||
-            !dm_fread_byte(fp, &colB))
-            return FALSE;
-
-        pal[i].r = colR;
-        pal[i].g = colG;
-        pal[i].b = colB;
-    }
-
-    return TRUE;
-}
-
-
-int dmWriteImageData(DMImage *img, void *cbdata, int (*writeRowCB)(void *, Uint8 *, size_t), const DMImageSpec *spec)
-{
-    int x, y, yscale, xscale, res = 0, rowSize, rowWidth;
-    Uint8 *row = NULL;
-
-    // Allocate memory for row buffer
-    rowWidth = img->width * spec->scale;
-    rowSize = rowWidth * dmImageGetBytesPerPixel(spec->format);
-
-    if ((row = dmMalloc(rowSize + 16)) == NULL)
-    {
-        res = DMERR_MALLOC;
-        goto done;
-    }
-
-    // Generate the image
-    for (y = 0; y < img->height; y++)
-    {
-        Uint8   *ptr1 = row,
-                *ptr2 = ptr1 + rowWidth,
-                *ptr3 = ptr2 + rowWidth;
-
-        for (x = 0; x < img->width; x++)
-        {
-            Uint8 c = img->data[(y * img->pitch) + x], qr, qg, qb, qa;
-            switch (spec->format)
-            {
-                case DM_IFMT_PALETTE:
-                    for (xscale = 0; xscale < spec->scale; xscale++)
-                        *ptr1++ = c;
-                    break;
-
-                case DM_IFMT_RGBA:
-                    qr = img->pal[c].r;
-                    qg = img->pal[c].g;
-                    qb = img->pal[c].b;
-                    qa = img->pal[c].a;
-                
-                    for (xscale = 0; xscale < spec->scale; xscale++)
-                    {
-                        *ptr1++ = qr;
-                        *ptr1++ = qg;
-                        *ptr1++ = qb;
-                        *ptr1++ = qa;
-                    }
-                    break;
-
-                case DM_IFMT_RGB:
-                    qr = img->pal[c].r;
-                    qg = img->pal[c].g;
-                    qb = img->pal[c].b;
-                
-                    for (xscale = 0; xscale < spec->scale; xscale++)
-                    {
-                        *ptr1++ = qr;
-                        *ptr1++ = qg;
-                        *ptr1++ = qb;
-                    }
-                    break;
-
-                case DM_IFMT_RGB_PLANE:
-                    qr = img->pal[c].r;
-                    qg = img->pal[c].g;
-                    qb = img->pal[c].b;
-                
-                    for (xscale = 0; xscale < spec->scale; xscale++)
-                    {
-                        *ptr1++ = qr;
-                        *ptr2++ = qg;
-                        *ptr3++ = qb;
-                    }
-                    break;
-            }
-        }
-
-        for (yscale = 0; yscale < spec->scale; yscale++)
-        {
-            if ((res = writeRowCB(cbdata, row, rowSize)) != DMERR_OK)
-                goto done;
-        }
-    }
-
-done:
-    dmFree(row);    
-    return res;
-}
-
-
-#define DMCOL(x) (((x) >> 4) & 0xf)
-
-int dmWriteIFFMasterRAWPalette(FILE *fp, DMImage *img, int ncolors,
-    const char *indent, const char *type)
-{
-    int i;
-
-    for (i = 0; i < ncolors; i++)
-    {
-        int color;
-        if (i < img->ncolors)
-        {
-            color = (DMCOL(img->pal[i].r) << 8) |
-                    (DMCOL(img->pal[i].g) << 4) |
-                    (DMCOL(img->pal[i].b));
-        }
-        else
-            color = 0;
-
-        fprintf(fp, "%s%s $%04X\n",
-            indent != NULL ? indent : "\t",
-            type != NULL ? type : "dc.w",
-            color);
-    }
-
-    return DMERR_OK;
-}
-
-
-int dmWriteRAWImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec)
-{
-    int xc, yc, plane, res;
-    DMBitStreamContext bs;
-    
-    if ((res = dmInitBitStreamFILE(&bs, fp)) != DMERR_OK)
-        return res;
-
-    if (spec->interleave)
-    {
-        // Output bitplanes in interleaved format (each plane of line sequentially)
-        for (yc = 0; yc < img->height; yc++)
-        {
-            for (plane = 0; plane < spec->nplanes; plane++)
-            {
-                Uint8 *sp = img->data + yc * img->pitch;
-                for (xc = 0; xc < img->width; xc++)
-                {
-                    if (!dmPutBits(&bs, (sp[xc] & (1 << plane)) ? 1 : 0, 1))
-                        return DMERR_FWRITE;
-                }
-            }
-        }
-    }
-    else
-    {
-        // Output each bitplane in sequence
-        for (plane = 0; plane < spec->nplanes; plane++)
-        {
-            for (yc = 0; yc < img->height; yc++)
-            {
-                Uint8 *sp = img->data + yc * img->pitch;
-                for (xc = 0; xc < img->width; xc++)
-                {
-                    if (!dmPutBits(&bs, (sp[xc] & (1 << plane)) ? 1 : 0, 1))
-                        return DMERR_FWRITE;
-                }
-            }
-        }
-    }
-    
-    return dmFlushBitStream(&bs);
-}
-
-
-int dmWriteRAWImage(const char *filename, DMImage *img, DMImageSpec *spec)
-{
-    FILE *fp;
-    int res;
-
-    if ((fp = fopen(filename, "wb")) == NULL)
-    {
-        dmError("RAW: Could not open file '%s' for writing.\n", filename);
-        return DMERR_FOPEN;
-    }
-
-    res = dmWriteRAWImageFILE(fp, img, spec);
-
-    fclose(fp);
-    return res;
-}
-
-
-static int dmWritePPMRow(void *cbdata, Uint8 *row, size_t len)
-{
-    if (fwrite(row, sizeof(Uint8), len, (FILE *) cbdata) == len)
-        return DMERR_OK;
-    else
-        return DMERR_FWRITE;
-}
-
-
-int dmWritePPMImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec)
-{
-    // Write PPM header
-    fprintf(fp,
-        "P6\n%d %d\n255\n",
-        img->width * spec->scale,
-        img->height * spec->scale);
-
-    // Write image data
-    spec->format = DM_IFMT_RGB;
-    return dmWriteImageData(img, (void *) fp, dmWritePPMRow, spec);
-}
-
-
-int dmWritePPMImage(const char *filename, DMImage *img, DMImageSpec *spec)
-{
-    FILE *fp;
-    int res;
-
-    // Create output file
-    if ((fp = fopen(filename, "wb")) == NULL)
-    {
-        dmError("PPM: could not open file '%s' for writing.\n", filename);
-        return DMERR_FOPEN;
-    }
-
-    res = dmWritePPMImageFILE(fp, img, spec);
-
-    fclose(fp);
-    return res;
-}
-
-
-#ifdef DM_USE_LIBPNG
-static int dmWritePNGRow(void *cbdata, Uint8 *row, size_t len)
-{
-    png_structp png_ptr = cbdata;
-    (void) len;
-
-    if (setjmp(png_jmpbuf(png_ptr)))
-        return DMERR_INTERNAL;
-
-    png_write_row(png_ptr, row);
-
-    return DMERR_OK;
-}
-
-
-int dmWritePNGImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec)
-{
-    png_structp png_ptr = NULL;
-    png_infop info_ptr = NULL;
-    png_colorp palette = NULL;
-    int fmt, res = DMERR_OK;
-
-    // Create PNG structures
-    png_ptr = png_create_write_struct(
-        PNG_LIBPNG_VER_STRING,
-        NULL, NULL, NULL);
-
-    if (png_ptr == NULL)
-    {
-        dmError("PNG: png_create_write_struct() failed.\n");
-        res = DMERR_MALLOC;
-        goto error;
-    }
-    
-    info_ptr = png_create_info_struct(png_ptr);
-    if (info_ptr == NULL)
-    {
-        dmError("PNG: png_create_info_struct(%p) failed.\n", png_ptr);
-        res = DMERR_INIT_FAIL;
-        goto error;
-    }
-    
-    if (setjmp(png_jmpbuf(png_ptr)))
-    {
-        dmError("PNG: Error during image writing..\n");
-        res = DMERR_INIT_FAIL;
-        goto error;
-    }
-
-    png_init_io(png_ptr, fp);
-
-    // Write PNG header info
-    switch (spec->format)
-    {
-        case DM_IFMT_PALETTE: fmt = PNG_COLOR_TYPE_PALETTE; break;
-        case DM_IFMT_RGB    : fmt = PNG_COLOR_TYPE_RGB; break;
-        case DM_IFMT_RGBA   : fmt = PNG_COLOR_TYPE_RGB_ALPHA; break;
-        default:
-            dmError("PNG: Unsupported image format %d.\n", spec->format);
-            res = DMERR_NOT_SUPPORTED;
-            goto error;
-    }
- 
-    png_set_IHDR(png_ptr, info_ptr,
-        img->width * spec->scale,
-        img->height * spec->scale,
-        8,                    /* bits per component */
-        fmt,
-        PNG_INTERLACE_NONE,
-        PNG_COMPRESSION_TYPE_DEFAULT,
-        PNG_FILTER_TYPE_DEFAULT);
-
-    dmMsg(3, "PNG: %d x %d, depth=%d, type=%d\n",
-        img->width * spec->scale,
-        img->height * spec->scale,
-        8, fmt);
-
-    // Palette
-    if (spec->format == DM_IFMT_PALETTE)
-    {
-        int i;
-
-        palette = png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof(png_color));
-        if (palette == NULL)
-        {
-            dmError("PNG: Could not allocate palette structure.");
-            res = DMERR_MALLOC;
-            goto error;
-        }
-        
-        memset(palette, 0, PNG_MAX_PALETTE_LENGTH * sizeof(png_color));
-
-        for (i = 0; i < img->ncolors; i++)
-        {
-            palette[i].red   = img->pal[i].r;
-            palette[i].green = img->pal[i].g;
-            palette[i].blue  = img->pal[i].b;
-        }
-
-        png_set_PLTE(png_ptr, info_ptr, palette, img->ncolors);
-    }
-
-//    png_set_gAMA(png_ptr, info_ptr, 2.2);
-
-    png_write_info(png_ptr, info_ptr);
-
-
-    // Write compressed image data
-    dmWriteImageData(img, (void *) png_ptr, dmWritePNGRow, spec);
-
-    // Write footer
-    png_write_end(png_ptr, NULL);
-
-error:
-    png_free(png_ptr, palette);
-    palette = NULL;
-
-    if (png_ptr && info_ptr)
-        png_destroy_write_struct(&png_ptr, &info_ptr);
-
-    return res;
-}
-
-
-int dmWritePNGImage(const char *filename, DMImage *img, DMImageSpec *spec)
-{
-    int res;
-    FILE *fp;
-
-    if ((fp = fopen(filename, "wb")) == NULL)
-    {
-        dmError("PNG: could not open file '%s' for writing.\n", filename);
-        return DMERR_FOPEN;
-    }
-
-    res = dmWritePNGImageFILE(fp, img, spec);
-
-    fclose(fp);
-    return res;
-}
-
-
-int dmReadPNGImageFILE(FILE *fp, DMImage **pimg)
-{
-    png_structp png_ptr = NULL;
-    png_infop info_ptr = NULL;
-    png_colorp palette = NULL;
-    png_bytep *row_pointers = NULL;
-    png_bytep trans = NULL;
-    png_uint_32 width, height;
-    int i, bit_depth, color_type, ncolors, ntrans;
-    int res = DMERR_OK;
-    DMImage *img;
-
-    // Create PNG structures
-    png_ptr = png_create_read_struct(
-        PNG_LIBPNG_VER_STRING,
-        NULL, NULL, NULL);
-
-    if (png_ptr == NULL)
-    {
-        dmError("PNG: png_create_write_struct() failed.\n");
-        res = DMERR_MALLOC;
-        goto error;
-    }
-
-    info_ptr = png_create_info_struct(png_ptr);
-    if (info_ptr == NULL)
-    {
-        dmError("PNG: png_create_info_struct(%p) failed.\n", png_ptr);
-        res = DMERR_INIT_FAIL;
-        goto error;
-    }
-    
-    if (setjmp(png_jmpbuf(png_ptr)))
-    {
-        dmError("PNG: Error during image reading..\n");
-        res = DMERR_INIT_FAIL;
-        goto error;
-    }
-
-    png_init_io(png_ptr, fp);
-
-    // Read image information
-    png_read_info(png_ptr, info_ptr);
-
-    png_get_IHDR(png_ptr, info_ptr, &width, &height,
-        &bit_depth, &color_type, NULL, NULL, NULL);
-
-    if (width < 1 || height < 1)
-    {
-        dmError("PNG: Invalid width or height (%d x %d)\n",
-            width, height);
-        res = DMERR_INVALID_DATA;
-        goto error;
-    }
-
-    switch (color_type)
-    {
-        case PNG_COLOR_TYPE_GRAY:
-            if (bit_depth < 8)
-                png_set_expand_gray_1_2_4_to_8(png_ptr);
-
-            if (bit_depth > 8)
-            {
-                dmError("PNG: Unsupported bit depth for grayscale image: %d\n",
-                    bit_depth);
-                res = DMERR_NOT_SUPPORTED;
-                goto error;
-            }
-            break;
-        
-        case PNG_COLOR_TYPE_PALETTE:
-            png_set_packing(png_ptr);
-            break;
-
-        default:
-            dmError("PNG: RGB/RGBA images not supported for loading.\n");
-            res = DMERR_NOT_SUPPORTED;
-            goto error;
-    }
-
-    // Allocate image
-    dmMsg(3, "PNG: %d x %d, depth=%d, type=%d\n",
-        width, height, bit_depth, color_type);
-
-    if ((*pimg = img = dmImageAlloc(width, height)) == NULL)
-    {
-        dmError("PNG: Could not allocate image data.\n");
-        res = DMERR_MALLOC;
-        goto error;
-    }
-
-    // ...
-    row_pointers = png_malloc(png_ptr, height * sizeof(png_bytep));
-    for (i = 0; i < img->height; i++)
-        row_pointers[i] = img->data + (i * img->pitch);
-
-    png_read_image(png_ptr, row_pointers);
-
-    png_read_end(png_ptr, NULL);
-
-    // Create palette
-    switch (color_type)
-    {
-        case PNG_COLOR_TYPE_GRAY:
-            ncolors = 256;
-            dmMsg(3, "PNG: Generating %d color grayscale palette.\n", ncolors);
-
-            if (!dmImageAllocPalette(img, ncolors, -1))
-            {
-                res = DMERR_MALLOC;
-                goto error;
-            }
-
-            for (i = 0; i < img->ncolors; i++)
-            {
-                img->pal[i].r = img->pal[i].g = img->pal[i].b = i;
-            }
-            break;
-        
-        case PNG_COLOR_TYPE_PALETTE:
-            png_get_PLTE(png_ptr, info_ptr, &palette, &ncolors);
-            dmMsg(3, "PNG: Palette of %d colors found.\n", ncolors);            
-            if (ncolors > 0 && palette != NULL)
-            {
-                if (!dmImageAllocPalette(img, ncolors, -1))
-                {
-                    res = DMERR_MALLOC;
-                    goto error;
-                }
-
-                for (i = 0; i < img->ncolors; i++)
-                {
-                    img->pal[i].r = palette[i].red;
-                    img->pal[i].g = palette[i].green;
-                    img->pal[i].b = palette[i].blue;
-                }
-            }
-            break;
-    }
-
-    if (color_type == PNG_COLOR_TYPE_PALETTE ||
-        color_type == PNG_COLOR_TYPE_GRAY)
-    {
-        png_get_tRNS(png_ptr, info_ptr, &trans, &ntrans, NULL);
-        if (trans != NULL && ntrans > 0)
-        {
-            for (i = 0; i < img->ncolors && i < ntrans; i++)
-            {
-                img->pal[i].a = trans[i];
-                if (img->ctransp < 0 && trans[i] == 0)
-                    img->ctransp = i;
-            }
-        }
-    }    
-
-error:
-//    png_free(png_ptr, palette);
-
-    if (png_ptr && info_ptr)
-        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
-
-    return res;
-}
-
-
-int dmReadPNGImage(const char *filename, DMImage **img)
-{
-    int res;
-    FILE *fp;
-
-    if ((fp = fopen(filename, "rb")) == NULL)
-    {
-        dmError("PNG: Could not open file '%s' for reading.\n", filename);
-        return DMERR_FOPEN;
-    }
-
-    res = dmReadPNGImageFILE(fp, img);
-
-    fclose(fp);
-    return res;
-}
-#endif
-
-
-typedef struct
-{
-    Uint8 r,g,b;
-} DMPCXColor;
-
-
-typedef struct
-{
-    Uint8 manufacturer,
-            version,
-            encoding,
-            bpp;
-    Uint16 xmin, ymin, xmax, ymax;
-    Uint16 hres, vres;
-    DMPCXColor colormap[16];
-    Uint8 reserved;
-    Uint8 nplanes;
-    Uint16 bpl;
-    Uint16 palinfo;
-    Uint8 filler[58];
-} DMPCXHeader;
-
-
-typedef struct
-{
-    DMPCXHeader *header;
-    Uint8 *buf;
-    size_t bufLen, bufOffs;
-    int format;
-    FILE *fp;
-} DMPCXData;
-
-
-static inline Uint8 dmPCXGetByte(Uint8 *row, const size_t len, const size_t soffs)
-{
-    return (soffs < len) ? row[soffs] : 0;
-}
-
-static BOOL dmPCXFlush(DMPCXData *pcx)
-{
-    BOOL ret = TRUE;
-    if (pcx->bufOffs > 0)
-        ret = fwrite(pcx->buf, sizeof(Uint8), pcx->bufOffs, pcx->fp) == pcx->bufOffs;
-    pcx->bufOffs = 0;
-    return ret;
-}
-
-static inline BOOL dmPCXPutByte(DMPCXData *pcx, const Uint8 val)
-{
-    if (pcx->bufOffs < pcx->bufLen)
-    {
-        pcx->buf[pcx->bufOffs++] = val;
-        return TRUE;
-    }
-    else
-        return dmPCXFlush(pcx);
-}
-
-static int dmWritePCXRow(void *cbdata, Uint8 *row, size_t len)
-{
-    DMPCXData *pcx = (DMPCXData *) cbdata;
-    int plane;
-    size_t soffs = 0;
-    
-//    fprintf(stderr, "%d, %d * %d = %d\n", len, pcx->header->bpl, pcx->header->nplanes, pcx->header->nplanes * pcx->header->bpl);
-
-    pcx->bufOffs = 0;
-
-    for (plane = 0; plane < pcx->header->nplanes; plane++)
-    {
-        Uint8 data = dmPCXGetByte(row, len, soffs++),
-              count = 1;
-
-//        size_t blen = pcx->header->bpl * pcx->header->nplanes;
-        size_t blen = pcx->header->bpl;
-        while (soffs < blen)
-        {
-            if (data == dmPCXGetByte(row, len, soffs) && count < 63)
-            {
-                count++;
-                soffs++;
-            }
-            else
-            {
-                if (count == 1 && (data & 0xC0) != 0xC0)
-                {
-                    if (!dmPCXPutByte(pcx, data))
-                        return DMERR_FWRITE;
-                }
-                else
-                {
-                    if (!dmPCXPutByte(pcx, 0xC0 | count) ||
-                        !dmPCXPutByte(pcx, data))
-                        return DMERR_FWRITE;
-                }
-
-                data = dmPCXGetByte(row, len, soffs++);
-                count = 1;
-            }
-        }
-
-        if (count > 1)
-        {
-            if (!dmPCXPutByte(pcx, 0xC0 | count) ||
-                !dmPCXPutByte(pcx, data))
-                return DMERR_FWRITE;
-        }
-
-        if (!dmPCXFlush(pcx))
-            return DMERR_FWRITE;
-    }
-
-
-    return DMERR_OK;
-}
-
-
-int dmWritePCXImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec)
-{
-    DMPCXData pcx;
-    DMPCXHeader hdr;
-    int res;
-
-    // Create output file
-    pcx.buf    = NULL;
-    pcx.format = spec->paletted ? DM_IFMT_PALETTE : DM_IFMT_RGB_PLANE;
-    pcx.header = &hdr;
-    pcx.fp     = fp;
-
-    // Create PCX header
-    memset(&hdr, 0, sizeof(hdr));
-    if (spec->paletted)
-    {
-        int i;
-        for (i = 0; i < (img->ncolors > 16 ? 16 : img->ncolors); i++)
-        {
-            hdr.colormap[i].r = img->pal[i].r;
-            hdr.colormap[i].g = img->pal[i].g;
-            hdr.colormap[i].b = img->pal[i].b;
-        }
-    }
-    hdr.manufacturer = 10;
-    hdr.version      = 5;
-    hdr.encoding     = 1;
-    hdr.bpp          = 8;
-    hdr.hres         = img->width * spec->scale;
-    hdr.vres         = img->height * spec->scale;
-    hdr.xmin         = hdr.ymin = 0;
-    hdr.xmax         = hdr.hres - 1;
-    hdr.ymax         = hdr.vres - 1;
-    hdr.nplanes      = dmImageGetBytesPerPixel(pcx.format);
-    hdr.palinfo      = 1;
-
-    res = (img->width * spec->scale);
-    hdr.bpl = res / 2;
-    if (res % 2) hdr.bpl++;
-    hdr.bpl *= 2;
-
-    dmMsg(3, "PCX: paletted=%d, nplanes=%d, bpp=%d, bpl=%d\n",
-        spec->paletted, hdr.nplanes, hdr.bpp, hdr.bpl);
-
-    pcx.bufLen       = hdr.bpl * 4;
-    if ((pcx.buf = dmMalloc(pcx.bufLen)) == NULL)
-    {
-        dmError("PCX: Could not allocate %d bytes for RLE compression buffer.\n",
-            pcx.bufLen);
-        res = DMERR_MALLOC;
-        goto error;
-    }
-
-    // Write PCX header
-    if (!dm_fwrite_byte(pcx.fp, hdr.manufacturer) ||
-        !dm_fwrite_byte(pcx.fp, hdr.version) ||
-        !dm_fwrite_byte(pcx.fp, hdr.encoding) ||
-        !dm_fwrite_byte(pcx.fp, hdr.bpp))
-    {
-        dmError("PCX: Could not write basic header data.\n");
-        res = DMERR_FWRITE;
-        goto error;
-    }
-    
-    if (!dm_fwrite_le16(pcx.fp, hdr.xmin) ||
-        !dm_fwrite_le16(pcx.fp, hdr.ymin) ||
-        !dm_fwrite_le16(pcx.fp, hdr.xmax) ||
-        !dm_fwrite_le16(pcx.fp, hdr.ymax) ||
-        !dm_fwrite_le16(pcx.fp, hdr.hres) ||
-        !dm_fwrite_le16(pcx.fp, hdr.vres))
-    {
-        dmError("PCX: Could not write image dimensions.\n");
-        res = DMERR_FWRITE;
-        goto error;
-    }
-
-    if (!dm_fwrite_str(pcx.fp, (Uint8 *) &hdr.colormap, sizeof(hdr.colormap)))
-    {
-        dmError("PCX: Could not write colormap.\n");
-        res = DMERR_FWRITE;
-        goto error;
-    }
-    
-    if (!dm_fwrite_byte(pcx.fp, hdr.reserved) ||
-        !dm_fwrite_byte(pcx.fp, hdr.nplanes) ||
-        !dm_fwrite_le16(pcx.fp, hdr.bpl) ||
-        !dm_fwrite_le16(pcx.fp, hdr.palinfo) ||
-        !dm_fwrite_str(pcx.fp, (Uint8 *) &hdr.filler, sizeof(hdr.filler)))
-    {
-        dmError("PCX: Could not write header remainder.\n");
-        res = DMERR_FWRITE;
-        goto error;
-    }
-
-    // Write image data
-    res = dmWriteImageData(img, (void *) &pcx, dmWritePCXRow, spec);
-
-    // Write VGA palette
-    if (spec->paletted)
-    {
-        int i;
-        dm_fwrite_byte(pcx.fp, 0x0C);
-        dmMsg(3, "PCX: Writing palette of %d active entries.\n", img->ncolors);
-
-        for (i = 0; i < img->ncolors; i++)
-        {
-            dm_fwrite_byte(pcx.fp, img->pal[i].r);
-            dm_fwrite_byte(pcx.fp, img->pal[i].g);
-            dm_fwrite_byte(pcx.fp, img->pal[i].b);
-        }
-
-        // Pad the palette, if necessary        
-        for (; i < 256; i++)
-        {
-            dm_fwrite_byte(pcx.fp, 0);
-            dm_fwrite_byte(pcx.fp, 0);
-            dm_fwrite_byte(pcx.fp, 0);
-        }
-    }
-    
-error:
-    dmFree(pcx.buf);
-    return res;
-}
-
-
-int dmWritePCXImage(const char *filename, DMImage *img, DMImageSpec *spec)
-{
-    FILE *fp;
-    int res;
-
-    if ((fp = fopen(filename, "wb")) == NULL)
-    {
-        dmError("PCX: Could not open file '%s' for writing.\n", filename);
-        return DMERR_FOPEN;
-    }
-    
-    res = dmWritePCXImageFILE(fp, img, spec);
-    
-    fclose(fp);
-    return res;
-}
-
-
-static BOOL dmPCXDecodeRLERow(FILE *fp, Uint8 *buf, const size_t bufLen)
-{
-    size_t offs = 0;
-    do
-    {
-        int count;
-        Uint8 data;
-
-        if (!dm_fread_byte(fp, &data))
-            return FALSE;
-        
-        if ((data & 0xC0) == 0xC0)
-        {
-            count = data & 0x3F;
-            if (!dm_fread_byte(fp, &data))
-                return FALSE;
-        }
-        else
-            count = 1;
-
-        while (count-- && offs < bufLen)
-            buf[offs++] = data;
-
-    } while (offs < bufLen);
-
-    return TRUE;
-}
-
-
-int dmReadPCXImageFILE(FILE *fp, DMImage **pimg)
-{
-    DMImage *img;
-    DMPCXData pcx;
-    DMPCXHeader hdr;
-    BOOL paletted;
-    int res = 0, yc, xc;
-    Uint8 *dp;
-
-    pcx.buf = NULL;
-
-    // Read PCX header
-    if (!dm_fread_byte(fp, &hdr.manufacturer) ||
-        !dm_fread_byte(fp, &hdr.version) ||
-        !dm_fread_byte(fp, &hdr.encoding) ||
-        !dm_fread_byte(fp, &hdr.bpp))
-    {
-        dmError("PCX: Could not read basic header data.\n");
-        res = DMERR_FREAD;
-        goto error;
-    }
-    
-    if (hdr.manufacturer != 10 ||
-        hdr.version != 5 ||
-        hdr.encoding != 1 ||
-        hdr.bpp != 8)
-    {
-        dmError("PCX: Not a PCX file, or unsupported variant.\n");
-        res = DMERR_FREAD;
-        goto error;
-    }
-    
-    if (!dm_fread_le16(fp, &hdr.xmin) ||
-        !dm_fread_le16(fp, &hdr.ymin) ||
-        !dm_fread_le16(fp, &hdr.xmax) ||
-        !dm_fread_le16(fp, &hdr.ymax) ||
-        !dm_fread_le16(fp, &hdr.hres) ||
-        !dm_fread_le16(fp, &hdr.vres))
-    {
-        dmError("PCX: Could not read image dimensions.\n");
-        res = DMERR_FREAD;
-        goto error;
-    }
-
-    if (!dm_fread_str(fp, (Uint8 *) &hdr.colormap, sizeof(hdr.colormap)))
-    {
-        dmError("PCX: Could not read colormap.\n");
-        res = DMERR_FREAD;
-        goto error;
-    }
-    
-    if (!dm_fread_byte(fp, &hdr.reserved) ||
-        !dm_fread_byte(fp, &hdr.nplanes) ||
-        !dm_fread_le16(fp, &hdr.bpl) ||
-        !dm_fread_le16(fp, &hdr.palinfo) ||
-        !dm_fread_str(fp, (Uint8 *) &hdr.filler, sizeof(hdr.filler)))
-    {
-        dmError("PCX: Could not read header remainder.\n");
-        res = DMERR_FREAD;
-        goto error;
-    }
-    
-    if (hdr.nplanes != 3 && hdr.nplanes != 1)
-    {
-        dmError("PCX: Unsupported number of bitplanes %d.\n", hdr.nplanes);
-        res = DMERR_FREAD;
-        goto error;
-    }
-
-    // Allocate image
-    if ((*pimg = img = dmImageAlloc(hdr.xmax - hdr.xmin + 1, hdr.ymax - hdr.ymin + 1)) == NULL)
-    {
-        dmError("PCX: Could not allocate image structure.\n");
-        res = DMERR_MALLOC;
-        goto error;
-    }
-
-    paletted = hdr.nplanes == 1;
-    pcx.bufLen = hdr.nplanes * hdr.bpl;
-    if ((pcx.buf = dmMalloc(pcx.bufLen)) == NULL)
-    {
-        dmError("PCX: Could not allocate RLE buffer.\n");
-        res = DMERR_MALLOC;
-        goto error;
-    }
-
-    // Read image data
-    dp = img->data;
-    for (yc = 0; yc < img->height; yc++)
-    {
-        // Decode row of RLE'd data
-        if (!dmPCXDecodeRLERow(fp, pcx.buf, pcx.bufLen))
-        {
-            dmError("PCX: Error decoding RLE data.\n");
-            res = DMERR_INVALID_DATA;
-            goto error;
-        }
-        
-        // Decode bitplanes
-        switch (hdr.nplanes)
-        {
-            case 1:
-                memcpy(dp, pcx.buf, img->width);
-                break;
-            
-            case 3:
-                {
-                    Uint8 *dptr = dp,
-                            *sptr1 = pcx.buf,
-                            *sptr2 = sptr1 + hdr.bpl,
-                            *sptr3 = sptr2 + hdr.bpl;
-
-                    for (xc = 0; xc < img->width; xc++)
-                    {
-                        *dptr++ = *sptr1++;
-                        *dptr++ = *sptr2++;
-                        *dptr++ = *sptr3++;
-                    }
-                }
-                break;
-        }
-        
-        dp += img->pitch;
-    }
-
-    // Read VGA palette
-    if (paletted)
-    {
-        int i, ncolors;
-        Uint8 tmpb;
-        BOOL read;
-
-        if (!dm_fread_byte(fp, &tmpb) || tmpb != 0x0C)
-        {
-            read = FALSE;
-            ncolors = 16;
-        }
-        else
-        {
-            read = TRUE;
-            ncolors = 256;
-        }
-
-        if (!dmImageAllocPalette(img, ncolors, -1))
-        {
-            dmError("PCX: Could not allocate palette data!\n");
-            res = DMERR_MALLOC;
-            goto error;
-        }
-        
-        if (read)
-        {
-            if (!dmReadPaletteData(fp, img->pal, ncolors))
-            {
-                dmError("PCX: Error reading palette.\n");
-                return DMERR_FREAD;
-            }
-        }
-        else
-        {
-            for (i = 0; i < img->ncolors; i++)
-            {
-                if (i < 16)
-                {
-                    img->pal[i].r = hdr.colormap[i].r;
-                    img->pal[i].g = hdr.colormap[i].g;
-                    img->pal[i].b = hdr.colormap[i].b;
-                }
-            }
-        }
-    }
-
-error:
-    dmFree(pcx.buf);
-    return res;
-}
-
-
-int dmReadPCXImage(const char *filename, DMImage **pimg)
-{
-    FILE *fp;
-    int res;
-
-    if ((fp = fopen(filename, "rb")) == NULL)
-    {
-        dmError("PCX: Could not open file '%s' for reading.\n", filename);
-        return -15;
-    }
-    
-    res = dmReadPCXImageFILE(fp, pimg);
-
-    fclose(fp);
-    return res;
-}
-
-
-#define IFF_ID_FORM        0x464F524D // "FORM"
-#define IFF_ID_ILBM        0x494C424D // "ILBM"
-#define IFF_ID_PBM         0x50424D20 // "PBM "
-#define IFF_ID_BMHD        0x424D4844 // "BMHD"
-#define IFF_ID_CMAP        0x434D4150 // "CMAP"
-#define IFF_ID_BODY        0x424F4459 // "BODY"
-#define IFF_ID_CAMG        0x43414D47 // "CAMG"
-
-#define IFF_MASK_NONE      0
-#define IFF_MASK_HAS_MASK  1
-#define IFF_MASK_TRANSP    2
-#define IFF_MASK_LASSO     3
-
-#define IFF_COMP_NONE      0
-#define IFF_COMP_BYTERUN1  1
-
-#define IFF_CAMG_LACE      0x00000004
-#define IFF_CAMG_HALFBRITE 0x00000080
-#define IFF_CAMG_HAM       0x00000800
-
-typedef struct
-{
-    Uint32 id;
-    Uint32 size;
-    int count;
-    char str[6];
-} DMIFFChunk;
-
-
-typedef struct
-{
-    Uint16 w, h;
-    Sint16 x, y;
-    Uint8  nplanes;
-    Uint8  masking;
-    Uint8  compression;
-    Uint8  pad1;
-    Uint16 transp;
-    Uint8  xasp, yasp;
-    Sint16 pagew, pageh;
-} DMIFFBMHD;
-
-
-typedef struct
-{
-    DMIFFChunk chBMHD, chCMAP, chBODY;
-    DMIFFBMHD bmhd;
-    Uint32 camg;
-    int ncolors;
-    DMColor *pal;
-    BOOL paletted, planar;
-} DMIFF;
-
-
-static BOOL dmReadIFFChunk(FILE *fp, DMIFFChunk *chunk)
-{
-    if (!dm_fread_be32(fp, &chunk->id) ||
-        !dm_fread_be32(fp, &chunk->size))
-    {
-        dmError("ILBM: Could not read IFF chunk header.\n");
-        return FALSE;
-    }
-    else
-        return TRUE;
-}
-
-static char * dmGetIFFChunkID(DMIFFChunk *chunk)
-{
-    chunk->str[0] = (chunk->id >> 24) & 0xff;
-    chunk->str[1] = (chunk->id >> 16) & 0xff;
-    chunk->str[2] = (chunk->id >> 8) & 0xff;
-    chunk->str[3] = (chunk->id) & 0xff;
-    chunk->str[4] = 0;
-    return chunk->str;
-}
-
-static BOOL dmSkipIFFChunkRest(FILE *fp, const DMIFFChunk *chunk, const Uint32 used)
-{
-    if (chunk->size > used)
-    {
-        dmMsg(4, "ILBM: Skipping %d bytes (%d of %d consumed)\n",
-            chunk->size - used, used, chunk->size);
-        return fseeko(fp, chunk->size - used, SEEK_CUR) == 0;
-    }
-    else
-        return TRUE;
-}
-
-static BOOL dmCheckIFFChunk(DMIFFChunk *dest, DMIFFChunk *chunk,
-    const BOOL multi, const Uint32 minSize)
-{
-    if (dest->count > 0 && !multi)
-    {
-        dmError("ILBM: Multiple instances of chunk %s found.\n",
-            dmGetIFFChunkID(chunk));
-        return FALSE;
-    }
-    
-    dest->count++;
-
-    if (chunk->size < minSize)
-        return FALSE;
-    
-    return TRUE;
-}
-
-
-static BOOL dmIFFDecodeByteRun1Row(FILE *fp, Uint8 *buf, const size_t bufLen)
-{
-    size_t offs = 0;
-    do
-    {
-        Sint8 dcount;
-        Uint8 data;
-
-        if (!dm_fread_byte(fp, (Uint8 *) &dcount))
-            return FALSE;
-        
-        if (dcount == -128)
-        {
-            if (!dm_fread_byte(fp, &data))
-                return FALSE;
-        }
-        else
-        if (dcount < 0)
-        {
-            int count = (-dcount) + 1;
-            if (!dm_fread_byte(fp, &data))
-                return FALSE;
-
-            while (count-- && offs < bufLen)
-                buf[offs++] = data;
-        }
-        else
-        {
-            int count = dcount + 1;
-            while (count-- && offs < bufLen)
-            {
-                if (!dm_fread_byte(fp, &data))
-                    return FALSE;
-
-                buf[offs++] = data;
-            }
-        }
-    } while (offs < bufLen);
-
-    return TRUE;
-}
-
-
-static BOOL dmIFFReadOneRow(FILE *fp, DMIFF *iff, Uint8 *buf, const size_t bufLen)
-{
-    if (iff->bmhd.compression == IFF_COMP_BYTERUN1)
-        return dmIFFDecodeByteRun1Row(fp, buf, bufLen);
-    else
-        return dm_fread_str(fp, buf, bufLen);
-}
-
-
-void dmDecodeBitPlane(Uint8 *dp, Uint8 *src, const int width, const int nplane)
-{
-    int xc;
-    for (xc = 0; xc < width; xc++)
-    {
-        const Uint8 data = (src[xc / 8] >> (7 - (xc & 7))) & 1;
-        dp[xc] |= (data << nplane);
-    }
-}
-
-
-int dmDecodeILBMBody(FILE *fp, DMIFF *iff, DMImage **pimg, Uint32 *read)
-{
-    DMImage *img;
-    Uint8 *buf;
-    size_t bufLen;
-    int yc, res = DMERR_OK;
-    
-    *read = 0;
-
-    // Allocate image
-    if ((*pimg = img = dmImageAlloc(iff->bmhd.w, iff->bmhd.h)) == NULL)
-        return DMERR_MALLOC;
-
-    // Allocate planar decoding buffer
-    bufLen = ((img->width + 15) / 16) * 2;
-    if ((buf = dmMalloc(bufLen)) == NULL)
-        return DMERR_MALLOC;
-
-    dmMsg(3, "ILBM: plane row size %d bytes.\n", bufLen);
-    
-    // Decode the chunk
-    for (yc = 0; yc < img->height; yc++)
-    {
-        int plane;
-        const int nplanes = iff->bmhd.nplanes;
-        Uint8 *dp = img->data + (yc * img->pitch);
-
-        memset(dp, 0, img->pitch);
-
-        for (plane = 0; plane < nplanes; plane++)
-        {
-            // Decompress or read data
-            if (!dmIFFReadOneRow(fp, iff, buf, bufLen))
-            {
-                dmError("ILBM: Error in reading image plane #%d @ %d.\n", plane, yc);
-                res = DMERR_FREAD;
-                goto error;
-            }
-
-            // Decode bitplane
-            dmDecodeBitPlane(dp, buf, img->width, plane);
-
-            *read += bufLen;
-        }
-
-        // Read mask data
-        if (iff->bmhd.masking == IFF_MASK_HAS_MASK)
-        {
-            int xc;
-
-            // Decompress or read data
-            if (!dmIFFReadOneRow(fp, iff, buf, bufLen))
-            {
-                dmError("ILBM: Error in reading mask plane.\n");
-                res = DMERR_FREAD;
-                goto error;
-            }
-
-            // Decode mask
-            for (xc = 0; xc < img->width; xc++)
-            {
-                const Uint8 data = (buf[xc / 8] >> (7 - (xc & 7))) & 1;
-                
-                // Black out any pixels with mask bit 0
-                if (!data)
-                    dp[xc] = 0;
-            }
-
-            *read += bufLen;
-        }
-    }
-
-error:
-    dmFree(buf);
-    return res;
-}
-
-
-int dmDecodePBMBody(FILE *fp, DMIFF *iff, DMImage **pimg, Uint32 *read)
-{
-    DMImage *img;
-    int yc, res = DMERR_OK;
-
-    *read = 0;
-
-    // Allocate image
-    if ((*pimg = img = dmImageAlloc(iff->bmhd.w, iff->bmhd.h)) == NULL)
-        return DMERR_MALLOC;
-
-    // Decode the chunk
-    for (yc = 0; yc < img->height; yc++)
-    {
-        Uint8 *dp = img->data + (yc * img->pitch);
-
-        if (!dmIFFReadOneRow(fp, iff, dp, img->width))
-        {
-            dmError("ILBM: Error in reading image row #%d.\n", yc);
-            res = DMERR_FREAD;
-            goto error;
-        }
-
-        *read += img->width;
-    }
-
-error:
-    return res;
-}
-
-
-int dmReadILBMImageFILE(FILE *fp, DMImage **pimg)
-{
-    Uint32 idILBM;
-    DMIFFChunk chunk;
-    DMIFF iff;
-    Uint32 read;
-    BOOL parsed = FALSE;
-    int i, res = DMERR_OK;
-
-    memset(&iff, 0, sizeof(iff));
-
-    // Read IFF FORM header
-    if (!dmReadIFFChunk(fp, &chunk) ||
-        chunk.id != IFF_ID_FORM ||
-        chunk.size < 32)
-    {
-        dmError("ILBM: Not a IFF file.\n");
-        return DMERR_FREAD;
-    }
-    
-    // Check IFF ILBM signature
-    if (!dm_fread_be32(fp, &idILBM) ||
-        (idILBM != IFF_ID_ILBM && idILBM != IFF_ID_PBM))
-    {
-        dmError("ILBM: Not a ILBM file.\n");
-        return DMERR_INVALID_DATA;
-    }
-
-    iff.planar = (idILBM == IFF_ID_ILBM);
-
-    while (!parsed && !feof(fp))
-    {
-        if (!dmReadIFFChunk(fp, &chunk))
-        {
-            dmError("ILBM: Error reading IFF ILBM data.\n");
-            return DMERR_FREAD;
-        }
-        
-        switch (chunk.id)
-        {
-            case IFF_ID_BMHD:
-                // Check for multiple occurences of BMHD
-                if (!dmCheckIFFChunk(&iff.chBMHD, &chunk, FALSE, sizeof(iff.bmhd)))
-                    return DMERR_FREAD;
-
-                // Read BMHD data
-                if (!dm_fread_be16(fp, &iff.bmhd.w) ||
-                    !dm_fread_be16(fp, &iff.bmhd.h) ||
-                    !dm_fread_be16(fp, (Uint16 *) &iff.bmhd.x) ||
-                    !dm_fread_be16(fp, (Uint16 *) &iff.bmhd.y) ||
-                    !dm_fread_byte(fp, &iff.bmhd.nplanes) ||
-                    !dm_fread_byte(fp, &iff.bmhd.masking) ||
-                    !dm_fread_byte(fp, &iff.bmhd.compression) ||
-                    !dm_fread_byte(fp, &iff.bmhd.pad1) ||
-                    !dm_fread_be16(fp, &iff.bmhd.transp) ||
-                    !dm_fread_byte(fp, &iff.bmhd.xasp) ||
-                    !dm_fread_byte(fp, &iff.bmhd.yasp) ||
-                    !dm_fread_be16(fp, (Uint16 *) &iff.bmhd.pagew) ||
-                    !dm_fread_be16(fp, (Uint16 *) &iff.bmhd.pageh))
-                {
-                    dmError("ILBM: Error reading BMHD chunk.\n");
-                    return DMERR_FREAD;
-                }
-                dmMsg(3, "ILBM: BMHD %d x %d @ %d, %d : nplanes=%d, comp=%d, mask=%d\n",
-                    iff.bmhd.w, iff.bmhd.h, iff.bmhd.x, iff.bmhd.y,
-                    iff.bmhd.nplanes, iff.bmhd.compression, iff.bmhd.masking);
-                
-                // Sanity check
-                if (iff.bmhd.nplanes < 1 || iff.bmhd.nplanes > 8 ||
-                    (iff.bmhd.compression != IFF_COMP_NONE &&
-                    iff.bmhd.compression != IFF_COMP_BYTERUN1) ||
-                    (iff.bmhd.masking != IFF_MASK_NONE &&
-                    iff.bmhd.masking != IFF_MASK_HAS_MASK &&
-                    iff.bmhd.masking != IFF_MASK_TRANSP))
-                {
-                    dmError("ILBM: Unsupported features, refusing to load.\n");
-                    return DMERR_NOT_SUPPORTED;
-                }
-
-                if (!dmSkipIFFChunkRest(fp, &chunk, sizeof(iff.bmhd)))
-                    return DMERR_FREAD;
-                break;
-
-
-            case IFF_ID_CMAP:
-                // Check for multiple occurences of CMAP
-                if (!dmCheckIFFChunk(&iff.chCMAP, &chunk, FALSE, 3))
-                    return DMERR_FREAD;
-
-                // Check for sanity
-                if (chunk.size % 3 != 0)
-                    dmError("ILBM: CMAP chunk size not divisible by 3, possibly broken file.\n");
-
-                iff.ncolors = chunk.size / 3;
-                dmMsg(3, "ILBM: CMAP %d entries (%d bytes)\n",
-                    iff.ncolors, chunk.size, 1 << iff.bmhd.nplanes);
-
-                if (iff.bmhd.nplanes > 0 && iff.ncolors != 1 << iff.bmhd.nplanes)
-                    dmMsg(3, "ILBM: Expected %d entries in CMAP.\n", 1 << iff.bmhd.nplanes);
-                
-                // Read palette
-                if (iff.ncolors > 0)
-                {
-                    if (!dmPaletteAlloc(&iff.pal, iff.ncolors,
-                        (iff.bmhd.masking == IFF_MASK_TRANSP) ? iff.bmhd.transp : -1))
-                    {
-                        dmError("ILBM: Could not allocate palette data.\n");
-                        return DMERR_MALLOC;
-                    }
-                    if (!dmReadPaletteData(fp, iff.pal, iff.ncolors))
-                    {
-                        dmError("ILBM: Error reading CMAP.\n");
-                        return DMERR_FREAD;
-                    }
-                }
-
-                if (iff.chBMHD.count && iff.chBODY.count)
-                    parsed = TRUE;
-                break;
-            
-            case IFF_ID_BODY:
-                // Check for multiple occurences of CMAP
-                if (!dmCheckIFFChunk(&iff.chBODY, &chunk, FALSE, 1))
-                    return DMERR_FREAD;
-
-                // Check for sanity
-                if (!iff.chBMHD.count)
-                {
-                    dmError("ILBM: BODY chunk before BMHD?\n");
-                    return DMERR_INVALID_DATA;
-                }
-
-                dmMsg(3, "ILBM: BODY chunk size %d bytes\n", chunk.size);
-                
-                // Decode the body
-                if (iff.planar)
-                {
-                    if ((res = dmDecodeILBMBody(fp, &iff, pimg, &read)) != DMERR_OK)
-                        return res;
-                }
-                else
-                {
-                    if ((res = dmDecodePBMBody(fp, &iff, pimg, &read)) != DMERR_OK)
-                        return res;
-                }
-
-                if (!dmSkipIFFChunkRest(fp, &chunk, read))
-                    return DMERR_FREAD;
-
-                if (iff.chCMAP.count)
-                    parsed = TRUE;
-                break;
-
-
-            case IFF_ID_CAMG:
-                if (!dm_fread_be32(fp, &iff.camg))
-                {
-                    dmError("ILBM: Error reading CAMG chunk.\n");
-                    return DMERR_FREAD;
-                }
-                
-                dmMsg(3, "ILBM: CAMG value 0x%08x\n", iff.camg);
-
-                if ((iff.camg & IFF_CAMG_HAM))
-                {
-                    dmError("ILBM: HAM files are not supported.\n");
-                    return DMERR_NOT_SUPPORTED;
-                }
-
-                if (!dmSkipIFFChunkRest(fp, &chunk, 4))
-                    return DMERR_FREAD;
-                break;
-
-            
-            default:
-                {
-                    dmMsg(4, "Unknown chunk ID '%s', size %d\n",
-                        dmGetIFFChunkID(&chunk), chunk.size);
-                    
-                    if (fseeko(fp, chunk.size, SEEK_CUR) != 0)
-                    {
-                        dmError("ILBM: Error skipping in file.");
-                        return DMERR_FREAD;
-                    }
-                }
-                break;
-        }
-        
-        if (chunk.size & 1)
-            fgetc(fp);
-    }
-
-    // Set colormap after finishing
-    if (iff.pal != NULL && iff.ncolors > 0 && *pimg != NULL)
-    {
-        // If halfbrite is used, duplicate the palette
-        if (iff.camg & IFF_CAMG_HALFBRITE)
-        {
-            if (iff.ncolors > 128)
-            {
-                dmError("ILBM: Halfbrite enabled, but ncolors > 128.\n");
-                return DMERR_NOT_SUPPORTED;
-            }
-
-            if ((iff.pal = dmRealloc(iff.pal, sizeof(DMColor) * iff.ncolors * 2)) == NULL)
-                return DMERR_MALLOC;
-            
-            for (i = 0; i < iff.ncolors; i++)
-            {
-                int i2 = iff.ncolors + i;
-                iff.pal[i2].r = iff.pal[i].r / 2;
-                iff.pal[i2].g = iff.pal[i].g / 2;
-                iff.pal[i2].b = iff.pal[i].b / 2;
-            }
-        }
-    
-        (*pimg)->ncolors = iff.ncolors;
-        (*pimg)->pal = iff.pal;
-    }
-
-    return res;
-}
-
-
-int dmReadILBMImage(const char *filename, DMImage **pimg)
-{
-    FILE *fp;
-    int res;
-
-    if ((fp = fopen(filename, "rb")) == NULL)
-    {
-        dmError("ILBM: Could not open file '%s' for reading.\n", filename);
-        return DMERR_FOPEN;
-    }
-    
-    res = dmReadILBMImageFILE(fp, pimg);
-
-    fclose(fp);
-    return res;
-}
-
-
-
-
-static int fmtProbePNG(const Uint8 *buf, const size_t len)
-{
-    if (len > 64 && buf[0] == 0x89 &&
-        buf[1] == 'P' && buf[2] == 'N' && buf[3] == 'G' &&
-        buf[4] == 0x0d && buf[5] == 0x0a)
-    {
-        if (buf[12] == 'I' && buf[13] == 'H' &&
-            buf[14] == 'D' && buf[15] == 'R')
-            return DM_PROBE_SCORE_MAX;
-        else
-            return DM_PROBE_SCORE_GOOD;
-    }
-
-    return DM_PROBE_SCORE_FALSE;
-}
-
-
-static int fmtProbePCX(const Uint8 *buf, const size_t len)
-{
-    if (len > 128 + 32 &&
-        buf[0] == 10 &&
-        (buf[1] == 5 || buf[1] == 2 || buf[1] == 3) &&
-        buf[2] == 1 &&
-        (buf[3] == 8 || buf[3] == 4 || buf[3] == 3 || buf[3] == 1) &&
-        buf[65] >= 1 && buf[65] <= 4)
-        return DM_PROBE_SCORE_GOOD;
-
-    return DM_PROBE_SCORE_FALSE;
-}
-
-
-static int fmtProbeILBM(const Uint8 *buf, const size_t len)
-{
-    if (len > 32 &&
-        buf[ 0] == 'F' && buf[ 1] == 'O' &&
-        buf[ 2] == 'R' && buf[ 3] == 'M' && (
-        (buf[ 8] == 'I' && buf[ 9] == 'L' && buf[10] == 'B' && buf[11] == 'M') ||
-        (buf[ 8] == 'P' && buf[ 9] == 'B' && buf[10] == 'M' && buf[11] == 0x20)
-        ))
-    {
-        if (buf[12] == 'B' && buf[13] == 'M' &&
-            buf[14] == 'H' && buf[15] == 'D')
-            return DM_PROBE_SCORE_MAX;
-        else
-            return DM_PROBE_SCORE_GOOD;
-    }
-
-    return DM_PROBE_SCORE_FALSE;
-}
-
-
-DMImageFormat dmImageFormatList[IMGFMT_LAST] =
-{
-    {
-        "PNG", "Portable Network Graphics",
-        fmtProbePNG,
-#ifdef DM_USE_LIBPNG
-        dmReadPNGImage, dmReadPNGImageFILE,
-        dmWritePNGImage, dmWritePNGImageFILE,
-#else
-        NULL, NULL,
-        NULL, NULL,
-#endif
-    },
-    {
-        "PPM", "Portable PixMap",
-        NULL,
-        NULL, NULL,
-        dmWritePPMImage, dmWritePPMImageFILE,
-    },
-    {
-        "PCX", "Z-Soft Paintbrush",
-        fmtProbePCX,
-        dmReadPCXImage, dmReadPCXImageFILE,
-        dmWritePCXImage, dmWritePCXImageFILE,
-    },
-    {
-        "ILBM", "IFF ILBM",
-        fmtProbeILBM,
-        dmReadILBMImage, dmReadILBMImageFILE,
-        NULL, NULL,
-    },
-    {
-        "RAW", "Plain bitplaned (interleaved or non-interleaved) RAW",
-        NULL,
-        NULL, NULL,
-        dmWriteRAWImage, dmWriteRAWImageFILE,
-    },
-    {
-        "ARAW", "IFFMaster Amiga RAW",
-        NULL,
-        NULL, NULL,
-        dmWriteRAWImage, dmWriteRAWImageFILE,
-    }
-};
-
-
-int dmImageProbeGeneric(const Uint8 *buf, const size_t len, DMImageFormat **pfmt, int *index)
-{
-    int i, scoreMax = DM_PROBE_SCORE_FALSE, scoreIndex = -1;
-
-    for (i = 0; i < IMGFMT_LAST; i++)
-    {
-        DMImageFormat *fmt = &dmImageFormatList[i];
-        if (fmt->probe != NULL)
-        {
-            int score = fmt->probe(buf, len);
-            if (score > scoreMax)
-            {
-                scoreMax = score;
-                scoreIndex = i;
-            }
-        }
-    }
-
-    if (scoreIndex >= 0)
-    {
-        *pfmt = &dmImageFormatList[scoreIndex];
-        *index = scoreIndex;
-        return scoreMax;
-    }
-    else
-        return DM_PROBE_SCORE_FALSE;
-}
--- a/libgfx.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +0,0 @@
-/*
- * Functions for loading and saving bitmap images
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2012 Tecnic Software productions (TNSP)
- *
- * Please read file 'COPYING' for information on license and distribution.
- */
-#ifndef LIBMGFX_H
-#define LIBMGFX_H 1
-
-#include "dmlib.h"
-#include "dmfile.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-enum
-{
-    IMGFMT_PNG,
-    IMGFMT_PPM,
-    IMGFMT_PCX,
-    IMGFMT_ILBM,
-    IMGFMT_RAW,
-    IMGFMT_ARAW,
-
-    IMGFMT_LAST
-};
-
-
-enum
-{
-    DM_IFMT_PALETTE,
-    DM_IFMT_RGB,
-    DM_IFMT_RGBA,
-    DM_IFMT_RGB_PLANE,
-};
-
-
-// RGBx color struct
-typedef struct
-{
-    Uint8 r, g, b, a;
-} DMColor;
-
-
-// Bitmapped image struct (can be one of types specified by DM_IFMT_*)
-typedef struct
-{
-    int width, height, pitch;
-    BOOL constpal;
-    int ncolors, ctransp;
-    DMColor *pal;
-    Uint8 *data;
-} DMImage;
-
-
-typedef struct
-{
-    int scale, nplanes, format;
-    BOOL interleave, paletted;
-} DMImageSpec;
-
-
-typedef struct
-{
-    char *fext;
-    char *desc;
-    int  (*probe)(const Uint8 *buf, const size_t len);
-    int  (*read)(const char *filename, DMImage **pimg);
-    int  (*readFILE)(FILE *fp, DMImage **pimg);
-    int  (*write)(const char *filename, DMImage *pimg, DMImageSpec *spec);
-    int  (*writeFILE)(FILE *fp, DMImage *pimg, DMImageSpec *spec);
-} DMImageFormat;
-
-
-// Probe scores
-#define DM_PROBE_SCORE_MAX     1000
-#define DM_PROBE_SCORE_GOOD    750
-#define DM_PROBE_SCORE_AVG     500
-#define DM_PROBE_SCORE_MAYBE   250
-#define DM_PROBE_SCORE_FALSE   0
-
-
-extern DMImageFormat dmImageFormatList[IMGFMT_LAST];
-
-
-DMImage * dmImageAlloc(int width, int height);
-void      dmImageFree(DMImage *img);
-int       dmImageGetBytesPerPixel(int format);
-int       dmImageProbeGeneric(const Uint8 *buf, const size_t len, DMImageFormat **fmt, int *index);
-
-BOOL dmCompareColor(const DMColor *c1, const DMColor *c2, BOOL alpha);
-
-
-int dmWriteImageData(DMImage *img, void *cbdata, int (*writeRowCB)(void *, Uint8 *, size_t), const DMImageSpec *spec);
-
-int dmWriteIFFMasterRAWPalette(FILE *fp, DMImage *img, int ncolors, const char *indent, const char *type);
-int dmWriteRAWImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec);
-int dmWriteRAWImage(const char *filename, DMImage *img, DMImageSpec *spec);
-
-int dmWritePPMImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec);
-int dmWritePPMImage(const char *filename, DMImage *img, DMImageSpec *spec);
-
-#ifdef DM_USE_LIBPNG
-int dmWritePNGImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec);
-int dmWritePNGImage(const char *filename, DMImage *img, DMImageSpec *spec);
-#endif
-
-int dmWritePCXImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec);
-int dmWritePCXImage(const char *filename, DMImage *img, DMImageSpec *spec);
-int dmReadPCXImageFILE(FILE *fp, DMImage **pimg);
-int dmReadPCXImage(const char *filename, DMImage **pimg);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // LIBMGFX_H
--- a/setupfont.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,191 +0,0 @@
-Uint8 engineSetupFont[3021] = {
-	 68, 77, 70, 79, 78, 84,  0,  1, 80,  0,255,  0,  6,  6,  8,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,
-	  0,  6,  6,  0, 15, 15, 15,  0,  0, 15,  0,  0,  0, 15,  0, 15,
-	 15,  0, 15, 15,  0, 15,  0, 15,  0, 15,  0, 15,  0,  0,  0, 15,
-	  0,  0, 15, 15, 15,  0,  0,  2,  0,  6,  6,  0, 15, 15, 15,  0,
-	  0, 15, 15, 15, 15, 15,  0, 15,  0, 15,  0, 15,  0, 15, 15,  0,
-	 15, 15,  0, 15, 15, 15, 15, 15,  0,  0, 15, 15, 15,  0,  0, 16,
-	  0,  6,  6,  0,  0, 15,  0,  0,  0,  0,  0, 15, 15,  0,  0,  0,
-	  0, 15, 15, 15,  0,  0,  0, 15, 15,  0,  0,  0,  0, 15,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0, 17,  0,  6,  6,  0,  0,  0, 15,  0,
-	  0,  0,  0, 15, 15,  0,  0,  0, 15, 15, 15,  0,  0,  0,  0, 15,
-	 15,  0,  0,  0,  0,  0, 15,  0,  0,  0,  0,  0,  0,  0,  0, 32,
-	  0,  6,  6,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0, 33,  0,  4,  6,  0, 12,  0,  0,  0,
-	 15,  0,  0,  0, 12,  0,  0,  0,  0,  0,  0,  0, 15,  0,  0,  0,
-	  0,  0,  0, 34,  0,  4,  6, 15,  0, 15,  0, 12,  0, 12,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 35,
-	  0,  6,  6,  0, 12,  0, 12,  0,  0, 12, 15, 15, 15, 12,  0,  0,
-	 15,  0, 15,  0,  0, 12, 15, 15, 15, 12,  0,  0, 12,  0, 12,  0,
-	  0,  0,  0,  0,  0,  0,  0, 36,  0,  6,  6,  0, 12, 15, 12,  0,
-	  0, 12,  0, 15,  0,  0,  0,  0, 15, 15, 15,  0,  0,  0,  0, 15,
-	  0, 12,  0,  0, 12, 15, 15,  0,  0,  0,  0, 15,  0,  0,  0, 37,
-	  0,  5,  6,  0,  0,  0,  0,  0, 15,  0,  0, 12,  0,  0,  0, 15,
-	  0,  0,  0, 15,  0,  0,  0, 12,  0,  0, 15,  0,  0,  0,  0,  0,
-	  0, 38,  0,  6,  6,  0, 12, 15,  0,  0,  0, 12,  0,  0, 12,  0,
-	  0,  0, 15, 15,  0, 12,  0, 12,  0,  0, 15,  0,  0,  0, 12, 15,
-	  0, 12,  0,  0,  0,  0,  0,  0,  0, 39,  0,  6,  6,  0,  0, 15,
-	  0,  0,  0,  0, 12,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	  0, 40,  0,  4,  6,  0,  0, 12,  0,  0, 12,  0,  0,  0, 15,  0,
-	  0,  0, 12,  0,  0,  0,  0, 12,  0,  0,  0,  0,  0, 41,  0,  4,
-	  6,  0, 11,  0,  0,  0,  0, 13,  0,  0,  0, 15,  0,  0,  0, 13,
-	  0,  0, 11,  0,  0,  0,  0,  0,  0, 42,  0,  6,  6, 12,  0, 12,
-	  0, 12,  0,  0, 13, 15, 13,  0,  0, 12, 15, 15, 15, 12,  0,  0,
-	 13, 15, 13,  0,  0, 12,  0, 12,  0, 12,  0,  0,  0,  0,  0,  0,
-	  0, 43,  0,  4,  6,  0,  0,  0,  0,  0, 15,  0,  0, 15, 15, 15,
-	  0,  0, 15,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 44,  0,  4,
-	  6,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	  0,  0,  0, 15,  0,  0, 15,  0,  0, 45,  0,  5,  6,  0,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0, 12, 15, 15, 12,  0,  0,  0,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 46,  0,  4,  6,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	 15,  0,  0,  0,  0,  0,  0, 47,  0,  6,  6,  0,  0,  0,  0, 12,
-	  0,  0,  0,  0, 15,  0,  0,  0,  0, 15,  0,  0,  0,  0, 15,  0,
-	  0,  0,  0, 12,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 48,
-	  0,  6,  6,  0, 13, 12, 12,  0,  0, 13,  0,  0, 12, 13,  0, 15,
-	  0, 12,  0, 15,  0, 13, 12,  0,  0, 13,  0,  0, 12, 11, 11,  0,
-	  0,  0,  0,  0,  0,  0,  0, 49,  0,  4,  6,  0, 11,  0,  0, 11,
-	 15,  0,  0,  0, 15,  0,  0,  0, 15,  0,  0, 11, 13, 11,  0,  0,
-	  0,  0,  0, 50,  0,  6,  6,  0, 13, 15, 13,  0,  0, 13,  0,  0,
-	  0, 11,  0,  0,  0,  0, 15,  0,  0,  0, 11, 15,  0,  0,  0, 11,
-	 15, 15, 15, 11,  0,  0,  0,  0,  0,  0,  0, 51,  0,  6,  6,  0,
-	 13, 15, 11,  0,  0, 11,  0,  0,  0, 13,  0,  0,  0, 13, 15,  0,
-	  0, 13,  0,  0,  0, 13,  0,  0, 11, 15, 11,  0,  0,  0,  0,  0,
-	  0,  0,  0, 52,  0,  6,  6,  0, 13,  0, 13,  0,  0, 13,  0,  0,
-	 15,  0,  0, 13, 15, 15, 15, 11,  0,  0,  0,  0, 15,  0,  0,  0,
-	  0,  0, 11,  0,  0,  0,  0,  0,  0,  0,  0, 53,  0,  6,  6, 13,
-	 15, 15, 15, 11,  0, 15,  0,  0,  0,  0,  0, 15, 15, 15, 13,  0,
-	  0,  0,  0,  0,  0, 11,  0, 13, 15, 15, 13,  0,  0,  0,  0,  0,
-	  0,  0,  0, 54,  0,  6,  6,  0, 14, 15, 13,  0,  0, 14,  0,  0,
-	  0,  0,  0, 15, 15, 15, 13,  0,  0, 13,  0,  0,  0, 11,  0,  0,
-	 14, 15, 11,  0,  0,  0,  0,  0,  0,  0,  0, 55,  0,  6,  6, 13,
-	 15, 15, 13,  0,  0, 13,  0,  0, 15,  0,  0,  0,  0, 13, 15, 13,
-	  0,  0,  0,  0, 15,  0,  0,  0,  0,  0, 13,  0,  0,  0,  0,  0,
-	  0,  0,  0, 56,  0,  6,  6,  0, 13, 15, 13,  0,  0, 13,  0,  0,
-	  0, 13,  0,  0, 13, 15, 13,  0,  0, 13,  0,  0,  0, 13,  0,  0,
-	 13, 15, 13,  0,  0,  0,  0,  0,  0,  0,  0, 57,  0,  6,  6,  0,
-	 13, 15, 13,  0,  0, 13,  0,  0,  0, 13,  0,  0, 13, 15, 15, 15,
-	  0,  0,  0,  0,  0, 13,  0,  0, 13, 15, 13,  0,  0,  0,  0,  0,
-	  0,  0,  0, 58,  0,  4,  6,  0,  0,  0,  0,  0, 15,  0,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0, 15,  0,  0,  0,  0,  0,  0, 59,
-	  0,  4,  6,  0,  0,  0,  0,  0,  0, 15,  0,  0,  0,  0,  0,  0,
-	  0, 15,  0,  0, 15,  0,  0,  0,  0,  0,  0, 60,  0,  4,  6,  0,
-	  0, 15,  0,  0, 15,  0,  0, 15,  0,  0,  0,  0, 15,  0,  0,  0,
-	  0, 15,  0,  0,  0,  0,  0, 61,  0,  5,  6,  0,  0,  0,  0,  0,
-	 13, 15, 15, 13,  0,  0,  0,  0,  0,  0, 13, 15, 15, 13,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0, 62,  0,  4,  6, 15,  0,  0,
-	  0,  0, 15,  0,  0,  0,  0, 15,  0,  0, 15,  0,  0, 15,  0,  0,
-	  0,  0,  0,  0,  0, 63,  0,  6,  6,  0, 13, 15, 13,  0,  0, 13,
-	  0,  0,  0, 13,  0,  0,  0,  0, 15,  0,  0,  0,  0, 13,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0, 15,  0,  0,  0, 64,  0,  6,
-	  6,  0, 13, 15, 13,  0,  0, 13,  0, 15,  0, 13,  0, 15,  0, 13,
-	 15, 15,  0, 13,  0,  0,  0,  0,  0,  0, 13, 15, 13,  0,  0,  0,
-	  0,  0,  0,  0,  0, 65,  0,  6,  6,  0, 11, 11, 11,  0,  0, 13,
-	  0,  0,  0, 13,  0, 15, 15, 15, 15, 15,  0, 13,  0,  0,  0, 13,
-	  0, 11,  0,  0,  0, 11,  0,  0,  0,  0,  0,  0,  0, 66,  0,  6,
-	  6, 11, 11, 11, 11,  0,  0, 13,  0,  0,  0, 13,  0, 15, 15, 15,
-	 15,  0,  0, 13,  0,  0,  0, 13,  0, 11, 11, 11, 11,  0,  0,  0,
-	  0,  0,  0,  0,  0, 67,  0,  6,  6,  0, 13, 12, 11, 10,  0, 13,
-	  0,  0,  0,  0,  0, 15,  0,  0,  0,  0,  0, 13,  0,  0,  0,  0,
-	  0,  0, 13, 12, 11, 10,  0,  0,  0,  0,  0,  0,  0, 68,  0,  6,
-	  6, 12, 11, 11, 12,  0,  0, 13,  0,  0,  0, 13,  0, 15,  0,  0,
-	  0, 15,  0, 13,  0,  0,  0, 13,  0, 12, 11, 11, 12,  0,  0,  0,
-	  0,  0,  0,  0,  0, 69,  0,  6,  6, 12, 11, 11, 11, 11,  0, 13,
-	  0,  0,  0,  0,  0, 15, 15, 13,  0,  0,  0, 13,  0,  0,  0,  0,
-	  0, 12, 11, 11, 11, 11,  0,  0,  0,  0,  0,  0,  0, 70,  0,  6,
-	  6, 13, 12, 11, 11, 10,  0, 15,  0,  0,  0,  0,  0, 15, 15, 13,
-	  0,  0,  0, 13,  0,  0,  0,  0,  0, 11,  0,  0,  0,  0,  0,  0,
-	  0,  0,  0,  0,  0, 71,  0,  6,  6,  0, 12, 11, 11, 10,  0, 15,
-	  0,  0,  0,  0,  0, 15,  0, 13, 15, 13,  0, 13,  0,  0,  0, 12,
-	  0,  0, 12, 11, 11, 11,  0,  0,  0,  0,  0,  0,  0, 72,  0,  6,
-	  6, 11,  0,  0,  0, 11,  0, 13,  0,  0,  0, 13,  0, 13, 14, 15,
-	 14, 13,  0, 13,  0,  0,  0, 13,  0, 11,  0,  0,  0, 11,  0,  0,
-	  0,  0,  0,  0,  0, 73,  0,  4,  6, 10, 11, 10,  0,  0, 13,  0,
-	  0,  0, 15,  0,  0,  0, 13,  0,  0, 10, 11, 10,  0,  0,  0,  0,
-	  0, 74,  0,  6,  6,  0,  0,  0,  0, 11,  0,  0,  0,  0,  0, 13,
-	  0,  0,  0,  0,  0, 15,  0, 10,  0,  0,  0, 13,  0,  0, 11, 12,
-	 13,  0,  0,  0,  0,  0,  0,  0,  0, 75,  0,  6,  6, 11,  0,  0,
-	  0, 11,  0, 13,  0, 13, 13,  0,  0, 15, 15, 15,  0,  0,  0, 13,
-	  0, 13, 13,  0,  0, 11,  0,  0,  0, 11,  0,  0,  0,  0,  0,  0,
-	  0, 76,  0,  6,  6, 11,  0,  0,  0,  0,  0, 13,  0,  0,  0,  0,
-	  0, 15,  0,  0,  0,  0,  0, 15,  0,  0,  0,  0,  0, 13, 12, 12,
-	 11, 11,  0,  0,  0,  0,  0,  0,  0, 77,  0,  6,  6, 11,  0,  0,
-	  0, 11,  0, 12, 13,  0, 13, 12,  0, 13, 15, 13, 15, 13,  0, 12,
-	  0, 12,  0, 12,  0, 11,  0,  0,  0, 11,  0,  0,  0,  0,  0,  0,
-	  0, 78,  0,  6,  6, 11,  0,  0,  0, 11,  0, 13, 13,  0,  0, 13,
-	  0, 15,  0, 15,  0, 15,  0, 13,  0,  0, 13, 13,  0, 11,  0,  0,
-	  0, 11,  0,  0,  0,  0,  0,  0,  0, 79,  0,  6,  6,  0, 13, 12,
-	 11,  0,  0, 13,  0,  0,  0, 13,  0, 15,  0,  0,  0, 15,  0, 13,
-	  0,  0,  0, 13,  0,  0, 12, 11, 11,  0,  0,  0,  0,  0,  0,  0,
-	  0, 80,  0,  6,  6, 12, 11, 11, 11,  0,  0, 13,  0,  0,  0, 12,
-	  0, 15, 15, 13, 12,  0,  0, 12,  0,  0,  0,  0,  0, 11,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0, 81,  0,  6,  6,  0, 11, 11,
-	 11,  0,  0, 13,  0,  0,  0, 13,  0, 15,  0, 15,  0, 15,  0, 13,
-	  0,  0, 13,  0,  0,  0, 11, 11,  0, 11,  0,  0,  0,  0,  0,  0,
-	  0, 82,  0,  6,  6, 11, 11, 11, 11,  0,  0, 13,  0,  0,  0, 13,
-	  0, 15, 15, 15, 13,  0,  0, 13,  0,  0,  0, 13,  0, 11,  0,  0,
-	  0, 11,  0,  0,  0,  0,  0,  0,  0, 83,  0,  6,  6,  0, 13, 11,
-	 11, 11,  0, 15,  0,  0,  0,  0,  0,  0, 13, 15, 15,  0,  0,  0,
-	  0,  0,  0, 13,  0, 11, 11, 11, 13,  0,  0,  0,  0,  0,  0,  0,
-	  0, 84,  0,  6,  6, 11, 12, 13, 12, 11,  0,  0,  0, 15,  0,  0,
-	  0,  0,  0, 15,  0,  0,  0,  0,  0, 13,  0,  0,  0,  0,  0, 11,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0, 85,  0,  6,  6, 11,  0,  0,
-	  0, 11,  0, 12,  0,  0,  0, 12,  0, 15,  0,  0,  0, 15,  0, 13,
-	  0,  0,  0, 13,  0,  0, 11, 11, 11,  0,  0,  0,  0,  0,  0,  0,
-	  0, 86,  0,  6,  6, 11,  0,  0,  0, 11,  0, 13,  0,  0,  0, 13,
-	  0,  0, 15,  0, 15,  0,  0,  0, 13,  0, 13,  0,  0,  0,  0, 11,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0, 87,  0,  6,  6, 11,  0,  0,
-	  0, 11,  0, 13,  0,  0,  0, 13,  0, 15,  0,  0,  0, 15,  0, 13,
-	  0, 13,  0, 13,  0,  0, 11,  0, 11,  0,  0,  0,  0,  0,  0,  0,
-	  0, 88,  0,  6,  6, 11,  0,  0,  0, 11,  0,  0, 13,  0, 13,  0,
-	  0,  0,  0, 15,  0,  0,  0,  0, 13,  0, 13,  0,  0, 11,  0,  0,
-	  0, 11,  0,  0,  0,  0,  0,  0,  0, 89,  0,  6,  6, 11,  0,  0,
-	  0, 11,  0, 13,  0,  0,  0, 13,  0,  0, 15,  0, 15,  0,  0,  0,
-	  0, 13,  0,  0,  0,  0,  0, 11,  0,  0,  0,  0,  0,  0,  0,  0,
-	  0, 90,  0,  6,  6, 13, 12, 12, 11, 13,  0,  0,  0,  0, 15,  0,
-	  0,  0,  0, 15,  0,  0,  0,  0, 15,  0,  0,  0,  0, 13, 12, 11,
-	 11, 11,  0,  0,  0,  0,  0,  0,  0, 91,  0,  4,  6,  0, 11, 11,
-	  0,  0, 13,  0,  0,  0, 15,  0,  0,  0, 13,  0,  0,  0, 11, 11,
-	  0,  0,  0,  0,  0, 92,  0,  6,  6, 11,  0,  0,  0,  0,  0,  0,
-	 15,  0,  0,  0,  0,  0,  0, 15,  0,  0,  0,  0,  0,  0, 15,  0,
-	  0,  0,  0,  0,  0, 11,  0,  0,  0,  0,  0,  0,  0, 93,  0,  4,
-	  6,  0, 11, 11,  0,  0,  0, 13,  0,  0,  0, 15,  0,  0,  0, 13,
-	  0,  0, 11, 11,  0,  0,  0,  0,  0, 94,  0,  4,  6,  0, 15,  0,
-	  0, 15,  0, 15,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	  0,  0,  0,  0,  0, 95,  0,  6,  6,  0,  0,  0,  0,  0,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	  0, 15, 15, 15, 15, 15,  0,  0,  0,  0,  0,  0,  0, 96,  0,  6,
-	  6,  0,  0, 15,  0,  0,  0,  0,  0, 15, 15,  0,  0,  0,  0,  0,
-	 15,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	  0,  0,  0,  0,  0,123,  0,  6,  6,  0,  0, 12, 15,  0,  0,  0,
-	  0, 15,  0,  0,  0,  0, 15, 15,  0,  0,  0,  0,  0, 15,  0,  0,
-	  0,  0,  0, 12, 15,  0,  0,  0,  0,  0,  0,  0,  0,125,  0,  6,
-	  6,  0,  0, 15, 12,  0,  0,  0,  0,  0, 15,  0,  0,  0,  0,  0,
-	 15, 15,  0,  0,  0,  0, 15,  0,  0,  0,  0, 15, 12,  0,  0,  0,
-	  0,  0,  0,  0,  0,126,  0,  6,  6,  0,  0, 15, 15,  0, 15,  0,
-	 15, 15,  0, 15,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,132,  0,  6,
-	  6, 15,  0,  0,  0, 15,  0,  0, 13, 15, 13,  0,  0, 13,  0,  0,
-	  0, 13,  0, 13, 14, 15, 14, 13,  0, 11,  0,  0,  0, 11,  0,  0,
-	  0,  0,  0,  0,  0,142,  0,  6,  6, 15,  0,  0,  0, 15,  0,  0,
-	 13, 15, 13,  0,  0, 13,  0,  0,  0, 13,  0, 13, 14, 15, 14, 13,
-	  0, 11,  0,  0,  0, 11,  0,  0,  0,  0,  0,  0,  0,148,  0,  6,
-	  6, 14,  0,  0,  0, 14,  0,  0, 12, 14, 12,  0,  0, 15,  0,  0,
-	  0, 15,  0, 13,  0,  0,  0, 13,  0,  0, 12, 11, 11,  0,  0,  0,
-	  0,  0,  0,  0,  0,153,  0,  6,  6, 14,  0,  0,  0, 14,  0,  0,
-	 12, 14, 12,  0,  0, 15,  0,  0,  0, 15,  0, 13,  0,  0,  0, 13,
-	  0,  0, 12, 11, 11,  0,  0,  0,  0,  0,  0,  0,  0,174,  0,  6,
-	  6,  0,  0, 15,  0,  0, 15,  0, 15,  0,  0, 15,  0, 15,  0,  0,
-	 15,  0,  0,  0, 15,  0,  0, 15,  0,  0,  0, 15,  0,  0, 15,  0,
-	  0,  0,  0,  0,  0,175,  0,  6,  6, 15,  0,  0, 15,  0,  0,  0,
-	 15,  0,  0, 15,  0,  0,  0, 15,  0,  0, 15,  0, 15,  0,  0, 15,
-	  0, 15,  0,  0, 15,  0,  0,  0,  0,  0,  0,  0,  0,177,  0,  6,
-	  6, 15,  0, 15,  0, 15,  0,  0, 15,  0, 15,  0, 15, 15,  0, 15,
-	  0, 15,  0,  0, 15,  0, 15,  0, 15, 15,  0, 15,  0, 15,  0,  0,
-	 15,  0, 15,  0, 15,254,  0,  6,  6, 11,  0,  0,  0, 11,  0, 13,
-	  0,  0, 13, 13,  0, 15,  0, 15,  0, 15,  0, 13, 13,  0,  0, 13,
-	  0, 11,  0,  0,  0, 11,  0,  0,  0,  0,  0,  0,  0,
-};
--- a/setupimage.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,643 +0,0 @@
-Uint8 engineSetupImage[10252] = {
-	137, 80, 78, 71, 13, 10, 26, 10,  0,  0,  0, 13, 73, 72, 68, 82,
-	  0,  0,  2,128,  0,  0,  1,224,  8,  3,  0,  0,  0,  2, 15, 44,
-	214,  0,  0,  0, 96, 80, 76, 84, 69, 13, 15, 11, 27, 22, 15, 33,
-	 21, 14, 39, 22, 15, 42, 27, 14, 59, 33, 14, 81, 40, 13, 81, 50,
-	 13, 95, 47, 13,111, 52, 13,105, 64, 10,130, 60, 13,150, 67, 12,
-	163, 74, 10,148, 89, 10,184, 81, 12,166, 97, 14,210, 91, 10,194,
-	104, 10,222, 97, 13,187,109,  9,212,106, 12,235,100,  8,194,114,
-	  2,249,105, 10,212,122,  7,255,111,  2,255,117,  7,255,122,  9,
-	241,140,  8,255,147, 10,255,165,  8,240,203, 69, 92,  0,  0, 32,
-	  0, 73, 68, 65, 84,120,218,237,157,237, 98,171,170, 18,134,147,
-	 84,173, 86,173,245,152,109,173,180, 93,247,127,151, 71, 62,  5,
-	  1,141,137, 70,147,190,243, 99,239, 44,131, 64,244,233,192, 12,
-	195,112, 56, 64, 32, 16,  8,  4,  2,129, 64, 32, 16,  8,  4,  2,
-	129, 64, 54,144,224,245, 13,  2, 89, 77, 94,131, 49,250,142,111,
-	 31, 16,200,202,242,118,244,241, 23,190,227,233, 64,214,151,247,
-	208,205,223, 43, 30, 13,228, 62,242,234,156,253,241,239,206,255,
-	 65, 32,171,201,153, 83,230,154,  9,178,241,247,127,228, 27,  2,
-	 89, 81,200,255,216, 40,236, 25,128,255,195,  3,130,172, 45,255,
-	185,  7, 97,106,  0,159,161,255, 32,235,235, 64, 58, 12,191, 57,
-	 71,224, 10, 79,  7,178,190, 84,206, 49,152,234, 69, 40, 64,200,
-	 61, 84, 32,101,205,242, 65,  3, 64,200, 61,  1, 60,  2, 64,  8,
-	  0,132,  0, 64,  0,  8,  1,128, 16,  0,  8,  0, 33,  0, 16,  2,
-	  0, 33, 16,  0,  8,  1,128, 16,  8,  0,132,  0, 64,  8,  4,  0,
-	 66,  0, 32,  4,  2,  0, 33,  0, 16,  2,  1,128, 16,  0,  8,129,
-	  0, 64,  8,  0,132, 64,214,  7,144, 44, 32, 43,213, 60,242, 59,
-	111,174,  1,178, 11,  0,201, 98,178, 82,189,139,116, 26, 92,236,
-	 20, 64,178,168,172, 93,237, 77,213,  3,141, 29,  2, 40,222, 77,
-	123,179, 24, 47, 89,123,235, 75, 86,123, 85,167,193,224,158,  1,
-	 36,164, 76,146,120,  1, 41,229,171,214,248,168,138, 60,187,176,
-	242,200,115,189,208,170,213,122,221, 94,210,233, 36, 73,179,162,
-	172,  7, 24,110,245, 82, 30,225, 47, 96,161, 78,206,  3, 48, 95,
-	 38,245,111,214, 52,134,178,105,242,248,180, 64,181,169,172,214,
-	236,116, 51,163,138, 83,156,149,180, 22,143, 54,189,239,171,221,
-	 51,129,139, 13, 20, 51,  0, 36,203,  1, 88,213, 61,129,109, 22,
-	 46,148,210, 58, 81,213, 94, 13, 32,131, 48, 41, 24,131, 91, 65,
-	 64,159, 73, 17,118,146,239,152, 64,218,201,152,118,178,189,177,
-	147,243,  0,204,104,238,222,215, 27,132,183,148,150, 10,149, 54,
-	127,145,239, 61,152,174, 89, 75, 32,103,  8,215,159,177,170,214,
-	232, 52,  5,240, 56, 85,115, 24,232, 15, 33, 72,107,141,193,251,
-	191,218, 38, 99,143,105,191, 58,144,117,146, 37,150,108,238, 14,
-	224,219,231,215,213,114,230,164, 36,  5, 67,165,171,176,224,217,
-	 49,195,183,143,243,249, 60, 89,241, 89,117,244,120, 54,174,115,
-	 50,163,162, 16,213, 26,157,174,105,  3,231,241,154, 63, 63,187,
-	246, 63,222,251,180,237, 39,174, 78,219,187, 19,200, 94,109,157,
-	178,199,212, 14,116,249,160, 51,183, 15,127,179,170,212,  6, 93,
-	214,201,138, 61,172, 90, 94, 32,115,218,185,  9,192,159,127, 87,
-	139,  0, 48,206, 59,  2,233,235,141,153,186,121, 63,159,127,126,
-	 47,186,189,239,232, 89,191,254,197,  1, 12,121,181,110,  0, 47,
-	168,254,247,247,235,124,126,147, 19,130, 99,170, 77, 20,238, 58,
-	175,106,235, 50, 49,  0,188,192,103, 52,233, 94,157,235,154,154,
-	 42,222,117,146,189,204,186, 29,117, 95, 77,251,200, 46,  6,144,
-	 44,  8, 96,198,116, 85, 21,114,252, 46,174,112, 10,192, 44,239,
-	170, 53,199,224, 57,  0, 50,249,233, 24, 20,205,  4,121,173, 16,
-	188, 35,126,157,  2, 44,116,  0, 13, 55,213, 13,254, 85, 55, 22,
-	254, 42,237,210,154,143,160, 83,128,133, 19,192,201,118,246,  0,
-	 96,212,145, 82,214,236,  7,188,157,103, 84,231,  3,240,231, 77,
-	204,220,168, 39,165,185, 13, 64,202,179, 66,176, 55,107,200, 61,
-	240,107,235, 60,137,186,137,125, 82,176,161, 33,105,212,219,107,
-	242, 36,142,184,116,223, 87,212, 76, 81, 14,164,172,108,217,100,
-	154,125,174,  6,254,213,182, 41,210,164,187, 94,107,191,129,243,
-	 80,101, 90,149, 17,179,  6, 85,149,105,209,154,245,180,109,145,
-	 50,155, 67, 72, 74,  1,204,178,238, 61,118,207,167,239, 74,154,
-	 55,147,237,220,  2, 96,187, 20,128,148, 20, 90,215,241,253,115,
-	214,237,247,  1,144, 34, 40,236,157,176,112, 89,214,235,240,215,
-	214,137,248,113,177,  9, 96, 91, 37,230,251, 41, 91, 97,166, 72,
-	155,169,232, 46,136, 50, 97, 41,250, 42,170,148,143, 44,146,215,
-	217,139,108,203,129,235,161,211,108, 77,164, 35,144,182,125, 61,
-	 29, 99,131,226, 81,167,166,203,162,147,170,105,140,174, 28,226,
-	202,104,103,112,227,209, 30,220,183,  2, 48, 99,135, 65,124,253,
-	187,  2, 64,250,223, 15,125,210,248,251, 46, 12,  7, 63,128,159,
-	243, 58,250,123,254,224, 93, 61,230,247, 32,144, 51,161, 44,160,
-	 40,215,  0,236,116,216,240,253, 20,210, 76,233, 61, 80,117, 21,
-	 43, 39,151,156, 20,118,119,234,238,213, 76,121,254,219, 38, 29,
-	250,158,154, 78,165, 69,198,149,151,170,175,199, 42, 30, 53, 29,
-	128,225,177,147,178,174,179,129,147,109,164,157, 99,187, 23,  0,
-	179,174,205,224,252,251,239, 90,  0,223, 13,  0,121,142,215, 35,
-	  5,176, 90,  4, 64, 58, 23,124, 29, 58, 45,215,181,124, 53,204,
-	116,  0,187,209,215,242, 84, 22,141, 48, 83, 52,  2,203,216, 32,
-	128, 87, 57, 40,163,  6,244,196,170,178,166, 64, 13, 40, 40,101,
-	113,139, 63, 14, 32,251,131, 41,235,114,248,245, 88, 59,141,181,
-	 80,181,  5,128, 97,146,118, 31, 78,115,249,147,  0,158,172, 94,
-	156,197, 47,167, 86,200, 66,  0,118, 74,240, 77,190, 91,225,220,
-	 89, 13,193,222,169, 49,  0,176,117,233,191, 14,192,186, 42,226,
-	161,115, 95,211, 95, 21,127,253,229,112,121, 41, 19, 51,205,204,
-	246,190,215, 93,149,195,  5,129, 83,229,228,152,245,176, 51, 33,
-	 75,230,193, 45,171,194,194, 76,182, 99,131,123,104,218,125,  0,
-	 72,159,246,199,236,138, 52,  0, 95,141,193,251, 28,  8,235,122,
-	 65,  0,255,253,251,124, 31, 18,184,158,  2,148,243,191,176,155,
-	201,119,115,123,  9, 96,203, 93,  5,221, 43,  9,163,152,206,229,
-	249, 28, 80,  2, 24,208,149,113,225, 74,165, 43,233,145,240, 50,
-	180,204,153, 40,144, 12,187,217,191, 64,177,230, 96,138,199, 24,
-	210,187, 35, 86,127, 88,119, 83, 58,254,137, 94, 12,229, 76,143,
-	253,105,132,125,113, 89, 62,162,192,178, 74,139,146,  3,120, 98,
-	247,137, 33,202,223,206, 78,  0,164,143,230,253,235,223, 13,  0,
-	134, 46, 63, 76,148, 46, 10,224,191,175,119,125,229,102, 53,  2,
-	 41,127,133,156,197,118,127, 67, 69,161,  0,108,132,182,234,236,
-	171, 78,210, 36, 20,182,185,  0, 48,164, 23, 83, 14, 72,150,211,
-	  2,140,198, 99,195, 44,106, 62,149, 75,250, 27,169, 99,167,  3,
-	 42, 62,200,123,233, 55,236,149,228, 10,192,152, 85,201,175,118,
-	147, 77,213, 53,222,131,174,124, 44,  0, 44, 21,128,170, 43,206,
-	118, 34,189,157, 98, 39, 67,112,215,224,235,249,223,181,  0,  6,
-	150, 25, 44,172,144,176, 51,110,170,218, 32,229, 38,  0, 59,  2,
-	197,152,178, 38,129,116,181,176,226,163, 85,247,  7, 84,148,101,
-	103, 94, 10,  0,155,154, 91,  6, 39,142,101,198,117, 77, 89, 75,
-	  0,163,188,160,216,177,167,154,209,  2,105,162,204,100,254,254,
-	143,244, 78, 90,134,145,113,234,140,221,154, 15,157,161,168,146,
-	213, 31, 85, 10,192,164,224,245, 28, 57, 72, 93, 61,137,170,135,
-	125, 21, 43,141,105,  2, 40,218,  9,250,118, 78,142,118,154, 93,
-	 24, 33,193,208,140,157,  7, 32,123, 80,230,253,103,225, 59,176,
-	204,224,219,  0,148,  4, 30,243, 82,120,184,201, 58, 51,192,146,
-	191,159,206,134,234, 80,168,196, 59, 77,168,101,240, 34,214, 46,
-	203,238,106,206,126,121, 90, 41,  0, 99, 74,107,206,163, 57, 50,
-	250, 89,192, 72,205,100,110, 35,208, 59, 89, 25, 73,102, 83,113,
-	141, 70,237,181,174, 74,106, 12, 30,142,  5,109,137,  3,152,150,
-	188, 30,214,161,128,218, 26,177,234, 26,189, 33, 79, 56,128, 85,
-	153,155,  0, 90,237,228,174,118,246, 97,  5,211, 57,220, 53, 68,
-	232,  0,190,153,147,192, 80, 46,177, 44, 11,224,191, 79,225, 98,
-	228,107,135,107,  1, 88,203,151, 79, 99, 32,154,166,146,  0,118,
-	160,177,159,156,119, 74,175,123,229, 41,127,211,181, 42, 17, 51,
-	205, 37,  0,172,217,103, 62,162,210, 18, 71,142,101,221,193, 69,
-	131, 45,197, 23,117,197,  6,245,151,110,168,160,213, 71,210,223,
-	 46,  1,164,213,208,122,184,222,235,  0, 20, 69,104,171, 20,199,
-	194,  3, 96, 84,233,237, 80, 59, 61,227, 15,206,104,167, 89,  2,
-	192,179, 91, 76,179,212, 35, 10, 64,219,  2,166, 11,177,182,124,
-	185,  0,164,181,  4,166, 43,250,189, 95,140, 27,  2, 88, 89,  0,
-	158,  7, 39,214,242,150,220, 42, 89,  5, 58,148,107, 13,194, 44,
-	 26, 55,224, 51,177,134, 79,251, 21,128,101, 33,172,142, 70,233,
-	180,188,106,180, 18,148,  9,174, 24, 51,118,185,231,172,191,179,
-	101, 95,136, 66,194,107, 18, 82,141, 46,180,212,169,168,217,189,
-	178, 26,230,100,206,148,113, 28,137,150, 68,215,124,  0,210, 96,
-	222, 90,111, 39, 25,182,243,226, 80,128, 87,  0,120, 56, 58,101,
-	160,145,220,133, 84, 67,150, 70,250, 57,191,191,  6,118,121,211,
-	214,144,  0,134, 54,194,  2,237,116,184, 26,236,  6,208, 17,  4,
-	 72,  3,114, 62, 93, 12, 10, 11, 59, 93,141, 64, 58,  5, 84, 47,
-	159,197,231,106,  0,242,113,172,108,212,100, 44, 46,217, 27, 45,
-	122, 59,185,236,201,233,202,191,  8,  0, 75,174,  1, 11, 86,101,
-	167, 98,179,128,235, 55,161, 71,131,186, 55,177,179,138,125,238,
-	251,192,128,229, 14, 29,101,238,240,169,117, 91,123,  1,100,128,
-	214, 98,154,208,181, 83, 56,219, 89,  2, 64,207, 17,235, 95, 19,
-	175,216, 60,142,243,103,232,241,112,135, 68,143,  0,104, 18,255,
-	245, 38, 84,224, 96, 12,190, 20, 64,246,179, 95, 63, 28,174,201,
-	159, 15, 17,153, 96,199,122, 45,103,131,  8,  3,128,  3,216,234,
-	  0,158,122,184,142, 82, 91,153,  0, 10, 29,101,  0, 72,117,231,
-	 11,191, 42, 66, 87,178,163,244, 32, 10,180,168,194,202,196,152,
-	222,106,  0, 74, 96, 21,128,220, 62,202, 90,238,219, 25,  7,176,
-	 41,123,  0, 85, 59, 77,223,142,253,244, 54,  2,112, 96,  2,159,
-	223, 60,229,220,  0,198,108, 70,123,118, 77, 47,147,129, 10,156,
-	  3, 32, 59, 40,217,158, 44,126,190,138,  5, 90,177,202, 66,214,
-	208,128,177,152,187, 91, 26, 48,228,122,164,123,139,201,169,147,
-	180, 18, 26,202,  6,144, 82,164,  3,200,237,222, 74,  0,197,202,
-	 28, 43,  5, 78, 68, 71,221,144, 86,153,203, 42,117,  0,133,234,
-	165,  0,102,226,201,150, 28, 83, 47,128,220,247, 87, 40,  0,249,
-	247,177,217,206, 78,  0, 52, 39,112, 82,125, 77,  3, 40,188, 56,
-	113,104,107, 81, 49, 11, 60,101,230, 80, 57, 19, 64, 58,197,253,
-	117,219, 62, 71,123,161,121,193, 57,160,112,247,149,214, 28,144,
-	 91,149, 17, 37,161,200,115,222,133, 17,  0,139, 23, 53,  7,228,
-	119,134, 85,171,134,111,186,128, 33,153,230, 38, 78,206,226,146,
-	218, 17,  0,187, 79,177, 17,247, 48, 14, 96,165, 76, 25, 87, 59,
-	100, 47,  0,154,133,127, 63, 14, 51,  1,228,206,177,179,203, 90,
-	  8,213, 80, 73,174,  2,240,240,106, 17, 40,254, 62, 88,192,245,
-	 10,150,176, 54,117,162,171,137, 69, 33,157, 32,236,213,241,185,
-	 27,115, 81,167,105,154,209,175,203,102, 26,192, 70,221,121, 76,
-	178, 92,248,135, 15,220,221, 34, 86,200, 66, 81, 37,243, 61,250,
-	  0,108,148, 93, 33,230,202,163,  0, 18, 29, 64,103, 59, 59,153,
-	  3,154,243,183,207,215,185,  0,114,183,186, 89,139,180, 22, 66,
-	195,103, 55, 31,192, 78, 61,255,220, 85,  5,242,145, 43,181, 39,
-	193,204, 15,152,219, 11,250,157,101, 49, 13,160,235,206,132, 27,
-	208, 89,100, 87,217, 15,158, 45, 31, 74,115, 17,163, 64, 43, 74,
-	251,117,234, 83,126, 25,128,141,167,157,219,194,177, 72, 30,188,
-	208,209,220,101,220,186,  1,244, 88,194,131, 80,130,190,253, 97,
-	 65, 55,128, 73,194,127,154,233,140,254, 21,  4,246, 62, 59,190,
-	 87,193, 11, 96,247, 75, 94,  2, 46,221,111,210,  9,252,117,171,
-	192,124, 21, 21,200,223, 91,102,131,198, 86, 66,138, 44,158,  5,
-	 32,119,213,112,208,  6,119,114,107, 67, 57, 14,205, 32,129,218,
-	 13, 32,171, 63,239, 81,186, 28, 64,119, 59,183,249,  1,233, 24,
-	223, 85, 75,215, 10, 13,137,124,  0,210, 21,244, 56,177, 11, 27,
-	193, 84,255, 62,148, 43,196, 40, 29,143,  0,152, 30, 29,164,252,
-	 10,119,116,192, 52,149, 10, 21,247,  2, 72,123,167,119, 44,112,
-	235, 93,117,195,105, 61, 21,200, 92,191, 39, 11, 64,238,145,139,
-	189,209, 48, 35,  0,242, 42,245, 55, 27, 21,210,218,200,109, 50,
-	106, 47,128, 45,155,194,117, 79,231,200,159,129, 13, 96,226,  2,
-	208,211,206, 13,  0,138,253, 90, 21, 91,242,211, 37, 77, 99,123,
-	101, 66,198,118,208,148,  3,108,238,162, 10, 71,158,112,210,195,
-	 41,210, 75,167,108, 89,211,  3, 96, 42, 94, 74,232, 38,240,148,
-	235,  4,250,  1,228,237,245, 93,147, 83, 37,107,161, 90,212,203,
-	 77,108,178,130, 10,100,184,164,161,  5, 32,127,141, 73,120, 41,
-	128,210,163,205, 62,151,250,157, 65, 42, 92,244,188,202, 56,240,
-	132, 99, 73,  0,185, 27,177,251,181,130, 64, 62,  3,205,115,  9,
-	160,182, 22,236,  6, 80,180,243,178, 88, 60,224,183,216, 48,195,
-	 34,177,115, 93, 88,159,156,  0, 70, 44,229,  5,237,119, 95,216,
-	 11, 32,229,143,209, 32, 10,102, 99,  0,138, 25,182, 69,224,171,
-	 36,176, 82,  4,122,  1,140, 98,217, 57,254,131,186,207, 82, 11,
-	 13, 86,170,127, 60, 94,198,  5,103,129, 53, 27, 90,244,125, 23,
-	 81, 38, 76, 98,235,139,130,186,147, 85,137,186, 72,216, 69,174,
-	221, 34,241, 89,141, 86,236,206, 40, 85,127, 59, 68,  0,197,118,
-	159,200, 26, 89,120, 85, 44,111,229,214, 44,253,151,112, 99,211,
-	 27,132,102, 72, 99, 21,142,197,154, 42,171,130,117, 37,109,164,
-	163, 90,117,192,209, 78,124, 35,128, 93,207, 58, 29,200,226, 53,
-	116, 73,125, 17,162, 81, 34,226,139, 52,241,  2,200,248,211, 10,
-	231, 99,  0,230,169,123,190, 38,  9,204,122,  2,253,  0,210,222,
-	209,150, 74,245,139,114,  1,118,112,118,141,193, 71,186,155,111,
-	 21,  0, 57,129,250,216, 34,221, 22,140, 35,253, 11,182,161,144,
-	171,  1, 86,162,149,155, 51,196,231,188, 80,170,174,175, 82,109,
-	 88, 85, 19, 41,125, 24,163, 95, 54,250,173,162,162,178,106, 36,
-	178,131, 25,106,204, 66, 38,104,249,154,117, 79,116,214,232, 12,
-	189,109,216,206, 45,193,  8,114,151, 83, 67, 23,151, 13, 41, 51,
-	 63,128,105, 70,223,175, 94, 56,246,  2,200,249,147,133,217, 50,
-	168,  7, 64,250, 26, 34,183,205, 42,  8, 60,102,210, 22,110, 71,
-	  0,100,189,211,250, 70,159, 37, 39,240,253,199,101, 97, 39,249,
-	 90,158, 24, 54,210, 25,127,216,210,157, 73,167, 61,198,245,138,
-	 45, 12, 83, 53, 32,214,103,235,238, 99,165,104,149,159,197,157,
-	101,127,147,182, 87,195, 85,165,121, 43,251, 87,163,254,149, 88,
-	217,125,106, 94,190,209,186, 98,118,198,213, 78,115, 51,128,116,
-	111,104, 99, 10,223,149,226,  4, 48, 78,216,223, 94, 93,247,101,
-	235, 81,  0, 89, 97, 30,119, 81,151, 35,  0, 82, 69, 25,120,  8,
-	124,235,  9,164, 74,112, 12, 64,222,187,190,115, 44,222,232,228,
-	114,149,139,144,132,245,156,209,124,116,209,254,180,107, 77, 99,
-	 25,215,121,120,  1, 13, 90, 81, 47,157, 62, 50,237,115,159,119,
-	 71, 84, 89,235, 41, 75,164, 26, 49,154, 18, 85, 54,178, 81, 81,
-	 17,113,  3, 24,178,213, 99, 94, 94,239,138,217, 25, 87, 59,228,
-	 22,  0,191,221,153,246, 26,182,109,198, 13, 96,202, 71, 12,189,
-	112,226,  3, 48, 97, 91, 58,120, 82, 22, 54,137,246,  2, 72, 53,
-	101, 41,172,176,110,184,253,112, 18, 40, 51,208,140,  0,200,129,
-	111,180,206,213, 66,159, 15, 23, 11,127,125,209, 54,203,238, 11,
-	214,254,184, 91, 65,140,231, 11, 61,143,156,245,153, 12,238,236,
-	175,105, 35,153,166, 71, 68,154, 30,121,239,183, 81, 17, 31, 88,
-	 13, 75, 60, 40,106, 45,163,162,153,210,206,172,197,209,206,247,
-	 13,  0,186, 19, 58,180,109, 49,  6,160,225, 18, 17,251, 87,221,
-	  0, 26,133,  5, 56, 30,  0,121,224,112, 32,187,251,229,138,225,
-	147,  4,142,  3,104,246,142, 13, 26,177,189,208, 39, 22,107, 78,
-	106, 46,191, 82, 90,  4, 50,124,159,151,124, 49, 47,239,235, 21,
-	 85,210, 92, 33, 39, 37, 97, 92,244,243,201,203,196,159, 62,116,
-	145, 28,209,211,  0,234,133, 39,  1, 84,191,122, 20, 64, 54, 75,
-	244, 17,248,174,141,194, 77, 57,  5,160,241,164, 26, 17,  4, 58,
-	  8, 24, 19,183,136, 44,150,150, 41,247,220,210,114, 19, 61,229,
-	134,112, 46, 31,193, 34,169,143,231,103,201,159, 15, 96, 59,  1,
-	224,135,  4,176,119, 21, 76,  2, 88,242,208,117,225,230, 58,190,
-	 59,  9, 60,177, 98, 94,  0, 29,189,227, 19,231,216, 17,108,115,
-	148, 75,181,142, 73,224,179,243,215,242, 72,  8,238, 34, 43, 10,
-	205,197,181,  5,128,142,217,243, 40,128,154,235,246,  2,  0, 53,
-	125, 52,  5, 96,163, 17,120, 24,228,248,144,145,  9,180,220, 37,
-	  0,234, 83, 92, 17,190,118,254,231,222,248,105, 37,224,226, 89,
-	115,226,167,150,200,144,171,171, 73,178,155,135, 96,167,  7,225,
-	  2,  0,251,194, 23,  0,232,203,233,162,  3, 88,115, 75,185, 39,
-	240,203,181,118, 65,131,248,138,177, 33,216,156,209, 73,155,239,
-	104,  3, 24,170,180, 74, 46,  0,219, 36,132, 92, 32,233, 51,  1,
-	200,172, 86, 31,129,191,125,  4, 75, 97,237,129,242,  2, 40, 61,
-	114,161,181, 24,242, 25,138,166,109,  0,149,119,212, 41,210,119,
-	114,233,245,181,228,166,246,184,147,148,201, 45,213,184,204,224,
-	199,  2, 48, 48,  1,228, 43,131,145,236,244,143, 59,130, 37,159,
-	  9, 32,225,121,162,222,221,  0, 90, 59,143, 71,  1,148, 47,110,
-	248,206,124,215, 87,196,175, 20, 46,231, 27,240,237, 93,145,  0,
-	 80,172,  2, 48,  2,133,143,234,116,118,  6,241,229,217, 24,128,
-	 86,152, 46,  3, 48,246,107, 64,121,203, 64,  5, 74, 55,187,253,
-	230, 82, 17, 91, 58,188,158,168, 77,144,247, 33, 48, 19, 75,104,
-	 27,  9,119,  4,146,  7, 31,130,135,  0, 10,183, 73,236, 10,115,
-	149, 42, 48,155, 13, 32,239,163,115, 14, 24,186,252, 48,254,115,
-	112,168,103, 59, 17,161,125,195,235,177, 58,176, 98,125,105,228,
-	118,224,248, 62,237,141,157,  3,244, 92,  0, 10,  2, 19,215,102,
-	 99, 25, 64,144,206,  2,144, 31, 64,224,179,130,195,212,229,135,
-	241, 59, 48,228,246,216,212,242, 54,150,177,182, 17,115,117, 63,
-	 74, 43,  0,140,154,155,125,217, 11, 31,164,246,232,  0, 26,  4,
-	 14, 48, 19, 65,124,201,124,  0, 35, 27,192,227, 53,  0,170,124,
-	227,169,229,108, 20,  0,182,119,115, 37,167, 18,192, 93,241,183,
-	 12,128,249,134,  0,234,163,240,209,149,184, 55,188,  2,192,192,
-	138,138,150, 49,172, 46,  0,173, 85, 39,123, 17, 75,  3,141,219,
-	 78, 42,138,212,125, 80,222,176,202,171,180,158, 46, 50, 81, 65,
-	221,120, 23,223,218,169,126,172,114,152,238,227,  3, 40,  8, 12,
-	 14,158,122, 79,241,108,  0,107,123,235,252,135,181,122, 55,208,
-	153,116,131, 73, 55, 57,204,130, 32, 12,163, 36, 43,106,181,136,
-	149,171,104, 57,150,239, 52, 22, 73,131, 76,  0,233, 23,225,169,
-	207, 29,209,168, 31, 87,101, 81,120, 10, 34, 61,253,184,190, 77,
-	140,237,184,181,103,164, 69, 18,  6,125,117,185,220, 80,126,144,
-	 11,186,101, 87, 40,165, 31, 10,217, 14,219,237, 67, 63, 68,122,
-	190,136,180, 92, 59, 59,241,227,  3,200,151,207, 50,199,214, 60,
-	254,187,226,217, 70,  8,173,235,195, 21, 13,227,  4,176,207,163,
-	155, 52, 90, 82,218, 48, 23,  1,205, 52, 18,179, 18, 19, 86,185,
-	122,125, 72,114, 29,192, 14,220,193,134,144, 90,106,208, 88, 11,
-	  2,117,216,235,214,145, 74,206,156,226, 89, 51,204, 99,170,210,
-	154, 23,114,181, 77,228, 42,111,234, 97, 62,242,122, 85,  2, 31,
-	 28, 64,181,120,193, 51, 28,187,139,207,118,195, 68,222,173,243,
-	177,195, 10,230,138,142, 39, 76, 54,226,230,162, 86, 69,210, 37,
-	237, 32,217,178,  1,160,142,153, 14, 96,219,148,250,214,141, 83,
-	 57, 80,188,114,213, 48,110,245, 80, 43, 51,131,254, 65, 38, 42,
-	 72,134,105,166,185, 29, 94,200,152,103,174,120,187,203, 86,166,
-	222,114,213,252,216,143, 14,160,138,211, 78,173, 48, 82,233, 58,
-	153,  6,208, 28,193, 74, 71, 68,116,168, 71,236, 12, 29,209, 42,
-	 99, 69,108,166,110, 78, 91, 29, 64, 35,217,119,156,233,219,192,
-	237, 13,180, 85,171, 37,185, 53,210,134,155,237,242, 28,104,173,
-	254,128,109,254, 92,  0,214, 21,207, 73,152,203,108, 32,222, 84,
-	209,131,102,  1,224,208, 18, 16,  4, 22, 86,  4,129,216,240, 30,
-	204,  1,144,254, 35,244,237,  9, 57,156, 18, 71, 64, 32,127,127,
-	 60, 60, 54, 55,  3, 55, 91,185,155, 34,161,150,135,158,238, 94,
-	  2, 72,109,  2, 87, 50,239,170, 29, 36, 46,231,237, 55, 38,128,
-	 42,123, 86,127,168,151, 51,167,184, 19,192,162,  7,176,181,  1,
-	212,115,153,157, 26,  0, 56,230,140, 19,131,240,209,115,130,215,
-	 28,  0,229, 12,112,160,  0,229, 20, 48, 76, 82,103, 48,  2,205,
-	173,193, 51, 70,178, 61,211, 42, 41,120, 35,253,128,221,236, 80,
-	 38,251, 14, 98,182,245,165,  7, 80,234, 57,154,159, 92,236,155,
-	166,217,208,104, 58, 34,149,184, 60,142,142,234,  4,  4, 19,192,
-	 80, 63, 85, 78,207, 41,206,107,227,222,129, 66,  2, 24,240,125,
-	168, 69,105,109,195,148,185, 96, 68,144,101,204,130,255,228,174,
-	206,100,197, 19,  2,158,  0, 64, 65, 96,224,  1,240,116, 49,128,
-	108, 58, 84, 56,246,  5,203,228, 33, 81,146,121,  0, 20,185, 73,
-	143,124,119,103,202, 49, 10,106, 45,147, 36, 31, 45,105, 50,111,
-	182,243, 47,143,212,  6,238,228, 32,179,131,247, 73,195, 85, 62,
-	 54,150, 21, 70, 93,215, 79, 71,229,219,119, 57, 97,149,124,106,
-	 50, 55,185, 76, 65,222,103, 53,231,  0,202,136, 62,207, 70,116,
-	 21,229,155,100,226,135, 88,205, 62, 31,128,255,110,177,130,181,
-	 32,170,112,232,  8,188, 16,192,214,  8, 85,167,161, 88,158,204,
-	  8,108,147, 85,225,140,  7, 84,137, 48,146,162,232,147,133, 71,
-	 42,153, 51, 77,116,197, 15, 86,224,187,  4, 75,  5,160, 76,124,
-	 26,242, 13,169, 42,153,183,156,223,177,196,229,125,250,241,220,
-	216,218,161, 82,162, 70, 98, 23,134,204, 77,126,202,120,109, 90,
-	 86,115,238,  7,100,123, 25,248, 94, 54,103, 50, 34,  9, 96,218,
-	 21,116, 55, 11,  0,109, 55,140,210,128,102,113, 17, 64, 48,  1,
-	160, 89, 15, 13,199,183, 78,208, 17, 46,109, 58,  5,244, 68, 68,
-	 43, 21,120, 42, 89,224, 73, 38, 67, 13, 36,128,149,240, 84, 38,
-	 34, 32,165,148, 89, 37,125, 73,195,229, 90, 73, 88,136, 26, 83,
-	 99,176, 29, 12,253,204, 16,230, 36,133,178,153, 74,198,235,210,
-	115,103, 37,128,124,139,162,157,144,114,  8, 96,198, 82, 59, 59,
-	155,  5,128,110,  0, 43,187, 19,193, 92,  0,153,107,236,100,157,
-	160, 35, 83, 91,135,137,123, 79,136,174,  2, 83, 58,219, 43,153,
-	126, 59,246,231, 41,196,149,200,100,193,143,158, 83,249, 52, 82,
-	153,133,247,200,246,  3, 10,203,148,101,177,170, 75, 45, 59, 56,
-	229, 59,146,170,206, 28,131, 51,117, 52,  7, 79,174,250, 34,207,
-	 23, 83,233,160,121, 86,115,115, 37,100, 18,192, 90,  4,187,241,
-	 95, 21,  1, 64, 29,192, 68,110,167,212,151,247, 67,123, 31,199,
-	225,  2,  0, 43,185, 60, 79, 79,160,228,  9,185,134,252,137,220,
-	151, 98,155,179,107, 91,166,166,  2, 95,120,166,220, 35, 31, 72,
-	 27, 13, 64,145, 35, 87, 90,157, 10, 64,158,181,158,231,105,206,
-	197,174,199, 62,105,120, 42,182,  1,139, 60,145, 38,128,164,233,
-	 84, 96,202,211,175,164,194,157,114, 18,137,  0,205,172,230, 42,
-	181,110,191,213,119, 20,192, 92,238,121,231,217,176,118, 14, 96,
-	118,111,  0,121, 70,  3, 61,220,141, 89,131,239,174,173,148, 35,
-	 86,112, 95, 79,247,220, 69,106,160, 87, 71,134,212, 64,142,192,
-	206, 41, 96,239,137, 17,241,  5,114, 27,109,174,157,167, 32,183,
-	 49,231, 42, 15,185,  9,224,161,178,147,134,139, 44,149, 50, 91,
-	 80,196,227,169, 44, 15,164, 56, 27,132,158,208,166,178, 19,101,
-	131,172,230, 42,185,184,210,247, 83,  0,138,125,238,174,102,255,
-	 60,128,222,180,151,159,206,153,155,215, 17,237, 74,136,249, 97,
-	 31,224,164, 18,  8,135,158, 41,160,169,  2,  3, 57,173, 11,181,
-	243, 20, 40,128, 34, 15, 57, 25,  2,152, 31,149,221,107, 38, 13,
-	143, 69,122,104, 65, 66,160,238,183,210,106,157,250,243,145,196,
-	129, 91,202,189,195,179,154,119,  0,242,164,245,141,220, 51,174,
-	122,208, 76,  0,168,154,253, 27,  0,214, 87,  3,104, 29,126, 45,
-	 87, 47, 46,  7, 48,124,119,100,201, 87,  9,132,143,124,  4,118,
-	230,103, 51, 84,160, 48,  4,242, 90,  3, 80,158,126,116, 40,172,
-	 33,152,147,121,162,234,146,101,146, 18,121,134,100,122,250,164,
-	213,194,186,216, 97,107,102,179, 61,129, 97,143,109, 87,174,169,
-	 51, 90, 91, 42,178, 22,137, 44,212,165,166,  1, 99,165, 19,189,
-	  0,186,155,125, 82,  0,227, 91,  0, 12,222,206, 95, 30,223,201,
-	101,  0,  6,175,239,231,179,235, 16, 40,201,177, 80,128,158,204,
-	 28,186, 10,148, 71,193,104,231, 41, 80,  0, 83,177, 87,153, 71,
-	 71,245,  0,202,108,226,133,158,135,188, 63,218, 67, 36,  1,228,
-	133,130, 65,122, 41,153,216, 45, 17, 71, 41,168,  3, 62,142, 25,
-	 75, 77, 37,179, 98,181,242,192,135, 80,238,131,110, 36,224, 41,
-	 75,239, 34, 15, 85,208,230,128,173, 58,112,206,106, 22,  0, 30,
-	173,179,142,190,124, 35,231,201,  3,224,251,224,168,164,207,159,
-	177,179,186,152,  2, 76,115,111,110, 34, 93,  5,202,  3, 40, 91,
-	 29,192, 62,215,119,  7,114,154, 36, 60, 42, 43,213,242,144,179,
-	147, 82, 89,206,214, 52,237,230,112,125,146,231, 83,148,136,115,
-	 88,169,113,106,121,128,250, 28,186, 49, 61, 89, 43,143,250,245,
-	147, 88,164,224,172,104,109,145,116, 37,209,181, 16, 90, 50, 59,
-	245,253,225,121,223,117, 43,152,174,233,120,155,  5,128,231, 95,
-	 93, 70, 14,150,227,103,195, 58,  0,252,152,184,223, 60, 47, 83,
-	154, 62,222,163, 66, 52, 21,200,127, 13, 43,217,175,132, 84,101,
-	238,200, 67,206, 64,112,229, 33,175,251,227,181,244,248, 26, 43,
-	191,153, 24,207,185, 10, 12,184,191,198,209, 12, 45,147, 30,141,
-	181,230,193,249, 11,135,161, 31, 48, 24,107,246,185,  0, 60, 95,
-	  3,224,228, 57,151, 82,115, 69, 62,  0, 47, 57,171,240, 71, 61,
-	155, 32,246,155, 32, 67, 95, 32,159,251,183,230,153, 51,213, 32,
-	101,115,159,103,207,149,135,188, 98, 46,144,  1,129,161,235,180,
-	 73, 62,190,178,225,244,200, 51, 51, 91,201,166,197,216,172,115,
-	 94, 58,  1,215,  0,212,  2,193, 92,205,  2,192,  9,114,126,229,
-	 60,239, 20,223,  0, 96,207,159,240,217,140,156,149,100,170,192,
-	 84, 36,  9,173,250,163,127,233, 84, 45,176,  0, 20,115,184,163,
-	  5,160,157,229,155,103, 25,183,179,210,168,104,176, 64,228, 38,
-	 79,173,102,248,245,216,  0,208,  6,220, 88,138, 11, 70,154,  5,
-	128,167, 41,  0,123,211, 33,142,175,  6,240,231, 67,233,146,144,
-	231,218, 28,201, 78,169,207,  2,197,185,104,204,148,136,245,132,
-	247,233, 32,105, 55,207, 44,206,206,231, 61, 13,  1, 20,233,233,
-	213, 15, 73,173,232, 89,149, 59,168,204,228,177, 88,156,180, 97,
-	 14,242, 76,172,106,244, 57,203, 75,153, 68,252,228,  1, 80,102,
-	 95, 12,197, 27,252,222, 59,128,239,187,  2, 80,153, 14,167, 56,
-	185, 26,192,175,254,193,136,  1,120,244,176, 56,161,  2,227, 40,
-	138, 19, 45,215,114, 70,115, 95, 23, 98, 97,139,102,155, 87,169,
-	126,186,235,101,219,167,108, 78,212,245,238,139,186,207,242, 77,
-	 45,  4,205,  3,100,242, 87,177,240,155,248,120,144, 94,110,171,
-	153,152, 53,211,202,156,229,180, 50, 86,191, 32,176,111,150,246,
-	167,174, 21,128,  9,251, 33,217, 74,  9, 17,159, 28,192,207,119,
-	 77,115, 37,238, 83, 76, 38,  1,252,124,239, 35, 50,121,254,234,
-	241,227, 50,213, 30,164, 62,215, 55, 79,114, 47, 51,136, 55,125,
-	150, 51,153,110, 92,207, 38,158,235,249,201, 27, 98, 36, 40,231,
-	 33, 84,118, 24, 88,155, 26,137,115, 91,149,152, 89,175, 77, 53,
-	175, 42,147,217,165,  7,  5,121,148,150,140,134,201,115,153,139,
-	109,247, 33,249,153,149, 74,229, 58,  0,179,139,  1, 12,206,151,
-	241,247, 66,189, 26, 87,  1,248,171,157,224,121,140, 18,109,  0,
-	 38,254, 71,193, 95,190,204,238,253, 45, 50,197,203,164,221,173,
-	150, 53, 92, 36,106,209,246, 54,151,195,100,222,122,154,241,178,
-	172, 92,187,145,219, 58,209,143,113,179,147,147,235,205,244,151,
-	101,253,118,193,166, 86, 70,136,175, 89,  0, 56,  9, 96,207, 31,
-	 61,137, 33,189, 10,192,175,115,104,240, 39,227, 22,198, 94, 70,
-	159,165,168, 95, 80,100, 23,154, 62,131,115,211,104,153,170,180,
-	108,226,252, 62,153,250, 71,223,114,218,136,212, 42,142, 24, 28,
-	229, 40,230,103,163, 84,205, 68, 51,178, 50, 99, 79,181,209,172,
-	 90,123,203, 42, 95,179,  0,112,  2, 64, 93,117,209, 40,119,158,
-	154, 99, 30,128, 63,231, 55,237,153,176,  3,109, 10,227, 16, 78,
-	239,179, 32, 70, 14, 20,125,167,186, 43,197,187,153, 77,124,244,
-	 11,226,216, 22,172, 39, 15,143,114,105,162,120,154, 49, 46,219,
-	 87,100, 22, 25,177,152,156,139, 36, 50,100,229,109,193,207,  7,
-	160,174,186,152,233,192,179, 99,205,  1,240,231,252,174, 25,145,
-	199,139,249, 51,114, 36, 12, 47,248, 82,120,248,114,123, 56,146,
-	 46,184,140,158, 52,226, 39, 16,101, 98,222, 56,214,204,212, 21,
-	233,209,161,246, 72,209,199,186,125,127,  3,192,139,  1,252,210,
-	 85,151, 48, 29,230,  1,248,251,101,224, 39,248,155,158,  0,154,
-	  8, 14, 47,184, 16, 37,254,252, 30,174, 27,156, 83,206,138,159,
-	 68,148,203,115,109, 38,106, 27,187,210,231, 35, 47, 10, 45, 85,
-	242,247, 55,  0,188, 20,192,159,207,243,155,230,214,234,248, 99,
-	 71, 42,229, 23,  3,248,219,213,240,241,106, 60,141, 19, 59,237,
-	 46, 87,199, 57,124,239, 71, 88, 40,140,200, 59, 89, 46,114,128,
-	211,240,168,163,187,252,138,197,  0,252,250,209,100, 10,192,201,
-	194, 10, 64,163,160,  6,224,143, 41, 95,231,243,249,253,117,136,
-	 14,229,143,167,232,117,  0,104,222, 79, 43,248,120,123, 29, 60,
-	138,112,192,223,206,  0,108,213, 65, 72,205, 34,189, 51,206, 90,
-	186,211,175, 88, 10,192,215, 55, 67,198,  1,156, 46, 44,  0, 12,
-	204,130, 74,191,157,222,  6,242, 26, 14, 22, 64, 95, 24, 58,133,
-	 72, 82,238,  0,112,112,191, 85,129, 24,126,121, 37, 59,228, 79,
-	 88,221,173, 58, 60,137, 44, 86,229, 61,127,235, 98,  0, 58,197,
-	  7,224,116, 97,  1,224,213, 18, 42,254,234,194,123,158,251, 69,
-	117,236,150, 63,151, 85,177, 96,149,223,  0,240,122,252,184,229,
-	192, 76,215,186,185, 18,192, 83, 36,135,223,106,167,252, 57,172,
-	238,197,170,188,223, 79,120, 70,  0,229,204,141,109,117,100, 71,
-	117,205,  6, 48,136,148,250,219, 47,127,207, 32,107,  3,152,207,
-	  1, 48, 95,  4,192, 32, 74,116,213,213,150,190,196,129,126,  5,
-	 26,242, 42,196, 18, 44,248,123, 92,  0,  7,251,104,199,  1,204,
-	236, 93,113,179,229, 20,198,137,161,186,102,  3,120,100,202,207,
-	194, 15,252,237, 24,192,212,247, 50,147, 57,  0, 38,183,  2,120,
-	 12, 66,177,163, 66,103,103,  6,128,199, 83,200,224,211,170,  0,
-	127, 15,  0, 32,169,104, 18,155,100,112,162, 29, 93,208,113,164,
-	177,106,203,177,194, 58,128, 45,143,133,179, 75,134,145, 75, 24,
-	 57, 12, 29, 83,117,249,  1, 12,196,  1,102, 42,110, 78,171,129,
-	 85,161,101, 95,  0, 41,123,  5, 80,186,207, 89, 16,228, 64,178,
-	126,  9, 85, 47, 92, 93, 80,152,200,248,185,204, 46,233, 23,177,
-	 44,101,168, 46,226,  5, 48, 20,208, 13, 42, 96,244,113,252,160,
-	254, 30,  6,192,202,  8,169,204, 50,253,108, 89, 50,  0,176,150,
-	 97,150,174,194,122,226,221, 65,160,230,148,176,  0, 74,190, 46,
-	165, 39,142,241,  3, 72, 67,131, 83,179,  2, 89, 67, 85,247,248,
-	129,191,189,  3, 56,140,108,236, 67, 28,135,  1,141,164, 39,208,
-	 95,152,232,168,186, 74,250, 69,156,255,103,156,  7, 52,  2,160,
-	 48, 53, 92, 53,244, 85,  0,146,  7,  0, 80, 44, 74,150,134, 84,
-	124, 20, 27,  6, 95, 92, 86, 88,  6, 80, 90,  5,189,162,194, 42,
-	 53,118,198,  1,228,206,194,194,174, 64, 63,205,  5,140,236, 28,
-	 64, 25,117,233, 58, 44,210,158, 68,201,128,221,201,194,102, 64,
-	240,229, 39, 50, 14,208,153,  2,208,204,178,213,200, 26, 90,  2,
-	252, 30,  6, 64,103,100,173,121,216,211,112,165,231,146,194,163,
-	  5, 39, 78,100, 52, 56,102,  0,158,191,152,136,168,154, 99,159,
-	241,153,229,171, 53,207,144,188,251,122, 40,  0, 92,  0, 64, 79,
-	 92,185,245, 30, 47, 47,236, 59,246,108,130, 59, 43,224,178,100,
-	169,135,152,152,225, 55,145, 74,116,233, 60, 22, 13,112, 60, 10,
-	128, 99,199, 69,186, 83,153, 93, 86,120,137, 99,241,  4,128, 78,
-	145, 41,122,219, 75, 15,214,131,236, 21,192,239, 89,103, 36, 46,
-	197,234, 37, 85, 92,  2, 32,224,123,124,  0,221,184,204, 67,246,
-	 58,245, 58,117, 26,232, 12,  0, 65,195,131,  3,184,203,223, 55,
-	  9, 32, 66, 93,  0,224,102,  0,250, 50,238, 66,  0,224, 29,  0,
-	140, 51,  0,  8,  0,215,  7,176, 41,139,130,  5,224, 12,  2,107,
-	226,201,124, 87, 16,  0,184,  0,128,190,168,154,108, 34,225, 31,
-	  4,  0, 46,  2,160,200,114, 54, 12,171, 17,167, 70,182,  0, 16,
-	  0,174, 14, 96,237,140,191, 49,195,111, 32,  0,112, 61,  2, 27,
-	153,172,204, 12,191,217, 95,190, 13,  0,248,140,  0,242,248,155,
-	198, 21,126,  3,  5,  8,  0,239, 65, 32,185, 44, 86,  7,  2,  0,
-	215, 34,112,230, 18, 30,  4,  0,222,137, 64, 48,  0,  0, 55, 68,
-	 16,  4,  0,192,173, 96,196,203,  7,128, 16,  0,  8,  0, 33,  0,
-	 16,  2,  0,  1, 32,  4,  0, 66,  0, 32,  0,132,  0, 64,  8,  0,
-	  4,128, 16,  0,  8,  1,128, 16,  8,  0,132,  0, 64,  8,  4,  0,
-	 66,  0, 32,  4,  2,  0, 33,  0, 16,  2,  1,128, 16,  0,  8,129,
-	  0, 64,  8,  0,132, 64,  0, 32,  4,  0, 66, 32,  0, 16,  2,  0,
-	 33, 16,  0,  8,  1,128, 16,  8,  0,132,  0, 64,  8,  4,  0, 66,
-	  0, 32,  4,  2,  0, 33,  0, 16,  2,  1,128, 16,  0,  8,  1,128,
-	  0, 16,  2,  0, 33,  0, 16,  0, 66,  0, 32,  4,  0,  2, 64,  8,
-	  0,132,  0, 64,  8,  4,  0, 66,  0, 32,  4,  2,  0, 33,  0, 16,
-	  2,  1,128, 16,  0,  8,129,  0, 64,200,165,111,184,165, 66,  0,
-	 32,100, 67,254,218, 22,  0, 66, 86,127,151,132,216,186, 78,  2,
-	232,184,188,139, 83,227,  1,224,179,233,186,193,123,107, 91,167,
-	 10,116, 99,  9,  0, 33,183, 15,182,196,117,113,  0, 32,  1,128,
-	144,165,197,137, 90, 15, 32,113,149,  5,128,144,229,  1, 36,174,
-	139,198, 85,143, 94,  4,128,144, 37,  0,108,157, 23,219,169,162,
-	  0, 16, 50,203,228,245,154, 27,218, 23,196,  9, 32,241,  1,216,
-	213, 73,  0, 32,228, 82,131,195, 99,110,104, 88,233, 23,137, 75,
-	 45,146,137, 90,  1, 32,196,111,239,182, 62,  0,201,252,139, 58,
-	152,  0, 16, 50,223,224,189, 29,192, 22,  0, 66,174, 55,120,111,
-	  6,144,  0, 64,200,108,131,151, 56, 13,222,118,148,181,118,158,
-	101,  2,  0, 33,126,  0,221,166,  5, 93,230,229, 43,195,173,125,
-	149,180, 83,230, 10,  0,132,220,  8,224,165, 66,  0, 32,228, 22,
-	 51,216, 55,181,155, 13,160,215, 50,  6,128,144,139,  0, 36,215,
-	240,215, 42,199, 51,  0,132,140,189, 37,226,  7,176,189,158, 62,
-	141,193,214, 15,224,186,139, 35,  0,240, 65,244,157,119,213,163,
-	189,137, 62, 87, 21, 19,141,  3,192,191, 57,222, 18,143, 21,178,
-	188, 76, 53, 14,  0,255,166,197, 75,124, 42,112, 97,185,111,220,
-	 22,  0,124, 28,151, 11,185, 15,128,110,206,  1, 32, 44,222,251,
-	 16, 72,166,154,  6,128,240,249,221,103,  8,190,139,107,  6,  0,
-	 62,208, 24, 44, 57, 32,100, 85, 35, 68,248, 93,252,150, 49,  0,
-	252,179,  0,182,235,227, 39, 17, 36, 45,  0,132, 56,156,126,235,
-	227,199, 85, 45,105,239,178, 56,  2,  0, 31, 11,192,141,  4,  0,
-	 98, 12,222, 84,190,  1, 32, 84,224, 83, 42, 64,  0,  8, 21,184,
-	169,  2,  4,128,123,212,120,163,193, 47,219, 43,192, 69,179,106,
-	  1,192, 93,142,184,187, 34,144, 12,240, 91,116, 76,  6,128, 59,
-	157,241,145,253, 12,194, 22,126, 75, 18,  8,  0,119,107,113,144,
-	 29,106, 64,178,184, 93,  2,  0,119,108,241,146,189, 88,193, 35,
-	157,  3,128,207,108,241,146,125,240,231,236,  8, 52,224, 95,112,
-	250,145,125,240,231,232,  8,134,224,191,225,244, 35,251,224,207,
-	238,  8,140,144,191,161,  2,247, 42,176,130,255,138, 10,220,169,
-	192, 15,  8, 21,248, 28,139,195,  0, 16, 42,112,211,197, 97,  0,
-	  8, 21,184,105,116, 12,  0,  4,129,155, 70,103,  1, 64, 16,184,
-	105,116, 32,  0,  4,129,155, 70,167,  2, 64, 16,184,105,116, 52,
-	  0,220,  5,110, 15,173,  1,  9,  0,124,  2,117, 71,200,131,240,
-	 55,200, 94,116,107,120, 42,  0,220,207,112,171, 24,124, 20, 43,
-	152, 44,112,234, 43,  0,220,149,227,153, 60,134, 39,218,250, 51,
-	  1,128, 79, 99,111,144, 71, 88,  9, 89, 48, 56, 11,  0,238,205,
-	222, 37, 15,177, 22, 76,150,178,141,  1,224,158, 70,224,199, 21,
-	104, 64,184,252, 30,211, 57,  8,  0, 65,224,166,206,105,  0,  8,
-	  2, 55, 93, 28,  1,129, 49, 27,144,  0,  0,  7, 91, 73, 68, 65,
-	 84,128,152,  6,110, 26, 29,  8,  0,161,  2, 55, 93, 29,  6,128,
-	 32,112,211,232,  4,  0,  8,  4, 55, 13,142,  1,128, 32,112,211,
-	224, 44,  0,  8, 83,100,211,216, 64,  0,  8,  0, 55,221, 29,  7,
-	  0, 49,  6,111,170,  2,  1, 32, 20,224,166, 42, 16,  0, 66,  1,
-	194,  8,249,155,192, 49,121,112,  5,168,171,192,225, 15,  2,128,
-	 15, 50,226, 18,242,184, 10, 80,166,174,188,254, 96,107,  0,184,
-	135, 17,151,144,199, 93, 10, 25,244,157,  0, 64, 76,249, 30,105,
-	 82,  8,  0, 97,243,110,106, 23,  3, 64, 40,192, 77, 85, 32,  0,
-	  4,128,  0, 16,  4, 98, 14,  8,  0, 65,224, 38,142,105,  0,  8,
-	  2, 55, 93, 24,  1,128, 32,112,211,149, 97,  0,  8,  4, 55, 93,
-	 23,  6,128,219, 18,248, 60,  8, 94,121,138, 53,  0,  4,130, 27,
-	226,  7,  0, 49, 14,111, 28, 22,  8,  0,  1,224,166, 97,129,  0,
-	 16,  0,  2,192,191, 45,127,213,  1,  3,  0,161,  0,119,160,  2,
-	  1, 32,  0,  4,128, 24,129,255,238, 24, 12,  0,183,113,254, 73,
-	121,154,197, 16,162,255, 40,  0,136, 49,247, 81, 70,100,  0,136,
-	 49,119,211, 17, 25,  0,  2, 64,  0,136, 17,248,239,142,193,  0,
-	 16,  0,  2, 64,  0,  8,  0,  1, 32,  0,  4,128, 32, 16,110, 24,
-	  0,  8,  4,239,186, 46,  7,  0,129,224,166,203,194,  0,112, 43,
-	  4,159,116, 95, 48, 54,166, 63, 18,131, 79,182, 43,238,154,141,
-	 33,  0, 16,171, 34,155,  6,196,  0, 64,  0,  8,  0,  1, 32,  0,
-	  4,128, 48,134,  1, 32,  0,252,123, 97,249,  0, 16,  0,  2, 64,
-	  0,  8,  0,  1, 32,  0,  4,128,127,202,  7,221,193,247,108,139,
-	 33,132, 57,163,177, 20,183,127,250,158, 61, 24,129,  0, 64,208,
-	247, 32, 12,  2, 64,204,250, 54,157, 17,  2, 64,  0,  8,  0,  1,
-	 32,  0,  4,128,  0, 16,  0,  2, 64,  0,  8,  0,  1, 32,  0,132,
-	 23,230,239,248, 97,  0, 32, 24,220,212, 19, 13,  0,183, 97,240,
-	137,143,107, 69,126, 64,204,  8, 17,140,  0,  1,128,  0, 16,  0,
-	  2, 64,  8,  0,  4,128,  0,240, 62,242, 13,  0, 31, 78,  0, 32,
-	  0,  4,128,  0, 16,  0,  2, 64,  0,136, 53,145, 59,174,127,  0,
-	 64, 24, 32, 59, 97, 16,  0, 66,247,109,202, 32,  0,  4,126,155,
-	250,  3,  1, 32,  6,223, 77, 17,  4,128,192,111, 83,  4,  1, 32,
-	 60, 47, 91,198, 67,147,246,189, 19,  0,  8, 13,184, 17,128,109,
-	  3,  0,  1, 32,  0,  4,128,207, 38, 23,207, 71,  0, 32, 38,129,
-	119,  4,144,  0, 64,  0,184,217,  8,204, 50,210, 13, 71,  3,  0,
-	184,133, 31, 90,110, 74, 34,207,179, 59,201,248, 77,196,239,124,
-	 39,  0, 16, 10,113,139, 73, 31,113, 21,  4,128, 48, 74,238,101,
-	245, 18, 87, 73,  0,  8,  0,239, 14,160, 94, 20,  0,  2,192,123,
-	185, 93,136, 11, 86,  0,136, 73, 32,  0,132, 10,252, 19, 11, 31,
-	196, 85, 26,  0,  2,192, 77,  1,132, 35,122, 23, 94,193,167, 12,
-	131, 38, 67, 40, 93,  3, 54, 52, 32,212,223, 58, 74,144,216,106,
-	113, 88, 86, 56,174,  1, 32,240, 91, 30, 65,226, 99,178, 95, 54,
-	145, 31,  1, 32,248, 91,156, 64,159,211,217, 37,  0, 16,252, 45,
-	 78,160,211,229,242, 13,  0,129,223,157,252,129,196,233, 32, 36,
-	  0, 16,252,221, 73,  9,142, 77, 12,  1, 32,248, 91,157, 64,215,
-	176,140, 57, 32,  0,188, 27,128,100, 56, 42,251,157,157,  0, 16,
-	  0,174, 12, 32, 25,245,181,  3,192,141,228,153,249, 27,252,121,
-	141,254,177,  1,192, 93,168,192,  7, 94,143, 27,116,157,204, 84,
-	240,  0,112,123, 21, 72,200,  3,143,201,100, 48,195,251,  6,128,
-	 15,163,  2,  9,209, 54,240, 60, 50,128, 98,159, 21, 93, 96, 35,
-	115,103, 24,  0, 16,102,201,  2,252,181,142, 13,151,  0, 16,  0,
-	222,215,230, 32,215,252, 28,  0,  8,  2, 23,179,121,  9,  1,128,
-	240,204,220,125,233,215, 23,108, 15,  0,161,  2,239,239,244,155,
-	109, 82,  1, 64,224,183,228,202,111, 59,215,165,  4,  0,193,223,
-	173,  4, 14, 61,209,179,126, 10,  0,  4,127, 55, 19,216, 94,190,
-	242,  6,  0,193,223,242,  4,222,210,123,  0,  8,254, 22, 94, 13,
-	  6,128,224,239,129,  8,  4,128,224,111,  1,  2,  1, 32, 28,208,
-	 15, 74, 32,  0,  4,127,155, 14,194,  0,112,111,  3, 48,121, 72,
-	149,119, 53,129,  0,112,103, 26,144, 60,196,148,208,250,187,185,
-	122, 38, 11,  0,119,165,  2, 31, 36, 56,154,144,214,204,239,127,
-	253,159, 13,  0,220, 17,129,143, 18, 29,109,141,183, 55,168,109,
-	  0,184,151, 65,248,154, 96,186,173,150, 62,134, 40,126,195, 10,
-	126,108, 21,104,229,119, 36,187,230,111, 48,248, 18, 56,162,225,
-	155,185,167,  1, 66, 38,162, 17,  0, 32, 22, 71,238, 59,  3,108,
-	  1, 32,248,123,148,224,  3,  0,  8,254,182, 92,250,  5,128,152,
-	  0,238,139, 64,  0,  8,  5,184,233, 32, 12,  0,193,223,166,  4,
-	  2, 64, 12,192, 87,249, 98,  0, 32, 20,224,126,188,209,  0,240,
-	105, 21,224,126,112, 92, 42,252,  5,  0, 62,146,  2, 36,123,209,
-	136,100,173,158,  1,192, 61, 43, 64,178,151, 49,217,209,145,133,
-	122,  6,  0,119,172,  0,119, 19,157, 69,220,157,131,  6,124,110,
-	  2,231,167,154, 90,151,191, 97,231, 48,  4, 63, 53,129,100, 55,
-	174, 25, 95,239, 96,132, 60, 49,129, 87, 38,188, 93,117,  0,230,
-	 25,173, 85,247, 96,  5, 63, 47,129,100, 95,174, 65,231,228,  0,
-	126, 64,248,166,183,179,129,  9,  0,  4,127,119, 38,144,172,227,
-	 33,  7,128,  0,240, 10, 55, 52,194,177,192,223,157,103,129,  0,
-	 16,  0, 46, 30, 14,127,249,210, 47,  1,128,  0,240,158,139,195,
-	228,110,205,  2,192,221,139,237,146, 35,119,176, 57,236, 83,167,
-	  9,  0,252,243, 10,240, 46,139,115,196, 71, 62,  1,128,127, 29,
-	192,123, 88, 38,196,169,123, 87,139,203,  1,128, 15, 52,  2,187,
-	217, 88,111,233,151,140,173,134,  0,192,191,  6, 32,185,147,107,
-	134, 56,233, 95,171, 97,  0,184,251, 33,152,220, 59, 58,198, 49,
-	  1,208,178, 39, 17,  0,248, 39,103,129,228,123, 19,  0, 87,143,
-	205,  1,128,143,161,  4, 71, 16,232,149,228,181, 99, 46,113,249,
-	122,250,182,134,201,227,160,  1, 65,164,237,180, 35, 55,208,231,
-	115,246, 92,224, 24,  7,128,  0,240, 22, 48,200,104,141,  0, 16,
-	 50,233,154,105,191, 23,  1,240,219, 59,  9, 28,109, 28,  0,194,
-	 55,232,  4,195,155, 54,119,248,197,132,191,123,117,  5,  8,  0,
-	 31, 28, 64, 50,174, 22,201,212, 18,155, 19, 44,  0,  8,185, 20,
-	192, 25,243,194,  9,  0,191,125,  0,242,205, 72, 66,125, 46,238,
-	  1,  2,128, 15, 13, 32,185,  6, 64,143,193, 65,124,  0,174, 18,
-	138, 15,  0,159,193,  8, 38,223, 11,  2,232,174,118,237, 61,201,
-	  0,240, 65, 61,211, 22, 40,100,202,180, 32,227, 54,140, 42,189,
-	170,223, 25,  0, 62, 17,130,222,213, 17, 50,  1,160,215,222, 32,
-	 54,126,107, 71,191,  2,192,199,101,112,166,105,124,137,193, 75,
-	 86,183,122,  1,224,159,178, 76,220,  0,122,237,141,  9,159, 35,
-	  0,132, 92, 66,138, 91,127,145, 43,  1, 92,121, 31, 30,  0,124,
-	 58,219,152, 76,  3,232, 46, 59,105,116,  3, 64,200,  5,156, 92,
-	160, 23,213,101, 50,175,106,  0,  8, 25, 27, 43, 29,193,163, 62,
-	 93,215,175,108,108, 76, 32,  0,124, 54, 10,191, 47,  2,240,155,
-	144,185, 21,  3, 64,200, 13,182,201,114, 42, 22,  0, 66,182,158,
-	102,  2, 64,  8,  0,132,  0, 64,  0,  8,  1,128,144, 63,103,208,
-	  0, 64,  8,  0,132,  0, 64,  0,  8,121,244, 41, 32,  0,132, 92,
-	  0, 30,214,130, 33,207,  8, 31,  0,132,108, 48,232,  2, 64,  8,
-	  0,132,  0, 64,  0,  8,  1,128, 16,  0,  8,  0, 33,  0, 16,  2,
-	  0,  1, 32,100,  3,  4,  1, 32,100, 10, 65,108,203,132,108,206,
-	 32,  1,128,144,205,  5,  0, 66,  0, 32,  4,  6,  9,  0,132,  0,
-	 64,  8,  0,  4,128, 16,  0,  8,  1,128,  0, 16,  2,  0, 33,207,
-	 78,223, 58,222,104,  0,  8,185,136, 62,172,132, 64,158,106,232,
-	  5,128,144, 29,224,  7,  0, 33,155,226,  7,  0, 33,219,242,  7,
-	  0, 33,  0, 16,  2,  0,  7,242, 14,  0, 33,247,  1,176,162,  0,
-	 14,249, 59,188,117,  0,254,135,167, 15, 89,253,168,184,246,127,
-	 29,127,111, 78,  0,161,  2, 33,235,  3, 88, 83,  5,248,106,  1,
-	 24, 80,  0,207, 32, 16,178,242,150,164,250,131,  2, 24, 28,220,
-	 42,240,227, 63,  2,129, 16,185, 10, 76,255,223, 44, 41, 21, 29,
-	127, 93, 10, 80,152, 33, 16,200, 80,222,151,151, 55, 23,127,135,
-	  0,  4, 66,238,  2,224,219,233,224,150, 55, 60,109,200,250,  4,
-	190, 30,188, 18,188,189, 65, 13, 66,214,  4,240,237, 53, 56,140,
-	203, 17,  2, 89, 77, 14, 16,  8,  4,  2,129, 64, 32, 16,  8,  4,
-	  2,129, 64, 32,144, 77,228,255,172,172, 61, 79,147, 31,110,198,
-	  0,  0,  0,  0, 73, 69, 78, 68,174, 66, 96,130,
-};
--- a/setupmenubar.h	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-Uint8 engineSetupMenuBar[134] = {
-	137, 80, 78, 71, 13, 10, 26, 10,  0,  0,  0, 13, 73, 72, 68, 82,
-	  0,  0,  0, 16,  0,  0,  0, 16,  8,  6,  0,  0,  0, 31,243,255,
-	 97,  0,  0,  0, 77, 73, 68, 65, 84, 56,203, 99,252,255,255,255,
-	100,  6, 10,  0, 19,  3,133,128,133,129,129, 65,148, 82,  3,  4,
-	 41, 53,128,141, 82,  3,228,137, 84,251,  3,151,  1,196,  2, 14,
-	154,120,129, 42,209,248,139, 82,  3,126, 80,106,192, 31, 74, 13,
-	184,134, 67, 78,144, 88,  3,112,129,247,196, 26,240,122, 64,163,
-	 17,  0,220, 81, 10,200,234, 71, 48, 81,  0,  0,  0,  0, 73, 69,
-	 78, 68,174, 66, 96,130,
-};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmargs.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,12 @@
+#include "dmargs.h"
+#define TH_EXTERNAL 1
+#define optarg_t DMOptArg
+#define th_args_process dmArgsProcess
+#define th_args_help dmArgsPrintHelp
+
+#define THERR dmError
+#define th_calloc dmCalloc
+#define th_malloc dmMalloc
+#define th_free dmFree
+
+#include "dmargs_int.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmargs.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,44 @@
+/*
+ * Simple commandline argument processing functions
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2002-2008 Tecnic Software productions (TNSP)
+ *
+ * Please read file 'COPYING' for information on license and distribution.
+ */
+#ifndef DMARGS_H
+#define DMARGS_H
+
+#include "dmlib.h"
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Option flags
+ */
+#define OPT_NONE       (0)    // Simple option with no arguments
+#define OPT_ARGREQ     (1)    // Option's argument is required
+#define OPT_ARGOPT     (3)    // Option's argument is optional
+#define OPT_ARGMASK    (3)    // Mask for option argument flags
+#define OPT_REQUIRED   (4)    // This option is required to be given
+
+typedef struct {
+    int id;
+    char optShort;
+    char *optLong;
+    char *desc;
+    int flags;
+} DMOptArg;
+
+BOOL dmArgsProcess(int argc, char *argv[],
+     DMOptArg argList[], int argListN,
+     BOOL (*handleOpt)(int, char *, char *),
+     BOOL (*handleFile)(char *), BOOL);
+
+void dmArgsPrintHelp(FILE *, DMOptArg optList[], int optListN);
+
+#ifdef __cplusplus
+}
+#endif
+#endif // DMARGS_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmargs_int.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,418 @@
+/*
+ * Simple commandline argument processing
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2002-2008 Tecnic Software productions (TNSP)
+ *
+ * Please read file 'COPYING' for information on license and distribution.
+ */
+/*
+Description
+===========
+Structures and functions for simple commandline argument processing,
+option argument handling (short and long forms supported).
+
+Output function for printing out short on-line help for said options
+and program commandline usage.
+
+
+Format for typical commandline:
+
+$ program -a -b -c --long-d -e argument-for-e --long-f="argument for f"
+
+where -a, -b and -c are short options without required arguments;
+--long-d is a long option without argument; -e is short option with
+argument and finally --long-f is long option with argument.
+
+
+Introduction
+============
+Handling of commandline options in th_args_process() has various
+options, which effect how an option is handled. Also the error
+situations (unknown option/no required argument) can be handled
+in different ways.
+
+Typically th_args_process() is called as follows:
+
+BOOL optionHandlerCallback(int optionNumber, char *optionArgument, char *optionName)
+{
+  if (option is OK)
+    return TRUE;
+  else
+    return FALSE;
+}
+
+BOOL nonoptionHandlerCallback(char *argumentString)
+{
+  // return value same as in optionHandlerCallback
+}
+
+
+int main(int argc, char *argv[])
+{
+  if (th_args_process(argc, argv, optList, optListN,
+      optionHandlerCallback, nonoptionHandlerCallback)) {
+    ... arguments OK ...
+  } else {
+    ... arguments invalid or required arguments missing ...
+  }
+}
+
+
+NOTICE!
+-------
+The return value from handler callbacks affects the return value of
+th_args_process(). Additionally, a failure in callback (returns FALSE)
+effects the argument processing if bailOut argument of th_args_process()
+is TRUE!
+
+If bailOut is TRUE, any error/failure in argument processing (including
+callbacks) immediately stops the argument processing and FALSE is
+returned from th_args_process().
+
+If bailOut is FALSE, most errors are "ignored", but FALSE is still returned
+if any errors occured.
+
+
+NOTICE #2!
+----------
+A small temporary buffer of N*sizeof(BOOL) (where N is number of
+options in optList[]) is allocated for processing required options.
+If this allocation fails, the program is immediately exited with
+code 128.
+
+
+Examples
+========
+Example of different options, in a fictional optionlist struct:
+
+optarg_t optList[] = {
+  // Option without arguments
+  { 0, '?', "help",      "Show this help",                    OPT_NONE },
+
+  // Option with a required argument
+  { 1, 'o', "output",    "Output file name",                  OPT_ARGREQ },
+  
+  // Option with optional argument
+  { 2, 'f', "foobar",    "Use foobar, with optional string",  OPT_ARGOPT },
+
+  // This option is required to be given, though without other flags
+  // it may not make much sense.
+  { 4, 'S', "stupid",     "You must give this option",        OPT_REQUIRED },
+
+  // The flags can be combined with OR operator: this option is both
+  // required to be specified, and also requires argument (the filename)
+  { 5, 'i', "input",     "Input file name",                   OPT_REQUIRED | OPT_ARGREQ },
+
+
+  // Option with only long form
+  { 0, 0,   "only-long", "Long option",                       OPT_NONE },
+
+  // Option with only short form
+  { 0, 's', NULL,        "Short option",                      OPT_NONE },
+
+};
+
+const int optListN = (sizeof(optList) / sizeof(optarg_t));
+
+
+*/
+#ifndef TH_EXTERNAL
+#include "th_util.h"
+#include "th_args.h"
+#include "th_string.h"
+#endif
+
+
+/* Check if option requires an argument
+ */
+static BOOL th_args_check_arg(const optarg_t *o, const char *optArg)
+{
+    if ((o->flags & OPT_ARGMASK) == OPT_ARGREQ && optArg == NULL)
+    {
+        if (o->optShort != 0 && o->optLong != NULL)
+        {
+            THERR("Option '-%c ARG' (--%s=ARG) requires an argument!\n",
+                  o->optShort, o->optLong);
+        }
+        else if (o->optShort != 0)
+        {
+            THERR("Option '-%c ARG' requires an argument!\n", o->optShort);
+        }
+        else if (o->optLong != NULL)
+        {
+            THERR("Option --%s=ARG requires an argument!\n", o->optLong);
+        }
+
+        return FALSE;
+    }
+    else
+        return TRUE;
+}
+
+
+/* Handle short options
+ */
+static BOOL th_args_process_short(char *currArg, int *newArgIndex,
+    BOOL *wasGiven, int argc, char *argv[],
+    optarg_t optList[], int optListN,
+    BOOL (*handleOpt)(int, char *, char *))
+{
+    char *tmpArg = currArg, *optArg;
+    int optN;
+    BOOL isFound;
+
+    // Short options can be combined: -a -b -c == -abc
+    while (*tmpArg)
+    {
+        for (optN = 0, isFound = FALSE; (optN < optListN) && !isFound; optN++)
+            if (*tmpArg == optList[optN].optShort)
+            {
+                // Get possible option argument, if needed
+                if ((optList[optN].flags & OPT_ARGMASK) != 0
+                    && (++(*newArgIndex) < argc))
+                    optArg = argv[*newArgIndex];
+                else
+                    optArg = NULL;
+
+                // Check if option argument is required
+                if (!th_args_check_arg(&optList[optN], optArg))
+                    return FALSE;
+                else
+                {
+                    char tmpStr[2] = { 0, 0 };
+
+                    // Option was given succesfully, try to handle it
+                    wasGiven[optN] = TRUE;
+
+                    tmpStr[0] = *tmpArg;
+
+                    if (!handleOpt(optList[optN].id, optArg, tmpStr))
+                        return FALSE;
+                }
+
+                isFound = TRUE;
+            }
+
+        if (!isFound)
+        {
+            THERR("Unknown short option '%c' in argument '-%s'\n",
+                  *tmpArg, currArg);
+            return FALSE;
+        }
+
+        tmpArg++;
+    }
+
+    return TRUE;
+}
+
+
+/* Handle long options
+ */
+static BOOL th_args_process_long(char *currArg, int *newArgIndex,
+    BOOL *wasGiven, int argc, char *argv[],
+    optarg_t optList[], int optListN,
+    BOOL (*handleOpt)(int, char *, char *))
+{
+    int optN, optLen, i;
+    char *optArg;
+
+    (void) argc;
+    (void) argv;
+    (void) newArgIndex;
+
+    // Long option
+    for (optN = -1, optLen = i = 0; i < optListN && optN < 0; i++)
+        if (optList[i].optLong)
+        {
+            optLen = strlen(optList[i].optLong);
+            if (strcmp(currArg, optList[i].optLong) == 0)
+                optN = i;
+        }
+
+    // Get possible option argument, if needed
+    if (optN >= 0)
+    {
+        if ((optList[optN].flags & OPT_ARGMASK) != 0)
+        {
+            if (currArg[optLen] == '=')
+                optArg = &currArg[optLen + 1];
+            else
+                optArg = NULL;
+        }
+        else
+            optArg = NULL;
+
+        // Check if option argument is required
+        if (!th_args_check_arg(&optList[optN], optArg))
+            return FALSE;
+        else
+        {
+            // Option was given succesfully, try to handle it
+            wasGiven[optN] = TRUE;
+            if (!handleOpt(optList[optN].id, optArg, currArg))
+                return FALSE;
+        }
+    }
+    else
+    {
+        THERR("Unknown long option '--%s'\n", currArg);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+
+/* Process arguments, handling short and long options by
+ * calling the given callback functions.
+ */
+BOOL th_args_process(int argc, char *argv[],
+                     optarg_t optList[], int optListN,
+                     BOOL(*handleOpt) (int, char *, char *),
+                     BOOL(*handleNonOption) (char *), BOOL bailOut)
+{
+    BOOL endOptions, optionsOK;
+    int argIndex, newArgIndex, i;
+    char *currArg;
+    BOOL *wasGiven;
+
+    // Allocate wasGiven
+    wasGiven = (BOOL *) th_calloc(optListN, sizeof(BOOL));
+    if (!wasGiven)
+    {
+        THERR("FATAL ERROR! Could not allocate wasGiven in th_args_process()!\n");
+        exit(128);
+    }
+
+    // Parse arguments
+    argIndex = 1;
+    optionsOK = TRUE;
+    endOptions = FALSE;
+    while (argIndex < argc)
+    {
+        currArg = argv[argIndex];
+        if ((currArg[0] == '-') && !endOptions)
+        {
+            newArgIndex = argIndex;
+            currArg++;
+            if (*currArg == '-')
+            {
+                // Check for "--", which ends the options-list
+                currArg++;
+                if (*currArg == 0)
+                {
+                    endOptions = TRUE;
+                    continue;
+                }
+
+                // Long options
+                if (!th_args_process_long(currArg, &newArgIndex,
+                                          wasGiven, argc, argv, optList,
+                                          optListN, handleOpt))
+                    optionsOK = FALSE;
+            }
+            else
+            {
+                // Short options
+                if (!th_args_process_short(currArg, &newArgIndex,
+                                           wasGiven, argc, argv, optList,
+                                           optListN, handleOpt))
+                    optionsOK = FALSE;
+            }
+
+            argIndex = newArgIndex;
+        }
+        else
+        {
+            // Was not option argument
+            if (handleNonOption == NULL
+                || (handleNonOption != NULL && !handleNonOption(currArg)))
+            {
+                THERR("Invalid argument '%s'\n", currArg);
+                optionsOK = FALSE;
+            }
+        }
+
+        // Check if we bail out on invalid argument
+        if (!optionsOK && bailOut)
+        {
+            th_free(wasGiven);
+            return FALSE;
+        }
+
+        argIndex++;
+    }
+
+    // Check wasGiven by isRequired
+    for (i = 0; i < optListN; i++)
+        if ((optList[i].flags & OPT_REQUIRED) != 0 && !wasGiven[i])
+        {
+            THERR("Option -%s (--%s) is required.\n",
+                  optList[i].optShort, optList[i].optLong);
+
+            optionsOK = FALSE;
+            if (bailOut)
+                break;
+        }
+
+    th_free(wasGiven);
+    return optionsOK;
+}
+
+
+/* Print help for commandline arguments/options
+ */
+void th_args_help(FILE *outFile, optarg_t optList[], int optListN)
+{
+    int i, nrequired;
+
+    for (i = nrequired = 0; i < optListN; i++)
+    {
+        optarg_t *o = &optList[i];
+
+        // Print short option
+        if (o->optShort != 0)
+            fprintf(outFile, "  -%c,  ", o->optShort);
+        else
+            fprintf(outFile, "       ");
+
+        // Print long option
+        if (o->optLong)
+        {
+            char tmpStr[64], *p;
+
+            if ((o->flags & OPT_ARGMASK) == OPT_ARGOPT)
+            {
+                snprintf(tmpStr, sizeof(tmpStr), "%s[=ARG]",
+                         optList[i].optLong);
+                p = tmpStr;
+            }
+            else if ((o->flags & OPT_ARGMASK) == OPT_ARGREQ)
+            {
+                snprintf(tmpStr, sizeof(tmpStr), "%s=ARG",
+                         optList[i].optLong);
+                p = tmpStr;
+            }
+            else
+                p = o->optLong;
+
+            fprintf(outFile, "--%-15s", p);
+        }
+        else
+            fprintf(outFile, "                 ");
+
+        fprintf(outFile, "  %s.", optList[i].desc);
+
+        if (o->flags & OPT_REQUIRED)
+        {
+            fprintf(outFile, " [*]\n");
+            nrequired++;
+        }
+        else
+            fprintf(outFile, "\n");
+    }
+
+    if (nrequired > 0)
+        fprintf(outFile, "(Options marked with [*] are required)\n");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmblit.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,251 @@
+/*
+ * DMLib
+ * -- Sprite / surface blitting functions
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2011 Tecnic Software productions (TNSP)
+ */
+#include "dmlib.h"
+
+//#define DM_CLIP_DEBUG
+
+typedef struct
+{
+    int v0, v1, voffs, vadd;
+    DMFixedPoint32 vdelta;
+} DMQValue;
+
+
+int dmScaledClipCoord(DMQValue *pv, int v0, int v1, int v2, int clipMin, int clipMax)
+{
+    DMFixedPoint32 a, b;
+
+    // Basic bounds check
+    if (v1 < 1 || v2 < 1 || v0 + v2 < clipMin || v0 >= clipMax)
+    {
+#ifdef DM_CLIPDEBUG
+        printf("out of bounds\n");
+#endif
+        return -1;
+    }
+
+    // Calculate delta
+    FP_SETHL(a, v1, 0);
+    FP_CONV(b, v2);
+    FP_DIV_R(pv->vdelta, a, b);
+
+    // Perform clipping
+    if (v0 + v2 >= clipMax)
+    {
+        pv->vadd = v0;
+        pv->v1 = clipMax;
+    }
+    else
+    {
+        pv->vadd = clipMax - v2;
+        pv->v1 = v0 + v2;
+    }
+    
+    if (v0 < clipMin)
+    {
+        pv->voffs = clipMin - v0;
+        pv->v0 = clipMin;
+        pv->vadd -= v0 + clipMin;
+    }
+    else
+    {
+        pv->voffs = 0;
+        pv->v0 = v0;
+    }
+    
+#ifdef DM_CLIP_DEBUG
+    printf("dmClipCoord(%d, (%d, %d), [%d, %d]): vdelta=",
+        v0, v1, v2, clipMin, clipMax);
+    FP_PRINTF(pv->vdelta);
+    printf(", v0=%d, v1=%d, voffs=%d, vadd=%d\n",
+        pv->v0, pv->v1, pv->voffs, pv->vadd);
+#endif
+
+    return 0;
+}
+
+
+int dmUnscaledClipCoord(DMQValue *pv, int v0, int v1, int clipMin, int clipMax)
+{
+    // Basic bounds check
+    if (v1 < 1 || v0 + v1 < clipMin || v0 >= clipMax)
+        return -1;
+
+    // Perform clipping
+    if (v0 + v1 >= clipMax)
+    {
+        pv->vadd = v0;
+        pv->v1 = clipMax;
+    }
+    else
+    {
+        pv->vadd = clipMax - v1;
+        pv->v1 = v0 + v1;
+    }
+    
+    if (v0 < clipMin)
+    {
+        pv->voffs = clipMin - v0;
+        pv->v0 = clipMin;
+        pv->vadd -= v0 + clipMin;
+    }
+    else
+    {
+        pv->voffs = 0;
+        pv->v0 = v0;
+    }
+    
+    return 0;
+}
+
+
+#include "dmblitfunc.h"
+
+
+static const DMScaledBlitFunc dmScaledBlitTable[DMD_NMODES][DMD_NBITDEPTHS][DMD_NBITDEPTHS] =
+{
+    // DMD_NONE
+    {
+        { dmScaledBlitSurface8to8             , dmScaledBlitSurface8to32 },
+        { NULL                                , dmScaledBlitSurface32to32 },
+    },
+    // DMD_TRANSPARENT
+    {
+        { dmScaledBlitSurface8to8Transparent  , dmScaledBlitSurface8to32Transparent },
+        { NULL                                , dmScaledBlitSurface32to32Transparent },
+    },
+    // DMD_SATURATE
+    {
+        { dmScaledBlitSurface8to8Saturate     , dmScaledBlitSurface8to32Saturate },
+        { NULL                                , dmScaledBlitSurface32to32Saturate },
+    },
+#if 0
+    // DMD_NONE | DMD_ANTIALIAS
+    {
+        { dmScaledBlitSurface8to8Antialias    , dmScaledBlitSurface8to32Antialias },
+        { NULL                                , dmScaledBlitSurface32to32Antialias },
+    },
+    // DMD_TRANSPARENT | DMD_ANTIALIAS
+    {
+        { dmScaledBlitSurface8to8AATransp     , dmScaledBlitSurface8to32AATransparent },
+        { NULL                                , dmScaledBlitSurface32to32AATransparent },
+    },
+    // DMD_SATURATE | DMD_ANTIALIAS
+    {
+        { dmScaledBlitSurface8to8AASaturate   , dmScaledBlitSurface8to32AASaturate },
+        { NULL                                , dmScaledBlitSurface32to32AASaturate },
+    },
+#endif
+};
+
+static const int ndmScaledBlitTable = sizeof(dmScaledBlitTable) / sizeof(dmScaledBlitTable[0]);
+
+
+DMScaledBlitFunc dmGetScaledBlitFunc(SDL_PixelFormat *src, SDL_PixelFormat *dst, int mode)
+{
+    int isrc, idst;
+    if (src == NULL || dst == NULL || mode < 0 || mode >= ndmScaledBlitTable)
+        return NULL;
+
+    isrc = dmBitsPerPixel2Index(src->BitsPerPixel);
+    idst = dmBitsPerPixel2Index(dst->BitsPerPixel);
+    if (isrc < 0 || idst < 0)
+        return NULL;
+    
+    return dmScaledBlitTable[mode][isrc][idst];
+}
+
+
+int dmScaledBlitSurfaceAny(SDL_Surface *src, const int x0, const int y0, const int dwidth, const int dheight, SDL_Surface *dst, int mode)
+{
+    DMScaledBlitFunc bfunc = dmGetScaledBlitFunc(src->format, dst->format, mode);
+    
+    if (bfunc == NULL)
+        return -15;
+
+    return bfunc(src, x0, y0, dwidth, dheight, dst);
+}
+
+
+static const DMUnscaledBlitFunc dmUnscaledBlitTable[DMD_NMODES][DMD_NBITDEPTHS][DMD_NBITDEPTHS] =
+{
+    // DMD_NONE
+    {
+        { dmUnscaledBlitSurface8to8           , dmUnscaledBlitSurface8to32 },
+        { NULL                                , dmUnscaledBlitSurface32to32 },
+    },
+    // DMD_TRANSPARENT
+    {
+        { dmUnscaledBlitSurface8to8Transparent, dmUnscaledBlitSurface8to32Transparent },
+        { NULL                                , dmUnscaledBlitSurface32to32Transparent },
+    },
+    // DMD_SATURATE
+    {
+        { dmUnscaledBlitSurface8to8Saturate   , dmUnscaledBlitSurface8to32Saturate },
+        { NULL                                , dmUnscaledBlitSurface32to32Saturate },
+    },
+#if 0
+    // DMD_NONE | DMD_ANTIALIAS
+    {
+        { dmUnscaledBlitSurface8to8Antialias  , dmUnscaledBlitSurface8to32Antialias },
+        { NULL                                , dmUnscaledBlitSurface32to32Antialias },
+    },
+    // DMD_TRANSPARENT | DMD_ANTIALIAS
+    {
+        { dmUnscaledBlitSurface8to8AATransp   , dmUnscaledBlitSurface8to32AATransparent },
+        { NULL                                , dmUnscaledBlitSurface32to32AATransparent },
+    },
+    // DMD_SATURATE | DMD_ANTIALIAS
+    {
+        { dmUnscaledBlitSurface8to8AASaturate , dmUnscaledBlitSurface8to32AASaturate },
+        { NULL                                , dmUnscaledBlitSurface32to32AASaturate },
+    },
+#endif
+};
+
+static const int ndmUnscaledBlitTable = sizeof(dmUnscaledBlitTable) / sizeof(dmUnscaledBlitTable[0]);
+
+
+
+DMUnscaledBlitFunc dmGetUnscaledBlitFunc(SDL_PixelFormat *src, SDL_PixelFormat *dst, int mode)
+{
+    int isrc, idst;
+    if (src == NULL || dst == NULL || mode < 0 || mode >= ndmUnscaledBlitTable)
+        return NULL;
+
+    isrc = dmBitsPerPixel2Index(src->BitsPerPixel);
+    idst = dmBitsPerPixel2Index(dst->BitsPerPixel);
+    if (isrc < 0 || idst < 0)
+        return NULL;
+    
+    return dmUnscaledBlitTable[mode][isrc][idst];
+}
+
+
+int dmUnscaledBlitSurfaceAny(SDL_Surface *src, const int x0, const int y0, SDL_Surface *dst, int mode)
+{
+    DMUnscaledBlitFunc bfunc = dmGetUnscaledBlitFunc(src->format, dst->format, mode);
+    
+    if (bfunc == NULL)
+        return -15;
+
+    return bfunc(src, x0, y0, dst);
+}
+
+
+SDL_Surface *dmConvertScaledSurface(SDL_Surface *src, SDL_PixelFormat *fmt, Uint32 flags, const int dwidth, const int dheight)
+{
+    // Create the target surface
+    SDL_Surface *result = SDL_CreateRGBSurface(flags, dwidth, dheight, fmt->BitsPerPixel, fmt->Rmask, fmt->Gmask, fmt->Bmask, fmt->Amask);
+    if (result == NULL)
+        return NULL;
+    
+    // Use scaled blitting to convert the scaled image ..
+    dmScaledBlitSurfaceAny(src, 0, 0, dwidth, dheight, result, DMD_NONE);
+
+    return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmblitfunc.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,558 @@
+/*
+ * DMLib
+ * -- Sprite / surface blitting functions
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2011-2012 Tecnic Software productions (TNSP)
+ */
+
+// =======================================================================
+// DMD_NONE
+// =======================================================================
+
+#define DM_BLITFUNC_NAME dmScaledBlitSurface8to8
+#define DM_BLITFUNC_SRC_BYTES 1
+#define DM_BLITFUNC_DST_BYTES 1
+#define DM_BLITFUNC_SRC_TYPE Uint8
+#define DM_BLITFUNC_DST_TYPE Uint8
+
+#define DM_BLITFUNC_INNER *dp++ = sp[FP_GETH16(xv)];
+
+#include "dmscaledblit.h"
+
+// -----------------------------------------------------------------------
+
+#define DM_BLITFUNC_NAME dmScaledBlitSurface8to32
+#define DM_BLITFUNC_SRC_BYTES 1
+#define DM_BLITFUNC_DST_BYTES 4
+#define DM_BLITFUNC_SRC_TYPE Uint8
+#define DM_BLITFUNC_DST_TYPE Uint32
+
+#define DM_BLITFUNC_VARS const Uint32 *pal;
+#define DM_BLITFUNC_INIT \
+    if (src->format->palette == NULL || src->format->palette->ncolors < 256) return -2;	\
+    pal = (Uint32 *) src->format->palette->colors;
+
+#define DM_BLITFUNC_INNER *dp++ = pal[sp[FP_GETH16(xv)]];
+
+#include "dmscaledblit.h"
+
+// -----------------------------------------------------------------------
+
+#define DM_BLITFUNC_NAME dmScaledBlitSurface32to32
+#define DM_BLITFUNC_SRC_BYTES 4
+#define DM_BLITFUNC_DST_BYTES 4
+#define DM_BLITFUNC_SRC_TYPE Uint32
+#define DM_BLITFUNC_DST_TYPE Uint32
+#define DM_BLITFUNC_INIT
+#define DM_BLITFUNC_INNER *dp++ = sp[FP_GETH16(xv)];
+
+#include "dmscaledblit.h"
+
+
+// =======================================================================
+// DMD_TRANSPARENT
+// =======================================================================
+
+#define DM_BLITFUNC_NAME dmScaledBlitSurface8to8Transparent
+#define DM_BLITFUNC_SRC_BYTES 1
+#define DM_BLITFUNC_DST_BYTES 1
+#define DM_BLITFUNC_SRC_TYPE Uint8
+#define DM_BLITFUNC_DST_TYPE Uint8
+
+#define DM_BLITFUNC_INNER \
+    *dp = sp[FP_GETH16(xv)] ? sp[FP_GETH16(xv)] : *dp; dp++;
+
+#include "dmscaledblit.h"
+
+// -----------------------------------------------------------------------
+
+#define DM_BLITFUNC_NAME dmScaledBlitSurface8to32Transparent
+#define DM_BLITFUNC_SRC_BYTES 1
+#define DM_BLITFUNC_DST_BYTES 4
+#define DM_BLITFUNC_SRC_TYPE Uint8
+#define DM_BLITFUNC_DST_TYPE DMRGBA32
+#define DM_BLITFUNC_VARS const DMRGBA32 *pal;
+#define DM_BLITFUNC_INIT \
+    if (src->format->palette == NULL || src->format->palette->ncolors < 256) return -2;	\
+    pal = (DMRGBA32 *) src->format->palette->colors;
+
+#define DM_BLITFUNC_INNER \
+    const DMRGBA32 q = pal[sp[FP_GETH16(xv)]]; \
+    dp->r += ((q.r - dp->r) * q.a) >> 8; \
+    dp->g += ((q.g - dp->g) * q.a) >> 8; \
+    dp->b += ((q.b - dp->b) * q.a) >> 8; \
+    dp->a  = q.a; \
+    dp++;
+
+#include "dmscaledblit.h"
+
+
+// -----------------------------------------------------------------------
+
+#define DM_BLITFUNC_NAME dmScaledBlitSurface32to32Transparent
+#define DM_BLITFUNC_SRC_BYTES 4
+#define DM_BLITFUNC_DST_BYTES 4
+
+#ifdef DM_USE_SIMD
+#define DM_BLITFUNC_VARS \
+    const Uint32 qpdmask =       0xff000000; \
+    const Uint64 qpdrm   = 0xff00ff00ff00ffULL;
+    
+#define DM_BLITFUNC_SRC_TYPE Uint32
+#define DM_BLITFUNC_DST_TYPE Uint32
+#define DM_BLITFUNC_INNER			\
+    asm(					\
+        "movd        %2,     %%mm1\n"		\
+        \
+        "movd        %3,     %%mm2\n"		\
+        "movq        %%mm1,  %%mm5\n"		\
+        "pand        %%mm2,  %%mm5\n"		\
+        "psrlw       $8,     %%mm5\n"		\
+        "punpcklwd   %%mm5,  %%mm5\n"		\
+        "punpckhwd   %%mm5,  %%mm5\n"		\
+        \
+        "pxor        %%mm2,  %%mm2\n"		\
+        "movd        %1,     %%mm3\n"		\
+        "punpcklbw   %%mm2,  %%mm1\n"		\
+        "punpcklbw   %%mm2,  %%mm3\n"		\
+        \
+        "psubw       %%mm3,  %%mm1\n"		\
+        "pmullw      %%mm5,  %%mm1\n"		\
+        "psraw       $8,     %%mm1\n"		\
+        "paddw       %%mm3,  %%mm1\n"		\
+        "pand        %4,     %%mm1\n"		\
+        "packuswb    %%mm2,  %%mm1\n"		\
+        "movd        %%mm1,  %0\n"		\
+        : "=m" (*dp)				\
+        : "m" (*dp), "m" (sp[FP_GETH16(xv)]), "m" (qpdmask), "m" (qpdrm)	\
+        : "memory", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5" ); dp++;
+
+#define DM_BLITFUNC_FINISH asm("emms\n");
+
+#else
+
+#define DM_BLITFUNC_SRC_TYPE DMRGBA32
+#define DM_BLITFUNC_DST_TYPE DMRGBA32
+#define DM_BLITFUNC_INNER \
+    const DMRGBA32 q = sp[FP_GETH16(xv)]; \
+    dp->r += ((q.r - dp->r) * q.a) >> 8; \
+    dp->g += ((q.g - dp->g) * q.a) >> 8; \
+    dp->b += ((q.b - dp->b) * q.a) >> 8; \
+    dp->a  = q.a; \
+    dp++;
+#endif
+
+#include "dmscaledblit.h"
+
+// -----------------------------------------------------------------------
+
+#define DM_BLITFUNC_NAME dmScaledBlitSurface32to32TransparentX
+#define DM_BLITFUNC_SRC_BYTES 4
+#define DM_BLITFUNC_DST_BYTES 4
+#define DM_BLITFUNC_SRC_TYPE DMRGBA32
+#define DM_BLITFUNC_DST_TYPE DMRGBA32
+#define DM_BLITFUNC_INIT
+
+#define DM_BLITFUNC_INNER \
+    const DMRGBA32 q = sp[FP_GETH16(xv)]; \
+    dp->r = (q.r * q.a + dp->r * dp->a) >> 8; \
+    dp->g = (q.g * q.a + dp->g * dp->a) >> 8; \
+    dp->b = (q.b * q.a + dp->b * dp->a) >> 8; \
+    dp->a = q.a ? q.a : dp->a; \
+    dp++;
+
+#include "dmscaledblit.h"
+
+
+// -----------------------------------------------------------------------
+
+#define DM_BLITFUNC_NAME dmScaledBlitSurface32to32TransparentGA
+#define DM_BLITFUNC_SRC_BYTES 4
+#define DM_BLITFUNC_DST_BYTES 4
+#define DM_BLITFUNC_ARGS , Uint32 alpha
+
+#ifdef DM_USE_SIMD
+#define DM_BLITFUNC_VARS \
+    const Uint32 qpdmask =       0xff000000; \
+    const Uint64 qpdrm   = 0xff00ff00ff00ffULL;
+
+#define DM_BLITFUNC_SRC_TYPE Uint32
+#define DM_BLITFUNC_DST_TYPE Uint32
+#define DM_BLITFUNC_INNER_INIT \
+    asm(					\
+        "movd        %0,     %%mm4\n"		\
+        "punpcklwd   %%mm4,  %%mm4\n"		\
+        "punpckldq   %%mm4,  %%mm4\n"		\
+        : 					\
+        : "m" (alpha)				\
+        : "%mm4" );
+
+#define DM_BLITFUNC_INNER			\
+    asm(					\
+        "movd        %2,     %%mm1\n"		\
+        \
+        "movd        %3,     %%mm2\n"		\
+        "movq        %%mm1,  %%mm5\n"		\
+        "pand        %%mm2,  %%mm5\n"		\
+        "psrlw       $8,     %%mm5\n"		\
+        "punpcklwd   %%mm5,  %%mm5\n"		\
+        "punpckhwd   %%mm5,  %%mm5\n"		\
+        \
+        "pmullw      %%mm4,  %%mm5\n"		\
+        "psrlw       $8,     %%mm5\n"		\
+        \
+        "pxor        %%mm2,  %%mm2\n"		\
+        "movd        %1,     %%mm3\n"		\
+        "punpcklbw   %%mm2,  %%mm1\n"		\
+        "punpcklbw   %%mm2,  %%mm3\n"		\
+        \
+        "psubw       %%mm3,  %%mm1\n"		\
+        "pmullw      %%mm5,  %%mm1\n"		\
+        "psraw       $8,     %%mm1\n"		\
+        "paddw       %%mm3,  %%mm1\n"		\
+        "pand        %4,     %%mm1\n"		\
+        "packuswb    %%mm2,  %%mm1\n"		\
+        "movd        %%mm1,  %0\n"		\
+        : "=m" (*dp)				\
+        : "m" (*dp), "m" (sp[FP_GETH16(xv)]), "m" (qpdmask), "m" (qpdrm)	\
+        : "memory", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5" ); dp++;
+
+#define DM_BLITFUNC_FINISH asm("emms\n");
+
+#else
+
+#define DM_BLITFUNC_SRC_TYPE DMRGBA32
+#define DM_BLITFUNC_DST_TYPE DMRGBA32
+#define DM_BLITFUNC_INNER \
+    const DMRGBA32 q = sp[FP_GETH16(xv)]; \
+    const int a = (alpha * q.a) >> 8; \
+    dp->r += ((q.r - dp->r) * a) >> 8; \
+    dp->g += ((q.g - dp->g) * a) >> 8; \
+    dp->b += ((q.b - dp->b) * a) >> 8; \
+    dp->a  = a;
+    dp++;
+#endif
+
+#include "dmscaledblit.h"
+
+// =======================================================================
+// DMD_SATURATE
+// =======================================================================
+
+#define DM_BLITFUNC_NAME dmScaledBlitSurface8to8Saturate
+#define DM_BLITFUNC_SRC_BYTES 1
+#define DM_BLITFUNC_DST_BYTES 1
+#define DM_BLITFUNC_SRC_TYPE Uint8
+#define DM_BLITFUNC_DST_TYPE Uint8
+#define DM_BLITFUNC_INNER \
+    const int q = sp[FP_GETH16(xv)] + *dp; \
+    *(dp++) = q < 256 ? q : 255;
+
+#include "dmscaledblit.h"
+
+// -----------------------------------------------------------------------
+
+#define DM_BLITFUNC_NAME dmScaledBlitSurface8to32Saturate
+#define DM_BLITFUNC_SRC_BYTES 1
+#define DM_BLITFUNC_DST_BYTES 4
+#define DM_BLITFUNC_SRC_TYPE Uint8
+#define DM_BLITFUNC_DST_TYPE DMRGBA32
+#define DM_BLITFUNC_VARS const DMRGBA32 *pal;
+#define DM_BLITFUNC_INIT \
+    if (src->format->palette == NULL || src->format->palette->ncolors < 256) return -2;	\
+    pal = (DMRGBA32 *) src->format->palette->colors;
+
+#ifdef DM_USE_SIMD
+#define DM_BLITFUNC_INNER				\
+    asm("movd        %2,     %%mm1\n"		\
+        "movd        %1,     %%mm2\n"		\
+        "paddusb     %%mm2,  %%mm1\n"		\
+        "movd        %%mm1,  %0\n"		\
+        : "=m" (*dp)				\
+        : "m" (*dp), "m" (pal[sp[FP_GETH16(xv)]])	\
+        : "memory", "%mm1", "%mm2" ); dp++;
+
+#define DM_BLITFUNC_FINISH asm("emms\n");
+#else
+#define DM_BLITFUNC_INNER \
+    const DMRGBA32 q = pal[sp[FP_GETH16(xv)]]; \
+    const int qr = dp->r + q.r, qg = dp->g + q.g, qb = dp->b + q.b; \
+    dp->r = qr < 256 ? qr : 255; \
+    dp->g = qg < 256 ? qg : 255; \
+    dp->b = qb < 256 ? qb : 255; \
+    dp->a = q.a; \
+    dp++;
+#endif
+
+#include "dmscaledblit.h"
+
+// -----------------------------------------------------------------------
+
+#define DM_BLITFUNC_NAME dmScaledBlitSurface32to32Saturate
+#define DM_BLITFUNC_SRC_BYTES 4
+#define DM_BLITFUNC_DST_BYTES 4
+#define DM_BLITFUNC_INIT
+
+#ifdef DM_USE_SIMD
+#define DM_BLITFUNC_SRC_TYPE Uint32
+#define DM_BLITFUNC_DST_TYPE Uint32
+#define DM_BLITFUNC_INNER				\
+    asm("movd        %2,     %%mm1\n"		\
+        "movd        %1,     %%mm2\n"		\
+        "paddusb     %%mm2,  %%mm1\n"		\
+        "movd        %%mm1,  %0\n"		\
+        : "=m" (*dp)				\
+        : "m" (*dp), "m" (sp[FP_GETH16(xv)])	\
+        : "memory", "%mm1", "%mm2" ); dp++;
+
+#define DM_BLITFUNC_FINISH asm("emms\n");
+#else
+#define DM_BLITFUNC_SRC_TYPE DMRGBA32
+#define DM_BLITFUNC_DST_TYPE DMRGBA32
+#define DM_BLITFUNC_INNER \
+    const DMRGBA32 q = sp[FP_GETH16(xv)]; \
+    const int qr = dp->r + q.r, qg = dp->g + q.g, qb = dp->b + q.b; \
+    dp->r = qr < 256 ? qr : 255; \
+    dp->g = qg < 256 ? qg : 255; \
+    dp->b = qb < 256 ? qb : 255; \
+    dp->a = q.a; \
+    dp++;
+#endif
+
+#include "dmscaledblit.h"
+
+
+
+// =======================================================================
+// =======================================================================
+
+
+
+// =======================================================================
+// DMD_NONE
+// =======================================================================
+
+#define DM_BLITFUNC_NAME dmUnscaledBlitSurface8to8
+#define DM_BLITFUNC_SRC_BYTES 1
+#define DM_BLITFUNC_DST_BYTES 1
+#define DM_BLITFUNC_SRC_TYPE Uint8
+#define DM_BLITFUNC_DST_TYPE Uint8
+
+#define DM_BLITFUNC_INNER *dp++ = sp[xv];
+
+#include "dmunscaledblit.h"
+
+// -----------------------------------------------------------------------
+
+#define DM_BLITFUNC_NAME dmUnscaledBlitSurface8to32
+#define DM_BLITFUNC_SRC_BYTES 1
+#define DM_BLITFUNC_DST_BYTES 4
+#define DM_BLITFUNC_SRC_TYPE Uint8
+#define DM_BLITFUNC_DST_TYPE Uint32
+
+#define DM_BLITFUNC_VARS const Uint32 *pal;
+#define DM_BLITFUNC_INIT \
+    if (src->format->palette == NULL || src->format->palette->ncolors < 256) return -2;	\
+    pal = (Uint32 *) src->format->palette->colors;
+
+#define DM_BLITFUNC_INNER *dp++ = pal[sp[xv]];
+
+#include "dmunscaledblit.h"
+
+// -----------------------------------------------------------------------
+
+#define DM_BLITFUNC_NAME dmUnscaledBlitSurface32to32
+#define DM_BLITFUNC_SRC_BYTES 4
+#define DM_BLITFUNC_DST_BYTES 4
+#define DM_BLITFUNC_SRC_TYPE Uint32
+#define DM_BLITFUNC_DST_TYPE Uint32
+#define DM_BLITFUNC_INIT
+#define DM_BLITFUNC_INNER *dp++ = sp[xv];
+
+#include "dmunscaledblit.h"
+
+
+// =======================================================================
+// DMD_TRANSPARENT
+// =======================================================================
+
+#define DM_BLITFUNC_NAME dmUnscaledBlitSurface8to8Transparent
+#define DM_BLITFUNC_SRC_BYTES 1
+#define DM_BLITFUNC_DST_BYTES 1
+#define DM_BLITFUNC_SRC_TYPE Uint8
+#define DM_BLITFUNC_DST_TYPE Uint8
+
+#define DM_BLITFUNC_INNER \
+    *dp = sp[xv] ? sp[xv] : *dp; dp++;
+
+#include "dmunscaledblit.h"
+
+// -----------------------------------------------------------------------
+
+#define DM_BLITFUNC_NAME dmUnscaledBlitSurface8to32Transparent
+#define DM_BLITFUNC_SRC_BYTES 1
+#define DM_BLITFUNC_DST_BYTES 4
+#define DM_BLITFUNC_SRC_TYPE Uint8
+#define DM_BLITFUNC_DST_TYPE DMRGBA32
+#define DM_BLITFUNC_VARS const DMRGBA32 *pal;
+#define DM_BLITFUNC_INIT \
+    if (src->format->palette == NULL || src->format->palette->ncolors < 256) return -2;	\
+    pal = (DMRGBA32 *) src->format->palette->colors;
+
+#define DM_BLITFUNC_INNER \
+    const DMRGBA32 q = pal[sp[xv]]; \
+    dp->r += ((q.r - dp->r) * q.a) >> 8; \
+    dp->g += ((q.g - dp->g) * q.a) >> 8; \
+    dp->b += ((q.b - dp->b) * q.a) >> 8; \
+    dp->a  = q.a; \
+    dp++;
+
+#include "dmunscaledblit.h"
+
+
+// -----------------------------------------------------------------------
+
+#define DM_BLITFUNC_NAME dmUnscaledBlitSurface32to32Transparent
+#define DM_BLITFUNC_SRC_BYTES 4
+#define DM_BLITFUNC_DST_BYTES 4
+
+#ifdef DM_USE_SIMD
+#define DM_BLITFUNC_VARS \
+    const Uint32 qpdmask =       0xff000000; \
+    const Uint64 qpdrm   = 0xff00ff00ff00ffULL;
+    
+#define DM_BLITFUNC_SRC_TYPE Uint32
+#define DM_BLITFUNC_DST_TYPE Uint32
+#define DM_BLITFUNC_INNER				\
+    asm(					\
+        "movd        %2,     %%mm1\n"		\
+        \
+        "movd        %3,     %%mm2\n"		\
+        "movq        %%mm1,  %%mm5\n"		\
+        "pand        %%mm2,  %%mm5\n"		\
+        "psrlw       $8,     %%mm5\n"		\
+        "punpcklwd   %%mm5,  %%mm5\n"		\
+        "punpckhwd   %%mm5,  %%mm5\n"		\
+        \
+        "pxor        %%mm2,  %%mm2\n"		\
+        "movd        %1,     %%mm3\n"		\
+        "punpcklbw   %%mm2,  %%mm1\n"		\
+        "punpcklbw   %%mm2,  %%mm3\n"		\
+        \
+        "psubw       %%mm3,  %%mm1\n"		\
+        "pmullw      %%mm5,  %%mm1\n"		\
+        "psraw       $8,     %%mm1\n"		\
+        "paddw       %%mm3,  %%mm1\n"		\
+        "pand        %4,     %%mm1\n"		\
+        "packuswb    %%mm2,  %%mm1\n"		\
+        "movd        %%mm1,  %0\n"		\
+        : "=m" (*dp)				\
+        : "m" (*dp), "m" (sp[xv]), "m" (qpdmask), "m" (qpdrm)	\
+        : "memory", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5" ); dp++;
+
+#define DM_BLITFUNC_FINISH asm("emms\n");
+
+#else
+
+#define DM_BLITFUNC_SRC_TYPE DMRGBA32
+#define DM_BLITFUNC_DST_TYPE DMRGBA32
+#define DM_BLITFUNC_INNER \
+    const DMRGBA32 q = sp[xv]; \
+    dp->r += ((q.r - dp->r) * q.a) >> 8; \
+    dp->g += ((q.g - dp->g) * q.a) >> 8; \
+    dp->b += ((q.b - dp->b) * q.a) >> 8; \
+    dp->a  = q.a; \
+    dp++;
+#endif
+
+#include "dmunscaledblit.h"
+
+
+// =======================================================================
+// DMD_SATURATE
+// =======================================================================
+
+#define DM_BLITFUNC_NAME dmUnscaledBlitSurface8to8Saturate
+#define DM_BLITFUNC_SRC_BYTES 1
+#define DM_BLITFUNC_DST_BYTES 1
+#define DM_BLITFUNC_SRC_TYPE Uint8
+#define DM_BLITFUNC_DST_TYPE Uint8
+#define DM_BLITFUNC_INNER \
+    const int q = sp[xv] + *dp; \
+    *(dp++) = q < 256 ? q : 255;
+
+#include "dmunscaledblit.h"
+
+// -----------------------------------------------------------------------
+
+#define DM_BLITFUNC_NAME dmUnscaledBlitSurface8to32Saturate
+#define DM_BLITFUNC_SRC_BYTES 1
+#define DM_BLITFUNC_DST_BYTES 4
+#define DM_BLITFUNC_SRC_TYPE Uint8
+#define DM_BLITFUNC_DST_TYPE DMRGBA32
+#define DM_BLITFUNC_VARS const DMRGBA32 *pal;
+#define DM_BLITFUNC_INIT \
+    if (src->format->palette == NULL || src->format->palette->ncolors < 256) return -2;	\
+    pal = (DMRGBA32 *) src->format->palette->colors;
+
+#ifdef DM_USE_SIMD
+#define DM_BLITFUNC_INNER				\
+    asm("movd        %2,     %%mm1\n"		\
+        "movd        %1,     %%mm2\n"		\
+        "paddusb     %%mm2,  %%mm1\n"		\
+        "movd        %%mm1,  %0\n"		\
+        : "=m" (*dp)				\
+        : "m" (*dp), "m" (pal[sp[xv]])	\
+        : "memory", "%mm1", "%mm2" ); dp++;
+
+#define DM_BLITFUNC_FINISH asm("emms\n");
+#else
+#define DM_BLITFUNC_INNER \
+    const DMRGBA32 q = pal[sp[xv]]; \
+    const int qr = dp->r + q.r, qg = dp->g + q.g, qb = dp->b + q.b; \
+    dp->r = qr < 256 ? qr : 255; \
+    dp->g = qg < 256 ? qg : 255; \
+    dp->b = qb < 256 ? qb : 255; \
+    dp->a = q.a; \
+    dp++;
+#endif
+
+#include "dmunscaledblit.h"
+
+// -----------------------------------------------------------------------
+
+#define DM_BLITFUNC_NAME dmUnscaledBlitSurface32to32Saturate
+#define DM_BLITFUNC_SRC_BYTES 4
+#define DM_BLITFUNC_DST_BYTES 4
+#define DM_BLITFUNC_INIT
+
+#ifdef DM_USE_SIMD
+#define DM_BLITFUNC_SRC_TYPE Uint32
+#define DM_BLITFUNC_DST_TYPE Uint32
+#define DM_BLITFUNC_INNER			\
+    asm("movd        %2,     %%mm1\n"		\
+        "movd        %1,     %%mm2\n"		\
+        "paddusb     %%mm2,  %%mm1\n"		\
+        "movd        %%mm1,  %0\n"		\
+        : "=m" (*dp)				\
+        : "m" (*dp), "m" (sp[xv])	\
+        : "memory", "%mm1", "%mm2" ); dp++;
+
+#define DM_BLITFUNC_FINISH asm("emms\n");
+#else
+#define DM_BLITFUNC_SRC_TYPE DMRGBA32
+#define DM_BLITFUNC_DST_TYPE DMRGBA32
+#define DM_BLITFUNC_INNER \
+    const DMRGBA32 q = sp[xv]; \
+    const int qr = dp->r + q.r, qg = dp->g + q.g, qb = dp->b + q.b; \
+    dp->r = qr < 256 ? qr : 255; \
+    dp->g = qg < 256 ? qg : 255; \
+    dp->b = qb < 256 ? qb : 255; \
+    dp->a = q.a; \
+    dp++;
+#endif
+
+#include "dmunscaledblit.h"
+
+
+// =======================================================================
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmbstr.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,76 @@
+/*
+ * DMLib
+ * -- Simple bitstream I/O functions
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012 Tecnic Software productions (TNSP)
+ */
+#include "dmbstr.h"
+
+
+static int dmPutByteFILE(DMBitStreamContext *ctx, Uint8 val)
+{
+    return fputc(val, (FILE *) ctx->fp);
+}
+
+
+void dmInitBitStreamContext(DMBitStreamContext *ctx)
+{
+    ctx->buf     = 0;
+    ctx->bytecnt = 0;
+    ctx->bitcnt  = 8;
+}
+
+
+int dmInitBitStreamFILE(DMBitStreamContext *ctx, FILE *fp)
+{
+    if (ctx == NULL || fp == NULL)
+        return DMERR_NULLPTR;
+
+    ctx->putByte = dmPutByteFILE;
+    ctx->fp      = (void *) fp;
+
+    dmInitBitStreamContext(ctx);
+
+    return DMERR_OK;
+}
+
+
+BOOL dmPutBits(DMBitStreamContext *ctx, const int val, const int n)
+{
+    int i;
+    unsigned int mask = 1 << (n - 1);
+
+    for (i = 0; i < n; i++)
+    {
+        ctx->buf <<= 1;
+
+        if (val & mask)
+          ctx->buf |= 1;
+
+        mask >>= 1;
+        ctx->bitcnt--;
+
+        if (ctx->bitcnt == 0)
+        {
+            if (ctx->putByte(ctx, (ctx->buf & 0xff)) == EOF)
+                return FALSE;
+
+            ctx->bitcnt = 8;
+            ctx->bytecnt++;
+        }
+    }
+
+    return TRUE;
+}
+
+
+int dmFlushBitStream(DMBitStreamContext *ctx)
+{
+  if (ctx == NULL)
+      return DMERR_NULLPTR;
+
+  if (ctx->bitcnt != 8)
+      dmPutBits(ctx, 0, ctx->bitcnt);
+  
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmbstr.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,31 @@
+/*
+ * DMLib
+ * -- Simple bitstream I/O functions
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012 Tecnic Software productions (TNSP)
+ */
+#ifndef DMBSTR_H
+#define DMBSTR_H
+
+#include "dmlib.h"
+
+typedef struct _DMBitStreamContext
+{
+  void *fp;
+  int (*putByte)(struct _DMBitStreamContext *ctx, Uint8 val);
+
+  int buf, bitcnt, bytecnt;
+} DMBitStreamContext;
+
+
+void  dmInitBitStreamContext(DMBitStreamContext *ctx);
+BOOL  dmPutBits(DMBitStreamContext *ctx, const int val, const int n);
+int   dmFlushBitStream(DMBitStreamContext *ctx);
+
+int   dmInitBitStreamFILE(DMBitStreamContext *ctx, FILE *fp);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif // DMBSTR_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmdrawline.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,108 @@
+/*
+ * DMLib
+ * -- Simple Bresenham's style line drawing
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2011-2012 Tecnic Software productions (TNSP)
+ */
+
+int DM_DRAWLINE_NAME (SDL_Surface *screen, DMFloat fx0, DMFloat fy0, DMFloat fx1, DMFloat fy1, const Uint32 col
+#ifdef DM_DRAWLINE_ARGS
+    DM_DRAWLINE_ARGS
+#endif
+)
+#ifdef DM_HEADER
+;
+#else
+{
+    int dx, dy, xstep, ystep;
+    const int qpitch = screen->pitch / DM_DRAWLINE_DST_BYTES;
+    (void) qpitch;
+    (void) col;
+
+    // Clipping
+    if (dmClipLineCoordsFloat(screen, &fx0, &fy0, &fx1, &fy1) < 0)
+        return -1;
+
+    int x0 = fx0, y0 = fy0, x1 = fx1, y1 = fy1;
+
+    // Compute initial deltas
+    dx = (x1 - x0) * 2;
+    dy = (y1 - y0) * 2;
+
+
+    if (dx < 0)
+    {
+        dx = -dx;
+        xstep = -1;
+    }
+    else
+        xstep = 1;
+
+    if (dy < 0)
+    {
+        dy = -dy;
+        ystep = -1;
+    }
+    else
+        ystep = 1;
+
+#ifndef DM_DRAWLINE_SPEC
+    // Compute offsets
+    y0 *= qpitch;
+    y1 *= qpitch;
+    ystep *= qpitch;
+#endif
+
+#ifdef DM_DRAWLINE_INIT
+    DM_DRAWLINE_INIT
+#endif
+
+    DM_DRAWLINE_DST_TYPE *pix = (DM_DRAWLINE_DST_TYPE *) screen->pixels;
+    (void) pix;
+
+    // Continue based on which delta is larger
+    if (dx > dy)
+    {
+        int afrac = dy - (dx / 2.0);
+        while (x0 != x1)
+        {
+            if (afrac >= 0)
+            {
+                y0 += ystep;
+                afrac -= dx;
+            }
+
+            x0 += xstep;
+            afrac += dy;
+            
+            DM_DRAWLINE_INNER
+        }
+    }
+    else
+    {
+        int afrac = dx - (dy / 2.0);
+        while (y0 != y1)
+        {
+            if (afrac >= 0)
+            {
+                x0 += xstep;
+                afrac -= dy;
+            }
+
+            y0 += ystep;
+            afrac += dx;
+
+            DM_DRAWLINE_INNER
+        }
+    }
+
+    return 0;
+}
+#endif
+
+#undef DM_DRAWLINE_NAME
+#undef DM_DRAWLINE_ARGS
+#undef DM_DRAWLINE_DST_BYTES
+#undef DM_DRAWLINE_DST_TYPE
+#undef DM_DRAWLINE_INIT
+#undef DM_DRAWLINE_INNER
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmengine.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,458 @@
+/*
+ * dmlib
+ * -- Demo engine / editor common code and definitions
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012-2013 Tecnic Software productions (TNSP)
+ */
+#include "dmengine.h"
+#include "dmimage.h"
+
+
+#ifdef DM_USE_TREMOR
+#include <tremor/ivorbiscodec.h>
+#include <tremor/ivorbisfile.h>
+#endif
+
+
+DMEngineData engine;
+DMEffect *engineEffects = NULL;
+int nengineEffects = 0, nengineEffectsAlloc = 0;
+
+
+int engineRegisterEffect(const DMEffect *ef)
+{
+    if (ef == NULL)
+        return DMERR_NULLPTR;
+
+    // Allocate more space for effects
+    if (nengineEffects + 1 >= nengineEffectsAlloc)
+    {
+        nengineEffectsAlloc += 16;
+        engineEffects = dmRealloc(engineEffects, sizeof(DMEffect) * nengineEffectsAlloc);
+        if (engineEffects == NULL)
+        {
+            dmError("Could not expand effects structure.\n"); 
+            return DMERR_INIT_FAIL;
+        }
+    }
+
+    // Copy effects structure
+    memcpy(engineEffects + nengineEffects, ef, sizeof(DMEffect));
+    nengineEffects++;
+    
+    return DMERR_OK;
+}
+
+
+int engineInitializeEffects(DMEngineData *engine)
+{
+    int i, res;
+
+    dmFree(engine->effectData);
+    engine->effectData = dmCalloc(nengineEffectsAlloc, sizeof(void *));
+    if (engine->effectData == NULL)
+    {
+        dmError("Could not expand effects data structure.\n"); 
+        return DMERR_INIT_FAIL;
+    }
+
+    for (i = 0; i < nengineEffects; i++)
+    {
+        if (engineEffects[i].init != NULL &&
+            (res = engineEffects[i].init(engine, &(engine->effectData[i]))) != DMERR_OK)
+            return res;
+    }
+
+    return DMERR_OK;
+}
+
+
+void engineShutdownEffects(DMEngineData *engine)
+{
+    if (engine != NULL && engine->effectData != NULL)
+    {
+        int i;
+        for (i = 0; i < nengineEffects; i++)
+        {
+            if (engineEffects[i].shutdown != NULL)
+                engineEffects[i].shutdown(engine, engine->effectData[i]);
+        }
+        dmFree(engine->effectData);
+        engine->effectData = NULL;
+    }
+}
+
+
+DMEffect *engineFindEffect(const char *name, const int nparams)
+{
+    int i;
+    for (i = 0; i < nengineEffects; i++)
+    {
+        if (strcmp(engineEffects[i].name, name) == 0 &&
+            engineEffects[i].nparams == nparams)
+            return &engineEffects[i];
+    }
+    return NULL;
+}
+
+
+DMEffect *engineFindEffectByName(const char *name)
+{
+    int i;
+    for (i = 0; i < nengineEffects; i++)
+    {
+        if (strcmp(engineEffects[i].name, name) == 0)
+            return &engineEffects[i];
+    }
+    return NULL;
+}
+
+
+static int engineResImageLoad(DMResource *res)
+{
+    SDL_Surface *img = dmLoadImage(res);
+    if (res != NULL)
+    {
+        res->resData = img;
+        return DMERR_OK;
+    }
+    else
+        return dmferror(res);
+}
+
+
+static void engineResImageFree(DMResource *res)
+{
+    SDL_FreeSurface((SDL_Surface *)res->resData);
+}
+
+static BOOL engineResImageProbe(DMResource *res, const char *fext)
+{
+    (void) res;
+    return fext != NULL && (strcasecmp(fext, ".jpg") == 0 || strcasecmp(fext, ".png") == 0);
+}
+
+
+#ifdef JSS_SUP_XM
+static int engineResXMModuleLoad(DMResource *res)
+{
+    return jssLoadXM(res, (JSSModule **) &(res->resData), FALSE);
+}
+
+static void engineResXMModuleFree(DMResource *res)
+{
+    jssFreeModule((JSSModule *) res->resData);
+}
+
+static BOOL engineResXMModuleProbe(DMResource *res, const char *fext)
+{
+    (void) res;
+    return fext != NULL && strcasecmp(fext, ".xm") == 0;
+}
+#endif
+
+
+#ifdef JSS_SUP_JSSMOD
+static int engineResJSSModuleLoad(DMResource *res)
+{
+    return jssLoadJSSMOD(res, (JSSModule **) &(res->resData), FALSE);
+}
+
+static void engineResJSSModuleFree(DMResource *res)
+{
+    jssFreeModule((JSSModule *) res->resData);
+}
+
+static BOOL engineResJSSModuleProbe(DMResource *res, const char *fext)
+{
+    (void) res;
+    return fext != NULL &&
+        (strcasecmp(fext, ".jss") == 0 || strcasecmp(fext, ".jmod") == 0);
+}
+#endif
+
+
+#ifdef DM_USE_TREMOR
+static size_t vorbisFileRead(void *ptr, size_t size, size_t nmemb, void *datasource)
+{
+    return dmfread(ptr, size, nmemb, (DMResource *) datasource);
+}
+
+static int vorbisFileSeek(void *datasource, ogg_int64_t offset, int whence)
+{
+    return dmfseek((DMResource *) datasource, offset, whence);
+}
+
+static int vorbisFileClose(void *datasource)
+{
+    (void) datasource;
+    return 0;
+}
+
+static long vorbisFileTell(void *datasource)
+{
+    return dmftell((DMResource *) datasource);
+}
+      
+
+static ov_callbacks vorbisFileCBS =
+{
+    vorbisFileRead,
+    vorbisFileSeek,
+    vorbisFileClose,
+    vorbisFileTell
+};
+
+static int engineResVorbisLoad(DMResource *res)
+{
+    OggVorbis_File vf;
+
+    dmMsg(1, "vorbisfile '%s', %d bytes resource loading\n",
+        res->filename, res->rawSize);
+
+    if (ov_open_callbacks(res, &vf, NULL, 0, vorbisFileCBS) < 0)
+        return DMERR_FOPEN;
+
+    res->resSize = ov_pcm_total(&vf, -1) * 2 * 2;
+    if ((res->resData = dmMalloc(res->resSize + 16)) == NULL)
+    {
+        ov_clear(&vf);
+        return DMERR_MALLOC;
+    }
+
+    dmMsg(1, "rdataSize=%d bytes?\n", res->resSize);
+
+    BOOL eof = FALSE;
+    int left = res->resSize;
+    char *ptr = res->resData;
+    int current_section;
+    while (!eof && left > 0)
+    {
+        int ret = ov_read(&vf, ptr, left > 4096 ? 4096 : left, &current_section);
+        if (ret == 0)
+            eof = TRUE;
+        else
+        if (ret < 0)
+        {
+            ov_clear(&vf);
+            return DMERR_INVALID_DATA;
+        }
+        else
+        {
+            left -= ret;
+            ptr += ret;
+        }
+    }
+
+    ov_clear(&vf);
+    return DMERR_OK;
+}
+
+static void engineResVorbisFree(DMResource *res)
+{
+    dmFree(res->resData);
+}
+
+static BOOL engineResVorbisProbe(DMResource *res, const char *fext)
+{
+    (void) res;
+    return fext != NULL && (strcasecmp(fext, ".ogg") == 0);
+}
+#endif
+
+
+static DMResourceDataOps engineResOps[] =
+{
+    {
+        engineResImageProbe,
+        engineResImageLoad,
+        engineResImageFree
+    },
+
+#ifdef JSS_SUP_JSSMOD
+    {
+        engineResJSSModuleProbe,
+        engineResJSSModuleLoad,
+        engineResJSSModuleFree
+    },
+#endif
+
+#ifdef JSS_SUP_XM
+    {
+        engineResXMModuleProbe,
+        engineResXMModuleLoad,
+        engineResXMModuleFree
+    },
+#endif
+
+#ifdef DM_USE_TREMOR
+    {
+        engineResVorbisProbe,
+        engineResVorbisLoad,
+        engineResVorbisFree
+    },
+#endif
+
+};
+
+static const int nengineResOps = sizeof(engineResOps) / sizeof(engineResOps[0]);
+
+
+int engineClassifier(DMResource *res)
+{
+    int i;
+    char *fext;
+
+    if (res == NULL)
+        return DMERR_NULLPTR;
+    
+    fext = strrchr(res->filename, '.');
+    for (i = 0; i < nengineResOps; i++)
+    {
+        DMResourceDataOps *rops = &engineResOps[i];
+        if (rops->probe != NULL && rops->probe(res, fext))
+        {
+            res->rops = rops;
+            return DMERR_OK;
+        }
+    }
+    
+    return DMERR_OK;
+}
+
+
+void *engineGetResource(DMEngineData *eng, const char *name)
+{
+    DMResource *res;
+    if (eng != NULL &&
+        (res = dmResourceFind(eng->resources, name)) != NULL &&
+        res->resData != NULL)
+        return res->resData;
+    else
+    {
+        dmError("Could not find resource '%s'.\n", name);
+        return NULL;
+    }
+}
+
+
+#ifdef DM_USE_JSS
+void engineGetJSSInfo(DMEngineData *eng, BOOL *playing, int *order, JSSPattern **pat, int *npattern, int *row)
+{
+    JSS_LOCK(eng->jssPlr);
+
+    *playing  = eng->jssPlr->isPlaying;
+    *row      = eng->jssPlr->row;
+    *pat      = eng->jssPlr->pattern;
+    *npattern = eng->jssPlr->npattern;
+    *order    = eng->jssPlr->order;
+
+    JSS_UNLOCK(eng->jssPlr);
+}
+
+
+void engineGetJSSChannelInfo(DMEngineData *eng, const int channel, int *ninst, int *nextInst, int *freq, int *note)
+{
+    JSS_LOCK(eng->jssPlr);
+
+    JSSPlayerChannel *chn = &(eng->jssPlr->channels[channel]);
+    *ninst    = chn->ninstrument;
+    *nextInst = chn->nextInstrument;
+    *freq     = chn->freq;
+    *note     = chn->note;
+
+    JSS_UNLOCK(eng->jssPlr);
+}
+#endif
+
+
+int engineGetTick(DMEngineData *engine)
+{
+    return engine->frameTime - engine->startTime;
+}
+
+
+float engineGetTimeDT(DMEngineData *engine)
+{
+    return (float) engineGetTick(engine) / 1000.0f;
+}
+
+
+int engineGetTimeDTi(DMEngineData *engine)
+{
+    return (float) engineGetTick(engine) / 1000;
+}
+
+
+int engineGetTime(DMEngineData *engine, int t)
+{
+    return engineGetTick(engine) - (1000 * t);
+}
+
+
+int engineGetDT(DMEngineData *engine, int t)
+{
+    return engineGetTime(engine, t) / 1000;
+}
+
+
+void engineAudioCallback(void *userdata, Uint8 *stream, int len)
+{
+    (void) userdata;
+
+    dmMutexLock(engine.audioStreamMutex);
+    engine.audioStreamBuf  = stream;
+    engine.audioStreamLen  = len / engine.audioSampleSize;
+    engine.audioTimePos   += (1000 * engine.audioStreamLen) / engine.optAfmt.freq;
+
+    if (engine.paused)
+    {
+        memset(stream, 0, len);
+    }
+    else
+    switch (engine.optAudioSetup)
+    {
+#ifdef DM_USE_JSS
+        case DM_ASETUP_JSS:
+            if (engine.jssDev != NULL)
+                jvmRenderAudio(engine.jssDev, stream, len / engine.audioSampleSize);
+            break;
+#endif
+#ifdef DM_USE_TREMOR
+        case DM_ASETUP_TREMOR:
+            if (engine.audioPos + len >= engine.audioRes->resSize)
+                engine.exitFlag = TRUE;
+            else
+            {
+                memcpy(stream, engine.audioRes->resData + engine.audioPos, len);
+                engine.audioPos += len;
+            }
+            break;
+#endif
+
+        default:
+            break;
+    }
+
+    dmMutexUnlock(engine.audioStreamMutex);
+}
+
+
+void enginePauseAudio(int status)
+{
+    if (status)
+        engine.audioStatus = SDL_AUDIO_PAUSED;
+    else
+        engine.audioStatus = SDL_AUDIO_PLAYING;
+
+    SDL_PauseAudio(status);
+}
+
+
+int engineGetVideoAspect(int width, int height)
+{
+    if (width > 0 && height > 0)
+        return (width * 1000) / height;
+    else
+        return 1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmengine.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,383 @@
+/*
+ * dmlib
+ * -- Demo engine / editor common code and definitions
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012-2013 Tecnic Software productions (TNSP)
+ */
+#ifndef DMENGINE_H
+#define DMENGINE_H
+
+#include "dmlib.h"
+#include <SDL_events.h>
+#include <SDL_audio.h>
+#include "dmres.h"
+#include "dmvecmat.h"
+
+#ifdef DM_USE_JSS
+#include "jss.h"
+#include "jssmod.h"
+#include "jssmix.h"
+#include "jssplr.h"
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Video setup screen / window size
+#define DM_VSETUP_WIDTH       640
+#define DM_VSETUP_HEIGHT      480
+
+
+// Video setup type
+enum
+{
+    DM_VSETUP_NONE    = 0x00,  // No video setup, just set window/screen to what demo specifies
+    DM_VSETUP_ASPECT  = 0x01,  // Only modes that match the optVidAspect aspect ratio are ok
+    DM_VSETUP_ANY     = 0x02,  // Any available mode is okay, the code can adapt
+};
+
+// Audio setup type
+enum
+{
+    DM_ASETUP_NONE    = 0,
+    DM_ASETUP_JSS     = 1,
+    DM_ASETUP_TREMOR  = 2,
+};
+
+
+
+#define DT_MAGIC_ID           "SDMETLNE"
+#define DT_MAX_EFFECT_PARAMS  16
+#define DT_MAX_NAME_LENGTH    32
+#define DT_FLOAT_STORE_SIZE   16
+
+
+enum
+{
+    EFIT_SET,    // No interpolation, just "set" the value
+    EFIT_LINEAR, // Linear interpolation
+    EFIT_SMOOTH, // Smoothstep interpolation
+};
+
+enum
+{
+    EFPT_INT,
+    EFPT_FLOAT,
+    EFPT_STRING,
+    EFPT_VECTOR,
+    EFPT_MATRIX,
+};
+
+
+typedef struct
+{
+    int type;                // Interpolation type (EFIT_*) between this and next point
+    int time;                // Offsets to event start, -1 == attach to event start, -2 = event end (if event)
+
+    int vint;
+    DMFloat vfloat;
+    DMVector vector;
+    DMMatrix matrix;
+} DMTimelinePoint;
+
+
+typedef struct
+{
+    int npoints, nallocated;
+    DMTimelinePoint *points;
+} DMTimelinePoints;
+
+
+typedef struct
+{
+    char *name;              // Name / description of the parameter
+    int type;                // Type (EFPT_*)
+
+    DMTimelinePoints pts;
+    char *vstr;
+
+    // Current values (interpolated)
+    int vint;
+    DMFloat vfloat;
+    DMVector vvector;
+    DMMatrix vmatrix;
+} DMTimelineEventParam;
+
+
+typedef struct
+{
+    char name[DT_MAX_NAME_LENGTH];
+    Uint32 type;
+} DMFTimelineEventParam;
+
+
+struct DMEngineData;
+
+
+typedef struct
+{
+    char *  name;
+    int     type;
+    
+    int     (*init)(struct DMEngineData *, void **data);
+    void    (*shutdown)(struct DMEngineData *, void *data);
+    int     (*render)(SDL_Surface *screen, void *data, const DMTimelineEventParam *params, const int time);
+
+    int     nparams;
+    DMTimelineEventParam params[DT_MAX_EFFECT_PARAMS];
+} DMEffect;
+
+
+#ifdef DM_USE_TIMELINE
+
+
+typedef struct
+{
+    Uint32 start, duration;
+    char effectName[DT_MAX_NAME_LENGTH];
+    Uint32 nparams;
+} DMFTimelineEvent;
+
+
+typedef struct
+{
+    int start, duration;
+    DMEffect *effect;
+    int nparams;
+    DMTimelineEventParam *params;
+} DMTimelineEvent;
+
+
+typedef struct
+{
+    BOOL enabled;
+    DMTimelinePoints points;
+} DMTimelineCurve;
+
+
+typedef struct
+{
+    Uint32 index, layer;
+    char name[DT_MAX_NAME_LENGTH];
+    Uint8 enabled;
+    Uint32 nevents;
+} DMFTimelineTrack;
+
+
+typedef struct
+{
+    int index;         // Track index
+    int layer;         // Target render layer (0 = engine.screen in software rendering)
+    char *name;        // Name of the timeline track
+    BOOL enabled;      // Enabled?
+
+    int nevents, nallocated;    // Number of events
+    DMTimelineEvent **events;   // Events
+
+    DMTimelineCurve composite;  // Composite curve (transparency of the "layer")
+} DMTimelineTrack;
+
+
+typedef struct
+{
+    char   magic[8];
+    char   name[DT_MAX_NAME_LENGTH];
+    Uint32 ntracks;
+    Uint32 duration;
+} DMFTimeline;
+
+
+typedef struct
+{
+    char *name;
+    int ntracks, nallocated, duration;
+    DMTimelineTrack **tracks;
+} DMTimeline;
+
+
+typedef struct
+{
+    DMTimelineTrack *track;
+    DMTimelineEvent *event;
+} DMPreparedEvent;
+
+
+typedef struct _DMPreparedEventGroup
+{
+    int start, end, nevents, nallocated;
+    DMPreparedEvent *events;
+
+    struct _DMPreparedEventGroup *next, *prev;
+} DMPreparedEventGroup;
+
+
+typedef struct
+{
+    int duration, ngroups, pos;
+    DMPreparedEventGroup **groups;
+} DMPreparedTimeline;
+
+#endif
+
+
+typedef struct DMEngineData
+{
+    DMResourceLib *resources;
+    void **effectData;
+
+#ifdef DM_USE_TIMELINE
+    DMResource *timeline;
+    DMTimeline *tl;
+    DMPreparedTimeline *ptl;
+#endif
+
+    int frameTime, frameCount,
+        startTime, endTime,
+        pauseTime;
+
+    BOOL pauseFlag, paused, exitFlag;
+
+    SDL_Surface *screen;
+    SDL_Event event;
+
+    int optVidWidth, optVidHeight,
+        optVidDepth, optVFlags,
+        optVidAspect, optVidSetup;
+    BOOL optVidNative;
+
+    int optResFlags;
+    char *optDataPath, *optPackFilename;
+
+    // Audio related
+    SDL_AudioSpec optAfmt;
+    int optAudioSetup;
+
+    int audioStatus;            // Current status of audio output (SDL_AUDIO_PLAYING, etc.)
+    DMMutex *audioStreamMutex;
+    Uint8 * audioStreamBuf;
+    size_t audioStreamLen;      // Length in samples
+    Uint32 audioTimePos;        // Approximate audio time (in milliseconds)
+    int audioSampleSize;        // Size of one audio sample in bytes (incl. all channels)
+
+    // No-sound audio simulation thread stuff
+    SDL_Thread *audioSimThread;
+    Uint8 * audioSimBuf;
+    size_t audioSimBufSize;
+    BOOL audioSimDone;
+    int  audioSimDelay;
+
+#ifdef DM_USE_JSS
+    JSSMixer *jssDev;
+    JSSPlayer *jssPlr;
+    int jssFormat;
+#endif
+
+#ifdef DM_USE_TREMOR
+    DMResource *audioRes;
+    size_t audioPos;
+#endif
+
+    int    (*demoInit)(struct DMEngineData *);
+    int    (*demoInitPreVideo)(struct DMEngineData *);
+    int    (*demoInitPostVideo)(struct DMEngineData *);
+    int    (*demoRender)(struct DMEngineData *);
+    void   (*demoShutdown)(struct DMEngineData *);
+    void   (*demoQuit)(struct DMEngineData *);
+
+    // Setup specifics
+    DMVector setupMenuPos, setupMenuDim, setupText1Pos;
+    BOOL setupMenuCenter, setupTextCondensed;
+    char setupTextFullscreen[64], setupTextWindowed[64], setupTextPrefix[64];
+} DMEngineData;
+
+
+extern DMEffect *engineEffects;
+extern int nengineEffects, nengineEffectsAlloc;
+
+
+// Effect registration
+int       engineRegisterEffect(const DMEffect *ef);
+int       engineInitializeEffects(DMEngineData *);
+void      engineShutdownEffects(DMEngineData *);
+DMEffect *engineFindEffect(const char *name, const int nparams);
+DMEffect *engineFindEffectByName(const char *name);
+
+
+#ifdef DM_USE_TIMELINE
+// Basic timeline handling
+int  dmLoadTimeline(DMResource *res, DMTimeline **tl);
+void dmFreeTimeline(DMTimeline *tl);
+
+void dmFreeTimelinePoints(DMTimelinePoints *points);
+void dmFreeTimelineEventParam(DMTimelineEventParam *param);
+void dmFreeTimelineEvent(DMTimelineEvent *event);
+void dmFreeTimelineTrack(DMTimelineTrack *track);
+
+
+// Execution related
+int  dmPrepareTimeline(DMTimeline *tl, DMPreparedTimeline *ptl);
+void dmFreePreparedTimelineData(DMPreparedTimeline *ptl);
+
+int  dmSeekTimeline(DMPreparedTimeline *tl, int time);
+int  dmExecuteTimeline(DMPreparedTimeline *tl, SDL_Surface *screen, int time);
+
+
+// Editing/saving related functions
+int  dmCopyTimelinePoints(const DMTimelinePoints *src, DMTimelinePoints *dst);
+int  dmCopyTimelineEventParam(const DMTimelineEventParam *src, DMTimelineEventParam *dst);
+int  dmCopyTimelineEvent(const DMTimelineEvent *src, DMTimelineEvent **pdst);
+int  dmCopyTimelineCurve(const DMTimelineCurve *src, DMTimelineCurve *dst);
+int  dmCopyTimelineTrack(const DMTimelineTrack *src, DMTimelineTrack **pdst);
+int  dmCopyTimeline(const DMTimeline *src, DMTimeline **pdst);
+
+int  dmSaveTimeline(DMResource *res, DMTimeline *tl);
+
+int  dmTimelineNew(DMTimeline **tl, const char *name);
+int  dmTimelineAddTrack(DMTimeline *tl, DMTimelineTrack **track, const char *name);
+int  dmTimelineTrackAddEvent(DMTimelineTrack *track, int start, int duration, DMTimelineEvent **pev);
+int  dmTimelineEventSetEffect(DMTimelineEvent *event, DMEffect *ef);
+int  dmTimelineEventSetEffectByIndex(DMTimelineEvent *event, const int index);
+int  dmTimelineEventSetEffectByName(DMTimelineEvent *event, const char *name);
+
+#endif // DM_USE_TIMELINE
+
+
+// Resource helpers
+#define engineGetResImage(eng, x, name) \
+    do { \
+        if ((x = (SDL_Surface *) engineGetResource(eng, name)) == NULL) \
+            return DMERR_INIT_FAIL; \
+    } while (0)
+
+#define engineGetResModule(eng, x, name) \
+    do { \
+        if ((x = (JSSModule *) engineGetResource(eng, name)) == NULL) \
+            return DMERR_INIT_FAIL; \
+    } while (0)
+
+#define engineFindResource(eng, name) dmResourceFind((eng)->resources, name)
+
+
+int    engineClassifier(DMResource *res);
+void * engineGetResource(DMEngineData *eng, const char *name);
+int    engineGetTime(DMEngineData *eng, int t);
+int    engineGetTimeDTi(DMEngineData *eng);
+int    engineGetTick(DMEngineData *eng);
+float  engineGetTimeDT(DMEngineData *eng);
+
+void   engineAudioCallback(void *userdata, Uint8 *stream, int len);
+void   enginePauseAudio(int status);
+int    engineGetVideoAspect(int width, int height);
+
+
+// Implemented in actual demo code
+int    demoPreInit(DMEngineData *eng);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DMENGINE_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmeval.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,765 @@
+#include "dmeval.h"
+#include <math.h>
+
+#define DM_MAX_BUF     512
+
+
+/* Operators
+ */
+const DMEvalOper dmEvalOpers[OP_NOPERS] =
+{
+    { "-"      , OT_UNARY , FALSE },
+    { "~"      , OT_UNARY , TRUE },
+    
+    { "+"      , OT_LEFT  , TRUE },
+    { "-"      , OT_LEFT  , TRUE },
+    { "*"      , OT_LEFT  , TRUE },
+    { "/"      , OT_LEFT  , TRUE },
+    { "%"      , OT_LEFT  , TRUE },
+
+
+    { "<<"     , OT_LEFT  , TRUE },
+    { ">>"     , OT_LEFT  , TRUE },
+
+    { "&"      , OT_LEFT  , TRUE },
+    { "|"      , OT_LEFT  , TRUE },
+    { "^"      , OT_LEFT  , TRUE },
+
+    { ">="     , OT_LEFT  , TRUE },
+    { "<="     , OT_LEFT  , TRUE },
+    { ">"      , OT_LEFT  , TRUE },
+    { "<"      , OT_LEFT  , TRUE },
+
+    { "FUNC"   , OT_NONE  , FALSE },
+    { "VAR"    , OT_NONE  , FALSE },
+    { "CONST"  , OT_NONE  , FALSE },
+
+    { "SUBEXPR", OT_NONE  , FALSE },
+};
+
+
+/* Function definitions
+ */
+static DMValue func_int_clip(DMValue *v)
+{
+    return (*v < -1.0f) ? -1.0f : ((*v > 1.0f) ? 1.0f : *v);
+}
+
+
+static DMValue func_sin(DMValue *v)
+{
+    return sin(*v);
+}
+
+
+static DMValue func_cos(DMValue *v)
+{
+    return cos(*v);
+}
+
+
+static DMValue func_pow(DMValue *v)
+{
+    return pow(v[0], v[1]);
+}
+
+
+/* Some basic functions
+ */
+static const DMEvalSymbol dmEvalBasicFuncs[] =
+{
+    { "sin",  SYM_FUNC , 1, func_sin, NULL, 0 },
+    { "cos",  SYM_FUNC , 1, func_cos, NULL, 0 },
+    { "clip", SYM_FUNC , 1, func_int_clip, NULL, 0 },
+    { "pow",  SYM_FUNC , 2, func_pow, NULL, 0 },
+
+    { "pi",   SYM_CONST, 0, NULL, NULL, DM_PI },
+    { "e",    SYM_CONST, 0, NULL, NULL, DM_E },
+};
+
+static const int ndmEvalBasicFuncs = sizeof(dmEvalBasicFuncs) / sizeof(dmEvalBasicFuncs[0]);
+
+
+void dmEvalErrorV(DMEvalContext *ev, const char *fmt, va_list ap)
+{
+    char *tmp = dm_strdup_vprintf(fmt, ap);
+    
+    ev->err = TRUE;
+
+    if (ev->errStr != NULL)
+    {
+        ev->errStr = dm_strdup_printf("%s%s", ev->errStr, tmp);
+        dmFree(tmp);
+    }
+    else
+        ev->errStr = tmp;
+}
+
+
+void dmEvalError(DMEvalContext *ev, const char *fmt, ...)
+{
+    va_list ap;
+    va_start(ap, fmt);
+    dmEvalErrorV(ev, fmt, ap);
+    va_end(ap);
+}
+
+
+DMEvalSymbol *dmEvalContextFindSymbol(DMEvalContext *ev, const char *name)
+{
+    int i;
+    if (ev->symbols == NULL)
+        return NULL;
+
+    for (i = 0; i < ev->nsymbols; i++)
+    {
+        if (strcmp(ev->symbols[i].name, name) == 0)
+            return &(ev->symbols[i]);
+    }
+    
+    return NULL;
+}
+
+
+// Add a new symbol to the evaluation context.
+// Return pointer to newly allocated symbol struct if successful.
+// If the symbol already exists or there was a memory allocation
+// error, NULL is returned.
+static DMEvalSymbol * dmEvalContextAddSymbol(DMEvalContext *ev, const char *name, const int type)
+{
+    DMEvalSymbol *symbol = dmEvalContextFindSymbol(ev, name);
+    if (symbol != NULL)
+        return NULL;
+
+    ev->symbols = dmRealloc(ev->symbols, sizeof(DMEvalSymbol) * (ev->nsymbols + 1));
+    if (ev->symbols == NULL)
+    {
+        dmEvalError(ev,
+            "Could not reallocate eval symbols array (#%d). Fatal error.\n",
+            ev->nsymbols + 1);
+        return NULL;
+    }
+    
+    symbol = &(ev->symbols[ev->nsymbols]);
+    ev->nsymbols++;
+
+    memset(symbol, 0, sizeof(DMEvalSymbol));
+    symbol->name = dm_strdup(name);
+    symbol->type = type;
+
+    return symbol;
+}
+
+
+DMEvalSymbol *dmEvalContextAddVar(DMEvalContext *ev, const char *name, DMValue *var)
+{
+    DMEvalSymbol *symbol = dmEvalContextAddSymbol(ev, name, SYM_VAR);
+    if (symbol == NULL)
+        return NULL;
+    
+    symbol->var = var;
+    return symbol;
+}
+
+
+DMEvalSymbol *dmEvalContextAddConst(DMEvalContext *ev, const char *name, DMValue value)
+{
+    DMEvalSymbol *symbol = dmEvalContextAddSymbol(ev, name, SYM_CONST);
+    if (symbol == NULL)
+        return NULL;
+    
+    symbol->cvalue = value;
+    return symbol;
+}
+
+
+DMEvalSymbol *dmEvalContextAddFunc(DMEvalContext *ev, const char *name, DMValue (*func)(DMValue *), int nargs)
+{
+    DMEvalSymbol *symbol = dmEvalContextAddSymbol(ev, name, SYM_VAR);
+    if (symbol == NULL)
+        return NULL;
+    
+    symbol->func  = func;
+    symbol->nargs = nargs;
+
+    return DMERR_OK;
+}
+
+
+DMEvalContext *dmEvalContextNew(void)
+{
+    int i;
+    DMEvalContext *ev = dmCalloc(1, sizeof(DMEvalContext));
+
+    if (ev == NULL)
+        return NULL;
+
+    for (i = 0; i < ndmEvalBasicFuncs; i++)
+    {
+        const DMEvalSymbol *symbol= &dmEvalBasicFuncs[i];
+        DMEvalSymbol *nsymbol = dmEvalContextAddSymbol(ev, symbol->name, symbol->type);
+        if (nsymbol != NULL)
+        {
+            nsymbol->nargs    = symbol->nargs;
+            nsymbol->func     = symbol->func;
+            nsymbol->var      = symbol->var;
+            nsymbol->cvalue   = symbol->cvalue;
+        }
+    }
+
+    return ev;
+}
+
+
+void dmEvalTreeFree(DMEvalNode *node)
+{
+    while (node != NULL)
+    {
+        DMEvalNode *next = node->next;
+        int i;
+
+        for (i = 0; i < DM_MAX_ARGS; i++)
+        {
+            dmEvalTreeFree(node->args[i]);
+            node->args[i] = NULL;
+        }
+
+        dmEvalTreeFree(node->subexpr);
+        node->subexpr = NULL;
+        dmFree(node);
+        node = next;
+    }
+}
+
+
+void dmEvalContextClear(DMEvalContext *ev)
+{
+    if (ev == NULL)
+        return;
+    
+    dmFree(ev->errStr);
+    ev->err = FALSE;
+    ev->errStr = NULL;
+}
+
+
+void dmEvalContextClose(DMEvalContext *ev)
+{
+    int i;
+
+    if (ev == NULL)
+        return;
+
+    for (i = 0; i < ev->nsymbols; i++)
+        dmFree(ev->symbols[i].name);
+
+    dmFree(ev->symbols);
+    dmEvalContextClear(ev);
+    dmFree(ev);
+}
+
+
+static DMEvalNode *dmEvalInsertNode(DMEvalNode **list, DMEvalNode *node)
+{
+    if (*list != NULL)
+    {
+        node->prev = (*list)->prev;
+        (*list)->prev->next = node;
+        (*list)->prev = node;
+    }
+    else
+    {
+        *list = node;
+        node->prev = *list;
+    }
+
+    node->next = NULL;
+    return node;
+}
+
+
+static DMEvalNode *dmEvalAddNode(DMEvalNode **list, const int op)
+{
+    DMEvalNode *node = dmCalloc(1, sizeof(DMEvalNode));
+    if (node == NULL)
+        return NULL;
+
+    node->op = op;
+
+    return dmEvalInsertNode(list, node);
+}
+
+
+enum
+{
+    PARSE_NONE          = 0x0000,
+    PARSE_START         = 0x1000,
+    PARSE_END           = 0x2000,
+    PARSE_ERROR         = 0x8000,
+
+    PARSE_IDENT         = 0x0001, // Any identifier (variable, function name)
+    PARSE_CONST         = 0x0002, // Constant value (n, n.nnn, etc)
+    PARSE_OPER          = 0x0004, // All operators
+    PARSE_OPER_UNARY    = 0x0008, // Unary operators ~, -
+    PARSE_SUBEXPR_START = 0x0010, // ( ...
+    PARSE_SUBEXPR_END   = 0x0020, // )
+    PARSE_ARGS          = 0x0040, // function args: (xxx[, yyy ...])
+
+    PARSE_NORMAL        = PARSE_CONST | PARSE_IDENT | PARSE_SUBEXPR_START | PARSE_OPER_UNARY,
+};
+
+#define DM_CHECK(x) { if (mode & PARSE_ ## x ) { if (str[0]) strcat(str, " or "); strcat(str, # x ); } }
+
+static char *dmEvalGetMode(int mode)
+{
+    char str[128] = "";
+
+    DM_CHECK(START);
+    DM_CHECK(END);
+    DM_CHECK(IDENT);
+    DM_CHECK(CONST);
+    DM_CHECK(OPER);
+    DM_CHECK(OPER_UNARY);
+    DM_CHECK(SUBEXPR_START);
+    DM_CHECK(SUBEXPR_END);
+    DM_CHECK(ARGS);
+            
+    return dm_strdup(str);
+}
+
+
+static void dmEvalSetMode(DMEvalContext *ev, const int mode)
+{
+    if (mode != PARSE_ERROR &&
+        mode != PARSE_START &&
+        ev->expect != PARSE_NONE &&
+        (mode & ev->expect) == 0)
+    {
+        char *tmp1 = dmEvalGetMode(ev->expect),
+             *tmp2 = dmEvalGetMode(mode);
+
+        dmEvalError(ev, "Expected [%s], got %s.\n", tmp1, tmp2);
+        dmFree(tmp1);
+        dmFree(tmp2);
+    }
+
+    ev->prev = ev->mode;
+    ev->mode = mode;
+}
+
+
+static BOOL dmEvalTokenizeExpr(DMEvalContext *ev, DMEvalNode **list, char **str, int depth)
+{
+    char *c = *str;
+    char tmpStr[DM_MAX_BUF + 2], *tmp;
+    int tmpStrLen = 0, argIndex, op;
+    DMEvalNode *node = NULL, *func = NULL;
+    BOOL first = FALSE, decimal = FALSE;
+
+    ev->expect = PARSE_NORMAL;
+    ev->mode = PARSE_START;
+    
+    while (ev->mode != PARSE_ERROR && ev->mode != PARSE_END)
+    switch (ev->mode)
+    {
+        case PARSE_START:
+            // Start
+            if (*c == 0)
+                dmEvalSetMode(ev, PARSE_END);
+
+            // Skip whitespace
+            else if (isspace(*c))
+                c++;
+
+            else if (*c == ')' || *c == ',')
+            {
+                if (depth > 0)
+                    dmEvalSetMode(ev, PARSE_END);
+                else
+                {
+                    dmEvalError(ev, "Invalid nesting near '%s' (depth %d).\n", c, depth);
+                    dmEvalSetMode(ev, PARSE_ERROR);
+                }
+                c++;
+            }
+            
+            else if (*c == '(')
+                dmEvalSetMode(ev, func != NULL ? PARSE_ARGS : PARSE_SUBEXPR_START);
+            
+            else if (*c == '-')
+                dmEvalSetMode(ev, (ev->prev == PARSE_START || ev->prev == PARSE_OPER || ev->prev == PARSE_OPER_UNARY) ? PARSE_OPER_UNARY : PARSE_OPER);
+            
+            else if (*c == '~')
+                dmEvalSetMode(ev, PARSE_OPER_UNARY);
+            
+            else if (strchr("+*/<>%&|!^", *c))
+                dmEvalSetMode(ev, PARSE_OPER);
+
+            else if (isdigit(*c) || *c == '.')
+                dmEvalSetMode(ev, PARSE_CONST);
+
+            else if (isalpha(*c) || *c == '_')
+                dmEvalSetMode(ev, PARSE_IDENT);
+            
+            else
+            {
+                dmEvalError(ev, "Syntax error near '%s' (depth %d).\n", c, depth);
+                dmEvalSetMode(ev, PARSE_ERROR);
+            }
+
+            first = TRUE;
+            break;
+        
+        case PARSE_SUBEXPR_START:
+            tmp = c + 1;
+
+            ev->expect = PARSE_NORMAL;
+
+            if ((node = dmEvalAddNode(list, OP_SUBEXPR)) == NULL)
+                dmEvalSetMode(ev, PARSE_ERROR);
+            else
+            if (dmEvalTokenizeExpr(ev, &(node->subexpr), &tmp, depth + 1) != 0)
+            {
+                dmEvalError(ev, "Subexpression starting at '%s' contained errors.\n", c);
+                dmEvalSetMode(ev, PARSE_ERROR);
+            }
+
+            if (ev->mode != PARSE_ERROR)
+            {
+                dmEvalSetMode(ev, PARSE_START);
+                ev->expect = PARSE_OPER | PARSE_SUBEXPR_END;
+                c = tmp;
+            }
+            break;
+
+        case PARSE_ARGS:
+            tmp = c + 1;
+            
+            for (argIndex = 0; argIndex < func->symbol->nargs; argIndex++)
+            {
+                if (dmEvalTokenizeExpr(ev, &(func->args[argIndex]), &tmp, depth + 1) != 0)
+                {
+                    dmEvalError(ev, "Function argument subexpression starting at '%s' contained errors.\n", c);
+                    dmEvalSetMode(ev, PARSE_ERROR);
+                }
+            }
+
+            func = NULL;
+
+            if (ev->mode != PARSE_ERROR)
+            {
+                dmEvalSetMode(ev, PARSE_START);
+                ev->expect = PARSE_OPER | PARSE_END;
+                c = tmp;
+            }
+            break;
+
+        case PARSE_CONST:
+            if (first)
+            {
+                first = FALSE;
+                decimal = FALSE;
+                tmpStrLen = 0;
+                
+                if (isdigit(*c) || *c == '-' || *c == '+' || *c == '.')
+                {
+                    if (*c == '.')
+                        decimal = TRUE;
+                    tmpStr[tmpStrLen++] = *c++;
+                }
+                else
+                {
+                    dmEvalError(ev, "Invalid constant expression near '%s'.\n", c);
+                    dmEvalSetMode(ev, PARSE_ERROR);
+                }
+            }
+            else
+            {
+                if (isdigit(*c))
+                {
+                    tmpStr[tmpStrLen++] = *c++;
+                }
+                else
+                if (*c == '.')
+                {
+                    if (!decimal)
+                    {
+                        tmpStr[tmpStrLen++] = *c++;
+                        decimal = TRUE;
+                    }
+                    else
+                    {
+                        dmEvalError(ev, "Invalid constant expression near '%s'.\n", c);
+                        dmEvalSetMode(ev, PARSE_ERROR);
+                    }
+                }
+                else
+                {
+                    tmpStr[tmpStrLen] = 0;
+
+                    if ((node = dmEvalAddNode(list, OP_VALUE)) == NULL)
+                    {
+                        dmEvalSetMode(ev, PARSE_ERROR);
+                    }
+                    else
+                    {
+                        node->val = atof(tmpStr);
+                        dmEvalSetMode(ev, PARSE_START);
+                        ev->expect = PARSE_OPER | PARSE_END;
+                    }
+                }
+            }
+            break;
+
+        case PARSE_OPER_UNARY:
+            {
+                int op = OP_INVALID;
+
+                switch (*c)
+                {
+                    case '-': op = OP_SUB_UNARY; c++; break;
+                    case '~': op = OP_BIT_COMPLEMENT; c++; break;
+                }
+
+                if (op != OP_INVALID)
+                {
+                    if ((node = dmEvalAddNode(list, op)) != NULL)
+                    {
+                        ev->expect = PARSE_NORMAL;
+                        dmEvalSetMode(ev, PARSE_START);
+                    }
+                    else
+                        dmEvalSetMode(ev, PARSE_ERROR);
+                }
+            }
+            break;
+
+        case PARSE_OPER:
+            op = OP_INVALID;
+
+            switch (*c)
+            {
+                case '+': op = OP_ADD; c++; break;
+                case '-': op = OP_SUB; c++; break;
+                case '*': op = OP_MUL; c++; break;
+                case '/': op = OP_DIV; c++; break;
+                case '%': op = OP_MOD; c++; break;
+                case '&': op = OP_BIT_AND; c++; break;
+                case '^': op = OP_BIT_XOR; c++; break;
+                case '|': op = OP_BIT_OR; c++; break;
+
+                case '>':
+                    if (c[1] == '>')
+                    {
+                        c += 2;
+                        op = OP_BIT_RSHIFT;
+                    }
+                    else
+                    {
+                        op = (c[1] == '=') ? OP_GT_EQ : OP_GT;
+                        c++;
+                    }
+                    break;
+                    
+                case '<':
+                    if (c[1] == '<')
+                    {
+                        c += 2;
+                        op = OP_BIT_LSHIFT;
+                    }
+                    else
+                    {
+                        op = (c[1] == '=') ? OP_LT_EQ : OP_LT;
+                        c++;
+                    }
+                    break;
+
+                default:
+                    dmEvalError(ev, "Unknown operator '%c' at %s\n", *c, c);
+                    dmEvalSetMode(ev, PARSE_ERROR);
+            }
+
+            if (op != OP_INVALID)
+            {
+                if ((node = dmEvalAddNode(list, op)) != NULL)
+                {
+                    ev->expect = PARSE_NORMAL | PARSE_OPER_UNARY;
+                    dmEvalSetMode(ev, PARSE_START);
+                }
+                else
+                    dmEvalSetMode(ev, PARSE_ERROR);
+            }
+            break;
+
+        case PARSE_IDENT:
+            if (isalnum(*c) || *c == '_')
+            {
+                if (first)
+                {
+                    tmpStrLen = 0;
+                    first = FALSE;
+                }
+
+                if (tmpStrLen < DM_MAX_BUF)
+                    tmpStr[tmpStrLen++] = *c++;
+                else
+                {
+                    tmpStr[tmpStrLen] = 0;
+                    dmEvalError(ev, "Identifier too long! ('%s') near %s\n", tmpStr, c);
+                }
+            }
+            else
+            {
+                tmpStr[tmpStrLen] = 0;
+                DMEvalSymbol *symbol = dmEvalContextFindSymbol(ev, tmpStr);
+                if (symbol != NULL)
+                {
+                    if ((node = dmEvalAddNode(list, symbol->type == SYM_FUNC ? OP_FUNC : OP_VAR)) != NULL)
+                    {
+                        node->symbol = symbol;
+                        if (symbol->type == SYM_FUNC)
+                        {
+                            func = node;
+                            ev->expect = PARSE_ARGS;
+                        }
+                        else
+                            ev->expect = PARSE_END | PARSE_OPER;
+
+                        dmEvalSetMode(ev, PARSE_START);
+                    }
+                    else
+                        dmEvalSetMode(ev, PARSE_ERROR);
+                }
+                else
+                {
+                    dmEvalError(ev, "No such identifier '%s'.\n", tmpStr);
+                    dmEvalSetMode(ev, PARSE_ERROR);
+                }
+            }
+            break;
+    }
+
+    *str = c;
+
+    return (ev->mode == PARSE_ERROR);
+}
+
+
+int dmEvalParseExpr(DMEvalContext *ev, char *expr, DMEvalNode **result)
+{
+    int ret;
+
+    if (ev == NULL || result == NULL)
+        return DMERR_NULLPTR;
+
+    ev->prev = PARSE_START;
+    ret = dmEvalTokenizeExpr(ev, result, &expr, 0);
+    
+    return ret;
+}
+
+
+
+
+BOOL dmEvalTreeExecute(DMEvalContext *ev, DMEvalNode *node, DMValue *presult)
+{
+    DMValue val1, val2;
+
+    if (node == NULL)
+        return FALSE;
+
+    switch (node->op)
+    {
+        case OP_VAR:
+            switch (node->symbol->type)
+            {
+                case SYM_CONST: *presult = node->symbol->cvalue; return TRUE;
+                case SYM_VAR  : *presult = *(node->symbol->var); return TRUE;
+            }
+            return FALSE;
+
+        case OP_VALUE:
+            *presult = node->val;
+            return TRUE;
+        
+        case OP_FUNC:
+            
+            return TRUE;
+        
+        case OP_SUBEXPR:
+            return dmEvalTreeExecute(ev, node->subexpr, presult);
+    
+        // Binary operators
+        case OP_BIT_LSHIFT:
+        case OP_BIT_RSHIFT:
+        
+        case OP_BIT_AND:
+        case OP_BIT_XOR:
+        case OP_BIT_OR:
+
+        case OP_ADD:
+        case OP_SUB:
+        case OP_MUL:
+        case OP_DIV:
+        case OP_MOD:
+            if (!dmEvalTreeExecute(ev, node->left, &val1) ||
+                !dmEvalTreeExecute(ev, node->right, &val2))
+                return FALSE;
+
+            switch (node->op)
+            {
+                case OP_DIV:
+                    if (val2 == 0)
+                    {
+                        dmEvalError(ev, "Division by zero.\n");
+                        return FALSE;
+                    }
+                    *presult = val1 / val2;
+                    break;
+
+
+                case OP_MOD:
+                    if (val2 == 0)
+                    {
+                        dmEvalError(ev, "Division by zero.\n");
+                        return FALSE;
+                    }
+                    *presult = DMCONVTYPE val1 % DMCONVTYPE val2;
+                    break;
+
+                case OP_BIT_LSHIFT:
+                    if (val2 > 31)
+                        dmEvalError(ev, "Left shift count >= width of type (%d << %d)\n", val1, val2);
+                    *presult = DMCONVTYPE val1 << DMCONVTYPE val2; break;
+
+                case OP_BIT_RSHIFT:
+                    if (val2 > 31)
+                        dmEvalError(ev, "Right shift count >= width of type (%d >> %d)\n", val1, val2);
+                    *presult = DMCONVTYPE val1 >> DMCONVTYPE val2; break;
+
+                case OP_MUL     : *presult = val1 * val2; break;
+                case OP_ADD     : *presult = val1 + val2; break;
+                case OP_SUB     : *presult = val1 - val2; break;
+                case OP_BIT_AND : *presult = DMCONVTYPE val1 & DMCONVTYPE val2; break;
+                case OP_BIT_OR  : *presult = DMCONVTYPE val1 | DMCONVTYPE val2; break;
+                case OP_BIT_XOR : *presult = DMCONVTYPE val1 ^ DMCONVTYPE val2; break;
+            }
+            return TRUE;
+
+        // Unary operators
+        case OP_SUB_UNARY:
+        case OP_BIT_COMPLEMENT:
+/*
+            switch (node->op)
+            {
+                case OP_SUB_UNARY: *presult -= tmp; break;
+                case OP_BIT_COMPLEMENT: *presult = DMCONVTYPE ~(DMCONVTYPE tmp); break;
+            }
+*/
+            return TRUE;
+
+        default:
+            dmEvalError(ev, "Invalid opcode %d in node %p.\n", node->op, node);
+            return FALSE;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmeval.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,136 @@
+#ifndef DMEVAL_H
+#define DMEVAL_H
+
+#include "dmlib.h"
+#include <stdio.h>
+
+
+typedef double DMValue;
+#define DMCONVTYPE       (int)
+#define DM_MAX_ARGS      8
+
+
+enum
+{
+    OP_SUB_UNARY,
+    OP_BIT_COMPLEMENT,
+
+    OP_ADD,
+    OP_SUB,
+    OP_MUL,
+    OP_DIV,
+    OP_MOD,
+
+    OP_BIT_LSHIFT,
+    OP_BIT_RSHIFT,
+
+    OP_BIT_AND,
+    OP_BIT_OR,
+    OP_BIT_XOR,
+
+    OP_GT_EQ,
+    OP_LT_EQ,
+    OP_GT,
+    OP_LT,
+
+    // Special ops
+    OP_FUNC,
+    OP_VAR,
+    OP_VALUE,
+    OP_SUBEXPR,
+
+    // Total number of operators
+    OP_NOPERS,
+
+    OP_INVALID
+} DMEvalOperId;
+
+
+enum
+{
+    OT_NONE,
+
+    OT_LEFT,      // Left-associative
+    OT_RIGHT,     // Right-associative
+    OT_UNARY,
+} DMEvalOperAssoc;
+
+
+typedef struct
+{
+    char *name;     // Token
+    int   assoc;    // Associativity type (DMEvalOperAssoc)
+    BOOL  tokenize; // Automatically tokenize?
+} DMEvalOper;
+
+
+enum
+{
+    SYM_FUNC,
+    SYM_VAR,
+    SYM_CONST,
+} DMEvalSymbolType;
+
+
+typedef struct
+{
+    char *name;     // Name of the symbol
+    int type;       // Type (SYM_*)
+    int nargs;      // Number of arguments, if SYM_FUNC
+
+    DMValue (*func)(DMValue arg[DM_MAX_ARGS]);
+
+    DMValue *var;   // Pointer to variable value if SYM_VAR
+    DMValue cvalue; // Const value, if SYM_CVAR
+} DMEvalSymbol;
+
+
+typedef struct DMEvalNode
+{
+    int op;               // Operator/token type
+    DMValue val;          // Value, if immediate constant 
+    DMEvalSymbol *symbol; // Symbol pointer, if function/variable/constvar
+
+    struct DMEvalNode *args[DM_MAX_ARGS]; // Arguments, if function
+
+    struct DMEvalNode *subexpr, *left, *right, *next, *prev;
+} DMEvalNode;
+
+
+typedef struct
+{
+    BOOL err;
+    char *errStr;
+    
+    int nsymbols;
+    DMEvalSymbol *symbols;
+
+    int mode, prev, expect;
+} DMEvalContext;
+
+
+// Evaluation context management
+DMEvalContext * dmEvalContextNew(void);
+void            dmEvalContextClose(DMEvalContext *ev);
+void            dmEvalContextClear(DMEvalContext *ev);
+
+
+// Symbol management
+DMEvalSymbol *  dmEvalContextFindSymbol(DMEvalContext *ev, const char *name);
+DMEvalSymbol *  dmEvalContextAddVar(DMEvalContext *ev, const char *name, DMValue *var);
+DMEvalSymbol *  dmEvalContextAddConst(DMEvalContext *ev, const char *name, DMValue value);
+DMEvalSymbol *  dmEvalContextAddFunc(DMEvalContext *ev, const char *name, DMValue (*func)(DMValue *), int nargs);
+
+
+// Evaluation trees, tokenization, parsing
+int   dmEvalParseExpr(DMEvalContext *ev, char *expr, DMEvalNode **plist);
+int   dmEvalTreeExecute(DMEvalContext *ev, DMEvalNode *tree, DMValue *presult);
+void  dmEvalTreeFree(DMEvalNode *node);
+
+
+void dmEvalPrintOpTree(FILE *out, DMEvalContext *ev, DMEvalNode *node);
+
+
+extern const DMEvalOper dmEvalOpers[OP_NOPERS];
+
+#endif // DMEVAL_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmevalw.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,55 @@
+#include "dmeval.h"
+
+
+void dmDoEvalPrintOpTree(FILE *out, DMEvalContext *ev, DMEvalNode *node, int level)
+{
+    int i;
+    while (node != NULL)
+    {
+        switch (node->op)
+        {
+            case OP_FUNC:
+                fprintf(out, "%s(", node->symbol != NULL ? node->symbol->name : "?ERROR");
+                for (i = 0; i < node->symbol->nargs; i++)
+                {
+                    dmDoEvalPrintOpTree(out, ev, node->args[i], level + 1);
+                    if (i < node->symbol->nargs - 1)
+                        fprintf(out, ",");
+                }
+                fprintf(out, ")");
+                break;
+
+            case OP_VAR:
+                fprintf(out, "%s", node->symbol != NULL ? node->symbol->name : "?ERROR");
+                break;
+
+            case OP_VALUE:
+                fprintf(out, "%.1f", node->val);
+                break;
+
+            case OP_SUBEXPR:
+                fprintf(out, "(");
+                if (node->subexpr != NULL)
+                    dmDoEvalPrintOpTree(out, ev, node->subexpr, level + 1);
+                else
+                    fprintf(out, "?ERROR");
+                fprintf(out, ")");
+                break;
+
+            default:
+                if (node->op >= 0 && node->op < OP_NOPERS)
+                    fprintf(out, "%s", dmEvalOpers[node->op].name);
+                else
+                    fprintf(out, "ERROR!");
+                break;
+        }
+        node = node->next;
+    }
+}
+
+
+void dmEvalPrintOpTree(FILE *out, DMEvalContext *ev, DMEvalNode *node)
+{
+    dmDoEvalPrintOpTree(out, ev, node, 0);
+    fprintf(out, "\n");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmfft.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,258 @@
+/*
+ * Realfftf
+ * Originally (C) Copyright 1993 Philib Van Baren
+ * Cleaned up and refactored to be re-entrant by
+ *     Matti 'ccr' Hamalainen <ccr@tnsp.org>, 2013
+ *
+ * Note: Output is BIT-REVERSED! so you must use the BitReversed to
+ *       get legible output, (i.e. Real_i = buffer[ BitReversed[i] ]
+ *                                 Imag_i = buffer[ BitReversed[i]+1 ] )
+ *       Input is in normal order.
+ */
+#include "dmfft.h"
+#include <math.h>
+
+
+int dmInitializeFFT(DMFFTContext * ctx, const int fftlen)
+{
+    int i;
+
+    if (ctx == NULL)
+        return DMERR_NULLPTR;
+
+    if (fftlen <= 16)
+        return DMERR_INVALID_ARGS;
+
+    // Allocate necessary tables
+    ctx->npoints = fftlen / 2;
+    ctx->sinTable = (DMFFTType *) dmMalloc(fftlen * sizeof(DMFFTType));
+    if (ctx->sinTable == NULL)
+        return DMERR_MALLOC;
+
+    // Bitreversion buffer
+    ctx->breversed = (int *) dmMalloc(ctx->npoints * sizeof(int));
+    if (ctx->breversed == NULL)
+    {
+        dmFree(ctx->sinTable);
+        return DMERR_MALLOC;
+    }
+
+    // Calculate data
+    for (i = 0; i < ctx->npoints; i++)
+    {
+        int mask, tmp;
+        for (tmp = 0, mask = ctx->npoints / 2; mask > 0; mask >>= 1)
+        {
+            tmp = (tmp >> 1) + ((i & mask) ? ctx->npoints : 0);
+        }
+
+        ctx->breversed[i] = tmp;
+    }
+
+    for (i = 0; i < ctx->npoints; i++)
+    {
+        ctx->sinTable[ctx->breversed[i]] = -sin((2.0f * DM_PI * i) / fftlen);
+        ctx->sinTable[ctx->breversed[i] + 1] =
+            -cos((2.0f * DM_PI * i) / fftlen);
+    }
+
+    return DMERR_OK;
+}
+
+
+void dmEndFFT(DMFFTContext * ctx)
+{
+    if (ctx != NULL)
+    {
+        dmFree(ctx->breversed);
+        dmFree(ctx->sinTable);
+        memset(ctx, 0, sizeof(DMFFTContext));
+    }
+}
+
+
+int dmRealFFT(DMFFTContext * ctx, DMFFTType * buffer)
+{
+    if (ctx == NULL || buffer == NULL)
+        return DMERR_NULLPTR;
+
+    int rounds = ctx->npoints / 2;
+    DMFFTType *endptr1 = buffer + ctx->npoints * 2;
+
+    while (rounds > 0)
+    {
+        DMFFTType *sptr = ctx->sinTable;
+        DMFFTType *A = buffer,
+                  *B = buffer + rounds * 2;
+
+        while (A < endptr1)
+        {
+            DMFFTType qsin = *sptr;
+            DMFFTType qcos = *(sptr + 1);
+            DMFFTType *endptr2 = B;
+
+            while (A < endptr2)
+            {
+                DMFFTType v1 = (*B) * qcos + (*(B + 1)) * qsin;
+                DMFFTType v2 = (*B) * qsin - (*(B + 1)) * qcos;
+                *B = (*A + v1) * 0.5;
+                *(A++) = *(B++) - v1;
+                *B = (*A - v2) * 0.5;
+                *(A++) = *(B++) + v2;
+            }
+            A = B;
+            B += rounds * 2;
+            sptr += 2;
+        }
+
+        rounds >>= 1;
+    }
+
+    /*
+     *  Massage output to get the output for a real input sequence.
+     */
+    const int *br1 = ctx->breversed + 1;
+    const int *br2 = ctx->breversed + ctx->npoints - 1;
+
+    while (br1 <= br2)
+    {
+        const DMFFTType vsin = ctx->sinTable[*br1];
+        const DMFFTType vcos = ctx->sinTable[*br1 + 1];
+        DMFFTType *A = buffer + *br1,
+                  *B = buffer + *br2,
+                  HRplus, HRminus,
+                  HIplus, HIminus,
+                  tmp1, tmp2;
+
+        HRminus  = *A - *B;
+        HRplus   = HRminus + (*B * 2);
+
+        HIminus  = *(A + 1) - *(B + 1);
+        HIplus   = HIminus + (*(B + 1) * 2);
+
+        tmp1     = (vsin * HRminus) - (vcos * HIplus);
+        tmp2     = (vcos * HRminus) + (vsin * HIplus);
+
+        *A       = (HRplus + tmp1) * 0.5f;
+        *B       = *A - tmp1;
+
+        *(A + 1) = (HIminus + tmp2) * 0.5f;
+        *(B + 1) = (*(A + 1)) - HIminus;
+
+        br1++;
+        br2--;
+    }
+
+    // Handle DC bin separately
+    buffer[0] += buffer[1];
+    buffer[1] = 0;
+
+    return DMERR_OK;
+}
+
+
+int dmConvertFFTtoFreqDomain(DMFFTContext *ctx, DMFFTType *buffer,
+    DMFFTType *real, DMFFTType *imag)
+{
+    int i;
+    if (ctx == NULL || buffer == NULL || real == NULL || imag == NULL)
+        return DMERR_NULLPTR;
+
+    // Convert from bitreversed form to normal frequency domain
+    const int *breversed = ctx->breversed;
+
+    for (i = 1; i < ctx->npoints; i++)
+    {
+        real[i] = buffer[breversed[i]  ];
+        imag[i] = buffer[breversed[i]+1];
+    }
+
+    // Make the ends meet
+    real[0]            = buffer[0];
+    imag[0]            = 0;
+    real[ctx->npoints] = buffer[1];
+    imag[ctx->npoints] = 0;
+
+    return DMERR_OK;
+}
+
+
+#define DM_PW(a, b, c) sqrt(a * a + b * b) * c
+
+
+int dmConvertFFTtoFreqAndPower(DMFFTContext *ctx, DMFFTType *buffer,
+    DMFFTType *real, DMFFTType *imag, DMFFTType *power, const DMFFTType scale)
+{
+    int i;
+    if (ctx == NULL || buffer == NULL || real == NULL || imag == NULL || power == NULL)
+        return DMERR_NULLPTR;
+
+    // Convert from bitreversed form to normal frequency domain
+    const int *breversed = ctx->breversed;
+
+    for (i = 1; i < ctx->npoints; i++)
+    {
+        DMFFTType fre = real[i] = buffer[breversed[i]  ],
+                  fim = imag[i] = buffer[breversed[i]+1];
+
+        power[i] = DM_PW(fre, fim, scale);
+    }
+
+    // Make the ends meet
+    real[0]             = buffer[0];
+    imag[0]             = 0;
+    power[0]            = DM_PW(buffer[0], 0, scale);
+    
+    real[ctx->npoints]  = buffer[1];
+    imag[ctx->npoints]  = 0;
+    power[ctx->npoints] = DM_PW(buffer[1], 0, scale);
+
+    return DMERR_OK;
+}
+
+
+int dmConvertFFTtoPowerAndSum(DMFFTContext *ctx, DMFFTType *buffer,
+    DMFFTType *power, const DMFFTType pscale, DMFFTType *sum, const DMFFTType sscale)
+{
+    int i;
+    if (ctx == NULL || buffer == NULL || power == NULL || sum == NULL)
+        return DMERR_NULLPTR;
+
+    // Convert from bitreversed form to normal frequency domain
+    const int *breversed = ctx->breversed;
+    DMFFTType psum = 0;
+
+    for (i = 1; i < ctx->npoints; i++)
+    {
+        DMFFTType fre = buffer[breversed[i]  ],
+                  fim = buffer[breversed[i]+1],
+                  fpw = sqrt(fre * fre + fim * fim);
+
+        power[i]  = fpw * pscale;
+        psum     += fpw * sscale;
+    }
+
+    // Make the ends meet
+    power[0]            = DM_PW(buffer[0], 0, pscale);
+    power[ctx->npoints] = DM_PW(buffer[1], 0, pscale);
+
+    *sum = psum;
+
+    return DMERR_OK;
+}
+
+
+int dmConvertFFTtoTimeDomain(DMFFTContext *ctx, DMFFTType *buffer, DMFFTType *tdom)
+{
+    int i, n;
+    if (ctx == NULL || buffer == NULL || tdom == NULL)
+        return DMERR_NULLPTR;
+
+    for (n = i = 0; i < ctx->npoints; i++, n += 2)
+    {
+        tdom[n  ] = buffer[ctx->breversed[i]  ];
+        tdom[n+1] = buffer[ctx->breversed[i]+1];
+    }
+
+    return DMERR_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmfft.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,34 @@
+#ifndef DMFFT_H
+#define DMFFT_H 1
+
+#include "dmlib.h"
+
+
+typedef double DMFFTType;
+
+
+typedef struct
+{
+    int npoints;
+    DMFFTType *sinTable;
+    int *breversed;
+} DMFFTContext;
+
+
+int   dmInitializeFFT(DMFFTContext *, int);
+void  dmEndFFT(DMFFTContext *);
+int   dmRealFFT(DMFFTContext *, DMFFTType *);
+
+int   dmConvertFFTtoFreqDomain(DMFFTContext *ctx, DMFFTType *buffer,
+      DMFFTType *real, DMFFTType *imag);
+
+int   dmConvertFFTtoFreqAndPower(DMFFTContext *ctx, DMFFTType *buffer,
+      DMFFTType *real, DMFFTType *imag, DMFFTType *power, const DMFFTType scale);
+
+int   dmConvertFFTtoPowerAndSum(DMFFTContext *ctx, DMFFTType *buffer,
+      DMFFTType *power, const DMFFTType pscale, DMFFTType *sum, const DMFFTType sscale);
+
+int   dmConvertFFTtoTimeDomain(DMFFTContext *ctx, DMFFTType *buffer, DMFFTType *tdom);
+
+
+#endif // DMFFT_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmfile.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,130 @@
+/*
+ * DMLib
+ * -- Standard I/O (stdio) file write/read endianess helpers
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2011 Tecnic Software productions (TNSP)
+ */
+#include "dmfile.h"
+
+
+BOOL dm_fread_str(FILE *f, void *buf, const size_t len)
+{
+    return fread(buf, len, 1, f) == 1;
+}
+
+
+BOOL dm_fread_byte(FILE *f, Uint8 *val)
+{
+    int tmp = fgetc(f);
+    *val = tmp;
+    return tmp != EOF;
+}
+
+
+#define DM_DEFINE_FFUNC(xname, xtype, xmacro)         \
+BOOL dm_fread_ ## xname (FILE *f, xtype *v) {         \
+    xtype result;                                     \
+    if (fread(&result, sizeof( xtype ), 1, f) != 1)   \
+        return FALSE;                                 \
+    *v = DM_ ## xmacro ## _TO_NATIVE (result);        \
+    return TRUE;                                      \
+}
+
+#include "dmfiletmpl.h"
+
+
+#undef DM_DEFINE_FFUNC
+
+
+BOOL dm_fwrite_str(FILE *f, const void *buf, const size_t len)
+{
+    return fwrite(buf, len, 1, f) == 1;
+}
+
+
+BOOL dm_fwrite_byte(FILE *f, const Uint8 val)
+{
+    return fputc(val, f) == val;
+}
+
+
+#define DM_DEFINE_FFUNC(xname, xtype, xmacro)         \
+BOOL dm_fwrite_ ## xname (FILE *f, const xtype v) {   \
+    xtype result = DM_NATIVE_TO_ ## xmacro (v);       \
+    return fwrite(&result, sizeof( xtype ), 1, f) == 1;  \
+}
+
+#include "dmfiletmpl.h"
+
+#undef DM_DEFINE_FFUNC
+
+
+#define BUF_SIZE_INITIAL   (16*1024)
+#define BUF_SIZE_GROW      (4*1024)
+
+int dmReadDataFile(FILE *inFile, const char *filename, Uint8 **pbuf, size_t *pbufSize)
+{
+    FILE *f;
+    int res = DMERR_OK;
+    Uint8 *dataBuf = NULL;
+    size_t readSize, dataSize, dataRead, dataPos;
+    
+    if (inFile != NULL)
+        f = inFile;
+    else
+    if (filename != NULL)
+    {
+        if ((f = fopen(filename, "rb")) == NULL)
+        {
+            dmError("Could not open '%s' for reading.\n", filename);
+            return DMERR_FOPEN;
+        }
+    }
+    else
+    {
+        dmError("NULL filename and stream pointers.\n");
+        return DMERR_NULLPTR;
+    }
+
+    // Allocate initial data buffer
+    readSize = dataSize = BUF_SIZE_INITIAL;
+    if ((dataBuf = dmMalloc(dataSize)) == NULL)
+    {
+        dmError("Error allocating memory for data, %d bytes.\n", dataSize);
+        res = DMERR_MALLOC;
+        goto error;
+    }
+
+    dataPos = 0;
+    dataRead = 0;
+
+    while (!feof(f) && !ferror(f))
+    {
+        size_t read = fread(dataBuf + dataPos, 1, readSize, f);
+        dataPos += read;
+        dataRead += read;
+
+        if (dataRead >= dataSize)
+        {
+            readSize = BUF_SIZE_GROW;
+            dataSize += BUF_SIZE_GROW;
+            if ((dataBuf = dmRealloc(dataBuf, dataSize)) == NULL)
+            {
+                dmError("Error reallocating memory for data, %d bytes.\n", dataSize);
+                res = DMERR_MALLOC;
+                goto error;
+            }
+        }
+        else
+            break;
+    }
+
+    *pbufSize = dataRead;
+    *pbuf = dataBuf;
+
+error:
+    if (f != inFile)
+        fclose(f);
+    
+    return res;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmfile.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,41 @@
+/*
+ * DMLib
+ * -- Standard I/O (stdio) file write/read endianess helpers
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2011 Tecnic Software productions (TNSP)
+ */
+#ifndef DMFILE_H
+#define DMFILE_H
+
+#include "dmlib.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Plain file endianess functions
+ */
+#define DM_DEFINE_FFUNC(xname, xtype, z)          \
+BOOL    dm_fread_ ## xname (FILE *f, xtype *v);  \
+BOOL    dm_fwrite_ ## xname (FILE *f, const xtype v);
+
+#include "dmfiletmpl.h"
+
+#undef DM_DEFINE_FFUNC
+
+BOOL    dm_fread_str(FILE *f, void *, const size_t);
+BOOL    dm_fwrite_str(FILE *f, const void *, const size_t);
+
+BOOL    dm_fread_byte(FILE *f, Uint8 *);
+BOOL    dm_fwrite_byte(FILE *f, const Uint8);
+
+
+int     dmReadDataFile(FILE *inFile, const char *filename, Uint8 **buf, size_t *size);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DMFILE_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmfiletmpl.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,17 @@
+/*
+ * DMLib
+ * -- Plain streamed file I/O endianess functions
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2011 Tecnic Software productions (TNSP)
+ */
+
+DM_DEFINE_FFUNC(le16, Uint16, LE16)
+DM_DEFINE_FFUNC(le32, Uint32, LE32)
+
+DM_DEFINE_FFUNC(be16, Uint16, BE16)
+DM_DEFINE_FFUNC(be32, Uint32, BE32)
+
+#ifdef DM_HAVE_64BIT
+DM_DEFINE_FFUNC(le64, Uint64, LE64)
+DM_DEFINE_FFUNC(be64, Uint64, BE64)
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmgfx.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,107 @@
+#include "dmlib.h"
+
+
+void dmFillRect(SDL_Surface *screen, int x0, int y0, int x1, int y1, Uint32 col)
+{
+    SDL_Rect rc;
+    rc.x = x0;
+    rc.y = y0;
+    rc.w = x1 - x0 + 1;
+    rc.h = y1 - y0 + 1;
+    SDL_FillRect(screen, &rc, col);
+}
+
+
+void dmDrawHLine(SDL_Surface *screen, int x0, int x1, int yc, const Uint32 col)
+{
+    const int bpp = screen->format->BytesPerPixel,
+              cx0 = screen->clip_rect.x, cy0 = screen->clip_rect.y,
+              cx1 = screen->clip_rect.x + screen->clip_rect.w - 1,
+              cy1 = screen->clip_rect.y + screen->clip_rect.h - 1;
+    
+    DM_SWAP(int, x0, x1);
+    if (yc < cy0|| yc > cy1 || x1 < cx0 || x0 > cx1) return;
+    if (x0 < cx0) x0 = cx0;
+    if (x1 > cx1) x1 = cx1;
+    
+    int x = x1 - x0 + 1;
+    Uint8 *pix = screen->pixels + yc * screen->pitch + (x0 * bpp);
+    switch (screen->format->BitsPerPixel)
+    {
+        case 8:
+            while (x--)
+                *pix++ = col;
+            break;
+        
+        case 32:
+            {
+                Uint32 *p = (Uint32 *) pix;
+                while (x--)
+                    *p++ = col;
+            }
+            break;
+    }
+}
+
+
+void dmDrawVLine(SDL_Surface *screen, int y0, int y1, int xc, const Uint32 col)
+{
+    const int bpp = screen->format->BytesPerPixel,
+              pitch = screen->pitch / bpp,
+              cx0 = screen->clip_rect.x, cy0 = screen->clip_rect.y,
+              cx1 = screen->clip_rect.x + screen->clip_rect.w - 1,
+              cy1 = screen->clip_rect.y + screen->clip_rect.h - 1;
+
+    DM_SWAP(int, y0, y1);
+    if (xc < cx0 || xc > cx1 || y1 < cy0 || y0 > cy1) return;
+    if (y0 < cy0) y0 = cy0;
+    if (y1 > cy1) y1 = cy1;
+
+    int y = y1 - y0 + 1;
+    Uint8 *pix = screen->pixels + y0 * screen->pitch + (xc * bpp);
+    switch (screen->format->BitsPerPixel)
+    {
+        case 8:
+            while (y--)
+            {
+                *pix = col;
+                pix += pitch;
+            }
+            break;
+        
+        case 32:
+            {
+                Uint32 *p = (Uint32 *) pix;
+                while (y--)
+                {
+                    *p = col;
+                    p += pitch;
+                }
+            }
+            break;
+    }
+}
+
+
+void dmDrawBox3D(SDL_Surface *screen, int x0, int y0, int x1, int y1, Uint32 ucol, Uint32 dcol)
+{
+    dmDrawHLine(screen, x0    , x1 - 1, y0, ucol);
+    dmDrawHLine(screen, x0 + 1, x1    , y1, dcol);
+
+    dmDrawVLine(screen, y0    , y1 - 1, x0, ucol);
+    dmDrawVLine(screen, y0 + 1, y1    , x1, dcol);
+}
+
+
+void dmFillBox3D(SDL_Surface *screen, int x0, int y0, int x1, int y1, Uint32 bgcol, Uint32 ucol, Uint32 dcol)
+{
+    SDL_Rect rc;
+
+    rc.x = x0 + 1;
+    rc.y = y0 + 1;
+    rc.w = x1 - x0 - 1;
+    rc.h = y1 - y0 - 1;
+    SDL_FillRect(screen, &rc, bgcol);
+
+    dmDrawBox3D(screen, x0, y0, x1, y1, ucol, dcol);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmimage.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,169 @@
+/*
+ * DMLib
+ * -- Bitmap image conversion and loading
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012 Tecnic Software productions (TNSP)
+ */
+#include "dmimage.h"
+
+
+#define STBI_FAILURE_USERMSG 1
+#define STBI_NO_STDIO 1
+#define STBI_NO_HDR 1
+#include "stb_image.c"
+
+
+SDL_Surface *dmCreateRGBSurfaceFrom(void *data, const int width, const int height, const int depth, const int pitch, const int rmask, const int gmask, const int bmask, const int amask)
+{
+    // Create source surface from given data
+    SDL_Surface *tmp = SDL_CreateRGBSurfaceFrom(data, width, height, depth, pitch, bmask, gmask, rmask, amask);
+
+    // Result surface component orders as masks
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+    Uint32
+        Xrmask = 0xff000000,
+        Xgmask = 0x00ff0000,
+        Xbmask = 0x0000ff00,
+        Xamask = 0x000000ff;
+#else
+    Uint32
+        Xrmask = 0x000000ff,
+        Xgmask = 0x0000ff00,
+        Xbmask = 0x00ff0000,
+        Xamask = 0xff000000;
+#endif
+
+    // Create result conversion surface
+    SDL_Surface
+        *result = NULL,
+        *pixtmp = SDL_CreateRGBSurface(
+        SDL_SWSURFACE | SDL_SRCALPHA, 16, 16, 32, Xrmask, Xgmask, Xbmask, Xamask);
+
+    if (tmp != NULL && pixtmp != NULL)
+    {
+        // Convert surface
+        result = SDL_ConvertSurface(tmp, pixtmp->format, SDL_SWSURFACE | SDL_SRCALPHA);
+        SDL_FreeSurface(tmp);
+    }
+    if (pixtmp != NULL)
+        SDL_FreeSurface(pixtmp);
+    
+    return result;
+}
+
+
+SDL_Surface *dmCreatePaletteSurfaceFrom(void *data, const int width, const int height, const int pitch)
+{
+    int yc;
+    Uint8 *dst, *src;
+    SDL_Surface *result;
+    result = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 8, 0,0,0,0);
+    if (result == NULL)
+        return NULL;
+    
+    dst = result->pixels;
+    src = data;
+    for (yc = 0; yc < height; yc++)
+    {
+        memcpy(dst, src, width * sizeof(Uint8));
+        dst += result->pitch;
+        src += pitch;
+    }
+
+    return result;
+}
+
+
+
+static int dmSTBIread(void *user, char *data, int size)
+{
+    return dmfread(data, 1, size, (DMResource *) user);
+}
+
+
+static void dmSTBIskip(void *user, unsigned int n)
+{
+    dmfseek((DMResource *) user, n, SEEK_CUR);
+}
+
+
+static int dmSTBIeof(void *user)
+{
+    return dmfeof((DMResource *) user);
+}
+
+
+static const stbi_io_callbacks dmSTBICallbacks =
+{
+    dmSTBIread,
+    dmSTBIskip,
+    dmSTBIeof,
+};
+
+
+SDL_Surface *dmLoadImage(DMResource *file)
+{
+    Uint32 rmask, gmask, bmask, amask;
+    SDL_Surface *result = NULL;
+    int width, height, comp;
+    Uint8 *data;
+
+    data = stbi_load_from_callbacks(&dmSTBICallbacks, file, &width, &height, &comp, 0);
+
+    if (data == NULL)
+    {
+        dmError("Error decoding image resource %p '%s' [%d, %d, %d]: %s\n",
+            file, file->filename, width, height, comp, stbi_failure_reason());
+        return NULL;
+    }
+
+
+    switch (comp)
+    {
+        case 4:
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+            rmask = 0xff000000;
+            gmask = 0x00ff0000;
+            bmask = 0x0000ff00;
+            amask = 0x000000ff;
+#else
+            rmask = 0x000000ff;
+            gmask = 0x0000ff00;
+            bmask = 0x00ff0000;
+            amask = 0xff000000;
+#endif
+            result = dmCreateRGBSurfaceFrom(data, width, height, comp * 8,
+                width * comp, rmask, gmask, bmask, amask);
+            break;
+
+        case 3:
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+            rmask = 0x00ff0000;
+            gmask = 0x0000ff00;
+            bmask = 0x000000ff;
+            amask = 0x00000000;
+#else
+            rmask = 0x000000ff;
+            gmask = 0x0000ff00;
+            bmask = 0x00ff0000;
+            amask = 0x00000000;
+#endif
+            result = dmCreateRGBSurfaceFrom(data, width, height, comp * 8,
+                width * comp, rmask, gmask, bmask, amask);
+            break;
+
+        case 1:
+            result = dmCreatePaletteSurfaceFrom(data, width, height, width * comp);
+            break;
+    }
+    
+    stbi_image_free(data);
+
+    if (result == NULL)
+    {
+        dmError("Format conversion failed for image resource %p '%s' [%d, %d, %d].\n",
+            file, file->filename, width, height, comp);
+    }
+
+    return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmimage.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,27 @@
+/*
+ * DMLib
+ * -- Bitmap image conversion and loading
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012 Tecnic Software productions (TNSP)
+ */
+#ifndef DMIMAGE_H
+#define DMIMAGE_H
+
+#include "dmlib.h"
+#include "dmres.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+SDL_Surface *dmCreateRGBSurfaceFrom(void *data, const int width, const int height, const int depth, const int pitch, const int rmask, const int gmask, const int bmask, const int amask);
+SDL_Surface *dmCreatePaletteSurfaceFrom(void *data, const int width, const int height, const int pitch);
+SDL_Surface *dmLoadImage(DMResource *file);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DMIMAGE_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmlerp.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,20 @@
+#include "dmlib.h"
+
+void dmLerpInit(DMLerpContext *ctx, DMFloat start, DMFloat end, DMFloat nsteps)
+{
+    ctx->start = start;
+    ctx->end = end;
+    ctx->nsteps = nsteps;
+}
+
+
+DMFloat dmCatmullRom(const DMFloat t, const DMFloat p0, const DMFloat p1, const DMFloat p2, const DMFloat p3)
+{
+    const DMFloat q = t * t;
+    return (
+        (2 * p1) +
+        (-p0 + p2) * t +
+        (2 * p0 - 5 * p1 + 4 * p2 - p3) * q +
+        (   -p0 + 3 * p1 - 3 * p2 + p3) * q * t
+        ) * 0.5f;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmlib.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,321 @@
+#include "dmlib.h"
+#include <errno.h>
+
+
+int      dmVerbosity = 0;
+char     *dmProgName = NULL,
+         *dmProgDesc = NULL,
+         *dmProgVersion = NULL,
+         *dmProgAuthor = NULL,
+         *dmProgLicense = NULL;
+
+
+void dmInitProg(char *name, char *desc, char *version, char *author, char *license)
+{
+    dmProgName     = name;
+    dmProgDesc     = desc;
+    dmProgVersion  = version;
+    dmProgAuthor   = author ? author : DM_PROG_AUTHOR;
+    dmProgLicense  = license ? license : DM_PROG_LICENSE;
+}
+
+
+void dmPrintBanner(FILE *outFile, const char *name, const char *usage)
+{
+    fprintf(outFile,
+        "\n%s v%s (%s)\n"
+        "%s\n"
+        "%s\n"
+        "Usage: %s %s\n",
+        dmProgName, dmProgVersion, dmProgDesc,
+        dmProgAuthor, dmProgLicense, name, usage);
+}
+
+
+void dmMsgVA(int level, const char *fmt, va_list ap)
+{
+    if (dmVerbosity >= level)
+    {
+        fprintf(stderr, "%s: ", dmProgName);
+        vfprintf(stderr, fmt, ap);
+    }
+}
+
+
+void dmPrintVA(int level, const char *fmt, va_list ap)
+{
+    if (dmVerbosity >= level)
+    {
+        vfprintf(stderr, fmt, ap);
+    }
+}
+
+
+void dmErrorVA(const char *fmt, va_list ap)
+{
+    fprintf(stderr, "%s: ", dmProgName);
+    vfprintf(stderr, fmt, ap);
+}
+
+
+void dmError(const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    dmErrorVA(fmt, ap);
+    va_end(ap);
+}
+
+
+void dmMsg(int level, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    dmMsgVA(level, fmt, ap);
+    va_end(ap);
+}
+
+
+void dmPrint(int level, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    dmPrintVA(level, fmt, ap);
+    va_end(ap);
+}
+
+
+/* Memory handling routines
+ */
+void *dmMalloc(size_t l)
+{
+    return malloc(l);
+}
+
+
+void *dmMalloc0(size_t l)
+{
+    return calloc(1, l);
+}
+
+
+void *dmCalloc(size_t n, size_t l)
+{
+    return calloc(n, l);
+}
+
+
+void *dmRealloc(void *p, size_t l)
+{
+    return realloc(p, l);
+}
+
+
+void dmFree(void *p)
+{
+    /* Check for NULL pointers for portability due to some libc
+     * implementations not handling free(NULL) too well.
+     */
+    if (p) free(p);
+}
+
+
+BOOL dmGetIntVal(const char *s, int *i)
+{
+    if (s[0] == '$')
+    {
+        if (sscanf(&s[1], "%x", i) < 1)
+            return FALSE;
+    }
+    else if (s[0] == '0' && s[1] == 'x')
+    {
+        if (sscanf(&s[2], "%x", i) < 1)
+            return FALSE;
+    }
+    else
+    {
+        if (sscanf(s, "%u", i) < 1)
+            return FALSE;
+    }
+    return TRUE;
+}
+
+
+/* Error handling
+ */
+#define DM_SYSTEM_ERRORS 100000
+
+int dmGetErrno()
+{
+    return DM_SYSTEM_ERRORS + errno;
+}
+
+
+const char *dmErrorStr(int error)
+{
+    if (error >= DM_SYSTEM_ERRORS)
+        return strerror(error - DM_SYSTEM_ERRORS);
+    
+    switch (error)
+    {
+        case DMERR_OK:             return "No error";
+        case DMERR_FOPEN:          return "File open error";
+        case DMERR_FREAD:          return "Read error";
+        case DMERR_FWRITE:         return "Write error";
+        case DMERR_FSEEK:          return "Seek error";
+        case DMERR_NOT_FOUND:      return "Resource not found";
+
+        case DMERR_INVALID_DATA:   return "Invalid data";
+        case DMERR_MALLOC:         return "Memory allocation failure";
+        case DMERR_ALREADY_INIT:   return "Already initialized";
+        case DMERR_INIT_FAIL:      return "Initialization failed";
+        case DMERR_INVALID_ARGS:   return "Invalid arguments";
+
+        case DMERR_NULLPTR:        return "NULL pointer";
+        case DMERR_NOT_SUPPORTED:  return "Operation not supported";
+        case DMERR_OUT_OF_DATA:    return "Out of data";
+        case DMERR_EXTRA_DATA:     return "Extra data";
+        case DMERR_BOUNDS:         return "Bounds check failed";
+
+        case DMERR_NOTPACK:        return "File is not a PACK";
+        case DMERR_VERSION:        return "Unsupported PACK version";
+        case DMERR_INVALID:        return "Invalid data, corrupted file";
+        case DMERR_COMPRESSION:    return "Error in compression";
+
+        default:                   return "Unknown error";
+    }
+}
+
+
+#ifdef DM_MUTEX_DEBUG
+
+static DMMutexLock * dmGetMutexThreadIDLock(DMMutex *mutex)
+{
+    Uint32 id = SDL_ThreadID();
+    int i;
+    for (i = 0; i < 8; i++)
+    {
+        DMMutexLock *lock = &(mutex->locks[i]);
+        if (lock->used && lock->id == id)
+            return lock;
+    }
+    return NULL;
+}
+
+static void dmPrintMutexLocks(DMMutex *mutex, const char *state, const char *file, const int line)
+{
+    int i;
+
+    fprintf(stderr,
+    "----------------------\n"
+    "%s --> %p @ %s:%d\n"
+    "Current thread: %d\n"
+    "Mutex         : %p (created @ %s:%d)\n",
+    state, mutex, file, line,
+    SDL_ThreadID(), mutex, mutex->cr_file, mutex->cr_line);
+
+    for (i = 0; i < 8; i++)
+    {
+        DMMutexLock *lock = &(mutex->locks[i]);
+        if (lock->used)
+        {
+            fprintf(stderr,
+            "Lock #%d: thread=%d, state=%d\n",
+            i, lock->id, lock->state);
+        }
+    }    
+}
+
+int dmDOMutexLock(DMMutex *mutex, const char *file, const int line)
+{
+    if (mutex != NULL)
+    {
+        dmPrintMutexLocks(mutex, "LOCKING", file, line);
+        
+        DMMutexLock *lock = dmGetMutexThreadIDLock(mutex);
+        if (lock != NULL)
+        {
+            int res;
+            if (lock->state == 0)
+                res = SDL_mutexP(mutex->m);
+            else
+                res = 1;
+            lock->state++;
+            fprintf(stderr, "LOCKING %p @ thread=%d done [1].\n", mutex, SDL_ThreadID());
+            return res;
+        }
+        else
+        {
+            int i;
+            for (i = 0; i < 8; i++)
+            {
+                DMMutexLock *lock = &(mutex->locks[i]);
+                if (!lock->used)
+                {
+                    int res;
+                    lock->used = TRUE;
+                    lock->id = SDL_ThreadID();
+                    lock->state++;
+                    res = SDL_mutexP(mutex->m);
+                    fprintf(stderr, "LOCKING %p @ thread=%d done [2].\n", mutex, SDL_ThreadID());
+                    return res;
+                }
+            }
+            return -2;
+        }
+    }
+    return -1;
+}
+
+
+int dmDOMutexUnlock(DMMutex *mutex, const char *file, const int line)
+{
+    if (mutex != NULL)
+    {
+        dmPrintMutexLocks(mutex, "UN-LOCKING", file, line);
+
+        DMMutexLock *lock = dmGetMutexThreadIDLock(mutex);
+        if (lock != NULL)
+        {
+            int res;
+            lock->state--;
+            if (lock->state == 0)
+                res = SDL_mutexV(mutex->m);
+            else
+                res = lock->state;
+            return res;
+        }
+        else
+        {
+            return -2;
+        }
+    }
+    return -1;
+}
+
+
+DMMutex * dmDOCreateMutex(const char *file, const int line)
+{
+    DMMutex *mutex = dmMalloc0(sizeof(DMMutex));
+    if (mutex == NULL)
+        return NULL;
+    mutex->cr_file = dm_strdup(file);
+    mutex->cr_line = line;
+    mutex->m = SDL_CreateMutex();
+    return mutex;
+}
+
+
+void dmDestroyMutex(DMMutex *mutex)
+{
+    if (mutex != NULL)
+    {
+        SDL_DestroyMutex(mutex->m);
+        dmFree(mutex);
+    }
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmlib.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,509 @@
+/*
+ * DMLib
+ * -- Main header file
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2011-2014 Tecnic Software productions (TNSP)
+ */
+#ifndef DMLIB_H
+#define DMLIB_H
+
+#include <SDL_config.h>
+#include <SDL_endian.h>
+#include <SDL_types.h>
+#include <SDL_mutex.h>
+#include <SDL_thread.h>
+#include <SDL_video.h>
+#include <stdarg.h>
+
+#ifdef DM_USE_ASSERTS
+#  include <assert.h>
+#else
+#  define assert(NEXPR) // stub
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Defaults
+#define DM_PROG_AUTHOR      "By Matti 'ccr' Hamalainen (C) Copyright 2014 TNSP"
+#define DM_PROG_LICENSE     "Et all, see README / COPYING for more information."
+
+/* Error codes
+ */
+enum {
+    // General error codes
+    DMERR_OK = 0,
+    DMERR_PROGRESS,     // Status OK, but operation in progress
+	
+    DMERR_FOPEN,
+    DMERR_FREAD,
+    DMERR_FWRITE,
+    DMERR_FSEEK,
+    DMERR_NOT_FOUND,    // Resource/data not found
+
+    DMERR_INVALID_DATA, // Some data was invalid
+    DMERR_MALLOC,       // Memory allocation failure
+    DMERR_ALREADY_INIT, // Resource has already been initialized
+    DMERR_INIT_FAIL,    // General initialization failure
+    DMERR_INVALID_ARGS,
+
+    DMERR_NULLPTR,      // NULL pointer specified in critical argument
+    DMERR_NOT_SUPPORTED,// Operation not supported
+    DMERR_OUT_OF_DATA,
+    DMERR_EXTRA_DATA,
+    DMERR_BOUNDS,
+
+    DMERR_INTERNAL,
+
+    // PACK-file subsystem
+    DMERR_NOTPACK,
+    DMERR_VERSION,
+    DMERR_INVALID,
+    DMERR_COMPRESSION,
+};
+
+
+// Resource management defines
+#define DMRES_NAME_LEN  32
+#define DMRES_DATA_PACK	"data.pak"  // Name of the data-file
+#define DMRES_DATA_PATH	"data/"     // Sub-directory path
+#define DMRES_RES_FILE  "res.txt"   // Resource data file
+
+
+/* Define a boolean type
+ */
+#if !defined(FALSE) && !defined(TRUE) && !defined(BOOL)
+typedef enum { FALSE = 0, TRUE = 1 } BOOL;
+#endif
+
+#ifndef BOOL
+#  ifdef bool
+#    define BOOL bool
+#  else
+#    define BOOL int
+#  endif
+#endif
+
+
+/* Math constants
+ */
+#define DM_PI   3.14159265358f
+#define DM_PI2  6.28318530718f
+#define DM_E    2.71828182846f
+
+
+/* Fixed point math type
+ */
+typedef union
+{
+    Sint64 dw;
+    Sint32 w[2];
+} DMFixedPoint;
+
+
+typedef union
+{
+    Sint32 dw;
+    Sint16 w[2];
+} DMFixedPoint32;
+
+
+/* Macros for fixed point math
+ */
+#if __GNUC__ >= 3
+#  define FP_SET(a, k) a.dw = k ## ULL
+#else
+#  define FP_SET(a, k) a.dw = k
+#endif
+
+#define FP_CONV(a, k) a.dw = (k)
+
+#ifndef SDL_BYTEORDER
+#  error Undefined byteorder!
+#endif
+
+#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
+#  define FP_SETH(a, k) a.w[0] = (k)
+#  define FP_SETL(a, k) a.w[1] = (k)
+#  define FP_SETHL(a, h, l) { a.w[0] = (h); a.w[1] = (l); }
+#  define FP_GETH32(a) a.w[0]
+#  define FP_GETL32(a) a.w[1]
+#  define FP_GETH16(a) a.w[0]
+#  define FP_GETL16(a) a.w[1]
+#elif (SDL_BYTEORDER == SDL_LIL_ENDIAN)
+#  define FP_SETH(a, k) a.w[1] = (k)
+#  define FP_SETL(a, k) a.w[0] = (k)
+#  define FP_SETHL(a, h, l) { a.w[1] = (h); a.w[0] = (l); }
+#  define FP_GETH32(a) a.w[1]
+#  define FP_GETL32(a) a.w[0]
+#  define FP_GETH16(a) a.w[1]
+#  define FP_GETL16(a) a.w[0]
+#else
+#  error Unsupported byte order!
+#endif
+
+#define FP_PRINTF64(a) printf("%.8x:%.8x", FP_GETH32(a), FP_GETL32(a))
+#define FP_PRINTF32(a) printf("%.4x:%.4x", FP_GETH16(a), FP_GETL16(a))
+
+#define FP_ADD(a, b) a.dw += b.dw
+#define FP_SUB(a, b) a.dw -= b.dw
+#define FP_ADD_R(r, a, b) r.dw = a.dw + b.dw
+#define FP_SUB_R(r, a, b) r.dw = a.dw - b.dw
+#define FP_DIV(a, b) a.dw /= b.dw
+#define FP_MUL(a, b) a.dw *= b.dw
+#define FP_DIV_R(r, a, b) r.dw = (a.dw / b.dw)
+#define FP_MUL_R(r, a, b) r.dw = (a.dw * b.dw)
+
+
+/* Miscellaneous types
+ */
+typedef struct
+{
+#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
+    Uint8 a,g,b,r;
+#elif (SDL_BYTEORDER == SDL_LIL_ENDIAN)
+    Uint8 r,g,b,a;
+#endif
+} DMRGBA32;
+
+
+typedef float DMFloat;
+
+
+// Macro for swapping two lvalues of same type
+#define DM_SWAP(T, A, B) { if ((B) < (A)) { T swtmp = (B); B = (A); A = swtmp; } }
+
+
+/* Drawing modes used by blitting and some other functions.
+ */
+enum
+{
+    DMD_NONE        = 0x0000,
+    DMD_TRANSPARENT = 0x0001,
+    DMD_SATURATE    = 0x0002,
+ 
+    DMD_ANTIALIAS   = 0x0004,
+    
+    DMD_NMODES      = 6
+};
+
+
+// Available bitdepths. Not all functions may support every one of these.
+enum
+{
+    DMD_8BIT = 0,
+    DMD_32BIT,
+    
+    DMD_NBITDEPTHS
+};
+
+
+static inline int dmBitsPerPixel2Index(int bpp)
+{
+    return (bpp == 8 ? 0 : (bpp == 32 ? 1 : -1));
+}
+
+
+/* Generic parameter interpolation
+ */
+#define DMM_S_CURVE(t)     ((t) * (t) * (3.0f - 2.0f * (t)))
+#define DMM_LERP(t, a, b)  ((a) + (t) * ((b) - (a)))
+
+typedef struct
+{
+    DMFloat start, end, nsteps;
+} DMLerpContext;
+
+
+void       dmLerpInit(DMLerpContext *ctx, DMFloat start, DMFloat end, DMFloat nsteps);
+DMFloat    dmCatmullRom(const DMFloat t, const DMFloat p0, const DMFloat p1, const DMFloat p2, const DMFloat p3);
+
+
+static inline DMFloat dmClamp10(const DMFloat a)
+{
+    return (a < 0.0f ? 0.0f : (a > 1.0f ? 1.0f : a));
+}
+
+
+static inline int dmClamp(const int v, const int min, const int max)
+{
+    return (v < min ? min : (v > max ? max : v));
+}
+
+
+static inline DMFloat dmLerpSCurve(DMLerpContext *ctx, const DMFloat step)
+{
+    const DMFloat n = step / ctx->nsteps;
+    const DMFloat v = DMM_S_CURVE(n);
+    return DMM_LERP(v, ctx->start, ctx->end);
+}
+
+
+static inline DMFloat dmLerpSCurveClamp(DMLerpContext *ctx, const DMFloat step)
+{
+    const DMFloat n = dmClamp10(step / ctx->nsteps);
+    const DMFloat v = DMM_S_CURVE(n);
+    return DMM_LERP(v, ctx->start, ctx->end);
+}
+
+
+static inline DMFloat dmLerp1(DMLerpContext *ctx, const DMFloat step)
+{
+    const DMFloat v = step / ctx->nsteps;
+    return DMM_LERP(v, ctx->start, ctx->end);
+}
+
+
+static inline DMFloat dmLerp1Clamp(DMLerpContext *ctx, const DMFloat step)
+{
+    const DMFloat v = dmClamp10(step / ctx->nsteps);
+    return DMM_LERP(v, ctx->start, ctx->end);
+}
+
+
+static inline DMFloat dmCatmullRomClamp(const DMFloat t, const DMFloat p0, const DMFloat p1, const DMFloat p2, const DMFloat p3)
+{
+    return dmCatmullRom(dmClamp10(t), p0, p1, p2, p3);
+}
+
+
+/* Perlin noise
+ */
+void       dmPerlinInit(void);
+DMFloat    dmPerlinNoise2D(DMFloat x, DMFloat y, DMFloat alpha, DMFloat beta, int n);
+
+
+/* Arbitrary line drawing
+ */
+#ifdef DM_GFX_LINES
+#define DM_HEADER
+#include "dmlinefunc.h"
+
+enum
+{
+    CLIP_TOP     = 1,
+    CLIP_BOTTOM  = 2,
+    CLIP_RIGHT   = 4,
+    CLIP_LEFT    = 8
+};
+
+#define DM_CLIP_FUNC dmClipLineCoordsFloat
+#define DM_COORD_TYPE DMFloat
+#include "dmlineclip.h"
+
+#undef DM_HEADER
+#endif
+
+
+/* Various blitting functions
+ */
+#ifdef DM_GFX_BLITS
+typedef int (*DMScaledBlitFunc)(SDL_Surface *src, const int x0, const int y0, const int dwidth, const int dheight, SDL_Surface *dst);
+DMScaledBlitFunc dmGetScaledBlitFunc(SDL_PixelFormat *src, SDL_PixelFormat *dst, int mode);
+int dmScaledBlitSurfaceAny(SDL_Surface *src, const int x0, const int y0, const int dwidth, const int dheight, SDL_Surface *dst, int mode);
+
+typedef int (*DMUnscaledBlitFunc)(SDL_Surface *src, const int x0, const int y0, SDL_Surface *dst);
+DMUnscaledBlitFunc dmGetUnscaledBlitFunc(SDL_PixelFormat *src, SDL_PixelFormat *dst, int mode);
+int dmUnscaledBlitSurfaceAny(SDL_Surface *src, const int x0, const int y0, SDL_Surface *dst, int mode);
+
+SDL_Surface *dmConvertScaledSurface(SDL_Surface *src, SDL_PixelFormat *fmt, Uint32 flags, const int dwidth, const int dheight);
+
+
+#define DM_HEADER
+#include "dmblitfunc.h"
+#undef DM_HEADER
+
+#endif // DM_GFX_BLITS
+
+
+/* Misc functions
+ */
+#ifdef DM_GFX_MISC
+
+void       dmFillRect(SDL_Surface *screen, int x0, int y0, int x1, int y1, const Uint32 col);
+void       dmDrawHLine(SDL_Surface *screen, int x0, int x1, int yc, const Uint32 col);
+void       dmDrawVLine(SDL_Surface *screen, int y0, int y1, int xc, const Uint32 col);
+
+void       dmDrawBox3D(SDL_Surface *screen, int x0, int y0, int x1, int y1, Uint32 ucol, Uint32 dcol);
+void       dmFillBox3D(SDL_Surface *screen, int x0, int y0, int x1, int y1, Uint32 bgcol, Uint32 ucol, Uint32 dcol);
+
+#endif // DM_GFX_MISC
+
+
+static inline void dmClearSurface(SDL_Surface *screen, const Uint32 col)
+{
+    SDL_FillRect(screen, NULL, col);
+}
+
+
+static inline Uint32 dmMapRGB(SDL_Surface *screen, int r, int g, int b)
+{
+    return SDL_MapRGB(screen->format, r, g, b);
+}
+
+
+static inline Uint32 dmMapRGBA(SDL_Surface *screen, int r, int g, int b, int a)
+{
+    return SDL_MapRGBA(screen->format, r, g, b, a);
+}
+
+
+static inline int dmDirectBlitSurface(SDL_Surface *bmp, SDL_Surface *screen)
+{
+    return SDL_BlitSurface(bmp, NULL, screen, NULL);
+}
+
+
+static inline SDL_Surface *dmCopySurface(SDL_Surface *src)
+{
+    if (src != NULL)
+        return SDL_ConvertSurface(src, src->format, src->flags);
+    else
+        return NULL;
+}
+
+
+/* Global variables
+ */
+extern char *dmProgName,
+            *dmProgDesc,
+            *dmProgVersion,
+            *dmProgAuthor,
+            *dmProgLicense;
+
+extern int dmVerbosity;
+void       dmInitProg(char *name, char *desc, char *version, char *author, char *license);
+void       dmPrintBanner(FILE *outFile, const char *name, const char *usage);
+
+void       dmMsgVA(int level, const char *fmt, va_list ap);
+void       dmMsg(int level, const char *fmt, ...);
+void       dmPrintVA(int level, const char *fmt, va_list ap);
+void       dmPrint(int level, const char *fmt, ...);
+void       dmErrorVA(const char *fmt, va_list);
+void       dmError(const char *fmt, ...);
+
+void *     dmMalloc(size_t);
+void *     dmMalloc0(size_t);
+void *     dmRealloc(void *, size_t);
+void *     dmCalloc(size_t, size_t);
+void       dmFree(void *);
+
+BOOL dmGetIntVal(const char *s, int *i);
+
+int         dmGetErrno();
+const char *dmErrorStr(int error);
+
+char *     dm_strdup(const char *);
+char *     dm_strndup(const char *, const size_t n);
+char *     dm_strdup_vprintf(const char *, va_list);
+char *     dm_strdup_printf(const char *, ...);
+
+
+/* Mutexes
+ */
+#ifdef DM_MUTEX_DEBUG
+
+typedef struct
+{
+    BOOL used;
+    Uint32 id;
+    int state;
+} DMMutexLock;
+
+typedef struct
+{
+    char *cr_file;
+    int cr_line;
+    SDL_mutex *m;
+    DMMutexLock locks[8];
+} DMMutex;
+
+#define dmMutexLock(x) dmDOMutexLock(x, __FILE__, (int) __LINE__)
+#define dmMutexUnlock(x) dmDOMutexUnlock(x, __FILE__, (int) __LINE__)
+#define dmCreateMutex(x) dmDOCreateMutex(__FILE__, (int) __LINE__)
+
+int        dmDOMutexLock(DMMutex *mutex, const char *file, const int line);
+int        dmDOMutexUnlock(DMMutex *mutex, const char *file, const int line);
+DMMutex *  dmDOCreateMutex(const char *file, const int line);
+void       dmDestroyMutex(DMMutex *mutex);
+
+#else
+#define DMMutex SDL_mutex
+#define dmCreateMutex() SDL_CreateMutex()
+#define dmDestroyMutex(x) SDL_DestroyMutex(x)
+#define dmMutexLock(x) SDL_mutexP(x)
+#define dmMutexUnlock(x) SDL_mutexV(x)
+#endif
+
+/* Endianess swapping macros
+ */
+#define DM_SWAP_16_LE_BE(value)    ((Uint16) (   \
+    (Uint16) ((Uint16) (value) >> 8) |      \
+    (Uint16) ((Uint16) (value) << 8)) )
+
+
+#define DM_SWAP_32_LE_BE(value) ((Uint32) (               \
+    (((Uint32) (value) & (Uint32) 0x000000ffU) << 24) | \
+    (((Uint32) (value) & (Uint32) 0x0000ff00U) <<  8) | \
+    (((Uint32) (value) & (Uint32) 0x00ff0000U) >>  8) | \
+    (((Uint32) (value) & (Uint32) 0xff000000U) >> 24)))
+
+#ifdef DM_HAVE_64BIT
+#define DM_SWAP_64_LE_BE(value) ((Uint64) (                           \
+    (((Uint64) (value) & (Uint64) 0x00000000000000ffULL) << 56) |   \
+    (((Uint64) (value) & (Uint64) 0x000000000000ff00ULL) << 40) |   \
+    (((Uint64) (value) & (Uint64) 0x0000000000ff0000ULL) << 24) |   \
+    (((Uint64) (value) & (Uint64) 0x00000000ff000000ULL) <<  8) |   \
+    (((Uint64) (value) & (Uint64) 0x000000ff00000000ULL) >>  8) |   \
+    (((Uint64) (value) & (Uint64) 0x0000ff0000000000ULL) >> 24) |   \
+    (((Uint64) (value) & (Uint64) 0x00ff000000000000ULL) >> 40) |   \
+    (((Uint64) (value) & (Uint64) 0xff00000000000000ULL) >> 56)))
+#endif
+
+/* Macros that swap only when needed ...
+ */
+#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
+#  define DM_LE16_TO_NATIVE(value) DM_SWAP_16_LE_BE(value)
+#  define DM_LE32_TO_NATIVE(value) DM_SWAP_32_LE_BE(value)
+#  define DM_NATIVE_TO_LE16(value) DM_SWAP_16_LE_BE(value)
+#  define DM_NATIVE_TO_LE32(value) DM_SWAP_32_LE_BE(value)
+
+#  define DM_BE16_TO_NATIVE(value) ((Uint16) (value))
+#  define DM_BE32_TO_NATIVE(value) ((Uint32) (value))
+#  define DM_NATIVE_TO_BE16(value) ((Uint16) (value))
+#  define DM_NATIVE_TO_BE32(value) ((Uint32) (value))
+
+#  ifdef DM_HAVE_64BIT
+#    define DM_LE64_TO_NATIVE(value) DM_SWAP_64_LE_BE(value)
+#    define DM_NATIVE_TO_LE64(value) DM_SWAP_64_LE_BE(value)
+#    define DM_BE64_TO_NATIVE(value) ((Uint64) (value))
+#    define DM_NATIVE_TO_BE64(value) ((Uint64) (value))
+#  endif
+
+#elif (SDL_BYTEORDER == SDL_LIL_ENDIAN)
+
+#  define DM_LE16_TO_NATIVE(value) ((Uint16) (value))
+#  define DM_LE32_TO_NATIVE(value) ((Uint32) (value))
+#  define DM_NATIVE_TO_LE16(value) ((Uint16) (value))
+#  define DM_NATIVE_TO_LE32(value) ((Uint32) (value))
+
+#  define DM_BE16_TO_NATIVE(value) DM_SWAP_16_LE_BE(value)
+#  define DM_BE32_TO_NATIVE(value) DM_SWAP_32_LE_BE(value)
+#  define DM_NATIVE_TO_BE16(value) DM_SWAP_16_LE_BE(value)
+#  define DM_NATIVE_TO_BE32(value) DM_SWAP_32_LE_BE(value)
+
+#  ifdef DM_HAVE_64BIT
+#    define DM_LE64_TO_NATIVE(value) ((Uint64) (value))
+#    define DM_NATIVE_TO_LE64(value) ((Uint64) (value))
+#    define DM_BE64_TO_NATIVE(value) DM_SWAP_64_LE_BE(value)
+#    define DM_NATIVE_TO_BE64(value) DM_SWAP_64_LE_BE(value)
+#  endif
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DMLIB_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmline.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,19 @@
+/*
+ * DMLib
+ * -- Arbitrary line drawing functions
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2011 Tecnic Software productions (TNSP)
+ */
+#include "dmlib.h"
+
+/* Clip line coordinates. Return value:
+ * = 0  : No clipping needed.
+ * > 0  : Clipped. Line partially inside the clipping area.
+ * < 0  : Line completely outside the clipping area.
+ */
+#define DM_CLIP_FUNC dmClipLineCoordsFloat
+#define DM_COORD_TYPE DMFloat
+#include "dmlineclip.h"
+
+
+#include "dmlinefunc.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmlineclip.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,309 @@
+/* Clip line coordinates. Return value:
+ * = 0  : No clipping needed.
+ * > 0  : Clipped. Line partially inside the clipping area.
+ * < 0  : Line completely outside the clipping area.
+ */
+
+#ifndef DM_HEADER
+#define DM_CLIP_BITS(QB, QX, QY)		\
+    do {					\
+        QB = 0;					\
+        if (QX < clipX0) QB |= CLIP_LEFT;	\
+        else					\
+        if (QX > clipX1) QB |= CLIP_RIGHT;	\
+                                                \
+        if (QY < clipY0) QB |= CLIP_TOP;	\
+        else					\
+        if (QY > clipY1) QB |= CLIP_BOTTOM;	\
+    } while (0)
+
+#define xA (fx0)
+#define xB (fx1)
+#define yA (fy0)
+#define yB (fy1)
+#endif
+
+#ifdef DM_CLIP_DEBUG
+#define CLIPDEB(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
+#else
+#define CLIPDEB(fmt, ...)
+#endif
+
+int DM_CLIP_FUNC (SDL_Surface *screen, DM_COORD_TYPE *x0, DM_COORD_TYPE *y0, DM_COORD_TYPE *x1, DM_COORD_TYPE *y1)
+#ifdef DM_HEADER
+;
+#else
+{
+    const DM_COORD_TYPE
+        clipX0 = screen->clip_rect.x,
+        clipY0 = screen->clip_rect.y,
+        clipX1 = clipX0 + screen->clip_rect.w - 1,
+        clipY1 = clipY0 + screen->clip_rect.h - 1;
+    double fx0 = *x0, fy0 = *y0, fx1 = *x1, fy1 = *y1;
+    int clipA, clipB;
+
+    DM_CLIP_BITS(clipA, xA, yA);
+    DM_CLIP_BITS(clipB, xB, yB);
+
+    CLIPDEB("-- clip [%1.3f, %1.3f - %1.3f, %1.3f] --\n", xA, yA, xB, yB);
+
+#if 1
+    // Cohen-Sutherland clipping method
+    do
+    {
+        const int c = clipA ? clipA : clipB;
+        DM_COORD_TYPE x, y;
+        
+        // The segment is inside?
+        if ((clipA | clipB) == 0)
+        {
+            *x0 = fx0;
+            *y0 = fy0;
+            *x1 = fx1;
+            *y1 = fy1;
+            return 0;
+        }
+
+        // The line segment is outside of the clip region
+        if (clipA & clipB)
+            return -1;
+
+#ifdef DM_CLIP_DEBUG
+        CLIPDEB    "CLIP   : ");
+        if (c == clipA)
+            CLIPDEB("A [%1.3f, %1.3f]\n", xA, yA);
+        else
+            CLIPDEB("B [%1.3f, %1.3f]\n", xB, yB);
+#endif
+        if (c & CLIP_TOP)
+        {
+            if (yB - yA != 0)
+                x = xA + ((clipY0 - yA) * (xB - xA)) / (yB - yA);
+            else
+                x = xA;
+            y = clipY0;
+            CLIPDEB("TOP    : %1.3f, %1.3f\n", x, y);
+        }
+        else
+        if (c & CLIP_BOTTOM)
+        {
+            if (yB - yA != 0)
+                x = xA + ((clipY1 - yA) * (xB - xA)) / (yB - yA);
+            else
+                x = xA;
+            y = clipY1;
+            CLIPDEB("BOTTOM : %1.3f, %1.3f\n", x, y);
+        }
+        else
+        if (c & CLIP_RIGHT)
+        {
+            if (xB - xA != 0)
+                y = yA + ((clipX1 - xA) * (yB - yA)) / (xB - xA);
+            else
+                y = yA;
+            x = clipX1;
+            CLIPDEB("RIGHT  : %1.3f, %1.3f\n", x, y);
+        }
+        else
+        {
+            if (xB - xA != 0)
+                y = yA + ((clipX0 - xA) * (yB - yA)) / (xB - xA);
+            else
+                y = yA;
+            x = clipX0;
+            CLIPDEB("LEFT   : %1.3f, %1.3f\n", x, y);
+        }
+
+        if (c == clipA)
+        {
+            xA = x;
+            yA = y;
+            DM_CLIP_BITS(clipA, xA, yA);
+        }
+        else
+        {
+            xB = x;
+            yB = y;
+            DM_CLIP_BITS(clipB, xB, yB);
+        }
+        
+    } while (1);
+#else
+    // Buyu-Skala clipping method
+    const DM_COORD_TYPE dx = xB - xA;
+    const DM_COORD_TYPE dy = yB - yA;
+    float k, m;
+    int z;
+
+    switch (clipA + clipB)
+    {
+        case 1:
+            if (clipA == 1)
+            {
+                xA = clipX0;
+                yA = (clipX0 - xB) * dy / dx + yB;
+            }
+            else
+            {
+                xB = clipX0;
+                yB = (clipX0 - xA) * dy / dx + yA;
+            }
+            break;
+
+        case 3:
+            k = dy / dx;
+            yA = (clipX0 - xA) * k + yA;
+            xA = clipX0;
+            yB = (clipX1 - xB) * k + yB;
+            xB = clipX1;
+            break;
+
+        case 5:
+            k = dy / dx;
+            z = (clipX0 - xA) * k + yA;
+            if (z < clipY0)
+            {
+                switch (clipA)
+                {
+                    case 0:
+                        xB = xB + (clipY0 - yB) / k;
+                        yB = clipY0;
+                        break;
+                    case 5:
+                        xA = xA + (clipY0 - yA) / k;
+                        yA = clipY0;
+                        break;
+
+                    default:
+                        return -1;  /* the line segment is outside */
+                }
+            }
+            else
+            {
+                switch (clipA)
+                {
+                    case 0:
+                        xB = clipX0;
+                        yB = z;
+                        break;
+                    case 1:
+                        xB = xB + (clipY0 - yB) / k;
+                        yB = clipY0;
+                        xA = clipX0;
+                        yA = z;
+                        break;
+                    case 4:
+                        xA = xA + (clipY0 - yA) / k;
+                        yA = clipY0;
+                        xB = clipX0;
+                        yB = z;
+                        break;
+                    case 5:
+                        xA = clipX0;
+                        yA = z;
+                        break;
+                }
+            }
+            break;
+
+        case 7:
+            switch (clipA)
+            {
+                case 1:
+                    k = dy / dx;
+                    yA = (clipX0 - xB) * k + yB;
+                    if (yA < clipY0)
+                        return -1;  /* the line segment is outside */
+                    xA = clipX0;
+                    yB = (clipX1 - clipX0) * k + yA;
+                    if (yB < clipY0)
+                    {
+                        xB = (clipY0 - yB) / k + clipX1;
+                        yB = clipY0;
+                    }
+                    else
+                        xB = clipX1;
+                    break;
+
+                    /* similarly for cases clipA == 2, 5, 6 */
+            }
+        case 15:
+            switch (clipA)
+            {
+            case 5:
+                if (dy * (clipX1 - clipX0) < dx * (clipY1 - clipY0))
+                {
+                    k = dy / dx;
+                    yA = (clipX0 - xB) * k + yB;
+                    if (yA > clipY1)
+                        return -1;  /* the line segment is outside */
+                    yB = (clipX1 - clipX0) * k + yA;
+                    if (yB < clipY0)
+                        return -1;  /* the line segment is outside */
+                    if (yA < clipY0)
+                    {
+                        xA = (clipY0 - yA) / k + clipX0;
+                        yA = clipY0;
+                        xB = clipX1;
+                    }
+                    else
+                    {
+                        xA = clipX0;
+                        if (yB > clipY1)
+                        {
+                            xB = (clipY1 - yB) / k + clipX1;
+                            yB = clipY1;
+                        }
+                        else
+                            xB = clipX1;
+                    }
+                }
+                else
+                {
+                    m = dx / dy;
+                    xA = (clipY0 - yB) * m + xB;
+                    if (xA > clipX1)
+                        return -1;  /* the line segment is outside */
+                    xB = (clipY1 - clipY0) * m + xA;
+                    if (xB < clipX0)
+                        return -1;  /* the line segment is outside */
+                    if (xA < clipX0)
+                    {
+                        yA = (clipX0 - xA) / m + clipY0;
+                        xA = clipX0;
+                        yB = clipY1;
+                    }
+                    else
+                    {
+                        yA = clipY0;
+                        if (xB > clipX1)
+                        {
+                            yB = (clipX1 - xB) / m + clipY1;
+                            xB = clipX1;
+                        }
+                        else
+                            yB = clipY1;
+                    }
+                }
+
+                /* similarly for cases clipA == 6, 9, 10 */
+            }
+
+            /* cases 2, 4, 8 are similar as case 1, cases 6, 9, 10 are similar as case 5 */
+            /* cases 11, 13, 14 are similar as case 7, case 12 is similar case 3 */
+    }                           /* of case clipA + clipB */
+#endif
+
+    return 1;
+}
+
+#undef DM_CLIP_BITS
+#undef xA
+#undef xB
+#undef yA
+#undef yB
+#undef CLIPDEB
+#endif
+
+#undef DM_CLIP_FUNC
+#undef DM_COORD_TYPE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmlinefunc.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,59 @@
+
+#define DM_DRAWLINE_NAME dmDrawLine8
+#define DM_DRAWLINE_DST_BYTES 1
+#define DM_DRAWLINE_DST_TYPE Uint8
+#define DM_DRAWLINE_INNER pix[y0 + x0] = col;
+#include "dmdrawline.h"
+
+
+#define DM_DRAWLINE_NAME dmDrawLine32
+#define DM_DRAWLINE_DST_BYTES 4
+#define DM_DRAWLINE_DST_TYPE Uint32
+#define DM_DRAWLINE_INNER pix[y0 + x0] = col;
+#include "dmdrawline.h"
+
+
+#define DM_DRAWLINE_NAME dmDrawLine8Transparent
+#define DM_DRAWLINE_DST_BYTES 1
+#define DM_DRAWLINE_DST_TYPE Uint8
+#define DM_DRAWLINE_INNER \
+  pix[y0 + x0] = ((int)pix[y0 + x0] + col) >> 1;
+#include "dmdrawline.h"
+
+
+#define DM_DRAWLINE_NAME dmDrawLine32Transparent
+#define DM_DRAWLINE_DST_BYTES 4
+#define DM_DRAWLINE_DST_TYPE DMRGBA32
+#define DM_DRAWLINE_INIT const DMRGBA32 *c = (DMRGBA32*) &col;
+#define DM_DRAWLINE_INNER \
+  const DMRGBA32 q = pix[y0 + x0]; \
+  const int qr = (q.r + c->r) >> 1, qg = (q.g + c->g) >> 1, qb = (q.b + c->b) >> 1;  \
+  pix[y0 + x0].r = qr; \
+  pix[y0 + x0].g = qg; \
+  pix[y0 + x0].b = qb;
+#include "dmdrawline.h"
+
+
+
+
+#define DM_DRAWLINE_NAME dmDrawLine8Saturate
+#define DM_DRAWLINE_DST_BYTES 1
+#define DM_DRAWLINE_DST_TYPE Uint8
+#define DM_DRAWLINE_INNER \
+  const int q = pix[y0 + x0] + col; \
+  pix[y0 + x0] = q < 255 ? q : 255;
+#include "dmdrawline.h"
+
+
+#define DM_DRAWLINE_NAME dmDrawLine32Saturate
+#define DM_DRAWLINE_DST_BYTES 4
+#define DM_DRAWLINE_DST_TYPE DMRGBA32
+#define DM_DRAWLINE_INIT const DMRGBA32 *c = (DMRGBA32*) &col;
+#define DM_DRAWLINE_INNER \
+  const DMRGBA32 q = pix[y0 + x0]; \
+  const int qr = q.r + c->r, qg = q.g + c->g, qb = q.b + c->b;  \
+  pix[y0 + x0].r = qr < 255 ? qr : 255; \
+  pix[y0 + x0].g = qg < 255 ? qg : 255; \
+  pix[y0 + x0].b = qb < 255 ? qb : 255;
+#include "dmdrawline.h"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmmutex.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,33 @@
+/*
+ * DMLib
+ * -- Bogus implementations of SDL mutex functions
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012 Tecnic Software productions (TNSP)
+ */
+
+Uint32 SDL_ThreadID()
+{
+    return 0;
+}
+
+int SDL_mutexP(SDL_mutex *p)
+{
+    (void) p;
+    return 0;
+}
+
+int SDL_mutexV(SDL_mutex *p)
+{
+    (void) p;
+    return 0;
+}
+
+SDL_mutex * SDL_CreateMutex()
+{
+    return NULL;
+}
+
+void SDL_DestroyMutex(SDL_mutex *p)
+{
+    (void) p;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmpack.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,191 @@
+/*
+ * DMLib
+ * -- PACK-file handling
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2011 Tecnic Software productions (TNSP)
+ */
+#include "dmpack.h"
+#include "dmfile.h"
+
+
+DMPackEntry *dmPackEntryNew()
+{
+    return (DMPackEntry *) dmMalloc0(sizeof(DMPackEntry));
+}
+
+
+void dmPackEntryFree(DMPackEntry * node)
+{
+    dmFree(node);
+}
+
+
+void dmPackEntryInsert(DMPackEntry ** packDir, DMPackEntry * node)
+{
+    if (*packDir != NULL)
+    {
+        node->prev = (*packDir)->prev;
+        (*packDir)->prev->next = node;
+        (*packDir)->prev = node;
+    }
+    else
+    {
+        *packDir = node->prev = node;
+    }
+    
+    node->next = NULL;
+}
+
+
+void dmPackEntryDelete(DMPackEntry ** packDir, DMPackEntry * node)
+{
+    if (node->prev)
+        node->prev->next = node->next;
+
+    if (node->next)
+        node->next->prev = node->prev;
+    else
+        (*packDir)->prev = node->prev;
+
+    node->prev = node->next = NULL;
+}
+
+
+DMPackEntry *dmPackFind(DMPackEntry *list, const char *filename)
+{
+    DMPackEntry *node;
+
+    for (node = list; node != NULL; node = node->next)
+    {
+        if (strcmp(node->filename, filename) == 0)
+            return node;
+    }
+
+    return NULL;
+}
+
+
+/*
+ * OPEN a packfile
+ */
+int dmPackOpen(const char *filename, DMPackFile ** ppPack, BOOL readOnly)
+{
+    unsigned int i;
+    DMPackFile *pack;
+    DMPackFileHeader hdr;
+
+    *ppPack = NULL;
+
+    // Allocate packfile-structure
+    pack = (DMPackFile *) dmMalloc0(sizeof(DMPackFile));
+    if (pack == NULL)
+        return DMERR_MALLOC;
+
+    // Open the file
+    pack->file = fopen(filename, readOnly ? "rb" : "r+b");
+    if (pack->file == NULL)
+    {
+        dmFree(pack);
+        return DMERR_FOPEN;
+    }
+
+    pack->filename = dm_strdup(filename);
+
+    // Read PACK header
+    fseek(pack->file, 0L, SEEK_SET);
+    if (!dm_fread_str(pack->file, (Uint8 *) &hdr.ident, sizeof(hdr.ident)) ||
+        !dm_fread_le16(pack->file, &hdr.version) ||
+        !dm_fread_le32(pack->file, &hdr.dirEntries) ||
+        !dm_fread_le32(pack->file, &hdr.dirOffset))
+    {
+        dmPackClose(pack);
+        return DMERR_FREAD;
+    }
+
+    // Check information
+    if (memcmp(&hdr.ident, DPACK_IDENT, sizeof(hdr.ident)) != 0)
+    {
+        dmPackClose(pack);
+        return DMERR_NOTPACK;
+    }
+
+    if (hdr.version != DPACK_VERSION)
+    {
+        dmPackClose(pack);
+        return DMERR_VERSION;
+    }
+
+    // Read directory
+    if (fseek(pack->file, hdr.dirOffset, SEEK_SET) != 0)
+    {
+        dmPackClose(pack);
+        return DMERR_INVALID;
+    }
+
+    for (i = 0; i < hdr.dirEntries; i++)
+    {
+        // Allocate and read directory entry
+        DMPackEntry *entry = dmPackEntryNew();
+
+        if (entry == NULL)
+        {
+            dmPackClose(pack);
+            return DMERR_MALLOC;
+        }
+
+        if (!dm_fread_str(pack->file, (Uint8 *) &entry->filename, sizeof(entry->filename)) ||
+            !dm_fread_le32(pack->file, &entry->size) ||
+            !dm_fread_le32(pack->file, &entry->offset) ||
+            !dm_fread_le32(pack->file, &entry->length) ||
+            !dm_fread_le32(pack->file, &entry->flags))
+        {
+            *ppPack = pack;
+            return DMERR_FREAD;
+        }
+
+        // Insert into list
+        dmPackEntryInsert(&pack->entries, entry);
+    }
+
+    // Set the result
+    *ppPack = pack;
+    return DMERR_OK;
+}
+
+
+/*
+ * CLOSE the packfile
+ */
+int dmPackClose(DMPackFile * pack)
+{
+    DMPackEntry *node;
+
+    if (pack == NULL)
+        return DMERR_OK;
+
+    // Write the directory
+    node = pack->entries;
+    while (node != NULL)
+    {
+        DMPackEntry *next = node->next;
+        dmPackEntryFree(node);
+        node = next;
+    }
+
+    // Close the file
+    if (pack->file != NULL)
+    {
+        fclose(pack->file);
+        pack->file = NULL;
+    }
+
+    // Free structures
+    dmFree(pack->filename);
+    pack->filename = NULL;
+
+    // Free packfile
+    pack->entries = NULL;
+    dmFree(pack);
+
+    return DMERR_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmpack.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,59 @@
+/*
+ * DMLib
+ * -- PACK-file routines
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2011 Tecnic Software productions (TNSP)
+ */
+#ifndef DMPACK_H
+#define DMPACK_H
+#include "dmlib.h"
+
+
+#define	DPACK_IDENT     "TNSPDPCK"      // Magic ident
+#define	DPACK_VERSION   (0x0120)        // Version
+#define	DPACK_TMPSIZE   (128 * 1024)
+
+
+typedef struct _DMPackEntry
+{
+    char    filename[DMRES_NAME_LEN];
+    Uint32  size;              // Size (UNCOMPRESSED)
+    Uint32  offset;            // Offset in pack file
+    Uint32  length;            // (Compressed) data length
+
+    Uint32  flags, privFlags;
+    
+    struct _DMPackEntry *next, *prev;
+} DMPackEntry;
+
+
+typedef struct
+{
+    DMPackEntry *entries;
+    char *  filename;          // Filename & path
+    FILE *  file;              // File
+} DMPackFile;
+
+
+typedef struct
+{
+    char    ident[8];          // Magic identifier
+    Uint16  version;           // Version
+    Uint32  dirEntries;        // Number of entries
+    Uint32  dirOffset;         // Offset of the directory
+} DMPackFileHeader;
+
+
+DMPackEntry *  dmPackEntryNew();
+void           dmPackEntryFree(DMPackEntry *);
+void           dmPackEntryInsert(DMPackEntry **, DMPackEntry *);
+void           dmPackEntryDelete(DMPackEntry **, DMPackEntry *);
+
+DMPackEntry *  dmPackFind(DMPackEntry *list, const char *filename);
+
+int            dmPackOpen(const char *, DMPackFile **, BOOL);
+int            dmPackClose(DMPackFile *);
+int            dmPackRead(DMPackFile *, const char *, Uint8 **, size_t *);
+
+
+#endif // DMPACK_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmpackutil.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,313 @@
+/*
+ * DMLib
+ * -- PACK-file additional utility routines
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2011 Tecnic Software productions (TNSP)
+ */
+#include "dmpackutil.h"
+#include <zlib.h>
+#include "dmfile.h"
+
+
+DMPackEntry *dmPackEntryCopy(const DMPackEntry *src)
+{
+    DMPackEntry *node = dmPackEntryNew();
+    if (node == NULL)
+        return NULL;
+
+    strncpy(node->filename, src->filename, sizeof(node->filename));
+    node->filename[sizeof(node->filename) - 1] = 0;
+
+    node->size     = src->size;
+    node->offset   = src->offset;
+    node->length   = src->length;
+    node->flags    = src->flags;
+
+    return node;
+}
+
+
+/*
+ * CLOSE/WRITE the packfile
+ */
+int dmPackWrite(DMPackFile * pack)
+{
+    DMPackEntry *node;
+    DMPackFileHeader hdr;
+
+    if (pack == NULL)
+        return DMERR_OK;
+
+    if (pack->file == NULL)
+        return DMERR_FOPEN;
+
+    // Compute directory offset and number of entries
+    memcpy(&hdr.ident, DPACK_IDENT, sizeof(hdr.ident));
+    hdr.version = DPACK_VERSION;
+    hdr.dirEntries = 0;
+    hdr.dirOffset =
+        sizeof(hdr.ident) + sizeof(hdr.version) +
+        sizeof(hdr.dirEntries) + sizeof(hdr.dirOffset);
+
+    node = pack->entries;
+    while (node != NULL)
+    {
+        hdr.dirEntries++;
+        hdr.dirOffset += node->length;
+        node = node->next;
+    }
+
+    // Write PACK header
+    if (fseek(pack->file, 0L, SEEK_SET) != 0)
+        return DMERR_FSEEK;
+
+    if (!dm_fwrite_str(pack->file, (Uint8 *) & hdr.ident, sizeof(hdr.ident)) ||
+        !dm_fwrite_le16(pack->file, hdr.version) ||
+        !dm_fwrite_le32(pack->file, hdr.dirEntries) ||
+        !dm_fwrite_le32(pack->file, hdr.dirOffset))
+        return DMERR_FWRITE;
+
+    // Write the directory
+    if (fseek(pack->file, hdr.dirOffset, SEEK_SET) != 0)
+        return DMERR_FSEEK;
+
+    node = pack->entries;
+    while (node != NULL)
+    {
+        // Write one entry
+        if (!dm_fwrite_str(pack->file, node->filename, sizeof(node->filename)) ||
+            !dm_fwrite_le32(pack->file, node->size) ||
+            !dm_fwrite_le32(pack->file, node->offset) ||
+            !dm_fwrite_le32(pack->file, node->length) ||
+            !dm_fwrite_le32(pack->file, node->flags))
+            return DMERR_FWRITE;
+
+        node = node->next;
+    }
+
+    return DMERR_OK;
+}
+
+
+/*
+ * CREATE a packfile, for writing
+ */
+int dmPackCreate(const char *filename, DMPackFile ** pack)
+{
+    // Allocate packfile-structure
+    *pack = (DMPackFile *) dmCalloc(1, sizeof(DMPackFile));
+    if (*pack == NULL)
+        return DMERR_MALLOC;
+
+    // Open the file
+    (*pack)->file = fopen(filename, "wb");
+    if ((*pack)->file == NULL)
+    {
+        dmFree(*pack);
+        return DMERR_FOPEN;
+    }
+
+    (*pack)->filename = dm_strdup(filename);
+
+    // Set the result
+    return DMERR_OK;
+}
+
+
+/*
+ * ADD a file into the PACK
+ */
+int dmPackAddFile(DMPackFile * pack, const char *filename,
+    BOOL doCompress, const Uint32 flags, DMPackEntry ** ppEntry)
+{
+    z_stream zstr;
+    off_t startOffs;
+    unsigned int zstrSize;
+    FILE *inFile;
+    Uint8 *inBuffer, *outBuffer;
+    DMPackEntry entry, *node;
+    int result;
+
+    *ppEntry = NULL;
+
+    if (pack == NULL)
+        return DMERR_OK;
+
+    if (pack->file == NULL)
+        return DMERR_FOPEN;
+
+    // Compute starting offset
+    startOffs = sizeof(DMPackFileHeader);
+    node = pack->entries;
+    while (node != NULL)
+    {
+        startOffs += node->length;
+        node = node->next;
+    }
+
+    // Seek to the position
+    if (fseek(pack->file, startOffs, SEEK_SET) != 0)
+        return DMERR_INVALID;
+
+    // Read file data
+    if ((inFile = fopen(filename, "rb")) == NULL)
+        return -1;
+
+    // Allocate temporary buffer
+    inBuffer = (Uint8 *) dmMalloc(DPACK_TMPSIZE);
+    if (!inBuffer)
+    {
+        fclose(inFile);
+        return DMERR_MALLOC;
+    }
+
+    outBuffer = (Uint8 *) dmMalloc(DPACK_TMPSIZE);
+    if (!outBuffer)
+    {
+        dmFree(inBuffer);
+        fclose(inFile);
+        return DMERR_MALLOC;
+    }
+
+    // Read (and possibly compress) the data
+    zstrSize = 0;
+    zstr.zalloc = (alloc_func) Z_NULL;
+    zstr.zfree = (free_func) Z_NULL;
+    zstr.opaque = (voidpf) Z_NULL;
+    result = deflateInit(&zstr, (doCompress) ? Z_DEFAULT_COMPRESSION : 0);
+    if (result != Z_OK)
+    {
+        dmFree(inBuffer);
+        dmFree(outBuffer);
+        fclose(inFile);
+        return DMERR_COMPRESSION;
+    }
+
+    // Initialize compression streams
+    result = Z_OK;
+    while (!feof(inFile) && result == Z_OK)
+    {
+        zstr.avail_in = fread(inBuffer, sizeof(Uint8), DPACK_TMPSIZE, inFile);
+        zstr.next_in = inBuffer;
+        zstr.next_out = outBuffer;
+        zstr.avail_out = DPACK_TMPSIZE;
+        zstr.total_out = 0;
+        result = deflate(&zstr, Z_FULL_FLUSH);
+
+        if (result == Z_OK && zstr.total_out > 0)
+        {
+            zstrSize += zstr.total_out;
+            fwrite(outBuffer, sizeof(Uint8), zstr.total_out, pack->file);
+        }
+    }
+
+    // Create directory entry
+    strncpy(entry.filename, filename, sizeof(entry.filename));
+    entry.filename[sizeof(entry.filename) - 1] = 0;
+    entry.size   = zstr.total_in;
+    entry.offset = startOffs;
+    entry.length = zstrSize;
+    entry.flags  = flags;
+
+    // Cleanup
+    deflateEnd(&zstr);
+    dmFree(inBuffer);
+    dmFree(outBuffer);
+    fclose(inFile);
+
+    // Add directory entry
+    if ((*ppEntry = dmPackEntryCopy(&entry)) == NULL)
+        return DMERR_MALLOC;
+
+    dmPackEntryInsert(&pack->entries, *ppEntry);
+
+    return DMERR_OK;
+}
+
+
+/*
+ * EXTRACT a file from the PACK
+ */
+int dmPackExtractFile(DMPackFile *pack, DMPackEntry * entry)
+{
+    z_stream zstr;
+    FILE *outFile;
+    Uint8 *inBuffer, *outBuffer;
+    size_t inDataLeft;
+    int ret;
+
+    if (pack == NULL)
+        return DMERR_OK;
+
+    if (pack->file == NULL)
+        return DMERR_FOPEN;
+
+    // Seek to the position
+    if (fseek(pack->file, entry->offset, SEEK_SET) != 0)
+        return DMERR_INVALID;
+
+    // Open destination file
+    if ((outFile = fopen(entry->filename, "wb")) == NULL)
+        return -1;
+
+    // Allocate temporary buffer
+    if ((inBuffer = (Uint8 *) dmMalloc(DPACK_TMPSIZE)) == NULL)
+    {
+        fclose(outFile);
+        return DMERR_MALLOC;
+    }
+
+    if ((outBuffer = (Uint8 *) dmMalloc(DPACK_TMPSIZE)) == NULL)
+    {
+        dmFree(inBuffer);
+        fclose(outFile);
+        return DMERR_MALLOC;
+    }
+
+    // Read and uncompress the data
+    zstr.zalloc = (alloc_func) Z_NULL;
+    zstr.zfree = (free_func) Z_NULL;
+    zstr.opaque = (voidpf) Z_NULL;
+    ret = inflateInit(&zstr);
+    if (ret != Z_OK)
+    {
+        dmFree(inBuffer);
+        dmFree(outBuffer);
+        fclose(outFile);
+        return DMERR_COMPRESSION;
+    }
+
+    // Initialize compression streams
+    inDataLeft = entry->length;
+    ret = Z_OK;
+    while (inDataLeft > 0 && ret == Z_OK)
+    {
+        if (inDataLeft >= DPACK_TMPSIZE)
+            zstr.avail_in = fread(inBuffer, sizeof(Uint8), DPACK_TMPSIZE, pack->file);
+        else
+            zstr.avail_in = fread(inBuffer, sizeof(Uint8), inDataLeft, pack->file);
+
+        inDataLeft -= zstr.avail_in;
+        zstr.next_in = inBuffer;
+
+        while (zstr.avail_in > 0 && ret == Z_OK)
+        {
+            zstr.next_out = outBuffer;
+            zstr.avail_out = DPACK_TMPSIZE;
+            zstr.total_out = 0;
+            ret = inflate(&zstr, Z_FULL_FLUSH);
+            if (zstr.total_out > 0)
+            {
+                fwrite(outBuffer, sizeof(Uint8), zstr.total_out, outFile);
+            }
+        }
+    }
+
+    // Cleanup
+    inflateEnd(&zstr);
+    dmFree(inBuffer);
+    dmFree(outBuffer);
+    fclose(outFile);
+
+    return DMERR_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmpackutil.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,17 @@
+/*
+ * DMLib
+ * -- PACK-file additional utility routines
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2011 Tecnic Software productions (TNSP)
+ */
+#ifndef DMPACKUTIL_H
+#define DMPACKUTIL_H
+#include "dmpack.h"
+
+DMPackEntry *  dmPackEntryCopy(const DMPackEntry *);
+int            dmPackWrite(DMPackFile *);
+int            dmPackCreate(const char *, DMPackFile **);
+int            dmPackAddFile(DMPackFile *, const char *, BOOL, const Uint32 flags, DMPackEntry **);
+int            dmPackExtractFile(DMPackFile *, DMPackEntry *);
+
+#endif // DMPACKUTIL_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmperlin.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,134 @@
+/*
+ * Coherent noise function over 1 or 2 dimensions.
+ */
+#include "dmlib.h"
+#include <math.h>
+
+#define B	(0x100)
+#define BM	(0x0ff)
+#define NP	(12)
+#define N	(0x1000)
+#define NM 	(0x0fff)
+
+
+#define DM_PERLIN_SETUP(i, b0, b1, r0, r1) \
+{				\
+    t = (vec[i] + N);		\
+    b0 = (((int) t) & BM);	\
+    b1 = ((b0 + 1) & BM);	\
+    r0 = (t - ((int) t));	\
+    r1 = (r0 - 1.0f);		\
+}
+        
+
+#define DM_PERLIN_AT2(rx,ry) ((rx) * q[0] + (ry) * q[1])
+
+
+static int p[B + B + 2];
+static DMFloat g2[B + B + 2][2];
+static DMFloat g1[B + B + 2];
+
+
+static DMFloat dmPerlinDoNoise2(DMFloat vec[2])
+{
+    int bx0, bx1, by0, by1, b00, b10, b01, b11;
+    DMFloat rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v;
+    int i, j;
+
+    DM_PERLIN_SETUP(0, bx0, bx1, rx0, rx1);
+    DM_PERLIN_SETUP(1, by0, by1, ry0, ry1);
+
+    i = p[bx0];
+    j = p[bx1];
+
+    b00 = p[i + by0];
+    b10 = p[j + by0];
+    b01 = p[i + by1];
+    b11 = p[j + by1];
+
+    sx = DMM_S_CURVE(rx0);
+    sy = DMM_S_CURVE(ry0);
+
+    q = g2[b00];
+    u = DM_PERLIN_AT2(rx0, ry0);
+    q = g2[b10];
+    v = DM_PERLIN_AT2(rx1, ry0);
+    a = DMM_LERP(sx, u, v);
+
+    q = g2[b01];
+    u = DM_PERLIN_AT2(rx0, ry1);
+    q = g2[b11];
+    v = DM_PERLIN_AT2(rx1, ry1);
+    b = DMM_LERP(sx, u, v);
+
+    return DMM_LERP(sy, a, b);
+}
+
+
+static void dmPerlinNormalize2(DMFloat v[2])
+{
+    DMFloat s = sqrt(v[0] * v[0] + v[1] * v[1]);
+    v[0] /= s;
+    v[1] /= s;
+}
+
+
+void dmPerlinInit(void)
+{
+    int i, j, k;
+
+    srand(32);
+    
+    for (i = 0; i < B; i++)
+    {
+        p[i] = i;
+        g1[i] = (DMFloat) ((rand() % (B + B)) - B) / B;
+
+        for (j = 0; j < 2; j++)
+            g2[i][j] = (DMFloat) ((rand() % (B + B)) - B) / B;
+
+        dmPerlinNormalize2(g2[i]);
+    }
+
+    while (--i)
+    {
+        k = p[i];
+        p[i] = p[j = rand() % B];
+        p[j] = k;
+    }
+
+    for (i = 0; i < B + 2; i++)
+    {
+        p[B + i] = p[i];
+        g1[B + i] = g1[i];
+
+        for (j = 0; j < 2; j++)
+            g2[B + i][j] = g2[i][j];
+    }
+}
+
+
+/* Harmonic summing functions - PDB
+ * In what follows "alpha" is the weight when the sum is formed.
+ * Typically it is 2, As this approaches 1 the function is noisier.
+ * "beta" is the harmonic scaling/spacing, typically 2.
+ */
+DMFloat dmPerlinNoise2D(DMFloat x, DMFloat y, DMFloat alpha, DMFloat beta, int n)
+{
+    int i;
+    DMFloat val, sum = 0;
+    DMFloat p[2], scale = 1;
+
+    p[0] = x;
+    p[1] = y;
+    for (i = 0; i < n; i++)
+    {
+        val = dmPerlinDoNoise2(p);
+        sum += val / scale;
+        scale *= alpha;
+        p[0] *= beta;
+        p[1] *= beta;
+    }
+
+    return sum;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmq3d.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,408 @@
+#include "dmlib.h"
+#include "dmq3d.h"
+#include "dmimage.h"
+
+
+#define DM_DRAWLINE_NAME dmDrawLineSpec
+#define DM_DRAWLINE_DST_BYTES 4
+#define DM_DRAWLINE_DST_TYPE DMRGBA32
+#define DM_DRAWLINE_ARGS , SDL_Surface *bmp
+#define DM_DRAWLINE_INIT const int px = bmp->w / 2, py = bmp->h / 2;
+#define DM_DRAWLINE_INNER \
+     dmUnscaledBlitSurface32to32Transparent(bmp, x0-px, y0-py, screen);
+#define DM_DRAWLINE_SPEC
+#include "dmdrawline.h"
+
+
+static int dmFind3DBitmap(int nitems, DM3DBitmap *items, DM3DBitmap *item)
+{
+    int i;
+    for (i = 0; i < nitems; i++)
+    if (strcmp(item->name, items[i].name) == 0)
+        return i;
+    return -1;
+}
+
+#define DM_FIND_ITEM_FUNC(NAME, TYPE) \
+static int dmFind3D ## NAME (int nitems, TYPE *items, TYPE *item) \
+{ \
+    int i; \
+    for (i = 0; i < nitems; i++) \
+    if (memcmp(item, items+i, sizeof(TYPE)) == 0) \
+        return i; \
+    return -1; \
+}
+
+#define DM_ADD_ITEM_FUNC(NAME, TYPE) \
+static int dmAdd3D ## NAME (int *nitems, int *nalloc, TYPE **items, TYPE *item, int *res) \
+{ \
+    int tmp; \
+    if ((tmp = dmFind3D ## NAME (*nitems, *items, item)) >= 0) \
+    { \
+        if (res != NULL) *res = tmp; \
+        return DMERR_OK; \
+    } \
+    if ((*nitems) + 1 >= *nalloc) \
+    { \
+        (*nalloc) += 16; \
+        if ((*items = dmRealloc(*items, *nalloc * sizeof(TYPE))) == NULL) \
+        { \
+            dmError("Error allocating memory for " # TYPE ".\n"); \
+            return DMERR_MALLOC; \
+        } \
+    } \
+    memcpy((*items) + (*nitems), item, sizeof(TYPE)); \
+    if (res != NULL) *res = *nitems; \
+    (*nitems)++; \
+    return DMERR_OK; \
+}
+
+DM_FIND_ITEM_FUNC(Vertex, DMVector)
+DM_FIND_ITEM_FUNC(Vector, DM3DVector)
+DM_FIND_ITEM_FUNC(Sprite, DM3DSprite)
+
+DM_ADD_ITEM_FUNC(Vertex, DMVector)
+DM_ADD_ITEM_FUNC(Vector, DM3DVector)
+DM_ADD_ITEM_FUNC(Sprite, DM3DSprite)
+DM_ADD_ITEM_FUNC(Bitmap, DM3DBitmap)
+
+
+int dmAdd3DVectorSpriteModelVertex(DM3DVectorSpriteModel *model, DMVector *v, int *index)
+{
+    return dmAdd3DVertex(&model->nvertices, &model->nvertexalloc,
+         &model->vertices, v, index);
+}
+
+int dmAdd3DVectorSpriteModelVector(DM3DVectorSpriteModel *model, DM3DVector *v, int *index)
+{
+    return dmAdd3DVector(&model->nlines, &model->nlinesalloc,
+         &model->lines, v, index);
+}
+
+int dmAdd3DVectorSpriteModelSprite(DM3DVectorSpriteModel *model, DM3DSprite *v, int *index)
+{
+    return dmAdd3DSprite(&model->nsprites, &model->nspritesalloc,
+         &model->sprites, v, index);
+}
+
+int dmAdd3DVectorSpriteModelBitmap(DM3DVectorSpriteModel *model, DM3DBitmap *v, int *index)
+{
+    return dmAdd3DBitmap(&model->nbitmaps, &model->nbitmapsalloc,
+         &model->bitmaps, v, index);
+}
+
+
+static inline DMFloat dmPX(int cx, DMVector p)
+{
+    return cx + (p.x * 250.0f) / p.z;
+}
+
+
+static inline DMFloat dmPY(int cy, DMVector p)
+{
+    return cy + (p.y * 250.0f) / p.z;
+}
+
+
+void dmDraw3DVectorSpriteModel(SDL_Surface *screen, const DM3DVectorSpriteModel *model, const DMVector *pos, const DMMatrix *mat, SDL_Surface *fbmap, const Uint32 lcol)
+{
+    int i;
+    int cx = screen->w / 2, cy = screen->h / 2;
+    for (i = 0; i < model->nlines; i++)
+    {
+        DM3DVector *line = &model->lines[i];
+        DMVector pv[2];
+        dm_vector_copy(&pv[0], &model->vertices[line->v1]);
+        dm_vector_copy(&pv[1], &model->vertices[line->v2]);
+        dm_vector_mul_by_mat_n(pv, 2, mat);
+        dm_vector_add(&pv[0], pos);
+        dm_vector_add(&pv[1], pos);
+        
+        if (pv[0].z <= 0 && pv[1].z <= 0)
+            continue;
+
+        if (line->type > 1)
+            dmDrawLineSpec(screen, dmPX(cx, pv[0]), dmPY(cy, pv[0]), dmPX(cx, pv[1]), dmPY(cy, pv[1]), lcol, fbmap);
+        else
+            dmDrawLine32(screen, dmPX(cx, pv[0]), dmPY(cy, pv[0]), dmPX(cx, pv[1]), dmPY(cy, pv[1]), lcol);
+    }
+
+    for (i = 0; i < model->nsprites; i++)
+    {
+        DM3DSprite *sprite = &model->sprites[i];
+        DM3DBitmap *bmp = &model->bitmaps[sprite->bitmap];
+        DMVector pv;
+        dm_vector_mul_by_mat(&pv, &model->vertices[sprite->v], mat);
+        dm_vector_add(&pv, pos);
+        if (pv.z <= 0)
+            continue;
+        dmUnscaledBlitSurface32to32Transparent(bmp->img, dmPX(cx, pv), dmPY(cy, pv), screen);
+    }
+}
+
+
+static char *dmSkipWhitespace(char *line, BOOL invert)
+{
+    if (invert)
+        for (; *line && !isspace(*line); line++);
+    else
+        for (; *line && isspace(*line); line++);
+    return line;
+}
+
+
+static char *dmSkipUntil(char *line, char ch)
+{
+    for (; *line && *line != ch; line++);
+    return line;
+}
+
+
+static BOOL dmReadCoordinate(const char *orig, char **line, float *value, BOOL next)
+{
+    *line = dmSkipWhitespace(*line, FALSE);
+    if (sscanf(*line, "%f", value) != 1)
+    {
+        dmError("Expected floating point value @ %d:\n%s\n", (*line - orig), orig);
+        return FALSE;
+    }
+    if (next)
+    {
+        *line = dmSkipUntil(*line, ',');
+        if (**line != ',')
+        {
+            dmError("Expected comma @ %d:\n%s\n", (*line - orig), orig);
+            return FALSE;
+        }
+        *(*line)++;
+    }
+    else
+        *line = dmSkipWhitespace(*line, TRUE);
+
+    return TRUE;
+}
+
+
+static BOOL dmReadVectorSegments(char *line, DM3DVectorSpriteModel *model, BOOL relative, const DMVector *pt)
+{
+    DMVector v, p, *t;
+    int nvertices, vertex, type;
+    int *indices = NULL;
+    char *ptr = line;
+    
+    if (sscanf(ptr+1, "%d", &nvertices) != 1)
+    {
+        dmError("No # of segments @ '%s'\n", ptr);
+        goto error;
+    }
+    
+    if ((indices = dmMalloc(sizeof(int) * (nvertices+1))) == NULL)
+        goto error;
+    
+    ptr = dmSkipWhitespace(ptr, TRUE);
+    dm_vector_copy(&v, pt);
+    for (vertex = 0; vertex <= nvertices; vertex++)
+    {
+        if (*ptr == 'Z')
+        {
+            indices[vertex] = indices[0];
+            ptr++;
+        }
+        else
+        {
+            if (!dmReadCoordinate(line, &ptr, &p.x, TRUE)) return FALSE;
+            if (!dmReadCoordinate(line, &ptr, &p.y, TRUE)) return FALSE;
+            if (!dmReadCoordinate(line, &ptr, &p.z, FALSE)) return FALSE;
+            if (relative)
+            {
+                dm_vector_add(&v, &p);
+                t = &v;
+            }
+            else
+            {
+                dm_vector_add_r(&v, &p, pt);
+                t = &v;
+            }
+
+            if (dmAdd3DVectorSpriteModelVertex(model, t, &indices[vertex]) != DMERR_OK)
+                goto error;
+        }
+
+        ptr = dmSkipWhitespace(ptr, FALSE);
+    }
+    
+    if (sscanf(ptr, "%d", &type) != 1)
+    {
+        dmError("No line type @ '%s'\n", ptr);
+        goto error;
+    }
+    
+    for (vertex = 1; vertex <= nvertices; vertex++)
+    {
+        DM3DVector vec;
+        vec.v1 = indices[vertex - 1];
+        vec.v2 = indices[vertex];
+        vec.type = type;
+        if (dmAdd3DVectorSpriteModelVector(model, &vec, NULL) != DMERR_OK)
+            goto error;
+    }
+
+    return TRUE;
+
+error:
+    dmFree(indices);
+    return FALSE;
+}
+
+
+static BOOL dmReadSprite(char *line, DM3DVectorSpriteModel *model, DMVector *pos)
+{
+    DMVector pt;
+    DM3DSprite spr;
+    char *ptr = line;
+
+    ptr++;
+    if (!dmReadCoordinate(line, &ptr, &pt.x, TRUE)) return FALSE;
+    if (!dmReadCoordinate(line, &ptr, &pt.y, TRUE)) return FALSE;
+    if (!dmReadCoordinate(line, &ptr, &pt.z, FALSE)) return FALSE;
+    ptr = dmSkipWhitespace(ptr, FALSE);
+    if (*ptr != 'B')
+    {
+        dmError("No bitmap definition found for sprite.\n");
+        return FALSE;
+    }
+
+    spr.bitmap = atoi(ptr + 1);
+
+    dm_vector_add(&pt, pos);
+    if (dmAdd3DVectorSpriteModelVertex(model, &pt, &spr.v) != DMERR_OK)
+        return FALSE;
+
+    if (dmAdd3DVectorSpriteModelSprite(model, &spr, NULL) != DMERR_OK)
+        return FALSE;
+
+    return TRUE;
+}
+
+static BOOL dmReadBitmap(char *line, DM3DVectorSpriteModel *model, DMResourceLib *lib)
+{
+    DM3DBitmap bmp, *rbmp;
+    int index;
+    char *ptr = line;
+
+    strncpy(bmp.name, ptr + 1, sizeof(bmp.name));
+    bmp.img = NULL;
+
+    if (dmAdd3DVectorSpriteModelBitmap(model, &bmp, &index) != DMERR_OK)
+        return FALSE;
+
+    rbmp = &(model->bitmaps[index]);
+    if (rbmp->img == NULL)
+    {
+        DMResource *fh;
+        int res;
+        if ((res = dmf_open(lib, rbmp->name, &fh)) != DMERR_OK)
+        {
+            dmError("Could not open resource file '%s', #%d: %s.\n",
+                rbmp->name, res, dmErrorStr(res));
+            return FALSE;
+        }
+        rbmp->img = dmLoadImage(fh);
+        dmf_close(fh);
+        if (rbmp->img == NULL)
+        {
+            dmError("Could not load image file '%s'.\n", rbmp->name);
+            return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+
+
+static int dmDoRead3DVectorSpriteModel(DMResource *f, DM3DVectorSpriteModel *model, DMVector *pos)
+{
+    char line[8192];
+
+    while (dmfgets(line, sizeof(line), f) != NULL)
+    {
+        char *start = dmSkipWhitespace(line, FALSE);
+        switch (*start)
+        {
+            case 0:
+            case '#':
+                break;
+            
+            case 'G':
+                {
+                int res;
+                DMVector pt;
+                start++;
+                if (!dmReadCoordinate(line, &start, &pt.x, TRUE)) return DMERR_INVALID_DATA;
+                if (!dmReadCoordinate(line, &start, &pt.y, TRUE)) return DMERR_INVALID_DATA;
+                if (!dmReadCoordinate(line, &start, &pt.z, FALSE)) return DMERR_INVALID_DATA;
+                dm_vector_add_r(&pt, pos, &pt);
+                if ((res = dmDoRead3DVectorSpriteModel(f, model, &pt)) != DMERR_OK)
+                    return res;
+                }
+                break;
+            
+            case 'E':
+                return DMERR_OK;
+
+            case 'B':
+                if (!dmReadBitmap(start, model, f->lib))
+                    return DMERR_INVALID_DATA;
+                break;
+
+            case 'L':
+                if (!dmReadVectorSegments(start, model, FALSE, pos))
+                    return DMERR_INVALID_DATA;
+                break;
+
+            case 'R':
+                if (!dmReadVectorSegments(start, model, TRUE, pos))
+                    return DMERR_INVALID_DATA;
+                break;
+            
+            case 'S':
+                if (!dmReadSprite(start, model, pos))
+                    return DMERR_INVALID_DATA;
+                break;
+            
+            default:
+                break;
+        }
+    }
+    return DMERR_OK;
+}
+
+
+int dmRead3DVectorSpriteModel(DMResource *f, DM3DVectorSpriteModel **model)
+{
+    DMVector pos;
+
+    if ((*model = dmMalloc0(sizeof(DM3DVectorSpriteModel))) == NULL)
+        return DMERR_MALLOC;
+
+    memset(&pos, 0, sizeof(pos));
+    
+    return dmDoRead3DVectorSpriteModel(f, *model, &pos);
+}
+
+
+void dmFree3DVectorSpriteModel(DM3DVectorSpriteModel *model)
+{
+    int i;
+    for (i = 0; i < model->nbitmaps; i++)
+    {
+        if (model->bitmaps[i].img != NULL)
+            SDL_FreeSurface(model->bitmaps[i].img);
+    }
+
+    dmFree(model->bitmaps);
+    dmFree(model->vertices);
+    dmFree(model->lines);
+    dmFree(model->sprites);
+    dmFree(model);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmq3d.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,69 @@
+/*
+ * DMLib
+ * -- Whatever
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012 Tecnic Software productions (TNSP)
+ */
+#ifndef DMQ3D_H
+#define DMQ3D_H
+
+#include "dmlib.h"
+#include "dmvecmat.h"
+#include "dmres.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct
+{
+    int v1, v2, type;
+} DM3DVector;
+
+
+typedef struct
+{
+    int v, bitmap;
+} DM3DSprite;
+
+
+typedef struct
+{
+    char name[64];
+    SDL_Surface *img;
+} DM3DBitmap;
+
+
+typedef struct
+{
+    int nvertices, nvertexalloc;
+    DMVector *vertices;
+
+    int nlines, nlinesalloc;
+    DM3DVector *lines;
+
+    int nbitmaps, nbitmapsalloc;
+    DM3DBitmap *bitmaps;
+    
+    int nsprites, nspritesalloc;
+    DM3DSprite *sprites;
+} DM3DVectorSpriteModel;
+
+
+int dmAdd3DVectorSpriteModelVertex(DM3DVectorSpriteModel *model, DMVector *v, int *index);
+int dmAdd3DVectorSpriteModelVector(DM3DVectorSpriteModel *model, DM3DVector *v, int *index);
+int dmAdd3DVectorSpriteModelSprite(DM3DVectorSpriteModel *model, DM3DSprite *v, int *index);
+int dmAdd3DVectorSpriteModelBitmap(DM3DVectorSpriteModel *model, DM3DBitmap *v, int *index);
+
+int dmRead3DVectorSpriteModel(DMResource *f, DM3DVectorSpriteModel **model);
+void dmFree3DVectorSpriteModel(DM3DVectorSpriteModel *model);
+
+void dmDraw3DVectorSpriteModel(SDL_Surface *screen, const DM3DVectorSpriteModel *model, const DMVector *pos, const DMMatrix *mat, SDL_Surface *fbmap, const Uint32 lcol);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DMQ3D_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmres.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,1177 @@
+/*
+ * dmlib
+ * -- Resource management
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2003-2013 Tecnic Software productions (TNSP)
+ */
+#include "dmres.h"
+#include <time.h>
+
+#ifdef DM_USE_PACKFS
+#include <zlib.h>
+#endif
+
+#ifdef DM_USE_STDIO
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#endif
+
+
+DMResource *dmResourceNew(DMResourceLib *lib, const char *filename, const size_t size)
+{
+    DMResource *node = dmMalloc0(sizeof(DMResource));
+    if (node == NULL)
+        return NULL;
+    
+    node->lib = lib;
+    node->filename = dm_strdup(filename);
+    node->rawSize = size;
+    
+    return node;
+}
+
+
+void dmResourceFreeResData(DMResource *node)
+{
+    if (node->resData != NULL &&
+        node->rops != NULL &&
+        node->rops->free != NULL)
+    {
+        node->rops->free(node);
+    }
+
+    node->resData = NULL;
+    node->flags &= ~DMF_LOADED_RES;
+}
+
+
+void dmResourceFreeRawData(DMResource *node)
+{
+    if ((node->flags & DMF_UNALLOCATED) == 0)
+    {
+        dmFree(node->rawData);
+        node->rawData = NULL;
+        node->flags &= ~DMF_LOADED_RAW;
+    }
+}
+
+
+void dmResourceFree(DMResource *node)
+{
+    if (node != NULL)
+    {
+        dmResourceFreeResData(node);
+        dmResourceFreeRawData(node);
+        dmFree(node->filename);
+        dmFree(node);
+    }
+}
+
+
+void dmResourceInsert(DMResourceLib *lib, DMResource * node)
+{
+    if (lib == NULL || node == NULL)
+        return;
+    
+    node->lib = lib;
+
+    if (lib->resources != NULL)
+    {
+        node->prev = lib->resources->prev;
+        lib->resources->prev->next = node;
+        lib->resources->prev = node;
+    }
+    else
+    {
+        lib->resources = node->prev = node;
+    }
+    
+    node->next = NULL;
+}
+
+
+void dmResourceDelete(DMResourceLib *lib, DMResource * node)
+{
+    if (lib == NULL)
+        return;
+
+    if (node->prev)
+        node->prev->next = node->next;
+
+    if (node->next)
+        node->next->prev = node->prev;
+    else
+        lib->resources->prev = node->prev;
+
+    node->prev = node->next = NULL;
+}
+
+
+DMResource * dmResourceFind(DMResourceLib *lib, const char *filename)
+{
+    DMResource *node, *found = NULL;
+
+    if (lib == NULL)
+        return NULL;
+
+    dmMutexLock(lib->mutex);
+
+    for (node = lib->resources; node != NULL; node = node->next)
+    {
+        if (strcmp(node->filename, filename) == 0)
+        {
+            found = node;
+            break;
+        }
+    }
+
+    dmMutexUnlock(lib->mutex);
+
+    return found;
+}
+
+
+#ifdef DM_USE_STDIO
+/* Basic stdio file routines
+ */
+static int dm_stdio_fopen(DMResource *handle)
+{
+    char *rfilename = dm_strdup_printf("%s%s", DMRES_DATA_PATH, handle->filename);
+    if (rfilename == NULL)
+        return DMERR_MALLOC;
+
+    handle->fh = fopen(rfilename, "rb");
+    dmFree(rfilename);
+
+    handle->error = dmGetErrno();
+    return (handle->fh != NULL) ? DMERR_OK : DMERR_FOPEN;
+}
+
+
+static void dm_stdio_fclose(DMResource * f)
+{
+    if (f->fh != NULL)
+    {
+        fclose(f->fh);
+        f->fh = NULL;
+    }
+}
+
+
+static int dm_stdio_ferror(DMResource * f)
+{
+    return f->error;
+}
+
+
+static int dm_stdio_fseek(DMResource *f, const off_t pos, const int whence)
+{
+    int ret = fseek(f->fh, pos, whence);
+    f->error = dmGetErrno();
+    return ret;
+}
+
+
+static int dm_stdio_freset(DMResource * f)
+{
+    if (f->fh != NULL)
+        return dm_stdio_fseek(f, 0L, SEEK_SET);
+    else
+        return DMERR_OK;
+}
+
+
+static off_t dm_stdio_fsize(DMResource *f)
+{
+    off_t savePos, fileSize;
+
+    // Check if the size is cached
+    if (f->rawSize != 0)
+        return f->rawSize;
+
+    // Get file size
+    savePos = ftello(f->fh);
+    if (fseeko(f->fh, 0L, SEEK_END) != 0)
+    {
+        f->error = dmGetErrno();
+        return -1;
+    }
+
+    fileSize = ftello(f->fh);
+    if (fseeko(f->fh, savePos, SEEK_SET) != 0)
+    {
+        f->error = dmGetErrno();
+        return -1;
+    }
+
+    f->rawSize = fileSize;
+    return fileSize;
+}
+
+
+static off_t dm_stdio_ftell(DMResource * f)
+{
+    return ftell(f->fh);
+}
+
+
+static BOOL dm_stdio_feof(DMResource * f)
+{
+    return feof(f->fh);
+}
+
+
+static int dm_stdio_fgetc(DMResource * f)
+{
+    int ret = fgetc(f->fh);
+    f->error = dmGetErrno();
+    return ret;
+}
+
+
+static int dm_stdio_fputc(int v, DMResource * f)
+{
+    int ret = fputc(v, f->fh);
+    f->error = dmGetErrno();
+    return ret;
+}
+
+
+static size_t dm_stdio_fread(void *ptr, size_t size, size_t nmemb, DMResource * f)
+{
+    size_t ret = fread(ptr, size, nmemb, f->fh);
+    f->error = dmGetErrno();
+    return ret;
+}
+
+
+static size_t dm_stdio_fwrite(void *ptr, size_t size, size_t nmemb, DMResource * f)
+{
+    size_t ret = fwrite(ptr, size, nmemb, f->fh);
+    f->error = dmGetErrno();
+    return ret;
+}
+
+
+static int dm_stdio_preload(DMResource *handle)
+{
+    int ret = dm_stdio_fopen(handle);
+    if (ret != DMERR_OK)
+        return ret;
+    
+    dm_stdio_fsize(handle);
+    
+    handle->rawData = dmMalloc(handle->rawSize);
+    if (handle->rawData == NULL)
+        return DMERR_MALLOC;
+    
+    if (dm_stdio_fread(handle->rawData, sizeof(Uint8), handle->rawSize, handle) != handle->rawSize)
+        return DMERR_FREAD;
+    
+    return DMERR_OK;
+}
+
+
+DMResourceOps dfStdioFileOps =
+{
+    "Stdio",
+
+    dm_stdio_freset,
+    dm_stdio_ferror,
+    dm_stdio_fseek,
+    dm_stdio_fsize,
+    dm_stdio_ftell,
+    dm_stdio_feof,
+    dm_stdio_fgetc,
+    dm_stdio_fputc,
+    dm_stdio_fread,
+    dm_stdio_fwrite,
+
+    dm_stdio_fopen,
+    dm_stdio_fclose,
+    dm_stdio_preload
+};
+
+DMResourceOps dfStdioFHOps =
+{
+    "StdioFH",
+
+    dm_stdio_freset,
+    dm_stdio_ferror,
+    dm_stdio_fseek,
+    dm_stdio_fsize,
+    dm_stdio_ftell,
+    dm_stdio_feof,
+    dm_stdio_fgetc,
+    dm_stdio_fputc,
+    dm_stdio_fread,
+    dm_stdio_fwrite,
+
+    NULL,
+    NULL,
+    NULL
+};
+#endif
+
+
+// Some mingw/windows headers define these as macros, which is bad for us
+#ifdef __WIN32
+#undef ferror
+#undef feof
+#endif
+
+
+/*
+ * PACK file routines
+ */
+#ifdef DM_USE_PACKFS
+static int dm_pack_preload(DMResource *handle)
+{
+    DMPackEntry *node;
+    int res = DMERR_OK, cres, cdataLeft;
+    z_stream cstream;
+    Uint8 *  cbuffer = NULL;
+
+    if (handle->lib == NULL || handle->lib->packFile == NULL)
+        return DMERR_NULLPTR;
+
+    // Search PACK nodelist for file
+    if ((node = dmPackFind(handle->lib->packFile->entries, handle->filename)) == NULL)
+    {
+        dmError("Entry '%s' not found in PACK file.\n", handle->filename);
+        res = DMERR_NOT_FOUND;
+        goto error;
+    }
+
+    // Seek to entry
+    if (fseek(handle->lib->packFile->file, node->offset, SEEK_SET) == -1)
+    {
+        dmError("Could not seek node position in PACK file.\n");
+        res = DMERR_FSEEK;
+        goto error;
+    }
+
+    // Allocate a structures and buffers
+    cbuffer = (Uint8 *) dmMalloc(DPACK_TMPSIZE);
+    if (cbuffer == NULL)
+    {
+        res = DMERR_MALLOC;
+        goto error;
+    }
+
+    // Initialize fields
+    handle->rawOffset = 0;
+    handle->rawSize = node->size;
+    handle->rawData = (Uint8 *) dmMalloc(node->size);
+    if (handle->rawData == NULL)
+    {
+        res = DMERR_MALLOC;
+        goto error;
+    }
+
+    // Initialize decompression
+    cstream.zalloc = (alloc_func) Z_NULL;
+    cstream.zfree = (free_func) Z_NULL;
+    cstream.opaque = (voidpf) Z_NULL;
+    cstream.next_out = handle->rawData;
+    cstream.avail_out = handle->rawSize;
+    cdataLeft = node->length;
+    cres = inflateInit(&(cstream));
+    if (cres != Z_OK)
+    {
+        dmError("Could not initialize zlib stream inflation.\n");
+        res = DMERR_INIT_FAIL;
+        goto error;
+    }
+
+    // Uncompress the data
+    while (cdataLeft > 0 &&
+           cstream.avail_out > 0 && cres == Z_OK)
+    {
+        cstream.avail_in = fread(
+            cbuffer, sizeof(Uint8),
+            (cdataLeft >= DPACK_TMPSIZE) ? DPACK_TMPSIZE : cdataLeft,
+            handle->lib->packFile->file);
+
+        cdataLeft -= cstream.avail_in;
+        cstream.next_in = cbuffer;
+        cres = inflate(&cstream, Z_FULL_FLUSH);
+    }
+
+    // Cleanup
+    inflateEnd(&(cstream));
+
+error:
+    dmFree(cbuffer);
+    return res;
+}
+
+
+static int dm_pack_fopen(DMResource * f)
+{
+    if ((f->flags & DMF_LOADED_RAW) == 0)
+    {
+        int res = dm_pack_preload(f);
+        if (res == DMERR_OK)
+            f->flags |= DMF_LOADED_RAW;
+
+        return res;
+    }
+    else
+        return DMERR_OK;
+}
+
+
+static void dm_pack_fclose(DMResource * f)
+{
+    if ((f->flags & DMF_PERSIST) == 0)
+        dmResourceFreeRawData(f);
+}
+#endif
+
+
+static int dm_mem_freset(DMResource * f)
+{
+    f->rawOffset = 0;
+    return DMERR_OK;
+}
+
+
+static int dm_mem_ferror(DMResource * f)
+{
+    return f->error;
+}
+
+
+static int dm_mem_fseek(DMResource * f, const off_t offset, const int whence)
+{
+    off_t newPos;
+
+    // Calculate the new position
+    switch (whence)
+    {
+        case SEEK_SET:
+            newPos = offset;
+            break;
+
+        case SEEK_CUR:
+            newPos = f->rawOffset + offset;
+            break;
+
+        case SEEK_END:
+            newPos = f->rawSize + offset;
+            break;
+
+        default:
+            return -1;
+    }
+
+    // Set the new position
+    f->rawOffset = newPos;
+
+    // Check the new position
+    if (newPos < 0 && (size_t) newPos >= f->rawSize)
+        return -1;
+
+    return 0;
+}
+
+
+static off_t dm_mem_fsize(DMResource * f)
+{
+    return f->rawSize;
+}
+
+
+static off_t dm_mem_ftell(DMResource * f)
+{
+    return f->rawOffset;
+}
+
+
+static BOOL dm_mem_feof(DMResource * f)
+{
+    // Check for EOF
+    if ((size_t) f->rawOffset <= f->rawSize)
+        return FALSE;
+    else
+        return TRUE;
+}
+
+
+static int dm_mem_fgetc(DMResource * f)
+{
+    // Check for EOF
+    if ((size_t) f->rawOffset < f->rawSize)
+        return f->rawData[f->rawOffset++];
+    else
+        return EOF;
+}
+
+
+static size_t dm_mem_fread(void *buf, size_t size, size_t nmemb, DMResource * f)
+{
+    size_t length = (size * nmemb);
+
+    // Check if we can read the whole chunk
+    if (((size_t) f->rawOffset + length) >= f->rawSize)
+    {
+        nmemb = (f->rawSize - f->rawOffset) / size;
+        length = size * nmemb;
+    }
+
+    memcpy(buf, f->rawData + f->rawOffset, length);
+    f->rawOffset += length;
+    return nmemb;
+}
+
+
+static int dm_mem_fputc(int ch, DMResource * f)
+{
+    // Check for EOF
+    if ((size_t) f->rawOffset < f->rawSize)
+    {
+        f->rawData[f->rawOffset++] = ch;
+        return ch;
+    }
+    else
+        return EOF;
+}
+
+
+static size_t dm_mem_fwrite(void *buf, size_t size, size_t nmemb, DMResource * f)
+{
+    size_t length = (size * nmemb);
+
+    // Check if we can write the whole chunk
+    if (((size_t) f->rawOffset + length) >= f->rawSize)
+    {
+        nmemb = (f->rawSize - f->rawOffset) / size;
+        length = size * nmemb;
+    }
+
+    if (length > 0)
+    {
+        memcpy(f->rawData + f->rawOffset, buf, length);
+        f->rawOffset += length;
+    }
+    return nmemb;
+}
+
+
+#ifdef DM_USE_PACKFS
+DMResourceOps dfPackFileOps =
+{
+    "PackFS",
+
+    dm_mem_freset,
+    dm_mem_ferror,
+    dm_mem_fseek,
+    dm_mem_fsize,
+    dm_mem_ftell,
+    dm_mem_feof,
+    dm_mem_fgetc,
+    NULL,
+    dm_mem_fread,
+    NULL,
+    
+    dm_pack_fopen,
+    dm_pack_fclose,
+    dm_pack_preload,
+};
+#endif
+
+
+DMResourceOps dfMemIOFileOps =
+{
+    "MemIO",
+
+    dm_mem_freset,
+    dm_mem_ferror,
+    dm_mem_fseek,
+    dm_mem_fsize,
+    dm_mem_ftell,
+    dm_mem_feof,
+    dm_mem_fgetc,
+    dm_mem_fputc,
+    dm_mem_fread,
+    dm_mem_fwrite,
+    
+    NULL,
+    dmResourceFree,
+    NULL
+};
+
+
+/* FS file handling functions. These functions call the actual
+ * functions depending on where the file is located.
+ */
+static int dmResourcePreload(DMResource *handle)
+{
+    int ret = DMERR_OK;
+
+    // Check if we want to preload raw data?
+    if ((handle->lib->flags & DRF_PRELOAD_RAW) ||
+        handle->rops == NULL || handle->rops->load == NULL)
+    {
+        if (handle->flags & DMF_LOADED_RAW)
+            ret = DMERR_OK;
+        else
+        if (handle->fops->preload != NULL)
+        {
+            ret = handle->fops->preload(handle);
+            if (ret == DMERR_OK)
+                handle->flags |= DMF_LOADED_RAW | DMF_PERSIST;
+        }
+        else
+            ret = DMERR_INIT_FAIL;
+
+        dmfreset(handle);
+    }
+
+    // Check if resource data is to be preloaded
+    if (handle->lib->flags & DRF_PRELOAD_RES)
+    {
+        if (handle->flags & DMF_LOADED_RES)
+            ret = DMERR_OK;
+        else
+        if (handle->rops != NULL &&
+            handle->rops->load != NULL)
+        {
+            if ((ret = handle->fops->fopen(handle)) == DMERR_OK)
+            {
+                ret = handle->rops->load(handle);
+                handle->fops->fclose(handle);
+            }
+            
+            if (ret == DMERR_OK)
+                handle->flags |= DMF_LOADED_RES;
+        }
+
+        dmfreset(handle);
+    }
+
+    return ret;
+}
+
+
+int dmf_open(DMResourceLib *lib, const char *filename, DMResource **phandle)
+{
+    DMResource *handle;
+    int res;
+
+    // Check master directory for resource
+    if ((*phandle = handle = dmResourceFind(lib, filename)) == NULL)
+    {
+#ifdef DM_USE_STDIO
+        if (lib->flags & DRF_USE_STDIO)
+        {
+            // Hmm.. does not exist? Fall back to a stdio file
+            *phandle = handle = dmResourceNew(lib, filename, 0);
+            if (handle == NULL)
+                return DMERR_MALLOC;
+
+            handle->fops   = &dfStdioFileOps;
+        }
+        else
+            return DMERR_INIT_FAIL;
+#else
+        // Stdio not enabled, fail
+        return DMERR_INIT_FAIL;
+#endif
+    }
+
+    // Check if the data is preloaded
+    if ((res = handle->fops->fopen(handle)) == DMERR_OK)
+    {
+        dmResourceRef(handle);
+        if (handle->flags & DMF_TEMPORARY)
+        {
+            handle->flags &= ~DMF_TEMPORARY;
+            dmResourceInsert(lib, handle);
+        }
+    }
+    else
+    if (handle->flags & DMF_TEMPORARY)
+    {
+        dmResourceFree(handle);
+        *phandle = handle = NULL;
+    }
+
+    dmfreset(handle);
+    return res;
+}
+
+
+int dmf_create_memio(DMResourceLib *lib, const char *filename,
+    Uint8 *buf, const size_t size, DMResource **phandle)
+{
+    DMResource *handle;
+
+    // Check master directory for resource
+    if ((*phandle = handle = dmResourceFind(lib, filename)) == NULL)
+    {
+        if ((*phandle = handle = dmResourceNew(lib, filename, size)) == NULL)
+            return DMERR_MALLOC;
+
+        handle->flags   = DMF_LOADED_RAW | DMF_UNALLOCATED;
+        handle->fops    = &dfMemIOFileOps;
+        handle->rawData = buf;
+        dmResourceInsert(lib, handle);
+    }
+
+    // Increase refcount
+    dmResourceRef(handle);
+    dmfreset(handle);
+    return DMERR_OK;
+}
+
+
+#ifdef DM_USE_STDIO
+int dmf_create_stdio(const char *filename, const char *mode, DMResource **phandle)
+{
+    DMResource *handle;
+    if ((*phandle = handle = dmResourceNew(NULL, filename, 0)) == NULL)
+        return DMERR_MALLOC;
+
+    handle->fops  = &dfStdioFileOps;
+    handle->fh    = fopen(filename, mode);
+    handle->error = dmGetErrno();
+    
+    if (handle->fh == NULL)
+    {
+        dmResourceFree(handle);
+        return handle->error;
+    }
+
+    dmResourceRef(handle);
+    return DMERR_OK;
+}
+
+
+int dmf_create_stdio_stream(FILE *fh, DMResource **phandle)
+{
+    DMResource *handle;
+    if ((*phandle = handle = dmResourceNew(NULL, "", 0)) == NULL)
+        return DMERR_MALLOC;
+
+    handle->fops = &dfStdioFHOps;
+    handle->fh   = fh;
+    dmResourceRef(handle);
+    return DMERR_OK;
+}
+#endif
+
+
+void dmf_close(DMResource * f)
+{
+    if (f == NULL)
+        return;
+
+    if (f->fops->fclose != NULL)
+        f->fops->fclose(f);
+
+    dmResourceUnref(f);
+}
+
+
+int dmfreset(DMResource *f)
+{
+    if (f == NULL)
+        return DMERR_NULLPTR;
+    
+    if (f->fops == NULL || f->fops->freset == NULL)
+        return DMERR_OK;
+    
+    return f->fops->freset(f);
+}
+
+int dmferror(DMResource * f)
+{
+    f->atime = time(NULL);
+    return f->fops->ferror(f);
+}
+
+int dmfseek(DMResource * f, off_t offset, int whence)
+{
+    f->atime = time(NULL);
+    return f->fops->fseek(f, offset, whence);
+}
+
+off_t dmfsize(DMResource * f)
+{
+    f->atime = time(NULL);
+    return f->fops->fsize(f);
+}
+
+off_t dmftell(DMResource * f)
+{
+    f->atime = time(NULL);
+    return f->fops->ftell(f);
+}
+
+BOOL dmfeof(DMResource * f)
+{
+    f->atime = time(NULL);
+    return f->fops->feof(f);
+}
+
+int dmfgetc(DMResource * f)
+{
+    f->atime = time(NULL);
+    return f->fops->fgetc(f);
+}
+
+int dmfputc(int v, DMResource * f)
+{
+    f->atime = time(NULL);
+    return f->fops->fputc(v, f);
+}
+
+size_t dmfread(void *ptr, size_t size, size_t nmemb, DMResource * f)
+{
+    f->atime = time(NULL);
+    return f->fops->fread(ptr, size, nmemb, f);
+}
+
+size_t dmfwrite(void *ptr, size_t size, size_t nmemb, DMResource * f)
+{
+    f->atime = time(NULL);
+    return f->fops->fwrite(ptr, size, nmemb, f);
+}
+
+char *dmfgets(char *s, int size, DMResource * f)
+{
+    char *p = s, c;
+    int n = 0;
+
+    while ((c = f->fops->fgetc(f)) != EOF)
+    {
+        n++;
+        if (c == '\n')
+            break;
+        else
+        if (n < size - 1)
+            *p++ = c;
+    }
+    *p = 0;
+    
+    return (n > 0) ? s : NULL;
+}
+
+
+int dmResourceRef(DMResource *node)
+{
+    if (node->lib != NULL) dmMutexLock(node->lib->mutex);
+    node->atime = time(NULL);
+    node->refcount++;
+    if (node->lib != NULL) dmMutexUnlock(node->lib->mutex);
+
+    return node->refcount;
+}
+
+
+int dmResourceUnref(DMResource *node)
+{
+    if (node->lib != NULL) dmMutexLock(node->lib->mutex);
+    node->refcount--;
+    if (node->lib != NULL) dmMutexUnlock(node->lib->mutex);
+
+    return node->refcount;
+}
+
+
+#ifdef DM_USE_STDIO
+static int dmResourcesLoadDirectory(DMResourceLib *lib, const char *path)
+{
+    int res = DMERR_OK;
+    struct dirent *dh;
+    DIR *hdir = opendir(path);
+    if (hdir == NULL)
+        return dmGetErrno();
+
+    dmMutexLock(lib->mutex);
+
+    do
+    {
+        DMResource *node = NULL;
+        dh = readdir(hdir);
+        if (dh != NULL)
+        {
+            struct stat sbuf;
+            char *fname = dm_strdup_printf("%s/%s", path, dh->d_name);
+            if (stat(fname, &sbuf) == -1)
+            {
+                res = dmGetErrno();
+                dmError("Could not stat() %s, #%d: %s\n",
+                    fname, res, dmErrorStr(res));
+                dmFree(fname);
+                goto out;
+            }
+
+            if (S_ISREG(sbuf.st_mode))
+                node = dmResourceNew(lib, dh->d_name, sbuf.st_size);
+        }
+
+        if (node != NULL)
+        {
+            node->fops = &dfStdioFileOps;
+            dmResourceInsert(lib, node);
+        }
+    } while (dh != NULL);
+
+out:
+    dmMutexUnlock(lib->mutex);
+
+#ifdef __WIN32
+#else
+    closedir(hdir);
+#endif
+
+    return res;
+}
+#endif
+
+
+/* Resources subsystem initialization and shutdown routines
+ */
+int dmResourcesInit(DMResourceLib **plib, const char *filename, const char *path, const int flags, int (*classifier)(DMResource *))
+{
+    DMResourceLib *lib;
+    BOOL initialized = FALSE;
+
+    // Allocate the resource library structure
+    if ((*plib = lib = dmMalloc0(sizeof(DMResourceLib))) == NULL)
+        return DMERR_MALLOC;
+
+    // Basic data
+    lib->mutex    = dmCreateMutex();
+    lib->flags    = flags; 
+    lib->resPath  = dm_strdup((path != NULL) ? path : DMRES_DATA_PATH);
+
+
+#ifdef DM_USE_PACKFS
+    if (flags & DRF_USE_PACK)
+    {
+        int ret;
+        DMPackEntry *node;
+
+        lib->packFilename = dm_strdup((filename != NULL) ? filename : DMRES_DATA_PACK);
+
+        // Initialize PACK, open as read-only
+        ret = dmPackOpen(lib->packFilename, &lib->packFile, TRUE);
+        if (ret != DMERR_OK)
+        {
+            if ((flags & DRF_USE_STDIO) == 0)
+            {
+                dmError("Error opening PACK file '%s', #%d: %s\n",
+                lib->packFilename, ret, dmErrorStr(ret));
+
+                return DMERR_INIT_FAIL;
+            }
+            else
+                dmError("Failed to open PACK, falling back to STDIO, '%s' %d: %s\n",
+                lib->packFilename, ret, dmErrorStr(ret));
+        }
+        else
+        {
+            // Initialize resources from a PACK file
+            for (node = lib->packFile->entries; node != NULL; node = node->next)
+            {
+                DMResource *res = dmResourceNew(lib, node->filename, node->size);
+                if (res == NULL)
+                {
+                    dmError("Could not allocate memory for resource node '%s' [0x%08x], %d.\n",
+                        node->filename, node->flags, node->size);
+                    return DMERR_INIT_FAIL;
+                }
+
+                res->fops = &dfPackFileOps;
+                dmResourceInsert(lib, res);
+            }
+            
+            initialized = TRUE;
+        }
+    }
+#endif
+
+#ifdef DM_USE_STDIO
+    if (!initialized && (flags & DRF_USE_STDIO))
+    {
+        // Initialize resources from a resource directory
+        int ret = dmResourcesLoadDirectory(lib, lib->resPath);
+        if (ret != DMERR_OK)
+            return ret;
+        initialized = TRUE;
+    }
+#endif
+
+    if (!initialized)
+        return DMERR_INIT_FAIL;
+
+    // Okay, classify resources
+    if (lib->resources != NULL && classifier != NULL)
+    {
+        DMResource *node;
+        for (node = lib->resources; node != NULL; node = node->next)
+        {
+            int ret = classifier(node);
+            if (ret != DMERR_OK)
+                return ret;
+        }
+    }
+
+    // Initialization complete
+    return DMERR_OK;
+}
+
+
+int dmResourcesClose(DMResourceLib *lib)
+{
+    DMResource *node;
+    
+    if (lib == NULL)
+        return DMERR_NULLPTR;
+    
+    dmMutexLock(lib->mutex);
+
+    // Shutdown possible subsystems
+#ifdef DM_USE_PACKFS
+    if (lib->flags & DRF_USE_PACK)
+    {
+        int res = dmPackClose(lib->packFile);
+        if (res != DMERR_OK)
+        {
+            dmError("Error closing PACK, #%i: %s\n",
+                res, dmErrorStr(res));
+        }
+
+        dmFree(lib->packFilename);
+    }
+#endif
+
+    // Free resource entries
+    node = lib->resources;
+    while (node != NULL)
+    {
+        DMResource *next = node->next;
+        dmResourceFree(node);
+        node = next;
+    }
+
+    // Etc.
+    dmFree(lib->resPath);
+    dmMutexUnlock(lib->mutex);
+    dmDestroyMutex(lib->mutex);
+    return DMERR_OK;
+}
+
+
+int dmResourcesPreload(DMResourceLib *lib, BOOL start, int *loaded, int *total)
+{
+    int ret = DMERR_OK;
+
+    dmMutexLock(lib->mutex);
+    
+    // Initialize preloading 
+    if (lib->preload == NULL || start)
+    {
+        DMResource *node;
+        
+        lib->preload = lib->resources;
+        *loaded = 0;
+        *total = 0;
+
+        // Calculate total number of resources to be preloaded
+        if (lib->flags & (DRF_PRELOAD_RAW | DRF_PRELOAD_RES))
+        {
+            for (node = lib->resources; node != NULL; node = node->next)
+                (*total)++;
+        }
+    }
+    else
+    if (lib->preload != NULL)
+    {
+        // Attempt to preload the resource
+        if ((ret = dmResourcePreload(lib->preload)) != DMERR_OK)
+        {
+            dmError("Error preloading '%s', %d: %s\n",
+                lib->preload->filename, ret, dmErrorStr(ret));
+            goto error;
+        }
+
+        (*loaded)++;
+        lib->preload = lib->preload->next;
+    }
+
+    dmMutexUnlock(lib->mutex);
+    return (lib->preload == NULL) ? DMERR_OK : DMERR_PROGRESS;
+
+error:
+    dmMutexUnlock(lib->mutex);
+    return ret;
+}
+
+
+void dmResourcePrune(DMResourceLib *lib, const int agems, int const flags)
+{
+    DMResource *node;
+    const int stamp = time(NULL);
+    dmMutexLock(lib->mutex);
+
+    for (node = lib->resources; node != NULL; node = node->next)
+    {
+        // Check if node has refcount of 0 and is
+        // not marked as persistent resource
+        if (node->refcount == 0 &&
+            (node->flags & DMF_PERSIST) == 0 &&
+            (node->flags & (DMF_LOADED_RES | DMF_LOADED_RAW)))
+        {
+            if (((flags & DMPRUNE_ATIME) && stamp - node->atime >= agems) ||
+                ((flags & DMPRUNE_MTIME) && stamp - node->mtime >= agems))
+            {
+                dmResourceFreeResData(node);
+                dmResourceFreeRawData(node);
+            }
+        }
+    }
+
+    dmMutexUnlock(lib->mutex);
+}
+
+
+/* Helper resource access routines
+ */
+int dmf_read_str(DMResource *f, void *s, size_t l)
+{
+    return dmfread(s, 1, l, f) == l;
+}
+
+BOOL dmf_read_byte(DMResource *f, Uint8 *val)
+{
+    int tmp = dmfgetc(f);
+    *val = tmp;
+    return tmp != EOF;
+}
+
+#define DM_DEFINE_FUNC(xname, xtype, xmacro)          \
+BOOL dmf_read_ ## xname (DMResource *f, xtype *v) {      \
+    xtype result;                                     \
+    if (dmfread(&result, sizeof( xtype ), 1, f) != 1) \
+        return FALSE;                                 \
+    *v = DM_ ## xmacro ## _TO_NATIVE (result);        \
+    return TRUE;                                      \
+}
+
+DM_DEFINE_FUNC(le16, Uint16, LE16)
+DM_DEFINE_FUNC(le32, Uint32, LE32)
+
+DM_DEFINE_FUNC(be16, Uint16, BE16)
+DM_DEFINE_FUNC(be32, Uint32, BE32)
+
+#ifdef DM_HAVE_64BIT
+DM_DEFINE_FUNC(le64, Uint64, LE64)
+DM_DEFINE_FUNC(be64, Uint64, BE64)
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmres.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,190 @@
+/*
+ * DMLib
+ * -- Resource management
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2011-2012 Tecnic Software productions (TNSP)
+ */
+#ifndef DMRES_H
+#define DMRES_H
+
+#include "dmlib.h"
+
+#ifdef DM_USE_PACKFS
+#include "dmpack.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Constants
+ */
+enum
+{
+    DMPRUNE_ATIME   = 0x0001,
+    DMPRUNE_MTIME   = 0x0002,
+};
+
+enum
+{
+    DRF_USE_PACK    = 0x0001,
+    DRF_USE_STDIO   = 0x0002,
+    DRF_PRELOAD_RAW = 0x0004,
+    DRF_PRELOAD_RES = 0x0008,
+};
+
+enum
+{
+    DMF_PERSIST     = 0x0001, // Persist loaded RAW resource
+    DMF_TEMPORARY   = 0x0002,
+    DMF_UNALLOCATED = 0x0004, // The raw data is not allocated, so do not free it
+    DMF_LOADED_RAW  = 0x1000, // Raw data has been loaded
+    DMF_LOADED_RES  = 0x2000, // Resource has been loaded
+};
+
+
+/* Typedefs and structures
+ */
+struct DMResourceLib;
+struct DMResourceDataOps;
+struct DMResourceOps;
+struct DMResource;
+
+typedef struct DMResource
+{
+    // Timestamps (in seconds from time())
+    int    mtime,              // When resource was loaded
+           atime;              // Last accessed (dmResourceRef()/unref)
+    int    refcount;           // Reference count
+
+    int    flags;              // Resource flags (DMF_*)
+    char   *filename;
+
+    // Raw data (or mem data)
+    size_t rawSize;            // Size of data
+    off_t  rawOffset;          // Current offset in data
+    Uint8 *rawData;            // Pointer to data
+
+    // Decoded resource data
+    void   *resData;
+    size_t resSize;
+    struct DMResourceDataOps *rops;
+
+    int    error;              // Error code
+
+#ifdef DM_USE_STDIO
+    FILE * fh;                 // File handle for stdio
+#endif
+
+    struct DMResourceOps *fops;    // Pointer to file handling functions struct
+    struct DMResourceLib *lib;     // Pointer to the resource library
+    struct DMResource *next, *prev;
+} DMResource;
+
+
+typedef struct DMResourceDataOps
+{
+    BOOL   (*probe)(DMResource *res, const char *fext);
+    int    (*load)(DMResource *res);
+    void   (*free)(DMResource *res);
+} DMResourceDataOps;
+
+
+typedef struct DMResourceLib
+{
+    int  flags;
+    char *resPath;
+
+    DMResource *resources, *preload;
+    DMMutex *mutex;
+
+#ifdef DM_USE_PACKFS
+    char *packFilename;
+    DMPackFile *packFile;
+#endif
+} DMResourceLib;
+
+
+typedef struct DMResourceOps
+{
+    char    *name;
+
+    int     (*freset)(DMResource *);
+    int     (*ferror)(DMResource *);
+    int     (*fseek)(DMResource *, const off_t, const int);
+    off_t   (*fsize)(DMResource *);
+    off_t   (*ftell)(DMResource *);
+    BOOL    (*feof)(DMResource *);
+    int     (*fgetc)(DMResource *);
+    int     (*fputc)(int, DMResource *);
+    size_t  (*fread)(void *, const size_t, const size_t, DMResource *);
+    size_t  (*fwrite)(void *, const size_t, const size_t, DMResource *);
+
+    int     (*fopen)(DMResource *);
+    void    (*fclose)(DMResource *);
+    int     (*preload)(DMResource *);
+} DMResourceOps;
+
+
+/* Functions
+ */
+int          dmResourcesInit(DMResourceLib **lib, const char *filename, const char *path, const int flags, int (*classifier)(DMResource *));
+int          dmResourcesClose(DMResourceLib *lib);
+
+void         dmResourcesPrune(DMResourceLib *lib, const int agems, int const flags);
+int          dmResourcesPreload(DMResourceLib *lib, BOOL start, int *loaded, int *total);
+
+DMResource * dmResourceNew(DMResourceLib *lib, const char *filename, const size_t size);
+void         dmResourceFree(DMResource *node);
+void         dmResourceInsert(DMResourceLib *lib, DMResource * node);
+void         dmResourceDelete(DMResourceLib *lib, DMResource * node);
+DMResource * dmResourceFind(DMResourceLib *lib, const char *filename);
+int          dmResourceRef(DMResource *);
+int          dmResourceUnref(DMResource *);
+
+
+// Opening and closing resources
+int          dmf_open(DMResourceLib *lib, const char *, DMResource **handle);
+int          dmf_create_memio(DMResourceLib *lib, const char *, Uint8 *buf, size_t len, DMResource **phandle);
+#ifdef DM_USE_STDIO
+int          dmf_create_stdio(const char *filename, const char *mode, DMResource **phandle);
+int          dmf_create_stdio_stream(FILE *, DMResource **phandle);
+#endif
+void         dmf_close(DMResource *);
+
+
+// Basic resource access functions
+int          dmfreset(DMResource *);
+int          dmferror(DMResource *);
+int          dmfseek(DMResource *, const off_t, const int);
+off_t        dmfsize(DMResource *);
+off_t        dmftell(DMResource *);
+BOOL         dmfeof(DMResource *);
+int          dmfgetc(DMResource *);
+int          dmfputc(int, DMResource *);
+size_t       dmfread(void *, const size_t, const size_t, DMResource *);
+size_t       dmfwrite(void *, const size_t, const size_t, DMResource *);
+char *       dmfgets(char *s, int size, DMResource * f);
+
+
+// Helper functions for endianess based reading etc
+int          dmf_read_str(DMResource *, void *, size_t);
+BOOL         dmf_read_byte(DMResource *, Uint8 *);
+
+BOOL         dmf_read_be16(DMResource *, Uint16 *);
+BOOL         dmf_read_be32(DMResource *, Uint32 *);
+BOOL         dmf_read_le16(DMResource *, Uint16 *);
+BOOL         dmf_read_le32(DMResource *, Uint32 *);
+
+#ifdef DM_HAVE_64BIT
+BOOL         dmf_read_be64(DMResource *, Uint64 *);
+BOOL         dmf_read_le64(DMResource *, Uint64 *);
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DMRES_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmresw.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,38 @@
+/*
+ * DMLib
+ * -- Resource management
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2011-2012 Tecnic Software productions (TNSP)
+ */
+#include "dmresw.h"
+
+int dmf_write_str(DMResource *f, void *s, size_t l)
+{
+    return dmfwrite(s, 1, l, f) == l;
+}
+
+
+BOOL dmf_write_byte(DMResource *f, const Uint8 val)
+{
+    return dmfputc(val, f) == val;
+}
+
+
+#define DM_DEFINE_FUNC(xname, xtype, xmacro)            \
+BOOL dmf_write_ ## xname (DMResource *f, xtype v) {     \
+    xtype result = DM_NATIVE_TO_ ## xmacro (v);         \
+    if (dmfwrite(&result, sizeof( xtype ), 1, f) != 1)  \
+        return FALSE;                                   \
+    return TRUE;                                        \
+}
+
+DM_DEFINE_FUNC(le16, Uint16, LE16)
+DM_DEFINE_FUNC(le32, Uint32, LE32)
+
+DM_DEFINE_FUNC(be16, Uint16, BE16)
+DM_DEFINE_FUNC(be32, Uint32, BE32)
+
+#ifdef DM_HAVE_64BIT
+DM_DEFINE_FUNC(le64, Uint64, LE64)
+DM_DEFINE_FUNC(be64, Uint64, BE64)
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmresw.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,34 @@
+/*
+ * DMLib
+ * -- Resource management write helpers
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2011-2012 Tecnic Software productions (TNSP)
+ */
+#ifndef DMRESW_H
+#define DMRESW_H
+
+#include "dmres.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int          dmf_write_str(DMResource *, void *, size_t);
+BOOL         dmf_write_byte(DMResource *, const Uint8);
+
+BOOL         dmf_write_be16(DMResource *, Uint16);
+BOOL         dmf_write_be32(DMResource *, Uint32);
+BOOL         dmf_write_le16(DMResource *, Uint16);
+BOOL         dmf_write_le32(DMResource *, Uint32);
+
+#ifdef DM_HAVE_64BIT
+BOOL         dmf_write_be64(DMResource *, Uint64);
+BOOL         dmf_write_le64(DMResource *, Uint64);
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DMRESW_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmscaledblit.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,89 @@
+/*
+ * DMLib
+ * -- Scaled sprite / surface blitting function template
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2011-2012 Tecnic Software productions (TNSP)
+ */
+
+
+int DM_BLITFUNC_NAME (SDL_Surface *src,
+    const int x0, const int y0,
+    const int dwidth, const int dheight,
+    SDL_Surface *dst
+#ifdef DM_BLITFUNC_ARGS
+    DM_BLITFUNC_ARGS
+#endif
+    )
+#ifdef DM_HEADER
+;
+#else
+{
+    int yc;
+    DMFixedPoint32 xv, yv, dx, dy;
+    DMQValue xr, yr;
+
+#ifdef DM_BLITFUNC_VARS
+    DM_BLITFUNC_VARS
+#endif
+    
+    // Clip coordinates
+    if (dmScaledClipCoord(&xr, x0, src->w, dwidth, 
+        dst->clip_rect.x, dst->clip_rect.x + dst->clip_rect.w)
+        ||
+        dmScaledClipCoord(&yr, y0, src->h, dheight,
+        dst->clip_rect.y, dst->clip_rect.y + dst->clip_rect.h))
+        return -1;
+
+#ifdef DM_BLITFUNC_INIT
+    DM_BLITFUNC_INIT
+#endif
+
+    // Calculate "final" initial source bitmap offsets
+    FP_CONV(dy, yr.voffs);
+    FP_MUL_R(yv, dy, yr.vdelta);
+
+    FP_CONV(dx, xr.voffs);
+    FP_MUL_R(dx, dx, xr.vdelta);
+
+    // Take pitch into account
+    const int dstadd = xr.vadd - dst->clip_rect.w + dst->clip_rect.x + (dst->pitch / DM_BLITFUNC_DST_BYTES);
+
+    // Blit scaled
+    DM_BLITFUNC_DST_TYPE * dp = ((DM_BLITFUNC_DST_TYPE *) dst->pixels) + (yr.v0 * dst->pitch) / DM_BLITFUNC_DST_BYTES + xr.v0;
+    for (yc = yr.v0; yc < yr.v1; yc++)
+    {
+        const DM_BLITFUNC_SRC_TYPE * sp = ((DM_BLITFUNC_SRC_TYPE *) src->pixels) + (FP_GETH16(yv) * src->pitch) / DM_BLITFUNC_SRC_BYTES;
+        int xc;
+
+#ifdef DM_BLITFUNC_INNER_INIT
+        DM_BLITFUNC_INNER_INIT
+#endif
+
+        for (xv.dw = dx.dw, xc = xr.v0; xc < xr.v1; xc++)
+        {
+            DM_BLITFUNC_INNER
+            FP_ADD(xv, xr.vdelta);
+        }
+        FP_ADD(yv, yr.vdelta);
+        dp += dstadd;
+    }
+
+#ifdef DM_BLITFUNC_FINISH
+    DM_BLITFUNC_FINISH
+#endif
+
+    return 0;
+}
+#endif
+
+#undef DM_BLITFUNC_NAME
+#undef DM_BLITFUNC_ARGS
+#undef DM_BLITFUNC_SRC_BYTES
+#undef DM_BLITFUNC_DST_BYTES
+#undef DM_BLITFUNC_SRC_TYPE
+#undef DM_BLITFUNC_DST_TYPE
+#undef DM_BLITFUNC_VARS
+#undef DM_BLITFUNC_INIT
+#undef DM_BLITFUNC_INNER_INIT
+#undef DM_BLITFUNC_INNER
+#undef DM_BLITFUNC_FINISH
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmsimple.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,924 @@
+/*
+ * dmlib
+ * -- Demo engine "player" code
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012-2013 Tecnic Software productions (TNSP)
+ */
+#include <SDL.h>
+#include "dmengine.h"
+#include "dmargs.h"
+#include "dmtext.h"
+#include "dmimage.h"
+#include "setupfont.h"
+#include "setupimage.h"
+#include "setupmenubar.h"
+
+static const char *engineSetupDataName = "SetupData.txt";
+static const char *engineSetupImageName = "SetupImage.png";
+static const char *engineSetupMenuBarName = "SetupMenuBar.png";
+static const char *engineSetupFontName = "SetupFont.dmf";
+
+static DMEngineData engine;
+
+static DMOptArg optList[] =
+{
+    { 0, '?', "help",       "Show this help", OPT_NONE },
+    { 1, 'v', "verbose",    "Be more verbose", OPT_NONE },
+};
+
+const int optListN = sizeof(optList) / sizeof(optList[0]);
+
+
+
+static void argShowHelp()
+{
+    dmPrintBanner(stdout, dmProgName, "[options]");
+    dmArgsPrintHelp(stdout, optList, optListN);
+}
+
+
+static BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
+{
+    (void) optArg;
+
+    switch (optN)
+    {
+        case 0:
+            argShowHelp();
+            exit(0);
+            break;
+
+        case 1:
+            dmVerbosity++;
+            break;
+        
+        default:
+            dmError("Unknown option '%s'.\n", currArg);
+            return FALSE;
+    }
+    
+    return TRUE;
+}
+
+
+static int engineAudioThreadFunc(void *userdata)
+{
+    do
+    {
+        if (engine.audioStatus == SDL_AUDIO_PLAYING)
+        {
+            engineAudioCallback(userdata, engine.audioSimBuf, engine.audioSimBufSize);
+        }
+
+        SDL_Delay(engine.audioSimDelay);
+    } while (!engine.audioSimDone);
+
+    return 0;
+}
+
+
+static int engineShowProgress(int loaded, int total)
+{
+    int dx = 60,
+        dh = 20,
+        dw = engine.screen->w - (2 * dx),
+        dy = (engine.screen->h - dh) / 2;
+    
+    if (SDL_MUSTLOCK(engine.screen) != 0 && SDL_LockSurface(engine.screen) != 0)
+        return DMERR_INIT_FAIL;
+    
+    // Draw the progress bar
+    dmClearSurface(engine.screen, dmMapRGBA(engine.screen, 0,0,0,0));
+    dmFillRect(engine.screen, dx, dy, dx+dw, dy+dh, dmMapRGB(engine.screen, 255,255,255));
+    dmFillRect(engine.screen, dx+1, dy+1, dx+dw-1, dy+dh-1, dmMapRGB(engine.screen, 0,0,0));
+
+    if (total > 0)
+    {
+        dmFillRect(engine.screen,
+            dx+3, dy+3,
+            dx + 3 + ((dw - 3) * loaded) / total,
+            dy + dh - 3,
+            dmMapRGB(engine.screen, 200,200,200));
+    }
+
+    // Flip screen
+    if (SDL_MUSTLOCK(engine.screen) != 0)
+        SDL_UnlockSurface(engine.screen);
+
+    SDL_Flip(engine.screen);
+    return DMERR_OK;
+}
+
+
+static int engineLoadResources()
+{
+    int err, loaded = 0, total = 0;
+    BOOL first = TRUE;
+
+    do
+    {
+        // Show a nice progress bar while loading
+        if ((err = engineShowProgress(loaded, total)) != DMERR_OK)
+            return err;
+
+        err = dmResourcesPreload(engine.resources, first, &loaded, &total);
+        first = FALSE;
+    }
+    while (err == DMERR_PROGRESS);
+    
+    return err;
+}
+
+
+static BOOL engineGenInitializeVideo(int width, int height, int depth, Uint32 flags)
+{
+    dmPrint(1, "Initializing SDL video %d x %d x %dbpp, flags=0x%08x\n",
+        width, height, depth, flags);
+
+    SDL_FreeSurface(engine.screen);
+
+    engine.screen = SDL_SetVideoMode(width, height, depth, flags);
+    if (engine.screen == NULL)
+    {
+        dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError());
+        return FALSE;
+    }
+
+    SDL_WM_SetCaption(dmProgDesc, dmProgName);
+
+    return TRUE;
+}
+
+
+static BOOL engineInitializeVideo()
+{
+    return engineGenInitializeVideo(engine.optVidWidth, engine.optVidHeight,
+        engine.optVidDepth, engine.optVFlags);
+}
+
+
+typedef struct
+{
+    int w, h, aspect;
+} DMModeEntry;
+
+
+DMModeEntry *engineModeList = NULL;
+int nengineModeList = 0, aengineModeList = 0;
+
+
+static int engineModeSort(const void *pa, const void *pb)
+{
+    DMModeEntry
+        *va = (DMModeEntry *) pa,
+        *vb = (DMModeEntry *) pb;
+
+    return (va->w - vb->w);
+}
+
+
+int engineAddModeToList(int w, int h)
+{
+    DMModeEntry *mode;
+    int i, aspect = engineGetVideoAspect(w, h);
+    
+    dmPrint(2, " - Proposed %d x %d\n", w, h);
+    if (aspect <= 0)
+        return DMERR_INVALID_ARGS;
+    
+    // Check if the mode is already in our list
+    for (i = 0; i < nengineModeList; i++)
+    {
+        mode = &engineModeList[i];
+        if (mode->w == w && mode->h == h)
+            return DMERR_OK;
+    }
+
+    // Check if the mode fits our criteria
+    switch (engine.optVidSetup)
+    {
+        case DM_VSETUP_ASPECT:
+            if (aspect != engine.optVidAspect)
+                return DMERR_OK;
+            break;
+        
+        case DM_VSETUP_ANY:
+            break;
+    }
+
+    // Reallocate array if needed
+    if (nengineModeList + 1 >= aengineModeList)
+    {
+        aengineModeList += 16;
+        engineModeList = dmRealloc(engineModeList, sizeof(DMModeEntry) * aengineModeList);
+        if (engineModeList == NULL)
+            return DMERR_MALLOC;
+    }
+    
+    // Store
+    mode = &engineModeList[nengineModeList];
+    mode->w = w;
+    mode->h = h;
+    mode->aspect = engineGetVideoAspect(w, h);
+    dmPrint(2, " - %d x %d, %d\n", w, h, mode->aspect);
+    
+    nengineModeList++;
+    
+    return DMERR_OK;
+}
+
+
+int engineParseSetupConfig(const char *filename)
+{
+    DMResource *file = NULL;
+    int res;
+    char buf[128];
+
+    if ((res = dmf_open(engine.resources, filename, &file)) != DMERR_OK)
+        return res;
+
+    while (dmfgets(buf, sizeof(buf), file) != NULL)
+    {
+        ssize_t pos;
+        // Trim line ending
+        for (pos = strlen(buf) - 1; pos >= 0 && isspace(buf[pos]); pos--)
+            buf[pos] = 0;
+
+        // Find start of the line
+        for (pos = 0; isspace(buf[pos]); pos++);
+        
+        // Skip empty lines and comments
+        if (buf[pos] == 0 || buf[pos] == '#')
+            continue;
+
+        char *str = buf+pos;
+        if (sscanf(str, "menuPos %f %f",
+            &engine.setupMenuPos.x, &engine.setupMenuPos.y) != 2 &&
+            sscanf(str, "menuDim %f %f",
+            &engine.setupMenuDim.x, &engine.setupMenuDim.y) != 2 &&
+            sscanf(str, "text1Pos %f %f",
+            &engine.setupText1Pos.x, &engine.setupText1Pos.y) != 2 &&
+            sscanf(str, "menuCenter %d", &engine.setupMenuCenter) != 1 &&
+            sscanf(str, "textCondensed %d", &engine.setupTextCondensed) != 1 &&
+            sscanf(str, "textFullscreen %s", engine.setupTextFullscreen) != 1 &&
+            sscanf(str, "textWindowed %s", engine.setupTextWindowed) != 1 &&
+            sscanf(str, "textPrefix %s", engine.setupTextPrefix) != 1
+            )
+        {
+            dmError("Syntax error in configuration:\n%s\n", buf);
+            res = DMERR_INVALID_DATA;
+            goto out;
+        }
+    }
+
+out:
+    dmf_close(file);
+    return res;
+}
+
+
+static inline DMFloat vsX(DMVector vec)
+{
+    return (DMFloat) engine.screen->w * vec.x;
+}
+
+
+static inline DMFloat vsY(DMVector vec)
+{
+    return (DMFloat) engine.screen->h * vec.y;
+}
+
+
+int engineVideoSetup()
+{
+    DMBitmapFont *menuFont = NULL;
+    DMResource *file = NULL;
+    SDL_Surface *menuBgImage = NULL, *menuBarImage = NULL;
+    int result, menuState = -1;
+    BOOL menuFullScreen = TRUE;
+
+    // Compute a list of valid modes
+    if (!engineGenInitializeVideo(DM_VSETUP_WIDTH, DM_VSETUP_HEIGHT, engine.optVidDepth, engine.optVFlags))
+        goto out;
+
+    SDL_Rect **modes = SDL_ListModes(engine.screen->format, engine.screen->flags | SDL_FULLSCREEN);
+    if (modes == (SDL_Rect**) 0)
+    {
+        dmError("No compatible video resolutions/depths available at all. Bailing out.\n");
+        goto out;
+    }
+    
+    if (modes != (SDL_Rect**) -1)
+    {
+        int i;
+        dmPrint(1, "Enumerating modes.\n");
+        for (i = 0; modes[i] != NULL; i++)
+            engineAddModeToList(modes[i]->w, modes[i]->h);
+    }
+
+    if (nengineModeList == 0)
+    {
+        dmError("Umm, no modes found.\n");
+        goto out;
+    }
+
+    qsort(engineModeList, nengineModeList, sizeof(engineModeList[0]), engineModeSort);
+
+    // Open video temporarily
+    if (!engineGenInitializeVideo(DM_VSETUP_WIDTH, DM_VSETUP_HEIGHT, 32, SDL_SWSURFACE | SDL_DOUBLEBUF))
+        goto out;
+
+    // Get setup data
+    engine.setupMenuPos.x = 0.18750f;
+    engine.setupMenuPos.y = 0.41666f;
+    engine.setupMenuDim.x = 0.625f;
+    engine.setupMenuDim.y = 0.41666f;
+
+    engine.setupText1Pos.x = 0.3f;
+    engine.setupText1Pos.y = 0.7f;
+
+    strcpy(engine.setupTextFullscreen , "FULLSCREEN");
+    strcpy(engine.setupTextWindowed   , " WINDOWED ");
+    strcpy(engine.setupTextPrefix     , "USE LEFT/RIGHT ARROW TO TOGGLE : ");
+
+    if (engineParseSetupConfig(engineSetupDataName) != DMERR_OK)
+        goto out;
+
+    // Fetch and decompress setup image, try regular resources first
+    if ((result = dmf_open(engine.resources, engineSetupImageName, &file)) == DMERR_OK ||
+        (result = dmf_create_memio(NULL, engineSetupImageName, engineSetupImage, sizeof(engineSetupImage), &file)) == DMERR_OK)
+    {
+        menuBgImage = dmLoadImage(file);
+        dmf_close(file);
+    }
+
+    if ((result = dmf_open(engine.resources, engineSetupMenuBarName, &file)) == DMERR_OK ||
+        (result = dmf_create_memio(NULL, engineSetupMenuBarName, engineSetupMenuBar, sizeof(engineSetupMenuBar), &file)) == DMERR_OK)
+    {
+        menuBarImage = dmLoadImage(file);
+        dmf_close(file);
+    }
+
+    if (menuBgImage == NULL || menuBarImage == NULL)
+    {
+        dmError("Could not instantiate setup screen images, %d: %s\n",
+            result, dmErrorStr(result));
+        goto out;
+    }
+    
+    if (menuBgImage->w != DM_VSETUP_WIDTH ||
+        menuBgImage->h != DM_VSETUP_HEIGHT)
+    {
+        dmError("Setup screen background image does not match "
+            "required dimensions (%dx%d vs %dx%d)\n",
+            menuBgImage->w, menuBgImage->h,
+            DM_VSETUP_WIDTH, DM_VSETUP_HEIGHT);
+        goto out;
+    }
+
+
+    // Load up the bitmap font
+    if ((result = dmf_open(engine.resources, engineSetupFontName, &file)) == DMERR_OK ||
+        (result = dmf_create_memio(NULL, engineSetupFontName, engineSetupFont, sizeof(engineSetupFont), &file)) == DMERR_OK)
+    {
+        result = dmLoadBitmapFont(file, &menuFont);
+        dmf_close(file);
+    }
+    if (result != DMERR_OK)
+    {
+        dmError("Could not instantiate setup screen font, %d: %s\n",
+            result, dmErrorStr(result));
+        goto out;
+    }
+
+    SDL_Surface *tmp = dmConvertScaledSurface(menuBgImage,
+        engine.screen->format, engine.screen->flags,
+        engine.screen->w, engine.screen->h);
+    if (tmp == NULL)
+    {
+        dmError("Could not convert setup screen background image.\n");
+        goto out;
+    }
+
+    SDL_FreeSurface(menuBgImage);
+    menuBgImage = tmp;
+
+    SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
+
+
+    // Enter the main loop of the menu
+    char menuStr[256];
+    int menuOffset = 0,
+        menuIndex = 0,
+        menuEntryHeight = menuFont->height + 2,
+        menuHeight = vsY(engine.setupMenuDim) / menuEntryHeight;
+
+    menuState = 0;
+
+    engine.startTime = SDL_GetTicks();
+
+    while (!menuState)
+    {
+        while (SDL_PollEvent(&engine.event))
+        switch (engine.event.type)
+        {
+            case SDL_KEYDOWN:
+                switch (engine.event.key.keysym.sym)
+                {
+                    case SDLK_ESCAPE:
+                        menuState = -1;
+                        break;
+
+                    case SDLK_RETURN:
+                        menuState = 1;
+                        break;
+
+                    case SDLK_UP:
+                        if (menuIndex > 0)
+                            menuIndex--;
+                        else
+                        if (menuOffset > 0)
+                            menuOffset--;
+                        break;
+
+                    case SDLK_DOWN:
+                        if (menuIndex < menuHeight - 1 && menuOffset + menuIndex < nengineModeList - 1)
+                            menuIndex++;
+                        else
+                        if (menuOffset + menuIndex < nengineModeList - 1)
+                            menuOffset++;
+                        break;
+
+                    case SDLK_LEFT:
+                        menuFullScreen = FALSE;
+                        break;
+
+                    case SDLK_RIGHT:
+                        menuFullScreen = TRUE;
+                        break;
+
+                    case SDLK_SPACE:
+                        menuFullScreen = !menuFullScreen;
+                        break;
+
+                    default:
+                        break;
+                }
+
+                break;
+
+            case SDL_QUIT:
+                menuState = -1;
+                break;
+        }
+
+        // Draw frame
+        engine.frameTime = SDL_GetTicks();
+        if (SDL_MUSTLOCK(engine.screen) != 0 && SDL_LockSurface(engine.screen) != 0)
+        {
+            dmError("Can't lock surface.\n");
+            goto out;
+        }
+
+        // Render the menu
+        dmDirectBlitSurface(menuBgImage, engine.screen);
+        
+        // XXX/TODO: Some hardcoded bits here ...
+        float t = engineGetTimeDT(&engine);
+        int index, entry;
+
+        for (index = 0, entry = menuOffset; entry < nengineModeList && index < menuHeight; index++, entry++)
+        {
+            DMModeEntry *mode = &engineModeList[entry];
+
+            if (entry == menuOffset + menuIndex)
+            {
+                dmScaledBlitSurface32to32TransparentGA(menuBarImage,
+                    vsX(engine.setupMenuPos),
+                    vsY(engine.setupMenuPos) + (index * menuEntryHeight),
+                    vsX(engine.setupMenuDim),
+                    menuEntryHeight + 4,
+                    engine.screen,
+                    200 + sin(t * 10.0) * 50);
+            }
+
+            snprintf(menuStr, sizeof(menuStr),
+                "%4d X %-4d  - %d:%d",
+                mode->w, mode->h,
+                mode->aspect / 1000,
+                mode->aspect % 1000);
+
+            DMFloat posX = engine.setupMenuCenter ?
+                2.0f + (vsX(engine.setupMenuDim) - menuFont->width * strlen(menuStr)) / 2.0f :
+                2.0f;
+            
+            dmDrawBMTextConst(
+                engine.screen, menuFont,
+                engine.setupTextCondensed, DMD_TRANSPARENT,
+                vsX(engine.setupMenuPos) + posX,
+                vsY(engine.setupMenuPos) + (index * menuEntryHeight),
+                menuStr);
+        }
+        
+        snprintf(menuStr, sizeof(menuStr),
+            "%s%s",
+            engine.setupTextPrefix,
+            menuFullScreen ? engine.setupTextFullscreen : engine.setupTextWindowed);
+
+        dmDrawBMTextConst(
+            engine.screen, menuFont,
+            engine.setupTextCondensed, DMD_TRANSPARENT,
+            vsX(engine.setupText1Pos),
+            vsY(engine.setupText1Pos),
+            menuStr);
+
+        // Flip screen
+        if (SDL_MUSTLOCK(engine.screen) != 0)
+            SDL_UnlockSurface(engine.screen);
+
+        SDL_Flip(engine.screen);
+        SDL_Delay(25);
+    }
+
+    // Okay, we accepted the selection
+    if (menuState == 1)
+    {
+        DMModeEntry *mode = &engineModeList[menuOffset + menuIndex];
+        engine.optVidNative =
+            mode->w == engine.optVidWidth &&
+            mode->h == engine.optVidHeight;
+
+        engine.optVidWidth = mode->w;
+        engine.optVidHeight = mode->h;
+        engine.optVidAspect = mode->aspect;
+        if (menuFullScreen)
+            engine.optVFlags |= SDL_FULLSCREEN;
+
+    }
+
+out:
+    SDL_FreeSurface(menuBgImage);
+    SDL_FreeSurface(menuBarImage);
+    dmFreeBitmapFont(menuFont);
+    
+    return menuState;
+}
+
+
+int main(int argc, char *argv[])
+{
+    int err;
+    BOOL initSDL = FALSE;
+
+    memset(&engine, 0, sizeof(engine));
+
+    // Pre-initialization
+    if ((err = demoPreInit(&engine)) != DMERR_OK)
+        goto error_exit;
+
+    if (!dmArgsProcess(argc, argv, optList, optListN,
+        argHandleOpt, NULL, FALSE))
+        return DMERR_INIT_FAIL;
+
+    dmPrint(0,
+    "%s\n"
+    "%s\n",
+    dmProgDesc, dmProgAuthor);
+
+    dmPrint(0,
+    "Using libSDL, "
+#ifdef DM_USE_PACKFS
+    "zlib, "
+#endif
+#ifdef DM_USE_TREMOR
+    "Tremor Vorbis codec"
+#endif
+    " and modified stb_image.\n"
+    "See README.txt for more information.\n");
+
+    // Initialize resource subsystem
+    dmPrint(1, "Initializing resources subsystem.\n");
+    if ((err = dmResourcesInit(&engine.resources, engine.optPackFilename,
+        engine.optDataPath, engine.optResFlags, engineClassifier)) != DMERR_OK)
+    {
+        dmError("Could not initialize resource manager, #%d: %s.\n", err, dmErrorStr(err));
+        goto error_exit;
+    }
+
+    // Initialize SDL components
+    dmPrint(1, "Initializing libSDL.\n");
+    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) != 0)
+    {
+        dmError("Could not initialize SDL: %s\n", SDL_GetError());
+        goto error_exit;
+    }
+    initSDL = TRUE;
+
+
+    // Present video mode selector
+    if (engine.optVidAspect <= 0)
+        engine.optVidAspect = engineGetVideoAspect(engine.optVidWidth, engine.optVidHeight);
+
+    if (engine.optVidSetup)
+    {
+        if ((err = engineVideoSetup()) <= 0)
+            goto error_exit;
+    }
+
+    // Initialize audio parts
+    if (engine.optAfmt.freq == 0 && engine.optAfmt.channels == 0)
+    {
+        engine.optAfmt.freq     = 44100;
+        engine.optAfmt.format   = AUDIO_S16SYS;
+        engine.optAfmt.channels = 2;
+    }
+    
+    if (engine.optAfmt.samples == 0)
+        engine.optAfmt.samples = engine.optAfmt.freq / 50;
+
+    switch (engine.optAudioSetup)
+    {
+        case DM_ASETUP_JSS:
+#ifdef DM_USE_JSS
+            jssInit();
+
+            switch (engine.optAfmt.format)
+            {
+                case AUDIO_S16SYS: engine.jssFormat = JSS_AUDIO_S16; break;
+                case AUDIO_U16SYS: engine.jssFormat = JSS_AUDIO_U16; break;
+                case AUDIO_S8:     engine.jssFormat = JSS_AUDIO_S8; break;
+                case AUDIO_U8:     engine.jssFormat = JSS_AUDIO_U8; break;
+            }
+
+            dmPrint(1, "Initializing miniJSS mixer with fmt=%d, chn=%d, freq=%d\n",
+                engine.jssFormat, engine.optAfmt.channels, engine.optAfmt.freq);
+
+            if ((engine.jssDev = jvmInit(engine.jssFormat, engine.optAfmt.channels, engine.optAfmt.freq, JMIX_AUTO)) == NULL)
+            {
+                dmError("jvmInit() returned NULL, voi perkele.\n");
+                goto error_exit;
+            }
+
+            if ((engine.jssPlr = jmpInit(engine.jssDev)) == NULL)
+            {
+                dmError("jmpInit() returned NULL\n");
+                goto error_exit;
+            }
+#else
+            dmError("miniJSS support not included.\n");
+#endif
+            break;
+
+        case DM_ASETUP_TREMOR:
+#ifndef DM_USE_TREMOR
+            dmError("Tremor support not included.\n");
+#endif
+            break;
+    }
+
+    // Initialize SDL audio
+    dmPrint(1, "Trying to init SDL audio with: fmt=%d, chn=%d, freq=%d, samples=%d\n",
+        engine.optAfmt.format, engine.optAfmt.channels,
+        engine.optAfmt.freq, engine.optAfmt.samples);
+
+    engine.audioStatus      = SDL_AUDIO_STOPPED;
+    engine.optAfmt.callback = engineAudioCallback;
+    engine.audioStreamMutex = dmCreateMutex();
+
+    engine.audioSampleSize  = engine.optAfmt.channels;
+    switch (engine.optAfmt.format)
+    {
+        case AUDIO_S16SYS:
+        case AUDIO_U16SYS: engine.audioSampleSize *= 2; break;
+    }
+    
+    if (SDL_OpenAudio(&engine.optAfmt, NULL) < 0)
+    {
+        // We'll let this pass, as we want to support no-sound.
+        dmError("Couldn't open SDL audio, falling back to no sound: %s\n", SDL_GetError());
+
+        // Set up simulated audio thread
+        engine.audioSimDelay   = 1000 / 45;
+        engine.audioSimBufSize = (engine.optAfmt.freq / 45) * engine.audioSampleSize;
+        engine.audioSimBuf     = dmMalloc(engine.audioSimBufSize);
+        engine.audioSimDone    = FALSE;
+        engine.audioSimThread  = SDL_CreateThread(engineAudioThreadFunc, NULL);
+    }
+
+    // Initialize SDL video
+    if (engine.demoInitPreVideo != NULL &&
+       (err = engine.demoInitPreVideo(&engine)) != DMERR_OK)
+    {
+        dmError("demoInitPreVideo() failed, #%d: %s\n", err, dmErrorStr(err));
+        goto error_exit;
+    }
+
+    if (!engineInitializeVideo())
+        goto error_exit;
+
+    if (engine.demoInitPostVideo != NULL &&
+       (err = engine.demoInitPostVideo(&engine)) != DMERR_OK)
+    {
+        dmError("demoInitPostVideo() failed, #%d: %s\n", err, dmErrorStr(err));
+        goto error_exit;
+    }
+
+    // Hide cursor
+    SDL_ShowCursor(SDL_DISABLE);
+
+    // Load resources
+    dmPrint(1, "Loading resources, please wait...\n");
+    if ((err = engineLoadResources()) != DMERR_OK)
+    {
+        dmError("Error loading resources, #%d: %s.\n",
+            err, dmErrorStr(err));
+        goto error_exit;
+    }
+
+    // Final initializations
+    if ((err = engine.demoInit(&engine)) != DMERR_OK)
+    {
+        dmError("Failure in demoInit(), #%d: %s\n",
+            err, dmErrorStr(err));
+        goto error_exit;
+    }
+
+    // Initialize effects
+    if ((err = engineInitializeEffects(&engine)) != DMERR_OK)
+    {
+        dmError("Effects initialization failed, #%d: %s\n",
+            err, dmErrorStr(err));
+        goto error_exit;
+    }
+
+    // Use a timeline, if set
+#ifdef DM_USE_TIMELINE
+    if (engine.timeline != NULL)
+    {
+        if ((err = dmLoadTimeline(engine.timeline, &engine.tl)) != DMERR_OK)
+        {
+            dmError("Error loading timeline, #%d: %s\n", err,
+                dmErrorStr(err));
+            goto error_exit;
+        }
+
+        if ((err = dmPrepareTimeline(engine.tl, engine.ptl)) != DMERR_OK)
+        {
+            dmError("Error creating prepared timeline, #%d: %s\n",
+                err, dmErrorStr(err));
+            goto error_exit;
+        }
+    }
+#endif
+
+    dmPrint(1, "Starting up.\n");
+
+    SDL_LockAudio();
+    enginePauseAudio(0);
+    SDL_UnlockAudio();
+
+    engine.startTime = SDL_GetTicks();
+
+    while (!engine.exitFlag)
+    {
+        while (SDL_PollEvent(&engine.event))
+        switch (engine.event.type)
+        {
+            case SDL_KEYDOWN:
+                switch (engine.event.key.keysym.sym)
+                {
+                    case SDLK_ESCAPE:
+                        engine.exitFlag = TRUE;
+                        break;
+                    
+                    case SDLK_SPACE:
+                        engine.pauseFlag = !engine.pauseFlag;
+                        break;
+
+                    case SDLK_f:
+                        engine.optVFlags ^= SDL_FULLSCREEN;
+                        if (!engineInitializeVideo())
+                            goto error_exit;
+                        break;
+
+                    case SDLK_RETURN:
+                        if (engine.event.key.keysym.mod & KMOD_ALT)
+                        {
+                            engine.optVFlags ^= SDL_FULLSCREEN;
+                            if (!engineInitializeVideo())
+                                goto error_exit;
+                        }
+                        break;
+
+                    default:
+                        break;
+                }
+
+                break;
+
+            case SDL_VIDEOEXPOSE:
+                break;
+
+            case SDL_QUIT:
+                engine.exitFlag = TRUE;
+                break;
+        }
+
+        // Draw frame
+        engine.frameTime = SDL_GetTicks();
+        if (engine.pauseFlag != engine.paused)
+        {
+            engine.paused = engine.pauseFlag;
+            engine.pauseTime = engineGetTick(&engine);
+        }
+        
+        if (engine.paused)
+        {
+            engine.startTime = engine.frameTime - engine.pauseTime;
+        }
+
+        if (SDL_MUSTLOCK(engine.screen) != 0 && SDL_LockSurface(engine.screen) != 0)
+        {
+            dmError("Can't lock surface.\n");
+            goto error_exit;
+        }
+
+        // Call main tick
+        if (engine.demoRender != NULL)
+        {
+            if ((err = engine.demoRender(&engine)) != DMERR_OK)
+                goto error_exit;
+        }
+#ifdef DM_USE_TIMELINE
+        else
+        {
+            if ((err = dmExecuteTimeline(engine.ptl, engine.screen, engineGetTick(&engine))) != DMERR_OK)
+                goto error_exit;
+        }
+#endif
+
+        // Flip screen
+        if (SDL_MUSTLOCK(engine.screen) != 0)
+            SDL_UnlockSurface(engine.screen);
+
+        SDL_Flip(engine.screen);
+        SDL_Delay(engine.paused ? 100 : 20);
+
+        engine.frameCount++;
+    }
+
+    // Print benchmark results
+    engine.endTime = SDL_GetTicks();
+    dmPrint(1, "%d frames in %d ms, fps = %1.3f\n",
+        engine.frameCount, engine.endTime - engine.startTime,
+        (float) (engine.frameCount * 1000.0f) / (float) (engine.endTime - engine.startTime));
+
+
+error_exit:
+
+    dmPrint(1, "Shutting down.\n");
+    SDL_ShowCursor(SDL_ENABLE);
+
+    SDL_LockAudio();
+    enginePauseAudio(1);
+#ifdef DM_USE_JSS
+    if (engine.optAudioSetup == DM_ASETUP_JSS)
+    {
+        jmpClose(engine.jssPlr);
+        jvmClose(engine.jssDev);
+        jssClose();
+    }
+#endif
+
+    if (engine.audioSimThread != NULL)
+    {
+        dmMutexLock(engine.audioStreamMutex);
+        engine.audioSimDone = TRUE;
+        dmMutexUnlock(engine.audioStreamMutex);
+        SDL_WaitThread(engine.audioSimThread, NULL);
+    }
+
+    SDL_UnlockAudio();
+    
+    if (engine.audioStreamMutex != NULL)
+        dmDestroyMutex(engine.audioStreamMutex);
+
+#ifdef DM_USE_TIMELINE
+    dmFreeTimeline(engine.tl);
+    dmFreePreparedTimelineData(engine.ptl);
+#endif
+
+    engineShutdownEffects(&engine);
+    dmResourcesClose(engine.resources);
+
+    if (engine.demoShutdown != NULL)
+        engine.demoShutdown(&engine);
+
+    if (initSDL)
+        SDL_Quit();
+
+    if (engine.demoQuit != NULL)
+        engine.demoQuit(&engine);
+    
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmstring.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,83 @@
+#include "dmlib.h"
+#include <stdarg.h>
+
+/* Implementation of strdup() with a NULL check
+ */
+char *dm_strdup(const char *s)
+{
+    char *res;
+    if (s == NULL)
+        return NULL;
+
+    if ((res = dmMalloc(strlen(s) + 1)) == NULL)
+        return NULL;
+
+    strcpy(res, s);
+    return res;
+}
+
+
+/* Implementation of strndup() with NULL check
+ */
+char *dm_strndup(const char *s, const size_t n)
+{
+    char *res;
+    if (s == NULL)
+        return NULL;
+
+    size_t len = strlen(s);
+    if (len > n)
+        len = n;
+
+    if ((res = dmMalloc(len + 1)) == NULL)
+        return NULL;
+
+    memcpy(res, s, len);
+    res[len] = 0;
+
+    return res;
+}
+
+
+/* Simulate a sprintf() that allocates memory
+ */
+char *dm_strdup_vprintf(const char *fmt, va_list args)
+{
+    int size = 64;
+    char *buf;
+
+    if ((buf = dmMalloc(size)) == NULL)
+        return NULL;
+
+    while (1)
+    {
+        int n;
+        va_list ap;
+        va_copy(ap, args);
+        n = vsnprintf(buf, size, fmt, ap);
+        va_end(ap);
+
+        if (n > -1 && n < size)
+            return buf;
+        if (n > -1)
+            size = n + 1;
+        else
+            size *= 2;
+
+        if ((buf = dmRealloc(buf, size)) == NULL)
+            return NULL;
+    }
+}
+
+
+char *dm_strdup_printf(const char *fmt, ...)
+{
+    char *res;
+    va_list ap;
+
+    va_start(ap, fmt);
+    res = dm_strdup_vprintf(fmt, ap);
+    va_end(ap);
+
+    return res;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmtext.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,84 @@
+/*
+ * DMLib
+ * -- Bitmap font support
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012 Tecnic Software productions (TNSP)
+ */
+#ifndef DMFONT_H
+#define DMFONT_H
+
+#include "dmlib.h"
+#include "dmres.h"
+
+#ifdef DM_GFX_TTF_TEXT
+#include <SDL_ttf.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Bitmapped fonts and text
+ */
+#ifdef DM_GFX_BM_TEXT
+
+// DMFONT format constants
+#define DMFONT_MAGIC         "DMFONT"
+#define DMFONT_VERSION       0x0100
+
+#define DMFONT_MIN_WIDTH     3
+#define DMFONT_MIN_HEIGHT    3
+#define DMFONT_MAX_WIDTH     128
+#define DMFONT_MAX_HEIGHT    128
+#define DMFONT_MAX_GLYPHS    1024
+
+#define DMFONT_NPALETTE      256
+
+// Legacy TSFONT loading support
+#define TSFONT_MAGIC         "TSFONT"
+#define TSFONT_VERSION       0x0205
+
+
+typedef struct
+{
+    int width, height;     // Dimensions
+    int nglyphs;           // Size of glyphs array
+    SDL_Surface **glyphs;  // NOTE! Not all glyphs may be allocated
+} DMBitmapFont;
+
+
+DMBitmapFont *dmNewBitmapFont(int nglyphs, int width, int height);
+int dmFreeBitmapFont(DMBitmapFont *font);
+int dmLoadBitmapFont(DMResource *res, DMBitmapFont **pfont);
+int dmSaveBitmapFont(DMResource *res, DMBitmapFont *font);
+int dmSetBitmapFontPalette(DMBitmapFont *font, SDL_Color *pal, int start, int size);
+
+void dmDrawBMTextConst(SDL_Surface *screen, DMBitmapFont *font, BOOL condensed, int mode, int xc, int yc, const char *str);
+void dmDrawBMTextVA(SDL_Surface *screen, DMBitmapFont *font, BOOL condensed, int mode, int xc, int yc, const char *fmt, va_list ap);
+void dmDrawBMText(SDL_Surface *screen, DMBitmapFont *font, BOOL condensed, int mode, int xc, int yc, const char *fmt, ...);
+
+
+static inline SDL_Surface *dmGetBMGlyph(DMBitmapFont *font, int ch)
+{
+    if (ch < 0 || ch >= font->nglyphs || ch == '\n' || ch == '\r')
+        ch = 32;
+
+    return font->glyphs[ch];
+}
+#endif
+
+
+/* TTF text drawing
+ */
+#ifdef DM_GFX_TTF_TEXT
+void dmDrawTTFTextConst(SDL_Surface *screen, TTF_Font *font, SDL_Color col, int x, int y, const char *fmt);
+void dmDrawTTFTextVA(SDL_Surface *screen, TTF_Font *font, SDL_Color col, int x, int y, const char *fmt, va_list ap);
+void dmDrawTTFText(SDL_Surface *screen, TTF_Font *font, SDL_Color col, int x, int y, const char *fmt, ...);
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DMFONT_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmtext_bm.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,295 @@
+/*
+ * DMLib
+ * -- Bitmap and TTF text & font support
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012 Tecnic Software productions (TNSP)
+ */
+#include "dmtext.h"
+
+
+void dmDrawBMTextConst(SDL_Surface *screen, DMBitmapFont *font, BOOL condensed, int mode, int xc, int yc, const char *fmt)
+{
+    const char *ptr = fmt;
+    DMUnscaledBlitFunc blit = NULL;
+
+    while (*ptr)
+    {
+        int ch = *ptr++;
+        SDL_Surface *glyph;
+
+        if (ch >= 0 && ch < font->nglyphs && (glyph = font->glyphs[ch]) != NULL)
+        {
+            if (blit == NULL)
+                blit = dmGetUnscaledBlitFunc(glyph->format, screen->format, mode);
+            
+            blit(glyph, xc, yc, screen);
+
+            xc += condensed ? glyph->w : font->width;
+        }
+        else
+            xc += font->width;
+    }
+}
+
+
+void dmDrawBMTextVA(SDL_Surface *screen, DMBitmapFont *font, BOOL condensed, int mode, int xc, int yc, const char *fmt, va_list ap)
+{
+    char tmp[512];
+    vsnprintf(tmp, sizeof(tmp), fmt, ap);
+    dmDrawBMTextConst(screen, font, condensed, mode, xc, yc, tmp);
+    dmFree(tmp);
+}
+
+
+void dmDrawBMText(SDL_Surface *screen, DMBitmapFont *font, BOOL condensed, int mode, int xc, int yc, const char *fmt, ...)
+{
+    va_list ap;
+    
+    va_start(ap, fmt);
+    dmDrawBMTextVA(screen, font, condensed, mode, xc, yc, fmt, ap);
+    va_end(ap);
+}
+
+
+DMBitmapFont *dmNewBitmapFont(int nglyphs, int width, int height)
+{
+    DMBitmapFont *font = dmMalloc0(sizeof(DMBitmapFont));
+    if (font == NULL)
+        return NULL;
+    
+    font->width = width;
+    font->height = height;
+    font->nglyphs = nglyphs;
+    font->glyphs = dmCalloc(nglyphs, sizeof(SDL_Surface *));
+    if (font->glyphs == NULL)
+    {
+        dmFree(font);
+        return NULL;
+    }
+
+    return font;
+}
+
+
+int dmFreeBitmapFont(DMBitmapFont *font)
+{
+    int i;
+
+    if (font == NULL)
+        return DMERR_NULLPTR;
+    
+    for (i = 0; i < font->nglyphs; i++)
+    {
+        if (font->glyphs[i] != NULL)
+        {
+            SDL_FreeSurface(font->glyphs[i]);
+            font->glyphs[i] = NULL;
+        }
+    }
+
+    dmFree(font);
+    return DMERR_OK;
+}
+
+
+/* Set the palette for each glyph. While the function allows you to
+ * specify 'start' and 'end' indices and palette array freely, you should
+ * typically use DMFONT_NPALETTE size palette starting at index 0.
+ */
+int dmSetBitmapFontPalette(DMBitmapFont *font, SDL_Color *pal, int start, int size)
+{
+    int i;
+
+    if (font == NULL)
+        return DMERR_NULLPTR;
+    
+    if (start < 0 || size < 1)
+        return DMERR_INVALID_ARGS;
+    
+    for (i = 0; i < font->nglyphs; i++)
+    {
+        SDL_Surface *glyph = font->glyphs[i];
+        if (glyph != NULL)
+        {
+            SDL_SetColors(glyph, pal, start, size);
+        }
+    }
+
+    return DMERR_OK;
+}
+
+//#define FN_DEBUG
+
+int dmLoadBitmapFont(DMResource *res, DMBitmapFont **pfont)
+{
+    DMBitmapFont *font;
+    char magic[8];
+    Uint16 version, nglyphs, maxglyph;
+    int width, height;
+    BOOL tsfont = FALSE;
+    
+    // Check magic and version
+    dmf_read_str(res, (Uint8 *) &magic, 6);
+    dmf_read_le16(res, &version);
+    
+    // Check if it is a legacy TSFONT file
+    if (memcmp(magic, TSFONT_MAGIC, 6) == 0)
+    {
+        // Yep, we handle these a bit differently
+        int encoding = dmfgetc(res);
+        tsfont = TRUE;
+
+        if (version > TSFONT_VERSION)
+            return DMERR_VERSION;
+
+#ifdef FN_DEBUG
+        fprintf(stderr, "TSFONT v%d.%d (0x%04x), encoding=%d\n", version >> 8, version & 0xff, version, encoding);
+#endif
+        
+        // There were only two encodings, 0 = none and 1 = RLE
+        // of which RLE was never actually used ... derp.
+        if (encoding != 0)
+            return DMERR_NOT_SUPPORTED;
+    }
+    else
+    {
+        if (memcmp(magic, DMFONT_MAGIC, 6) != 0)
+            return DMERR_INVALID;
+
+        if (version > DMFONT_VERSION)
+            return DMERR_VERSION;
+    }
+    
+    // Read other header data
+    if (tsfont)
+    {
+        // TSFONT only has number of glyphs stored in the file
+        nglyphs = dmfgetc(res);
+        
+        // Maximum glyph number
+        maxglyph = 256;
+    }
+    else
+    {
+        dmf_read_le16(res, &nglyphs);
+        dmf_read_le16(res, &maxglyph);
+    }
+    
+    width = dmfgetc(res);
+    height = dmfgetc(res);
+
+#ifdef FN_DEBUG
+    fprintf(stderr, "nglyphs=%d (0x%02x), maxglyph=%d (0x%02x) width=%d, height=%d\n",
+        nglyphs, nglyphs, maxglyph, maxglyph, width, height);
+#endif
+
+    if (tsfont)
+    {
+        // TSFONT color assignments (boolean) .. we discard this.
+        dmfgetc(res);
+        
+        // Very old TSFONTs have some extra data that is not used
+        // .. can't actually even remember what it was for.
+        if (version == 0x0200)
+        {
+            int i;
+            for (i = 0; i < 32; i++)
+                dmfgetc(res);
+        }
+    }
+
+    if (width < DMFONT_MIN_WIDTH ||
+        height < DMFONT_MIN_HEIGHT ||
+        width > DMFONT_MAX_WIDTH ||
+        height > DMFONT_MAX_HEIGHT ||
+        nglyphs > DMFONT_MAX_GLYPHS ||
+        maxglyph > DMFONT_MAX_GLYPHS ||
+        maxglyph < 1)
+        return DMERR_INVALID_DATA;
+
+    // Allocate font
+    if ((*pfont = font = dmNewBitmapFont(maxglyph, width, height)) == NULL)
+        return DMERR_MALLOC;
+
+    // Read glyph data, if any
+    if (nglyphs > 0)
+    {
+        int n, i;
+        Uint32 BitsPerPixel, Rmask, Gmask, Bmask, Amask;
+        SDL_Color pal[DMFONT_NPALETTE];
+
+        // Setup palette for 8bpp fonts
+        for (n = 0; n < DMFONT_NPALETTE; n++)
+        {
+            pal[n].r = pal[n].g = pal[n].b = 0;
+            pal[n].unused = n > 0 ? 255 : 0;
+        }
+
+        if (tsfont)
+        {
+            BitsPerPixel = 8;
+            Rmask = Gmask = Bmask = Amask = 0;
+        }
+        else
+        {
+            BitsPerPixel = dmfgetc(res);
+            dmf_read_le32(res, &Rmask);
+            dmf_read_le32(res, &Gmask);
+            dmf_read_le32(res, &Bmask);
+            dmf_read_le32(res, &Amask);
+        }
+
+        for (i = 0; i < nglyphs; i++)
+        {
+            int y;
+            Uint16 index;
+            Uint8 *pixels;
+            SDL_Surface *glyph;
+
+            // TSFONT format has only byte sized index
+            if (tsfont)
+                index = dmfgetc(res);
+            else
+                dmf_read_le16(res, &index);
+
+            // Read dimensions
+            width = dmfgetc(res);
+            height = dmfgetc(res);
+
+#ifdef FN_DEBUG
+            fprintf(stderr, "#%d @ %d - w=%d, h=%d\n", i, index, width, height);
+#endif
+
+            if (width < DMFONT_MIN_WIDTH ||
+                height < DMFONT_MIN_HEIGHT ||
+                width > DMFONT_MAX_WIDTH ||
+                height > DMFONT_MAX_HEIGHT ||
+                index >= maxglyph)
+                return DMERR_INVALID_DATA;
+
+            // Allocate bitmap
+            font->glyphs[index] = glyph = SDL_CreateRGBSurface(
+                SDL_SWSURFACE, width, height,
+                BitsPerPixel, Rmask, Gmask,
+                Bmask,
+                Amask);
+
+            if (glyph == NULL)
+                return DMERR_MALLOC;
+
+            if (BitsPerPixel == 8)
+                SDL_SetColors(glyph, pal, 0, DMFONT_NPALETTE);
+
+            // Read pixel data
+            pixels = glyph->pixels;
+            for (y = 0; y < glyph->h; y++)
+            {
+                if (dmfread(pixels, glyph->format->BytesPerPixel, glyph->w, res) != (size_t) glyph->w)
+                    return DMERR_FREAD;
+                pixels += glyph->pitch;
+            }
+        }
+    }
+
+    return DMERR_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmtext_ttf.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,42 @@
+/*
+ * DMLib
+ * -- Bitmap and TTF text & font support
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012 Tecnic Software productions (TNSP)
+ */
+#include "dmtext.h"
+
+
+void dmDrawTTFTextConst(SDL_Surface *screen, TTF_Font *font, SDL_Color col, int xc, int yc, const char *fmt)
+{
+    SDL_Surface *text = TTF_RenderText_Blended(font, fmt, col);
+    if (text)
+    {
+        SDL_Rect rect;
+        rect.x = xc;
+        rect.y = yc;
+        rect.w = text->w;
+        rect.h = text->h;
+        SDL_BlitSurface(text, NULL, screen, &rect);
+        SDL_FreeSurface(text);
+    }
+}
+
+void dmDrawTTFTextVA(SDL_Surface *screen, TTF_Font *font, SDL_Color col, int xc, int yc, const char *fmt, va_list ap)
+{
+    char *tmp = dm_strdup_vprintf(fmt, ap);
+    if (tmp != NULL)
+    {
+        dmDrawTTFTextConst(screen, font, col, xc, yc, tmp);
+        dmFree(tmp);
+    }
+}
+
+void dmDrawTTFText(SDL_Surface *screen, TTF_Font *font, SDL_Color col, int xc, int yc, const char *fmt, ...)
+{
+    va_list ap;
+    
+    va_start(ap, fmt);
+    dmDrawTTFTextVA(screen, font, col, xc, yc, fmt, ap);
+    va_end(ap);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmtimeline.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,434 @@
+/*
+ * dmlib
+ * -- Timeline file loading and timeline processing/execution
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012-2013 Tecnic Software productions (TNSP)
+ */
+#include "dmengine.h"
+
+
+static BOOL dmLoadFloatValue(DMResource *res, DMFloat *val)
+{
+    char tmp[DT_FLOAT_STORE_SIZE + 1];
+    if (!dmf_read_str(res, &tmp, DT_FLOAT_STORE_SIZE))
+        return FALSE;
+
+    tmp[DT_FLOAT_STORE_SIZE] = 0;
+    *val = atof(tmp);
+    return TRUE;
+}
+
+
+static int dmLoadTimelinePoints(DMResource *res, DMTimelinePoints *points, int type)
+{
+    int point;
+    Uint32 npoints;
+
+    // Get number of points
+    if (!dmf_read_le32(res, &npoints))
+        return DMERR_FREAD;
+
+    // Calculate and allocate space
+    points->npoints = npoints;
+    points->nallocated = ((npoints / 16) + 1) * 16;
+    
+    points->points = dmCalloc(points->nallocated, sizeof(DMTimelinePoint));
+    if (points->points == NULL)
+        return DMERR_MALLOC;
+    
+    // Read points
+    for (point = 0; point < points->npoints; point++)
+    {
+        DMTimelinePoint *pt = &(points->points[point]);
+        Uint32 ptype, ptime;
+        if (!dmf_read_le32(res, &ptype) ||
+            !dmf_read_le32(res, &ptime))
+            return DMERR_FREAD;
+        
+        switch (type)
+        {
+            case EFPT_INT:
+                {
+                    Uint32 tmp;
+                    if (!dmf_read_le32(res, &tmp))
+                        return DMERR_FREAD;
+                    pt->vint = tmp;
+                }
+                break;
+
+            case EFPT_FLOAT:
+                if (!dmLoadFloatValue(res, &pt->vfloat))
+                    return DMERR_FREAD;
+                break;
+            
+            case EFPT_VECTOR:
+                if (!dmLoadFloatValue(res, &pt->vector.x) ||
+                    !dmLoadFloatValue(res, &pt->vector.y) ||
+                    !dmLoadFloatValue(res, &pt->vector.z) ||
+                    !dmLoadFloatValue(res, &pt->vector.W))
+                    return DMERR_FREAD;
+                break;
+
+            case EFPT_MATRIX:
+                {
+                    int x, y;
+                    for (y = 0; y < DM_MATRIX_SIZE; y++)
+                    for (x = 0; x < DM_MATRIX_SIZE; x++)
+                    {
+                        if (!dmLoadFloatValue(res, &(pt->matrix.m[y][x])))
+                            return DMERR_FREAD;
+                    }
+                }
+                break;
+        }
+        
+        pt->type = ptype;
+        pt->time = ptime;
+    }
+    return DMERR_OK;
+}
+
+
+static int dmLoadTimelineEventParam(DMResource *res, DMTimelineEventParam *param)
+{
+    int err;
+    DMFTimelineEventParam hdr;
+    Uint16 len;
+
+    if (!dmf_read_str(res, &hdr.name, sizeof(hdr.name)) ||
+        !dmf_read_le32(res, &hdr.type))
+        return DMERR_FREAD;
+
+    hdr.name[sizeof(hdr.name) - 1] = 0;
+
+    param->name = dm_strdup(hdr.name);
+    param->type = hdr.type;
+
+    switch (param->type)
+    {
+        case EFPT_INT:
+        case EFPT_FLOAT:
+        case EFPT_VECTOR:
+        case EFPT_MATRIX:
+            if ((err = dmLoadTimelinePoints(res, &param->pts, param->type)) != DMERR_OK)
+                return err;
+            break;
+
+        case EFPT_STRING:
+            if (!dmf_read_le16(res, &len))
+                return DMERR_FREAD;
+
+            param->vstr = dmMalloc((unsigned int)len + 1);
+            if (!dmf_read_str(res, param->vstr, len))
+                return DMERR_FREAD;
+
+            param->vstr[len] = 0;
+            break;
+    }
+
+    return DMERR_OK;
+}
+
+
+static int dmLoadTimelineEvent(DMResource *res, DMTimelineEvent **pevent)
+{
+    int param;
+    DMFTimelineEvent hdr;
+    DMTimelineEvent *event;
+    if ((*pevent = event = dmMalloc0(sizeof(DMTimelineEvent))) == NULL)
+        return DMERR_MALLOC;
+
+    // Get basic event data
+    if (!dmf_read_le32(res, &hdr.start) ||
+        !dmf_read_le32(res, &hdr.duration) ||
+        !dmf_read_str(res, &hdr.effectName, sizeof(hdr.effectName)) ||
+        !dmf_read_le32(res, &hdr.nparams))
+        return DMERR_FREAD;
+
+    hdr.effectName[sizeof(hdr.effectName) - 1] = 0;
+    
+    if (hdr.nparams > DT_MAX_EFFECT_PARAMS)
+    {
+        dmError("Invalid number of parameters, %d > %d ('%s' @ %d:%d)\n",
+            hdr.nparams, DT_MAX_EFFECT_PARAMS, hdr.effectName, hdr.start, hdr.duration);
+        return DMERR_INVALID_DATA;
+    }
+
+    event->start     = hdr.start;
+    event->duration  = hdr.duration;
+    event->nparams   = hdr.nparams;
+    event->effect    = engineFindEffect(hdr.effectName, hdr.nparams);
+    if (event->effect == NULL)
+    {
+        dmError("No matching registered effect found for '%s'.\n", hdr.effectName);
+        return DMERR_INVALID_DATA;
+    }
+
+    event->params    = dmCalloc(event->nparams, sizeof(DMTimelineEventParam));
+    if (event->params == NULL)
+    {
+        dmError("Could not allocate memory for timeline event parameters.\n");
+        return DMERR_MALLOC;
+    }
+
+    for (param = 0; param < event->nparams; param++)
+    {
+        int err;
+        if ((err = dmLoadTimelineEventParam(res, &(event->params[param]))) != DMERR_OK)
+            return err;
+    }
+
+    return DMERR_OK;
+}
+
+
+static int dmLoadTimelineCurve(DMResource *res, DMTimelineCurve *curve)
+{
+    int err;
+
+    curve->enabled = dmfgetc(res);
+    if ((err = dmLoadTimelinePoints(res, &(curve->points), EFPT_FLOAT)) != DMERR_OK)
+        return err;
+    
+    return DMERR_OK;
+}
+
+
+static int dmLoadTimelineTrack(DMResource *res, DMTimelineTrack **ptrack)
+{
+    int event, err;
+    DMFTimelineTrack hdr;
+    DMTimelineTrack *track;
+    if ((*ptrack = track = dmMalloc0(sizeof(DMTimelineTrack))) == NULL)
+        return DMERR_MALLOC;
+
+    if (!dmf_read_le32(res, &hdr.index) ||
+        !dmf_read_le32(res, &hdr.layer) ||
+        !dmf_read_str(res, &hdr.name, sizeof(hdr.name)) ||
+        !dmf_read_byte(res, &hdr.enabled) ||
+        !dmf_read_le32(res, &hdr.nevents))
+        return DMERR_FREAD;
+
+    if (hdr.nevents >= 4096)
+        return DMERR_INVALID_DATA;
+
+    if ((track->events = dmCalloc(hdr.nevents, sizeof(DMTimelineEvent *))) == NULL)
+        return DMERR_MALLOC;
+
+    hdr.name[sizeof(hdr.name) - 1] = 0;
+    track->name    = dm_strdup(hdr.name);
+    track->enabled = hdr.enabled;
+    track->nevents = hdr.nevents;
+
+    for (event = 0; event < track->nevents; event++)
+    {
+        if ((err = dmLoadTimelineEvent(res, &(track->events[event]))) != DMERR_OK)
+            return err;
+    }
+
+    if ((err = dmLoadTimelineCurve(res, &(track->composite))) != DMERR_OK)
+        return err;
+
+    return DMERR_OK;
+}
+
+
+int dmLoadTimeline(DMResource *res, DMTimeline **ptl)
+{
+    int track, err;
+    DMFTimeline hdr;
+    DMTimeline *tl;
+    if ((*ptl = tl = dmMalloc0(sizeof(DMTimeline))) == NULL)
+        return DMERR_MALLOC;
+
+    // Read and check header
+    if (!dmf_read_str(res, &hdr.magic, sizeof(hdr.magic)))
+        return DMERR_FREAD;
+
+    if (memcmp(hdr.magic, DT_MAGIC_ID, sizeof(hdr.magic)) != 0)
+        return DMERR_INVALID_DATA;
+
+    if (!dmf_read_str(res, &hdr.name, sizeof(hdr.name)) ||
+        !dmf_read_le32(res, &hdr.ntracks) ||
+        !dmf_read_le32(res, &hdr.duration))
+        return DMERR_FREAD;
+
+    if (hdr.ntracks >= 64)
+        return DMERR_INVALID_DATA;
+
+    // Allocate track pointers
+    tl->tracks = (DMTimelineTrack **) dmCalloc(hdr.ntracks, sizeof(DMTimelineTrack *));
+    if (tl->tracks == NULL)
+        return DMERR_MALLOC;
+
+    // Copy rest
+    hdr.name[sizeof(hdr.name) - 1] = 0;
+    tl->name     = dm_strdup(hdr.name);
+    tl->duration = hdr.duration;
+    tl->ntracks  = hdr.ntracks;
+
+    // Read tracks
+    for (track = 0; track < tl->ntracks; track++)
+    {
+        if ((err = dmLoadTimelineTrack(res, &(tl->tracks[track]))) != DMERR_OK)
+            return err;
+    }
+    
+    return DMERR_OK;
+}
+
+
+void dmFreeTimelinePoints(DMTimelinePoints *points)
+{
+    dmFree(points->points);
+    points->points = NULL;
+    points->npoints = points->nallocated = 0;
+}
+
+
+void dmFreeTimelineEventParam(DMTimelineEventParam *param)
+{
+    dmFree(param->name);
+    dmFree(param->vstr);
+    dmFreeTimelinePoints(&(param->pts));
+}
+
+
+void dmFreeTimelineEvent(DMTimelineEvent *event)
+{
+    if (event != NULL)
+    {
+        int param;
+        for (param = 0; param < event->nparams; param++)
+            dmFreeTimelineEventParam(&(event->params[param]));
+        dmFree(event->params);
+    }
+}
+
+
+void dmFreeTimelineTrack(DMTimelineTrack *track)
+{
+    if (track != NULL)
+    {
+        int event;
+
+        dmFree(track->name);
+
+        for (event = 0; event < track->nevents; event++)
+            dmFreeTimelineEvent(track->events[event]);
+        dmFree(track->events);
+
+        dmFreeTimelinePoints(&(track->composite.points));
+    }
+}
+
+
+void dmFreeTimeline(DMTimeline *tl)
+{
+    if (tl != NULL)
+    {
+        int i;
+        for (i = 0; i < tl->ntracks; i++)
+            dmFreeTimelineTrack(tl->tracks[i]);
+
+        dmFree(tl->tracks);
+        dmFree(tl->name);
+    }
+}
+
+
+static void dmFreePreparedEventGroup(DMPreparedEventGroup *group)
+{
+    if (group != NULL)
+    {
+        dmFree(group->events);
+        dmFree(group);
+    }
+}
+
+
+void dmFreePreparedTimelineData(DMPreparedTimeline *ptl)
+{
+    if (ptl != NULL)
+    {
+        int group;
+        for (group = 0; group < ptl->ngroups; group++)
+        {
+            dmFreePreparedEventGroup(ptl->groups[group]);
+            ptl->groups[group] = NULL;
+        }
+
+        dmFree(ptl->groups);
+        ptl->groups = NULL;
+    }
+}
+
+
+/* Prepare a loaded timeline for execution. Creates the "stacked" structure
+ * of timeline data for efficient rendering.
+ */
+int dmAddSplitPreparedEventGroup(DMPreparedEventGroup **groups, DMTimelineTrack *track, DMTimelineEvent *event)
+{
+    DMPreparedEventGroup *node;
+    
+    for (node = *groups; node != NULL; node = node->next)
+    {
+    }
+    
+    return DMERR_OK;
+}
+
+
+int dmPrepareTimeline(DMTimeline *tl, DMPreparedTimeline *ptl)
+{
+    int group, ntrack, event, err;
+    DMPreparedEventGroup *groups = NULL, *node;
+
+    // Free previous data
+    dmFreePreparedTimelineData(ptl);
+
+    // Process tracks
+    for (ntrack = 0; ntrack < tl->ntracks; ntrack++)
+    {
+        DMTimelineTrack *track = tl->tracks[ntrack];
+        for (event = 0; event < track->nevents; event++)
+        {
+            if ((err = dmAddSplitPreparedEventGroup(&groups, track, track->events[event])) != DMERR_OK)
+                return err;
+        }
+    }
+    
+    // Compute number of groups
+    ptl->ngroups = 0;
+    for (node = groups; node != NULL; node = node->next)
+        ptl->ngroups++;
+
+    // Allocate linear array for fast access
+    ptl->groups = dmMalloc(sizeof(DMPreparedEventGroup) * ptl->ngroups);
+    if (ptl->groups == NULL)
+        return DMERR_MALLOC;
+
+    // Store pointers in the array
+    for (group = 0, node = groups; node != NULL; node = node->next)
+        ptl->groups[group++] = node;
+    
+    return DMERR_OK;
+}
+
+
+/* Seeks to specified position in the timeline. The execution function
+ * only handles monotonously increasing time, going backwards will not work
+ * there correctly, thus to seek freely this function must be used.
+ */
+int dmSeekTimeline(DMPreparedTimeline *tl, int time)
+{
+    return DMERR_OK;
+}
+
+
+/* "Executes", or rather renders a frame on the specified timeline position.
+ */
+int dmExecuteTimeline(DMPreparedTimeline *tl, SDL_Surface *screen, int time)
+{
+    return DMERR_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmtimelinew.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,430 @@
+/*
+ * dmlib
+ * -- Timeline file writing
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012-2013 Tecnic Software productions (TNSP)
+ */
+#include "dmengine.h"
+#include "dmresw.h"
+
+
+static BOOL dmSaveFloatValue(DMResource *res, DMFloat val)
+{
+    char tmp[DT_FLOAT_STORE_SIZE];
+    snprintf(tmp, DT_FLOAT_STORE_SIZE, "%f", val);
+    return !dmf_write_str(res, tmp, DT_FLOAT_STORE_SIZE);
+}
+
+
+static int dmSaveTimelinePoints(DMResource *res, DMTimelinePoints *points, int type)
+{
+    int point;
+    Uint32 npoints;
+
+    // Save number of points
+    npoints = points->npoints;
+    if (!dmf_write_le32(res, npoints))
+        return DMERR_FWRITE;
+    
+    // Save points
+    for (point = 0; point < points->npoints; point++)
+    {
+        DMTimelinePoint *pt = &(points->points[point]);
+        Uint32 ptype, ptime;
+        ptype = pt->type;
+        ptime = pt->time;
+        if (!dmf_write_le32(res, ptype) ||
+            !dmf_write_le32(res, ptime))
+            return DMERR_FWRITE;
+
+        switch (type)
+        {
+            case EFPT_INT:
+                if (!dmf_write_le32(res, pt->vint))
+                    return DMERR_FWRITE;
+                break;
+
+            case EFPT_FLOAT:
+                if (!dmSaveFloatValue(res, pt->vfloat))
+                    return DMERR_FWRITE;
+                break;
+            
+            case EFPT_VECTOR:
+                if (!dmSaveFloatValue(res, pt->vector.x) ||
+                    !dmSaveFloatValue(res, pt->vector.y) ||
+                    !dmSaveFloatValue(res, pt->vector.z) ||
+                    !dmSaveFloatValue(res, pt->vector.W))
+                    return DMERR_FWRITE;
+                break;
+
+            case EFPT_MATRIX:
+                {
+                    int x, y;
+                    for (y = 0; y < DM_MATRIX_SIZE; y++)
+                    for (x = 0; x < DM_MATRIX_SIZE; x++)
+                    {
+                        if (!dmSaveFloatValue(res, pt->matrix.m[y][x]))
+                            return DMERR_FWRITE;
+                    }
+                }
+                break;
+        }
+    }
+    return DMERR_OK;
+}
+
+
+static int dmSaveTimelineCurve(DMResource *res, DMTimelineCurve *curve)
+{
+    int err;
+
+    if (!dmf_write_byte(res, curve->enabled))
+        return DMERR_FWRITE;
+
+    if ((err = dmSaveTimelinePoints(res, &(curve->points), EFPT_FLOAT)) != DMERR_OK)
+        return err;
+    
+    return DMERR_OK;
+}
+
+
+static int dmSaveTimelineEventParam(DMResource *res, DMTimelineEventParam *param)
+{
+    int err;
+    DMFTimelineEventParam hdr;
+    Uint16 len;
+
+    strncpy(hdr.name, param->name, sizeof(hdr.name));
+    hdr.type = param->type;
+
+    if (!dmf_write_str(res, hdr.name, sizeof(hdr.name)) ||
+        !dmf_write_le32(res, hdr.type))
+        return DMERR_FWRITE;
+
+    switch (param->type)
+    {
+        case EFPT_INT:
+        case EFPT_FLOAT:
+        case EFPT_VECTOR:
+        case EFPT_MATRIX:
+            if ((err = dmSaveTimelinePoints(res, &param->pts, param->type)) != DMERR_OK)
+                return err;
+            break;
+
+        case EFPT_STRING:
+            len = strlen(param->vstr);
+            if (!dmf_write_le16(res, len))
+                return DMERR_FWRITE;
+
+            if (!dmf_write_str(res, param->vstr, len))
+                return DMERR_FWRITE;
+            break;
+    }
+
+    return DMERR_OK;
+}
+
+
+static int dmSaveTimelineEvent(DMResource *res, DMTimelineEvent *event)
+{
+    int param, err;
+    DMFTimelineEvent hdr;
+
+    strncpy(hdr.effectName, event->effect->name, sizeof(hdr.effectName));
+    hdr.start    = event->start;
+    hdr.duration = event->duration;
+    hdr.nparams  = event->nparams;
+
+    if (!dmf_write_le32(res, hdr.start) ||
+        !dmf_write_le32(res, hdr.duration) ||
+        !dmf_write_str(res, hdr.effectName, sizeof(hdr.effectName)) ||
+        !dmf_write_le32(res, hdr.nparams))
+        return DMERR_FWRITE;
+
+    for (param = 0; param < event->nparams; param++)
+    {
+        if ((err = dmSaveTimelineEventParam(res, &(event->params[param]))) != DMERR_OK)
+            return err;
+    }
+
+    return DMERR_OK;
+}
+
+
+static int dmSaveTimelineTrack(DMResource *res, DMTimelineTrack *track)
+{
+    int event, err;
+    DMFTimelineTrack hdr;
+    
+    strncpy(hdr.name, track->name, sizeof(hdr.name));
+
+    if (!dmf_write_le32(res, track->index) ||
+        !dmf_write_le32(res, track->layer) ||
+        !dmf_write_str(res, hdr.name, sizeof(hdr.name)) ||
+        !dmf_write_byte(res, track->enabled) ||
+        !dmf_write_le32(res, track->nevents))
+        return DMERR_FWRITE;
+
+    for (event = 0; event < track->nevents; event++)
+    {
+        if ((err = dmSaveTimelineEvent(res, track->events[event])) != DMERR_OK)
+            return err;
+    }
+
+    if ((err = dmSaveTimelineCurve(res, &(track->composite))) != DMERR_OK)
+        return err;
+
+    return DMERR_OK;
+}
+
+
+int dmSaveTimeline(DMResource *res, DMTimeline *tl)
+{
+    int track, err;
+    DMFTimeline hdr;
+
+    memcpy(&hdr.magic, DT_MAGIC_ID, sizeof(hdr.magic));
+    strncpy(hdr.name, tl->name, sizeof(hdr.name));
+    hdr.ntracks = tl->ntracks;
+    hdr.duration = tl->duration;
+    
+    if (!dmf_write_str(res, hdr.magic, sizeof(hdr.magic)) ||
+        !dmf_write_str(res, hdr.name, sizeof(hdr.name)) ||
+        !dmf_write_le32(res, hdr.ntracks) ||
+        !dmf_write_le32(res, hdr.duration))
+        return DMERR_FWRITE;
+
+    for (track = 0; track < tl->ntracks; track++)
+    {
+        if ((err = dmSaveTimelineTrack(res, tl->tracks[track])) != DMERR_OK)
+            return err;
+    }
+
+    return DMERR_OK;
+}
+
+
+int dmTimelineNew(DMTimeline **ptl, const char *name)
+{
+    DMTimeline *tl;
+    if ((*ptl = tl = dmMalloc0(sizeof(DMTimeline))) == NULL)
+        return DMERR_MALLOC;
+
+    tl->name = dm_strdup(name);
+    
+    return DMERR_OK;
+}
+
+
+int dmTimelineAddTrack(DMTimeline *tl, DMTimelineTrack **ptrack, const char *name)
+{
+    DMTimelineTrack *track;
+    
+    if ((*ptrack = track = dmMalloc0(sizeof(DMTimelineTrack))) == NULL)
+        return DMERR_MALLOC;
+    
+    track->name = dm_strdup(name);
+    track->enabled = TRUE;
+
+    if (tl->ntracks + 1 >= tl->nallocated)
+    {
+        tl->nallocated += 16;
+        tl->tracks = dmRealloc(tl->tracks, sizeof(DMTimelineTrack *) * tl->nallocated);
+        if (tl->tracks == NULL)
+            return DMERR_MALLOC;
+    }
+    
+    tl->tracks[tl->ntracks] = track;
+    tl->ntracks++;
+    
+    return DMERR_OK;
+}
+
+
+int dmTimelineTrackAddEvent(DMTimelineTrack *track, int start, int duration, DMTimelineEvent **pev)
+{
+    DMTimelineEvent *ev;
+    
+    if ((*pev = ev = dmMalloc0(sizeof(DMTimelineEvent))) == NULL)
+        return DMERR_MALLOC;
+    
+    ev->start    = start;
+    ev->duration = duration;
+    
+    if (track->nevents + 1 >= track->nallocated)
+    {
+        track->nallocated += 16;
+        track->events = dmRealloc(track->events, sizeof(DMTimelineEvent *) * track->nallocated);
+        if (track->events == NULL)
+            return DMERR_MALLOC;
+    }
+    
+    track->events[track->nevents] = ev;
+    track->nevents++;
+    
+    return DMERR_OK;
+}
+
+
+int dmTimelineEventSetEffect(DMTimelineEvent *event, DMEffect *ef)
+{
+    int param;
+    if (ef == NULL)
+        return DMERR_INVALID_DATA;
+
+    event->effect = ef;
+    event->nparams = ef->nparams;
+    event->params = dmCalloc(ef->nparams, sizeof(DMTimelineEventParam));
+    if (event->params == NULL)
+        return DMERR_MALLOC;
+    
+    for (param = 0; param < ef->nparams; param++)
+    {
+        DMTimelineEventParam *psrc = &ef->params[param],
+                             *pdst = &event->params[param];
+
+        pdst->name   = dm_strdup(psrc->name);
+        pdst->type   = psrc->type;
+        pdst->vstr   = dm_strdup(psrc->vstr);
+
+        if (psrc->pts.points != NULL && psrc->pts.npoints > 0)
+        {
+            pdst->pts.npoints    = psrc->pts.npoints;
+            pdst->pts.nallocated = psrc->pts.nallocated;
+            pdst->pts.points     = dmMalloc(psrc->pts.nallocated * sizeof(DMTimelinePoint));
+            if (pdst->pts.points == NULL)
+                return DMERR_MALLOC;
+
+            memcpy(pdst->pts.points, psrc->pts.points, pdst->pts.npoints * sizeof(DMTimelinePoint));
+        }
+    }
+    
+    return DMERR_OK;
+}
+
+
+int dmTimelineEventSetEffectByIndex(DMTimelineEvent *event, const int index)
+{
+    if (index < 0 || index >= nengineEffects)
+        return DMERR_INVALID_DATA;
+
+    return dmTimelineEventSetEffect(event, &engineEffects[index]);
+}
+
+
+int dmTimelineEventSetEffectByName(DMTimelineEvent *event, const char *name)
+{
+    return dmTimelineEventSetEffect(event, engineFindEffectByName(name));
+}
+
+
+int dmCopyTimelinePoints(const DMTimelinePoints *src, DMTimelinePoints *dst)
+{
+    if (src->points == NULL || src->npoints <= 0 || src->nallocated <= 0)
+        return DMERR_OK;
+
+    dst->npoints    = src->npoints;
+    dst->nallocated = src->nallocated;
+    dst->points     = dmCalloc(src->nallocated, sizeof(DMTimelinePoint));
+    if (dst->points == NULL)
+        return DMERR_MALLOC;
+
+    memcpy(dst->points, src->points, sizeof(DMTimelinePoint) * src->npoints);
+    
+    return DMERR_OK;
+}
+
+
+int dmCopyTimelineEventParam(const DMTimelineEventParam *src, DMTimelineEventParam *dst)
+{
+    dst->name = dm_strdup(src->name);
+    dst->type = src->type;
+    dst->vstr = dm_strdup(src->vstr);
+
+    return dmCopyTimelinePoints(&src->pts, &dst->pts);
+}
+
+
+int dmCopyTimelineEvent(const DMTimelineEvent *src, DMTimelineEvent **pdst)
+{
+    int param;
+    DMTimelineEvent *dst;
+    if ((*pdst = dst = dmMalloc0(sizeof(DMTimelineEvent))) == NULL)
+        return DMERR_MALLOC;
+    
+    dst->start     = src->start;
+    dst->duration  = src->duration;
+    dst->nparams   = src->nparams;
+    dst->effect    = src->effect;
+    dst->params    = dmCalloc(src->nparams, sizeof(DMTimelineEventParam));
+    if (dst->params == NULL)
+        return DMERR_MALLOC;
+
+    for (param = 0; param < src->nparams; param++)
+    {
+        int err;
+        if ((err = dmCopyTimelineEventParam(&(src->params[param]), &(dst->params[param]))) != DMERR_OK)
+            return err;
+    }
+
+    return DMERR_OK;
+}
+
+
+int dmCopyTimelineCurve(const DMTimelineCurve *src, DMTimelineCurve *dst)
+{
+    dst->enabled = src->enabled;
+    return dmCopyTimelinePoints(&(src->points), &(dst->points));
+}
+
+
+int dmCopyTimelineTrack(const DMTimelineTrack *src, DMTimelineTrack **pdst)
+{
+    int event, err;
+    DMTimelineTrack *dst;
+    if ((*pdst = dst = dmMalloc0(sizeof(DMTimelineTrack))) == NULL)
+        return DMERR_MALLOC;
+
+    if ((dst->events = dmCalloc(src->nevents, sizeof(DMTimelineEvent *))) == NULL)
+        return DMERR_MALLOC;
+    
+    dst->name    = dm_strdup(src->name);
+    dst->enabled = src->enabled;
+    dst->nevents = src->nevents;
+
+    for (event = 0; event < src->nevents; event++)
+    {
+        if ((err = dmCopyTimelineEvent(src->events[event], &(dst->events[event]))) != DMERR_OK)
+            return err;
+    }
+
+    if ((err = dmCopyTimelineCurve(&(src->composite), &(dst->composite))) != DMERR_OK)
+        return err;
+
+    return DMERR_OK;
+}
+
+
+int dmCopyTimeline(const DMTimeline *src, DMTimeline **pdst)
+{
+    int track, err;
+    DMTimeline *dst;
+    if ((*pdst = dst = dmMalloc0(sizeof(DMTimeline))) == NULL)
+        return DMERR_MALLOC;
+    
+    dst->tracks = (DMTimelineTrack **) dmCalloc(src->ntracks, sizeof(DMTimelineTrack *));
+    if (dst->tracks == NULL)
+        return DMERR_MALLOC;
+
+    dst->name     = dm_strdup(src->name);
+    dst->duration = src->duration;
+    dst->ntracks  = src->ntracks;
+
+    for (track = 0; track < src->ntracks; track++)
+    {
+        if ((err = dmCopyTimelineTrack(src->tracks[track], &(dst->tracks[track]))) != DMERR_OK)
+            return err;
+    }
+    
+    return DMERR_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmunscaledblit.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,76 @@
+/*
+ * DMLib
+ * -- Unscaled sprite / surface blitting function template
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012 Tecnic Software productions (TNSP)
+ */
+
+int DM_BLITFUNC_NAME (SDL_Surface *src,
+    const int x0, const int y0,
+    SDL_Surface *dst
+#ifdef DM_BLITFUNC_ARGS
+    DM_BLITFUNC_ARGS
+#endif
+    )
+#ifdef DM_HEADER
+;
+#else
+{
+    int yc;
+    DMQValue xr, yr;
+#ifdef DM_BLITFUNC_VARS
+    DM_BLITFUNC_VARS
+#endif
+    
+    // Clip coordinates
+    if (dmUnscaledClipCoord(&xr, x0, src->w,
+        dst->clip_rect.x, dst->clip_rect.x + dst->clip_rect.w)
+        ||
+        dmUnscaledClipCoord(&yr, y0, src->h,
+        dst->clip_rect.y, dst->clip_rect.y + dst->clip_rect.h))
+        return -1;
+
+#ifdef DM_BLITFUNC_INIT
+    DM_BLITFUNC_INIT
+#endif
+    const int srcadd = src->pitch / DM_BLITFUNC_SRC_BYTES;
+    const int dstadd = xr.vadd - dst->clip_rect.w + dst->clip_rect.x + (dst->pitch / DM_BLITFUNC_DST_BYTES);
+
+    DM_BLITFUNC_SRC_TYPE * sp = ((DM_BLITFUNC_SRC_TYPE *) src->pixels) + (yr.voffs * src->pitch) / DM_BLITFUNC_SRC_BYTES;
+    DM_BLITFUNC_DST_TYPE * dp = ((DM_BLITFUNC_DST_TYPE *) dst->pixels) + (yr.v0 * dst->pitch) / DM_BLITFUNC_DST_BYTES + xr.v0;
+
+    for (yc = yr.v0; yc < yr.v1; yc++)
+    {
+        int xv, xc;
+
+#ifdef DM_BLITFUNC_INNER_INIT
+        DM_BLITFUNC_INNER_INIT
+#endif
+
+        for (xv = xr.voffs, xc = xr.v0; xc < xr.v1; xc++, xv++)
+        {
+            DM_BLITFUNC_INNER
+        }
+        sp += srcadd;
+        dp += dstadd;
+    }
+
+#ifdef DM_BLITFUNC_FINISH
+    DM_BLITFUNC_FINISH
+#endif
+    return 0;
+}
+#endif
+
+
+#undef DM_BLITFUNC_NAME
+#undef DM_BLITFUNC_ARGS
+#undef DM_BLITFUNC_SRC_BYTES
+#undef DM_BLITFUNC_DST_BYTES
+#undef DM_BLITFUNC_SRC_TYPE
+#undef DM_BLITFUNC_DST_TYPE
+#undef DM_BLITFUNC_VARS
+#undef DM_BLITFUNC_INIT
+#undef DM_BLITFUNC_INNER_INIT
+#undef DM_BLITFUNC_INNER
+#undef DM_BLITFUNC_FINISH
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmvecmat.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,451 @@
+/*
+ * DMLib
+ * -- Vector and matrix functions
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2011-2012 Tecnic Software productions (TNSP)
+ */
+#include "dmvecmat.h"
+
+
+void dm_vector_add_n(DMVector *dst, const DMVector *src, const int nlist)
+{
+    int i;
+    for (i = 0; i < nlist; i++)
+    {
+#ifdef DM_USE_SIMD
+    asm("movups      %2,     %%xmm1\n"
+        "movups      %1,     %%xmm2\n"
+        "addps       %%xmm2, %%xmm1\n"
+        "movups      %%xmm1, %0\n"
+        : "=m" (dst[i])
+        : "m" (dst[i]), "m" (src[i])
+        : "memory", "%xmm1", "%xmm2");
+#else
+        dm_vector_add(dst + i, src + i);
+#endif
+    }
+}
+
+
+void dm_vector_add_r_n(DMVector *dst, const DMVector *src1, const DMVector *src2, const int nlist)
+{
+    int i;
+    for (i = 0; i < nlist; i++)
+    {
+#ifdef DM_USE_SIMD
+    asm("movups      %2,     %%xmm1\n"
+        "movups      %1,     %%xmm2\n"
+        "addps       %%xmm2, %%xmm1\n"
+        "movups      %%xmm1, %0\n"
+        : "=m" (dst[i])
+        : "m" (src1[i]), "m" (src2[i])
+        : "memory", "%xmm1", "%xmm2");
+#else
+        dm_vector_add_r(dst + i, src1 + i, src2 + i);
+#endif
+    }
+}
+
+
+void dm_vector_sub_n(DMVector *dst, const DMVector *src, const int nlist)
+{
+    int i;
+    for (i = 0; i < nlist; i++)
+    {
+#ifdef DM_USE_SIMD
+    asm("movups      %2,     %%xmm1\n"
+        "movups      %1,     %%xmm2\n"
+        "subps       %%xmm2, %%xmm1\n"
+        "movups      %%xmm1, %0\n"
+        : "=m" (dst[i])
+        : "m" (dst[i]), "m" (src[i])
+        : "memory", "%xmm1", "%xmm2");
+#else
+        dm_vector_add(dst + i, src + i);
+#endif
+    }
+}
+
+
+void dm_vector_sub_r_n(DMVector *dst, const DMVector *src1, const DMVector *src2, const int nlist)
+{
+    int i;
+    for (i = 0; i < nlist; i++)
+    {
+#ifdef DM_USE_SIMD
+    asm("movups      %2,     %%xmm1\n"
+        "movups      %1,     %%xmm2\n"
+        "subps       %%xmm2, %%xmm1\n"
+        "movups      %%xmm1, %0\n"
+        : "=m" (dst[i])
+        : "m" (src1[i]), "m" (src2[i])
+        : "memory", "%xmm1", "%xmm2");
+#else
+        dm_vector_sub_r(dst + i, src1 + i, src2 + i);
+#endif
+    }
+}
+
+
+/* Multiply given vector with a matrix
+ */
+void dm_vector_mul_by_mat(DMVector *vd, const DMVector *vs, const DMMatrix *mat)
+{
+#ifdef DM_USE_SIMD
+    asm volatile(
+        "mov           %1,        %%edx\n"
+        "movups        (%%edx),   %%xmm4\n"
+        "movups      16(%%edx),   %%xmm5\n"
+        "movups      32(%%edx),   %%xmm6\n"
+        "movups      48(%%edx),   %%xmm7\n"
+
+        // vector -> xmm0
+        "movups      %2,     %%xmm0\n"
+        
+        // zero final result in xmm2
+        "xorps       %%xmm2, %%xmm2\n"
+
+        // perform shuffle and multiply and add whole "column" "X"
+        "movups      %%xmm0, %%xmm1\n"
+        "shufps      $0x00,  %%xmm1, %%xmm1\n"
+        "mulps       %%xmm4, %%xmm1\n"
+        "addps       %%xmm1, %%xmm2\n"
+
+        // Y
+        "movups      %%xmm0, %%xmm1\n"
+        "shufps      $0x55,  %%xmm1, %%xmm1\n"
+        "mulps       %%xmm5, %%xmm1\n"
+        "addps       %%xmm1, %%xmm2\n"
+
+        // Z
+        "movups      %%xmm0, %%xmm1\n"
+        "shufps      $0xAA,  %%xmm1, %%xmm1\n"
+        "mulps       %%xmm6, %%xmm1\n"
+        "addps       %%xmm1, %%xmm2\n"
+
+        // W
+        "movups      %%xmm0, %%xmm1\n"
+        "shufps      $0xFF,  %%xmm1, %%xmm1\n"
+        "mulps       %%xmm7, %%xmm1\n"
+        "addps       %%xmm1, %%xmm2\n"
+
+        // Result ->
+        "movups      %%xmm2, %0\n"
+        : "=m" (vd)
+        : "m" (mat), "m" (vs)
+        : "memory", "%edx", "%xmm0", "%xmm1", "%xmm2", "%xmm4", "%xmm5", "%xmm6", "%xmm7"
+        );
+#else
+    vd->x = (vs->x * mat->m[0][0]) + (vs->y * mat->m[1][0]) + (vs->z * mat->m[2][0]);
+    vd->y = (vs->x * mat->m[0][1]) + (vs->y * mat->m[1][1]) + (vs->z * mat->m[2][1]);
+    vd->z = (vs->x * mat->m[0][2]) + (vs->y * mat->m[1][2]) + (vs->z * mat->m[2][2]);
+#endif
+}
+
+
+/* Multiply list of given vectors with given matrix.
+ */
+void dm_vector_mul_by_mat_n(DMVector *list, const int nlist, const DMMatrix *mat)
+{
+    int i;
+
+#ifdef DM_USE_SIMD
+    asm volatile(
+        "mov           %0,        %%edx\n"
+        "movups        (%%edx),   %%xmm4\n"
+        "movups      16(%%edx),   %%xmm5\n"
+        "movups      32(%%edx),   %%xmm6\n"
+        "movups      48(%%edx),   %%xmm7\n"
+        :
+        : "m" (mat)
+        : "%edx", "%xmm4", "%xmm5", "%xmm6", "%xmm7"
+        );
+#endif
+
+    for (i = 0; i < nlist; i++)
+    {
+#ifdef DM_USE_SIMD
+        asm volatile
+            (
+            // list[i] -> xmm0
+            "movups      %1,     %%xmm0\n"
+            
+            // zero final result in xmm2
+            "xorps       %%xmm2, %%xmm2\n"
+
+            // perform shuffle and multiply and add whole "column" "X"
+            "movups      %%xmm0, %%xmm1\n"
+            "shufps      $0x00,  %%xmm1, %%xmm1\n"
+            "mulps       %%xmm4, %%xmm1\n"
+            "addps       %%xmm1, %%xmm2\n"
+
+            // Y
+            "movups      %%xmm0, %%xmm1\n"
+            "shufps      $0x55,  %%xmm1, %%xmm1\n"
+            "mulps       %%xmm5, %%xmm1\n"
+            "addps       %%xmm1, %%xmm2\n"
+
+            // Z
+            "movups      %%xmm0, %%xmm1\n"
+            "shufps      $0xAA,  %%xmm1, %%xmm1\n"
+            "mulps       %%xmm6, %%xmm1\n"
+            "addps       %%xmm1, %%xmm2\n"
+
+            // W
+            "movups      %%xmm0, %%xmm1\n"
+            "shufps      $0xFF,  %%xmm1, %%xmm1\n"
+            "mulps       %%xmm7, %%xmm1\n"
+            "addps       %%xmm1, %%xmm2\n"
+
+            // Result ->
+            "movups      %%xmm2, %0\n"
+            : "=m" (list[i])
+            : "m" (list[i])
+            : "memory", "%xmm0", "%xmm1", "%xmm2", "%xmm4", "%xmm5", "%xmm6", "%xmm7");
+#else
+        DMVector q;
+        memcpy(&q, &list[i], sizeof(DMVector));
+
+        list[i].x = (q.x * mat->m[0][0]) + (q.y * mat->m[1][0]) + (q.z * mat->m[2][0]);
+        list[i].y = (q.x * mat->m[0][1]) + (q.y * mat->m[1][1]) + (q.z * mat->m[2][1]);
+        list[i].z = (q.x * mat->m[0][2]) + (q.y * mat->m[1][2]) + (q.z * mat->m[2][2]);
+#endif
+    }
+}
+
+
+/* Set matrix to unit-matrix
+ */
+void dm_matrix_unit(DMMatrix *mat)
+{
+    memset(mat, 0, sizeof(DMMatrix));
+    mat->m[0][0] = 1.0f;
+    mat->m[1][1] = 1.0f;
+    mat->m[2][2] = 1.0f;
+    mat->m[3][3] = 1.0f;
+}
+
+
+/* Transpose the matrix mat2 to mat1
+ */
+void dm_matrix_transpose(DMMatrix *mat1, const DMMatrix *mat2)
+{
+    int i, j;
+
+    for (i = 0; i < DM_MATRIX_SIZE; i++)
+        for (j = 0; j < DM_MATRIX_SIZE; j++)
+            mat1->m[i][j] = mat2->m[j][i];
+}
+
+
+/* Multiply matrices mat1 and mat2, putting result into mat1
+ */
+void dm_matrix_mul_r(DMMatrix *dst, const DMMatrix *mat1, const DMMatrix *mat2)
+{
+#ifdef DM_USE_SIMD
+    asm volatile(
+        "mov           %1,        %%ebx\n"
+        "mov           %2,        %%edx\n"
+
+        // --------------------------------------------------
+
+        // 0
+        "movups        (%%ebx),   %%xmm0\n" // mat1[0]
+        "movups        (%%edx),   %%xmm1\n" // mat2[0]
+        "shufps        $0x00, %%xmm1, %%xmm1\n" // mat2[0][0]
+        "mulps         %%xmm0,    %%xmm1\n"
+        "movups        %%xmm1,    %%xmm3\n"
+        
+        // 1
+        "movups        16(%%ebx), %%xmm0\n" // mat1[0]
+        "movups        (%%edx),   %%xmm1\n" // mat2[0]
+        "shufps        $0x55, %%xmm1, %%xmm1\n" // mat2[0][1]
+        "mulps         %%xmm0,    %%xmm1\n"
+        "addps         %%xmm1,    %%xmm3\n"
+
+        // 2
+        "movups        32(%%ebx), %%xmm0\n" // mat1[0]
+        "movups        (%%edx),   %%xmm1\n" // mat2[0]
+        "shufps        $0xAA, %%xmm1, %%xmm1\n" // mat2[0][2]
+        "mulps         %%xmm0,    %%xmm1\n"
+        "addps         %%xmm1,    %%xmm3\n"
+
+        // 3
+        "movups        48(%%ebx), %%xmm0\n" // mat1[0]
+        "movups        (%%edx),   %%xmm1\n" // mat2[0]
+        "shufps        $0xFF, %%xmm1, %%xmm1\n" // mat2[0][3]
+        "mulps         %%xmm0,    %%xmm1\n"
+        "addps         %%xmm1,    %%xmm3\n"
+
+        "mov           %0,        %%ebx\n"
+        "movups        %%xmm3,    (%%ebx)\n"
+
+        // --------------------------------------------------
+
+        "mov           %1,        %%ebx\n"
+
+        // 0
+        "movups        (%%ebx),   %%xmm0\n" // mat1[0]
+        "movups        16(%%edx), %%xmm1\n" // mat2[1]
+        "shufps        $0x00, %%xmm1, %%xmm1\n" // mat2[0][0]
+        "mulps         %%xmm0,    %%xmm1\n"
+        "movups        %%xmm1,    %%xmm3\n"
+        
+        // 1
+        "movups        16(%%ebx), %%xmm0\n" // mat1[0]
+        "movups        16(%%edx), %%xmm1\n" // mat2[1]
+        "shufps        $0x55, %%xmm1, %%xmm1\n" // mat2[0][1]
+        "mulps         %%xmm0,    %%xmm1\n"
+        "addps         %%xmm1,    %%xmm3\n"
+
+        // 2
+        "movups        32(%%ebx), %%xmm0\n" // mat1[0]
+        "movups        16(%%edx), %%xmm1\n" // mat2[1]
+        "shufps        $0xAA, %%xmm1, %%xmm1\n" // mat2[0][2]
+        "mulps         %%xmm0,    %%xmm1\n"
+        "addps         %%xmm1,    %%xmm3\n"
+
+        // 3
+        "movups        48(%%ebx), %%xmm0\n" // mat1[0]
+        "movups        16(%%edx), %%xmm1\n" // mat2[1]
+        "shufps        $0xFF, %%xmm1, %%xmm1\n" // mat2[0][3]
+        "mulps         %%xmm0,    %%xmm1\n"
+        "addps         %%xmm1,    %%xmm3\n"
+
+        "mov           %0,        %%ebx\n"
+        "movups        %%xmm3,    16(%%ebx)\n"
+
+        // --------------------------------------------------
+
+        "mov           %1,        %%ebx\n"
+
+        // 0
+        "movups        (%%ebx),   %%xmm0\n" // mat1[0]
+        "movups        32(%%edx), %%xmm1\n" // mat2[1]
+        "shufps        $0x00, %%xmm1, %%xmm1\n" // mat2[0][0]
+        "mulps         %%xmm0,    %%xmm1\n"
+        "movups        %%xmm1,    %%xmm3\n"
+        
+        // 1
+        "movups        16(%%ebx), %%xmm0\n" // mat1[0]
+        "movups        32(%%edx), %%xmm1\n" // mat2[1]
+        "shufps        $0x55, %%xmm1, %%xmm1\n" // mat2[0][1]
+        "mulps         %%xmm0,    %%xmm1\n"
+        "addps         %%xmm1,    %%xmm3\n"
+
+        // 2
+        "movups        32(%%ebx), %%xmm0\n" // mat1[0]
+        "movups        32(%%edx), %%xmm1\n" // mat2[1]
+        "shufps        $0xAA, %%xmm1, %%xmm1\n" // mat2[0][2]
+        "mulps         %%xmm0,    %%xmm1\n"
+        "addps         %%xmm1,    %%xmm3\n"
+
+        // 3
+        "movups        48(%%ebx), %%xmm0\n" // mat1[0]
+        "movups        32(%%edx), %%xmm1\n" // mat2[1]
+        "shufps        $0xFF, %%xmm1, %%xmm1\n" // mat2[0][3]
+        "mulps         %%xmm0,    %%xmm1\n"
+        "addps         %%xmm1,    %%xmm3\n"
+
+        "mov           %0,        %%ebx\n"
+        "movups        %%xmm3,    32(%%ebx)\n"
+
+        // --------------------------------------------------
+
+        "mov           %1,        %%ebx\n"
+
+        // 0
+        "movups        (%%ebx),   %%xmm0\n" // mat1[0]
+        "movups        48(%%edx), %%xmm1\n" // mat2[1]
+        "shufps        $0x00, %%xmm1, %%xmm1\n" // mat2[0][0]
+        "mulps         %%xmm0,    %%xmm1\n"
+        "movups        %%xmm1,    %%xmm3\n"
+        
+        // 1
+        "movups        16(%%ebx), %%xmm0\n" // mat1[0]
+        "movups        48(%%edx), %%xmm1\n" // mat2[1]
+        "shufps        $0x55, %%xmm1, %%xmm1\n" // mat2[0][1]
+        "mulps         %%xmm0,    %%xmm1\n"
+        "addps         %%xmm1,    %%xmm3\n"
+
+        // 2
+        "movups        32(%%ebx), %%xmm0\n" // mat1[0]
+        "movups        48(%%edx), %%xmm1\n" // mat2[1]
+        "shufps        $0xAA, %%xmm1, %%xmm1\n" // mat2[0][2]
+        "mulps         %%xmm0,    %%xmm1\n"
+        "addps         %%xmm1,    %%xmm3\n"
+
+        // 3
+        "movups        48(%%ebx), %%xmm0\n" // mat1[0]
+        "movups        48(%%edx), %%xmm1\n" // mat2[1]
+        "shufps        $0xFF, %%xmm1, %%xmm1\n" // mat2[0][3]
+        "mulps         %%xmm0,    %%xmm1\n"
+        "addps         %%xmm1,    %%xmm3\n"
+
+        "mov           %0,        %%ebx\n"
+        "movups        %%xmm3,    48(%%ebx)\n"
+
+        : "=m" (dst)
+        : "m" (mat1), "m" (mat2)
+        : "memory", "%edx", "%ebx", "%xmm0", "%xmm2", "%xmm3"
+        );
+#else
+    int i, j;
+    for (i = 0; i < DM_MATRIX_SIZE; i++)
+        for (j = 0; j < DM_MATRIX_SIZE; j++)
+            dst->m[i][j] =
+                (mat1->m[i][0] * mat2->m[0][j]) +
+                (mat1->m[i][1] * mat2->m[1][j]) +
+                (mat1->m[i][2] * mat2->m[2][j]);
+#endif
+}
+
+
+void dm_matrix_mul(DMMatrix *mat1, const DMMatrix *mat2)
+{
+    DMMatrix tmpM;
+    dm_matrix_mul_r(&tmpM, mat1, mat2);
+    memcpy(mat1, &tmpM, sizeof(DMMatrix));
+}
+
+
+/* Multiply given list of matrices (size of nMatrices units) with given matrix.
+ */
+void dm_matrix_mul_n(DMMatrix * list, const int nlist, const DMMatrix *mat)
+{
+    int i;
+    for (i = 0; i < nlist; i++)
+        dm_matrix_mul(&list[i], mat);
+}
+
+
+/* Optimized rotation matrix creation
+ */
+void dm_matrix_rot(DMMatrix *mat,
+    const DMFloat sx, const DMFloat sy, const DMFloat sz,
+    const DMFloat cx, const DMFloat cy, const DMFloat cz)
+{
+    const DMFloat
+        q = cx * sz,
+        l = cx * cz,
+        i = sx * sz,
+        j = sx * cz;
+
+    memset(mat, 0, sizeof(DMMatrix));
+
+    mat->m[0][0] = cy * cz;
+    mat->m[0][1] = cy * sz;
+    mat->m[0][2] = -sy;
+
+
+    mat->m[1][0] = (sy * j) - q;
+    mat->m[1][1] = (sy * i) + l;
+    mat->m[1][2] = sx * cy;
+
+
+    mat->m[2][0] = (sy * l) + i;
+    mat->m[2][1] = (sy * q) - j;
+    mat->m[2][2] = cx * cy;
+
+    mat->m[3][3] = 1.0f;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmvecmat.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,153 @@
+/*
+ * DMLib
+ * -- Vector and matrix functions
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2011-2012 Tecnic Software productions (TNSP)
+ */
+#ifndef DMVECMAT_H
+#define DMVECMAT_H
+#include "dmlib.h"
+
+#include <math.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DM_MATRIX_SIZE	(4)
+
+typedef struct
+{
+    DMFloat x, y, z, W;
+} DMVector;
+
+typedef	struct
+{
+    DMFloat m[DM_MATRIX_SIZE][DM_MATRIX_SIZE];
+} DMMatrix;
+
+
+void    dm_vector_add_n(DMVector *dst, const DMVector *src, const int nlist);
+void    dm_vector_add_r_n(DMVector *dst, const DMVector *src1, const DMVector *src2, const int nlist);
+void    dm_vector_sub_n(DMVector *dst, const DMVector *src, const int nlist);
+void    dm_vector_sub_r_n(DMVector *dst, const DMVector *src1, const DMVector *src2, const int nlist);
+
+void    dm_vector_mul_by_mat(DMVector *vd, const DMVector *vs, const DMMatrix *mat);
+void    dm_vector_mul_by_mat_n(DMVector *list, const int nlist, const DMMatrix *mat);
+
+void    dm_matrix_unit(DMMatrix *mat);
+void    dm_matrix_transpose(DMMatrix *mat1, const DMMatrix *mat2);
+
+void    dm_matrix_mul(DMMatrix *mat1, const DMMatrix *mat2);
+void    dm_matrix_mul_r(DMMatrix *dst, const DMMatrix *mat1, const DMMatrix *mat2);
+void    dm_matrix_mul_n(DMMatrix *list, const int nlist, const DMMatrix *mat);
+
+void    dm_matrix_rot(DMMatrix *mat,
+        const DMFloat sx, const DMFloat sy, const DMFloat sz,
+        const DMFloat cx, const DMFloat cy, const DMFloat cz);
+
+
+/* Basic vector operations
+ */
+static inline void dm_vector_copy(DMVector *vd, const DMVector *vs)
+{
+    memcpy(vd, vs, sizeof(DMVector));
+}
+
+
+static inline void dm_vector_add(DMVector *vr, const DMVector *v2)
+{
+    vr->x += v2->x;
+    vr->y += v2->y;
+    vr->z += v2->z;
+}
+
+
+static inline void dm_vector_add_r(DMVector *vr, const DMVector *v1, const DMVector *v2)
+{
+    vr->x = v1->x + v2->x;
+    vr->y = v1->y + v2->y;
+    vr->z = v1->z + v2->z;
+}
+
+
+static inline void dm_vector_sub(DMVector *vr, const DMVector *v2)
+{
+    vr->x -= v2->x;
+    vr->y -= v2->y;
+    vr->z -= v2->z;
+}
+
+
+static inline void dm_vector_sub_r(DMVector *vr, const DMVector *v1, const DMVector *v2)
+{
+    vr->x = v1->x - v2->x;
+    vr->y = v1->y - v2->y;
+    vr->z = v1->z - v2->z;
+}
+
+
+/* Returns dot-product of two given vectors
+ */
+static inline DMFloat dm_vector_dot(const DMVector *v1, const DMVector *v2)
+{
+    return (v1->x * v2->x) + (v1->y * v2->y) + (v1->z * v2->z);
+}
+
+
+/* Return vector length
+ */
+static inline DMFloat dm_vector_length(const DMVector *vs)
+{
+    return sqrt((vs->x * vs->x) + (vs->y * vs->y) + (vs->z * vs->z));
+}
+
+
+/* Normalize vector
+ */
+static inline void dm_vector_normalize(DMVector *vec)
+{
+    DMFloat l = dm_vector_length(vec);
+
+    if (l > 0.0f)
+    {
+        l = 1.0f / l;
+        vec->x *= l;
+        vec->y *= l;
+        vec->z *= l;
+    }
+}
+
+
+/* Scale given vector
+ */
+static inline void dm_vector_scale(DMVector * vec, const DMFloat k)
+{
+    vec->x *= k;
+    vec->y *= k;
+    vec->z *= k;
+}
+
+
+/* Returns cross-product of two given vectors
+ */
+static inline void dm_vector_cross(DMVector *vr, const DMVector *v1, const DMVector *v2)
+{
+    vr->x = (v1->y * v2->z) - (v1->z * v2->y);
+    vr->y = (v1->z * v2->x) - (v1->x * v2->z);
+    vr->z = (v1->x * v2->y) - (v1->y * v2->x);
+}
+
+
+/* Make rotation matrix from given angles (radians)
+ */
+static inline void dm_matrix_rot_a(DMMatrix *mat, const DMFloat ax, const DMFloat ay, const DMFloat az)
+{
+    dm_matrix_rot(mat, sin(ax), sin(ay), sin(az), cos(ax), cos(ay), cos(az));
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif // DMVECMAT_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmwav.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,61 @@
+/*
+ * DMLib
+ * -- Wav file writing
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012 Tecnic Software productions (TNSP)
+ */
+#include "dmwav.h"
+#include "dmfile.h"
+
+
+BOOL dmWriteWAVChunk(FILE * f, DMWaveChunk *ch)
+{
+    return dm_fwrite_str(f, ch->chunkID, 4) && dm_fwrite_le32(f, ch->chunkSize);
+}
+
+
+void dmMakeWAVChunk(DMWaveChunk *ch, const char *chunkID, const Uint32 chunkSize)
+{
+    memcpy(&(ch->chunkID), (const void *) chunkID, 4);
+    ch->chunkSize = chunkSize;
+}
+
+
+void dmWriteWAVHeader(FILE *outFile, int sampBits, int sampFreq, int sampChn, size_t sampLen)
+{
+    DMWaveFile wav;
+    
+    // PCM WAVE chunk
+    dmMakeWAVChunk(&wav.chFormat, DM_WAVE_FMT_ID, (2 + 2 + 4 + 4 + 2 + 2));
+
+    wav.wFormatTag = DM_WAVE_FORMAT_PCM;
+    wav.nChannels = sampChn;
+    wav.nSamplesPerSec = sampFreq;
+    wav.nAvgBytesPerSec = (sampBits * sampChn * sampFreq) / 8;
+    wav.nBlockAlign = (sampBits * sampChn) / 8;
+    wav.wBitsPerSample = sampBits;
+
+    // Data chunk
+    dmMakeWAVChunk(&wav.chData, DM_WAVE_DATA_ID, (sampLen * wav.nBlockAlign));
+
+    // RIFF header
+    memcpy(&wav.riffID, (const void *) DM_WAVE_RIFF_ID, 4);
+    memcpy(&wav.riffType, (const void *) DM_WAVE_WAVE_ID, 4);
+    wav.fileSize = ((4 + 4 + 4) + wav.chFormat.chunkSize + wav.chData.chunkSize);
+
+    // Write header
+    dm_fwrite_str(outFile, wav.riffID, sizeof(wav.riffID));
+    dm_fwrite_le32(outFile, wav.fileSize);
+    
+    dm_fwrite_str(outFile, wav.riffType, sizeof(wav.riffType));
+    dmWriteWAVChunk(outFile, &wav.chFormat);
+    
+    dm_fwrite_le16(outFile, wav.wFormatTag);
+    dm_fwrite_le16(outFile, wav.nChannels);
+    dm_fwrite_le32(outFile, wav.nSamplesPerSec);
+    dm_fwrite_le32(outFile, wav.nAvgBytesPerSec);
+    dm_fwrite_le16(outFile, wav.nBlockAlign);
+    dm_fwrite_le16(outFile, wav.wBitsPerSample);
+    
+    dmWriteWAVChunk(outFile, &wav.chData);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmwav.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,60 @@
+/*
+ * DMLib
+ * -- Wav file writing
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012 Tecnic Software productions (TNSP)
+ */
+#ifndef DMWAV_H
+#define DMWAV_H
+
+#include "dmlib.h"
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DM_WAVE_FORMAT_PCM     (1)
+#define DM_WAVE_RIFF_ID        "RIFF"
+#define DM_WAVE_WAVE_ID        "WAVE"
+#define DM_WAVE_FMT_ID         "fmt "
+#define DM_WAVE_DATA_ID        "data"
+
+
+typedef struct
+{
+    Uint8     chunkID[4];
+    Uint32    chunkSize;
+} DMWaveChunk; 
+
+
+typedef struct
+{
+    Uint8     riffID[4];
+    Uint32    fileSize;
+    Uint8     riffType[4];
+
+    DMWaveChunk chFormat;
+
+    Uint16    wFormatTag;
+    Uint16    nChannels;
+    Uint32    nSamplesPerSec;
+    Uint32    nAvgBytesPerSec;
+    Uint16    nBlockAlign;
+    Uint16    wBitsPerSample;
+
+    DMWaveChunk chData;
+    // Data follows here
+} DMWaveFile;
+
+
+BOOL dmWriteWAVChunk(FILE * f, DMWaveChunk *ch);
+void dmMakeWAVChunk(DMWaveChunk *ch, const char *chunkID, const Uint32 chunkSize);
+void dmWriteWAVHeader(FILE *outFile, int sampBits, int sampFreq, int sampChn, size_t sampLen);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DMWAV_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib64gfx.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,864 @@
+/*
+ * Functions for reading and converting various restricted
+ * C64/etc and/or indexed/paletted graphics formats.
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012 Tecnic Software productions (TNSP)
+ *
+ * Please read file 'COPYING' for information on license and distribution.
+ */
+#include "lib64gfx.h"
+
+#define BUF_SIZE_INITIAL   (16*1024)
+#define BUF_SIZE_GROW      (4*1024)
+
+
+char * dmC64GetImageTypeString(char *buf, const size_t len, const int type)
+{
+    snprintf(buf, len,
+        "%s%s%s",
+        (type & D64_FMT_FLI) ? "FLI " : "",
+        (type & D64_FMT_MC) ? "MCol" : "HiRes",
+        (type & D64_FMT_ILACE) ? " Ilace" : ""
+        );
+
+    return buf;
+}
+
+
+// Based on Pepto's palette, stolen from VICE
+DMColor dmC64Palette[C64_NCOLORS] =
+{
+    { 0x00, 0x00, 0x00, 0xff },
+    { 0xFF, 0xFF, 0xFF, 0xff },
+    { 0x68, 0x37, 0x2B, 0xff },
+    { 0x70, 0xA4, 0xB2, 0xff },
+    { 0x6F, 0x3D, 0x86, 0xff },
+    { 0x58, 0x8D, 0x43, 0xff },
+    { 0x35, 0x28, 0x79, 0xff },
+    { 0xB8, 0xC7, 0x6F, 0xff },
+    { 0x6F, 0x4F, 0x25, 0xff },
+    { 0x43, 0x39, 0x00, 0xff },
+    { 0x9A, 0x67, 0x59, 0xff },
+    { 0x44, 0x44, 0x44, 0xff },
+    { 0x6C, 0x6C, 0x6C, 0xff },
+    { 0x9A, 0xD2, 0x84, 0xff },
+    { 0x6C, 0x5E, 0xB5, 0xff },
+    { 0x95, 0x95, 0x95, 0xff },
+};
+
+
+const size_t dmC64DefaultSizes[DT_LAST] =
+{
+    C64_SCR_COLOR_SIZE,
+    C64_SCR_BITMAP_SIZE,
+    C64_SCR_SCREEN_SIZE,
+    1,
+    C64_SCR_EXTRADATA,
+};
+
+
+#define DM_GET_ADDR_LO(addr) ((addr) & 0xff)
+#define DM_GET_ADDR_HI(addr) (((addr) >> 8) & 0xff)
+
+
+static BOOL dmCompareAddr16(const Uint8 *buf, const size_t offs, const Uint16 addr)
+{
+    return buf[offs] == DM_GET_ADDR_LO(addr) &&
+           buf[offs + 1] == DM_GET_ADDR_HI(addr);
+}
+
+
+int dmC64ConvertCSData(DMImage *img,
+    int xoffs, int yoffs, const Uint8 *buf,
+    int width, int height, BOOL multicolor, int *colors)
+{
+    int yc, widthpx = width * 8;
+    Uint8 *dp;
+
+    if (img == NULL)
+        return DMERR_NULLPTR;
+
+    if (xoffs < 0 || yoffs < 0 ||
+        xoffs > img->width - widthpx ||
+        yoffs > img->height - height)
+        return DMERR_INVALID_ARGS;
+
+    dp = img->data + (yoffs * img->pitch) + xoffs;
+
+    if (multicolor)
+    {
+        for (yc = 0; yc < height; yc++)
+        {
+            const int offs = yc * width;
+            int xc;
+            Uint8 *d = dp;
+
+            for (xc = 0; xc < widthpx / 2; xc++)
+            {
+                const int b = buf[offs + (xc / 4)];
+                const int v = 6 - ((xc * 2) & 6);
+                const Uint8 c = colors[(b >> v) & 3];
+                
+                *d++ = c;
+                *d++ = c;
+            }
+
+            dp += img->pitch;
+        }
+    }
+    else
+    {
+        for (yc = 0; yc < height; yc++)
+        {
+            const int offs = yc * width;
+            int xc;
+            Uint8 *d = dp;
+
+            for (xc = 0; xc < widthpx; xc++)
+            {
+                const int b = buf[offs + (xc / 8)];
+                const int v = 7 - (xc & 7);
+                const Uint8 c = colors[(b >> v) & 1];
+                
+                *d++ = c;
+            }
+
+            dp += img->pitch;
+        }
+    }
+    
+    return DMERR_OK;
+}
+
+
+static int fmtProbeDrazPaint20Packed(const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt)
+{
+    const char *ident = (const char *) buf + 2;
+
+    if (len > 22 &&
+        dmCompareAddr16(buf, 0, fmt->addr) &&
+        strncmp(ident, "DRAZPAINT ", 10) == 0 &&
+        ident[11] == '.' && (
+        (ident[10] == '1' && ident[12] == '4') ||
+        (ident[10] == '2' && ident[12] == '0')
+        ))
+        return DM_PROBE_SCORE_MAX;
+
+    return DM_PROBE_SCORE_FALSE;
+}
+
+
+static int dmDecodeGenericRLE(Uint8 **mem, Uint8 **pdstEnd, const Uint8 *src, const Uint8 *srcEnd, const Uint8 rleMarker)
+{
+    Uint8 *dst, *dstEnd;
+
+    if ((*mem = dmMalloc(C64_RAM_SIZE)) == NULL)
+        return DMERR_MALLOC;
+    
+    dst       = *mem;
+    dstEnd    = *mem + C64_RAM_SIZE;
+
+    while (src <= srcEnd && dst <= dstEnd)
+    {
+        int c = *src++;
+        if (c == rleMarker && src + 2 <= srcEnd)
+        {
+            int cnt = *src++;
+            c = *src++;
+            while (cnt-- && dst <= dstEnd)
+                *dst++ = c;
+        }
+        else
+            *dst++ = c;
+    }
+
+    *pdstEnd = dst;
+
+    return DMERR_OK;
+}
+
+
+static int fmtDecodeDrazPaintPacked(DMC64Image *img, const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt)
+{
+    int res;
+    Uint8 *mem = NULL, *dstEnd;
+
+    if ((res = dmDecodeGenericRLE(&mem, &dstEnd, buf + 0x0e, buf + len, *(buf + 0x0d))) != DMERR_OK)
+        goto out;
+
+    res = dmC64DecodeGenericBMP(img, mem, dstEnd - mem + 1, fmt);
+
+out:
+    dmFree(mem);
+    return res;
+}
+
+
+static int fmtProbeDrazLace10Packed(const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt)
+{
+    const char *ident = (const char *) buf + 2;
+    if (len > 22 &&
+        dmCompareAddr16(buf, 0, fmt->addr) &&
+        strncmp(ident, "DRAZLACE! 1.0", 13) == 0)
+        return DM_PROBE_SCORE_MAX;
+    
+    return DM_PROBE_SCORE_FALSE;
+}
+
+
+static BOOL fmtDrazLaceSetLaceType(DMC64Image *img, const struct _DMC64EncDecOp *op, const Uint8 *buf, const size_t len)
+{
+    (void) len;
+
+    img->laceType = buf[op->offs] ? D64_ILACE_RES : D64_ILACE_COLOR;
+    img->laceBank1 = img->laceBank2 = 0;
+    return TRUE;
+}
+
+
+#define AMICA_DM_PROBE_SIZE 2048
+static int fmtProbeAmicaPaintPacked(const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt)
+{
+    size_t i, n;
+    if (len < AMICA_DM_PROBE_SIZE || !dmCompareAddr16(buf, 0, fmt->addr))
+        return DM_PROBE_SCORE_FALSE;
+    
+    // Interpaint Hi-Res gives a false positive
+    if (len == 9002)
+        return DM_PROBE_SCORE_FALSE;
+    
+    for (n = 0, i = 2; i < len; i++)
+        if (buf[i] == 0xC2) n++;
+    
+    if (n > 50)
+        return DM_PROBE_SCORE_GOOD;
+    if (n > 25)
+        return DM_PROBE_SCORE_AVG;
+    if (n > 10)
+        return DM_PROBE_SCORE_MAYBE;
+    return DM_PROBE_SCORE_FALSE;
+}
+
+
+static int fmtDecodeAmicaPaintPacked(DMC64Image *img, const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt)
+{
+    int res;
+    Uint8 *mem = NULL, *dstEnd;
+
+    if ((res = dmDecodeGenericRLE(&mem, &dstEnd, buf, buf + len, 0xC2)) != DMERR_OK)
+        goto out;
+
+    res = dmC64DecodeGenericBMP(img, mem, dstEnd - mem + 1, fmt);
+    
+out:
+    dmFree(mem);
+    return res;
+}
+
+
+static BOOL fmtTruePaintSetLaceType(DMC64Image *img, const struct _DMC64EncDecOp *op, const Uint8 *buf, const size_t len)
+{
+    (void) op;
+    (void) buf;
+    (void) len;
+    img->laceType = D64_ILACE_RES;
+    img->laceBank1 = 0;
+    img->laceBank2 = 1;
+    return TRUE;
+}
+
+
+static BOOL fmtSetFLIType(DMC64Image *img, const struct _DMC64EncDecOp *op, const Uint8 *buf, const size_t len)
+{
+    (void) buf;
+    (void) len;
+    img->fliType = op->bank;
+    return TRUE;
+}
+
+
+const DMC64ImageFormat dmC64ImageFormats[] =
+{
+    {
+        D64_FMT_MC, "d2p", "DrazPaint 2.0 (packed)", 0x5800, -1,
+        fmtProbeDrazPaint20Packed, fmtDecodeDrazPaintPacked,
+        NULL, NULL, NULL,
+        4,
+        {
+            { DT_COLOR_RAM,    0x0000, 0,  0, NULL, NULL },
+            { DT_BITMAP,       0x0800, 0,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x0400, 0,  0, NULL, NULL },
+            { DT_BGCOLOR,      0x2740, 0,  0, NULL, NULL },
+        }
+    },
+
+    {
+        D64_FMT_MC | D64_FMT_ILACE, "dlp", "DrazLace 1.0 (packed)", 0x5800, -1,
+        fmtProbeDrazLace10Packed, fmtDecodeDrazPaintPacked,
+        NULL, NULL, NULL,
+        6,
+        {
+            { DT_COLOR_RAM,    0x0000, 0,  0, NULL, NULL },
+            { DT_BITMAP,       0x0800, 0,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x0400, 0,  0, NULL, NULL },
+            { DT_BGCOLOR,      0x2740, 0,  0, NULL, NULL },
+            { DT_BITMAP,       0x2800, 1,  0, NULL, NULL },
+            { DT_DEC_FUNCTION, 0x2742, 0,  1, fmtDrazLaceSetLaceType, NULL },
+        }
+    },
+    
+    {
+        D64_FMT_MC, "drp", "DrazPaint (unpacked)", 0x5800, 10051,
+        NULL, NULL,
+        NULL, NULL, NULL,
+        4,
+        {
+            { DT_COLOR_RAM,    0x0000, 0,  0, NULL, NULL },
+            { DT_BITMAP,       0x0800, 0,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x0400, 0,  0, NULL, NULL },
+            { DT_BGCOLOR,      0x2740, 0,  0, NULL, NULL },
+        }
+    },
+
+    {
+        D64_FMT_MC | D64_FMT_ILACE, "drl", "DrazLace 1.0 (unpacked)", 0x5800, 18242,
+        NULL, NULL,
+        NULL, NULL, NULL,
+        6,
+        {
+            { DT_COLOR_RAM,    0x0000, 0,  0, NULL, NULL },
+            { DT_BITMAP,       0x0800, 0,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x0400, 0,  0, NULL, NULL },
+            { DT_BGCOLOR,      0x2740, 0,  0, NULL, NULL },
+            { DT_BITMAP,       0x2800, 1,  0, NULL, NULL },
+            { DT_DEC_FUNCTION, 0x2742, 0,  1, fmtDrazLaceSetLaceType, NULL },
+        }
+    },
+    
+    {
+        D64_FMT_MC | D64_FMT_ILACE, "mci", "Truepaint (unpacked)", 0x9c00, 19434,
+        NULL, NULL,
+        NULL, NULL, NULL,
+        6,
+        {
+            { DT_SCREEN_RAM,   0x0000, 0,  0, NULL, NULL },
+            { DT_BGCOLOR,      0x03e8, 0,  0, NULL, NULL },
+            { DT_BITMAP,       0x0400, 0,  0, NULL, NULL },
+            { DT_BITMAP,       0x2400, 1,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x4400, 1,  0, NULL, NULL },
+            { DT_COLOR_RAM,    0x4800, 0,  0, NULL, NULL },
+            { DT_DEC_FUNCTION, 0x0000, 0,  0, fmtTruePaintSetLaceType, NULL },
+        }
+    },
+    
+    {
+        D64_FMT_MC, "kla", "Koala Paint (unpacked)", 0x6000, 10003,
+        NULL, NULL,
+        NULL, NULL, NULL,
+        4,
+        {
+            { DT_BITMAP,       0x0000, 0,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x1f40, 0,  0, NULL, NULL },
+            { DT_COLOR_RAM,    0x2328, 0,  0, NULL, NULL },
+            { DT_BGCOLOR,      0x2710, 0,  0, NULL, NULL },
+        }
+    },
+
+    {
+        D64_FMT_MC, "ocp", "Advanced Art Studio (unpacked)", 0x2000, 10018,
+        NULL, NULL,
+        NULL, NULL, NULL,
+        4,
+        {
+            { DT_BITMAP,       0x0000, 0,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x1f40, 0,  0, NULL, NULL },
+            { DT_COLOR_RAM,    0x2338, 0,  0, NULL, NULL },
+            { DT_BGCOLOR,      0x2329, 0,  0, NULL, NULL },
+        }
+    },
+
+    {
+        D64_FMT_MC, "ami", "Amica Paint (packed)", 0x4000, -1,
+        fmtProbeAmicaPaintPacked, fmtDecodeAmicaPaintPacked,
+        NULL, NULL, NULL,
+        4,
+        {
+            { DT_COLOR_RAM,    0x2328, 0,  0, NULL, NULL },
+            { DT_BITMAP,       0x0000, 0,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x1f40, 0,  0, NULL, NULL },
+            { DT_BGCOLOR,      0x2710, 0,  0, NULL, NULL },
+        }
+    },
+
+    {
+        D64_FMT_MC, "rpm", "Run Paint (unpacked)", 0x6000, 10006,
+        NULL, NULL,
+        NULL, NULL, NULL,
+        4,
+        {
+            { DT_COLOR_RAM,    0x2328, 0,  0, NULL, NULL },
+            { DT_BITMAP,       0x0000, 0,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x1f40, 0,  0, NULL, NULL },
+            { DT_BGCOLOR,      0x2710, 0,  0, NULL, NULL },
+        }
+    },
+
+    {
+        D64_FMT_HIRES, "art", "Art Studio (unpacked)", 0x2000, 9009,
+        NULL, NULL,
+        NULL, NULL, NULL,
+        2,
+        {
+            { DT_BITMAP,       0x0000, 0,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x1f40, 0,  0, NULL, NULL },
+        }
+    },
+
+    {
+        D64_FMT_HIRES, "iph", "Interpaint (unpacked)", 0x4000, 9002,
+        NULL, NULL,
+        NULL, NULL, NULL,
+        2,
+        {
+            { DT_BITMAP,       0x0000, 0,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x1f40, 0,  0, NULL, NULL },
+        }
+    },
+
+    {
+        D64_FMT_HIRES, "dd", "Doodle (unpacked)", 0x1c00, 9218,
+        NULL, NULL,
+        NULL, NULL, NULL,
+        2,
+        {
+            { DT_SCREEN_RAM,   0x0000, 0,  0, NULL, NULL },
+            { DT_BITMAP,       0x0400, 0,  0, NULL, NULL },
+        }
+    },
+    
+    {
+        D64_FMT_MC | D64_FMT_FLI, "bml", "Blackmail FLI (unpacked)", 0x3b00, 17474,
+        NULL, NULL,
+        NULL, NULL, NULL,
+        11,
+        {
+            { DT_COLOR_RAM,    0x0100, 0,  0, NULL, NULL },
+
+            { DT_SCREEN_RAM,   0x0500, 0,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x0900, 1,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x0d00, 2,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x1100, 3,  0, NULL, NULL },
+
+            { DT_SCREEN_RAM,   0x1500, 4,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x1900, 5,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x1d00, 6,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x2100, 7,  0, NULL, NULL },
+
+            { DT_BITMAP,       0x2500, 0,  0, NULL, NULL },
+            { DT_DEC_FUNCTION, 0x0000, D64_FLI_8BANK,  0, fmtSetFLIType, NULL },
+        }
+    },
+
+    {
+        D64_FMT_MC | D64_FMT_FLI, "fli", "FLI Designer (unpacked)", 0x3c00, 17409,
+        NULL, NULL,
+        NULL, NULL, NULL,
+        11,
+        {
+            { DT_COLOR_RAM,    0x0000, 0,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x0400, 0,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x0800, 1,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x0c00, 2,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x1000, 3,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x1400, 4,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x1800, 5,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x1c00, 6,  0, NULL, NULL },
+            { DT_SCREEN_RAM,   0x2000, 7,  0, NULL, NULL },
+            { DT_BITMAP,       0x2400, 0,  0, NULL, NULL },
+            { DT_DEC_FUNCTION, 0x0000, D64_FLI_8BANK,  0, fmtSetFLIType, NULL },
+        }
+    },
+
+};
+
+const int ndmC64ImageFormats = sizeof(dmC64ImageFormats) / sizeof(dmC64ImageFormats[0]);
+
+
+// Perform probing of the given data buffer, trying to determine
+// if it contains a supported "C64" image format. Returns the
+// "probe score", see libgfx.h for list of values. If a match
+// is found, pointer to format description is set to *pfmt.
+int dmC64ProbeBMP(const Uint8 *buf, const size_t len, const DMC64ImageFormat **pfmt)
+{
+    int i, scoreMax = DM_PROBE_SCORE_FALSE, scoreIndex = -1;
+
+    for (i = 0; i < ndmC64ImageFormats; i++)
+    {
+        const DMC64ImageFormat *fmt = &dmC64ImageFormats[i];
+        int score = DM_PROBE_SCORE_FALSE;
+        if (fmt->probe == NULL && fmt->size > 0 && fmt->addr > 0)
+        {
+            // Generic probe just checks matching size and load address
+            if (len == fmt->size && dmCompareAddr16(buf, 0, fmt->addr))
+                score = DM_PROBE_SCORE_GOOD;
+        }
+        else
+            score = fmt->probe(buf, len, fmt);
+
+        if (score > scoreMax)
+        {
+            scoreMax = score;
+            scoreIndex = i;
+        }
+    }
+
+    if (scoreIndex >= 0)
+    {
+        *pfmt = &dmC64ImageFormats[scoreIndex];
+        return scoreMax;
+    }
+    else
+        return DM_PROBE_SCORE_FALSE;
+}
+
+
+static int dmC64SanityCheckEncDecOp(const int i, const DMC64EncDecOp *op)
+{
+    if (op->bank < 0 || op->bank >= C64_SCR_MAX_BANK)
+    {
+        dmError("Invalid bank %d definition in generic encode/decode operator %d @ #%d.\n",
+            op->bank, op->type, i);
+        return DMERR_INTERNAL;
+    }
+
+    if (op->type < 0 || op->type >= DT_LAST)
+    {
+        dmError("Invalid encode/decode operator type %d @ #%d.\n",
+            op->type, i);
+        return DMERR_INTERNAL;
+    }
+
+    return DMERR_OK;
+}
+
+
+int dmC64DecodeGenericBMP(DMC64Image *img, const Uint8 *buf,
+    const size_t len, const DMC64ImageFormat *fmt)
+{
+    int i;
+
+    if (buf == NULL || img == NULL || fmt == NULL)
+        return DMERR_NULLPTR;
+
+    // Clear the image structure
+    memset(img, 0, sizeof(*img));
+    img->type = fmt->type;
+
+    // Perform decoding
+    for (i = 0; i < fmt->nencdecOps; i++)
+    {
+        const DMC64EncDecOp *op = &fmt->encdecOps[i];
+        const Uint8 *src;
+        size_t size;
+        int res;
+
+        // Check operation validity
+        if ((res = dmC64SanityCheckEncDecOp(i, op)) != DMERR_OK)
+            return res;
+        
+        // Check size
+        size = (op->size == 0) ? dmC64DefaultSizes[op->type] : op->size;
+
+        // Do we need to reallocate some more space?
+        if (op->offs + size > len)
+        {
+            dmError("Decode out of bounds, op #%d type=%d, offs=%d ($%04x), "
+                "bank=%d, size=%d ($%04x) @ %d ($%04x)\n",
+                i, op->type, op->offs, op->offs, op->bank, size, size, len, len);
+            return DMERR_INVALID_DATA;
+        }
+
+        src = buf + op->offs;
+
+        // Perform operation
+        switch (op->type)
+        {
+            case DT_COLOR_RAM:   memcpy(img->color[op->bank], src, size); break;
+            case DT_BITMAP:      memcpy(img->bitmap[op->bank], src, size); break;
+            case DT_SCREEN_RAM:  memcpy(img->screen[op->bank], src, size); break;
+            case DT_BGCOLOR:     img->bgcolor = *src; break;
+            case DT_EXTRADATA:   memcpy(img->extradata, src, size); break;
+            case DT_DEC_FUNCTION:
+                if (op->decfunction == NULL)
+                {
+                    dmError("Decode op is a function, but function ptr is NULL: "
+                        "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n",
+                        i, op->offs, op->offs, op->bank, size, size, len, len);
+                    return DMERR_INTERNAL;
+                }
+                if (!op->decfunction(img, op, buf, len))
+                {
+                    dmError("Decode op custom function failed: op #%d, "
+                        "offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n",
+                        i, op->offs, op->offs, op->bank, size, size, len, len);
+                    return DMERR_INTERNAL;
+                }
+                break;
+        }
+    }
+    
+    return DMERR_OK;
+}
+
+
+int dmC64EncodeGenericBMP(Uint8 **pbuf, size_t *plen, const DMC64Image *img, const DMC64ImageFormat *fmt)
+{
+    int i, res = DMERR_OK;
+    Uint8 *buf;
+    size_t allocated;
+
+    if (pbuf == NULL || plen == NULL || img == NULL || fmt == NULL)
+        return DMERR_NULLPTR;
+
+    // Allocate the output buffer
+    *plen = 0;
+    if (fmt->size > 0)
+        *plen = allocated = fmt->size;
+    else
+        allocated = 8 * 1024;
+
+    if ((buf = dmMalloc(allocated)) == NULL)
+    {
+        dmError("Could not allocate %d bytes of memory for C64 image encoding buffer.\n",
+            allocated);
+        res = DMERR_MALLOC;
+        goto error;
+    }
+
+    // Perform encoding
+    for (i = 0; i < fmt->nencdecOps; i++)
+    {
+        const DMC64EncDecOp *op = &fmt->encdecOps[i];
+        Uint8 *dst = 2 + buf + op->offs;
+        size_t size;
+
+        // Check operation validity
+        if ((res = dmC64SanityCheckEncDecOp(i, op)) != DMERR_OK)
+            goto error;
+
+        // Check size
+        size = (op->size == 0) ? dmC64DefaultSizes[op->type] : op->size;
+
+        // Do we need to reallocate some more space?
+        if (2 + op->offs + size > allocated)
+        {
+            if ((buf = dmRealloc(buf, allocated)) == NULL)
+            {
+                size_t diff = allocated - (op->offs + size + 2),
+                       grow = (diff / (BUF_SIZE_GROW - 1)) * BUF_SIZE_GROW;
+                allocated = allocated + grow;
+                dmError("Could not re-allocate %d bytes of memory for C64 image encoding buffer.\n",
+                    allocated);
+                res = DMERR_MALLOC;
+                goto error;
+            }
+        }
+
+        if (fmt->size == 0 && op->offs + size + 2 > *plen)
+            *plen = op->offs + size + 2;
+
+        // Perform operation
+        switch (op->type)
+        {
+            case DT_COLOR_RAM:   memcpy(dst, img->color[op->bank], size); break;
+            case DT_BITMAP:      memcpy(dst, img->bitmap[op->bank], size); break;
+            case DT_SCREEN_RAM:  memcpy(dst, img->screen[op->bank], size); break;
+            case DT_BGCOLOR:     *dst = img->bgcolor; break;
+            case DT_EXTRADATA:   memcpy(dst, img->extradata, size); break;
+            case DT_ENC_FUNCTION:
+                break;
+        }
+    }
+
+    buf[0] = DM_GET_ADDR_LO(fmt->addr);
+    buf[1] = DM_GET_ADDR_HI(fmt->addr);
+
+    *pbuf = buf;
+    return DMERR_OK;
+
+error:
+    dmFree(buf);
+    *pbuf = NULL;
+    *plen = 0;
+    return res;
+}
+
+
+static inline Uint8 dmC64GetMCColor(const DMC64Image *img, const int bits, const int cbank, const int vbank, const int scroffs)
+{
+    switch (bits)
+    {
+        case  0: return img->bgcolor; break;
+        case  1: return img->screen[vbank][scroffs] >> 4; break;
+        case  2: return img->screen[vbank][scroffs] & 15; break;
+        default: return img->color[cbank][scroffs] & 15; break;
+    }
+}
+
+
+// Convert a generic "C64" format bitmap in DMC64Image struct to
+// a indexed/paletted bitmap image.
+int dmC64ConvertGenericBMP2Image(DMImage *dst, const DMC64Image *src, const BOOL doubleMC)
+{
+    Uint8 *dp = dst->data;
+    int yc;
+
+    // Sanity check arguments
+    if (dst == NULL || src == NULL)
+        return DMERR_NULLPTR;
+
+    if (dst->width < 8)
+        return DMERR_INVALID_ARGS;
+
+    // Perform generic conversion
+    for (yc = 0; yc < dst->height; yc++)
+    {
+        Uint8 *d = dp;
+        const int y = yc / 8, yb = yc & 7;
+        const int scroffsy = y * C64_SCR_CH_WIDTH;
+        const int bmoffsy = y * C64_SCR_WIDTH;
+        int xc;
+
+        if ((src->type & D64_FMT_MC) == D64_FMT_HIRES)
+        {
+            // Hi-res bitmap
+            for (xc = 0; xc < dst->width; xc++)
+            {
+                const int x = xc / 8;
+                const int scroffs = scroffsy + x;
+                const int bmoffs = bmoffsy + (x * 8) + yb;
+                const int v = 7 - (xc & 7);
+
+                if ((src->bitmap[0][bmoffs] >> v) & 1)
+                    *d++ = src->screen[0][scroffs] >> 4;
+                else
+                    *d++ = src->screen[0][scroffs] & 15;
+            }
+        }
+        else
+        {
+            // Multicolor variants
+            const int
+                wdivisor = doubleMC ? 2 : 1,
+                divisor  = doubleMC ? 4 : 8;
+
+            for (xc = 0; xc < dst->width / wdivisor; xc++)
+            {
+                const int x = xc / divisor;
+                const int scroffs = scroffsy + x;
+                const int bmoffs = bmoffsy + (x * 8) + yb;
+                const int v = 6 - ((xc * 2) & 6);
+                Uint8 c;
+
+                if (src->type & D64_FMT_FLI)
+                {
+                    int vbank = 0;
+                    switch (src->fliType)
+                    {
+                        case D64_FLI_2BANK:
+                            vbank = yb / 4;
+                            break;
+                        case D64_FLI_4BANK:
+                            vbank = yb / 2;
+                            break;
+                        case D64_FLI_8BANK:
+                            vbank = yb;
+                            break;
+                    }
+                    c = dmC64GetMCColor(src, (src->bitmap[0][bmoffs] >> v) & 3, 0, vbank, scroffs);
+                    *d++ = c;
+                    if (doubleMC)
+                        *d++ = c;
+                }
+                else
+                if (src->type & D64_FMT_ILACE)
+                {
+                    *d++ = dmC64GetMCColor(src, (src->bitmap[0][bmoffs] >> v) & 3, 0, src->laceBank1, scroffs);
+                    if (doubleMC)
+                        *d++ = dmC64GetMCColor(src, (src->bitmap[1][bmoffs] >> v) & 3, 0, src->laceBank2, scroffs);
+                }
+                else
+                {
+                    c = dmC64GetMCColor(src, (src->bitmap[0][bmoffs] >> v) & 3, 0, 0, scroffs);
+                    *d++ = c;
+                    if (doubleMC)
+                        *d++ = c;
+                }
+            }
+        }
+        dp += dst->pitch;
+    }
+
+    return DMERR_OK;
+}
+
+
+int dmC64ConvertBMP2Image(DMImage **pdst, const DMC64Image *src, const DMC64ImageFormat *fmt, const BOOL doubleMC)
+{
+    int width, res;
+    DMImage *dst;
+
+    if (pdst == NULL || src == NULL)
+        return DMERR_NULLPTR;
+
+    // Calculate output image width
+    if ((src->type & D64_FMT_MC) && !doubleMC)
+        width = C64_SCR_WIDTH / 2;
+    else
+        width = C64_SCR_WIDTH;
+
+    // Allocate image structure
+    if ((*pdst = dst = dmImageAlloc(width, C64_SCR_HEIGHT)) == NULL)
+        return DMERR_MALLOC;
+
+    // Set palette
+    dst->pal      = (DMColor *) &dmC64Palette;
+    dst->ncolors  = C64_NCOLORS;
+    dst->constpal = TRUE;
+
+    // Convert
+    if (fmt->convertFrom != NULL)
+        res = fmt->convertFrom(dst, src, doubleMC);
+    else
+        res = dmC64ConvertGenericBMP2Image(dst, src, doubleMC);
+
+    return res;
+}
+
+
+int dmC64DecodeBMP(DMC64Image *img, const Uint8 *buf, const size_t len,
+    const size_t probeOffs, const size_t loadOffs,
+    const DMC64ImageFormat **fmt, const DMC64ImageFormat *forced)
+{
+    // Check for forced format
+    if (forced != NULL)
+        *fmt = forced;
+    else
+    {
+        // Nope, perform a generic probe
+        if (probeOffs >= len)
+            return -200;
+
+        if (dmC64ProbeBMP(buf + probeOffs, len - probeOffs, fmt) == DM_PROBE_SCORE_FALSE)
+            return -201;
+    }
+
+    if (loadOffs >= len)
+        return -203;
+
+    // Decode the bitmap to memory layout
+    if ((*fmt)->decode != NULL)
+        return (*fmt)->decode(img, buf + loadOffs, len - loadOffs, *fmt);
+    else
+        return dmC64DecodeGenericBMP(img, buf + loadOffs, len - loadOffs, *fmt);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib64gfx.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,194 @@
+/*
+ * Functions for reading and converting various restricted
+ * C64/etc and/or indexed/paletted graphics formats.
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012 Tecnic Software productions (TNSP)
+ *
+ * Please read file 'COPYING' for information on license and distribution.
+ */
+#ifndef LIB64GFX_H
+#define LIB64GFX_H 1
+
+#include "libgfx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+// Bitmap constants
+#define C64_SCR_WIDTH          320
+#define C64_SCR_HEIGHT         200
+#define C64_SCR_CH_WIDTH       (C64_SCR_WIDTH/8)
+#define C64_SCR_CH_HEIGHT      (C64_SCR_HEIGHT/8)
+#define C64_SCR_COLOR_SIZE     (C64_SCR_CH_WIDTH * C64_SCR_CH_HEIGHT)
+#define C64_SCR_SCREEN_SIZE    (C64_SCR_CH_WIDTH * C64_SCR_CH_HEIGHT)
+#define C64_SCR_BITMAP_SIZE    (C64_SCR_WIDTH * C64_SCR_HEIGHT/8)
+#define C64_SCR_EXTRADATA      1024
+#define C64_SCR_MAX_BANK       8
+
+// C64 video screen pixel aspect ratio on PAL
+#define C64_SCR_PAR_XY         (0.9365f)
+
+// Sprite constants
+#define C64_SPR_WIDTH          3 // bytes
+#define C64_SPR_HEIGHT         21 // lines
+#define C64_SPR_WIDTH_PX       (8 * C64_SPR_WIDTH)
+#define C64_SPR_SIZE           ((C64_SPR_WIDTH * C64_SPR_HEIGHT) + 1)
+
+// Character constants
+#define C64_CHR_WIDTH          1 // bytes
+#define C64_CHR_HEIGHT         8 // lines
+#define C64_CHR_WIDTH_PX       (8 * C64_CHR_WIDTH)
+#define C64_CHR_SIZE           (C64_CHR_WIDTH * C64_CHR_HEIGHT)
+
+// Etc.
+#define C64_RAM_SIZE           (64*1024)
+#define C64_NCOLORS            16
+#define C64_MAX_COLORS         16
+#define C64_VIDBANK_SIZE       (16*1024)
+#define C64_MAX_SPRITES        (C64_VIDBANK_SIZE / C64_SPR_SIZE)
+#define C64_MAX_CHARS          256
+
+// Different supported C64 bitmap "modes"
+enum
+{
+    D64_FMT_HIRES        = 0x0000,
+    D64_FMT_MC           = 0x0001,
+    D64_FMT_ILACE        = 0x0002,
+    D64_FMT_FLI          = 0x0004,
+
+    D64_FMT_MODE_MASK    = 0x000f,
+
+};
+
+enum
+{
+    D64_FLI_2BANK,
+    D64_FLI_4BANK,
+    D64_FLI_8BANK,
+};
+
+enum
+{
+    D64_ILACE_COLOR,
+    D64_ILACE_RES,
+};
+
+typedef struct
+{
+    BOOL multicolor, xexpand, yexpand;
+    int color, xc, yc;
+    Uint8 data[C64_SPR_HEIGHT][C64_SPR_WIDTH];
+} DMC64Sprite;
+
+enum
+{
+    D64_CHR_GLOBAL,		// use font-global setting
+    D64_CHR_MULTICOLOR,	// character is multicolor
+    D64_CHR_HIRES,
+};
+
+typedef struct
+{
+    int mode, color;
+    Uint8 data[C64_CHR_HEIGHT];
+} DMC64Char;
+
+
+typedef struct
+{
+    BOOL multicolor;
+    int colbg, color, col1, col2;
+    int nglyphs;
+    DMC64Char *glyphs;
+} DMC64Font;
+
+
+
+typedef struct
+{
+    int type,     // Image type (D64_FMT_*)
+        fliType,  // FLI type (if FLI used)
+        laceType, // Interlace type (D64_ILACE_*)
+        laceBank1,
+        laceBank2;
+
+    Uint8 color[C64_SCR_MAX_BANK][C64_SCR_COLOR_SIZE],
+            bitmap[C64_SCR_MAX_BANK][C64_SCR_BITMAP_SIZE],
+            screen[C64_SCR_MAX_BANK][C64_SCR_SCREEN_SIZE],
+            extradata[C64_SCR_EXTRADATA],
+            d020, bgcolor, d022, d023, d024;
+
+    Uint8 charset[C64_MAX_CHARS][C64_CHR_HEIGHT * C64_CHR_WIDTH];
+    DMC64Sprite sprites[C64_MAX_SPRITES];
+} DMC64Image;
+
+
+enum
+{
+    DT_COLOR_RAM,
+    DT_BITMAP,
+    DT_SCREEN_RAM,
+    DT_BGCOLOR,
+    DT_EXTRADATA,
+    
+    DT_DEC_FUNCTION,
+    DT_ENC_FUNCTION,
+    
+    DT_LAST,
+};
+
+
+typedef struct _DMC64EncDecOp
+{
+    int    type;
+    size_t offs;
+    int    bank;
+    size_t size;
+    BOOL   (*decfunction)(DMC64Image *img, const struct _DMC64EncDecOp *op, const Uint8 *buf, const size_t len);
+    BOOL   (*encfunction)(const struct _DMC64EncDecOp *op, Uint8 **buf, size_t *len, const DMC64Image *img);
+} DMC64EncDecOp;
+
+
+typedef struct _DMC64ImageFormat
+{
+    int  type;
+    char *fext;
+    char *name;
+    size_t addr; // Loading address (0 if no loading address)
+    size_t size; // Size, including loading address. Only used in encoding, if even there (0 if no static size)
+    int  (*probe)(const Uint8 *buf, const size_t len, const struct _DMC64ImageFormat *fmt);
+    int  (*decode)(DMC64Image *img, const Uint8 *buf, const size_t len, const struct _DMC64ImageFormat *fmt);
+    int  (*encode)(DMC64Image *img, Uint8 **buf, size_t *len, const struct _DMC64ImageFormat *fmt);
+    int  (*convertFrom)(DMImage *, const DMC64Image *, const BOOL doubleMC);
+    int  (*convertTo)(DMImage *, DMC64Image *);
+
+    int nencdecOps;
+    DMC64EncDecOp encdecOps[16];
+} DMC64ImageFormat;
+
+
+extern const size_t      dmC64DefaultSizes[DT_LAST];
+extern DMColor           dmC64Palette[C64_NCOLORS];
+extern const DMC64ImageFormat  dmC64ImageFormats[];
+extern const int         ndmC64ImageFormats;
+
+
+char *    dmC64GetImageTypeString(char *buf, const size_t len, const int type);
+int       dmC64ConvertCSData(DMImage *img, int xoffs, int yoffs, const Uint8 *inBuf, int width, int height, BOOL multicolor, int *colors);
+
+int       dmC64DecodeGenericBMP(DMC64Image *img, const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt);
+int       dmC64EncodeGenericBMP(Uint8 **pbuf, size_t *plen, const DMC64Image *img, const DMC64ImageFormat *fmt);
+int       dmC64ConvertGenericBMP2Image(DMImage *dst, const DMC64Image *src, const BOOL doubleMC);
+
+int       dmC64ConvertBMP2Image(DMImage **pdst, const DMC64Image *src, const DMC64ImageFormat *fmt, const BOOL doubleMC);
+int       dmC64ProbeBMP(const Uint8 *buf, const size_t len, const DMC64ImageFormat **fmt);
+int       dmC64DecodeBMP(DMC64Image *img, const Uint8 *buf, const size_t len, const size_t probeOffs, const size_t loadOffs, const DMC64ImageFormat **fmt, const DMC64ImageFormat *forced);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LIB64GFX_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libgfx.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,1811 @@
+/*
+ * Functions for reading and converting various restricted
+ * C64/etc and/or indexed/paletted graphics formats.
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012 Tecnic Software productions (TNSP)
+ *
+ * Please read file 'COPYING' for information on license and distribution.
+ */
+#include "libgfx.h"
+#include "dmfile.h"
+#include "dmbstr.h"
+
+#ifdef DM_USE_LIBPNG
+#include <png.h>
+#endif
+
+
+BOOL dmCompareColor(const DMColor *c1, const DMColor *c2, BOOL alpha)
+{
+    if (c1->r == c2->r &&
+        c1->g == c2->g &&
+        c1->b == c2->b)
+        return alpha ? (c1->a == c2->a) : TRUE;
+    else
+        return FALSE;
+}
+
+
+DMImage * dmImageAlloc(int width, int height)
+{
+    DMImage *img = dmCalloc(1, sizeof(DMImage));
+    if (img == NULL)
+        return NULL;
+    
+    img->width = img->pitch = width;
+    img->height = height;
+    img->data = dmMalloc(width * height * sizeof(Uint8));
+    if (img->data == NULL)
+    {
+        dmFree(img);
+        return NULL;
+    }
+    
+    return img;
+}
+
+
+void dmImageFree(DMImage *img)
+{
+    if (img != NULL)
+    {
+        if (!img->constpal)
+        {
+            dmFree(img->pal);
+        }
+        dmFree(img->data);
+        dmFree(img);
+    }
+}
+
+
+BOOL dmPaletteAlloc(DMColor **ppal, int ncolors, int ctransp)
+{
+    int i;
+
+    if (ppal == NULL)
+        return FALSE;
+
+    // Allocate desired amount of palette
+    if ((*ppal = dmCalloc(ncolors, sizeof(DMColor))) == NULL)
+        return FALSE;
+
+    // Set alpha values to max, except for transparent color
+    for (i = 0; i < ncolors; i++)
+    {
+        (*ppal)[i].a = (i == ctransp) ? 0 : 255;
+    }
+
+    return TRUE;
+}
+
+
+BOOL dmImageAllocPalette(DMImage *img, int ncolors, int ctransp)
+{
+    if (img == NULL)
+        return FALSE;
+    
+    img->ncolors = ncolors;
+    img->ctransp = ctransp;
+    return dmPaletteAlloc(&(img->pal), ncolors, ctransp);
+}
+
+
+int dmImageGetBytesPerPixel(int format)
+{
+    switch (format)
+    {
+        case DM_IFMT_PALETTE   : return 1;
+
+        case DM_IFMT_RGB_PLANE :
+        case DM_IFMT_RGB       : return 3;
+
+        case DM_IFMT_RGBA      : return 4;
+
+        default:                 return 0;
+    }
+}
+
+
+static BOOL dmReadPaletteData(FILE *fp, DMColor *pal, int ncolors)
+{
+    int i;
+    
+    for (i = 0; i < ncolors; i++)
+    {
+        Uint8 colR, colG, colB;
+        if (!dm_fread_byte(fp, &colR) ||
+            !dm_fread_byte(fp, &colG) ||
+            !dm_fread_byte(fp, &colB))
+            return FALSE;
+
+        pal[i].r = colR;
+        pal[i].g = colG;
+        pal[i].b = colB;
+    }
+
+    return TRUE;
+}
+
+
+int dmWriteImageData(DMImage *img, void *cbdata, int (*writeRowCB)(void *, Uint8 *, size_t), const DMImageSpec *spec)
+{
+    int x, y, yscale, xscale, res = 0, rowSize, rowWidth;
+    Uint8 *row = NULL;
+
+    // Allocate memory for row buffer
+    rowWidth = img->width * spec->scale;
+    rowSize = rowWidth * dmImageGetBytesPerPixel(spec->format);
+
+    if ((row = dmMalloc(rowSize + 16)) == NULL)
+    {
+        res = DMERR_MALLOC;
+        goto done;
+    }
+
+    // Generate the image
+    for (y = 0; y < img->height; y++)
+    {
+        Uint8   *ptr1 = row,
+                *ptr2 = ptr1 + rowWidth,
+                *ptr3 = ptr2 + rowWidth;
+
+        for (x = 0; x < img->width; x++)
+        {
+            Uint8 c = img->data[(y * img->pitch) + x], qr, qg, qb, qa;
+            switch (spec->format)
+            {
+                case DM_IFMT_PALETTE:
+                    for (xscale = 0; xscale < spec->scale; xscale++)
+                        *ptr1++ = c;
+                    break;
+
+                case DM_IFMT_RGBA:
+                    qr = img->pal[c].r;
+                    qg = img->pal[c].g;
+                    qb = img->pal[c].b;
+                    qa = img->pal[c].a;
+                
+                    for (xscale = 0; xscale < spec->scale; xscale++)
+                    {
+                        *ptr1++ = qr;
+                        *ptr1++ = qg;
+                        *ptr1++ = qb;
+                        *ptr1++ = qa;
+                    }
+                    break;
+
+                case DM_IFMT_RGB:
+                    qr = img->pal[c].r;
+                    qg = img->pal[c].g;
+                    qb = img->pal[c].b;
+                
+                    for (xscale = 0; xscale < spec->scale; xscale++)
+                    {
+                        *ptr1++ = qr;
+                        *ptr1++ = qg;
+                        *ptr1++ = qb;
+                    }
+                    break;
+
+                case DM_IFMT_RGB_PLANE:
+                    qr = img->pal[c].r;
+                    qg = img->pal[c].g;
+                    qb = img->pal[c].b;
+                
+                    for (xscale = 0; xscale < spec->scale; xscale++)
+                    {
+                        *ptr1++ = qr;
+                        *ptr2++ = qg;
+                        *ptr3++ = qb;
+                    }
+                    break;
+            }
+        }
+
+        for (yscale = 0; yscale < spec->scale; yscale++)
+        {
+            if ((res = writeRowCB(cbdata, row, rowSize)) != DMERR_OK)
+                goto done;
+        }
+    }
+
+done:
+    dmFree(row);    
+    return res;
+}
+
+
+#define DMCOL(x) (((x) >> 4) & 0xf)
+
+int dmWriteIFFMasterRAWPalette(FILE *fp, DMImage *img, int ncolors,
+    const char *indent, const char *type)
+{
+    int i;
+
+    for (i = 0; i < ncolors; i++)
+    {
+        int color;
+        if (i < img->ncolors)
+        {
+            color = (DMCOL(img->pal[i].r) << 8) |
+                    (DMCOL(img->pal[i].g) << 4) |
+                    (DMCOL(img->pal[i].b));
+        }
+        else
+            color = 0;
+
+        fprintf(fp, "%s%s $%04X\n",
+            indent != NULL ? indent : "\t",
+            type != NULL ? type : "dc.w",
+            color);
+    }
+
+    return DMERR_OK;
+}
+
+
+int dmWriteRAWImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec)
+{
+    int xc, yc, plane, res;
+    DMBitStreamContext bs;
+    
+    if ((res = dmInitBitStreamFILE(&bs, fp)) != DMERR_OK)
+        return res;
+
+    if (spec->interleave)
+    {
+        // Output bitplanes in interleaved format (each plane of line sequentially)
+        for (yc = 0; yc < img->height; yc++)
+        {
+            for (plane = 0; plane < spec->nplanes; plane++)
+            {
+                Uint8 *sp = img->data + yc * img->pitch;
+                for (xc = 0; xc < img->width; xc++)
+                {
+                    if (!dmPutBits(&bs, (sp[xc] & (1 << plane)) ? 1 : 0, 1))
+                        return DMERR_FWRITE;
+                }
+            }
+        }
+    }
+    else
+    {
+        // Output each bitplane in sequence
+        for (plane = 0; plane < spec->nplanes; plane++)
+        {
+            for (yc = 0; yc < img->height; yc++)
+            {
+                Uint8 *sp = img->data + yc * img->pitch;
+                for (xc = 0; xc < img->width; xc++)
+                {
+                    if (!dmPutBits(&bs, (sp[xc] & (1 << plane)) ? 1 : 0, 1))
+                        return DMERR_FWRITE;
+                }
+            }
+        }
+    }
+    
+    return dmFlushBitStream(&bs);
+}
+
+
+int dmWriteRAWImage(const char *filename, DMImage *img, DMImageSpec *spec)
+{
+    FILE *fp;
+    int res;
+
+    if ((fp = fopen(filename, "wb")) == NULL)
+    {
+        dmError("RAW: Could not open file '%s' for writing.\n", filename);
+        return DMERR_FOPEN;
+    }
+
+    res = dmWriteRAWImageFILE(fp, img, spec);
+
+    fclose(fp);
+    return res;
+}
+
+
+static int dmWritePPMRow(void *cbdata, Uint8 *row, size_t len)
+{
+    if (fwrite(row, sizeof(Uint8), len, (FILE *) cbdata) == len)
+        return DMERR_OK;
+    else
+        return DMERR_FWRITE;
+}
+
+
+int dmWritePPMImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec)
+{
+    // Write PPM header
+    fprintf(fp,
+        "P6\n%d %d\n255\n",
+        img->width * spec->scale,
+        img->height * spec->scale);
+
+    // Write image data
+    spec->format = DM_IFMT_RGB;
+    return dmWriteImageData(img, (void *) fp, dmWritePPMRow, spec);
+}
+
+
+int dmWritePPMImage(const char *filename, DMImage *img, DMImageSpec *spec)
+{
+    FILE *fp;
+    int res;
+
+    // Create output file
+    if ((fp = fopen(filename, "wb")) == NULL)
+    {
+        dmError("PPM: could not open file '%s' for writing.\n", filename);
+        return DMERR_FOPEN;
+    }
+
+    res = dmWritePPMImageFILE(fp, img, spec);
+
+    fclose(fp);
+    return res;
+}
+
+
+#ifdef DM_USE_LIBPNG
+static int dmWritePNGRow(void *cbdata, Uint8 *row, size_t len)
+{
+    png_structp png_ptr = cbdata;
+    (void) len;
+
+    if (setjmp(png_jmpbuf(png_ptr)))
+        return DMERR_INTERNAL;
+
+    png_write_row(png_ptr, row);
+
+    return DMERR_OK;
+}
+
+
+int dmWritePNGImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec)
+{
+    png_structp png_ptr = NULL;
+    png_infop info_ptr = NULL;
+    png_colorp palette = NULL;
+    int fmt, res = DMERR_OK;
+
+    // Create PNG structures
+    png_ptr = png_create_write_struct(
+        PNG_LIBPNG_VER_STRING,
+        NULL, NULL, NULL);
+
+    if (png_ptr == NULL)
+    {
+        dmError("PNG: png_create_write_struct() failed.\n");
+        res = DMERR_MALLOC;
+        goto error;
+    }
+    
+    info_ptr = png_create_info_struct(png_ptr);
+    if (info_ptr == NULL)
+    {
+        dmError("PNG: png_create_info_struct(%p) failed.\n", png_ptr);
+        res = DMERR_INIT_FAIL;
+        goto error;
+    }
+    
+    if (setjmp(png_jmpbuf(png_ptr)))
+    {
+        dmError("PNG: Error during image writing..\n");
+        res = DMERR_INIT_FAIL;
+        goto error;
+    }
+
+    png_init_io(png_ptr, fp);
+
+    // Write PNG header info
+    switch (spec->format)
+    {
+        case DM_IFMT_PALETTE: fmt = PNG_COLOR_TYPE_PALETTE; break;
+        case DM_IFMT_RGB    : fmt = PNG_COLOR_TYPE_RGB; break;
+        case DM_IFMT_RGBA   : fmt = PNG_COLOR_TYPE_RGB_ALPHA; break;
+        default:
+            dmError("PNG: Unsupported image format %d.\n", spec->format);
+            res = DMERR_NOT_SUPPORTED;
+            goto error;
+    }
+ 
+    png_set_IHDR(png_ptr, info_ptr,
+        img->width * spec->scale,
+        img->height * spec->scale,
+        8,                    /* bits per component */
+        fmt,
+        PNG_INTERLACE_NONE,
+        PNG_COMPRESSION_TYPE_DEFAULT,
+        PNG_FILTER_TYPE_DEFAULT);
+
+    dmMsg(3, "PNG: %d x %d, depth=%d, type=%d\n",
+        img->width * spec->scale,
+        img->height * spec->scale,
+        8, fmt);
+
+    // Palette
+    if (spec->format == DM_IFMT_PALETTE)
+    {
+        int i;
+
+        palette = png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof(png_color));
+        if (palette == NULL)
+        {
+            dmError("PNG: Could not allocate palette structure.");
+            res = DMERR_MALLOC;
+            goto error;
+        }
+        
+        memset(palette, 0, PNG_MAX_PALETTE_LENGTH * sizeof(png_color));
+
+        for (i = 0; i < img->ncolors; i++)
+        {
+            palette[i].red   = img->pal[i].r;
+            palette[i].green = img->pal[i].g;
+            palette[i].blue  = img->pal[i].b;
+        }
+
+        png_set_PLTE(png_ptr, info_ptr, palette, img->ncolors);
+    }
+
+//    png_set_gAMA(png_ptr, info_ptr, 2.2);
+
+    png_write_info(png_ptr, info_ptr);
+
+
+    // Write compressed image data
+    dmWriteImageData(img, (void *) png_ptr, dmWritePNGRow, spec);
+
+    // Write footer
+    png_write_end(png_ptr, NULL);
+
+error:
+    png_free(png_ptr, palette);
+    palette = NULL;
+
+    if (png_ptr && info_ptr)
+        png_destroy_write_struct(&png_ptr, &info_ptr);
+
+    return res;
+}
+
+
+int dmWritePNGImage(const char *filename, DMImage *img, DMImageSpec *spec)
+{
+    int res;
+    FILE *fp;
+
+    if ((fp = fopen(filename, "wb")) == NULL)
+    {
+        dmError("PNG: could not open file '%s' for writing.\n", filename);
+        return DMERR_FOPEN;
+    }
+
+    res = dmWritePNGImageFILE(fp, img, spec);
+
+    fclose(fp);
+    return res;
+}
+
+
+int dmReadPNGImageFILE(FILE *fp, DMImage **pimg)
+{
+    png_structp png_ptr = NULL;
+    png_infop info_ptr = NULL;
+    png_colorp palette = NULL;
+    png_bytep *row_pointers = NULL;
+    png_bytep trans = NULL;
+    png_uint_32 width, height;
+    int i, bit_depth, color_type, ncolors, ntrans;
+    int res = DMERR_OK;
+    DMImage *img;
+
+    // Create PNG structures
+    png_ptr = png_create_read_struct(
+        PNG_LIBPNG_VER_STRING,
+        NULL, NULL, NULL);
+
+    if (png_ptr == NULL)
+    {
+        dmError("PNG: png_create_write_struct() failed.\n");
+        res = DMERR_MALLOC;
+        goto error;
+    }
+
+    info_ptr = png_create_info_struct(png_ptr);
+    if (info_ptr == NULL)
+    {
+        dmError("PNG: png_create_info_struct(%p) failed.\n", png_ptr);
+        res = DMERR_INIT_FAIL;
+        goto error;
+    }
+    
+    if (setjmp(png_jmpbuf(png_ptr)))
+    {
+        dmError("PNG: Error during image reading..\n");
+        res = DMERR_INIT_FAIL;
+        goto error;
+    }
+
+    png_init_io(png_ptr, fp);
+
+    // Read image information
+    png_read_info(png_ptr, info_ptr);
+
+    png_get_IHDR(png_ptr, info_ptr, &width, &height,
+        &bit_depth, &color_type, NULL, NULL, NULL);
+
+    if (width < 1 || height < 1)
+    {
+        dmError("PNG: Invalid width or height (%d x %d)\n",
+            width, height);
+        res = DMERR_INVALID_DATA;
+        goto error;
+    }
+
+    switch (color_type)
+    {
+        case PNG_COLOR_TYPE_GRAY:
+            if (bit_depth < 8)
+                png_set_expand_gray_1_2_4_to_8(png_ptr);
+
+            if (bit_depth > 8)
+            {
+                dmError("PNG: Unsupported bit depth for grayscale image: %d\n",
+                    bit_depth);
+                res = DMERR_NOT_SUPPORTED;
+                goto error;
+            }
+            break;
+        
+        case PNG_COLOR_TYPE_PALETTE:
+            png_set_packing(png_ptr);
+            break;
+
+        default:
+            dmError("PNG: RGB/RGBA images not supported for loading.\n");
+            res = DMERR_NOT_SUPPORTED;
+            goto error;
+    }
+
+    // Allocate image
+    dmMsg(3, "PNG: %d x %d, depth=%d, type=%d\n",
+        width, height, bit_depth, color_type);
+
+    if ((*pimg = img = dmImageAlloc(width, height)) == NULL)
+    {
+        dmError("PNG: Could not allocate image data.\n");
+        res = DMERR_MALLOC;
+        goto error;
+    }
+
+    // ...
+    row_pointers = png_malloc(png_ptr, height * sizeof(png_bytep));
+    for (i = 0; i < img->height; i++)
+        row_pointers[i] = img->data + (i * img->pitch);
+
+    png_read_image(png_ptr, row_pointers);
+
+    png_read_end(png_ptr, NULL);
+
+    // Create palette
+    switch (color_type)
+    {
+        case PNG_COLOR_TYPE_GRAY:
+            ncolors = 256;
+            dmMsg(3, "PNG: Generating %d color grayscale palette.\n", ncolors);
+
+            if (!dmImageAllocPalette(img, ncolors, -1))
+            {
+                res = DMERR_MALLOC;
+                goto error;
+            }
+
+            for (i = 0; i < img->ncolors; i++)
+            {
+                img->pal[i].r = img->pal[i].g = img->pal[i].b = i;
+            }
+            break;
+        
+        case PNG_COLOR_TYPE_PALETTE:
+            png_get_PLTE(png_ptr, info_ptr, &palette, &ncolors);
+            dmMsg(3, "PNG: Palette of %d colors found.\n", ncolors);            
+            if (ncolors > 0 && palette != NULL)
+            {
+                if (!dmImageAllocPalette(img, ncolors, -1))
+                {
+                    res = DMERR_MALLOC;
+                    goto error;
+                }
+
+                for (i = 0; i < img->ncolors; i++)
+                {
+                    img->pal[i].r = palette[i].red;
+                    img->pal[i].g = palette[i].green;
+                    img->pal[i].b = palette[i].blue;
+                }
+            }
+            break;
+    }
+
+    if (color_type == PNG_COLOR_TYPE_PALETTE ||
+        color_type == PNG_COLOR_TYPE_GRAY)
+    {
+        png_get_tRNS(png_ptr, info_ptr, &trans, &ntrans, NULL);
+        if (trans != NULL && ntrans > 0)
+        {
+            for (i = 0; i < img->ncolors && i < ntrans; i++)
+            {
+                img->pal[i].a = trans[i];
+                if (img->ctransp < 0 && trans[i] == 0)
+                    img->ctransp = i;
+            }
+        }
+    }    
+
+error:
+//    png_free(png_ptr, palette);
+
+    if (png_ptr && info_ptr)
+        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+
+    return res;
+}
+
+
+int dmReadPNGImage(const char *filename, DMImage **img)
+{
+    int res;
+    FILE *fp;
+
+    if ((fp = fopen(filename, "rb")) == NULL)
+    {
+        dmError("PNG: Could not open file '%s' for reading.\n", filename);
+        return DMERR_FOPEN;
+    }
+
+    res = dmReadPNGImageFILE(fp, img);
+
+    fclose(fp);
+    return res;
+}
+#endif
+
+
+typedef struct
+{
+    Uint8 r,g,b;
+} DMPCXColor;
+
+
+typedef struct
+{
+    Uint8 manufacturer,
+            version,
+            encoding,
+            bpp;
+    Uint16 xmin, ymin, xmax, ymax;
+    Uint16 hres, vres;
+    DMPCXColor colormap[16];
+    Uint8 reserved;
+    Uint8 nplanes;
+    Uint16 bpl;
+    Uint16 palinfo;
+    Uint8 filler[58];
+} DMPCXHeader;
+
+
+typedef struct
+{
+    DMPCXHeader *header;
+    Uint8 *buf;
+    size_t bufLen, bufOffs;
+    int format;
+    FILE *fp;
+} DMPCXData;
+
+
+static inline Uint8 dmPCXGetByte(Uint8 *row, const size_t len, const size_t soffs)
+{
+    return (soffs < len) ? row[soffs] : 0;
+}
+
+static BOOL dmPCXFlush(DMPCXData *pcx)
+{
+    BOOL ret = TRUE;
+    if (pcx->bufOffs > 0)
+        ret = fwrite(pcx->buf, sizeof(Uint8), pcx->bufOffs, pcx->fp) == pcx->bufOffs;
+    pcx->bufOffs = 0;
+    return ret;
+}
+
+static inline BOOL dmPCXPutByte(DMPCXData *pcx, const Uint8 val)
+{
+    if (pcx->bufOffs < pcx->bufLen)
+    {
+        pcx->buf[pcx->bufOffs++] = val;
+        return TRUE;
+    }
+    else
+        return dmPCXFlush(pcx);
+}
+
+static int dmWritePCXRow(void *cbdata, Uint8 *row, size_t len)
+{
+    DMPCXData *pcx = (DMPCXData *) cbdata;
+    int plane;
+    size_t soffs = 0;
+    
+//    fprintf(stderr, "%d, %d * %d = %d\n", len, pcx->header->bpl, pcx->header->nplanes, pcx->header->nplanes * pcx->header->bpl);
+
+    pcx->bufOffs = 0;
+
+    for (plane = 0; plane < pcx->header->nplanes; plane++)
+    {
+        Uint8 data = dmPCXGetByte(row, len, soffs++),
+              count = 1;
+
+//        size_t blen = pcx->header->bpl * pcx->header->nplanes;
+        size_t blen = pcx->header->bpl;
+        while (soffs < blen)
+        {
+            if (data == dmPCXGetByte(row, len, soffs) && count < 63)
+            {
+                count++;
+                soffs++;
+            }
+            else
+            {
+                if (count == 1 && (data & 0xC0) != 0xC0)
+                {
+                    if (!dmPCXPutByte(pcx, data))
+                        return DMERR_FWRITE;
+                }
+                else
+                {
+                    if (!dmPCXPutByte(pcx, 0xC0 | count) ||
+                        !dmPCXPutByte(pcx, data))
+                        return DMERR_FWRITE;
+                }
+
+                data = dmPCXGetByte(row, len, soffs++);
+                count = 1;
+            }
+        }
+
+        if (count > 1)
+        {
+            if (!dmPCXPutByte(pcx, 0xC0 | count) ||
+                !dmPCXPutByte(pcx, data))
+                return DMERR_FWRITE;
+        }
+
+        if (!dmPCXFlush(pcx))
+            return DMERR_FWRITE;
+    }
+
+
+    return DMERR_OK;
+}
+
+
+int dmWritePCXImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec)
+{
+    DMPCXData pcx;
+    DMPCXHeader hdr;
+    int res;
+
+    // Create output file
+    pcx.buf    = NULL;
+    pcx.format = spec->paletted ? DM_IFMT_PALETTE : DM_IFMT_RGB_PLANE;
+    pcx.header = &hdr;
+    pcx.fp     = fp;
+
+    // Create PCX header
+    memset(&hdr, 0, sizeof(hdr));
+    if (spec->paletted)
+    {
+        int i;
+        for (i = 0; i < (img->ncolors > 16 ? 16 : img->ncolors); i++)
+        {
+            hdr.colormap[i].r = img->pal[i].r;
+            hdr.colormap[i].g = img->pal[i].g;
+            hdr.colormap[i].b = img->pal[i].b;
+        }
+    }
+    hdr.manufacturer = 10;
+    hdr.version      = 5;
+    hdr.encoding     = 1;
+    hdr.bpp          = 8;
+    hdr.hres         = img->width * spec->scale;
+    hdr.vres         = img->height * spec->scale;
+    hdr.xmin         = hdr.ymin = 0;
+    hdr.xmax         = hdr.hres - 1;
+    hdr.ymax         = hdr.vres - 1;
+    hdr.nplanes      = dmImageGetBytesPerPixel(pcx.format);
+    hdr.palinfo      = 1;
+
+    res = (img->width * spec->scale);
+    hdr.bpl = res / 2;
+    if (res % 2) hdr.bpl++;
+    hdr.bpl *= 2;
+
+    dmMsg(3, "PCX: paletted=%d, nplanes=%d, bpp=%d, bpl=%d\n",
+        spec->paletted, hdr.nplanes, hdr.bpp, hdr.bpl);
+
+    pcx.bufLen       = hdr.bpl * 4;
+    if ((pcx.buf = dmMalloc(pcx.bufLen)) == NULL)
+    {
+        dmError("PCX: Could not allocate %d bytes for RLE compression buffer.\n",
+            pcx.bufLen);
+        res = DMERR_MALLOC;
+        goto error;
+    }
+
+    // Write PCX header
+    if (!dm_fwrite_byte(pcx.fp, hdr.manufacturer) ||
+        !dm_fwrite_byte(pcx.fp, hdr.version) ||
+        !dm_fwrite_byte(pcx.fp, hdr.encoding) ||
+        !dm_fwrite_byte(pcx.fp, hdr.bpp))
+    {
+        dmError("PCX: Could not write basic header data.\n");
+        res = DMERR_FWRITE;
+        goto error;
+    }
+    
+    if (!dm_fwrite_le16(pcx.fp, hdr.xmin) ||
+        !dm_fwrite_le16(pcx.fp, hdr.ymin) ||
+        !dm_fwrite_le16(pcx.fp, hdr.xmax) ||
+        !dm_fwrite_le16(pcx.fp, hdr.ymax) ||
+        !dm_fwrite_le16(pcx.fp, hdr.hres) ||
+        !dm_fwrite_le16(pcx.fp, hdr.vres))
+    {
+        dmError("PCX: Could not write image dimensions.\n");
+        res = DMERR_FWRITE;
+        goto error;
+    }
+
+    if (!dm_fwrite_str(pcx.fp, (Uint8 *) &hdr.colormap, sizeof(hdr.colormap)))
+    {
+        dmError("PCX: Could not write colormap.\n");
+        res = DMERR_FWRITE;
+        goto error;
+    }
+    
+    if (!dm_fwrite_byte(pcx.fp, hdr.reserved) ||
+        !dm_fwrite_byte(pcx.fp, hdr.nplanes) ||
+        !dm_fwrite_le16(pcx.fp, hdr.bpl) ||
+        !dm_fwrite_le16(pcx.fp, hdr.palinfo) ||
+        !dm_fwrite_str(pcx.fp, (Uint8 *) &hdr.filler, sizeof(hdr.filler)))
+    {
+        dmError("PCX: Could not write header remainder.\n");
+        res = DMERR_FWRITE;
+        goto error;
+    }
+
+    // Write image data
+    res = dmWriteImageData(img, (void *) &pcx, dmWritePCXRow, spec);
+
+    // Write VGA palette
+    if (spec->paletted)
+    {
+        int i;
+        dm_fwrite_byte(pcx.fp, 0x0C);
+        dmMsg(3, "PCX: Writing palette of %d active entries.\n", img->ncolors);
+
+        for (i = 0; i < img->ncolors; i++)
+        {
+            dm_fwrite_byte(pcx.fp, img->pal[i].r);
+            dm_fwrite_byte(pcx.fp, img->pal[i].g);
+            dm_fwrite_byte(pcx.fp, img->pal[i].b);
+        }
+
+        // Pad the palette, if necessary        
+        for (; i < 256; i++)
+        {
+            dm_fwrite_byte(pcx.fp, 0);
+            dm_fwrite_byte(pcx.fp, 0);
+            dm_fwrite_byte(pcx.fp, 0);
+        }
+    }
+    
+error:
+    dmFree(pcx.buf);
+    return res;
+}
+
+
+int dmWritePCXImage(const char *filename, DMImage *img, DMImageSpec *spec)
+{
+    FILE *fp;
+    int res;
+
+    if ((fp = fopen(filename, "wb")) == NULL)
+    {
+        dmError("PCX: Could not open file '%s' for writing.\n", filename);
+        return DMERR_FOPEN;
+    }
+    
+    res = dmWritePCXImageFILE(fp, img, spec);
+    
+    fclose(fp);
+    return res;
+}
+
+
+static BOOL dmPCXDecodeRLERow(FILE *fp, Uint8 *buf, const size_t bufLen)
+{
+    size_t offs = 0;
+    do
+    {
+        int count;
+        Uint8 data;
+
+        if (!dm_fread_byte(fp, &data))
+            return FALSE;
+        
+        if ((data & 0xC0) == 0xC0)
+        {
+            count = data & 0x3F;
+            if (!dm_fread_byte(fp, &data))
+                return FALSE;
+        }
+        else
+            count = 1;
+
+        while (count-- && offs < bufLen)
+            buf[offs++] = data;
+
+    } while (offs < bufLen);
+
+    return TRUE;
+}
+
+
+int dmReadPCXImageFILE(FILE *fp, DMImage **pimg)
+{
+    DMImage *img;
+    DMPCXData pcx;
+    DMPCXHeader hdr;
+    BOOL paletted;
+    int res = 0, yc, xc;
+    Uint8 *dp;
+
+    pcx.buf = NULL;
+
+    // Read PCX header
+    if (!dm_fread_byte(fp, &hdr.manufacturer) ||
+        !dm_fread_byte(fp, &hdr.version) ||
+        !dm_fread_byte(fp, &hdr.encoding) ||
+        !dm_fread_byte(fp, &hdr.bpp))
+    {
+        dmError("PCX: Could not read basic header data.\n");
+        res = DMERR_FREAD;
+        goto error;
+    }
+    
+    if (hdr.manufacturer != 10 ||
+        hdr.version != 5 ||
+        hdr.encoding != 1 ||
+        hdr.bpp != 8)
+    {
+        dmError("PCX: Not a PCX file, or unsupported variant.\n");
+        res = DMERR_FREAD;
+        goto error;
+    }
+    
+    if (!dm_fread_le16(fp, &hdr.xmin) ||
+        !dm_fread_le16(fp, &hdr.ymin) ||
+        !dm_fread_le16(fp, &hdr.xmax) ||
+        !dm_fread_le16(fp, &hdr.ymax) ||
+        !dm_fread_le16(fp, &hdr.hres) ||
+        !dm_fread_le16(fp, &hdr.vres))
+    {
+        dmError("PCX: Could not read image dimensions.\n");
+        res = DMERR_FREAD;
+        goto error;
+    }
+
+    if (!dm_fread_str(fp, (Uint8 *) &hdr.colormap, sizeof(hdr.colormap)))
+    {
+        dmError("PCX: Could not read colormap.\n");
+        res = DMERR_FREAD;
+        goto error;
+    }
+    
+    if (!dm_fread_byte(fp, &hdr.reserved) ||
+        !dm_fread_byte(fp, &hdr.nplanes) ||
+        !dm_fread_le16(fp, &hdr.bpl) ||
+        !dm_fread_le16(fp, &hdr.palinfo) ||
+        !dm_fread_str(fp, (Uint8 *) &hdr.filler, sizeof(hdr.filler)))
+    {
+        dmError("PCX: Could not read header remainder.\n");
+        res = DMERR_FREAD;
+        goto error;
+    }
+    
+    if (hdr.nplanes != 3 && hdr.nplanes != 1)
+    {
+        dmError("PCX: Unsupported number of bitplanes %d.\n", hdr.nplanes);
+        res = DMERR_FREAD;
+        goto error;
+    }
+
+    // Allocate image
+    if ((*pimg = img = dmImageAlloc(hdr.xmax - hdr.xmin + 1, hdr.ymax - hdr.ymin + 1)) == NULL)
+    {
+        dmError("PCX: Could not allocate image structure.\n");
+        res = DMERR_MALLOC;
+        goto error;
+    }
+
+    paletted = hdr.nplanes == 1;
+    pcx.bufLen = hdr.nplanes * hdr.bpl;
+    if ((pcx.buf = dmMalloc(pcx.bufLen)) == NULL)
+    {
+        dmError("PCX: Could not allocate RLE buffer.\n");
+        res = DMERR_MALLOC;
+        goto error;
+    }
+
+    // Read image data
+    dp = img->data;
+    for (yc = 0; yc < img->height; yc++)
+    {
+        // Decode row of RLE'd data
+        if (!dmPCXDecodeRLERow(fp, pcx.buf, pcx.bufLen))
+        {
+            dmError("PCX: Error decoding RLE data.\n");
+            res = DMERR_INVALID_DATA;
+            goto error;
+        }
+        
+        // Decode bitplanes
+        switch (hdr.nplanes)
+        {
+            case 1:
+                memcpy(dp, pcx.buf, img->width);
+                break;
+            
+            case 3:
+                {
+                    Uint8 *dptr = dp,
+                            *sptr1 = pcx.buf,
+                            *sptr2 = sptr1 + hdr.bpl,
+                            *sptr3 = sptr2 + hdr.bpl;
+
+                    for (xc = 0; xc < img->width; xc++)
+                    {
+                        *dptr++ = *sptr1++;
+                        *dptr++ = *sptr2++;
+                        *dptr++ = *sptr3++;
+                    }
+                }
+                break;
+        }
+        
+        dp += img->pitch;
+    }
+
+    // Read VGA palette
+    if (paletted)
+    {
+        int i, ncolors;
+        Uint8 tmpb;
+        BOOL read;
+
+        if (!dm_fread_byte(fp, &tmpb) || tmpb != 0x0C)
+        {
+            read = FALSE;
+            ncolors = 16;
+        }
+        else
+        {
+            read = TRUE;
+            ncolors = 256;
+        }
+
+        if (!dmImageAllocPalette(img, ncolors, -1))
+        {
+            dmError("PCX: Could not allocate palette data!\n");
+            res = DMERR_MALLOC;
+            goto error;
+        }
+        
+        if (read)
+        {
+            if (!dmReadPaletteData(fp, img->pal, ncolors))
+            {
+                dmError("PCX: Error reading palette.\n");
+                return DMERR_FREAD;
+            }
+        }
+        else
+        {
+            for (i = 0; i < img->ncolors; i++)
+            {
+                if (i < 16)
+                {
+                    img->pal[i].r = hdr.colormap[i].r;
+                    img->pal[i].g = hdr.colormap[i].g;
+                    img->pal[i].b = hdr.colormap[i].b;
+                }
+            }
+        }
+    }
+
+error:
+    dmFree(pcx.buf);
+    return res;
+}
+
+
+int dmReadPCXImage(const char *filename, DMImage **pimg)
+{
+    FILE *fp;
+    int res;
+
+    if ((fp = fopen(filename, "rb")) == NULL)
+    {
+        dmError("PCX: Could not open file '%s' for reading.\n", filename);
+        return -15;
+    }
+    
+    res = dmReadPCXImageFILE(fp, pimg);
+
+    fclose(fp);
+    return res;
+}
+
+
+#define IFF_ID_FORM        0x464F524D // "FORM"
+#define IFF_ID_ILBM        0x494C424D // "ILBM"
+#define IFF_ID_PBM         0x50424D20 // "PBM "
+#define IFF_ID_BMHD        0x424D4844 // "BMHD"
+#define IFF_ID_CMAP        0x434D4150 // "CMAP"
+#define IFF_ID_BODY        0x424F4459 // "BODY"
+#define IFF_ID_CAMG        0x43414D47 // "CAMG"
+
+#define IFF_MASK_NONE      0
+#define IFF_MASK_HAS_MASK  1
+#define IFF_MASK_TRANSP    2
+#define IFF_MASK_LASSO     3
+
+#define IFF_COMP_NONE      0
+#define IFF_COMP_BYTERUN1  1
+
+#define IFF_CAMG_LACE      0x00000004
+#define IFF_CAMG_HALFBRITE 0x00000080
+#define IFF_CAMG_HAM       0x00000800
+
+typedef struct
+{
+    Uint32 id;
+    Uint32 size;
+    int count;
+    char str[6];
+} DMIFFChunk;
+
+
+typedef struct
+{
+    Uint16 w, h;
+    Sint16 x, y;
+    Uint8  nplanes;
+    Uint8  masking;
+    Uint8  compression;
+    Uint8  pad1;
+    Uint16 transp;
+    Uint8  xasp, yasp;
+    Sint16 pagew, pageh;
+} DMIFFBMHD;
+
+
+typedef struct
+{
+    DMIFFChunk chBMHD, chCMAP, chBODY;
+    DMIFFBMHD bmhd;
+    Uint32 camg;
+    int ncolors;
+    DMColor *pal;
+    BOOL paletted, planar;
+} DMIFF;
+
+
+static BOOL dmReadIFFChunk(FILE *fp, DMIFFChunk *chunk)
+{
+    if (!dm_fread_be32(fp, &chunk->id) ||
+        !dm_fread_be32(fp, &chunk->size))
+    {
+        dmError("ILBM: Could not read IFF chunk header.\n");
+        return FALSE;
+    }
+    else
+        return TRUE;
+}
+
+static char * dmGetIFFChunkID(DMIFFChunk *chunk)
+{
+    chunk->str[0] = (chunk->id >> 24) & 0xff;
+    chunk->str[1] = (chunk->id >> 16) & 0xff;
+    chunk->str[2] = (chunk->id >> 8) & 0xff;
+    chunk->str[3] = (chunk->id) & 0xff;
+    chunk->str[4] = 0;
+    return chunk->str;
+}
+
+static BOOL dmSkipIFFChunkRest(FILE *fp, const DMIFFChunk *chunk, const Uint32 used)
+{
+    if (chunk->size > used)
+    {
+        dmMsg(4, "ILBM: Skipping %d bytes (%d of %d consumed)\n",
+            chunk->size - used, used, chunk->size);
+        return fseeko(fp, chunk->size - used, SEEK_CUR) == 0;
+    }
+    else
+        return TRUE;
+}
+
+static BOOL dmCheckIFFChunk(DMIFFChunk *dest, DMIFFChunk *chunk,
+    const BOOL multi, const Uint32 minSize)
+{
+    if (dest->count > 0 && !multi)
+    {
+        dmError("ILBM: Multiple instances of chunk %s found.\n",
+            dmGetIFFChunkID(chunk));
+        return FALSE;
+    }
+    
+    dest->count++;
+
+    if (chunk->size < minSize)
+        return FALSE;
+    
+    return TRUE;
+}
+
+
+static BOOL dmIFFDecodeByteRun1Row(FILE *fp, Uint8 *buf, const size_t bufLen)
+{
+    size_t offs = 0;
+    do
+    {
+        Sint8 dcount;
+        Uint8 data;
+
+        if (!dm_fread_byte(fp, (Uint8 *) &dcount))
+            return FALSE;
+        
+        if (dcount == -128)
+        {
+            if (!dm_fread_byte(fp, &data))
+                return FALSE;
+        }
+        else
+        if (dcount < 0)
+        {
+            int count = (-dcount) + 1;
+            if (!dm_fread_byte(fp, &data))
+                return FALSE;
+
+            while (count-- && offs < bufLen)
+                buf[offs++] = data;
+        }
+        else
+        {
+            int count = dcount + 1;
+            while (count-- && offs < bufLen)
+            {
+                if (!dm_fread_byte(fp, &data))
+                    return FALSE;
+
+                buf[offs++] = data;
+            }
+        }
+    } while (offs < bufLen);
+
+    return TRUE;
+}
+
+
+static BOOL dmIFFReadOneRow(FILE *fp, DMIFF *iff, Uint8 *buf, const size_t bufLen)
+{
+    if (iff->bmhd.compression == IFF_COMP_BYTERUN1)
+        return dmIFFDecodeByteRun1Row(fp, buf, bufLen);
+    else
+        return dm_fread_str(fp, buf, bufLen);
+}
+
+
+void dmDecodeBitPlane(Uint8 *dp, Uint8 *src, const int width, const int nplane)
+{
+    int xc;
+    for (xc = 0; xc < width; xc++)
+    {
+        const Uint8 data = (src[xc / 8] >> (7 - (xc & 7))) & 1;
+        dp[xc] |= (data << nplane);
+    }
+}
+
+
+int dmDecodeILBMBody(FILE *fp, DMIFF *iff, DMImage **pimg, Uint32 *read)
+{
+    DMImage *img;
+    Uint8 *buf;
+    size_t bufLen;
+    int yc, res = DMERR_OK;
+    
+    *read = 0;
+
+    // Allocate image
+    if ((*pimg = img = dmImageAlloc(iff->bmhd.w, iff->bmhd.h)) == NULL)
+        return DMERR_MALLOC;
+
+    // Allocate planar decoding buffer
+    bufLen = ((img->width + 15) / 16) * 2;
+    if ((buf = dmMalloc(bufLen)) == NULL)
+        return DMERR_MALLOC;
+
+    dmMsg(3, "ILBM: plane row size %d bytes.\n", bufLen);
+    
+    // Decode the chunk
+    for (yc = 0; yc < img->height; yc++)
+    {
+        int plane;
+        const int nplanes = iff->bmhd.nplanes;
+        Uint8 *dp = img->data + (yc * img->pitch);
+
+        memset(dp, 0, img->pitch);
+
+        for (plane = 0; plane < nplanes; plane++)
+        {
+            // Decompress or read data
+            if (!dmIFFReadOneRow(fp, iff, buf, bufLen))
+            {
+                dmError("ILBM: Error in reading image plane #%d @ %d.\n", plane, yc);
+                res = DMERR_FREAD;
+                goto error;
+            }
+
+            // Decode bitplane
+            dmDecodeBitPlane(dp, buf, img->width, plane);
+
+            *read += bufLen;
+        }
+
+        // Read mask data
+        if (iff->bmhd.masking == IFF_MASK_HAS_MASK)
+        {
+            int xc;
+
+            // Decompress or read data
+            if (!dmIFFReadOneRow(fp, iff, buf, bufLen))
+            {
+                dmError("ILBM: Error in reading mask plane.\n");
+                res = DMERR_FREAD;
+                goto error;
+            }
+
+            // Decode mask
+            for (xc = 0; xc < img->width; xc++)
+            {
+                const Uint8 data = (buf[xc / 8] >> (7 - (xc & 7))) & 1;
+                
+                // Black out any pixels with mask bit 0
+                if (!data)
+                    dp[xc] = 0;
+            }
+
+            *read += bufLen;
+        }
+    }
+
+error:
+    dmFree(buf);
+    return res;
+}
+
+
+int dmDecodePBMBody(FILE *fp, DMIFF *iff, DMImage **pimg, Uint32 *read)
+{
+    DMImage *img;
+    int yc, res = DMERR_OK;
+
+    *read = 0;
+
+    // Allocate image
+    if ((*pimg = img = dmImageAlloc(iff->bmhd.w, iff->bmhd.h)) == NULL)
+        return DMERR_MALLOC;
+
+    // Decode the chunk
+    for (yc = 0; yc < img->height; yc++)
+    {
+        Uint8 *dp = img->data + (yc * img->pitch);
+
+        if (!dmIFFReadOneRow(fp, iff, dp, img->width))
+        {
+            dmError("ILBM: Error in reading image row #%d.\n", yc);
+            res = DMERR_FREAD;
+            goto error;
+        }
+
+        *read += img->width;
+    }
+
+error:
+    return res;
+}
+
+
+int dmReadILBMImageFILE(FILE *fp, DMImage **pimg)
+{
+    Uint32 idILBM;
+    DMIFFChunk chunk;
+    DMIFF iff;
+    Uint32 read;
+    BOOL parsed = FALSE;
+    int i, res = DMERR_OK;
+
+    memset(&iff, 0, sizeof(iff));
+
+    // Read IFF FORM header
+    if (!dmReadIFFChunk(fp, &chunk) ||
+        chunk.id != IFF_ID_FORM ||
+        chunk.size < 32)
+    {
+        dmError("ILBM: Not a IFF file.\n");
+        return DMERR_FREAD;
+    }
+    
+    // Check IFF ILBM signature
+    if (!dm_fread_be32(fp, &idILBM) ||
+        (idILBM != IFF_ID_ILBM && idILBM != IFF_ID_PBM))
+    {
+        dmError("ILBM: Not a ILBM file.\n");
+        return DMERR_INVALID_DATA;
+    }
+
+    iff.planar = (idILBM == IFF_ID_ILBM);
+
+    while (!parsed && !feof(fp))
+    {
+        if (!dmReadIFFChunk(fp, &chunk))
+        {
+            dmError("ILBM: Error reading IFF ILBM data.\n");
+            return DMERR_FREAD;
+        }
+        
+        switch (chunk.id)
+        {
+            case IFF_ID_BMHD:
+                // Check for multiple occurences of BMHD
+                if (!dmCheckIFFChunk(&iff.chBMHD, &chunk, FALSE, sizeof(iff.bmhd)))
+                    return DMERR_FREAD;
+
+                // Read BMHD data
+                if (!dm_fread_be16(fp, &iff.bmhd.w) ||
+                    !dm_fread_be16(fp, &iff.bmhd.h) ||
+                    !dm_fread_be16(fp, (Uint16 *) &iff.bmhd.x) ||
+                    !dm_fread_be16(fp, (Uint16 *) &iff.bmhd.y) ||
+                    !dm_fread_byte(fp, &iff.bmhd.nplanes) ||
+                    !dm_fread_byte(fp, &iff.bmhd.masking) ||
+                    !dm_fread_byte(fp, &iff.bmhd.compression) ||
+                    !dm_fread_byte(fp, &iff.bmhd.pad1) ||
+                    !dm_fread_be16(fp, &iff.bmhd.transp) ||
+                    !dm_fread_byte(fp, &iff.bmhd.xasp) ||
+                    !dm_fread_byte(fp, &iff.bmhd.yasp) ||
+                    !dm_fread_be16(fp, (Uint16 *) &iff.bmhd.pagew) ||
+                    !dm_fread_be16(fp, (Uint16 *) &iff.bmhd.pageh))
+                {
+                    dmError("ILBM: Error reading BMHD chunk.\n");
+                    return DMERR_FREAD;
+                }
+                dmMsg(3, "ILBM: BMHD %d x %d @ %d, %d : nplanes=%d, comp=%d, mask=%d\n",
+                    iff.bmhd.w, iff.bmhd.h, iff.bmhd.x, iff.bmhd.y,
+                    iff.bmhd.nplanes, iff.bmhd.compression, iff.bmhd.masking);
+                
+                // Sanity check
+                if (iff.bmhd.nplanes < 1 || iff.bmhd.nplanes > 8 ||
+                    (iff.bmhd.compression != IFF_COMP_NONE &&
+                    iff.bmhd.compression != IFF_COMP_BYTERUN1) ||
+                    (iff.bmhd.masking != IFF_MASK_NONE &&
+                    iff.bmhd.masking != IFF_MASK_HAS_MASK &&
+                    iff.bmhd.masking != IFF_MASK_TRANSP))
+                {
+                    dmError("ILBM: Unsupported features, refusing to load.\n");
+                    return DMERR_NOT_SUPPORTED;
+                }
+
+                if (!dmSkipIFFChunkRest(fp, &chunk, sizeof(iff.bmhd)))
+                    return DMERR_FREAD;
+                break;
+
+
+            case IFF_ID_CMAP:
+                // Check for multiple occurences of CMAP
+                if (!dmCheckIFFChunk(&iff.chCMAP, &chunk, FALSE, 3))
+                    return DMERR_FREAD;
+
+                // Check for sanity
+                if (chunk.size % 3 != 0)
+                    dmError("ILBM: CMAP chunk size not divisible by 3, possibly broken file.\n");
+
+                iff.ncolors = chunk.size / 3;
+                dmMsg(3, "ILBM: CMAP %d entries (%d bytes)\n",
+                    iff.ncolors, chunk.size, 1 << iff.bmhd.nplanes);
+
+                if (iff.bmhd.nplanes > 0 && iff.ncolors != 1 << iff.bmhd.nplanes)
+                    dmMsg(3, "ILBM: Expected %d entries in CMAP.\n", 1 << iff.bmhd.nplanes);
+                
+                // Read palette
+                if (iff.ncolors > 0)
+                {
+                    if (!dmPaletteAlloc(&iff.pal, iff.ncolors,
+                        (iff.bmhd.masking == IFF_MASK_TRANSP) ? iff.bmhd.transp : -1))
+                    {
+                        dmError("ILBM: Could not allocate palette data.\n");
+                        return DMERR_MALLOC;
+                    }
+                    if (!dmReadPaletteData(fp, iff.pal, iff.ncolors))
+                    {
+                        dmError("ILBM: Error reading CMAP.\n");
+                        return DMERR_FREAD;
+                    }
+                }
+
+                if (iff.chBMHD.count && iff.chBODY.count)
+                    parsed = TRUE;
+                break;
+            
+            case IFF_ID_BODY:
+                // Check for multiple occurences of CMAP
+                if (!dmCheckIFFChunk(&iff.chBODY, &chunk, FALSE, 1))
+                    return DMERR_FREAD;
+
+                // Check for sanity
+                if (!iff.chBMHD.count)
+                {
+                    dmError("ILBM: BODY chunk before BMHD?\n");
+                    return DMERR_INVALID_DATA;
+                }
+
+                dmMsg(3, "ILBM: BODY chunk size %d bytes\n", chunk.size);
+                
+                // Decode the body
+                if (iff.planar)
+                {
+                    if ((res = dmDecodeILBMBody(fp, &iff, pimg, &read)) != DMERR_OK)
+                        return res;
+                }
+                else
+                {
+                    if ((res = dmDecodePBMBody(fp, &iff, pimg, &read)) != DMERR_OK)
+                        return res;
+                }
+
+                if (!dmSkipIFFChunkRest(fp, &chunk, read))
+                    return DMERR_FREAD;
+
+                if (iff.chCMAP.count)
+                    parsed = TRUE;
+                break;
+
+
+            case IFF_ID_CAMG:
+                if (!dm_fread_be32(fp, &iff.camg))
+                {
+                    dmError("ILBM: Error reading CAMG chunk.\n");
+                    return DMERR_FREAD;
+                }
+                
+                dmMsg(3, "ILBM: CAMG value 0x%08x\n", iff.camg);
+
+                if ((iff.camg & IFF_CAMG_HAM))
+                {
+                    dmError("ILBM: HAM files are not supported.\n");
+                    return DMERR_NOT_SUPPORTED;
+                }
+
+                if (!dmSkipIFFChunkRest(fp, &chunk, 4))
+                    return DMERR_FREAD;
+                break;
+
+            
+            default:
+                {
+                    dmMsg(4, "Unknown chunk ID '%s', size %d\n",
+                        dmGetIFFChunkID(&chunk), chunk.size);
+                    
+                    if (fseeko(fp, chunk.size, SEEK_CUR) != 0)
+                    {
+                        dmError("ILBM: Error skipping in file.");
+                        return DMERR_FREAD;
+                    }
+                }
+                break;
+        }
+        
+        if (chunk.size & 1)
+            fgetc(fp);
+    }
+
+    // Set colormap after finishing
+    if (iff.pal != NULL && iff.ncolors > 0 && *pimg != NULL)
+    {
+        // If halfbrite is used, duplicate the palette
+        if (iff.camg & IFF_CAMG_HALFBRITE)
+        {
+            if (iff.ncolors > 128)
+            {
+                dmError("ILBM: Halfbrite enabled, but ncolors > 128.\n");
+                return DMERR_NOT_SUPPORTED;
+            }
+
+            if ((iff.pal = dmRealloc(iff.pal, sizeof(DMColor) * iff.ncolors * 2)) == NULL)
+                return DMERR_MALLOC;
+            
+            for (i = 0; i < iff.ncolors; i++)
+            {
+                int i2 = iff.ncolors + i;
+                iff.pal[i2].r = iff.pal[i].r / 2;
+                iff.pal[i2].g = iff.pal[i].g / 2;
+                iff.pal[i2].b = iff.pal[i].b / 2;
+            }
+        }
+    
+        (*pimg)->ncolors = iff.ncolors;
+        (*pimg)->pal = iff.pal;
+    }
+
+    return res;
+}
+
+
+int dmReadILBMImage(const char *filename, DMImage **pimg)
+{
+    FILE *fp;
+    int res;
+
+    if ((fp = fopen(filename, "rb")) == NULL)
+    {
+        dmError("ILBM: Could not open file '%s' for reading.\n", filename);
+        return DMERR_FOPEN;
+    }
+    
+    res = dmReadILBMImageFILE(fp, pimg);
+
+    fclose(fp);
+    return res;
+}
+
+
+
+
+static int fmtProbePNG(const Uint8 *buf, const size_t len)
+{
+    if (len > 64 && buf[0] == 0x89 &&
+        buf[1] == 'P' && buf[2] == 'N' && buf[3] == 'G' &&
+        buf[4] == 0x0d && buf[5] == 0x0a)
+    {
+        if (buf[12] == 'I' && buf[13] == 'H' &&
+            buf[14] == 'D' && buf[15] == 'R')
+            return DM_PROBE_SCORE_MAX;
+        else
+            return DM_PROBE_SCORE_GOOD;
+    }
+
+    return DM_PROBE_SCORE_FALSE;
+}
+
+
+static int fmtProbePCX(const Uint8 *buf, const size_t len)
+{
+    if (len > 128 + 32 &&
+        buf[0] == 10 &&
+        (buf[1] == 5 || buf[1] == 2 || buf[1] == 3) &&
+        buf[2] == 1 &&
+        (buf[3] == 8 || buf[3] == 4 || buf[3] == 3 || buf[3] == 1) &&
+        buf[65] >= 1 && buf[65] <= 4)
+        return DM_PROBE_SCORE_GOOD;
+
+    return DM_PROBE_SCORE_FALSE;
+}
+
+
+static int fmtProbeILBM(const Uint8 *buf, const size_t len)
+{
+    if (len > 32 &&
+        buf[ 0] == 'F' && buf[ 1] == 'O' &&
+        buf[ 2] == 'R' && buf[ 3] == 'M' && (
+        (buf[ 8] == 'I' && buf[ 9] == 'L' && buf[10] == 'B' && buf[11] == 'M') ||
+        (buf[ 8] == 'P' && buf[ 9] == 'B' && buf[10] == 'M' && buf[11] == 0x20)
+        ))
+    {
+        if (buf[12] == 'B' && buf[13] == 'M' &&
+            buf[14] == 'H' && buf[15] == 'D')
+            return DM_PROBE_SCORE_MAX;
+        else
+            return DM_PROBE_SCORE_GOOD;
+    }
+
+    return DM_PROBE_SCORE_FALSE;
+}
+
+
+DMImageFormat dmImageFormatList[IMGFMT_LAST] =
+{
+    {
+        "PNG", "Portable Network Graphics",
+        fmtProbePNG,
+#ifdef DM_USE_LIBPNG
+        dmReadPNGImage, dmReadPNGImageFILE,
+        dmWritePNGImage, dmWritePNGImageFILE,
+#else
+        NULL, NULL,
+        NULL, NULL,
+#endif
+    },
+    {
+        "PPM", "Portable PixMap",
+        NULL,
+        NULL, NULL,
+        dmWritePPMImage, dmWritePPMImageFILE,
+    },
+    {
+        "PCX", "Z-Soft Paintbrush",
+        fmtProbePCX,
+        dmReadPCXImage, dmReadPCXImageFILE,
+        dmWritePCXImage, dmWritePCXImageFILE,
+    },
+    {
+        "ILBM", "IFF ILBM",
+        fmtProbeILBM,
+        dmReadILBMImage, dmReadILBMImageFILE,
+        NULL, NULL,
+    },
+    {
+        "RAW", "Plain bitplaned (interleaved or non-interleaved) RAW",
+        NULL,
+        NULL, NULL,
+        dmWriteRAWImage, dmWriteRAWImageFILE,
+    },
+    {
+        "ARAW", "IFFMaster Amiga RAW",
+        NULL,
+        NULL, NULL,
+        dmWriteRAWImage, dmWriteRAWImageFILE,
+    }
+};
+
+
+int dmImageProbeGeneric(const Uint8 *buf, const size_t len, DMImageFormat **pfmt, int *index)
+{
+    int i, scoreMax = DM_PROBE_SCORE_FALSE, scoreIndex = -1;
+
+    for (i = 0; i < IMGFMT_LAST; i++)
+    {
+        DMImageFormat *fmt = &dmImageFormatList[i];
+        if (fmt->probe != NULL)
+        {
+            int score = fmt->probe(buf, len);
+            if (score > scoreMax)
+            {
+                scoreMax = score;
+                scoreIndex = i;
+            }
+        }
+    }
+
+    if (scoreIndex >= 0)
+    {
+        *pfmt = &dmImageFormatList[scoreIndex];
+        *index = scoreIndex;
+        return scoreMax;
+    }
+    else
+        return DM_PROBE_SCORE_FALSE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libgfx.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,121 @@
+/*
+ * Functions for loading and saving bitmap images
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2012 Tecnic Software productions (TNSP)
+ *
+ * Please read file 'COPYING' for information on license and distribution.
+ */
+#ifndef LIBMGFX_H
+#define LIBMGFX_H 1
+
+#include "dmlib.h"
+#include "dmfile.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+enum
+{
+    IMGFMT_PNG,
+    IMGFMT_PPM,
+    IMGFMT_PCX,
+    IMGFMT_ILBM,
+    IMGFMT_RAW,
+    IMGFMT_ARAW,
+
+    IMGFMT_LAST
+};
+
+
+enum
+{
+    DM_IFMT_PALETTE,
+    DM_IFMT_RGB,
+    DM_IFMT_RGBA,
+    DM_IFMT_RGB_PLANE,
+};
+
+
+// RGBx color struct
+typedef struct
+{
+    Uint8 r, g, b, a;
+} DMColor;
+
+
+// Bitmapped image struct (can be one of types specified by DM_IFMT_*)
+typedef struct
+{
+    int width, height, pitch;
+    BOOL constpal;
+    int ncolors, ctransp;
+    DMColor *pal;
+    Uint8 *data;
+} DMImage;
+
+
+typedef struct
+{
+    int scale, nplanes, format;
+    BOOL interleave, paletted;
+} DMImageSpec;
+
+
+typedef struct
+{
+    char *fext;
+    char *desc;
+    int  (*probe)(const Uint8 *buf, const size_t len);
+    int  (*read)(const char *filename, DMImage **pimg);
+    int  (*readFILE)(FILE *fp, DMImage **pimg);
+    int  (*write)(const char *filename, DMImage *pimg, DMImageSpec *spec);
+    int  (*writeFILE)(FILE *fp, DMImage *pimg, DMImageSpec *spec);
+} DMImageFormat;
+
+
+// Probe scores
+#define DM_PROBE_SCORE_MAX     1000
+#define DM_PROBE_SCORE_GOOD    750
+#define DM_PROBE_SCORE_AVG     500
+#define DM_PROBE_SCORE_MAYBE   250
+#define DM_PROBE_SCORE_FALSE   0
+
+
+extern DMImageFormat dmImageFormatList[IMGFMT_LAST];
+
+
+DMImage * dmImageAlloc(int width, int height);
+void      dmImageFree(DMImage *img);
+int       dmImageGetBytesPerPixel(int format);
+int       dmImageProbeGeneric(const Uint8 *buf, const size_t len, DMImageFormat **fmt, int *index);
+
+BOOL dmCompareColor(const DMColor *c1, const DMColor *c2, BOOL alpha);
+
+
+int dmWriteImageData(DMImage *img, void *cbdata, int (*writeRowCB)(void *, Uint8 *, size_t), const DMImageSpec *spec);
+
+int dmWriteIFFMasterRAWPalette(FILE *fp, DMImage *img, int ncolors, const char *indent, const char *type);
+int dmWriteRAWImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec);
+int dmWriteRAWImage(const char *filename, DMImage *img, DMImageSpec *spec);
+
+int dmWritePPMImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec);
+int dmWritePPMImage(const char *filename, DMImage *img, DMImageSpec *spec);
+
+#ifdef DM_USE_LIBPNG
+int dmWritePNGImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec);
+int dmWritePNGImage(const char *filename, DMImage *img, DMImageSpec *spec);
+#endif
+
+int dmWritePCXImageFILE(FILE *fp, DMImage *img, DMImageSpec *spec);
+int dmWritePCXImage(const char *filename, DMImage *img, DMImageSpec *spec);
+int dmReadPCXImageFILE(FILE *fp, DMImage **pimg);
+int dmReadPCXImage(const char *filename, DMImage **pimg);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LIBMGFX_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/setupfont.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,191 @@
+Uint8 engineSetupFont[3021] = {
+	 68, 77, 70, 79, 78, 84,  0,  1, 80,  0,255,  0,  6,  6,  8,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,
+	  0,  6,  6,  0, 15, 15, 15,  0,  0, 15,  0,  0,  0, 15,  0, 15,
+	 15,  0, 15, 15,  0, 15,  0, 15,  0, 15,  0, 15,  0,  0,  0, 15,
+	  0,  0, 15, 15, 15,  0,  0,  2,  0,  6,  6,  0, 15, 15, 15,  0,
+	  0, 15, 15, 15, 15, 15,  0, 15,  0, 15,  0, 15,  0, 15, 15,  0,
+	 15, 15,  0, 15, 15, 15, 15, 15,  0,  0, 15, 15, 15,  0,  0, 16,
+	  0,  6,  6,  0,  0, 15,  0,  0,  0,  0,  0, 15, 15,  0,  0,  0,
+	  0, 15, 15, 15,  0,  0,  0, 15, 15,  0,  0,  0,  0, 15,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0, 17,  0,  6,  6,  0,  0,  0, 15,  0,
+	  0,  0,  0, 15, 15,  0,  0,  0, 15, 15, 15,  0,  0,  0,  0, 15,
+	 15,  0,  0,  0,  0,  0, 15,  0,  0,  0,  0,  0,  0,  0,  0, 32,
+	  0,  6,  6,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0, 33,  0,  4,  6,  0, 12,  0,  0,  0,
+	 15,  0,  0,  0, 12,  0,  0,  0,  0,  0,  0,  0, 15,  0,  0,  0,
+	  0,  0,  0, 34,  0,  4,  6, 15,  0, 15,  0, 12,  0, 12,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 35,
+	  0,  6,  6,  0, 12,  0, 12,  0,  0, 12, 15, 15, 15, 12,  0,  0,
+	 15,  0, 15,  0,  0, 12, 15, 15, 15, 12,  0,  0, 12,  0, 12,  0,
+	  0,  0,  0,  0,  0,  0,  0, 36,  0,  6,  6,  0, 12, 15, 12,  0,
+	  0, 12,  0, 15,  0,  0,  0,  0, 15, 15, 15,  0,  0,  0,  0, 15,
+	  0, 12,  0,  0, 12, 15, 15,  0,  0,  0,  0, 15,  0,  0,  0, 37,
+	  0,  5,  6,  0,  0,  0,  0,  0, 15,  0,  0, 12,  0,  0,  0, 15,
+	  0,  0,  0, 15,  0,  0,  0, 12,  0,  0, 15,  0,  0,  0,  0,  0,
+	  0, 38,  0,  6,  6,  0, 12, 15,  0,  0,  0, 12,  0,  0, 12,  0,
+	  0,  0, 15, 15,  0, 12,  0, 12,  0,  0, 15,  0,  0,  0, 12, 15,
+	  0, 12,  0,  0,  0,  0,  0,  0,  0, 39,  0,  6,  6,  0,  0, 15,
+	  0,  0,  0,  0, 12,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0, 40,  0,  4,  6,  0,  0, 12,  0,  0, 12,  0,  0,  0, 15,  0,
+	  0,  0, 12,  0,  0,  0,  0, 12,  0,  0,  0,  0,  0, 41,  0,  4,
+	  6,  0, 11,  0,  0,  0,  0, 13,  0,  0,  0, 15,  0,  0,  0, 13,
+	  0,  0, 11,  0,  0,  0,  0,  0,  0, 42,  0,  6,  6, 12,  0, 12,
+	  0, 12,  0,  0, 13, 15, 13,  0,  0, 12, 15, 15, 15, 12,  0,  0,
+	 13, 15, 13,  0,  0, 12,  0, 12,  0, 12,  0,  0,  0,  0,  0,  0,
+	  0, 43,  0,  4,  6,  0,  0,  0,  0,  0, 15,  0,  0, 15, 15, 15,
+	  0,  0, 15,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 44,  0,  4,
+	  6,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0, 15,  0,  0, 15,  0,  0, 45,  0,  5,  6,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0, 12, 15, 15, 12,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 46,  0,  4,  6,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	 15,  0,  0,  0,  0,  0,  0, 47,  0,  6,  6,  0,  0,  0,  0, 12,
+	  0,  0,  0,  0, 15,  0,  0,  0,  0, 15,  0,  0,  0,  0, 15,  0,
+	  0,  0,  0, 12,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 48,
+	  0,  6,  6,  0, 13, 12, 12,  0,  0, 13,  0,  0, 12, 13,  0, 15,
+	  0, 12,  0, 15,  0, 13, 12,  0,  0, 13,  0,  0, 12, 11, 11,  0,
+	  0,  0,  0,  0,  0,  0,  0, 49,  0,  4,  6,  0, 11,  0,  0, 11,
+	 15,  0,  0,  0, 15,  0,  0,  0, 15,  0,  0, 11, 13, 11,  0,  0,
+	  0,  0,  0, 50,  0,  6,  6,  0, 13, 15, 13,  0,  0, 13,  0,  0,
+	  0, 11,  0,  0,  0,  0, 15,  0,  0,  0, 11, 15,  0,  0,  0, 11,
+	 15, 15, 15, 11,  0,  0,  0,  0,  0,  0,  0, 51,  0,  6,  6,  0,
+	 13, 15, 11,  0,  0, 11,  0,  0,  0, 13,  0,  0,  0, 13, 15,  0,
+	  0, 13,  0,  0,  0, 13,  0,  0, 11, 15, 11,  0,  0,  0,  0,  0,
+	  0,  0,  0, 52,  0,  6,  6,  0, 13,  0, 13,  0,  0, 13,  0,  0,
+	 15,  0,  0, 13, 15, 15, 15, 11,  0,  0,  0,  0, 15,  0,  0,  0,
+	  0,  0, 11,  0,  0,  0,  0,  0,  0,  0,  0, 53,  0,  6,  6, 13,
+	 15, 15, 15, 11,  0, 15,  0,  0,  0,  0,  0, 15, 15, 15, 13,  0,
+	  0,  0,  0,  0,  0, 11,  0, 13, 15, 15, 13,  0,  0,  0,  0,  0,
+	  0,  0,  0, 54,  0,  6,  6,  0, 14, 15, 13,  0,  0, 14,  0,  0,
+	  0,  0,  0, 15, 15, 15, 13,  0,  0, 13,  0,  0,  0, 11,  0,  0,
+	 14, 15, 11,  0,  0,  0,  0,  0,  0,  0,  0, 55,  0,  6,  6, 13,
+	 15, 15, 13,  0,  0, 13,  0,  0, 15,  0,  0,  0,  0, 13, 15, 13,
+	  0,  0,  0,  0, 15,  0,  0,  0,  0,  0, 13,  0,  0,  0,  0,  0,
+	  0,  0,  0, 56,  0,  6,  6,  0, 13, 15, 13,  0,  0, 13,  0,  0,
+	  0, 13,  0,  0, 13, 15, 13,  0,  0, 13,  0,  0,  0, 13,  0,  0,
+	 13, 15, 13,  0,  0,  0,  0,  0,  0,  0,  0, 57,  0,  6,  6,  0,
+	 13, 15, 13,  0,  0, 13,  0,  0,  0, 13,  0,  0, 13, 15, 15, 15,
+	  0,  0,  0,  0,  0, 13,  0,  0, 13, 15, 13,  0,  0,  0,  0,  0,
+	  0,  0,  0, 58,  0,  4,  6,  0,  0,  0,  0,  0, 15,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0, 15,  0,  0,  0,  0,  0,  0, 59,
+	  0,  4,  6,  0,  0,  0,  0,  0,  0, 15,  0,  0,  0,  0,  0,  0,
+	  0, 15,  0,  0, 15,  0,  0,  0,  0,  0,  0, 60,  0,  4,  6,  0,
+	  0, 15,  0,  0, 15,  0,  0, 15,  0,  0,  0,  0, 15,  0,  0,  0,
+	  0, 15,  0,  0,  0,  0,  0, 61,  0,  5,  6,  0,  0,  0,  0,  0,
+	 13, 15, 15, 13,  0,  0,  0,  0,  0,  0, 13, 15, 15, 13,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0, 62,  0,  4,  6, 15,  0,  0,
+	  0,  0, 15,  0,  0,  0,  0, 15,  0,  0, 15,  0,  0, 15,  0,  0,
+	  0,  0,  0,  0,  0, 63,  0,  6,  6,  0, 13, 15, 13,  0,  0, 13,
+	  0,  0,  0, 13,  0,  0,  0,  0, 15,  0,  0,  0,  0, 13,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0, 15,  0,  0,  0, 64,  0,  6,
+	  6,  0, 13, 15, 13,  0,  0, 13,  0, 15,  0, 13,  0, 15,  0, 13,
+	 15, 15,  0, 13,  0,  0,  0,  0,  0,  0, 13, 15, 13,  0,  0,  0,
+	  0,  0,  0,  0,  0, 65,  0,  6,  6,  0, 11, 11, 11,  0,  0, 13,
+	  0,  0,  0, 13,  0, 15, 15, 15, 15, 15,  0, 13,  0,  0,  0, 13,
+	  0, 11,  0,  0,  0, 11,  0,  0,  0,  0,  0,  0,  0, 66,  0,  6,
+	  6, 11, 11, 11, 11,  0,  0, 13,  0,  0,  0, 13,  0, 15, 15, 15,
+	 15,  0,  0, 13,  0,  0,  0, 13,  0, 11, 11, 11, 11,  0,  0,  0,
+	  0,  0,  0,  0,  0, 67,  0,  6,  6,  0, 13, 12, 11, 10,  0, 13,
+	  0,  0,  0,  0,  0, 15,  0,  0,  0,  0,  0, 13,  0,  0,  0,  0,
+	  0,  0, 13, 12, 11, 10,  0,  0,  0,  0,  0,  0,  0, 68,  0,  6,
+	  6, 12, 11, 11, 12,  0,  0, 13,  0,  0,  0, 13,  0, 15,  0,  0,
+	  0, 15,  0, 13,  0,  0,  0, 13,  0, 12, 11, 11, 12,  0,  0,  0,
+	  0,  0,  0,  0,  0, 69,  0,  6,  6, 12, 11, 11, 11, 11,  0, 13,
+	  0,  0,  0,  0,  0, 15, 15, 13,  0,  0,  0, 13,  0,  0,  0,  0,
+	  0, 12, 11, 11, 11, 11,  0,  0,  0,  0,  0,  0,  0, 70,  0,  6,
+	  6, 13, 12, 11, 11, 10,  0, 15,  0,  0,  0,  0,  0, 15, 15, 13,
+	  0,  0,  0, 13,  0,  0,  0,  0,  0, 11,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0, 71,  0,  6,  6,  0, 12, 11, 11, 10,  0, 15,
+	  0,  0,  0,  0,  0, 15,  0, 13, 15, 13,  0, 13,  0,  0,  0, 12,
+	  0,  0, 12, 11, 11, 11,  0,  0,  0,  0,  0,  0,  0, 72,  0,  6,
+	  6, 11,  0,  0,  0, 11,  0, 13,  0,  0,  0, 13,  0, 13, 14, 15,
+	 14, 13,  0, 13,  0,  0,  0, 13,  0, 11,  0,  0,  0, 11,  0,  0,
+	  0,  0,  0,  0,  0, 73,  0,  4,  6, 10, 11, 10,  0,  0, 13,  0,
+	  0,  0, 15,  0,  0,  0, 13,  0,  0, 10, 11, 10,  0,  0,  0,  0,
+	  0, 74,  0,  6,  6,  0,  0,  0,  0, 11,  0,  0,  0,  0,  0, 13,
+	  0,  0,  0,  0,  0, 15,  0, 10,  0,  0,  0, 13,  0,  0, 11, 12,
+	 13,  0,  0,  0,  0,  0,  0,  0,  0, 75,  0,  6,  6, 11,  0,  0,
+	  0, 11,  0, 13,  0, 13, 13,  0,  0, 15, 15, 15,  0,  0,  0, 13,
+	  0, 13, 13,  0,  0, 11,  0,  0,  0, 11,  0,  0,  0,  0,  0,  0,
+	  0, 76,  0,  6,  6, 11,  0,  0,  0,  0,  0, 13,  0,  0,  0,  0,
+	  0, 15,  0,  0,  0,  0,  0, 15,  0,  0,  0,  0,  0, 13, 12, 12,
+	 11, 11,  0,  0,  0,  0,  0,  0,  0, 77,  0,  6,  6, 11,  0,  0,
+	  0, 11,  0, 12, 13,  0, 13, 12,  0, 13, 15, 13, 15, 13,  0, 12,
+	  0, 12,  0, 12,  0, 11,  0,  0,  0, 11,  0,  0,  0,  0,  0,  0,
+	  0, 78,  0,  6,  6, 11,  0,  0,  0, 11,  0, 13, 13,  0,  0, 13,
+	  0, 15,  0, 15,  0, 15,  0, 13,  0,  0, 13, 13,  0, 11,  0,  0,
+	  0, 11,  0,  0,  0,  0,  0,  0,  0, 79,  0,  6,  6,  0, 13, 12,
+	 11,  0,  0, 13,  0,  0,  0, 13,  0, 15,  0,  0,  0, 15,  0, 13,
+	  0,  0,  0, 13,  0,  0, 12, 11, 11,  0,  0,  0,  0,  0,  0,  0,
+	  0, 80,  0,  6,  6, 12, 11, 11, 11,  0,  0, 13,  0,  0,  0, 12,
+	  0, 15, 15, 13, 12,  0,  0, 12,  0,  0,  0,  0,  0, 11,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0, 81,  0,  6,  6,  0, 11, 11,
+	 11,  0,  0, 13,  0,  0,  0, 13,  0, 15,  0, 15,  0, 15,  0, 13,
+	  0,  0, 13,  0,  0,  0, 11, 11,  0, 11,  0,  0,  0,  0,  0,  0,
+	  0, 82,  0,  6,  6, 11, 11, 11, 11,  0,  0, 13,  0,  0,  0, 13,
+	  0, 15, 15, 15, 13,  0,  0, 13,  0,  0,  0, 13,  0, 11,  0,  0,
+	  0, 11,  0,  0,  0,  0,  0,  0,  0, 83,  0,  6,  6,  0, 13, 11,
+	 11, 11,  0, 15,  0,  0,  0,  0,  0,  0, 13, 15, 15,  0,  0,  0,
+	  0,  0,  0, 13,  0, 11, 11, 11, 13,  0,  0,  0,  0,  0,  0,  0,
+	  0, 84,  0,  6,  6, 11, 12, 13, 12, 11,  0,  0,  0, 15,  0,  0,
+	  0,  0,  0, 15,  0,  0,  0,  0,  0, 13,  0,  0,  0,  0,  0, 11,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0, 85,  0,  6,  6, 11,  0,  0,
+	  0, 11,  0, 12,  0,  0,  0, 12,  0, 15,  0,  0,  0, 15,  0, 13,
+	  0,  0,  0, 13,  0,  0, 11, 11, 11,  0,  0,  0,  0,  0,  0,  0,
+	  0, 86,  0,  6,  6, 11,  0,  0,  0, 11,  0, 13,  0,  0,  0, 13,
+	  0,  0, 15,  0, 15,  0,  0,  0, 13,  0, 13,  0,  0,  0,  0, 11,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0, 87,  0,  6,  6, 11,  0,  0,
+	  0, 11,  0, 13,  0,  0,  0, 13,  0, 15,  0,  0,  0, 15,  0, 13,
+	  0, 13,  0, 13,  0,  0, 11,  0, 11,  0,  0,  0,  0,  0,  0,  0,
+	  0, 88,  0,  6,  6, 11,  0,  0,  0, 11,  0,  0, 13,  0, 13,  0,
+	  0,  0,  0, 15,  0,  0,  0,  0, 13,  0, 13,  0,  0, 11,  0,  0,
+	  0, 11,  0,  0,  0,  0,  0,  0,  0, 89,  0,  6,  6, 11,  0,  0,
+	  0, 11,  0, 13,  0,  0,  0, 13,  0,  0, 15,  0, 15,  0,  0,  0,
+	  0, 13,  0,  0,  0,  0,  0, 11,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0, 90,  0,  6,  6, 13, 12, 12, 11, 13,  0,  0,  0,  0, 15,  0,
+	  0,  0,  0, 15,  0,  0,  0,  0, 15,  0,  0,  0,  0, 13, 12, 11,
+	 11, 11,  0,  0,  0,  0,  0,  0,  0, 91,  0,  4,  6,  0, 11, 11,
+	  0,  0, 13,  0,  0,  0, 15,  0,  0,  0, 13,  0,  0,  0, 11, 11,
+	  0,  0,  0,  0,  0, 92,  0,  6,  6, 11,  0,  0,  0,  0,  0,  0,
+	 15,  0,  0,  0,  0,  0,  0, 15,  0,  0,  0,  0,  0,  0, 15,  0,
+	  0,  0,  0,  0,  0, 11,  0,  0,  0,  0,  0,  0,  0, 93,  0,  4,
+	  6,  0, 11, 11,  0,  0,  0, 13,  0,  0,  0, 15,  0,  0,  0, 13,
+	  0,  0, 11, 11,  0,  0,  0,  0,  0, 94,  0,  4,  6,  0, 15,  0,
+	  0, 15,  0, 15,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0, 95,  0,  6,  6,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0, 15, 15, 15, 15, 15,  0,  0,  0,  0,  0,  0,  0, 96,  0,  6,
+	  6,  0,  0, 15,  0,  0,  0,  0,  0, 15, 15,  0,  0,  0,  0,  0,
+	 15,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,123,  0,  6,  6,  0,  0, 12, 15,  0,  0,  0,
+	  0, 15,  0,  0,  0,  0, 15, 15,  0,  0,  0,  0,  0, 15,  0,  0,
+	  0,  0,  0, 12, 15,  0,  0,  0,  0,  0,  0,  0,  0,125,  0,  6,
+	  6,  0,  0, 15, 12,  0,  0,  0,  0,  0, 15,  0,  0,  0,  0,  0,
+	 15, 15,  0,  0,  0,  0, 15,  0,  0,  0,  0, 15, 12,  0,  0,  0,
+	  0,  0,  0,  0,  0,126,  0,  6,  6,  0,  0, 15, 15,  0, 15,  0,
+	 15, 15,  0, 15,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,132,  0,  6,
+	  6, 15,  0,  0,  0, 15,  0,  0, 13, 15, 13,  0,  0, 13,  0,  0,
+	  0, 13,  0, 13, 14, 15, 14, 13,  0, 11,  0,  0,  0, 11,  0,  0,
+	  0,  0,  0,  0,  0,142,  0,  6,  6, 15,  0,  0,  0, 15,  0,  0,
+	 13, 15, 13,  0,  0, 13,  0,  0,  0, 13,  0, 13, 14, 15, 14, 13,
+	  0, 11,  0,  0,  0, 11,  0,  0,  0,  0,  0,  0,  0,148,  0,  6,
+	  6, 14,  0,  0,  0, 14,  0,  0, 12, 14, 12,  0,  0, 15,  0,  0,
+	  0, 15,  0, 13,  0,  0,  0, 13,  0,  0, 12, 11, 11,  0,  0,  0,
+	  0,  0,  0,  0,  0,153,  0,  6,  6, 14,  0,  0,  0, 14,  0,  0,
+	 12, 14, 12,  0,  0, 15,  0,  0,  0, 15,  0, 13,  0,  0,  0, 13,
+	  0,  0, 12, 11, 11,  0,  0,  0,  0,  0,  0,  0,  0,174,  0,  6,
+	  6,  0,  0, 15,  0,  0, 15,  0, 15,  0,  0, 15,  0, 15,  0,  0,
+	 15,  0,  0,  0, 15,  0,  0, 15,  0,  0,  0, 15,  0,  0, 15,  0,
+	  0,  0,  0,  0,  0,175,  0,  6,  6, 15,  0,  0, 15,  0,  0,  0,
+	 15,  0,  0, 15,  0,  0,  0, 15,  0,  0, 15,  0, 15,  0,  0, 15,
+	  0, 15,  0,  0, 15,  0,  0,  0,  0,  0,  0,  0,  0,177,  0,  6,
+	  6, 15,  0, 15,  0, 15,  0,  0, 15,  0, 15,  0, 15, 15,  0, 15,
+	  0, 15,  0,  0, 15,  0, 15,  0, 15, 15,  0, 15,  0, 15,  0,  0,
+	 15,  0, 15,  0, 15,254,  0,  6,  6, 11,  0,  0,  0, 11,  0, 13,
+	  0,  0, 13, 13,  0, 15,  0, 15,  0, 15,  0, 13, 13,  0,  0, 13,
+	  0, 11,  0,  0,  0, 11,  0,  0,  0,  0,  0,  0,  0,
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/setupimage.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,643 @@
+Uint8 engineSetupImage[10252] = {
+	137, 80, 78, 71, 13, 10, 26, 10,  0,  0,  0, 13, 73, 72, 68, 82,
+	  0,  0,  2,128,  0,  0,  1,224,  8,  3,  0,  0,  0,  2, 15, 44,
+	214,  0,  0,  0, 96, 80, 76, 84, 69, 13, 15, 11, 27, 22, 15, 33,
+	 21, 14, 39, 22, 15, 42, 27, 14, 59, 33, 14, 81, 40, 13, 81, 50,
+	 13, 95, 47, 13,111, 52, 13,105, 64, 10,130, 60, 13,150, 67, 12,
+	163, 74, 10,148, 89, 10,184, 81, 12,166, 97, 14,210, 91, 10,194,
+	104, 10,222, 97, 13,187,109,  9,212,106, 12,235,100,  8,194,114,
+	  2,249,105, 10,212,122,  7,255,111,  2,255,117,  7,255,122,  9,
+	241,140,  8,255,147, 10,255,165,  8,240,203, 69, 92,  0,  0, 32,
+	  0, 73, 68, 65, 84,120,218,237,157,237, 98,171,170, 18,134,147,
+	 84,173, 86,173,245,152,109,173,180, 93,247,127,151, 71, 62,  5,
+	  1,141,137, 70,147,190,243, 99,239, 44,131, 64,244,233,192, 12,
+	195,112, 56, 64, 32, 16,  8,  4,  2,129, 64, 32, 16,  8,  4,  2,
+	129, 64, 54,144,224,245, 13,  2, 89, 77, 94,131, 49,250,142,111,
+	 31, 16,200,202,242,118,244,241, 23,190,227,233, 64,214,151,247,
+	208,205,223, 43, 30, 13,228, 62,242,234,156,253,241,239,206,255,
+	 65, 32,171,201,153, 83,230,154,  9,178,241,247,127,228, 27,  2,
+	 89, 81,200,255,216, 40,236, 25,128,255,195,  3,130,172, 45,255,
+	185,  7, 97,106,  0,159,161,255, 32,235,235, 64, 58, 12,191, 57,
+	 71,224, 10, 79,  7,178,190, 84,206, 49,152,234, 69, 40, 64,200,
+	 61, 84, 32,101,205,242, 65,  3, 64,200, 61,  1, 60,  2, 64,  8,
+	  0,132,  0, 64,  0,  8,  1,128, 16,  0,  8,  0, 33,  0, 16,  2,
+	  0, 33, 16,  0,  8,  1,128, 16,  8,  0,132,  0, 64,  8,  4,  0,
+	 66,  0, 32,  4,  2,  0, 33,  0, 16,  2,  1,128, 16,  0,  8,129,
+	  0, 64,  8,  0,132, 64,214,  7,144, 44, 32, 43,213, 60,242, 59,
+	111,174,  1,178, 11,  0,201, 98,178, 82,189,139,116, 26, 92,236,
+	 20, 64,178,168,172, 93,237, 77,213,  3,141, 29,  2, 40,222, 77,
+	123,179, 24, 47, 89,123,235, 75, 86,123, 85,167,193,224,158,  1,
+	 36,164, 76,146,120,  1, 41,229,171,214,248,168,138, 60,187,176,
+	242,200,115,189,208,170,213,122,221, 94,210,233, 36, 73,179,162,
+	172,  7, 24,110,245, 82, 30,225, 47, 96,161, 78,206,  3, 48, 95,
+	 38,245,111,214, 52,134,178,105,242,248,180, 64,181,169,172,214,
+	236,116, 51,163,138, 83,156,149,180, 22,143, 54,189,239,171,221,
+	 51,129,139, 13, 20, 51,  0, 36,203,  1, 88,213, 61,129,109, 22,
+	 46,148,210, 58, 81,213, 94, 13, 32,131, 48, 41, 24,131, 91, 65,
+	 64,159, 73, 17,118,146,239,152, 64,218,201,152,118,178,189,177,
+	147,243,  0,204,104,238,222,215, 27,132,183,148,150, 10,149, 54,
+	127,145,239, 61,152,174, 89, 75, 32,103,  8,215,159,177,170,214,
+	232, 52,  5,240, 56, 85,115, 24,232, 15, 33, 72,107,141,193,251,
+	191,218, 38, 99,143,105,191, 58,144,117,146, 37,150,108,238, 14,
+	224,219,231,215,213,114,230,164, 36,  5, 67,165,171,176,224,217,
+	 49,195,183,143,243,249, 60, 89,241, 89,117,244,120, 54,174,115,
+	 50,163,162, 16,213, 26,157,174,105,  3,231,241,154, 63, 63,187,
+	246, 63,222,251,180,237, 39,174, 78,219,187, 19,200, 94,109,157,
+	178,199,212, 14,116,249,160, 51,183, 15,127,179,170,212,  6, 93,
+	214,201,138, 61,172, 90, 94, 32,115,218,185,  9,192,159,127, 87,
+	139,  0, 48,206, 59,  2,233,235,141,153,186,121, 63,159,127,126,
+	 47,186,189,239,232, 89,191,254,197,  1, 12,121,181,110,  0, 47,
+	168,254,247,247,235,124,126,147, 19,130, 99,170, 77, 20,238, 58,
+	175,106,235, 50, 49,  0,188,192,103, 52,233, 94,157,235,154,154,
+	 42,222,117,146,189,204,186, 29,117, 95, 77,251,200, 46,  6,144,
+	 44,  8, 96,198,116, 85, 21,114,252, 46,174,112, 10,192, 44,239,
+	170, 53,199,224, 57,  0, 50,249,233, 24, 20,205,  4,121,173, 16,
+	188, 35,126,157,  2, 44,116,  0, 13, 55,213, 13,254, 85, 55, 22,
+	254, 42,237,210,154,143,160, 83,128,133, 19,192,201,118,246,  0,
+	 96,212,145, 82,214,236,  7,188,157,103, 84,231,  3,240,231, 77,
+	204,220,168, 39,165,185, 13, 64,202,179, 66,176, 55,107,200, 61,
+	240,107,235, 60,137,186,137,125, 82,176,161, 33,105,212,219,107,
+	242, 36,142,184,116,223, 87,212, 76, 81, 14,164,172,108,217,100,
+	154,125,174,  6,254,213,182, 41,210,164,187, 94,107,191,129,243,
+	 80,101, 90,149, 17,179,  6, 85,149,105,209,154,245,180,109,145,
+	 50,155, 67, 72, 74,  1,204,178,238, 61,118,207,167,239, 74,154,
+	 55,147,237,220,  2, 96,187, 20,128,148, 20, 90,215,241,253,115,
+	214,237,247,  1,144, 34, 40,236,157,176,112, 89,214,235,240,215,
+	214,137,248,113,177,  9, 96, 91, 37,230,251, 41, 91, 97,166, 72,
+	155,169,232, 46,136, 50, 97, 41,250, 42,170,148,143, 44,146,215,
+	217,139,108,203,129,235,161,211,108, 77,164, 35,144,182,125, 61,
+	 29, 99,131,226, 81,167,166,203,162,147,170,105,140,174, 28,226,
+	202,104,103,112,227,209, 30,220,183,  2, 48, 99,135, 65,124,253,
+	187,  2, 64,250,223, 15,125,210,248,251, 46, 12,  7, 63,128,159,
+	243, 58,250,123,254,224, 93, 61,230,247, 32,144, 51,161, 44,160,
+	 40,215,  0,236,116,216,240,253, 20,210, 76,233, 61, 80,117, 21,
+	 43, 39,151,156, 20,118,119,234,238,213, 76,121,254,219, 38, 29,
+	250,158,154, 78,165, 69,198,149,151,170,175,199, 42, 30, 53, 29,
+	128,225,177,147,178,174,179,129,147,109,164,157, 99,187, 23,  0,
+	179,174,205,224,252,251,239, 90,  0,223, 13,  0,121,142,215, 35,
+	  5,176, 90,  4, 64, 58, 23,124, 29, 58, 45,215,181,124, 53,204,
+	116,  0,187,209,215,242, 84, 22,141, 48, 83, 52,  2,203,216, 32,
+	128, 87, 57, 40,163,  6,244,196,170,178,166, 64, 13, 40, 40,101,
+	113,139, 63, 14, 32,251,131, 41,235,114,248,245, 88, 59,141,181,
+	 80,181,  5,128, 97,146,118, 31, 78,115,249,147,  0,158,172, 94,
+	156,197, 47,167, 86,200, 66,  0,118, 74,240, 77,190, 91,225,220,
+	 89, 13,193,222,169, 49,  0,176,117,233,191, 14,192,186, 42,226,
+	161,115, 95,211, 95, 21,127,253,229,112,121, 41, 19, 51,205,204,
+	246,190,215, 93,149,195,  5,129, 83,229,228,152,245,176, 51, 33,
+	 75,230,193, 45,171,194,194, 76,182, 99,131,123,104,218,125,  0,
+	 72,159,246,199,236,138, 52,  0, 95,141,193,251, 28,  8,235,122,
+	 65,  0,255,253,251,124, 31, 18,184,158,  2,148,243,191,176,155,
+	201,119,115,123,  9, 96,203, 93,  5,221, 43,  9,163,152,206,229,
+	249, 28, 80,  2, 24,208,149,113,225, 74,165, 43,233,145,240, 50,
+	180,204,153, 40,144, 12,187,217,191, 64,177,230, 96,138,199, 24,
+	210,187, 35, 86,127, 88,119, 83, 58,254,137, 94, 12,229, 76,143,
+	253,105,132,125,113, 89, 62,162,192,178, 74,139,146,  3,120, 98,
+	247,137, 33,202,223,206, 78,  0,164,143,230,253,235,223, 13,  0,
+	134, 46, 63, 76,148, 46, 10,224,191,175,119,125,229,102, 53,  2,
+	 41,127,133,156,197,118,127, 67, 69,161,  0,108,132,182,234,236,
+	171, 78,210, 36, 20,182,185,  0, 48,164, 23, 83, 14, 72,150,211,
+	  2,140,198, 99,195, 44,106, 62,149, 75,250, 27,169, 99,167,  3,
+	 42, 62,200,123,233, 55,236,149,228, 10,192,152, 85,201,175,118,
+	147, 77,213, 53,222,131,174,124, 44,  0, 44, 21,128,170, 43,206,
+	118, 34,189,157, 98, 39, 67,112,215,224,235,249,223,181,  0,  6,
+	150, 25, 44,172,144,176, 51,110,170,218, 32,229, 38,  0, 59,  2,
+	197,152,178, 38,129,116,181,176,226,163, 85,247,  7, 84,148,101,
+	103, 94, 10,  0,155,154, 91,  6, 39,142,101,198,117, 77, 89, 75,
+	  0,163,188,160,216,177,167,154,209,  2,105,162,204,100,254,254,
+	143,244, 78, 90,134,145,113,234,140,221,154, 15,157,161,168,146,
+	213, 31, 85, 10,192,164,224,245, 28, 57, 72, 93, 61,137,170,135,
+	125, 21, 43,141,105,  2, 40,218,  9,250,118, 78,142,118,154, 93,
+	 24, 33,193,208,140,157,  7, 32,123, 80,230,253,103,225, 59,176,
+	204,224,219,  0,148,  4, 30,243, 82,120,184,201, 58, 51,192,146,
+	191,159,206,134,234, 80,168,196, 59, 77,168,101,240, 34,214, 46,
+	203,238,106,206,126,121, 90, 41,  0, 99, 74,107,206,163, 57, 50,
+	250, 89,192, 72,205,100,110, 35,208, 59, 89, 25, 73,102, 83,113,
+	141, 70,237,181,174, 74,106, 12, 30,142,  5,109,137,  3,152,150,
+	188, 30,214,161,128,218, 26,177,234, 26,189, 33, 79, 56,128, 85,
+	153,155,  0, 90,237,228,174,118,246, 97,  5,211, 57,220, 53, 68,
+	232,  0,190,153,147,192, 80, 46,177, 44, 11,224,191, 79,225, 98,
+	228,107,135,107,  1, 88,203,151, 79, 99, 32,154,166,146,  0,118,
+	160,177,159,156,119, 74,175,123,229, 41,127,211,181, 42, 17, 51,
+	205, 37,  0,172,217,103, 62,162,210, 18, 71,142,101,221,193, 69,
+	131, 45,197, 23,117,197,  6,245,151,110,168,160,213, 71,210,223,
+	 46,  1,164,213,208,122,184,222,235,  0, 20, 69,104,171, 20,199,
+	194,  3, 96, 84,233,237, 80, 59, 61,227, 15,206,104,167, 89,  2,
+	192,179, 91, 76,179,212, 35, 10, 64,219,  2,166, 11,177,182,124,
+	185,  0,164,181,  4,166, 43,250,189, 95,140, 27,  2, 88, 89,  0,
+	158,  7, 39,214,242,150,220, 42, 89,  5, 58,148,107, 13,194, 44,
+	 26, 55,224, 51,177,134, 79,251, 21,128,101, 33,172,142, 70,233,
+	180,188,106,180, 18,148,  9,174, 24, 51,118,185,231,172,191,179,
+	101, 95,136, 66,194,107, 18, 82,141, 46,180,212,169,168,217,189,
+	178, 26,230,100,206,148,113, 28,137,150, 68,215,124,  0,210, 96,
+	222, 90,111, 39, 25,182,243,226, 80,128, 87,  0,120, 56, 58,101,
+	160,145,220,133, 84, 67,150, 70,250, 57,191,191,  6,118,121,211,
+	214,144,  0,134, 54,194,  2,237,116,184, 26,236,  6,208, 17,  4,
+	 72,  3,114, 62, 93, 12, 10, 11, 59, 93,141, 64, 58,  5, 84, 47,
+	159,197,231,106,  0,242,113,172,108,212,100, 44, 46,217, 27, 45,
+	122, 59,185,236,201,233,202,191,  8,  0, 75,174,  1, 11, 86,101,
+	167, 98,179,128,235, 55,161, 71,131,186, 55,177,179,138,125,238,
+	251,192,128,229, 14, 29,101,238,240,169,117, 91,123,  1,100,128,
+	214, 98,154,208,181, 83, 56,219, 89,  2, 64,207, 17,235, 95, 19,
+	175,216, 60,142,243,103,232,241,112,135, 68,143,  0,104, 18,255,
+	245, 38, 84,224, 96, 12,190, 20, 64,246,179, 95, 63, 28,174,201,
+	159, 15, 17,153, 96,199,122, 45,103,131,  8,  3,128,  3,216,234,
+	  0,158,122,184,142, 82, 91,153,  0, 10, 29,101,  0, 72,117,231,
+	 11,191, 42, 66, 87,178,163,244, 32, 10,180,168,194,202,196,152,
+	222,106,  0, 74, 96, 21,128,220, 62,202, 90,238,219, 25,  7,176,
+	 41,123,  0, 85, 59, 77,223,142,253,244, 54,  2,112, 96,  2,159,
+	223, 60,229,220,  0,198,108, 70,123,118, 77, 47,147,129, 10,156,
+	  3, 32, 59, 40,217,158, 44,126,190,138,  5, 90,177,202, 66,214,
+	208,128,177,152,187, 91, 26, 48,228,122,164,123,139,201,169,147,
+	180, 18, 26,202,  6,144, 82,164,  3,200,237,222, 74,  0,197,202,
+	 28, 43,  5, 78, 68, 71,221,144, 86,153,203, 42,117,  0,133,234,
+	165,  0,102,226,201,150, 28, 83, 47,128,220,247, 87, 40,  0,249,
+	247,177,217,206, 78,  0, 52, 39,112, 82,125, 77,  3, 40,188, 56,
+	113,104,107, 81, 49, 11, 60,101,230, 80, 57, 19, 64, 58,197,253,
+	117,219, 62, 71,123,161,121,193, 57,160,112,247,149,214, 28,144,
+	 91,149, 17, 37,161,200,115,222,133, 17,  0,139, 23, 53,  7,228,
+	119,134, 85,171,134,111,186,128, 33,153,230, 38, 78,206,226,146,
+	218, 17,  0,187, 79,177, 17,247, 48, 14, 96,165, 76, 25, 87, 59,
+	100, 47,  0,154,133,127, 63, 14, 51,  1,228,206,177,179,203, 90,
+	  8,213, 80, 73,174,  2,240,240,106, 17, 40,254, 62, 88,192,245,
+	 10,150,176, 54,117,162,171,137, 69, 33,157, 32,236,213,241,185,
+	 27,115, 81,167,105,154,209,175,203,102, 26,192, 70,221,121, 76,
+	178, 92,248,135, 15,220,221, 34, 86,200, 66, 81, 37,243, 61,250,
+	  0,108,148, 93, 33,230,202,163,  0, 18, 29, 64,103, 59, 59,153,
+	  3,154,243,183,207,215,185,  0,114,183,186, 89,139,180, 22, 66,
+	195,103, 55, 31,192, 78, 61,255,220, 85,  5,242,145, 43,181, 39,
+	193,204, 15,152,219, 11,250,157,101, 49, 13,160,235,206,132, 27,
+	208, 89,100, 87,217, 15,158, 45, 31, 74,115, 17,163, 64, 43, 74,
+	251,117,234, 83,126, 25,128,141,167,157,219,194,177, 72, 30,188,
+	208,209,220,101,220,186,  1,244, 88,194,131, 80,130,190,253, 97,
+	 65, 55,128, 73,194,127,154,233,140,254, 21,  4,246, 62, 59,190,
+	 87,193, 11, 96,247, 75, 94,  2, 46,221,111,210,  9,252,117,171,
+	192,124, 21, 21,200,223, 91,102,131,198, 86, 66,138, 44,158,  5,
+	 32,119,213,112,208,  6,119,114,107, 67, 57, 14,205, 32,129,218,
+	 13, 32,171, 63,239, 81,186, 28, 64,119, 59,183,249,  1,233, 24,
+	223, 85, 75,215, 10, 13,137,124,  0,210, 21,244, 56,177, 11, 27,
+	193, 84,255, 62,148, 43,196, 40, 29,143,  0,152, 30, 29,164,252,
+	 10,119,116,192, 52,149, 10, 21,247,  2, 72,123,167,119, 44,112,
+	235, 93,117,195,105, 61, 21,200, 92,191, 39, 11, 64,238,145,139,
+	189,209, 48, 35,  0,242, 42,245, 55, 27, 21,210,218,200,109, 50,
+	106, 47,128, 45,155,194,117, 79,231,200,159,129, 13, 96,226,  2,
+	208,211,206, 13,  0,138,253, 90, 21, 91,242,211, 37, 77, 99,123,
+	101, 66,198,118,208,148,  3,108,238,162, 10, 71,158,112,210,195,
+	 41,210, 75,167,108, 89,211,  3, 96, 42, 94, 74,232, 38,240,148,
+	235,  4,250,  1,228,237,245, 93,147, 83, 37,107,161, 90,212,203,
+	 77,108,178,130, 10,100,184,164,161,  5, 32,127,141, 73,120, 41,
+	128,210,163,205, 62,151,250,157, 65, 42, 92,244,188,202, 56,240,
+	132, 99, 73,  0,185, 27,177,251,181,130, 64, 62,  3,205,115,  9,
+	160,182, 22,236,  6, 80,180,243,178, 88, 60,224,183,216, 48,195,
+	 34,177,115, 93, 88,159,156,  0, 70, 44,229,  5,237,119, 95,216,
+	 11, 32,229,143,209, 32, 10,102, 99,  0,138, 25,182, 69,224,171,
+	 36,176, 82,  4,122,  1,140, 98,217, 57,254,131,186,207, 82, 11,
+	 13, 86,170,127, 60, 94,198,  5,103,129, 53, 27, 90,244,125, 23,
+	 81, 38, 76, 98,235,139,130,186,147, 85,137,186, 72,216, 69,174,
+	221, 34,241, 89,141, 86,236,206, 40, 85,127, 59, 68,  0,197,118,
+	159,200, 26, 89,120, 85, 44,111,229,214, 44,253,151,112, 99,211,
+	 27,132,102, 72, 99, 21,142,197,154, 42,171,130,117, 37,109,164,
+	163, 90,117,192,209, 78,124, 35,128, 93,207, 58, 29,200,226, 53,
+	116, 73,125, 17,162, 81, 34,226,139, 52,241,  2,200,248,211, 10,
+	231, 99,  0,230,169,123,190, 38,  9,204,122,  2,253,  0,210,222,
+	209,150, 74,245,139,114,  1,118,112,118,141,193, 71,186,155,111,
+	 21,  0, 57,129,250,216, 34,221, 22,140, 35,253, 11,182,161,144,
+	171,  1, 86,162,149,155, 51,196,231,188, 80,170,174,175, 82,109,
+	 88, 85, 19, 41,125, 24,163, 95, 54,250,173,162,162,178,106, 36,
+	178,131, 25,106,204, 66, 38,104,249,154,117, 79,116,214,232, 12,
+	189,109,216,206, 45,193,  8,114,151, 83, 67, 23,151, 13, 41, 51,
+	 63,128,105, 70,223,175, 94, 56,246,  2,200,249,147,133,217, 50,
+	168,  7, 64,250, 26, 34,183,205, 42,  8, 60,102,210, 22,110, 71,
+	  0,100,189,211,250, 70,159, 37, 39,240,253,199,101, 97, 39,249,
+	 90,158, 24, 54,210, 25,127,216,210,157, 73,167, 61,198,245,138,
+	 45, 12, 83, 53, 32,214,103,235,238, 99,165,104,149,159,197,157,
+	101,127,147,182, 87,195, 85,165,121, 43,251, 87,163,254,149, 88,
+	217,125,106, 94,190,209,186, 98,118,198,213, 78,115, 51,128,116,
+	111,104, 99, 10,223,149,226,  4, 48, 78,216,223, 94, 93,247,101,
+	235, 81,  0, 89, 97, 30,119, 81,151, 35,  0, 82, 69, 25,120,  8,
+	124,235,  9,164, 74,112, 12, 64,222,187,190,115, 44,222,232,228,
+	114,149,139,144,132,245,156,209,124,116,209,254,180,107, 77, 99,
+	 25,215,121,120,  1, 13, 90, 81, 47,157, 62, 50,237,115,159,119,
+	 71, 84, 89,235, 41, 75,164, 26, 49,154, 18, 85, 54,178, 81, 81,
+	 17,113,  3, 24,178,213, 99, 94, 94,239,138,217, 25, 87, 59,228,
+	 22,  0,191,221,153,246, 26,182,109,198, 13, 96,202, 71, 12,189,
+	112,226,  3, 48, 97, 91, 58,120, 82, 22, 54,137,246,  2, 72, 53,
+	101, 41,172,176,110,184,253,112, 18, 40, 51,208,140,  0,200,129,
+	111,180,206,213, 66,159, 15, 23, 11,127,125,209, 54,203,238, 11,
+	214,254,184, 91, 65,140,231, 11, 61,143,156,245,153, 12,238,236,
+	175,105, 35,153,166, 71, 68,154, 30,121,239,183, 81, 17, 31, 88,
+	 13, 75, 60, 40,106, 45,163,162,153,210,206,172,197,209,206,247,
+	 13,  0,186, 19, 58,180,109, 49,  6,160,225, 18, 17,251, 87,221,
+	  0, 26,133,  5, 56, 30,  0,121,224,112, 32,187,251,229,138,225,
+	147,  4,142,  3,104,246,142, 13, 26,177,189,208, 39, 22,107, 78,
+	106, 46,191, 82, 90,  4, 50,124,159,151,124, 49, 47,239,235, 21,
+	 85,210, 92, 33, 39, 37, 97, 92,244,243,201,203,196,159, 62,116,
+	145, 28,209,211,  0,234,133, 39,  1, 84,191,122, 20, 64, 54, 75,
+	244, 17,248,174,141,194, 77, 57,  5,160,241,164, 26, 17,  4, 58,
+	  8, 24, 19,183,136, 44,150,150, 41,247,220,210,114, 19, 61,229,
+	134,112, 46, 31,193, 34,169,143,231,103,201,159, 15, 96, 59,  1,
+	224,135,  4,176,119, 21, 76,  2, 88,242,208,117,225,230, 58,190,
+	 59,  9, 60,177, 98, 94,  0, 29,189,227, 19,231,216, 17,108,115,
+	148, 75,181,142, 73,224,179,243,215,242, 72,  8,238, 34, 43, 10,
+	205,197,181,  5,128,142,217,243, 40,128,154,235,246,  2,  0, 53,
+	125, 52,  5, 96,163, 17,120, 24,228,248,144,145,  9,180,220, 37,
+	  0,234, 83, 92, 17,190,118,254,231,222,248,105, 37,224,226, 89,
+	115,226,167,150,200,144,171,171, 73,178,155,135, 96,167,  7,225,
+	  2,  0,251,194, 23,  0,232,203,233,162,  3, 88,115, 75,185, 39,
+	240,203,181,118, 65,131,248,138,177, 33,216,156,209, 73,155,239,
+	104,  3, 24,170,180, 74, 46,  0,219, 36,132, 92, 32,233, 51,  1,
+	200,172, 86, 31,129,191,125,  4, 75, 97,237,129,242,  2, 40, 61,
+	114,161,181, 24,242, 25,138,166,109,  0,149,119,212, 41,210,119,
+	114,233,245,181,228,166,246,184,147,148,201, 45,213,184,204,224,
+	199,  2, 48, 48,  1,228, 43,131,145,236,244,143, 59,130, 37,159,
+	  9, 32,225,121,162,222,221,  0, 90, 59,143, 71,  1,148, 47,110,
+	248,206,124,215, 87,196,175, 20, 46,231, 27,240,237, 93,145,  0,
+	 80,172,  2, 48,  2,133,143,234,116,118,  6,241,229,217, 24,128,
+	 86,152, 46,  3, 48,246,107, 64,121,203, 64,  5, 74, 55,187,253,
+	230, 82, 17, 91, 58,188,158,168, 77,144,247, 33, 48, 19, 75,104,
+	 27,  9,119,  4,146,  7, 31,130,135,  0, 10,183, 73,236, 10,115,
+	149, 42, 48,155, 13, 32,239,163,115, 14, 24,186,252, 48,254,115,
+	112,168,103, 59, 17,161,125,195,235,177, 58,176, 98,125,105,228,
+	118,224,248, 62,237,141,157,  3,244, 92,  0, 10,  2, 19,215,102,
+	 99, 25, 64,144,206,  2,144, 31, 64,224,179,130,195,212,229,135,
+	241, 59, 48,228,246,216,212,242, 54,150,177,182, 17,115,117, 63,
+	 74, 43,  0,140,154,155,125,217, 11, 31,164,246,232,  0, 26,  4,
+	 14, 48, 19, 65,124,201,124,  0, 35, 27,192,227, 53,  0,170,124,
+	227,169,229,108, 20,  0,182,119,115, 37,167, 18,192, 93,241,183,
+	 12,128,249,134,  0,234,163,240,209,149,184, 55,188,  2,192,192,
+	138,138,150, 49,172, 46,  0,173, 85, 39,123, 17, 75,  3,141,219,
+	 78, 42,138,212,125, 80,222,176,202,171,180,158, 46, 50, 81, 65,
+	221,120, 23,223,218,169,126,172,114,152,238,227,  3, 40,  8, 12,
+	 14,158,122, 79,241,108,  0,107,123,235,252,135,181,122, 55,208,
+	153,116,131, 73, 55, 57,204,130, 32, 12,163, 36, 43,106,181,136,
+	149,171,104, 57,150,239, 52, 22, 73,131, 76,  0,233, 23,225,169,
+	207, 29,209,168, 31, 87,101, 81,120, 10, 34, 61,253,184,190, 77,
+	140,237,184,181,103,164, 69, 18,  6,125,117,185,220, 80,126,144,
+	 11,186,101, 87, 40,165, 31, 10,217, 14,219,237, 67, 63, 68,122,
+	190,136,180, 92, 59, 59,241,227,  3,200,151,207, 50,199,214, 60,
+	254,187,226,217, 70,  8,173,235,195, 21, 13,227,  4,176,207,163,
+	155, 52, 90, 82,218, 48, 23,  1,205, 52, 18,179, 18, 19, 86,185,
+	122,125, 72,114, 29,192, 14,220,193,134,144, 90,106,208, 88, 11,
+	  2,117,216,235,214,145, 74,206,156,226, 89, 51,204, 99,170,210,
+	154, 23,114,181, 77,228, 42,111,234, 97, 62,242,122, 85,  2, 31,
+	 28, 64,181,120,193, 51, 28,187,139,207,118,195, 68,222,173,243,
+	177,195, 10,230,138,142, 39, 76, 54,226,230,162, 86, 69,210, 37,
+	237, 32,217,178,  1,160,142,153, 14, 96,219,148,250,214,141, 83,
+	 57, 80,188,114,213, 48,110,245, 80, 43, 51,131,254, 65, 38, 42,
+	 72,134,105,166,185, 29, 94,200,152,103,174,120,187,203, 86,166,
+	222,114,213,252,216,143, 14,160,138,211, 78,173, 48, 82,233, 58,
+	153,  6,208, 28,193, 74, 71, 68,116,168, 71,236, 12, 29,209, 42,
+	 99, 69,108,166,110, 78, 91, 29, 64, 35,217,119,156,233,219,192,
+	237, 13,180, 85,171, 37,185, 53,210,134,155,237,242, 28,104,173,
+	254,128,109,254, 92,  0,214, 21,207, 73,152,203,108, 32,222, 84,
+	209,131,102,  1,224,208, 18, 16,  4, 22, 86,  4,129,216,240, 30,
+	204,  1,144,254, 35,244,237,  9, 57,156, 18, 71, 64, 32,127,127,
+	 60, 60, 54, 55,  3, 55, 91,185,155, 34,161,150,135,158,238, 94,
+	  2, 72,109,  2, 87, 50,239,170, 29, 36, 46,231,237, 55, 38,128,
+	 42,123, 86,127,168,151, 51,167,184, 19,192,162,  7,176,181,  1,
+	212,115,153,157, 26,  0, 56,230,140, 19,131,240,209,115,130,215,
+	 28,  0,229, 12,112,160,  0,229, 20, 48, 76, 82,103, 48,  2,205,
+	173,193, 51, 70,178, 61,211, 42, 41,120, 35,253,128,221,236, 80,
+	 38,251, 14, 98,182,245,165,  7, 80,234, 57,154,159, 92,236,155,
+	166,217,208,104, 58, 34,149,184, 60,142,142,234,  4,  4, 19,192,
+	 80, 63, 85, 78,207, 41,206,107,227,222,129, 66,  2, 24,240,125,
+	168, 69,105,109,195,148,185, 96, 68,144,101,204,130,255,228,174,
+	206,100,197, 19,  2,158,  0, 64, 65, 96,224,  1,240,116, 49,128,
+	108, 58, 84, 56,246,  5,203,228, 33, 81,146,121,  0, 20,185, 73,
+	143,124,119,103,202, 49, 10,106, 45,147, 36, 31, 45,105, 50,111,
+	182,243, 47,143,212,  6,238,228, 32,179,131,247, 73,195, 85, 62,
+	 54,150, 21, 70, 93,215, 79, 71,229,219,119, 57, 97,149,124,106,
+	 50, 55,185, 76, 65,222,103, 53,231,  0,202,136, 62,207, 70,116,
+	 21,229,155,100,226,135, 88,205, 62, 31,128,255,110,177,130,181,
+	 32,170,112,232,  8,188, 16,192,214,  8, 85,167,161, 88,158,204,
+	  8,108,147, 85,225,140,  7, 84,137, 48,146,162,232,147,133, 71,
+	 42,153, 51, 77,116,197, 15, 86,224,187,  4, 75,  5,160, 76,124,
+	 26,242, 13,169, 42,153,183,156,223,177,196,229,125,250,241,220,
+	216,218,161, 82,162, 70, 98, 23,134,204, 77,126,202,120,109, 90,
+	 86,115,238,  7,100,123, 25,248, 94, 54,103, 50, 34,  9, 96,218,
+	 21,116, 55, 11,  0,109, 55,140,210,128,102,113, 17, 64, 48,  1,
+	160, 89, 15, 13,199,183, 78,208, 17, 46,109, 58,  5,244, 68, 68,
+	 43, 21,120, 42, 89,224, 73, 38, 67, 13, 36,128,149,240, 84, 38,
+	 34, 32,165,148, 89, 37,125, 73,195,229, 90, 73, 88,136, 26, 83,
+	 99,176, 29, 12,253,204, 16,230, 36,133,178,153, 74,198,235,210,
+	115,103, 37,128,124,139,162,157,144,114,  8, 96,198, 82, 59, 59,
+	155,  5,128,110,  0, 43,187, 19,193, 92,  0,153,107,236,100,157,
+	160, 35, 83, 91,135,137,123, 79,136,174,  2, 83, 58,219, 43,153,
+	126, 59,246,231, 41,196,149,200,100,193,143,158, 83,249, 52, 82,
+	153,133,247,200,246,  3, 10,203,148,101,177,170, 75, 45, 59, 56,
+	229, 59,146,170,206, 28,131, 51,117, 52,  7, 79,174,250, 34,207,
+	 23, 83,233,160,121, 86,115,115, 37,100, 18,192, 90,  4,187,241,
+	 95, 21,  1, 64, 29,192, 68,110,167,212,151,247, 67,123, 31,199,
+	225,  2,  0, 43,185, 60, 79, 79,160,228,  9,185,134,252,137,220,
+	151, 98,155,179,107, 91,166,166,  2, 95,120,166,220, 35, 31, 72,
+	 27, 13, 64,145, 35, 87, 90,157, 10, 64,158,181,158,231,105,206,
+	197,174,199, 62,105,120, 42,182,  1,139, 60,145, 38,128,164,233,
+	 84, 96,202,211,175,164,194,157,114, 18,137,  0,205,172,230, 42,
+	181,110,191,213,119, 20,192, 92,238,121,231,217,176,118, 14, 96,
+	118,111,  0,121, 70,  3, 61,220,141, 89,131,239,174,173,148, 35,
+	 86,112, 95, 79,247,220, 69,106,160, 87, 71,134,212, 64,142,192,
+	206, 41, 96,239,137, 17,241,  5,114, 27,109,174,157,167, 32,183,
+	 49,231, 42, 15,185,  9,224,161,178,147,134,139, 44,149, 50, 91,
+	 80,196,227,169, 44, 15,164, 56, 27,132,158,208,166,178, 19,101,
+	131,172,230, 42,185,184,210,247, 83,  0,138,125,238,174,102,255,
+	 60,128,222,180,151,159,206,153,155,215, 17,237, 74,136,249, 97,
+	 31,224,164, 18,  8,135,158, 41,160,169,  2,  3, 57,173, 11,181,
+	243, 20, 40,128, 34, 15, 57, 25,  2,152, 31,149,221,107, 38, 13,
+	143, 69,122,104, 65, 66,160,238,183,210,106,157,250,243,145,196,
+	129, 91,202,189,195,179,154,119,  0,242,164,245,141,220, 51,174,
+	122,208, 76,  0,168,154,253, 27,  0,214, 87,  3,104, 29,126, 45,
+	 87, 47, 46,  7, 48,124,119,100,201, 87,  9,132,143,124,  4,118,
+	230,103, 51, 84,160, 48,  4,242, 90,  3, 80,158,126,116, 40,172,
+	 33,152,147,121,162,234,146,101,146, 18,121,134,100,122,250,164,
+	213,194,186,216, 97,107,102,179, 61,129, 97,143,109, 87,174,169,
+	 51, 90, 91, 42,178, 22,137, 44,212,165,166,  1, 99,165, 19,189,
+	  0,186,155,125, 82,  0,227, 91,  0, 12,222,206, 95, 30,223,201,
+	101,  0,  6,175,239,231,179,235, 16, 40,201,177, 80,128,158,204,
+	 28,186, 10,148, 71,193,104,231, 41, 80,  0, 83,177, 87,153, 71,
+	 71,245,  0,202,108,226,133,158,135,188, 63,218, 67, 36,  1,228,
+	133,130, 65,122, 41,153,216, 45, 17, 71, 41,168,  3, 62,142, 25,
+	 75, 77, 37,179, 98,181,242,192,135, 80,238,131,110, 36,224, 41,
+	 75,239, 34, 15, 85,208,230,128,173, 58,112,206,106, 22,  0, 30,
+	173,179,142,190,124, 35,231,201,  3,224,251,224,168,164,207,159,
+	177,179,186,152,  2, 76,115,111,110, 34, 93,  5,202,  3, 40, 91,
+	 29,192, 62,215,119,  7,114,154, 36, 60, 42, 43,213,242,144,179,
+	147, 82, 89,206,214, 52,237,230,112,125,146,231, 83,148,136,115,
+	 88,169,113,106,121,128,250, 28,186, 49, 61, 89, 43,143,250,245,
+	147, 88,164,224,172,104,109,145,116, 37,209,181, 16, 90, 50, 59,
+	245,253,225,121,223,117, 43,152,174,233,120,155,  5,128,231, 95,
+	 93, 70, 14,150,227,103,195, 58,  0,252,152,184,223, 60, 47, 83,
+	154, 62,222,163, 66, 52, 21,200,127, 13, 43,217,175,132, 84,101,
+	238,200, 67,206, 64,112,229, 33,175,251,227,181,244,248, 26, 43,
+	191,153, 24,207,185, 10, 12,184,191,198,209, 12, 45,147, 30,141,
+	181,230,193,249, 11,135,161, 31, 48, 24,107,246,185,  0, 60, 95,
+	  3,224,228, 57,151, 82,115, 69, 62,  0, 47, 57,171,240, 71, 61,
+	155, 32,246,155, 32, 67, 95, 32,159,251,183,230,153, 51,213, 32,
+	101,115,159,103,207,149,135,188, 98, 46,144,  1,129,161,235,180,
+	 73, 62,190,178,225,244,200, 51, 51, 91,201,166,197,216,172,115,
+	 94, 58,  1,215,  0,212,  2,193, 92,205,  2,192,  9,114,126,229,
+	 60,239, 20,223,  0, 96,207,159,240,217,140,156,149,100,170,192,
+	 84, 36,  9,173,250,163,127,233, 84, 45,176,  0, 20,115,184,163,
+	  5,160,157,229,155,103, 25,183,179,210,168,104,176, 64,228, 38,
+	 79,173,102,248,245,216,  0,208,  6,220, 88,138, 11, 70,154,  5,
+	128,167, 41,  0,123,211, 33,142,175,  6,240,231, 67,233,146,144,
+	231,218, 28,201, 78,169,207,  2,197,185,104,204,148,136,245,132,
+	247,233, 32,105, 55,207, 44,206,206,231, 61, 13,  1, 20,233,233,
+	213, 15, 73,173,232, 89,149, 59,168,204,228,177, 88,156,180, 97,
+	 14,242, 76,172,106,244, 57,203, 75,153, 68,252,228,  1, 80,102,
+	 95, 12,197, 27,252,222, 59,128,239,187,  2, 80,153, 14,167, 56,
+	185, 26,192,175,254,193,136,  1,120,244,176, 56,161,  2,227, 40,
+	138, 19, 45,215,114, 70,115, 95, 23, 98, 97,139,102,155, 87,169,
+	126,186,235,101,219,167,108, 78,212,245,238,139,186,207,242, 77,
+	 45,  4,205,  3,100,242, 87,177,240,155,248,120,144, 94,110,171,
+	153,152, 53,211,202,156,229,180, 50, 86,191, 32,176,111,150,246,
+	167,174, 21,128,  9,251, 33,217, 74,  9, 17,159, 28,192,207,119,
+	 77,115, 37,238, 83, 76, 38,  1,252,124,239, 35, 50,121,254,234,
+	241,227, 50,213, 30,164, 62,215, 55, 79,114, 47, 51,136, 55,125,
+	150, 51,153,110, 92,207, 38,158,235,249,201, 27, 98, 36, 40,231,
+	 33, 84,118, 24, 88,155, 26,137,115, 91,149,152, 89,175, 77, 53,
+	175, 42,147,217,165,  7,  5,121,148,150,140,134,201,115,153,139,
+	109,247, 33,249,153,149, 74,229, 58,  0,179,139,  1, 12,206,151,
+	241,247, 66,189, 26, 87,  1,248,171,157,224,121,140, 18,109,  0,
+	 38,254, 71,193, 95,190,204,238,253, 45, 50,197,203,164,221,173,
+	150, 53, 92, 36,106,209,246, 54,151,195,100,222,122,154,241,178,
+	172, 92,187,145,219, 58,209,143,113,179,147,147,235,205,244,151,
+	101,253,118,193,166, 86, 70,136,175, 89,  0, 56,  9, 96,207, 31,
+	 61,137, 33,189, 10,192,175,115,104,240, 39,227, 22,198, 94, 70,
+	159,165,168, 95, 80,100, 23,154, 62,131,115,211,104,153,170,180,
+	108,226,252, 62,153,250, 71,223,114,218,136,212, 42,142, 24, 28,
+	229, 40,230,103,163, 84,205, 68, 51,178, 50, 99, 79,181,209,172,
+	 90,123,203, 42, 95,179,  0,112,  2, 64, 93,117,209, 40,119,158,
+	154, 99, 30,128, 63,231, 55,237,153,176,  3,109, 10,227, 16, 78,
+	239,179, 32, 70, 14, 20,125,167,186, 43,197,187,153, 77,124,244,
+	 11,226,216, 22,172, 39, 15,143,114,105,162,120,154, 49, 46,219,
+	 87,100, 22, 25,177,152,156,139, 36, 50,100,229,109,193,207,  7,
+	160,174,186,152,233,192,179, 99,205,  1,240,231,252,174, 25,145,
+	199,139,249, 51,114, 36, 12, 47,248, 82,120,248,114,123, 56,146,
+	 46,184,140,158, 52,226, 39, 16,101, 98,222, 56,214,204,212, 21,
+	233,209,161,246, 72,209,199,186,125,127,  3,192,139,  1,252,210,
+	 85,151, 48, 29,230,  1,248,251,101,224, 39,248,155,158,  0,154,
+	  8, 14, 47,184, 16, 37,254,252, 30,174, 27,156, 83,206,138,159,
+	 68,148,203,115,109, 38,106, 27,187,210,231, 35, 47, 10, 45, 85,
+	242,247, 55,  0,188, 20,192,159,207,243,155,230,214,234,248, 99,
+	 71, 42,229, 23,  3,248,219,213,240,241,106, 60,141, 19, 59,237,
+	 46, 87,199, 57,124,239, 71, 88, 40,140,200, 59, 89, 46,114,128,
+	211,240,168,163,187,252,138,197,  0,252,250,209,100, 10,192,201,
+	194, 10, 64,163,160,  6,224,143, 41, 95,231,243,249,253,117,136,
+	 14,229,143,167,232,117,  0,104,222, 79, 43,248,120,123, 29, 60,
+	138,112,192,223,206,  0,108,213, 65, 72,205, 34,189, 51,206, 90,
+	186,211,175, 88, 10,192,215, 55, 67,198,  1,156, 46, 44,  0, 12,
+	204,130, 74,191,157,222,  6,242, 26, 14, 22, 64, 95, 24, 58,133,
+	 72, 82,238,  0,112,112,191, 85,129, 24,126,121, 37, 59,228, 79,
+	 88,221,173, 58, 60,137, 44, 86,229, 61,127,235, 98,  0, 58,197,
+	  7,224,116, 97,  1,224,213, 18, 42,254,234,194,123,158,251, 69,
+	117,236,150, 63,151, 85,177, 96,149,223,  0,240,122,252,184,229,
+	192, 76,215,186,185, 18,192, 83, 36,135,223,106,167,252, 57,172,
+	238,197,170,188,223, 79,120, 70,  0,229,204,141,109,117,100, 71,
+	117,205,  6, 48,136,148,250,219, 47,127,207, 32,107,  3,152,207,
+	  1, 48, 95,  4,192, 32, 74,116,213,213,150,190,196,129,126,  5,
+	 26,242, 42,196, 18, 44,248,123, 92,  0,  7,251,104,199,  1,204,
+	236, 93,113,179,229, 20,198,137,161,186,102,  3,120,100,202,207,
+	194, 15,252,237, 24,192,212,247, 50,147, 57,  0, 38,183,  2,120,
+	 12, 66,177,163, 66,103,103,  6,128,199, 83,200,224,211,170,  0,
+	127, 15,  0, 32,169,104, 18,155,100,112,162, 29, 93,208,113,164,
+	177,106,203,177,194, 58,128, 45,143,133,179, 75,134,145, 75, 24,
+	 57, 12, 29, 83,117,249,  1, 12,196,  1,102, 42,110, 78,171,129,
+	 85,161,101, 95,  0, 41,123,  5, 80,186,207, 89, 16,228, 64,178,
+	126,  9, 85, 47, 92, 93, 80,152,200,248,185,204, 46,233, 23,177,
+	 44,101,168, 46,226,  5, 48, 20,208, 13, 42, 96,244,113,252,160,
+	254, 30,  6,192,202,  8,169,204, 50,253,108, 89, 50,  0,176,150,
+	 97,150,174,194,122,226,221, 65,160,230,148,176,  0, 74,190, 46,
+	165, 39,142,241,  3, 72, 67,131, 83,179,  2, 89, 67, 85,247,248,
+	129,191,189,  3, 56,140,108,236, 67, 28,135,  1,141,164, 39,208,
+	 95,152,232,168,186, 74,250, 69,156,255,103,156,  7, 52,  2,160,
+	 48, 53, 92, 53,244, 85,  0,146,  7,  0, 80, 44, 74,150,134, 84,
+	124, 20, 27,  6, 95, 92, 86, 88,  6, 80, 90,  5,189,162,194, 42,
+	 53,118,198,  1,228,206,194,194,174, 64, 63,205,  5,140,236, 28,
+	 64, 25,117,233, 58, 44,210,158, 68,201,128,221,201,194,102, 64,
+	240,229, 39, 50, 14,208,153,  2,208,204,178,213,200, 26, 90,  2,
+	252, 30,  6, 64,103,100,173,121,216,211,112,165,231,146,194,163,
+	  5, 39, 78,100, 52, 56,102,  0,158,191,152,136,168,154, 99,159,
+	241,153,229,171, 53,207,144,188,251,122, 40,  0, 92,  0, 64, 79,
+	 92,185,245, 30, 47, 47,236, 59,246,108,130, 59, 43,224,178,100,
+	169,135,152,152,225, 55,145, 74,116,233, 60, 22, 13,112, 60, 10,
+	128, 99,199, 69,186, 83,153, 93, 86,120,137, 99,241,  4,128, 78,
+	145, 41,122,219, 75, 15,214,131,236, 21,192,239, 89,103, 36, 46,
+	197,234, 37, 85, 92,  2, 32,224,123,124,  0,221,184,204, 67,246,
+	 58,245, 58,117, 26,232, 12,  0, 65,195,131,  3,184,203,223, 55,
+	  9, 32, 66, 93,  0,224,102,  0,250, 50,238, 66,  0,224, 29,  0,
+	140, 51,  0,  8,  0,215,  7,176, 41,139,130,  5,224, 12,  2,107,
+	226,201,124, 87, 16,  0,184,  0,128,190,168,154,108, 34,225, 31,
+	  4,  0, 46,  2,160,200,114, 54, 12,171, 17,167, 70,182,  0, 16,
+	  0,174, 14, 96,237,140,191, 49,195,111, 32,  0,112, 61,  2, 27,
+	153,172,204, 12,191,217, 95,190, 13,  0,248,140,  0,242,248,155,
+	198, 21,126,  3,  5,  8,  0,239, 65, 32,185, 44, 86,  7,  2,  0,
+	215, 34,112,230, 18, 30,  4,  0,222,137, 64, 48,  0,  0, 55, 68,
+	 16,  4,  0,192,173, 96,196,203,  7,128, 16,  0,  8,  0, 33,  0,
+	 16,  2,  0,  1, 32,  4,  0, 66,  0, 32,  0,132,  0, 64,  8,  0,
+	  4,128, 16,  0,  8,  1,128, 16,  8,  0,132,  0, 64,  8,  4,  0,
+	 66,  0, 32,  4,  2,  0, 33,  0, 16,  2,  1,128, 16,  0,  8,129,
+	  0, 64,  8,  0,132, 64,  0, 32,  4,  0, 66, 32,  0, 16,  2,  0,
+	 33, 16,  0,  8,  1,128, 16,  8,  0,132,  0, 64,  8,  4,  0, 66,
+	  0, 32,  4,  2,  0, 33,  0, 16,  2,  1,128, 16,  0,  8,  1,128,
+	  0, 16,  2,  0, 33,  0, 16,  0, 66,  0, 32,  4,  0,  2, 64,  8,
+	  0,132,  0, 64,  8,  4,  0, 66,  0, 32,  4,  2,  0, 33,  0, 16,
+	  2,  1,128, 16,  0,  8,129,  0, 64,200,165,111,184,165, 66,  0,
+	 32,100, 67,254,218, 22,  0, 66, 86,127,151,132,216,186, 78,  2,
+	232,184,188,139, 83,227,  1,224,179,233,186,193,123,107, 91,167,
+	 10,116, 99,  9,  0, 33,183, 15,182,196,117,113,  0, 32,  1,128,
+	144,165,197,137, 90, 15, 32,113,149,  5,128,144,229,  1, 36,174,
+	139,198, 85,143, 94,  4,128,144, 37,  0,108,157, 23,219,169,162,
+	  0, 16, 50,203,228,245,154, 27,218, 23,196,  9, 32,241,  1,216,
+	213, 73,  0, 32,228, 82,131,195, 99,110,104, 88,233, 23,137, 75,
+	 45,146,137, 90,  1, 32,196,111,239,182, 62,  0,201,252,139, 58,
+	152,  0, 16, 50,223,224,189, 29,192, 22,  0, 66,174, 55,120,111,
+	  6,144,  0, 64,200,108,131,151, 56, 13,222,118,148,181,118,158,
+	101,  2,  0, 33,126,  0,221,166,  5, 93,230,229, 43,195,173,125,
+	149,180, 83,230, 10,  0,132,220,  8,224,165, 66,  0, 32,228, 22,
+	 51,216, 55,181,155, 13,160,215, 50,  6,128,144,139,  0, 36,215,
+	240,215, 42,199, 51,  0,132,140,189, 37,226,  7,176,189,158, 62,
+	141,193,214, 15,224,186,139, 35,  0,240, 65,244,157,119,213,163,
+	189,137, 62, 87, 21, 19,141,  3,192,191, 57,222, 18,143, 21,178,
+	188, 76, 53, 14,  0,255,166,197, 75,124, 42,112, 97,185,111,220,
+	 22,  0,124, 28,151, 11,185, 15,128,110,206,  1, 32, 44,222,251,
+	 16, 72,166,154,  6,128,240,249,221,103,  8,190,139,107,  6,  0,
+	 62,208, 24, 44, 57, 32,100, 85, 35, 68,248, 93,252,150, 49,  0,
+	252,179,  0,182,235,227, 39, 17, 36, 45,  0,132, 56,156,126,235,
+	227,199, 85, 45,105,239,178, 56,  2,  0, 31, 11,192,141,  4,  0,
+	 98, 12,222, 84,190,  1, 32, 84,224, 83, 42, 64,  0,  8, 21,184,
+	169,  2,  4,128,123,212,120,163,193, 47,219, 43,192, 69,179,106,
+	  1,192, 93,142,184,187, 34,144, 12,240, 91,116, 76,  6,128, 59,
+	157,241,145,253, 12,194, 22,126, 75, 18,  8,  0,119,107,113,144,
+	 29,106, 64,178,184, 93,  2,  0,119,108,241,146,189, 88,193, 35,
+	157,  3,128,207,108,241,146,125,240,231,236,  8, 52,224, 95,112,
+	250,145,125,240,231,232,  8,134,224,191,225,244, 35,251,224,207,
+	238,  8,140,144,191,161,  2,247, 42,176,130,255,138, 10,220,169,
+	192, 15,  8, 21,248, 28,139,195,  0, 16, 42,112,211,197, 97,  0,
+	  8, 21,184,105,116, 12,  0,  4,129,155, 70,103,  1, 64, 16,184,
+	105,116, 32,  0,  4,129,155, 70,167,  2, 64, 16,184,105,116, 52,
+	  0,220,  5,110, 15,173,  1,  9,  0,124,  2,117, 71,200,131,240,
+	 55,200, 94,116,107,120, 42,  0,220,207,112,171, 24,124, 20, 43,
+	152, 44,112,234, 43,  0,220,149,227,153, 60,134, 39,218,250, 51,
+	  1,128, 79, 99,111,144, 71, 88,  9, 89, 48, 56, 11,  0,238,205,
+	222, 37, 15,177, 22, 76,150,178,141,  1,224,158, 70,224,199, 21,
+	104, 64,184,252, 30,211, 57,  8,  0, 65,224,166,206,105,  0,  8,
+	  2, 55, 93, 28,  1,129, 49, 27,144,  0,  0,  7, 91, 73, 68, 65,
+	 84,128,152,  6,110, 26, 29,  8,  0,161,  2, 55, 93, 29,  6,128,
+	 32,112,211,232,  4,  0,  8,  4, 55, 13,142,  1,128, 32,112,211,
+	224, 44,  0,  8, 83,100,211,216, 64,  0,  8,  0, 55,221, 29,  7,
+	  0, 49,  6,111,170,  2,  1, 32, 20,224,166, 42, 16,  0, 66,  1,
+	194,  8,249,155,192, 49,121,112,  5,168,171,192,225, 15,  2,128,
+	 15, 50,226, 18,242,184, 10, 80,166,174,188,254, 96,107,  0,184,
+	135, 17,151,144,199, 93, 10, 25,244,157,  0, 64, 76,249, 30,105,
+	 82,  8,  0, 97,243,110,106, 23,  3, 64, 40,192, 77, 85, 32,  0,
+	  4,128,  0, 16,  4, 98, 14,  8,  0, 65,224, 38,142,105,  0,  8,
+	  2, 55, 93, 24,  1,128, 32,112,211,149, 97,  0,  8,  4, 55, 93,
+	 23,  6,128,219, 18,248, 60,  8, 94,121,138, 53,  0,  4,130, 27,
+	226,  7,  0, 49, 14,111, 28, 22,  8,  0,  1,224,166, 97,129,  0,
+	 16,  0,  2,192,191, 45,127,213,  1,  3,  0,161,  0,119,160,  2,
+	  1, 32,  0,  4,128, 24,129,255,238, 24, 12,  0,183,113,254, 73,
+	121,154,197, 16,162,255, 40,  0,136, 49,247, 81, 70,100,  0,136,
+	 49,119,211, 17, 25,  0,  2, 64,  0,136, 17,248,239,142,193,  0,
+	 16,  0,  2, 64,  0,  8,  0,  1, 32,  0,  4,128, 32, 16,110, 24,
+	  0,  8,  4,239,186, 46,  7,  0,129,224,166,203,194,  0,112, 43,
+	  4,159,116, 95, 48, 54,166, 63, 18,131, 79,182, 43,238,154,141,
+	 33,  0, 16,171, 34,155,  6,196,  0, 64,  0,  8,  0,  1, 32,  0,
+	  4,128, 48,134,  1, 32,  0,252,123, 97,249,  0, 16,  0,  2, 64,
+	  0,  8,  0,  1, 32,  0,  4,128,127,202,  7,221,193,247,108,139,
+	 33,132, 57,163,177, 20,183,127,250,158, 61, 24,129,  0, 64,208,
+	247, 32, 12,  2, 64,204,250, 54,157, 17,  2, 64,  0,  8,  0,  1,
+	 32,  0,  4,128,  0, 16,  0,  2, 64,  0,  8,  0,  1, 32,  0,132,
+	 23,230,239,248, 97,  0, 32, 24,220,212, 19, 13,  0,183, 97,240,
+	137,143,107, 69,126, 64,204,  8, 17,140,  0,  1,128,  0, 16,  0,
+	  2, 64,  8,  0,  4,128,  0,240, 62,242, 13,  0, 31, 78,  0, 32,
+	  0,  4,128,  0, 16,  0,  2, 64,  0,136, 53,145, 59,174,127,  0,
+	 64, 24, 32, 59, 97, 16,  0, 66,247,109,202, 32,  0,  4,126,155,
+	250,  3,  1, 32,  6,223, 77, 17,  4,128,192,111, 83,  4,  1, 32,
+	 60, 47, 91,198, 67,147,246,189, 19,  0,  8, 13,184, 17,128,109,
+	  3,  0,  1, 32,  0,  4,128,207, 38, 23,207, 71,  0, 32, 38,129,
+	119,  4,144,  0, 64,  0,184,217,  8,204, 50,210, 13, 71,  3,  0,
+	184,133, 31, 90,110, 74, 34,207,179, 59,201,248, 77,196,239,124,
+	 39,  0, 16, 10,113,139, 73, 31,113, 21,  4,128, 48, 74,238,101,
+	245, 18, 87, 73,  0,  8,  0,239, 14,160, 94, 20,  0,  2,192,123,
+	185, 93,136, 11, 86,  0,136, 73, 32,  0,132, 10,252, 19, 11, 31,
+	196, 85, 26,  0,  2,192, 77,  1,132, 35,122, 23, 94,193,167, 12,
+	131, 38, 67, 40, 93,  3, 54, 52, 32,212,223, 58, 74,144,216,106,
+	113, 88, 86, 56,174,  1, 32,240, 91, 30, 65,226, 99,178, 95, 54,
+	145, 31,  1, 32,248, 91,156, 64,159,211,217, 37,  0, 16,252, 45,
+	 78,160,211,229,242, 13,  0,129,223,157,252,129,196,233, 32, 36,
+	  0, 16,252,221, 73,  9,142, 77, 12,  1, 32,248, 91,157, 64,215,
+	176,140, 57, 32,  0,188, 27,128,100, 56, 42,251,157,157,  0, 16,
+	  0,174, 12, 32, 25,245,181,  3,192,141,228,153,249, 27,252,121,
+	141,254,177,  1,192, 93,168,192,  7, 94,143, 27,116,157,204, 84,
+	240,  0,112,123, 21, 72,200,  3,143,201,100, 48,195,251,  6,128,
+	 15,163,  2,  9,209, 54,240, 60, 50,128, 98,159, 21, 93, 96, 35,
+	115,103, 24,  0, 16,102,201,  2,252,181,142, 13,151,  0, 16,  0,
+	222,215,230, 32,215,252, 28,  0,  8,  2, 23,179,121,  9,  1,128,
+	240,204,220,125,233,215, 23,108, 15,  0,161,  2,239,239,244,155,
+	109, 82,  1, 64,224,183,228,202,111, 59,215,165,  4,  0,193,223,
+	173,  4, 14, 61,209,179,126, 10,  0,  4,127, 55, 19,216, 94,190,
+	242,  6,  0,193,223,242,  4,222,210,123,  0,  8,254, 22, 94, 13,
+	  6,128,224,239,129,  8,  4,128,224,111,  1,  2,  1, 32, 28,208,
+	 15, 74, 32,  0,  4,127,155, 14,194,  0,112,111,  3, 48,121, 72,
+	149,119, 53,129,  0,112,103, 26,144, 60,196,148,208,250,187,185,
+	122, 38, 11,  0,119,165,  2, 31, 36, 56,154,144,214,204,239,127,
+	253,159, 13,  0,220, 17,129,143, 18, 29,109,141,183, 55,168,109,
+	  0,184,151, 65,248,154, 96,186,173,150, 62,134, 40,126,195, 10,
+	126,108, 21,104,229,119, 36,187,230,111, 48,248, 18, 56,162,225,
+	155,185,167,  1, 66, 38,162, 17,  0, 32, 22, 71,238, 59,  3,108,
+	  1, 32,248,123,148,224,  3,  0,  8,254,182, 92,250,  5,128,152,
+	  0,238,139, 64,  0,  8,  5,184,233, 32, 12,  0,193,223,166,  4,
+	  2, 64, 12,192, 87,249, 98,  0, 32, 20,224,126,188,209,  0,240,
+	105, 21,224,126,112, 92, 42,252,  5,  0, 62,146,  2, 36,123,209,
+	136,100,173,158,  1,192, 61, 43, 64,178,151, 49,217,209,145,133,
+	122,  6,  0,119,172,  0,119, 19,157, 69,220,157,131,  6,124,110,
+	  2,231,167,154, 90,151,191, 97,231, 48,  4, 63, 53,129,100, 55,
+	174, 25, 95,239, 96,132, 60, 49,129, 87, 38,188, 93,117,  0,230,
+	 25,173, 85,247, 96,  5, 63, 47,129,100, 95,174, 65,231,228,  0,
+	126, 64,248,166,183,179,129,  9,  0,  4,127,119, 38,144,172,227,
+	 33,  7,128,  0,240, 10, 55, 52,194,177,192,223,157,103,129,  0,
+	 16,  0, 46, 30, 14,127,249,210, 47,  1,128,  0,240,158,139,195,
+	228,110,205,  2,192,221,139,237,146, 35,119,176, 57,236, 83,167,
+	  9,  0,252,243, 10,240, 46,139,115,196, 71, 62,  1,128,127, 29,
+	192,123, 88, 38,196,169,123, 87,139,203,  1,128, 15, 52,  2,187,
+	217, 88,111,233,151,140,173,134,  0,192,191,  6, 32,185,147,107,
+	134, 56,233, 95,171, 97,  0,184,251, 33,152,220, 59, 58,198, 49,
+	  1,208,178, 39, 17,  0,248, 39,103,129,228,123, 19,  0, 87,143,
+	205,  1,128,143,161,  4, 71, 16,232,149,228,181, 99, 46,113,249,
+	122,250,182,134,201,227,160,  1, 65,164,237,180, 35, 55,208,231,
+	115,246, 92,224, 24,  7,128,  0,240, 22, 48,200,104,141,  0, 16,
+	 50,233,154,105,191, 23,  1,240,219, 59,  9, 28,109, 28,  0,194,
+	 55,232,  4,195,155, 54,119,248,197,132,191,123,117,  5,  8,  0,
+	 31, 28, 64, 50,174, 22,201,212, 18,155, 19, 44,  0,  8,185, 20,
+	192, 25,243,194,  9,  0,191,125,  0,242,205, 72, 66,125, 46,238,
+	  1,  2,128, 15, 13, 32,185,  6, 64,143,193, 65,124,  0,174, 18,
+	138, 15,  0,159,193,  8, 38,223, 11,  2,232,174,118,237, 61,201,
+	  0,240, 65, 61,211, 22, 40,100,202,180, 32,227, 54,140, 42,189,
+	170,223, 25,  0, 62, 17,130,222,213, 17, 50,  1,160,215,222, 32,
+	 54,126,107, 71,191,  2,192,199,101,112,166,105,124,137,193, 75,
+	 86,183,122,  1,224,159,178, 76,220,  0,122,237,141,  9,159, 35,
+	  0,132, 92, 66,138, 91,127,145, 43,  1, 92,121, 31, 30,  0,124,
+	 58,219,152, 76,  3,232, 46, 59,105,116,  3, 64,200,  5,156, 92,
+	160, 23,213,101, 50,175,106,  0,  8, 25, 27, 43, 29,193,163, 62,
+	 93,215,175,108,108, 76, 32,  0,124, 54, 10,191, 47,  2,240,155,
+	144,185, 21,  3, 64,200, 13,182,201,114, 42, 22,  0, 66,182,158,
+	102,  2, 64,  8,  0,132,  0, 64,  0,  8,  1,128,144, 63,103,208,
+	  0, 64,  8,  0,132,  0, 64,  0,  8,121,244, 41, 32,  0,132, 92,
+	  0, 30,214,130, 33,207,  8, 31,  0,132,108, 48,232,  2, 64,  8,
+	  0,132,  0, 64,  0,  8,  1,128, 16,  0,  8,  0, 33,  0, 16,  2,
+	  0,  1, 32,100,  3,  4,  1, 32,100, 10, 65,108,203,132,108,206,
+	 32,  1,128,144,205,  5,  0, 66,  0, 32,  4,  6,  9,  0,132,  0,
+	 64,  8,  0,  4,128, 16,  0,  8,  1,128,  0, 16,  2,  0, 33,207,
+	 78,223, 58,222,104,  0,  8,185,136, 62,172,132, 64,158,106,232,
+	  5,128,144, 29,224,  7,  0, 33,155,226,  7,  0, 33,219,242,  7,
+	  0, 33,  0, 16,  2,  0,  7,242, 14,  0, 33,247,  1,176,162,  0,
+	 14,249, 59,188,117,  0,254,135,167, 15, 89,253,168,184,246,127,
+	 29,127,111, 78,  0,161,  2, 33,235,  3, 88, 83,  5,248,106,  1,
+	 24, 80,  0,207, 32, 16,178,242,150,164,250,131,  2, 24, 28,220,
+	 42,240,227, 63,  2,129, 16,185, 10, 76,255,223, 44, 41, 21, 29,
+	127, 93, 10, 80,152, 33, 16,200, 80,222,151,151, 55, 23,127,135,
+	  0,  4, 66,238,  2,224,219,233,224,150, 55, 60,109,200,250,  4,
+	190, 30,188, 18,188,189, 65, 13, 66,214,  4,240,237, 53, 56,140,
+	203, 17,  2, 89, 77, 14, 16,  8,  4,  2,129, 64, 32, 16,  8,  4,
+	  2,129, 64, 32,144, 77,228,255,172,172, 61, 79,147, 31,110,198,
+	  0,  0,  0,  0, 73, 69, 78, 68,174, 66, 96,130,
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/setupmenubar.h	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,11 @@
+Uint8 engineSetupMenuBar[134] = {
+	137, 80, 78, 71, 13, 10, 26, 10,  0,  0,  0, 13, 73, 72, 68, 82,
+	  0,  0,  0, 16,  0,  0,  0, 16,  8,  6,  0,  0,  0, 31,243,255,
+	 97,  0,  0,  0, 77, 73, 68, 65, 84, 56,203, 99,252,255,255,255,
+	100,  6, 10,  0, 19,  3,133,128,133,129,129, 65,148, 82,  3,  4,
+	 41, 53,128,141, 82,  3,228,137, 84,251,  3,151,  1,196,  2, 14,
+	154,120,129, 42,209,248,139, 82,  3,126, 80,106,192, 31, 74, 13,
+	184,134, 67, 78,144, 88,  3,112,129,247,196, 26,240,122, 64,163,
+	 17,  0,220, 81, 10,200,234, 71, 48, 81,  0,  0,  0,  0, 73, 69,
+	 78, 68,174, 66, 96,130,
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/stb_image.c	Fri May 16 03:22:39 2014 +0300
@@ -0,0 +1,4685 @@
+/* stbi-1.33 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c
+   when you control the images you're loading
+                                     no warranty implied; use at your own risk
+
+   QUICK NOTES:
+      Primarily of interest to game developers and other people who can
+          avoid problematic images and only need the trivial interface
+
+      JPEG baseline (no JPEG progressive)
+      PNG 8-bit only
+
+      TGA (not sure what subset, if a subset)
+      BMP non-1bpp, non-RLE
+      PSD (composited view only, no extra channels)
+
+      GIF (*comp always reports as 4-channel)
+      HDR (radiance rgbE format)
+      PIC (Softimage PIC)
+
+      - decode from memory or through FILE (define STBI_NO_STDIO to remove code)
+      - decode from arbitrary I/O callbacks
+      - overridable dequantizing-IDCT, YCbCr-to-RGB conversion (define STBI_SIMD)
+
+   Latest revisions:
+      1.33 (2011-07-14) minor fixes suggested by Dave Moore
+      1.32 (2011-07-13) info support for all filetypes (SpartanJ)
+      1.31 (2011-06-19) a few more leak fixes, bug in PNG handling (SpartanJ)
+      1.30 (2011-06-11) added ability to load files via io callbacks (Ben Wenger)
+      1.29 (2010-08-16) various warning fixes from Aurelien Pocheville 
+      1.28 (2010-08-01) fix bug in GIF palette transparency (SpartanJ)
+      1.27 (2010-08-01) cast-to-Uint8 to fix warnings (Laurent Gomila)
+                        allow trailing 0s at end of image data (Laurent Gomila)
+      1.26 (2010-07-24) fix bug in file buffering for PNG reported by SpartanJ
+
+   See end of file for full revision history.
+
+   TODO:
+      stbi_info support for BMP,PSD,HDR,PIC
+
+
+ ============================    Contributors    =========================
+              
+ Image formats                                Optimizations & bugfixes
+    Sean Barrett (jpeg, png, bmp)                Fabian "ryg" Giesen
+    Nicolas Schulz (hdr, psd)                                                 
+    Jonathan Dummer (tga)                     Bug fixes & warning fixes           
+    Jean-Marc Lienher (gif)                      Marc LeBlanc               
+    Tom Seddon (pic)                             Christpher Lloyd           
+    Thatcher Ulrich (psd)                        Dave Moore                 
+                                                 Won Chun                   
+                                                 the Horde3D community      
+ Extensions, features                            Janez Zemva                
+    Jetro Lauha (stbi_info)                      Jonathan Blow              
+    James "moose2000" Brown (iPhone PNG)         Laurent Gomila                             
+    Ben "Disch" Wenger (io callbacks)            Aruelien Pocheville
+    Martin "SpartanJ" Golini                     Ryamond Barbiero
+                                                 David Woo
+                                                 
+
+ If your name should be here but isn't, let Sean know.
+
+*/
+
+#ifndef STBI_INCLUDE_STB_IMAGE_H
+#define STBI_INCLUDE_STB_IMAGE_H
+
+// To get a header file for this, either cut and paste the header,
+// or create stb_image.h, #define STBI_HEADER_FILE_ONLY, and
+// then include stb_image.c from it.
+
+////   begin header file  ////////////////////////////////////////////////////
+//
+// Limitations:
+//    - no jpeg progressive support
+//    - non-HDR formats support 8-bit samples only (jpeg, png)
+//    - no delayed line count (jpeg) -- IJG doesn't support either
+//    - no 1-bit BMP
+//    - GIF always returns *comp=4
+//
+// Basic usage (see HDR discussion below):
+//    int x,y,n;
+//    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
+//    // ... process data if not NULL ... 
+//    // ... x = width, y = height, n = # 8-bit components per pixel ...
+//    // ... replace '0' with '1'..'4' to force that many components per pixel
+//    // ... but 'n' will always be the number that it would have been if you said 0
+//    stbi_image_free(data)
+//
+// Standard parameters:
+//    int *x       -- outputs image width in pixels
+//    int *y       -- outputs image height in pixels
+//    int *comp    -- outputs # of image components in image file
+//    int req_comp -- if non-zero, # of image components requested in result
+//
+// The return value from an image loader is an 'unsigned char *' which points
+// to the pixel data. The pixel data consists of *y scanlines of *x pixels,
+// with each pixel consisting of N interleaved 8-bit components; the first
+// pixel pointed to is top-left-most in the image. There is no padding between
+// image scanlines or between pixels, regardless of format. The number of
+// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise.
+// If req_comp is non-zero, *comp has the number of components that _would_
+// have been output otherwise. E.g. if you set req_comp to 4, you will always
+// get RGBA output, but you can check *comp to easily see if it's opaque.
+//
+// An output image with N components has the following components interleaved
+// in this order in each pixel:
+//
+//     N=#comp     components
+//       1           grey
+//       2           grey, alpha
+//       3           red, green, blue
+//       4           red, green, blue, alpha
+//
+// If image loading fails for any reason, the return value will be NULL,
+// and *x, *y, *comp will be unchanged. The function stbi_failure_reason()
+// can be queried for an extremely brief, end-user unfriendly explanation
+// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid
+// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
+// more user-friendly ones.
+//
+// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.
+//
+// ===========================================================================
+//
+// iPhone PNG support:
+//
+// By default we convert iphone-formatted PNGs back to RGB; nominally they
+// would silently load as BGR, except the existing code should have just
+// failed on such iPhone PNGs. But you can disable this conversion by
+// by calling stbi_convert_iphone_png_to_rgb(0), in which case
+// you will always just get the native iphone "format" through.
+//
+// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per
+// pixel to remove any premultiplied alpha *only* if the image file explicitly
+// says there's premultiplied data (currently only happens in iPhone images,
+// and only if iPhone convert-to-rgb processing is on).
+//
+// ===========================================================================
+//
+// HDR image support   (disable by defining STBI_NO_HDR)
+//
+// stb_image now supports loading HDR images in general, and currently
+// the Radiance .HDR file format, although the support is provided
+// generically. You can still load any file through the existing interface;
+// if you attempt to load an HDR file, it will be automatically remapped to
+// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;
+// both of these constants can be reconfigured through this interface:
+//
+//     stbi_hdr_to_ldr_gamma(2.2f);
+//     stbi_hdr_to_ldr_scale(1.0f);
+//
+// (note, do not use _inverse_ constants; stbi_image will invert them
+// appropriately).
+//
+// Additionally, there is a new, parallel interface for loading files as
+// (linear) floats to preserve the full dynamic range:
+//
+//    float *data = stbi_loadf(filename, &x, &y, &n, 0);
+// 
+// If you load LDR images through this interface, those images will
+// be promoted to floating point values, run through the inverse of
+// constants corresponding to the above:
+//
+//     stbi_ldr_to_hdr_scale(1.0f);
+//     stbi_ldr_to_hdr_gamma(2.2f);
+//
+// Finally, given a filename (or an open file or memory block--see header
+// file for details) containing image data, you can query for the "most
+// appropriate" interface to use (that is, whether the image is HDR or
+// not), using:
+//
+//     stbi_is_hdr(char *filename);
+//
+// ===========================================================================
+//
+// I/O callbacks
+//
+// I/O callbacks allow you to read from arbitrary sources, like packaged
+// files or some other source. Data read from callbacks are processed
+// through a small internal buffer (currently 128 bytes) to try to reduce
+// overhead. 
+//
+// The three functions you must define are "read" (reads some bytes of data),
+// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end).
+
+
+#ifndef STBI_NO_STDIO
+
+#if defined(_MSC_VER) && _MSC_VER >= 0x1400
+#define _CRT_SECURE_NO_WARNINGS // suppress bogus warnings about fopen()
+#endif
+
+#include <stdio.h>
+#endif
+
+#define STBI_VERSION 1
+
+enum
+{
+   STBI_default = 0, // only used for req_comp
+
+   STBI_grey       = 1,
+   STBI_grey_alpha = 2,
+   STBI_rgb        = 3,
+   STBI_rgb_alpha  = 4
+};
+
+typedef unsigned char stbi_uc;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// PRIMARY API - works on images of any type
+//
+
+//
+// load image by filename, open file, or memory buffer
+//
+
+extern stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
+
+#ifndef STBI_NO_STDIO
+extern stbi_uc *stbi_load            (char const *filename,     int *x, int *y, int *comp, int req_comp);
+extern stbi_uc *stbi_load_from_file  (FILE *f,                  int *x, int *y, int *comp, int req_comp);
+// for stbi_load_from_file, file pointer is left pointing immediately after image
+#endif
+
+typedef struct
+{
+   int      (*read)  (void *user,char *data,int size);   // fill 'data' with 'size' bytes.  return number of bytes actually read 
+   void     (*skip)  (void *user,unsigned n);            // skip the next 'n' bytes
+   int      (*eof)   (void *user);                       // returns nonzero if we are at end of file/data
+} stbi_io_callbacks;
+
+extern stbi_uc *stbi_load_from_callbacks  (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp);
+
+#ifndef STBI_NO_HDR
+   extern float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
+
+   #ifndef STBI_NO_STDIO
+   extern float *stbi_loadf            (char const *filename,   int *x, int *y, int *comp, int req_comp);
+   extern float *stbi_loadf_from_file  (FILE *f,                int *x, int *y, int *comp, int req_comp);
+   #endif
+   
+   extern float *stbi_loadf_from_callbacks  (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp);
+
+   extern void   stbi_hdr_to_ldr_gamma(float gamma);
+   extern void   stbi_hdr_to_ldr_scale(float scale);
+
+   extern void   stbi_ldr_to_hdr_gamma(float gamma);
+   extern void   stbi_ldr_to_hdr_scale(float scale);
+#endif // STBI_NO_HDR
+
+// stbi_is_hdr is always defined
+extern int    stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);
+extern int    stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);
+#ifndef STBI_NO_STDIO
+extern int      stbi_is_hdr          (char const *filename);
+extern int      stbi_is_hdr_from_file(FILE *f);
+#endif // STBI_NO_STDIO
+
+
+// get a VERY brief reason for failure
+// NOT THREADSAFE
+extern const char *stbi_failure_reason  (void); 
+
+// free the loaded image -- this is just free()
+extern void     stbi_image_free      (void *retval_from_stbi_load);
+
+// get image dimensions & components without fully decoding
+extern int      stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
+extern int      stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
+
+#ifndef STBI_NO_STDIO
+extern int      stbi_info            (char const *filename,     int *x, int *y, int *comp);
+extern int      stbi_info_from_file  (FILE *f,                  int *x, int *y, int *comp);
+
+#endif
+
+
+
+// for image formats that explicitly notate that they have premultiplied alpha,
+// we just return the colors as stored in the file. set this flag to force
+// unpremultiplication. results are undefined if the unpremultiply overflow.
+extern void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply);
+
+// indicate whether we should process iphone images back to canonical format,
+// or just pass them through "as-is"
+extern void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);
+
+
+// ZLIB client - used by PNG, available for other purposes
+
+extern char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);
+extern char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);
+extern int   stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
+
+extern char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);
+extern int   stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
+
+
+// define faster low-level operations (typically SIMD support)
+#ifdef STBI_SIMD
+typedef void (*stbi_idct_8x8)(stbi_uc *out, int out_stride, Sint16 data[64], Uint16 *dequantize);
+// compute an integer IDCT on "input"
+//     input[x] = data[x] * dequantize[x]
+//     write results to 'out': 64 samples, each run of 8 spaced by 'out_stride'
+//                             CLAMP results to 0..255
+typedef void (*stbi_YCbCr_to_RGB_run)(stbi_uc *output, stbi_uc const  *y, stbi_uc const *cb, stbi_uc const *cr, int count, int step);
+// compute a conversion from YCbCr to RGB
+//     'count' pixels
+//     write pixels to 'output'; each pixel is 'step' bytes (either 3 or 4; if 4, write '255' as 4th), order R,G,B
+//     y: Y input channel
+//     cb: Cb input channel; scale/biased to be 0..255
+//     cr: Cr input channel; scale/biased to be 0..255
+
+extern void stbi_install_idct(stbi_idct_8x8 func);
+extern void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func);
+#endif // STBI_SIMD
+
+
+#ifdef __cplusplus
+}
+#endif
+
+//
+//
+////   end header file   /////////////////////////////////////////////////////
+#endif // STBI_INCLUDE_STB_IMAGE_H
+
+#ifndef STBI_HEADER_FILE_ONLY
+
+#ifndef STBI_NO_HDR
+#include <math.h>  // ldexp
+#include <string.h> // strcmp, strtok
+#endif
+
+#ifndef STBI_NO_STDIO
+#include <stdio.h>
+#endif
+#include <stdlib.h>
+#include <memory.h>
+#include <assert.h>
+#include <stdarg.h>
+
+#ifndef _MSC_VER
+   #ifdef __cplusplus
+   #define stbi_inline inline
+   #else
+   #define stbi_inline
+   #endif
+#else
+   #define stbi_inline __forceinline
+#endif
+
+typedef unsigned int Uint;
+
+#if defined(STBI_NO_STDIO) && !defined(STBI_NO_WRITE)
+#define STBI_NO_WRITE
+#endif
+
+#define STBI_NOTUSED(v)  (void)sizeof(v)
+
+#ifdef _MSC_VER
+#define STBI_HAS_LROTL
+#endif
+
+#ifdef STBI_HAS_LROTL
+   #define stbi_lrot(x,y)  _lrotl(x,y)
+#else
+   #define stbi_lrot(x,y)  (((x) << (y)) | ((x) >> (32 - (y))))
+#endif
+
+///////////////////////////////////////////////
+//
+//  stbi struct and start_xxx functions
+
+// stbi structure is our basic context used by all images, so it
+// contains all the IO context, plus some basic image information
+typedef struct
+{
+   Uint32 img_x, img_y;
+   int img_n, img_out_n;
+   
+   stbi_io_callbacks io;
+   void *io_user_data;
+
+   int read_from_callbacks;
+   int buflen;
+   Uint8 buffer_start[128];
+
+   Uint8 *img_buffer, *img_buffer_end;
+   Uint8 *img_buffer_original;
+} stbi;
+
+
+static void refill_buffer(stbi *s);
+
+// initialize a memory-decode context
+static void start_mem(stbi *s, Uint8 const *buffer, int len)
+{
+   s->io.read = NULL;
+   s->read_from_callbacks = 0;
+   s->img_buffer = s->img_buffer_original = (Uint8 *) buffer;
+   s->img_buffer_end = (Uint8 *) buffer+len;
+}
+
+// initialize a callback-based context
+static void start_callbacks(stbi *s, stbi_io_callbacks *c, void *user)
+{
+   s->io = *c;
+   s->io_user_data = user;
+   s->buflen = sizeof(s->buffer_start);
+   s->read_from_callbacks = 1;
+   s->img_buffer_original = s->buffer_start;
+   refill_buffer(s);
+}
+
+#ifndef STBI_NO_STDIO
+
+static int stdio_read(void *user, char *data, int size)
+{
+   return (int) fread(data,1,size,(FILE*) user);
+}
+
+static void stdio_skip(void *user, unsigned n)
+{
+   fseek((FILE*) user, n, SEEK_CUR);
+}
+
+static int stdio_eof(void *user)
+{
+   return feof((FILE*) user);
+}
+
+static stbi_io_callbacks stbi_stdio_callbacks =
+{
+   stdio_read,
+   stdio_skip,
+   stdio_eof,
+};
+
+static void start_file(stbi *s, FILE *f)
+{
+   start_callbacks(s, &stbi_stdio_callbacks, (void *) f);
+}
+
+//static void stop_file(stbi *s) { }
+
+#endif // !STBI_NO_STDIO
+
+static void stbi_rewind(stbi *s)
+{
+   // conceptually rewind SHOULD rewind to the beginning of the stream,
+   // but we just rewind to the beginning of the initial buffer, because
+   // we only use it after doing 'test', which only ever looks at at most 92 bytes
+   s->img_buffer = s->img_buffer_original;
+}
+
+static int      stbi_jpeg_test(stbi *s);
+static stbi_uc *stbi_jpeg_load(stbi *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi_jpeg_info(stbi *s, int *x, int *y, int *comp);
+static int      stbi_png_test(stbi *s);
+static stbi_uc *stbi_png_load(stbi *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi_png_info(stbi *s, int *x, int *y, int *comp);
+#ifdef STBI_CRAP_FORMATS
+static int      stbi_bmp_test(stbi *s);
+static stbi_uc *stbi_bmp_load(stbi *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi_tga_test(stbi *s);
+static stbi_uc *stbi_tga_load(stbi *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi_tga_info(stbi *s, int *x, int *y, int *comp);
+static int      stbi_psd_test(stbi *s);
+static stbi_uc *stbi_psd_load(stbi *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi_pic_test(stbi *s);
+static stbi_uc *stbi_pic_load(stbi *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi_gif_test(stbi *s);
+static stbi_uc *stbi_gif_load(stbi *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi_gif_info(stbi *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_HDR
+static int      stbi_hdr_test(stbi *s);
+static float   *stbi_hdr_load(stbi *s, int *x, int *y, int *comp, int req_comp);
+#endif
+
+// this is not threadsafe
+static const char *failure_reason;
+
+const char *stbi_failure_reason(void)
+{
+   return failure_reason;
+}
+
+static int e(const char *str)
+{
+   failure_reason = str;
+   return 0;
+}
+
+// e - error
+// epf - error returning pointer to float
+// epuc - error returning pointer to unsigned char
+
+#ifdef STBI_NO_FAILURE_STRINGS
+   #define e(x,y)  0
+#elif defined(STBI_FAILURE_USERMSG)
+   #define e(x,y)  e(y)
+#else
+   #define e(x,y)  e(x)
+#endif
+
+#define epf(x,y)   ((float *) (e(x,y)?NULL:NULL))
+#define epuc(x,y)  ((unsigned char *) (e(x,y)?NULL:NULL))
+
+void stbi_image_free(void *retval_from_stbi_load)
+{
+   free(retval_from_stbi_load);
+}
+
+#ifndef STBI_NO_HDR
+static float   *ldr_to_hdr(stbi_uc *data, int x, int y, int comp);
+static stbi_uc *hdr_to_ldr(float   *data, int x, int y, int comp);
+#endif
+
+static unsigned char *stbi_load_main(stbi *s, int *x, int *y, int *comp, int req_comp)
+{
+   if (stbi_jpeg_test(s)) return stbi_jpeg_load(s,x,y,comp,req_comp);
+   if (stbi_png_test(s))  return stbi_png_load(s,x,y,comp,req_comp);
+#ifdef STBI_CRAP_FORMATS
+   if (stbi_bmp_test(s))  return stbi_bmp_load(s,x,y,comp,req_comp);
+   if (stbi_gif_test(s))  return stbi_gif_load(s,x,y,comp,req_comp);
+   if (stbi_psd_test(s))  return stbi_psd_load(s,x,y,comp,req_comp);
+   if (stbi_pic_test(s))  return stbi_pic_load(s,x,y,comp,req_comp);
+#endif
+
+   #ifndef STBI_NO_HDR
+   if (stbi_hdr_test(s)) {
+      float *hdr = stbi_hdr_load(s, x,y,comp,req_comp);
+      return hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp);
+   }
+   #endif
+
+#ifdef STBI_CRAP_FORMATS
+   // test tga last because it's a crappy test!
+   if (stbi_tga_test(s))
+      return stbi_tga_load(s,x,y,comp,req_comp);
+#endif
+
+   return epuc("unknown image type", "Image not of any known type, or corrupt");
+}
+
+#ifndef STBI_NO_STDIO
+unsigned char *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+   FILE *f = fopen(filename, "rb");
+   unsigned char *result;
+   if (!f) return epuc("can't fopen", "Unable to open file");
+   result = stbi_load_from_file(f,x,y,comp,req_comp);
+   fclose(f);
+   return result;
+}
+
+unsigned char *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+   stbi s;
+   start_file(&s,f);
+   return stbi_load_main(&s,x,y,comp,req_comp);
+}
+#endif //!STBI_NO_STDIO
+
+unsigned char *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
+{
+   stbi s;
+   start_mem(&s,buffer,len);
+   return stbi_load_main(&s,x,y,comp,req_comp);
+}
+
+unsigned char *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
+{
+   stbi s;
+   start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+   return stbi_load_main(&s,x,y,comp,req_comp);
+}
+
+#ifndef STBI_NO_HDR
+
+float *stbi_loadf_main(stbi *s, int *x, int *y, int *comp, int req_comp)
+{
+   unsigned char *data;
+   #ifndef STBI_NO_HDR
+   if (stbi_hdr_test(s))
+      return stbi_hdr_load(s,x,y,comp,req_comp);
+   #endif
+   data = stbi_load_main(s, x, y, comp, req_comp);
+   if (data)
+      return ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp);
+   return epf("unknown image type", "Image not of any known type, or corrupt");
+}
+
+float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
+{
+   stbi s;
+   start_mem(&s,buffer,len);
+   return stbi_loadf_main(&s,x,y,comp,req_comp);
+}
+
+float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
+{
+   stbi s;
+   start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+   return stbi_loadf_main(&s,x,y,comp,req_comp);
+}
+
+#ifndef STBI_NO_STDIO
+float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+   FILE *f = fopen(filename, "rb");
+   float *result;
+   if (!f) return epf("can't fopen", "Unable to open file");
+   result = stbi_loadf_from_file(f,x,y,comp,req_comp);
+   fclose(f);
+   return result;
+}
+
+float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+   stbi s;
+   start_file(&s,f);
+   return stbi_loadf_main(&s,x,y,comp,req_comp);
+}
+#endif // !STBI_NO_STDIO
+
+#endif // !STBI_NO_HDR
+
+// these is-hdr-or-not is defined independent of whether STBI_NO_HDR is
+// defined, for API simplicity; if STBI_NO_HDR is defined, it always
+// reports false!
+
+int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len)
+{
+   #ifndef STBI_NO_HDR
+   stbi s;
+   start_mem(&s,buffer,len);
+   return stbi_hdr_test(&s);
+   #else
+   STBI_NOTUSED(buffer);
+   STBI_NOTUSED(len);
+   return 0;
+   #endif
+}
+
+#ifndef STBI_NO_STDIO
+extern int      stbi_is_hdr          (char const *filename)
+{
+   FILE *f = fopen(filename, "rb");
+   int result=0;
+   if (f) {
+      result = stbi_is_hdr_from_file(f);
+      fclose(f);
+   }
+   return result;
+}
+
+extern int      stbi_is_hdr_from_file(FILE *f)
+{
+   #ifndef STBI_NO_HDR
+   stbi s;
+   start_file(&s,f);
+   return stbi_hdr_test(&s);
+   #else
+   return 0;
+   #endif
+}
+#endif // !STBI_NO_STDIO
+
+extern int      stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user)
+{
+   #ifndef STBI_NO_HDR
+   stbi s;
+   start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+   return stbi_hdr_test(&s);
+   #else
+   (void) clbk;
+   (void) user;
+   return 0;
+   #endif
+}
+
+#ifndef STBI_NO_HDR
+static float h2l_gamma_i=1.0f/2.2f, h2l_scale_i=1.0f;
+static float l2h_gamma=2.2f, l2h_scale=1.0f;
+
+void   stbi_hdr_to_ldr_gamma(float gamma) { h2l_gamma_i = 1/gamma; }
+void   stbi_hdr_to_ldr_scale(float scale) { h2l_scale_i = 1/scale; }
+
+void   stbi_ldr_to_hdr_gamma(float gamma) { l2h_gamma = gamma; }
+void   stbi_ldr_to_hdr_scale(float scale) { l2h_scale = scale; }
+#endif
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Common code used by all image loaders
+//
+
+enum
+{
+   SCAN_load=0,
+   SCAN_type,
+   SCAN_header
+};
+
+static void refill_buffer(stbi *s)
+{
+   int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen);
+   if (n == 0) {
+      // at end of file, treat same as if from memory
+      s->read_from_callbacks = 0;
+      s->img_buffer = s->img_buffer_end-1;
+      *s->img_buffer = 0;
+   } else {
+      s->img_buffer = s->buffer_start;
+      s->img_buffer_end = s->buffer_start + n;
+   }
+}
+
+stbi_inline static int get8(stbi *s)
+{
+   if (s->img_buffer < s->img_buffer_end)
+      return *s->img_buffer++;
+   if (s->read_from_callbacks) {
+      refill_buffer(s);
+      return *s->img_buffer++;
+   }
+   return 0;
+}
+
+stbi_inline static int at_eof(stbi *s)
+{
+   if (s->io.read) {
+      if (!(s->io.eof)(s->io_user_data)) return 0;
+      // if feof() is true, check if buffer = end
+      // special case: we've only got the special 0 character at the end
+      if (s->read_from_callbacks == 0) return 1;
+   }
+
+   return s->img_buffer >= s->img_buffer_end;   
+}
+
+stbi_inline static Uint8 get8u(stbi *s)
+{
+   return (Uint8) get8(s);
+}
+
+static void skip(stbi *s, int n)
+{
+   if (s->io.read) {
+      int blen = s->img_buffer_end - s->img_buffer;
+      if (blen < n) {
+         s->img_buffer = s->img_buffer_end;
+         (s->io.skip)(s->io_user_data, n - blen);
+         return;
+      }
+   }
+   s->img_buffer += n;
+}
+
+static int getn(stbi *s, stbi_uc *buffer, int n)
+{
+   if (s->io.read) {
+      int blen = s->img_buffer_end - s->img_buffer;
+      if (blen < n) {
+         int res, count;
+
+         memcpy(buffer, s->img_buffer, blen);
+         
+         count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen);
+         res = (count == (n-blen));
+         s->img_buffer = s->img_buffer_end;
+         return res;
+      }
+   }
+
+   if (s->img_buffer+n <= s->img_buffer_end) {
+      memcpy(buffer, s->img_buffer, n);
+      s->img_buffer += n;
+      return 1;
+   } else
+      return 0;
+}
+
+static int get16(stbi *s)
+{
+   int z = get8(s);
+   return (z << 8) + get8(s);
+}
+
+static Uint32 get32(stbi *s)
+{
+   Uint32 z = get16(s);
+   return (z << 16) + get16(s);
+}
+
+#ifdef STBI_CRAP_FORMATS
+static int get16le(stbi *s)
+{
+   int z = get8(s);
+   return z + (get8(s) << 8);
+}
+
+static Uint32 get32le(stbi *s)
+{
+   Uint32 z = get16le(s);
+   return z + (get16le(s) << 16);
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+//  generic converter from built-in img_n to req_comp
+//    individual types do this automatically as much as possible (e.g. jpeg
+//    does all cases internally since it needs to colorspace convert anyway,
+//    and it never has alpha, so very few cases ). png can automatically
+//    interleave an alpha=255 channel, but falls back to this for other cases
+//
+//  assume data buffer is malloced, so malloc a new one and free that one
+//  only failure mode is malloc failing
+
+static Uint8 compute_y(int r, int g, int b)
+{
+   return (Uint8) (((r*77) + (g*150) +  (29*b)) >> 8);
+}
+
+static unsigned char *convert_format(unsigned char *data, int img_n, int req_comp, Uint x, Uint y)
+{
+   int i,j;
+   unsigned char *good;
+
+   if (req_comp == img_n) return data;
+   assert(req_comp >= 1 && req_comp <= 4);
+
+   good = (unsigned char *) malloc(req_comp * x * y);
+   if (good == NULL) {
+      free(data);
+      return epuc("outofmem", "Out of memory");
+   }
+
+   for (j=0; j < (int) y; ++j) {
+      unsigned char *src  = data + j * x * img_n   ;
+      unsigned char *dest = good + j * x * req_comp;
+
+      #define COMBO(a,b)  ((a)*8+(b))
+      #define CASE(a,b)   case COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
+      // convert source image with img_n components to one with req_comp components;
+      // avoid switch per pixel, so use switch per scanline and massive macros
+      switch (COMBO(img_n, req_comp)) {
+         CASE(1,2) dest[0]=src[0], dest[1]=255; break;
+         CASE(1,3) dest[0]=dest[1]=dest[2]=src[0]; break;
+         CASE(1,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; break;
+         CASE(2,1) dest[0]=src[0]; break;
+         CASE(2,3) dest[0]=dest[1]=dest[2]=src[0]; break;
+         CASE(2,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; break;
+         CASE(3,4) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; break;
+         CASE(3,1) dest[0]=compute_y(src[0],src[1],src[2]); break;
+         CASE(3,2) dest[0]=compute_y(src[0],src[1],src[2]), dest[1] = 255; break;
+         CASE(4,1) dest[0]=compute_y(src[0],src[1],src[2]); break;
+         CASE(4,2) dest[0]=compute_y(src[0],src[1],src[2]), dest[1] = src[3]; break;
+         CASE(4,3) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; break;
+         default: assert(0);
+      }
+      #undef CASE
+   }
+
+   free(data);
+   return good;
+}
+
+#ifndef STBI_NO_HDR
+static float   *ldr_to_hdr(stbi_uc *data, int x, int y, int comp)
+{
+   int i,k,n;
+   float *output = (float *) malloc(x * y * comp * sizeof(float));
+   if (output == NULL) { free(data); return epf("outofmem", "Out of memory"); }
+   // compute number of non-alpha components
+   if (comp & 1) n = comp; else n = comp-1;
+   for (i=0; i < x*y; ++i) {
+      for (k=0; k < n; ++k) {
+         output[i*comp + k] = (float) pow(data[i*comp+k]/255.0f, l2h_gamma) * l2h_scale;
+      }
+      if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f;
+   }
+   free(data);
+   return output;
+}
+
+#define float2int(x)   ((int) (x))
+static stbi_uc *hdr_to_ldr(float   *data, int x, int y, int comp)
+{
+   int i,k,n;
+   stbi_uc *output = (stbi_uc *) malloc(x * y * comp);
+   if (output == NULL) { free(data); return epuc("outofmem", "Out of memory"); }
+   // compute number of non-alpha components
+   if (comp & 1) n = comp; else n = comp-1;
+   for (i=0; i < x*y; ++i) {
+      for (k=0; k < n; ++k) {
+         float z = (float) pow(data[i*comp+k]*h2l_scale_i, h2l_gamma_i) * 255 + 0.5f;
+         if (z < 0) z = 0;
+         if (z > 255) z = 255;
+         output[i*comp + k] = (Uint8) float2int(z);
+      }
+      if (k < comp) {
+         float z = data[i*comp+k] * 255 + 0.5f;
+         if (z < 0) z = 0;
+         if (z > 255) z = 255;
+         output[i*comp + k] = (Uint8) float2int(z);
+      }
+   }
+   free(data);
+   return output;
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+//  "baseline" JPEG/JFIF decoder (not actually fully baseline implementation)
+//
+//    simple implementation
+//      - channel subsampling of at most 2 in each dimension
+//      - doesn't support delayed output of y-dimension
+//      - simple interface (only one output format: 8-bit interleaved RGB)
+//      - doesn't try to recover corrupt jpegs
+//      - doesn't allow partial loading, loading multiple at once
+//      - still fast on x86 (copying globals into locals doesn't help x86)
+//      - allocates lots of intermediate memory (full size of all components)
+//        - non-interleaved case requires this anyway
+//        - allows good upsampling (see next)
+//    high-quality
+//      - upsampled channels are bilinearly interpolated, even across blocks
+//      - quality integer IDCT derived from IJG's 'slow'
+//    performance
+//      - fast huffman; reasonable integer IDCT
+//      - uses a lot of intermediate memory, could cache poorly
+//      - load http://nothings.org/remote/anemones.jpg 3 times on 2.8Ghz P4
+//          stb_jpeg:   1.34 seconds (MSVC6, default release build)
+//          stb_jpeg:   1.06 seconds (MSVC6, processor = Pentium Pro)
+//          IJL11.dll:  1.08 seconds (compiled by intel)
+//          IJG 1998:   0.98 seconds (MSVC6, makefile provided by IJG)
+//          IJG 1998:   0.95 seconds (MSVC6, makefile + proc=PPro)
+
+// huffman decoding acceleration
+#define FAST_BITS   9  // larger handles more cases; smaller stomps less cache
+
+typedef struct
+{
+   Uint8  fast[1 << FAST_BITS];
+   // weirdly, repacking this into AoS is a 10% speed loss, instead of a win
+   Uint16 code[256];
+   Uint8  values[256];
+   Uint8  size[257];
+   unsigned int maxcode[18];
+   int    delta[17];   // old 'firstsymbol' - old 'firstcode'
+} huffman;
+
+typedef struct
+{
+   #ifdef STBI_SIMD
+   Uint16 dequant2[4][64];
+   #endif
+   stbi *s;
+   huffman huff_dc[4];
+   huffman huff_ac[4];
+   Uint8 dequant[4][64];
+
+// sizes for components, interleaved MCUs
+   int img_h_max, img_v_max;
+   int img_mcu_x, img_mcu_y;
+   int img_mcu_w, img_mcu_h;
+
+// definition of jpeg image component
+   struct
+   {
+      int id;
+      int h,v;
+      int tq;
+      int hd,ha;
+      int dc_pred;
+
+      int x,y,w2,h2;
+      Uint8 *data;
+      void *raw_data;
+      Uint8 *linebuf;
+   } img_comp[4];
+
+   Uint32         code_buffer; // jpeg entropy-coded buffer
+   int            code_bits;   // number of valid bits
+   unsigned char  marker;      // marker seen while filling entropy buffer
+   int            nomore;      // flag if we saw a marker so must stop
+
+   int scan_n, order[4];
+   int restart_interval, todo;
+} jpeg;
+
+static int build_huffman(huffman *h, int *count)
+{
+   int i,j,k=0,code;
+   // build size list for each symbol (from JPEG spec)
+   for (i=0; i < 16; ++i)
+      for (j=0; j < count[i]; ++j)
+         h->size[k++] = (Uint8) (i+1);
+   h->size[k] = 0;
+
+   // compute actual symbols (from jpeg spec)
+   code = 0;
+   k = 0;
+   for(j=1; j <= 16; ++j) {
+      // compute delta to add to code to compute symbol id
+      h->delta[j] = k - code;
+      if (h->size[k] == j) {
+         while (h->size[k] == j)
+            h->code[k++] = (Uint16) (code++);
+         if (code-1 >= (1 << j)) return e("bad code lengths","Corrupt JPEG");
+      }
+      // compute largest code + 1 for this size, preshifted as needed later
+      h->maxcode[j] = code << (16-j);
+      code <<= 1;
+   }
+   h->maxcode[j] = 0xffffffff;
+
+   // build non-spec acceleration table; 255 is flag for not-accelerated
+   memset(h->fast, 255, 1 << FAST_BITS);
+   for (i=0; i < k; ++i) {
+      int s = h->size[i];
+      if (s <= FAST_BITS) {
+         int c = h->code[i] << (FAST_BITS-s);
+         int m = 1 << (FAST_BITS-s);
+         for (j=0; j < m; ++j) {
+            h->fast[c+j] = (Uint8) i;
+         }
+      }
+   }
+   return 1;
+}
+
+static void grow_buffer_unsafe(jpeg *j)
+{
+   do {
+      int b = j->nomore ? 0 : get8(j->s);
+      if (b == 0xff) {
+         int c = get8(j->s);
+         if (c != 0) {
+            j->marker = (unsigned char) c;
+            j->nomore = 1;
+            return;
+         }
+      }
+      j->code_buffer |= b << (24 - j->code_bits);
+      j->code_bits += 8;
+   } while (j->code_bits <= 24);
+}
+
+// (1 << n) - 1
+static Uint32 bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};
+
+// decode a jpeg huffman value from the bitstream
+stbi_inline static int decode(jpeg *j, huffman *h)
+{
+   unsigned int temp;
+   int c,k;
+
+   if (j->code_bits < 16) grow_buffer_unsafe(j);
+
+   // look at the top FAST_BITS and determine what symbol ID it is,
+   // if the code is <= FAST_BITS
+   c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+   k = h->fast[c];
+   if (k < 255) {
+      int s = h->size[k];
+      if (s > j->code_bits)
+         return -1;
+      j->code_buffer <<= s;
+      j->code_bits -= s;
+      return h->values[k];
+   }
+
+   // naive test is to shift the code_buffer down so k bits are
+   // valid, then test against maxcode. To speed this up, we've
+   // preshifted maxcode left so that it has (16-k) 0s at the
+   // end; in other words, regardless of the number of bits, it
+   // wants to be compared against something shifted to have 16;
+   // that way we don't need to shift inside the loop.
+   temp = j->code_buffer >> 16;
+   for (k=FAST_BITS+1 ; ; ++k)
+      if (temp < h->maxcode[k])
+         break;
+   if (k == 17) {
+      // error! code not found
+      j->code_bits -= 16;
+      return -1;
+   }
+
+   if (k > j->code_bits)
+      return -1;
+
+   // convert the huffman code to the symbol id
+   c = ((j->code_buffer >> (32 - k)) & bmask[k]) + h->delta[k];
+   assert((((j->code_buffer) >> (32 - h->size[c])) & bmask[h->size[c]]) == h->code[c]);
+
+   // convert the id to a symbol
+   j->code_bits -= k;
+   j->code_buffer <<= k;
+   return h->values[c];
+}
+
+// combined JPEG 'receive' and JPEG 'extend', since baseline
+// always extends everything it receives.
+stbi_inline static int extend_receive(jpeg *j, int n)
+{
+   unsigned int m = 1 << (n-1);
+   unsigned int k;
+   if (j->code_bits < n) grow_buffer_unsafe(j);
+
+   #if 1
+   k = stbi_lrot(j->code_buffer, n);
+   j->code_buffer = k & ~bmask[n];
+   k &= bmask[n];
+   j->code_bits -= n;
+   #else
+   k = (j->code_buffer >> (32 - n)) & bmask[n];
+   j->code_bits -= n;
+   j->code_buffer <<= n;
+   #endif
+   // the following test is probably a random branch that won't
+   // predict well. I tried to table accelerate it but failed.
+   // maybe it's compiling as a conditional move?
+   if (k < m)
+      return (-1 << n) + k + 1;
+   else
+      return k;
+}
+
+// given a value that's at position X in the zigzag stream,
+// where does it appear in the 8x8 matrix coded as row-major?
+static Uint8 dezigzag[64+15] =
+{
+    0,  1,  8, 16,  9,  2,  3, 10,
+   17, 24, 32, 25, 18, 11,  4,  5,
+   12, 19, 26, 33, 40, 48, 41, 34,
+   27, 20, 13,  6,  7, 14, 21, 28,
+   35, 42, 49, 56, 57, 50, 43, 36,
+   29, 22, 15, 23, 30, 37, 44, 51,
+   58, 59, 52, 45, 38, 31, 39, 46,
+   53, 60, 61, 54, 47, 55, 62, 63,
+   // let corrupt input sample past end
+   63, 63, 63, 63, 63, 63, 63, 63,
+   63, 63, 63, 63, 63, 63, 63
+};
+
+// decode one 64-entry block--
+static int decode_block(jpeg *j, Sint16 data[64], huffman *hdc, huffman *hac, int b)
+{
+   int diff,dc,k;
+   int t = decode(j, hdc);
+   if (t < 0) return e("bad huffman code","Corrupt JPEG");
+
+   // 0 all the ac values now so we can do it 32-bits at a time
+   memset(data,0,64*sizeof(data[0]));
+
+   diff = t ? extend_receive(j, t) : 0;
+   dc = j->img_comp[b].dc_pred + diff;
+   j->img_comp[b].dc_pred = dc;
+   data[0] = (Sint16) dc;
+
+   // decode AC components, see JPEG spec
+   k = 1;
+   do {
+      int r,s;
+      int rs = decode(j, hac);
+      if (rs < 0) return e("bad huffman code","Corrupt JPEG");
+      s = rs & 15;
+      r = rs >> 4;
+      if (s == 0) {
+         if (rs != 0xf0) break; // end block
+         k += 16;
+      } else {
+         k += r;
+         // decode into unzigzag'd location
+         data[dezigzag[k++]] = (Sint16) extend_receive(j,s);
+      }
+   } while (k < 64);
+   return 1;
+}
+
+// take a -128..127 value and clamp it and convert to 0..255
+stbi_inline static Uint8 clamp(int x)
+{
+   // trick to use a single test to catch both cases
+   if ((unsigned int) x > 255) {
+      if (x < 0) return 0;
+      if (x > 255) return 255;
+   }
+   return (Uint8) x;
+}
+
+#define f2f(x)  (int) (((x) * 4096 + 0.5))
+#define fsh(x)  ((x) << 12)
+
+// derived from jidctint -- DCT_ISLOW
+#define IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7)       \
+   int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \
+   p2 = s2;                                    \
+   p3 = s6;                                    \
+   p1 = (p2+p3) * f2f(0.5411961f);             \
+   t2 = p1 + p3*f2f(-1.847759065f);            \
+   t3 = p1 + p2*f2f( 0.765366865f);            \
+   p2 = s0;                                    \
+   p3 = s4;                                    \
+   t0 = fsh(p2+p3);                            \
+   t1 = fsh(p2-p3);                            \
+   x0 = t0+t3;                                 \
+   x3 = t0-t3;                                 \
+   x1 = t1+t2;                                 \
+   x2 = t1-t2;                                 \
+   t0 = s7;                                    \
+   t1 = s5;                                    \
+   t2 = s3;                                    \
+   t3 = s1;                                    \
+   p3 = t0+t2;                                 \
+   p4 = t1+t3;                                 \
+   p1 = t0+t3;                                 \
+   p2 = t1+t2;                                 \
+   p5 = (p3+p4)*f2f( 1.175875602f);            \
+   t0 = t0*f2f( 0.298631336f);                 \
+   t1 = t1*f2f( 2.053119869f);                 \
+   t2 = t2*f2f( 3.072711026f);                 \
+   t3 = t3*f2f( 1.501321110f);                 \
+   p1 = p5 + p1*f2f(-0.899976223f);            \
+   p2 = p5 + p2*f2f(-2.562915447f);            \
+   p3 = p3*f2f(-1.961570560f);                 \
+   p4 = p4*f2f(-0.390180644f);                 \
+   t3 += p1+p4;                                \
+   t2 += p2+p3;                                \
+   t1 += p2+p4;                                \
+   t0 += p1+p3;
+
+#ifdef STBI_SIMD
+typedef Uint16 stbi_dequantize_t;
+#else
+typedef Uint8 stbi_dequantize_t;
+#endif
+
+// .344 seconds on 3*anemones.jpg
+static void idct_block(Uint8 *out, int out_stride, Sint16 data[64], stbi_dequantize_t *dequantize)
+{
+   int i,val[64],*v=val;
+   stbi_dequantize_t *dq = dequantize;
+   Uint8 *o;
+   Sint16 *d = data;
+
+   // columns
+   for (i=0; i < 8; ++i,++d,++dq, ++v) {
+      // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing
+      if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0
+           && d[40]==0 && d[48]==0 && d[56]==0) {
+         //    no shortcut                 0     seconds
+         //    (1|2|3|4|5|6|7)==0          0     seconds
+         //    all separate               -0.047 seconds
+         //    1 && 2|3 && 4|5 && 6|7:    -0.047 seconds
+         int dcterm = d[0] * dq[0] << 2;
+         v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;
+      } else {
+         IDCT_1D(d[ 0]*dq[ 0],d[ 8]*dq[ 8],d[16]*dq[16],d[24]*dq[24],
+                 d[32]*dq[32],d[40]*dq[40],d[48]*dq[48],d[56]*dq[56])
+         // constants scaled things up by 1<<12; let's bring them back
+         // down, but keep 2 extra bits of precision
+         x0 += 512; x1 += 512; x2 += 512; x3 += 512;
+         v[ 0] = (x0+t3) >> 10;
+         v[56] = (x0-t3) >> 10;
+         v[ 8] = (x1+t2) >> 10;
+         v[48] = (x1-t2) >> 10;
+         v[16] = (x2+t1) >> 10;
+         v[40] = (x2-t1) >> 10;
+         v[24] = (x3+t0) >> 10;
+         v[32] = (x3-t0) >> 10;
+      }
+   }
+
+   for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) {
+      // no fast case since the first 1D IDCT spread components out
+      IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7])
+      // constants scaled things up by 1<<12, plus we had 1<<2 from first
+      // loop, plus horizontal and vertical each scale by sqrt(8) so together
+      // we've got an extra 1<<3, so 1<<17 total we need to remove.
+      // so we want to round that, which means adding 0.5 * 1<<17,
+      // aka 65536. Also, we'll end up with -128 to 127 that we want
+      // to encode as 0..255 by adding 128, so we'll add that before the shift
+      x0 += 65536 + (128<<17);
+      x1 += 65536 + (128<<17);
+      x2 += 65536 + (128<<17);
+      x3 += 65536 + (128<<17);
+      // tried computing the shifts into temps, or'ing the temps to see
+      // if any were out of range, but that was slower
+      o[0] = clamp((x0+t3) >> 17);
+      o[7] = clamp((x0-t3) >> 17);
+      o[1] = clamp((x1+t2) >> 17);
+      o[6] = clamp((x1-t2) >> 17);
+      o[2] = clamp((x2+t1) >> 17);
+      o[5] = clamp((x2-t1) >> 17);
+      o[3] = clamp((x3+t0) >> 17);
+      o[4] = clamp((x3-t0) >> 17);
+   }
+}
+
+#ifdef STBI_SIMD
+static stbi_idct_8x8 stbi_idct_installed = idct_block;
+
+void stbi_install_idct(stbi_idct_8x8 func)
+{
+   stbi_idct_installed = func;
+}
+#endif
+
+#define MARKER_none  0xff
+// if there's a pending marker from the entropy stream, return that
+// otherwise, fetch from the stream and get a marker. if there's no
+// marker, return 0xff, which is never a valid marker value
+static Uint8 get_marker(jpeg *j)
+{
+   Uint8 x;
+   if (j->marker != MARKER_none) { x = j->marker; j->marker = MARKER_none; return x; }
+   x = get8u(j->s);
+   if (x != 0xff) return MARKER_none;
+   while (x == 0xff)
+      x = get8u(j->s);
+   return x;
+}
+
+// in each scan, we'll have scan_n components, and the order
+// of the components is specified by order[]
+#define RESTART(x)     ((x) >= 0xd0 && (x) <= 0xd7)
+
+// after a restart interval, reset the entropy decoder and
+// the dc prediction
+static void reset(jpeg *j)
+{
+   j->code_bits = 0;
+   j->code_buffer = 0;
+   j->nomore = 0;
+   j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = 0;
+   j->marker = MARKER_none;
+   j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff;
+   // no more than 1<<31 MCUs if no restart_interal? that's plenty safe,
+   // since we don't even allow 1<<30 pixels
+}
+
+static int parse_entropy_coded_data(jpeg *z)
+{
+   reset(z);
+   if (z->scan_n == 1) {
+      int i,j;
+      #ifdef STBI_SIMD
+      __declspec(align(16))
+      #endif
+      Sint16 data[64];
+      int n = z->order[0];
+      // non-interleaved data, we just need to process one block at a time,
+      // in trivial scanline order
+      // number of blocks to do just depends on how many actual "pixels" this
+      // component has, independent of interleaved MCU blocking and such
+      int w = (z->img_comp[n].x+7) >> 3;
+      int h = (z->img_comp[n].y+7) >> 3;
+      for (j=0; j < h; ++j) {
+         for (i=0; i < w; ++i) {
+            if (!decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+z->img_comp[n].ha, n)) return 0;
+            #ifdef STBI_SIMD
+            stbi_idct_installed(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data, z->dequant2[z->img_comp[n].tq]);
+            #else
+            idct_block(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data, z->dequant[z->img_comp[n].tq]);
+            #endif
+            // every data block is an MCU, so countdown the restart interval
+            if (--z->todo <= 0) {
+               if (z->code_bits < 24) grow_buffer_unsafe(z);
+               // if it's NOT a restart, then just bail, so we get corrupt data
+               // rather than no data
+               if (!RESTART(z->marker)) return 1;
+               reset(z);
+            }
+         }
+      }
+   } else { // interleaved!
+      int i,j,k,x,y;
+      Sint16 data[64];
+      for (j=0; j < z->img_mcu_y; ++j) {
+         for (i=0; i < z->img_mcu_x; ++i) {
+            // scan an interleaved mcu... process scan_n components in order
+            for (k=0; k < z->scan_n; ++k) {
+               int n = z->order[k];
+               // scan out an mcu's worth of this component; that's just determined
+               // by the basic H and V specified for the component
+               for (y=0; y < z->img_comp[n].v; ++y) {
+                  for (x=0; x < z->img_comp[n].h; ++x) {
+                     int x2 = (i*z->img_comp[n].h + x)*8;
+                     int y2 = (j*z->img_comp[n].v + y)*8;
+                     if (!decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+z->img_comp[n].ha, n)) return 0;
+                     #ifdef STBI_SIMD
+                     stbi_idct_installed(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data, z->dequant2[z->img_comp[n].tq]);
+                     #else
+                     idct_block(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data, z->dequant[z->img_comp[n].tq]);
+                     #endif
+                  }
+               }
+            }
+            // after all interleaved components, that's an interleaved MCU,
+            // so now count down the restart interval
+            if (--z->todo <= 0) {
+               if (z->code_bits < 24) grow_buffer_unsafe(z);
+               // if it's NOT a restart, then just bail, so we get corrupt data
+               // rather than no data
+               if (!RESTART(z->marker)) return 1;
+               reset(z);
+            }
+         }
+      }
+   }
+   return 1;
+}
+
+static int process_marker(jpeg *z, int m)
+{
+   int L;
+   switch (m) {
+      case MARKER_none: // no marker found
+         return e("expected marker","Corrupt JPEG");
+
+      case 0xC2: // SOF - progressive
+         return e("progressive jpeg","JPEG format not supported (progressive)");
+
+      case 0xDD: // DRI - specify restart interval
+         if (get16(z->s) != 4) return e("bad DRI len","Corrupt JPEG");
+         z->restart_interval = get16(z->s);
+         return 1;
+
+      case 0xDB: // DQT - define quantization table
+         L = get16(z->s)-2;
+         while (L > 0) {
+            int q = get8(z->s);
+            int p = q >> 4;
+            int t = q & 15,i;
+            if (p != 0) return e("bad DQT type","Corrupt JPEG");
+            if (t > 3) return e("bad DQT table","Corrupt JPEG");
+            for (i=0; i < 64; ++i)
+               z->dequant[t][dezigzag[i]] = get8u(z->s);
+            #ifdef STBI_SIMD
+            for (i=0; i < 64; ++i)
+               z->dequant2[t][i] = z->dequant[t][i];
+            #endif
+            L -= 65;
+         }
+         return L==0;
+
+      case 0xC4: // DHT - define huffman table
+         L = get16(z->s)-2;
+         while (L > 0) {
+            Uint8 *v;
+            int sizes[16],i,m=0;
+            int q = get8(z->s);
+            int tc = q >> 4;
+            int th = q & 15;
+            if (tc > 1 || th > 3) return e("bad DHT header","Corrupt JPEG");
+            for (i=0; i < 16; ++i) {
+               sizes[i] = get8(z->s);
+               m += sizes[i];
+            }
+            L -= 17;
+            if (tc == 0) {
+               if (!build_huffman(z->huff_dc+th, sizes)) return 0;
+               v = z->huff_dc[th].values;
+            } else {
+               if (!build_huffman(z->huff_ac+th, sizes)) return 0;
+               v = z->huff_ac[th].values;
+            }
+            for (i=0; i < m; ++i)
+               v[i] = get8u(z->s);
+            L -= m;
+         }
+         return L==0;
+   }
+   // check for comment block or APP blocks
+   if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) {
+      skip(z->s, get16(z->s)-2);
+      return 1;
+   }
+   return 0;
+}
+
+// after we see SOS
+static int process_scan_header(jpeg *z)
+{
+   int i;
+   int Ls = get16(z->s);
+   z->scan_n = get8(z->s);
+   if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return e("bad SOS component count","Corrupt JPEG");
+   if (Ls != 6+2*z->scan_n) return e("bad SOS len","Corrupt JPEG");
+   for (i=0; i < z->scan_n; ++i) {
+      int id = get8(z->s), which;
+      int q = get8(z->s);
+      for (which = 0; which < z->s->img_n; ++which)
+         if (z->img_comp[which].id == id)
+            break;
+      if (which == z->s->img_n) return 0;
+      z->img_comp[which].hd = q >> 4;   if (z->img_comp[which].hd > 3) return e("bad DC huff","Corrupt JPEG");
+      z->img_comp[which].ha = q & 15;   if (z->img_comp[which].ha > 3) return e("bad AC huff","Corrupt JPEG");
+      z->order[i] = which;
+   }
+   if (get8(z->s) != 0) return e("bad SOS","Corrupt JPEG");
+   get8(z->s); // should be 63, but might be 0
+   if (get8(z->s) != 0) return e("bad SOS","Corrupt JPEG");
+
+   return 1;
+}
+
+static int process_frame_header(jpeg *z, int scan)
+{
+   stbi *s = z->s;
+   int Lf,p,i,q, h_max=1,v_max=1,c;
+   Lf = get16(s);         if (Lf < 11) return e("bad SOF len","Corrupt JPEG"); // JPEG
+   p  = get8(s);          if (p != 8) return e("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline
+   s->img_y = get16(s);   if (s->img_y == 0) return e("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG
+   s->img_x = get16(s);   if (s->img_x == 0) return e("0 width","Corrupt JPEG"); // JPEG requires
+   c = get8(s);
+   if (c != 3 && c != 1) return e("bad component count","Corrupt JPEG");    // JFIF requires
+   s->img_n = c;
+   for (i=0; i < c; ++i) {
+      z->img_comp[i].data = NULL;
+      z->img_comp[i].linebuf = NULL;
+   }
+
+   if (Lf != 8+3*s->img_n) return e("bad SOF len","Corrupt JPEG");
+
+   for (i=0; i < s->img_n; ++i) {
+      z->img_comp[i].id = get8(s);
+      if (z->img_comp[i].id != i+1)   // JFIF requires
+         if (z->img_comp[i].id != i)  // some version of jpegtran outputs non-JFIF-compliant files!
+            return e("bad component ID","Corrupt JPEG");
+      q = get8(s);
+      z->img_comp[i].h = (q >> 4);  if (!z->img_comp[i].h || z->img_comp[i].h > 4) return e("bad H","Corrupt JPEG");
+      z->img_comp[i].v = q & 15;    if (!z->img_comp[i].v || z->img_comp[i].v > 4) return e("bad V","Corrupt JPEG");
+      z->img_comp[i].tq = get8(s);  if (z->img_comp[i].tq > 3) return e("bad TQ","Corrupt JPEG");
+   }
+
+   if (scan != SCAN_load) return 1;
+
+   if ((1 << 30) / s->img_x / s->img_n < s->img_y) return e("too large", "Image too large to decode");
+
+   for (i=0; i < s->img_n; ++i) {
+      if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h;
+      if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v;
+   }
+
+   // compute interleaved mcu info
+   z->img_h_max = h_max;
+   z->img_v_max = v_max;
+   z->img_mcu_w = h_max * 8;
+   z->img_mcu_h = v_max * 8;
+   z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w;
+   z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h;
+
+   for (i=0; i < s->img_n; ++i) {
+      // number of effective pixels (e.g. for non-interleaved MCU)
+      z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max;
+      z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max;
+      // to simplify generation, we'll allocate enough memory to decode
+      // the bogus oversized data from using interleaved MCUs and their
+      // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't
+      // discard the extra data until colorspace conversion
+      z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8;
+      z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8;
+      z->img_comp[i].raw_data = malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15);
+      if (z->img_comp[i].raw_data == NULL) {
+         for(--i; i >= 0; --i) {
+            free(z->img_comp[i].raw_data);
+            z->img_comp[i].data = NULL;
+         }
+         return e("outofmem", "Out of memory");
+      }
+      // align blocks for installable-idct using mmx/sse
+      z->img_comp[i].data = (Uint8*) (((size_t) z->img_comp[i].raw_data + 15) & ~15);
+      z->img_comp[i].linebuf = NULL;
+   }
+
+   return 1;
+}
+
+// use comparisons since in some cases we handle more than one case (e.g. SOF)
+#define DNL(x)         ((x) == 0xdc)
+#define SOI(x)         ((x) == 0xd8)
+#define EOI(x)         ((x) == 0xd9)
+#define SOF(x)         ((x) == 0xc0 || (x) == 0xc1)
+#define SOS(x)         ((x) == 0xda)
+
+static int decode_jpeg_header(jpeg *z, int scan)
+{
+   int m;
+   z->marker = MARKER_none; // initialize cached marker to empty
+   m = get_marker(z);
+   if (!SOI(m)) return e("no SOI","Corrupt JPEG");
+   if (scan == SCAN_type) return 1;
+   m = get_marker(z);
+   while (!SOF(m)) {
+      if (!process_marker(z,m)) return 0;
+      m = get_marker(z);
+      while (m == MARKER_none) {
+         // some files have extra padding after their blocks, so ok, we'll scan
+         if (at_eof(z->s)) return e("no SOF", "Corrupt JPEG");
+         m = get_marker(z);
+      }
+   }
+   if (!process_frame_header(z, scan)) return 0;
+   return 1;
+}
+
+static int decode_jpeg_image(jpeg *j)
+{
+   int m;
+   j->restart_interval = 0;
+   if (!decode_jpeg_header(j, SCAN_load)) return 0;
+   m = get_marker(j);
+   while (!EOI(m)) {
+      if (SOS(m)) {
+         if (!process_scan_header(j)) return 0;
+         if (!parse_entropy_coded_data(j)) return 0;
+         if (j->marker == MARKER_none ) {
+            // handle 0s at the end of image data from IP Kamera 9060
+            while (!at_eof(j->s)) {
+               int x = get8(j->s);
+               if (x == 255) {
+                  j->marker = get8u(j->s);
+                  break;
+               } else if (x != 0) {
+                  return 0;
+               }
+            }
+            // if we reach eof without hitting a marker, get_marker() below will fail and we'll eventually return 0
+         }
+      } else {
+         if (!process_marker(j, m)) return 0;
+      }
+      m = get_marker(j);
+   }
+   return 1;
+}
+
+// static jfif-centered resampling (across block boundaries)
+
+typedef Uint8 *(*resample_row_func)(Uint8 *out, Uint8 *in0, Uint8 *in1,
+                                    int w, int hs);
+
+#define div4(x) ((Uint8) ((x) >> 2))
+
+static Uint8 *resample_row_1(Uint8 *out, Uint8 *in_near, Uint8 *in_far, int w, int hs)
+{
+   STBI_NOTUSED(out);
+   STBI_NOTUSED(in_far);
+   STBI_NOTUSED(w);
+   STBI_NOTUSED(hs);
+   return in_near;
+}
+
+static Uint8* resample_row_v_2(Uint8 *out, Uint8 *in_near, Uint8 *in_far, int w, int hs)
+{
+   // need to generate two samples vertically for every one in input
+   int i;
+   STBI_NOTUSED(hs);
+   for (i=0; i < w; ++i)
+      out[i] = div4(3*in_near[i] + in_far[i] + 2);
+   return out;
+}
+
+static Uint8*  resample_row_h_2(Uint8 *out, Uint8 *in_near, Uint8 *in_far, int w, int hs)
+{
+   // need to generate two samples horizontally for every one in input
+   int i;
+   Uint8 *input = in_near;
+
+   if (w == 1) {
+      // if only one sample, can't do any interpolation
+      out[0] = out[1] = input[0];
+      return out;
+   }
+
+   out[0] = input[0];
+   out[1] = div4(input[0]*3 + input[1] + 2);
+   for (i=1; i < w-1; ++i) {
+      int n = 3*input[i]+2;
+      out[i*2+0] = div4(n+input[i-1]);
+      out[i*2+1] = div4(n+input[i+1]);
+   }
+   out[i*2+0] = div4(input[w-2]*3 + input[w-1] + 2);
+   out[i*2+1] = input[w-1];
+
+   STBI_NOTUSED(in_far);
+   STBI_NOTUSED(hs);
+
+   return out;
+}
+
+#define div16(x) ((Uint8) ((x) >> 4))
+
+static Uint8 *resample_row_hv_2(Uint8 *out, Uint8 *in_near, Uint8 *in_far, int w, int hs)
+{
+   // need to generate 2x2 samples for every one in input
+   int i,t0,t1;
+   if (w == 1) {
+      out[0] = out[1] = div4(3*in_near[0] + in_far[0] + 2);
+      return out;
+   }
+
+   t1 = 3*in_near[0] + in_far[0];
+   out[0] = div4(t1+2);
+   for (i=1; i < w; ++i) {
+      t0 = t1;
+      t1 = 3*in_near[i]+in_far[i];
+      out[i*2-1] = div16(3*t0 + t1 + 8);
+      out[i*2  ] = div16(3*t1 + t0 + 8);
+   }
+   out[w*2-1] = div4(t1+2);
+
+   STBI_NOTUSED(hs);
+
+   return out;
+}
+
+static Uint8 *resample_row_generic(Uint8 *out, Uint8 *in_near, Uint8 *in_far, int w, int hs)
+{
+   // resample with nearest-neighbor
+   int i,j;
+   (void) in_far;
+   for (i=0; i < w; ++i)
+      for (j=0; j < hs; ++j)
+         out[i*hs+j] = in_near[i];
+   return out;
+}
+
+#define float2fixed(x)  ((int) ((x) * 65536 + 0.5))
+
+// 0.38 seconds on 3*anemones.jpg   (0.25 with processor = Pro)
+// VC6 without processor=Pro is generating multiple LEAs per multiply!
+static void YCbCr_to_RGB_row(Uint8 *out, const Uint8 *y, const Uint8 *pcb, const Uint8 *pcr, int count, int step)
+{
+   int i;
+   for (i=0; i < count; ++i) {
+      int y_fixed = (y[i] << 16) + 32768; // rounding
+      int r,g,b;
+      int cr = pcr[i] - 128;
+      int cb = pcb[i] - 128;
+      r = y_fixed + cr*float2fixed(1.40200f);
+      g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f);
+      b = y_fixed                            + cb*float2fixed(1.77200f);
+      r >>= 16;
+      g >>= 16;
+      b >>= 16;
+      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }
+      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }
+      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }
+      out[0] = (Uint8)r;
+      out[1] = (Uint8)g;
+      out[2] = (Uint8)b;
+      out[3] = 255;
+      out += step;
+   }
+}
+
+#ifdef STBI_SIMD
+static stbi_YCbCr_to_RGB_run stbi_YCbCr_installed = YCbCr_to_RGB_row;
+
+void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func)
+{
+   stbi_YCbCr_installed = func;
+}
+#endif
+
+
+// clean up the temporary component buffers
+static void cleanup_jpeg(jpeg *j)
+{
+   int i;
+   for (i=0; i < j->s->img_n; ++i) {
+      if (j->img_comp[i].data) {
+         free(j->img_comp[i].raw_data);
+         j->img_comp[i].data = NULL;
+      }
+      if (j->img_comp[i].linebuf) {
+         free(j->img_comp[i].linebuf);
+         j->img_comp[i].linebuf = NULL;
+      }
+   }
+}
+
+typedef struct
+{
+   resample_row_func resample;
+   Uint8 *line0,*line1;
+   int hs,vs;   // expansion factor in each axis
+   int w_lores; // horizontal pixels pre-expansion 
+   int ystep;   // how far through vertical expansion we are
+   int ypos;    // which pre-expansion row we're on
+} stbi_resample;
+
+static Uint8 *load_jpeg_image(jpeg *z, int *out_x, int *out_y, int *comp, int req_comp)
+{
+   int n, decode_n;
+   // validate req_comp
+   if (req_comp < 0 || req_comp > 4) return epuc("bad req_comp", "Internal error");
+   z->s->img_n = 0;
+
+   // load a jpeg image from whichever source
+   if (!decode_jpeg_image(z)) { cleanup_jpeg(z); return NULL; }
+
+   // determine actual number of components to generate
+   n = req_comp ? req_comp : z->s->img_n;
+
+   if (z->s->img_n == 3 && n < 3)
+      decode_n = 1;
+   else
+      decode_n = z->s->img_n;
+
+   // resample and color-convert
+   {
+      int k;
+      Uint i,j;
+      Uint8 *output;
+      Uint8 *coutput[4];
+
+      stbi_resample res_comp[4];
+
+      for (k=0; k < decode_n; ++k) {
+         stbi_resample *r = &res_comp[k];
+
+         // allocate line buffer big enough for upsampling off the edges
+         // with upsample factor of 4
+         z->img_comp[k].linebuf = (Uint8 *) malloc(z->s->img_x + 3);
+         if (!z->img_comp[k].linebuf) { cleanup_jpeg(z); return epuc("outofmem", "Out of memory"); }
+
+         r->hs      = z->img_h_max / z->img_comp[k].h;
+         r->vs      = z->img_v_max / z->img_comp[k].v;
+         r->ystep   = r->vs >> 1;
+         r->w_lores = (z->s->img_x + r->hs-1) / r->hs;
+         r->ypos    = 0;
+         r->line0   = r->line1 = z->img_comp[k].data;
+
+         if      (r->hs == 1 && r->vs == 1) r->resample = resample_row_1;
+         else if (r->hs == 1 && r->vs == 2) r->resample = resample_row_v_2;
+         else if (r->hs == 2 && r->vs == 1) r->resample = resample_row_h_2;
+         else if (r->hs == 2 && r->vs == 2) r->resample = resample_row_hv_2;
+         else                               r->resample = resample_row_generic;
+      }
+
+      // can't error after this so, this is safe
+      output = (Uint8 *) malloc(n * z->s->img_x * z->s->img_y + 1);
+      if (!output) { cleanup_jpeg(z); return epuc("outofmem", "Out of memory"); }
+
+      // now go ahead and resample
+      for (j=0; j < z->s->img_y; ++j) {
+         Uint8 *out = output + n * z->s->img_x * j;
+         for (k=0; k < decode_n; ++k) {
+            stbi_resample *r = &res_comp[k];
+            int y_bot = r->ystep >= (r->vs >> 1);
+            coutput[k] = r->resample(z->img_comp[k].linebuf,
+                                     y_bot ? r->line1 : r->line0,
+                                     y_bot ? r->line0 : r->line1,
+                                     r->w_lores, r->hs);
+            if (++r->ystep >= r->vs) {
+               r->ystep = 0;
+               r->line0 = r->line1;
+               if (++r->ypos < z->img_comp[k].y)
+                  r->line1 += z->img_comp[k].w2;
+            }
+         }
+         if (n >= 3) {
+            Uint8 *y = coutput[0];
+            if (z->s->img_n == 3) {
+               #ifdef STBI_SIMD
+               stbi_YCbCr_installed(out, y, coutput[1], coutput[2], z->s.img_x, n);
+               #else
+               YCbCr_to_RGB_row(out, y, coutput[1], coutput[2], z->s->img_x, n);
+               #endif
+            } else
+               for (i=0; i < z->s->img_x; ++i) {
+                  out[0] = out[1] = out[2] = y[i];
+                  out[3] = 255; // not used if n==3
+                  out += n;
+               }
+         } else {
+            Uint8 *y = coutput[0];
+            if (n == 1)
+               for (i=0; i < z->s->img_x; ++i) out[i] = y[i];
+            else
+               for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255;
+         }
+      }
+      cleanup_jpeg(z);
+      *out_x = z->s->img_x;
+      *out_y = z->s->img_y;
+      if (comp) *comp  = z->s->img_n; // report original components, not output
+      return output;
+   }
+}
+
+static unsigned char *stbi_jpeg_load(stbi *s, int *x, int *y, int *comp, int req_comp)
+{
+   jpeg j;
+   j.s = s;
+   return load_jpeg_image(&j, x,y,comp,req_comp);
+}
+
+static int stbi_jpeg_test(stbi *s)
+{
+   int r;
+   jpeg j;
+   j.s = s;
+   r = decode_jpeg_header(&j, SCAN_type);
+   stbi_rewind(s);
+   return r;
+}
+
+static int stbi_jpeg_info_raw(jpeg *j, int *x, int *y, int *comp)
+{
+   if (!decode_jpeg_header(j, SCAN_header)) {
+      stbi_rewind( j->s );
+      return 0;
+   }
+   if (x) *x = j->s->img_x;
+   if (y) *y = j->s->img_y;
+   if (comp) *comp = j->s->img_n;
+   return 1;
+}
+
+static int stbi_jpeg_info(stbi *s, int *x, int *y, int *comp)
+{
+   jpeg j;
+   j.s = s;
+   return stbi_jpeg_info_raw(&j, x, y, comp);
+}
+
+// public domain zlib decode    v0.2  Sean Barrett 2006-11-18
+//    simple implementation
+//      - all input must be provided in an upfront buffer
+//      - all output is written to a single output buffer (can malloc/realloc)
+//    performance
+//      - fast huffman
+
+// fast-way is faster to check than jpeg huffman, but slow way is slower
+#define ZFAST_BITS  9 // accelerate all cases in default tables
+#define ZFAST_MASK  ((1 << ZFAST_BITS) - 1)
+
+// zlib-style huffman encoding
+// (jpegs packs from left, zlib from right, so can't share code)
+typedef struct
+{
+   Uint16 fast[1 << ZFAST_BITS];
+   Uint16 firstcode[16];
+   int maxcode[17];
+   Uint16 firstsymbol[16];
+   Uint8  size[288];
+   Uint16 value[288]; 
+} zhuffman;
+
+stbi_inline static int bitreverse16(int n)
+{
+  n = ((n & 0xAAAA) >>  1) | ((n & 0x5555) << 1);
+  n = ((n & 0xCCCC) >>  2) | ((n & 0x3333) << 2);
+  n = ((n & 0xF0F0) >>  4) | ((n & 0x0F0F) << 4);
+  n = ((n & 0xFF00) >>  8) | ((n & 0x00FF) << 8);
+  return n;
+}
+
+stbi_inline static int bit_reverse(int v, int bits)
+{
+   assert(bits <= 16);
+   // to bit reverse n bits, reverse 16 and shift
+   // e.g. 11 bits, bit reverse and shift away 5
+   return bitreverse16(v) >> (16-bits);
+}
+
+static int zbuild_huffman(zhuffman *z, Uint8 *sizelist, int num)
+{
+   int i,k=0;
+   int code, next_code[16], sizes[17];
+
+   // DEFLATE spec for generating codes
+   memset(sizes, 0, sizeof(sizes));
+   memset(z->fast, 255, sizeof(z->fast));
+   for (i=0; i < num; ++i) 
+      ++sizes[sizelist[i]];
+   sizes[0] = 0;
+   for (i=1; i < 16; ++i)
+      assert(sizes[i] <= (1 << i));
+   code = 0;
+   for (i=1; i < 16; ++i) {
+      next_code[i] = code;
+      z->firstcode[i] = (Uint16) code;
+      z->firstsymbol[i] = (Uint16) k;
+      code = (code + sizes[i]);
+      if (sizes[i])
+         if (code-1 >= (1 << i)) return e("bad codelengths","Corrupt JPEG");
+      z->maxcode[i] = code << (16-i); // preshift for inner loop
+      code <<= 1;
+      k += sizes[i];
+   }
+   z->maxcode[16] = 0x10000; // sentinel
+   for (i=0; i < num; ++i) {
+      int s = sizelist[i];
+      if (s) {
+         int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s];
+         z->size[c] = (Uint8)s;
+         z->value[c] = (Uint16)i;
+         if (s <= ZFAST_BITS) {
+            int k = bit_reverse(next_code[s],s);
+            while (k < (1 << ZFAST_BITS)) {
+               z->fast[k] = (Uint16) c;
+               k += (1 << s);
+            }
+         }
+         ++next_code[s];
+      }
+   }
+   return 1;
+}
+
+// zlib-from-memory implementation for PNG reading
+//    because PNG allows splitting the zlib stream arbitrarily,
+//    and it's annoying structurally to have PNG call ZLIB call PNG,
+//    we require PNG read all the IDATs and combine them into a single
+//    memory buffer
+
+typedef struct
+{
+   Uint8 *zbuffer, *zbuffer_end;
+   int num_bits;
+   Uint32 code_buffer;
+
+   char *zout;
+   char *zout_start;
+   char *zout_end;
+   int   z_expandable;
+
+   zhuffman z_length, z_distance;
+} zbuf;
+
+stbi_inline static int zget8(zbuf *z)
+{
+   if (z->zbuffer >= z->zbuffer_end) return 0;
+   return *z->zbuffer++;
+}
+
+static void fill_bits(zbuf *z)
+{
+   do {
+      assert(z->code_buffer < (1U << z->num_bits));
+      z->code_buffer |= zget8(z) << z->num_bits;
+      z->num_bits += 8;
+   } while (z->num_bits <= 24);
+}
+
+stbi_inline static unsigned int zreceive(zbuf *z, int n)
+{
+   unsigned int k;
+   if (z->num_bits < n) fill_bits(z);
+   k = z->code_buffer & ((1 << n) - 1);
+   z->code_buffer >>= n;
+   z->num_bits -= n;
+   return k;   
+}
+
+stbi_inline static int zhuffman_decode(zbuf *a, zhuffman *z)
+{
+   int b,s,k;
+   if (a->num_bits < 16) fill_bits(a);
+   b = z->fast[a->code_buffer & ZFAST_MASK];
+   if (b < 0xffff) {
+      s = z->size[b];
+      a->code_buffer >>= s;
+      a->num_bits -= s;
+      return z->value[b];
+   }
+
+   // not resolved by fast table, so compute it the slow way
+   // use jpeg approach, which requires MSbits at top
+   k = bit_reverse(a->code_buffer, 16);
+   for (s=ZFAST_BITS+1; ; ++s)
+      if (k < z->maxcode[s])
+         break;
+   if (s == 16) return -1; // invalid code!
+   // code size is s, so:
+   b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s];
+   assert(z->size[b] == s);
+   a->code_buffer >>= s;
+   a->num_bits -= s;
+   return z->value[b];
+}
+
+static int expand(zbuf *z, int n)  // need to make room for n bytes
+{
+   char *q;
+   int cur, limit;
+   if (!z->z_expandable) return e("output buffer limit","Corrupt PNG");
+   cur   = (int) (z->zout     - z->zout_start);
+   limit = (int) (z->zout_end - z->zout_start);
+   while (cur + n > limit)
+      limit *= 2;
+   q = (char *) realloc(z->zout_start, limit);
+   if (q == NULL) return e("outofmem", "Out of memory");
+   z->zout_start = q;
+   z->zout       = q + cur;
+   z->zout_end   = q + limit;
+   return 1;
+}
+
+static int length_base[31] = {
+   3,4,5,6,7,8,9,10,11,13,
+   15,17,19,23,27,31,35,43,51,59,
+   67,83,99,115,131,163,195,227,258,0,0 };
+
+static int length_extra[31]= 
+{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
+
+static int dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,
+257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
+
+static int dist_extra[32] =
+{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+static int parse_huffman_block(zbuf *a)
+{
+   for(;;) {
+      int z = zhuffman_decode(a, &a->z_length);
+      if (z < 256) {
+         if (z < 0) return e("bad huffman code","Corrupt PNG"); // error in huffman codes
+         if (a->zout >= a->zout_end) if (!expand(a, 1)) return 0;
+         *a->zout++ = (char) z;
+      } else {
+         Uint8 *p;
+         int len,dist;
+         if (z == 256) return 1;
+         z -= 257;
+         len = length_base[z];
+         if (length_extra[z]) len += zreceive(a, length_extra[z]);
+         z = zhuffman_decode(a, &a->z_distance);
+         if (z < 0) return e("bad huffman code","Corrupt PNG");
+         dist = dist_base[z];
+         if (dist_extra[z]) dist += zreceive(a, dist_extra[z]);
+         if (a->zout - a->zout_start < dist) return e("bad dist","Corrupt PNG");
+         if (a->zout + len > a->zout_end) if (!expand(a, len)) return 0;
+         p = (Uint8 *) (a->zout - dist);
+         while (len--)
+            *a->zout++ = *p++;
+      }
+   }
+}
+
+static int compute_huffman_codes(zbuf *a)
+{
+   static Uint8 length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
+   zhuffman z_codelength;
+   Uint8 lencodes[286+32+137];//padding for maximum single op
+   Uint8 codelength_sizes[19];
+   int i,n;
+
+   int hlit  = zreceive(a,5) + 257;
+   int hdist = zreceive(a,5) + 1;
+   int hclen = zreceive(a,4) + 4;
+
+   memset(codelength_sizes, 0, sizeof(codelength_sizes));
+   for (i=0; i < hclen; ++i) {
+      int s = zreceive(a,3);
+      codelength_sizes[length_dezigzag[i]] = (Uint8) s;
+   }
+   if (!zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0;
+
+   n = 0;
+   while (n < hlit + hdist) {
+      int c = zhuffman_decode(a, &z_codelength);
+      assert(c >= 0 && c < 19);
+      if (c < 16)
+         lencodes[n++] = (Uint8) c;
+      else if (c == 16) {
+         c = zreceive(a,2)+3;
+         memset(lencodes+n, lencodes[n-1], c);
+         n += c;
+      } else if (c == 17) {
+         c = zreceive(a,3)+3;
+         memset(lencodes+n, 0, c);
+         n += c;
+      } else {
+         assert(c == 18);
+         c = zreceive(a,7)+11;
+         memset(lencodes+n, 0, c);
+         n += c;
+      }
+   }
+   if (n != hlit+hdist) return e("bad codelengths","Corrupt PNG");
+   if (!zbuild_huffman(&a->z_length, lencodes, hlit)) return 0;
+   if (!zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0;
+   return 1;
+}
+
+static int parse_uncompressed_block(zbuf *a)
+{
+   Uint8 header[4];
+   int len,nlen,k;
+   if (a->num_bits & 7)
+      zreceive(a, a->num_bits & 7); // discard
+   // drain the bit-packed data into header
+   k = 0;
+   while (a->num_bits > 0) {
+      header[k++] = (Uint8) (a->code_buffer & 255); // wtf this warns?
+      a->code_buffer >>= 8;
+      a->num_bits -= 8;
+   }
+   assert(a->num_bits == 0);
+   // now fill header the normal way
+   while (k < 4)
+      header[k++] = (Uint8) zget8(a);
+   len  = header[1] * 256 + header[0];
+   nlen = header[3] * 256 + header[2];
+   if (nlen != (len ^ 0xffff)) return e("zlib corrupt","Corrupt PNG");
+   if (a->zbuffer + len > a->zbuffer_end) return e("read past buffer","Corrupt PNG");
+   if (a->zout + len > a->zout_end)
+      if (!expand(a, len)) return 0;
+   memcpy(a->zout, a->zbuffer, len);
+   a->zbuffer += len;
+   a->zout += len;
+   return 1;
+}
+
+static int parse_zlib_header(zbuf *a)
+{
+   int cmf   = zget8(a);
+   int cm    = cmf & 15;
+   // int cinfo = cmf >> 4;
+   int flg   = zget8(a);
+   if ((cmf*256+flg) % 31 != 0) return e("bad zlib header","Corrupt PNG"); // zlib spec
+   if (flg & 32) return e("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png
+   if (cm != 8) return e("bad compression","Corrupt PNG"); // DEFLATE required for png
+   // window = 1 << (8 + cinfo)... but who cares, we fully buffer output
+   return 1;
+}
+
+// @TODO: should statically initialize these for optimal thread safety
+static Uint8 default_length[288], default_distance[32];
+static void init_defaults(void)
+{
+   int i;   // use <= to match clearly with spec
+   for (i=0; i <= 143; ++i)     default_length[i]   = 8;
+   for (   ; i <= 255; ++i)     default_length[i]   = 9;
+   for (   ; i <= 279; ++i)     default_length[i]   = 7;
+   for (   ; i <= 287; ++i)     default_length[i]   = 8;
+
+   for (i=0; i <=  31; ++i)     default_distance[i] = 5;
+}
+
+int stbi_png_partial; // a quick hack to only allow decoding some of a PNG... I should implement real streaming support instead
+static int parse_zlib(zbuf *a, int parse_header)
+{
+   int final, type;
+   if (parse_header)
+      if (!parse_zlib_header(a)) return 0;
+   a->num_bits = 0;
+   a->code_buffer = 0;
+   do {
+      final = zreceive(a,1);
+      type = zreceive(a,2);
+      if (type == 0) {
+         if (!parse_uncompressed_block(a)) return 0;
+      } else if (type == 3) {
+         return 0;
+      } else {
+         if (type == 1) {
+            // use fixed code lengths
+            if (!default_distance[31]) init_defaults();
+            if (!zbuild_huffman(&a->z_length  , default_length  , 288)) return 0;
+            if (!zbuild_huffman(&a->z_distance, default_distance,  32)) return 0;
+         } else {
+            if (!compute_huffman_codes(a)) return 0;
+         }
+         if (!parse_huffman_block(a)) return 0;
+      }
+      if (stbi_png_partial && a->zout - a->zout_start > 65536)
+         break;
+   } while (!final);
+   return 1;
+}
+
+static int do_zlib(zbuf *a, char *obuf, int olen, int exp, int parse_header)
+{
+   a->zout_start = obuf;
+   a->zout       = obuf;
+   a->zout_end   = obuf + olen;
+   a->z_expandable = exp;
+
+   return parse_zlib(a, parse_header);
+}
+
+char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen)
+{
+   zbuf a;
+   char *p = (char *) malloc(initial_size);
+   if (p == NULL) return NULL;
+   a.zbuffer = (Uint8 *) buffer;
+   a.zbuffer_end = (Uint8 *) buffer + len;
+   if (do_zlib(&a, p, initial_size, 1, 1)) {
+      if (outlen) *outlen = (int) (a.zout - a.zout_start);
+      return a.zout_start;
+   } else {
+      free(a.zout_start);
+      return NULL;
+   }
+}
+
+char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen)
+{
+   return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen);
+}
+
+char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header)
+{
+   zbuf a;
+   char *p = (char *) malloc(initial_size);
+   if (p == NULL) return NULL;
+   a.zbuffer = (Uint8 *) buffer;
+   a.zbuffer_end = (Uint8 *) buffer + len;
+   if (do_zlib(&a, p, initial_size, 1, parse_header)) {
+      if (outlen) *outlen = (int) (a.zout - a.zout_start);
+      return a.zout_start;
+   } else {
+      free(a.zout_start);
+      return NULL;
+   }
+}
+
+int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen)
+{
+   zbuf a;
+   a.zbuffer = (Uint8 *) ibuffer;
+   a.zbuffer_end = (Uint8 *) ibuffer + ilen;
+   if (do_zlib(&a, obuffer, olen, 0, 1))
+      return (int) (a.zout - a.zout_start);
+   else
+      return -1;
+}
+
+char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen)
+{
+   zbuf a;
+   char *p = (char *) malloc(16384);
+   if (p == NULL) return NULL;
+   a.zbuffer = (Uint8 *) buffer;
+   a.zbuffer_end = (Uint8 *) buffer+len;
+   if (do_zlib(&a, p, 16384, 1, 0)) {
+      if (outlen) *outlen = (int) (a.zout - a.zout_start);
+      return a.zout_start;
+   } else {
+      free(a.zout_start);
+      return NULL;
+   }
+}
+
+int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen)
+{
+   zbuf a;
+   a.zbuffer = (Uint8 *) ibuffer;
+   a.zbuffer_end = (Uint8 *) ibuffer + ilen;
+   if (do_zlib(&a, obuffer, olen, 0, 0))
+      return (int) (a.zout - a.zout_start);
+   else
+      return -1;
+}
+
+// public domain "baseline" PNG decoder   v0.10  Sean Barrett 2006-11-18
+//    simple implementation
+//      - only 8-bit samples
+//      - no CRC checking
+//      - allocates lots of intermediate memory
+//        - avoids problem of streaming data between subsystems
+//        - avoids explicit window management
+//    performance
+//      - uses stb_zlib, a PD zlib implementation with fast huffman decoding
+
+
+typedef struct
+{
+   Uint32 length;
+   Uint32 type;
+} chunk;
+
+#define PNG_TYPE(a,b,c,d)  (((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
+
+static chunk get_chunk_header(stbi *s)
+{
+   chunk c;
+   c.length = get32(s);
+   c.type   = get32(s);
+   return c;
+}
+
+static int check_png_header(stbi *s)
+{
+   static Uint8 png_sig[8] = { 137,80,78,71,13,10,26,10 };
+   int i;
+   for (i=0; i < 8; ++i)
+      if (get8u(s) != png_sig[i]) return e("bad png sig","Not a PNG");
+   return 1;
+}
+
+typedef struct
+{
+   stbi *s;
+   Uint8 *idata, *expanded, *out;
+} png;
+
+
+enum {
+   F_none=0, F_sub=1, F_up=2, F_avg=3, F_paeth=4,
+   F_avg_first, F_paeth_first
+};
+
+static Uint8 first_row_filter[5] =
+{
+   F_none, F_sub, F_none, F_avg_first, F_paeth_first
+};
+
+static int paeth(int a, int b, int c)
+{
+   int p = a + b - c;
+   int pa = abs(p-a);
+   int pb = abs(p-b);
+   int pc = abs(p-c);
+   if (pa <= pb && pa <= pc) return a;
+   if (pb <= pc) return b;
+   return c;
+}
+
+// create the png data from post-deflated data
+static int create_png_image_raw(png *a, Uint8 *raw, Uint32 raw_len, int out_n, Uint32 x, Uint32 y)
+{
+   stbi *s = a->s;
+   Uint32 i,j,stride = x*out_n;
+   int k;
+   int img_n = s->img_n; // copy it into a local for later
+   assert(out_n == s->img_n || out_n == s->img_n+1);
+   if (stbi_png_partial) y = 1;
+   a->out = (Uint8 *) malloc(x * y * out_n);
+   if (!a->out) return e("outofmem", "Out of memory");
+   if (!stbi_png_partial) {
+      if (s->img_x == x && s->img_y == y) {
+         if (raw_len != (img_n * x + 1) * y) return e("not enough pixels","Corrupt PNG");
+      } else { // interlaced:
+         if (raw_len < (img_n * x + 1) * y) return e("not enough pixels","Corrupt PNG");
+      }
+   }
+   for (j=0; j < y; ++j) {
+      Uint8 *cur = a->out + stride*j;
+      Uint8 *prior = cur - stride;
+      int filter = *raw++;
+      if (filter > 4) return e("invalid filter","Corrupt PNG");
+      // if first row, use special filter that doesn't sample previous row
+      if (j == 0) filter = first_row_filter[filter];
+      // handle first pixel explicitly
+      for (k=0; k < img_n; ++k) {
+         switch (filter) {
+            case F_none       : cur[k] = raw[k]; break;
+            case F_sub        : cur[k] = raw[k]; break;
+            case F_up         : cur[k] = raw[k] + prior[k]; break;
+            case F_avg        : cur[k] = raw[k] + (prior[k]>>1); break;
+            case F_paeth      : cur[k] = (Uint8) (raw[k] + paeth(0,prior[k],0)); break;
+            case F_avg_first  : cur[k] = raw[k]; break;
+            case F_paeth_first: cur[k] = raw[k]; break;
+         }
+      }
+      if (img_n != out_n) cur[img_n] = 255;
+      raw += img_n;
+      cur += out_n;
+      prior += out_n;
+      // this is a little gross, so that we don't switch per-pixel or per-component
+      if (img_n == out_n) {
+         #define CASE(f) \
+             case f:     \
+                for (i=x-1; i >= 1; --i, raw+=img_n,cur+=img_n,prior+=img_n) \
+                   for (k=0; k < img_n; ++k)
+         switch (filter) {
+            CASE(F_none)  cur[k] = raw[k]; break;
+            CASE(F_sub)   cur[k] = raw[k] + cur[k-img_n]; break;
+            CASE(F_up)    cur[k] = raw[k] + prior[k]; break;
+            CASE(F_avg)   cur[k] = raw[k] + ((prior[k] + cur[k-img_n])>>1); break;
+            CASE(F_paeth)  cur[k] = (Uint8) (raw[k] + paeth(cur[k-img_n],prior[k],prior[k-img_n])); break;
+            CASE(F_avg_first)    cur[k] = raw[k] + (cur[k-img_n] >> 1); break;
+            CASE(F_paeth_first)  cur[k] = (Uint8) (raw[k] + paeth(cur[k-img_n],0,0)); break;
+         }
+         #undef CASE
+      } else {
+         assert(img_n+1 == out_n);
+         #define CASE(f) \
+             case f:     \
+                for (i=x-1; i >= 1; --i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \
+                   for (k=0; k < img_n; ++k)
+         switch (filter) {
+            CASE(F_none)  cur[k] = raw[k]; break;
+            CASE(F_sub)   cur[k] = raw[k] + cur[k-out_n]; break;
+            CASE(F_up)    cur[k] = raw[k] + prior[k]; break;
+            CASE(F_avg)   cur[k] = raw[k] + ((prior[k] + cur[k-out_n])>>1); break;
+            CASE(F_paeth)  cur[k] = (Uint8) (raw[k] + paeth(cur[k-out_n],prior[k],prior[k-out_n])); break;
+            CASE(F_avg_first)    cur[k] = raw[k] + (cur[k-out_n] >> 1); break;
+            CASE(F_paeth_first)  cur[k] = (Uint8) (raw[k] + paeth(cur[k-out_n],0,0)); break;
+         }
+         #undef CASE
+      }
+   }
+   return 1;
+}
+
+static int create_png_image(png *a, Uint8 *raw, Uint32 raw_len, int out_n, int interlaced)
+{
+   Uint8 *final;
+   int p;
+   int save;
+   if (!interlaced)
+      return create_png_image_raw(a, raw, raw_len, out_n, a->s->img_x, a->s->img_y);
+   save = stbi_png_partial;
+   stbi_png_partial = 0;
+
+   // de-interlacing
+   final = (Uint8 *) malloc(a->s->img_x * a->s->img_y * out_n);
+   for (p=0; p < 7; ++p) {
+      int xorig[] = { 0,4,0,2,0,1,0 };
+      int yorig[] = { 0,0,4,0,2,0,1 };
+      int xspc[]  = { 8,8,4,4,2,2,1 };
+      int yspc[]  = { 8,8,8,4,4,2,2 };
+      int i,j,x,y;
+      // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1
+      x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p];
+      y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p];
+      if (x && y) {
+         if (!create_png_image_raw(a, raw, raw_len, out_n, x, y)) {
+            free(final);
+            return 0;
+         }
+         for (j=0; j < y; ++j)
+            for (i=0; i < x; ++i)
+               memcpy(final + (j*yspc[p]+yorig[p])*a->s->img_x*out_n + (i*xspc[p]+xorig[p])*out_n,
+                      a->out + (j*x+i)*out_n, out_n);
+         free(a->out);
+         raw += (x*out_n+1)*y;
+         raw_len -= (x*out_n+1)*y;
+      }
+   }
+   a->out = final;
+
+   stbi_png_partial = save;
+   return 1;
+}
+
+static int compute_transparency(png *z, Uint8 tc[3], int out_n)
+{
+   stbi *s = z->s;
+   Uint32 i, pixel_count = s->img_x * s->img_y;
+   Uint8 *p = z->out;
+
+   // compute color-based transparency, assuming we've
+   // already got 255 as the alpha value in the output
+   assert(out_n == 2 || out_n == 4);
+
+   if (out_n == 2) {
+      for (i=0; i < pixel_count; ++i) {
+         p[1] = (p[0] == tc[0] ? 0 : 255);
+         p += 2;
+      }
+   } else {
+      for (i=0; i < pixel_count; ++i) {
+         if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
+            p[3] = 0;
+         p += 4;
+      }
+   }
+   return 1;
+}
+
+static int expand_palette(png *a, Uint8 *palette, int len, int pal_img_n)
+{
+   Uint32 i, pixel_count = a->s->img_x * a->s->img_y;
+   Uint8 *p, *temp_out, *orig = a->out;
+
+   p = (Uint8 *) malloc(pixel_count * pal_img_n);
+   if (p == NULL) return e("outofmem", "Out of memory");
+
+   // between here and free(out) below, exitting would leak
+   temp_out = p;
+
+   if (pal_img_n == 3) {
+      for (i=0; i < pixel_count; ++i) {
+         int n = orig[i]*4;
+         p[0] = palette[n  ];
+         p[1] = palette[n+1];
+         p[2] = palette[n+2];
+         p += 3;
+      }
+   } else {
+      for (i=0; i < pixel_count; ++i) {
+         int n = orig[i]*4;
+         p[0] = palette[n  ];
+         p[1] = palette[n+1];
+         p[2] = palette[n+2];
+         p[3] = palette[n+3];
+         p += 4;
+      }
+   }
+   free(a->out);
+   a->out = temp_out;
+
+   STBI_NOTUSED(len);
+
+   return 1;
+}
+
+static int stbi_unpremultiply_on_load = 0;
+static int stbi_de_iphone_flag = 0;
+
+void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply)
+{
+   stbi_unpremultiply_on_load = flag_true_if_should_unpremultiply;
+}
+void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)
+{
+   stbi_de_iphone_flag = flag_true_if_should_convert;
+}
+
+static void stbi_de_iphone(png *z)
+{
+   stbi *s = z->s;
+   Uint32 i, pixel_count = s->img_x * s->img_y;
+   Uint8 *p = z->out;
+
+   if (s->img_out_n == 3) {  // convert bgr to rgb
+      for (i=0; i < pixel_count; ++i) {
+         Uint8 t = p[0];
+         p[0] = p[2];
+         p[2] = t;
+         p += 3;
+      }
+   } else {
+      assert(s->img_out_n == 4);
+      if (stbi_unpremultiply_on_load) {
+         // convert bgr to rgb and unpremultiply
+         for (i=0; i < pixel_count; ++i) {
+            Uint8 a = p[3];
+            Uint8 t = p[0];
+            if (a) {
+               p[0] = p[2] * 255 / a;
+               p[1] = p[1] * 255 / a;
+               p[2] =  t   * 255 / a;
+            } else {
+               p[0] = p[2];
+               p[2] = t;
+            } 
+            p += 4;
+         }
+      } else {
+         // convert bgr to rgb
+         for (i=0; i < pixel_count; ++i) {
+            Uint8 t = p[0];
+            p[0] = p[2];
+            p[2] = t;
+            p += 4;
+         }
+      }
+   }
+}
+
+static int parse_png_file(png *z, int scan, int req_comp)
+{
+   Uint8 palette[1024], pal_img_n=0;
+   Uint8 has_trans=0, tc[3];
+   Uint32 ioff=0, idata_limit=0, i, pal_len=0;
+   int first=1,k,interlace=0, iphone=0;
+   stbi *s = z->s;
+
+   z->expanded = NULL;
+   z->idata = NULL;
+   z->out = NULL;
+
+   if (!check_png_header(s)) return 0;
+
+   if (scan == SCAN_type) return 1;
+
+   for (;;) {
+      chunk c = get_chunk_header(s);
+      switch (c.type) {
+         case PNG_TYPE('C','g','B','I'):
+            iphone = stbi_de_iphone_flag;
+            skip(s, c.length);
+            break;
+         case PNG_TYPE('I','H','D','R'): {
+            int depth,color,comp,filter;
+            if (!first) return e("multiple IHDR","Corrupt PNG");
+            first = 0;
+            if (c.length != 13) return e("bad IHDR len","Corrupt PNG");
+            s->img_x = get32(s); if (s->img_x > (1 << 24)) return e("too large","Very large image (corrupt?)");
+            s->img_y = get32(s); if (s->img_y > (1 << 24)) return e("too large","Very large image (corrupt?)");
+            depth = get8(s);  if (depth != 8)        return e("8bit only","PNG not supported: 8-bit only");
+            color = get8(s);  if (color > 6)         return e("bad ctype","Corrupt PNG");
+            if (color == 3) pal_img_n = 3; else if (color & 1) return e("bad ctype","Corrupt PNG");
+            comp  = get8(s);  if (comp) return e("bad comp method","Corrupt PNG");
+            filter= get8(s);  if (filter) return e("bad filter method","Corrupt PNG");
+            interlace = get8(s); if (interlace>1) return e("bad interlace method","Corrupt PNG");
+            if (!s->img_x || !s->img_y) return e("0-pixel image","Corrupt PNG");
+            if (!pal_img_n) {
+               s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);
+               if ((1 << 30) / s->img_x / s->img_n < s->img_y) return e("too large", "Image too large to decode");
+               if (scan == SCAN_header) return 1;
+            } else {
+               // if paletted, then pal_n is our final components, and
+               // img_n is # components to decompress/filter.
+               s->img_n = 1;
+               if ((1 << 30) / s->img_x / 4 < s->img_y) return e("too large","Corrupt PNG");
+               // if SCAN_header, have to scan to see if we have a tRNS
+            }
+            break;
+         }
+
+         case PNG_TYPE('P','L','T','E'):  {
+            if (first) return e("first not IHDR", "Corrupt PNG");
+            if (c.length > 256*3) return e("invalid PLTE","Corrupt PNG");
+            pal_len = c.length / 3;
+            if (pal_len * 3 != c.length) return e("invalid PLTE","Corrupt PNG");
+            for (i=0; i < pal_len; ++i) {
+               palette[i*4+0] = get8u(s);
+               palette[i*4+1] = get8u(s);
+               palette[i*4+2] = get8u(s);
+               palette[i*4+3] = 255;
+            }
+            break;
+         }
+
+         case PNG_TYPE('t','R','N','S'): {
+            if (first) return e("first not IHDR", "Corrupt PNG");
+            if (z->idata) return e("tRNS after IDAT","Corrupt PNG");
+            if (pal_img_n) {
+               if (scan == SCAN_header) { s->img_n = 4; return 1; }
+               if (pal_len == 0) return e("tRNS before PLTE","Corrupt PNG");
+               if (c.length > pal_len) return e("bad tRNS len","Corrupt PNG");
+               pal_img_n = 4;
+               for (i=0; i < c.length; ++i)
+                  palette[i*4+3] = get8u(s);
+            } else {
+               if (!(s->img_n & 1)) return e("tRNS with alpha","Corrupt PNG");
+               if (c.length != (Uint32) s->img_n*2) return e("bad tRNS len","Corrupt PNG");
+               has_trans = 1;
+               for (k=0; k < s->img_n; ++k)
+                  tc[k] = (Uint8) get16(s); // non 8-bit images will be larger
+            }
+            break;
+         }
+
+         case PNG_TYPE('I','D','A','T'): {
+            if (first) return e("first not IHDR", "Corrupt PNG");
+            if (pal_img_n && !pal_len) return e("no PLTE","Corrupt PNG");
+            if (scan == SCAN_header) { s->img_n = pal_img_n; return 1; }
+            if (ioff + c.length > idata_limit) {
+               Uint8 *p;
+               if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;
+               while (ioff + c.length > idata_limit)
+                  idata_limit *= 2;
+               p = (Uint8 *) realloc(z->idata, idata_limit); if (p == NULL) return e("outofmem", "Out of memory");
+               z->idata = p;
+            }
+            if (!getn(s, z->idata+ioff,c.length)) return e("outofdata","Corrupt PNG");
+            ioff += c.length;
+            break;
+         }
+
+         case PNG_TYPE('I','E','N','D'): {
+            Uint32 raw_len;
+            if (first) return e("first not IHDR", "Corrupt PNG");
+            if (scan != SCAN_load) return 1;
+            if (z->idata == NULL) return e("no IDAT","Corrupt PNG");
+            z->expanded = (Uint8 *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, 16384, (int *) &raw_len, !iphone);
+            if (z->expanded == NULL) return 0; // zlib should set error
+            free(z->idata); z->idata = NULL;
+            if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans)
+               s->img_out_n = s->img_n+1;
+            else
+               s->img_out_n = s->img_n;
+            if (!create_png_image(z, z->expanded, raw_len, s->img_out_n, interlace)) return 0;
+            if (has_trans)
+               if (!compute_transparency(z, tc, s->img_out_n)) return 0;
+            if (iphone && s->img_out_n > 2)
+               stbi_de_iphone(z);
+            if (pal_img_n) {
+               // pal_img_n == 3 or 4
+               s->img_n = pal_img_n; // record the actual colors we had
+               s->img_out_n = pal_img_n;
+               if (req_comp >= 3) s->img_out_n = req_comp;
+               if (!expand_palette(z, palette, pal_len, s->img_out_n))
+                  return 0;
+            }
+            free(z->expanded); z->expanded = NULL;
+            return 1;
+         }
+
+         default:
+            // if critical, fail
+            if (first) return e("first not IHDR", "Corrupt PNG");
+            if ((c.type & (1 << 29)) == 0) {
+               #if !defined(STBI_NO_FAILURE_STRINGS) && !defined(STBI_FAILURE_USERMSG)
+               // not threadsafe
+               static char invalid_chunk[] = "XXXX chunk not known";
+               invalid_chunk[0] = (Uint8) (c.type >> 24);
+               invalid_chunk[1] = (Uint8) (c.type >> 16);
+               invalid_chunk[2] = (Uint8) (c.type >>  8);
+               invalid_chunk[3] = (Uint8) (c.type >>  0);
+               #endif
+               return e(invalid_chunk, "PNG not supported: unknown chunk type");
+            }
+            skip(s, c.length);
+            break;
+      }
+      // end of chunk, read and skip CRC
+      get32(s);
+   }
+}
+
+static unsigned char *do_png(png *p, int *x, int *y, int *n, int req_comp)
+{
+   unsigned char *result=NULL;
+   if (req_comp < 0 || req_comp > 4) return epuc("bad req_comp", "Internal error");
+   if (parse_png_file(p, SCAN_load, req_comp)) {
+      result = p->out;
+      p->out = NULL;
+      if (req_comp && req_comp != p->s->img_out_n) {
+         result = convert_format(result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
+         p->s->img_out_n = req_comp;
+         if (result == NULL) return result;
+      }
+      *x = p->s->img_x;
+      *y = p->s->img_y;
+      if (n) *n = p->s->img_n;
+   }
+   free(p->out);      p->out      = NULL;
+   free(p->expanded); p->expanded = NULL;
+   free(p->idata);    p->idata    = NULL;
+
+   return result;
+}
+
+static unsigned char *stbi_png_load(stbi *s, int *x, int *y, int *comp, int req_comp)
+{
+   png p;
+   p.s = s;
+   return do_png(&p, x,y,comp,req_comp);
+}
+
+static int stbi_png_test(stbi *s)
+{
+   int r;
+   r = check_png_header(s);
+   stbi_rewind(s);
+   return r;
+}
+
+static int stbi_png_info_raw(png *p, int *x, int *y, int *comp)
+{
+   if (!parse_png_file(p, SCAN_header, 0)) {
+      stbi_rewind( p->s );
+      return 0;
+   }
+   if (x) *x = p->s->img_x;
+   if (y) *y = p->s->img_y;
+   if (comp) *comp = p->s->img_n;
+   return 1;
+}
+
+static int      stbi_png_info(stbi *s, int *x, int *y, int *comp)
+{
+   png p;
+   p.s = s;
+   return stbi_png_info_raw(&p, x, y, comp);
+}
+
+#ifdef STBI_CRAP_FORMATS
+
+// Microsoft/Windows BMP image
+
+static int bmp_test(stbi *s)
+{
+   int sz;
+   if (get8(s) != 'B') return 0;
+   if (get8(s) != 'M') return 0;
+   get32le(s); // discard filesize
+   get16le(s); // discard reserved
+   get16le(s); // discard reserved
+   get32le(s); // discard data offset
+   sz = get32le(s);
+   if (sz == 12 || sz == 40 || sz == 56 || sz == 108) return 1;
+   return 0;
+}
+
+static int stbi_bmp_test(stbi *s)
+{
+   int r = bmp_test(s);
+   stbi_rewind(s);
+   return r;
+}
+
+
+// returns 0..31 for the highest set bit
+static int high_bit(unsigned int z)
+{
+   int n=0;
+   if (z == 0) return -1;
+   if (z >= 0x10000) n += 16, z >>= 16;
+   if (z >= 0x00100) n +=  8, z >>=  8;
+   if (z >= 0x00010) n +=  4, z >>=  4;
+   if (z >= 0x00004) n +=  2, z >>=  2;
+   if (z >= 0x00002) n +=  1, z >>=  1;
+   return n;
+}
+
+static int bitcount(unsigned int a)
+{
+   a = (a & 0x55555555) + ((a >>  1) & 0x55555555); // max 2
+   a = (a & 0x33333333) + ((a >>  2) & 0x33333333); // max 4
+   a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits
+   a = (a + (a >> 8)); // max 16 per 8 bits
+   a = (a + (a >> 16)); // max 32 per 8 bits
+   return a & 0xff;
+}
+
+static int shiftsigned(int v, int shift, int bits)
+{
+   int result;
+   int z=0;
+
+   if (shift < 0) v <<= -shift;
+   else v >>= shift;
+   result = v;
+
+   z = bits;
+   while (z < 8) {
+      result += v >> z;
+      z += bits;
+   }
+   return result;
+}
+
+static stbi_uc *bmp_load(stbi *s, int *x, int *y, int *comp, int req_comp)
+{
+   Uint8 *out;
+   unsigned int mr=0,mg=0,mb=0,ma=0, fake_a=0;
+   stbi_uc pal[256][4];
+   int psize=0,i,j,compress=0,width;
+   int bpp, flip_vertically, pad, target, offset, hsz;
+   if (get8(s) != 'B' || get8(s) != 'M') return epuc("not BMP", "Corrupt BMP");
+   get32le(s); // discard filesize
+   get16le(s); // discard reserved
+   get16le(s); // discard reserved
+   offset = get32le(s);
+   hsz = get32le(s);
+   if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108) return epuc("unknown BMP", "BMP type not supported: unknown");
+   if (hsz == 12) {
+      s->img_x = get16le(s);
+      s->img_y = get16le(s);
+   } else {
+      s->img_x = get32le(s);
+      s->img_y = get32le(s);
+   }
+   if (get16le(s) != 1) return epuc("bad BMP", "bad BMP");
+   bpp = get16le(s);
+   if (bpp == 1) return epuc("monochrome", "BMP type not supported: 1-bit");
+   flip_vertically = ((int) s->img_y) > 0;
+   s->img_y = abs((int) s->img_y);
+   if (hsz == 12) {
+      if (bpp < 24)
+         psize = (offset - 14 - 24) / 3;
+   } else {
+      compress = get32le(s);
+      if (compress == 1 || compress == 2) return epuc("BMP RLE", "BMP type not supported: RLE");
+      get32le(s); // discard sizeof
+      get32le(s); // discard hres
+      get32le(s); // discard vres
+      get32le(s); // discard colorsused
+      get32le(s); // discard max important
+      if (hsz == 40 || hsz == 56) {
+         if (hsz == 56) {
+            get32le(s);
+            get32le(s);
+            get32le(s);
+            get32le(s);
+         }
+         if (bpp == 16 || bpp == 32) {
+            mr = mg = mb = 0;
+            if (compress == 0) {
+               if (bpp == 32) {
+                  mr = 0xffu << 16;
+                  mg = 0xffu <<  8;
+                  mb = 0xffu <<  0;
+                  ma = 0xffu << 24;
+                  fake_a = 1; // @TODO: check for cases like alpha value is all 0 and switch it to 255
+               } else {
+                  mr = 31u << 10;
+                  mg = 31u <<  5;
+                  mb = 31u <<  0;
+               }
+            } else if (compress == 3) {
+               mr = get32le(s);
+               mg = get32le(s);
+               mb = get32le(s);
+               // not documented, but generated by photoshop and handled by mspaint
+               if (mr == mg && mg == mb) {
+                  // ?!?!?
+                  return epuc("bad BMP", "bad BMP");
+               }
+            } else
+               return epuc("bad BMP", "bad BMP");
+         }
+      } else {
+         assert(hsz == 108);
+         mr = get32le(s);
+         mg = get32le(s);
+         mb = get32le(s);
+         ma = get32le(s);
+         get32le(s); // discard color space
+         for (i=0; i < 12; ++i)
+            get32le(s); // discard color space parameters
+      }
+      if (bpp < 16)
+         psize = (offset - 14 - hsz) >> 2;
+   }
+   s->img_n = ma ? 4 : 3;
+   if (req_comp && req_comp >= 3) // we can directly decode 3 or 4
+      target = req_comp;
+   else
+      target = s->img_n; // if they want monochrome, we'll post-convert
+   out = (stbi_uc *) malloc(target * s->img_x * s->img_y);
+   if (!out) return epuc("outofmem", "Out of memory");
+   if (bpp < 16) {
+      int z=0;
+      if (psize == 0 || psize > 256) { free(out); return epuc("invalid", "Corrupt BMP"); }
+      for (i=0; i < psize; ++i) {
+         pal[i][2] = get8u(s);
+         pal[i][1] = get8u(s);
+         pal[i][0] = get8u(s);
+         if (hsz != 12) get8(s);
+         pal[i][3] = 255;
+      }
+      skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4));
+      if (bpp == 4) width = (s->img_x + 1) >> 1;
+      else if (bpp == 8) width = s->img_x;
+      else { free(out); return epuc("bad bpp", "Corrupt BMP"); }
+      pad = (-width)&3;
+      for (j=0; j < (int) s->img_y; ++j) {
+         for (i=0; i < (int) s->img_x; i += 2) {
+            int v=get8(s),v2=0;
+            if (bpp == 4) {
+               v2 = v & 15;
+               v >>= 4;
+            }
+            out[z++] = pal[v][0];
+            out[z++] = pal[v][1];
+            out[z++] = pal[v][2];
+            if (target == 4) out[z++] = 255;
+            if (i+1 == (int) s->img_x) break;
+            v = (bpp == 8) ? get8(s) : v2;
+            out[z++] = pal[v][0];
+            out[z++] = pal[v][1];
+            out[z++] = pal[v][2];
+            if (target == 4) out[z++] = 255;
+         }
+         skip(s, pad);
+      }
+   } else {
+      int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;
+      int z = 0;
+      int easy=0;
+      skip(s, offset - 14 - hsz);
+      if (bpp == 24) width = 3 * s->img_x;
+      else if (bpp == 16) width = 2*s->img_x;
+      else /* bpp = 32 and pad = 0 */ width=0;
+      pad = (-width) & 3;
+      if (bpp == 24) {
+         easy = 1;
+      } else if (bpp == 32) {
+         if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)
+            easy = 2;
+      }
+      if (!easy) {
+         if (!mr || !mg || !mb) { free(out); return epuc("bad masks", "Corrupt BMP"); }
+         // right shift amt to put high bit in position #7
+         rshift = high_bit(mr)-7; rcount = bitcount(mr);
+         gshift = high_bit(mg)-7; gcount = bitcount(mr);
+         bshift = high_bit(mb)-7; bcount = bitcount(mr);
+         ashift = high_bit(ma)-7; acount = bitcount(mr);
+      }
+      for (j=0; j < (int) s->img_y; ++j) {
+         if (easy) {
+            for (i=0; i < (int) s->img_x; ++i) {
+               int a;
+               out[z+2] = get8u(s);
+               out[z+1] = get8u(s);
+               out[z+0] = get8u(s);
+               z += 3;
+               a = (easy == 2 ? get8(s) : 255);
+               if (target == 4) out[z++] = (Uint8) a;
+            }
+         } else {
+            for (i=0; i < (int) s->img_x; ++i) {
+               Uint32 v = (bpp == 16 ? get16le(s) : get32le(s));
+               int a;
+               out[z++] = (Uint8) shiftsigned(v & mr, rshift, rcount);
+               out[z++] = (Uint8) shiftsigned(v & mg, gshift, gcount);
+               out[z++] = (Uint8) shiftsigned(v & mb, bshift, bcount);
+               a = (ma ? shiftsigned(v & ma, ashift, acount) : 255);
+               if (target == 4) out[z++] = (Uint8) a; 
+            }
+         }
+         skip(s, pad);
+      }
+   }
+   if (flip_vertically) {
+      stbi_uc t;
+      for (j=0; j < (int) s->img_y>>1; ++j) {
+         stbi_uc *p1 = out +      j     *s->img_x*target;
+         stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target;
+         for (i=0; i < (int) s->img_x*target; ++i) {
+            t = p1[i], p1[i] = p2[i], p2[i] = t;
+         }
+      }
+   }
+
+   if (req_comp && req_comp != target) {
+      out = convert_format(out, target, req_comp, s->img_x, s->img_y);
+      if (out == NULL) return out; // convert_format frees input on failure
+   }
+
+   *x = s->img_x;
+   *y = s->img_y;
+   if (comp) *comp = s->img_n;
+   return out;
+}
+
+static stbi_uc *stbi_bmp_load(stbi *s,int *x, int *y, int *comp, int req_comp)
+{
+   return bmp_load(s, x,y,comp,req_comp);
+}
+
+
+// Targa Truevision - TGA
+// by Jonathan Dummer
+
+static int tga_info(stbi *s, int *x, int *y, int *comp)
+{
+    int tga_w, tga_h, tga_comp;
+    int sz;
+    get8u(s);                   // discard Offset
+    sz = get8u(s);              // color type
+    if( sz > 1 ) {
+        stbi_rewind(s);
+        return 0;      // only RGB or indexed allowed
+    }
+    sz = get8u(s);              // image type
+    // only RGB or grey allowed, +/- RLE
+    if ((sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11)) return 0;
+    skip(s,9);
+    tga_w = get16le(s);
+    if( tga_w < 1 ) {
+        stbi_rewind(s);
+        return 0;   // test width
+    }
+    tga_h = get16le(s);
+    if( tga_h < 1 ) {
+        stbi_rewind(s);
+        return 0;   // test height
+    }
+    sz = get8(s);               // bits per pixel
+    // only RGB or RGBA or grey allowed
+    if ((sz != 8) && (sz != 16) && (sz != 24) && (sz != 32)) {
+        stbi_rewind(s);
+        return 0;
+    }
+    tga_comp = sz;
+    if (x) *x = tga_w;
+    if (y) *y = tga_h;
+    if (comp) *comp = tga_comp / 8;
+    return 1;                   // seems to have passed everything
+}
+
+int stbi_tga_info(stbi *s, int *x, int *y, int *comp)
+{
+    return tga_info(s, x, y, comp);
+}
+
+static int tga_test(stbi *s)
+{
+   int sz;
+   get8u(s);      //   discard Offset
+   sz = get8u(s);   //   color type
+   if ( sz > 1 ) return 0;   //   only RGB or indexed allowed
+   sz = get8u(s);   //   image type
+   if ( (sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11) ) return 0;   //   only RGB or grey allowed, +/- RLE
+   get16(s);      //   discard palette start
+   get16(s);      //   discard palette length
+   get8(s);         //   discard bits per palette color entry
+   get16(s);      //   discard x origin
+   get16(s);      //   discard y origin
+   if ( get16(s) < 1 ) return 0;      //   test width
+   if ( get16(s) < 1 ) return 0;      //   test height
+   sz = get8(s);   //   bits per pixel
+   if ( (sz != 8) && (sz != 16) && (sz != 24) && (sz != 32) ) return 0;   //   only RGB or RGBA or grey allowed
+   return 1;      //   seems to have passed everything
+}
+
+static int stbi_tga_test(stbi *s)
+{
+   int res = tga_test(s);
+   stbi_rewind(s);
+   return res;
+}
+
+static stbi_uc *tga_load(stbi *s, int *x, int *y, int *comp, int req_comp)
+{
+   //   read in the TGA header stuff
+   int tga_offset = get8u(s);
+   int tga_indexed = get8u(s);
+   int tga_image_type = get8u(s);
+   int tga_is_RLE = 0;
+   int tga_palette_start = get16le(s);
+   int tga_palette_len = get16le(s);
+   int tga_palette_bits = get8u(s);
+   int tga_x_origin = get16le(s);
+   int tga_y_origin = get16le(s);
+   int tga_width = get16le(s);
+   int tga_height = get16le(s);
+   int tga_bits_per_pixel = get8u(s);
+   int tga_inverted = get8u(s);
+   //   image data
+   unsigned char *tga_data;
+   unsigned char *tga_palette = NULL;
+   int i, j;
+   unsigned char raw_data[4];
+   unsigned char trans_data[4];
+   int RLE_count = 0;
+   int RLE_repeating = 0;
+   int read_next_pixel = 1;
+
+   //   do a tiny bit of precessing
+   if ( tga_image_type >= 8 )
+   {
+      tga_image_type -= 8;
+      tga_is_RLE = 1;
+   }
+   // int tga_alpha_bits = tga_inverted & 15;
+   tga_inverted = 1 - ((tga_inverted >> 5) & 1);
+
+   //   error check
+   if ( //(tga_indexed) ||
+      (tga_width < 1) || (tga_height < 1) ||
+      (tga_image_type < 1) || (tga_image_type > 3) ||
+      ((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16) &&
+      (tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32))
+      )
+   {
+      return NULL; // we don't report this as a bad TGA because we don't even know if it's TGA
+   }
+
+   //   If I'm paletted, then I'll use the number of bits from the palette
+   if ( tga_indexed )
+   {
+      tga_bits_per_pixel = tga_palette_bits;
+   }
+
+   //   tga info
+   *x = tga_width;
+   *y = tga_height;
+   if ( (req_comp < 1) || (req_comp > 4) )
+   {
+      //   just use whatever the file was
+      req_comp = tga_bits_per_pixel / 8;
+      *comp = req_comp;
+   } else
+   {
+      //   force a new number of components
+      *comp = tga_bits_per_pixel/8;
+   }
+   tga_data = (unsigned char*)malloc( tga_width * tga_height * req_comp );
+   if (!tga_data) return epuc("outofmem", "Out of memory");
+
+   //   skip to the data's starting position (offset usually = 0)
+   skip(s, tga_offset );
+   //   do I need to load a palette?
+   if ( tga_indexed )
+   {
+      //   any data to skip? (offset usually = 0)
+      skip(s, tga_palette_start );
+      //   load the palette
+      tga_palette = (unsigned char*)malloc( tga_palette_len * tga_palette_bits / 8 );
+      if (!tga_palette) return epuc("outofmem", "Out of memory");
+      if (!getn(s, tga_palette, tga_palette_len * tga_palette_bits / 8 )) {
+         free(tga_data);
+         free(tga_palette);
+         return epuc("bad palette", "Corrupt TGA");
+      }
+   }
+   //   load the data
+   trans_data[0] = trans_data[1] = trans_data[2] = trans_data[3] = 0;
+   for (i=0; i < tga_width * tga_height; ++i)
+   {
+      //   if I'm in RLE mode, do I need to get a RLE chunk?
+      if ( tga_is_RLE )
+      {
+         if ( RLE_count == 0 )
+         {
+            //   yep, get the next byte as a RLE command
+            int RLE_cmd = get8u(s);
+            RLE_count = 1 + (RLE_cmd & 127);
+            RLE_repeating = RLE_cmd >> 7;
+            read_next_pixel = 1;
+         } else if ( !RLE_repeating )
+         {
+            read_next_pixel = 1;
+         }
+      } else
+      {
+         read_next_pixel = 1;
+      }
+      //   OK, if I need to read a pixel, do it now
+      if ( read_next_pixel )
+      {
+         //   load however much data we did have
+         if ( tga_indexed )
+         {
+            //   read in 1 byte, then perform the lookup
+            int pal_idx = get8u(s);
+            if ( pal_idx >= tga_palette_len )
+            {
+               //   invalid index
+               pal_idx = 0;
+            }
+            pal_idx *= tga_bits_per_pixel / 8;
+            for (j = 0; j*8 < tga_bits_per_pixel; ++j)
+            {
+               raw_data[j] = tga_palette[pal_idx+j];
+            }
+         } else
+         {
+            //   read in the data raw
+            for (j = 0; j*8 < tga_bits_per_pixel; ++j)
+            {
+               raw_data[j] = get8u(s);
+            }
+         }
+         //   convert raw to the intermediate format
+         switch (tga_bits_per_pixel)
+         {
+         case 8:
+            //   Luminous => RGBA
+            trans_data[0] = raw_data[0];
+            trans_data[1] = raw_data[0];
+            trans_data[2] = raw_data[0];
+            trans_data[3] = 255;
+            break;
+         case 16:
+            //   Luminous,Alpha => RGBA
+            trans_data[0] = raw_data[0];
+            trans_data[1] = raw_data[0];
+            trans_data[2] = raw_data[0];
+            trans_data[3] = raw_data[1];
+            break;
+         case 24:
+            //   BGR => RGBA
+            trans_data[0] = raw_data[2];
+            trans_data[1] = raw_data[1];
+            trans_data[2] = raw_data[0];
+            trans_data[3] = 255;
+            break;
+         case 32:
+            //   BGRA => RGBA
+            trans_data[0] = raw_data[2];
+            trans_data[1] = raw_data[1];
+            trans_data[2] = raw_data[0];
+            trans_data[3] = raw_data[3];
+            break;
+         }
+         //   clear the reading flag for the next pixel
+         read_next_pixel = 0;
+      } // end of reading a pixel
+      //   convert to final format
+      switch (req_comp)
+      {
+      case 1:
+         //   RGBA => Luminance
+         tga_data[i*req_comp+0] = compute_y(trans_data[0],trans_data[1],trans_data[2]);
+         break;
+      case 2:
+         //   RGBA => Luminance,Alpha
+         tga_data[i*req_comp+0] = compute_y(trans_data[0],trans_data[1],trans_data[2]);
+         tga_data[i*req_comp+1] = trans_data[3];
+         break;
+      case 3:
+         //   RGBA => RGB
+         tga_data[i*req_comp+0] = trans_data[0];
+         tga_data[i*req_comp+1] = trans_data[1];
+         tga_data[i*req_comp+2] = trans_data[2];
+         break;
+      case 4:
+         //   RGBA => RGBA
+         tga_data[i*req_comp+0] = trans_data[0];
+         tga_data[i*req_comp+1] = trans_data[1];
+         tga_data[i*req_comp+2] = trans_data[2];
+         tga_data[i*req_comp+3] = trans_data[3];
+         break;
+      }
+      //   in case we're in RLE mode, keep counting down
+      --RLE_count;
+   }
+   //   do I need to invert the image?
+   if ( tga_inverted )
+   {
+      for (j = 0; j*2 < tga_height; ++j)
+      {
+         int index1 = j * tga_width * req_comp;
+         int index2 = (tga_height - 1 - j) * tga_width * req_comp;
+         for (i = tga_width * req_comp; i > 0; --i)
+         {
+            unsigned char temp = tga_data[index1];
+            tga_data[index1] = tga_data[index2];
+            tga_data[index2] = temp;
+            ++index1;
+            ++index2;
+         }
+      }
+   }
+   //   clear my palette, if I had one
+   if ( tga_palette != NULL )
+   {
+      free( tga_palette );
+   }
+   //   the things I do to get rid of an error message, and yet keep
+   //   Microsoft's C compilers happy... [8^(
+   tga_palette_start = tga_palette_len = tga_palette_bits =
+         tga_x_origin = tga_y_origin = 0;
+   //   OK, done
+   return tga_data;
+}
+
+static stbi_uc *stbi_tga_load(stbi *s, int *x, int *y, int *comp, int req_comp)
+{
+   return tga_load(s,x,y,comp,req_comp);
+}
+
+
+// *************************************************************************************************
+// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB
+
+static int psd_test(stbi *s)
+{
+   if (get32(s) != 0x38425053) return 0;   // "8BPS"
+   else return 1;
+}
+
+static int stbi_psd_test(stbi *s)
+{
+   int r = psd_test(s);
+   stbi_rewind(s);
+   return r;
+}
+
+static stbi_uc *psd_load(stbi *s, int *x, int *y, int *comp, int req_comp)
+{
+   int   pixelCount;
+   int channelCount, compression;
+   int channel, i, count, len;
+   int w,h;
+   Uint8 *out;
+
+   // Check identifier
+   if (get32(s) != 0x38425053)   // "8BPS"
+      return epuc("not PSD", "Corrupt PSD image");
+
+   // Check file type version.
+   if (get16(s) != 1)
+      return epuc("wrong version", "Unsupported version of PSD image");
+
+   // Skip 6 reserved bytes.
+   skip(s, 6 );
+
+   // Read the number of channels (R, G, B, A, etc).
+   channelCount = get16(s);
+   if (channelCount < 0 || channelCount > 16)
+      return epuc("wrong channel count", "Unsupported number of channels in PSD image");
+
+   // Read the rows and columns of the image.
+   h = get32(s);
+   w = get32(s);
+   
+   // Make sure the depth is 8 bits.
+   if (get16(s) != 8)
+      return epuc("unsupported bit depth", "PSD bit depth is not 8 bit");
+
+   // Make sure the color mode is RGB.
+   // Valid options are:
+   //   0: Bitmap
+   //   1: Grayscale
+   //   2: Indexed color
+   //   3: RGB color
+   //   4: CMYK color
+   //   7: Multichannel
+   //   8: Duotone
+   //   9: Lab color
+   if (get16(s) != 3)
+      return epuc("wrong color format", "PSD is not in RGB color format");
+
+   // Skip the Mode Data.  (It's the palette for indexed color; other info for other modes.)
+   skip(s,get32(s) );
+
+   // Skip the image resources.  (resolution, pen tool paths, etc)
+   skip(s, get32(s) );
+
+   // Skip the reserved data.
+   skip(s, get32(s) );
+
+   // Find out if the data is compressed.
+   // Known values:
+   //   0: no compression
+   //   1: RLE compressed
+   compression = get16(s);
+   if (compression > 1)
+      return epuc("bad compression", "PSD has an unknown compression format");
+
+   // Create the destination image.
+   out = (stbi_uc *) malloc(4 * w*h);
+   if (!out) return epuc("outofmem", "Out of memory");
+   pixelCount = w*h;
+
+   // Initialize the data to zero.
+   //memset( out, 0, pixelCount * 4 );
+   
+   // Finally, the image data.
+   if (compression) {
+      // RLE as used by .PSD and .TIFF
+      // Loop until you get the number of unpacked bytes you are expecting:
+      //     Read the next source byte into n.
+      //     If n is between 0 and 127 inclusive, copy the next n+1 bytes literally.
+      //     Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times.
+      //     Else if n is 128, noop.
+      // Endloop
+
+      // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data,
+      // which we're going to just skip.
+      skip(s, h * channelCount * 2 );
+
+      // Read the RLE data by channel.
+      for (channel = 0; channel < 4; channel++) {
+         Uint8 *p;
+         
+         p = out+channel;
+         if (channel >= channelCount) {
+            // Fill this channel with default data.
+            for (i = 0; i < pixelCount; i++) *p = (channel == 3 ? 255 : 0), p += 4;
+         } else {
+            // Read the RLE data.
+            count = 0;
+            while (count < pixelCount) {
+               len = get8(s);
+               if (len == 128) {
+                  // No-op.
+               } else if (len < 128) {
+                  // Copy next len+1 bytes literally.
+                  len++;
+                  count += len;
+                  while (len) {
+                     *p = get8u(s);
+                     p += 4;
+                     len--;
+                  }
+               } else if (len > 128) {
+                  Uint8   val;
+                  // Next -len+1 bytes in the dest are replicated from next source byte.
+                  // (Interpret len as a negative 8-bit int.)
+                  len ^= 0x0FF;
+                  len += 2;
+                  val = get8u(s);
+                  count += len;
+                  while (len) {
+                     *p = val;
+                     p += 4;
+                     len--;
+                  }
+               }
+            }
+         }
+      }
+      
+   } else {
+      // We're at the raw image data.  It's each channel in order (Red, Green, Blue, Alpha, ...)
+      // where each channel consists of an 8-bit value for each pixel in the image.
+      
+      // Read the data by channel.
+      for (channel = 0; channel < 4; channel++) {
+         Uint8 *p;
+         
+         p = out + channel;
+         if (channel > channelCount) {
+            // Fill this channel with default data.
+            for (i = 0; i < pixelCount; i++) *p = channel == 3 ? 255 : 0, p += 4;
+         } else {
+            // Read the data.
+            for (i = 0; i < pixelCount; i++)
+               *p = get8u(s), p += 4;
+         }
+      }
+   }
+
+   if (req_comp && req_comp != 4) {
+      out = convert_format(out, 4, req_comp, w, h);
+      if (out == NULL) return out; // convert_format frees input on failure
+   }
+
+   if (comp) *comp = channelCount;
+   *y = h;
+   *x = w;
+   
+   return out;
+}
+
+static stbi_uc *stbi_psd_load(stbi *s, int *x, int *y, int *comp, int req_comp)
+{
+   return psd_load(s,x,y,comp,req_comp);
+}
+
+// *************************************************************************************************
+// Softimage PIC loader
+// by Tom Seddon
+//
+// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format
+// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/
+
+static int pic_is4(stbi *s,const char *str)
+{
+   int i;
+   for (i=0; i<4; ++i)
+      if (get8(s) != (stbi_uc)str[i])
+         return 0;
+
+   return 1;
+}
+
+static int pic_test(stbi *s)
+{
+   int i;
+
+   if (!pic_is4(s,"\x53\x80\xF6\x34"))
+      return 0;
+
+   for(i=0;i<84;++i)
+      get8(s);
+
+   if (!pic_is4(s,"PICT"))
+      return 0;
+
+   return 1;
+}
+
+typedef struct
+{
+   stbi_uc size,type,channel;
+} pic_packet_t;
+
+static stbi_uc *pic_readval(stbi *s, int channel, stbi_uc *dest)
+{
+   int mask=0x80, i;
+
+   for (i=0; i<4; ++i, mask>>=1) {
+      if (channel & mask) {
+         if (at_eof(s)) return epuc("bad file","PIC file too short");
+         dest[i]=get8u(s);
+      }
+   }
+
+   return dest;
+}
+
+static void pic_copyval(int channel,stbi_uc *dest,const stbi_uc *src)
+{
+   int mask=0x80,i;
+
+   for (i=0;i<4; ++i, mask>>=1)
+      if (channel&mask)
+         dest[i]=src[i];
+}
+
+static stbi_uc *pic_load2(stbi *s,int width,int height,int *comp, stbi_uc *result)
+{
+   int act_comp=0,num_packets=0,y,chained;
+   pic_packet_t packets[10];
+
+   // this will (should...) cater for even some bizarre stuff like having data
+    // for the same channel in multiple packets.
+   do {
+      pic_packet_t *packet;
+
+      if (num_packets==sizeof(packets)/sizeof(packets[0]))
+         return epuc("bad format","too many packets");
+
+      packet = &packets[num_packets++];
+
+      chained = get8(s);
+      packet->size    = get8u(s);
+      packet->type    = get8u(s);
+      packet->channel = get8u(s);
+
+      act_comp |= packet->channel;
+
+      if (at_eof(s))          return epuc("bad file","file too short (reading packets)");
+      if (packet->size != 8)  return epuc("bad format","packet isn't 8bpp");
+   } while (chained);
+
+   *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel?
+
+   for(y=0; y<height; ++y) {
+      int packet_idx;
+
+      for(packet_idx=0; packet_idx < num_packets; ++packet_idx) {
+         pic_packet_t *packet = &packets[packet_idx];
+         stbi_uc *dest = result+y*width*4;
+
+         switch (packet->type) {
+            default:
+               return epuc("bad format","packet has bad compression type");
+
+            case 0: {//uncompressed
+               int x;
+
+               for(x=0;x<width;++x, dest+=4)
+                  if (!pic_readval(s,packet->channel,dest))
+                     return 0;
+               break;
+            }
+
+            case 1://Pure RLE
+               {
+                  int left=width, i;
+
+                  while (left>0) {
+                     stbi_uc count,value[4];
+
+                     count=get8u(s);
+                     if (at_eof(s))   return epuc("bad file","file too short (pure read count)");
+
+                     if (count > left)
+                        count = (Uint8) left;
+
+                     if (!pic_readval(s,packet->channel,value))  return 0;
+
+                     for(i=0; i<count; ++i,dest+=4)
+                        pic_copyval(packet->channel,dest,value);
+                     left -= count;
+                  }
+               }
+               break;
+
+            case 2: {//Mixed RLE
+               int left=width;
+               while (left>0) {
+                  int count = get8(s), i;
+                  if (at_eof(s))  return epuc("bad file","file too short (mixed read count)");
+
+                  if (count >= 128) { // Repeated
+                     stbi_uc value[4];
+                     int i;
+
+                     if (count==128)
+                        count = get16(s);
+                     else
+                        count -= 127;
+                     if (count > left)
+                        return epuc("bad file","scanline overrun");
+
+                     if (!pic_readval(s,packet->channel,value))
+                        return 0;
+
+                     for(i=0;i<count;++i, dest += 4)
+                        pic_copyval(packet->channel,dest,value);
+                  } else { // Raw
+                     ++count;
+                     if (count>left) return epuc("bad file","scanline overrun");
+
+                     for(i=0;i<count;++i, dest+=4)
+                        if (!pic_readval(s,packet->channel,dest))
+                           return 0;
+                  }
+                  left-=count;
+               }
+               break;
+            }
+         }
+      }
+   }
+
+   return result;
+}
+
+static stbi_uc *pic_load(stbi *s,int *px,int *py,int *comp,int req_comp)
+{
+   stbi_uc *result;
+   int i, x,y;
+
+   for (i=0; i<92; ++i)
+      get8(s);
+
+   x = get16(s);
+   y = get16(s);
+   if (at_eof(s))  return epuc("bad file","file too short (pic header)");
+   if ((1 << 28) / x < y) return epuc("too large", "Image too large to decode");
+
+   get32(s); //skip `ratio'
+   get16(s); //skip `fields'
+   get16(s); //skip `pad'
+
+   // intermediate buffer is RGBA
+   result = (stbi_uc *) malloc(x*y*4);
+   memset(result, 0xff, x*y*4);
+
+   if (!pic_load2(s,x,y,comp, result)) {
+      free(result);
+      result=0;
+   }
+   *px = x;
+   *py = y;
+   if (req_comp == 0) req_comp = *comp;
+   result=convert_format(result,4,req_comp,x,y);
+
+   return result;
+}
+
+static int stbi_pic_test(stbi *s)
+{
+   int r = pic_test(s);
+   stbi_rewind(s);
+   return r;
+}
+
+static stbi_uc *stbi_pic_load(stbi *s, int *x, int *y, int *comp, int req_comp)
+{
+   return pic_load(s,x,y,comp,req_comp);
+}
+
+// *************************************************************************************************
+// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb
+typedef struct stbi_gif_lzw_struct {
+   int16 prefix;
+   Uint8 first;
+   Uint8 suffix;
+} stbi_gif_lzw;
+
+typedef struct stbi_gif_struct
+{
+   int w,h;
+   stbi_uc *out;                 // output buffer (always 4 components)
+   int flags, bgindex, ratio, transparent, eflags;
+   Uint8  pal[256][4];
+   Uint8 lpal[256][4];
+   stbi_gif_lzw codes[4096];
+   Uint8 *color_table;
+   int parse, step;
+   int lflags;
+   int start_x, start_y;
+   int max_x, max_y;
+   int cur_x, cur_y;
+   int line_size;
+} stbi_gif;
+
+static int gif_test(stbi *s)
+{
+   int sz;
+   if (get8(s) != 'G' || get8(s) != 'I' || get8(s) != 'F' || get8(s) != '8') return 0;
+   sz = get8(s);
+   if (sz != '9' && sz != '7') return 0;
+   if (get8(s) != 'a') return 0;
+   return 1;
+}
+
+static int stbi_gif_test(stbi *s)
+{
+   int r = gif_test(s);
+   stbi_rewind(s);
+   return r;
+}
+
+static void stbi_gif_parse_colortable(stbi *s, Uint8 pal[256][4], int num_entries, int transp)
+{
+   int i;
+   for (i=0; i < num_entries; ++i) {
+      pal[i][2] = get8u(s);
+      pal[i][1] = get8u(s);
+      pal[i][0] = get8u(s);
+      pal[i][3] = transp ? 0 : 255;
+   }   
+}
+
+static int stbi_gif_header(stbi *s, stbi_gif *g, int *comp, int is_info)
+{
+   Uint8 version;
+   if (get8(s) != 'G' || get8(s) != 'I' || get8(s) != 'F' || get8(s) != '8')
+      return e("not GIF", "Corrupt GIF");
+
+   version = get8u(s);
+   if (version != '7' && version != '9')    return e("not GIF", "Corrupt GIF");
+   if (get8(s) != 'a')                      return e("not GIF", "Corrupt GIF");
+ 
+   failure_reason = "";
+   g->w = get16le(s);
+   g->h = get16le(s);
+   g->flags = get8(s);
+   g->bgindex = get8(s);
+   g->ratio = get8(s);
+   g->transparent = -1;
+
+   if (comp != 0) *comp = 4;  // can't actually tell whether it's 3 or 4 until we parse the comments
+
+   if (is_info) return 1;
+
+   if (g->flags & 0x80)
+      stbi_gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1);
+
+   return 1;
+}
+
+static int stbi_gif_info_raw(stbi *s, int *x, int *y, int *comp)
+{
+   stbi_gif g;   
+   if (!stbi_gif_header(s, &g, comp, 1)) {
+      stbi_rewind( s );
+      return 0;
+   }
+   if (x) *x = g.w;
+   if (y) *y = g.h;
+   return 1;
+}
+
+static void stbi_out_gif_code(stbi_gif *g, Uint16 code)
+{
+   Uint8 *p, *c;
+
+   // recurse to decode the prefixes, since the linked-list is backwards,
+   // and working backwards through an interleaved image would be nasty
+   if (g->codes[code].prefix >= 0)
+      stbi_out_gif_code(g, g->codes[code].prefix);
+
+   if (g->cur_y >= g->max_y) return;
+  
+   p = &g->out[g->cur_x + g->cur_y];
+   c = &g->color_table[g->codes[code].suffix * 4];
+
+   if (c[3] >= 128) {
+      p[0] = c[2];
+      p[1] = c[1];
+      p[2] = c[0];
+      p[3] = c[3];
+   }
+   g->cur_x += 4;
+
+   if (g->cur_x >= g->max_x) {
+      g->cur_x = g->start_x;
+      g->cur_y += g->step;
+
+      while (g->cur_y >= g->max_y && g->parse > 0) {
+         g->step = (1 << g->parse) * g->line_size;
+         g->cur_y = g->start_y + (g->step >> 1);
+         --g->parse;
+      }
+   }
+}
+
+static Uint8 *stbi_process_gif_raster(stbi *s, stbi_gif *g)
+{
+   Uint8 lzw_cs;
+   int32 len, code;
+   Uint32 first;
+   int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear;
+   stbi_gif_lzw *p;
+
+   lzw_cs = get8u(s);
+   clear = 1 << lzw_cs;
+   first = 1;
+   codesize = lzw_cs + 1;
+   codemask = (1 << codesize) - 1;
+   bits = 0;
+   valid_bits = 0;
+   for (code = 0; code < clear; code++) {
+      g->codes[code].prefix = -1;
+      g->codes[code].first = (Uint8) code;
+      g->codes[code].suffix = (Uint8) code;
+   }
+
+   // support no starting clear code
+   avail = clear+2;
+   oldcode = -1;
+
+   len = 0;
+   for(;;) {
+      if (valid_bits < codesize) {
+         if (len == 0) {
+            len = get8(s); // start new block
+            if (len == 0) 
+               return g->out;
+         }
+         --len;
+         bits |= (int32) get8(s) << valid_bits;
+         valid_bits += 8;
+      } else {
+         int32 code = bits & codemask;
+         bits >>= codesize;
+         valid_bits -= codesize;
+         // @OPTIMIZE: is there some way we can accelerate the non-clear path?
+         if (code == clear) {  // clear code
+            codesize = lzw_cs + 1;
+            codemask = (1 << codesize) - 1;
+            avail = clear + 2;
+            oldcode = -1;
+            first = 0;
+         } else if (code == clear + 1) { // end of stream code
+            skip(s, len);
+            while ((len = get8(s)) > 0)
+               skip(s,len);
+            return g->out;
+         } else if (code <= avail) {
+            if (first) return epuc("no clear code", "Corrupt GIF");
+
+            if (oldcode >= 0) {
+               p = &g->codes[avail++];
+               if (avail > 4096)        return epuc("too many codes", "Corrupt GIF");
+               p->prefix = (int16) oldcode;
+               p->first = g->codes[oldcode].first;
+               p->suffix = (code == avail) ? p->first : g->codes[code].first;
+            } else if (code == avail)
+               return epuc("illegal code in raster", "Corrupt GIF");
+
+            stbi_out_gif_code(g, (Uint16) code);
+
+            if ((avail & codemask) == 0 && avail <= 0x0FFF) {
+               codesize++;
+               codemask = (1 << codesize) - 1;
+            }
+
+            oldcode = code;
+         } else {
+            return epuc("illegal code in raster", "Corrupt GIF");
+         }
+      } 
+   }
+}
+
+static void stbi_fill_gif_background(stbi_gif *g)
+{
+   int i;
+   Uint8 *c = g->pal[g->bgindex];
+   // @OPTIMIZE: write a dword at a time
+   for (i = 0; i < g->w * g->h * 4; i += 4) {
+      Uint8 *p  = &g->out[i];
+      p[0] = c[2];
+      p[1] = c[1];
+      p[2] = c[0];
+      p[3] = c[3];
+   }
+}
+
+// this function is designed to support animated gifs, although stb_image doesn't support it
+static Uint8 *stbi_gif_load_next(stbi *s, stbi_gif *g, int *comp, int req_comp)
+{
+   int i;
+   Uint8 *old_out = 0;
+
+   if (g->out == 0) {
+      if (!stbi_gif_header(s, g, comp,0))     return 0; // failure_reason set by stbi_gif_header
+      g->out = (Uint8 *) malloc(4 * g->w * g->h);
+      if (g->out == 0)                      return epuc("outofmem", "Out of memory");
+      stbi_fill_gif_background(g);
+   } else {
+      // animated-gif-only path
+      if (((g->eflags & 0x1C) >> 2) == 3) {
+         old_out = g->out;
+         g->out = (Uint8 *) malloc(4 * g->w * g->h);
+         if (g->out == 0)                   return epuc("outofmem", "Out of memory");
+         memcpy(g->out, old_out, g->w*g->h*4);
+      }
+   }
+    
+   for (;;) {
+      switch (get8(s)) {
+         case 0x2C: // Image Descriptor
+         {
+            int32 x, y, w, h;
+            Uint8 *o;
+
+            x = get16le(s);
+            y = get16le(s);
+            w = get16le(s);
+            h = get16le(s);
+            if (((x + w) > (g->w)) || ((y + h) > (g->h)))
+               return epuc("bad Image Descriptor", "Corrupt GIF");
+
+            g->line_size = g->w * 4;
+            g->start_x = x * 4;
+            g->start_y = y * g->line_size;
+            g->max_x   = g->start_x + w * 4;
+            g->max_y   = g->start_y + h * g->line_size;
+            g->cur_x   = g->start_x;
+            g->cur_y   = g->start_y;
+
+            g->lflags = get8(s);
+
+            if (g->lflags & 0x40) {
+               g->step = 8 * g->line_size; // first interlaced spacing
+               g->parse = 3;
+            } else {
+               g->step = g->line_size;
+               g->parse = 0;
+            }
+
+            if (g->lflags & 0x80) {
+               stbi_gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1);
+               g->color_table = (Uint8 *) g->lpal;       
+            } else if (g->flags & 0x80) {
+               for (i=0; i < 256; ++i)  // @OPTIMIZE: reset only the previous transparent
+                  g->pal[i][3] = 255; 
+               if (g->transparent >= 0 && (g->eflags & 0x01))
+                  g->pal[g->transparent][3] = 0;
+               g->color_table = (Uint8 *) g->pal;
+            } else
+               return epuc("missing color table", "Corrupt GIF");
+   
+            o = stbi_process_gif_raster(s, g);
+            if (o == NULL) return NULL;
+
+            if (req_comp && req_comp != 4)
+               o = convert_format(o, 4, req_comp, g->w, g->h);
+            return o;
+         }
+
+         case 0x21: // Comment Extension.
+         {
+            int len;
+            if (get8(s) == 0xF9) { // Graphic Control Extension.
+               len = get8(s);
+               if (len == 4) {
+                  g->eflags = get8(s);
+                  get16le(s); // delay
+                  g->transparent = get8(s);
+               } else {
+                  skip(s, len);
+                  break;
+               }
+            }
+            while ((len = get8(s)) != 0)
+               skip(s, len);
+            break;
+         }
+
+         case 0x3B: // gif stream termination code
+            return (Uint8 *) 1;
+
+         default:
+            return epuc("unknown code", "Corrupt GIF");
+      }
+   }
+}
+
+static stbi_uc *stbi_gif_load(stbi *s, int *x, int *y, int *comp, int req_comp)
+{
+   Uint8 *u = 0;
+   stbi_gif g={0};
+
+   u = stbi_gif_load_next(s, &g, comp, req_comp);
+   if (u == (void *) 1) u = 0;  // end of animated gif marker
+   if (u) {
+      *x = g.w;
+      *y = g.h;
+   }
+
+   return u;
+}
+
+static int stbi_gif_info(stbi *s, int *x, int *y, int *comp)
+{
+   return stbi_gif_info_raw(s,x,y,comp);
+}
+
+#endif
+
+// *************************************************************************************************
+// Radiance RGBE HDR loader
+// originally by Nicolas Schulz
+#ifndef STBI_NO_HDR
+static int hdr_test(stbi *s)
+{
+   const char *signature = "#?RADIANCE\n";
+   int i;
+   for (i=0; signature[i]; ++i)
+      if (get8(s) != signature[i])
+         return 0;
+   return 1;
+}
+
+static int stbi_hdr_test(stbi* s)
+{
+   int r = hdr_test(s);
+   stbi_rewind(s);
+   return r;
+}
+
+#define HDR_BUFLEN  1024
+static char *hdr_gettoken(stbi *z, char *buffer)
+{
+   int len=0;
+   char c = '\0';
+
+   c = (char) get8(z);
+
+   while (!at_eof(z) && c != '\n') {
+      buffer[len++] = c;
+      if (len == HDR_BUFLEN-1) {
+         // flush to end of line
+         while (!at_eof(z) && get8(z) != '\n')
+            ;
+         break;
+      }
+      c = (char) get8(z);
+   }
+
+   buffer[len] = 0;
+   return buffer;
+}
+
+static void hdr_convert(float *output, stbi_uc *input, int req_comp)
+{
+   if ( input[3] != 0 ) {
+      float f1;
+      // Exponent
+      f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8));
+      if (req_comp <= 2)
+         output[0] = (input[0] + input[1] + input[2]) * f1 / 3;
+      else {
+         output[0] = input[0] * f1;
+         output[1] = input[1] * f1;
+         output[2] = input[2] * f1;
+      }
+      if (req_comp == 2) output[1] = 1;
+      if (req_comp == 4) output[3] = 1;
+   } else {
+      switch (req_comp) {
+         case 4: output[3] = 1; // fallthrough
+         case 3: output[0] = output[1] = output[2] = 0;
+                 break;
+         case 2: output[1] = 1; // fallthrough
+         case 1: output[0] = 0;
+                 break;
+      }
+   }
+}
+
+static float *hdr_load(stbi *s, int *x, int *y, int *comp, int req_comp)
+{
+   char buffer[HDR_BUFLEN];
+   char *token;
+   int valid = 0;
+   int width, height;
+   stbi_uc *scanline;
+   float *hdr_data;
+   int len;
+   unsigned char count, value;
+   int i, j, k, c1,c2, z;
+
+
+   // Check identifier
+   if (strcmp(hdr_gettoken(s,buffer), "#?RADIANCE") != 0)
+      return epf("not HDR", "Corrupt HDR image");
+   
+   // Parse header
+   for(;;) {
+      token = hdr_gettoken(s,buffer);
+      if (token[0] == 0) break;
+      if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1;
+   }
+
+   if (!valid)    return epf("unsupported format", "Unsupported HDR format");
+
+   // Parse width and height
+   // can't use sscanf() if we're not using stdio!
+   token = hdr_gettoken(s,buffer);
+   if (strncmp(token, "-Y ", 3))  return epf("unsupported data layout", "Unsupported HDR format");
+   token += 3;
+   height = strtol(token, &token, 10);
+   while (*token == ' ') ++token;
+   if (strncmp(token, "+X ", 3))  return epf("unsupported data layout", "Unsupported HDR format");
+   token += 3;
+   width = strtol(token, NULL, 10);
+
+   *x = width;
+   *y = height;
+
+   *comp = 3;
+   if (req_comp == 0) req_comp = 3;
+
+   // Read data
+   hdr_data = (float *) malloc(height * width * req_comp * sizeof(float));
+
+   // Load image data
+   // image data is stored as some number of sca
+   if ( width < 8 || width >= 32768) {
+      // Read flat data
+      for (j=0; j < height; ++j) {
+         for (i=0; i < width; ++i) {
+            stbi_uc rgbe[4];
+           main_decode_loop:
+            getn(s, rgbe, 4);
+            hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp);
+         }
+      }
+   } else {
+      // Read RLE-encoded data
+      scanline = NULL;
+
+      for (j = 0; j < height; ++j) {
+         c1 = get8(s);
+         c2 = get8(s);
+         len = get8(s);
+         if (c1 != 2 || c2 != 2 || (len & 0x80)) {
+            // not run-length encoded, so we have to actually use THIS data as a decoded
+            // pixel (note this can't be a valid pixel--one of RGB must be >= 128)
+            Uint8 rgbe[4];
+            rgbe[0] = (Uint8) c1;
+            rgbe[1] = (Uint8) c2;
+            rgbe[2] = (Uint8) len;
+            rgbe[3] = (Uint8) get8u(s);
+            hdr_convert(hdr_data, rgbe, req_comp);
+            i = 1;
+            j = 0;
+            free(scanline);
+            goto main_decode_loop; // yes, this makes no sense
+         }
+         len <<= 8;
+         len |= get8(s);
+         if (len != width) { free(hdr_data); free(scanline); return epf("invalid decoded scanline length", "corrupt HDR"); }
+         if (scanline == NULL) scanline = (stbi_uc *) malloc(width * 4);
+            
+         for (k = 0; k < 4; ++k) {
+            i = 0;
+            while (i < width) {
+               count = get8u(s);
+               if (count > 128) {
+                  // Run
+                  value = get8u(s);
+                  count -= 128;
+                  for (z = 0; z < count; ++z)
+                     scanline[i++ * 4 + k] = value;
+               } else {
+                  // Dump
+                  for (z = 0; z < count; ++z)
+                     scanline[i++ * 4 + k] = get8u(s);
+               }
+            }
+         }
+         for (i=0; i < width; ++i)
+            hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp);
+      }
+      free(scanline);
+   }
+
+   return hdr_data;
+}
+
+static float *stbi_hdr_load(stbi *s, int *x, int *y, int *comp, int req_comp)
+{
+   return hdr_load(s,x,y,comp,req_comp);
+}
+
+static int stbi_hdr_info(stbi *s, int *x, int *y, int *comp)
+{
+   char buffer[HDR_BUFLEN];
+   char *token;
+   int valid = 0;
+
+   if (strcmp(hdr_gettoken(s,buffer), "#?RADIANCE") != 0) {
+       stbi_rewind( s );
+       return 0;
+   }
+
+   for(;;) {
+      token = hdr_gettoken(s,buffer);
+      if (token[0] == 0) break;
+      if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1;
+   }
+
+   if (!valid) {
+       stbi_rewind( s );
+       return 0;
+   }
+   token = hdr_gettoken(s,buffer);
+   if (strncmp(token, "-Y ", 3)) {
+       stbi_rewind( s );
+       return 0;
+   }
+   token += 3;
+   *y = strtol(token, &token, 10);
+   while (*token == ' ') ++token;
+   if (strncmp(token, "+X ", 3)) {
+       stbi_rewind( s );
+       return 0;
+   }
+   token += 3;
+   *x = strtol(token, NULL, 10);
+   *comp = 3;
+   return 1;
+}
+#endif // STBI_NO_HDR
+
+#ifdef STBI_CRAP_FORMATS
+
+static int stbi_bmp_info(stbi *s, int *x, int *y, int *comp)
+{
+   int hsz;
+   if (get8(s) != 'B' || get8(s) != 'M') {
+       stbi_rewind( s );
+       return 0;
+   }
+   skip(s,12);
+   hsz = get32le(s);
+   if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108) {
+       stbi_rewind( s );
+       return 0;
+   }
+   if (hsz == 12) {
+      *x = get16le(s);
+      *y = get16le(s);
+   } else {
+      *x = get32le(s);
+      *y = get32le(s);
+   }
+   if (get16le(s) != 1) {
+       stbi_rewind( s );
+       return 0;
+   }
+   *comp = get16le(s) / 8;
+   return 1;
+}
+
+static int stbi_psd_info(stbi *s, int *x, int *y, int *comp)
+{
+   int channelCount;
+   if (get32(s) != 0x38425053) {
+       stbi_rewind( s );
+       return 0;
+   }
+   if (get16(s) != 1) {
+       stbi_rewind( s );
+       return 0;
+   }
+   skip(s, 6);
+   channelCount = get16(s);
+   if (channelCount < 0 || channelCount > 16) {
+       stbi_rewind( s );
+       return 0;
+   }
+   *y = get32(s);
+   *x = get32(s);
+   if (get16(s) != 8) {
+       stbi_rewind( s );
+       return 0;
+   }
+   if (get16(s) != 3) {
+       stbi_rewind( s );
+       return 0;
+   }
+   *comp = 4;
+   return 1;
+}
+
+static int stbi_pic_info(stbi *s, int *x, int *y, int *comp)
+{
+   int act_comp=0,num_packets=0,chained;
+   pic_packet_t packets[10];
+
+   skip(s, 92);
+
+   *x = get16(s);
+   *y = get16(s);
+   if (at_eof(s))  return 0;
+   if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) {
+       stbi_rewind( s );
+       return 0;
+   }
+
+   skip(s, 8);
+
+   do {
+      pic_packet_t *packet;
+
+      if (num_packets==sizeof(packets)/sizeof(packets[0]))
+         return 0;
+
+      packet = &packets[num_packets++];
+      chained = get8(s);
+      packet->size    = get8u(s);
+      packet->type    = get8u(s);
+      packet->channel = get8u(s);
+      act_comp |= packet->channel;
+
+      if (at_eof(s)) {
+          stbi_rewind( s );
+          return 0;
+      }
+      if (packet->size != 8) {
+          stbi_rewind( s );
+          return 0;
+      }
+   } while (chained);
+
+   *comp = (act_comp & 0x10 ? 4 : 3);
+
+   return 1;
+}
+#endif
+
+
+static int stbi_info_main(stbi *s, int *x, int *y, int *comp)
+{
+   if (stbi_jpeg_info(s, x, y, comp))
+       return 1;
+   if (stbi_png_info(s, x, y, comp))
+       return 1;
+#ifdef STBI_CRAP_FORMATS
+   if (stbi_gif_info(s, x, y, comp))
+       return 1;
+   if (stbi_bmp_info(s, x, y, comp))
+       return 1;
+   if (stbi_psd_info(s, x, y, comp))
+       return 1;
+   if (stbi_pic_info(s, x, y, comp))
+       return 1;
+   #ifndef STBI_NO_HDR
+   if (stbi_hdr_info(s, x, y, comp))
+       return 1;
+   #endif
+   // test tga last because it's a crappy test!
+   if (stbi_tga_info(s, x, y, comp))
+       return 1;
+#endif
+   return e("unknown image type", "Image not of any known type, or corrupt");
+}
+
+#ifndef STBI_NO_STDIO
+int stbi_info(char const *filename, int *x, int *y, int *comp)
+{
+    FILE *f = fopen(filename, "rb");
+    int result;
+    if (!f) return e("can't fopen", "Unable to open file");
+    result = stbi_info_from_file(f, x, y, comp);
+    fclose(f);
+    return result;
+}
+
+int stbi_info_from_file(FILE *f, int *x, int *y, int *comp)
+{
+   int r;
+   stbi s;
+   long pos = ftell(f);
+   start_file(&s, f);
+   r = stbi_info_main(&s,x,y,comp);
+   fseek(f,pos,SEEK_SET);
+   return r;
+}
+#endif // !STBI_NO_STDIO
+
+int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp)
+{
+   stbi s;
+   start_mem(&s,buffer,len);
+   return stbi_info_main(&s,x,y,comp);
+}
+
+int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp)
+{
+   stbi s;
+   start_callbacks(&s, (stbi_io_callbacks *) c, user);
+   return stbi_info_main(&s,x,y,comp);
+}
+
+#endif // STBI_HEADER_FILE_ONLY
+
+/*
+   revision history:
+      1.33 (2011-07-14)
+             make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements
+      1.32 (2011-07-13)
+             support for "info" function for all supported filetypes (SpartanJ)
+      1.31 (2011-06-20)
+             a few more leak fixes, bug in PNG handling (SpartanJ)
+      1.30 (2011-06-11)
+             added ability to load files via callbacks to accomidate custom input streams (Ben Wenger)
+             removed deprecated format-specific test/load functions
+             removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway
+             error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha)
+             fix inefficiency in decoding 32-bit BMP (David Woo)
+      1.29 (2010-08-16)
+             various warning fixes from Aurelien Pocheville 
+      1.28 (2010-08-01)
+             fix bug in GIF palette transparency (SpartanJ)
+      1.27 (2010-08-01)
+             cast-to-Uint8 to fix warnings
+      1.26 (2010-07-24)
+             fix bug in file buffering for PNG reported by SpartanJ
+      1.25 (2010-07-17)
+             refix trans_data warning (Won Chun)
+      1.24 (2010-07-12)
+             perf improvements reading from files on platforms with lock-heavy fgetc()
+             minor perf improvements for jpeg
+             deprecated type-specific functions so we'll get feedback if they're needed
+             attempt to fix trans_data warning (Won Chun)
+      1.23   fixed bug in iPhone support
+      1.22 (2010-07-10)
+             removed image *writing* support
+             stbi_info support from Jetro Lauha
+             GIF support from Jean-Marc Lienher
+             iPhone PNG-extensions from James Brown
+             warning-fixes from Nicolas Schulz and Janez Zemva (i.e. Janez (U+017D)emva)
+      1.21   fix use of 'Uint8' in header (reported by jon blow)
+      1.20   added support for Softimage PIC, by Tom Seddon
+      1.19   bug in interlaced PNG corruption check (found by ryg)
+      1.18 2008-08-02
+             fix a threading bug (local mutable static)
+      1.17   support interlaced PNG
+      1.16   major bugfix - convert_format converted one too many pixels
+      1.15   initialize some fields for thread safety
+      1.14   fix threadsafe conversion bug
+             header-file-only version (#define STBI_HEADER_FILE_ONLY before including)
+      1.13   threadsafe
+      1.12   const qualifiers in the API
+      1.11   Support installable IDCT, colorspace conversion routines
+      1.10   Fixes for 64-bit (don't use "unsigned long")
+             optimized upsampling by Fabian "ryg" Giesen
+      1.09   Fix format-conversion for PSD code (bad global variables!)
+      1.08   Thatcher Ulrich's PSD code integrated by Nicolas Schulz
+      1.07   attempt to fix C++ warning/errors again
+      1.06   attempt to fix C++ warning/errors again
+      1.05   fix TGA loading to return correct *comp and use good luminance calc
+      1.04   default float alpha is 1, not 255; use 'void *' for stbi_image_free
+      1.03   bugfixes to STBI_NO_STDIO, STBI_NO_HDR
+      1.02   support for (subset of) HDR files, float interface for preferred access to them
+      1.01   fix bug: possible bug in handling right-side up bmps... not sure
+             fix bug: the stbi_bmp_load() and stbi_tga_load() functions didn't work at all
+      1.00   interface to zlib that skips zlib header
+      0.99   correct handling of alpha in palette
+      0.98   TGA loader by lonesock; dynamically add loaders (untested)
+      0.97   jpeg errors on too large a file; also catch another malloc failure
+      0.96   fix detection of invalid v value - particleman@mollyrocket forum
+      0.95   during header scan, seek to markers in case of padding
+      0.94   STBI_NO_STDIO to disable stdio usage; rename all #defines the same
+      0.93   handle jpegtran output; verbose errors
+      0.92   read 4,8,16,24,32-bit BMP files of several formats
+      0.91   output 24-bit Windows 3.0 BMP files
+      0.90   fix a few more warnings; bump version number to approach 1.0
+      0.61   bugfixes due to Marc LeBlanc, Christopher Lloyd
+      0.60   fix compiling as c++
+      0.59   fix warnings: merge Dave Moore's -Wall fixes
+      0.58   fix bug: zlib uncompressed mode len/nlen was wrong endian
+      0.57   fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available
+      0.56   fix bug: zlib uncompressed mode len vs. nlen
+      0.55   fix bug: restart_interval not initialized to 0
+      0.54   allow NULL for 'int *comp'
+      0.53   fix bug in png 3->4; speedup png decoding
+      0.52   png handles req_comp=3,4 directly; minor cleanup; jpeg comments
+      0.51   obey req_comp requests, 1-component jpegs return as 1-component,
+             on 'test' only check type, not whether we support this variant
+      0.50   first released version
+*/
--- a/stb_image.c	Fri May 16 03:01:51 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4685 +0,0 @@
-/* stbi-1.33 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c
-   when you control the images you're loading
-                                     no warranty implied; use at your own risk
-
-   QUICK NOTES:
-      Primarily of interest to game developers and other people who can
-          avoid problematic images and only need the trivial interface
-
-      JPEG baseline (no JPEG progressive)
-      PNG 8-bit only
-
-      TGA (not sure what subset, if a subset)
-      BMP non-1bpp, non-RLE
-      PSD (composited view only, no extra channels)
-
-      GIF (*comp always reports as 4-channel)
-      HDR (radiance rgbE format)
-      PIC (Softimage PIC)
-
-      - decode from memory or through FILE (define STBI_NO_STDIO to remove code)
-      - decode from arbitrary I/O callbacks
-      - overridable dequantizing-IDCT, YCbCr-to-RGB conversion (define STBI_SIMD)
-
-   Latest revisions:
-      1.33 (2011-07-14) minor fixes suggested by Dave Moore
-      1.32 (2011-07-13) info support for all filetypes (SpartanJ)
-      1.31 (2011-06-19) a few more leak fixes, bug in PNG handling (SpartanJ)
-      1.30 (2011-06-11) added ability to load files via io callbacks (Ben Wenger)
-      1.29 (2010-08-16) various warning fixes from Aurelien Pocheville 
-      1.28 (2010-08-01) fix bug in GIF palette transparency (SpartanJ)
-      1.27 (2010-08-01) cast-to-Uint8 to fix warnings (Laurent Gomila)
-                        allow trailing 0s at end of image data (Laurent Gomila)
-      1.26 (2010-07-24) fix bug in file buffering for PNG reported by SpartanJ
-
-   See end of file for full revision history.
-
-   TODO:
-      stbi_info support for BMP,PSD,HDR,PIC
-
-
- ============================    Contributors    =========================
-              
- Image formats                                Optimizations & bugfixes
-    Sean Barrett (jpeg, png, bmp)                Fabian "ryg" Giesen
-    Nicolas Schulz (hdr, psd)                                                 
-    Jonathan Dummer (tga)                     Bug fixes & warning fixes           
-    Jean-Marc Lienher (gif)                      Marc LeBlanc               
-    Tom Seddon (pic)                             Christpher Lloyd           
-    Thatcher Ulrich (psd)                        Dave Moore                 
-                                                 Won Chun                   
-                                                 the Horde3D community      
- Extensions, features                            Janez Zemva                
-    Jetro Lauha (stbi_info)                      Jonathan Blow              
-    James "moose2000" Brown (iPhone PNG)         Laurent Gomila                             
-    Ben "Disch" Wenger (io callbacks)            Aruelien Pocheville
-    Martin "SpartanJ" Golini                     Ryamond Barbiero
-                                                 David Woo
-                                                 
-
- If your name should be here but isn't, let Sean know.
-
-*/
-
-#ifndef STBI_INCLUDE_STB_IMAGE_H
-#define STBI_INCLUDE_STB_IMAGE_H
-
-// To get a header file for this, either cut and paste the header,
-// or create stb_image.h, #define STBI_HEADER_FILE_ONLY, and
-// then include stb_image.c from it.
-
-////   begin header file  ////////////////////////////////////////////////////
-//
-// Limitations:
-//    - no jpeg progressive support
-//    - non-HDR formats support 8-bit samples only (jpeg, png)
-//    - no delayed line count (jpeg) -- IJG doesn't support either
-//    - no 1-bit BMP
-//    - GIF always returns *comp=4
-//
-// Basic usage (see HDR discussion below):
-//    int x,y,n;
-//    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
-//    // ... process data if not NULL ... 
-//    // ... x = width, y = height, n = # 8-bit components per pixel ...
-//    // ... replace '0' with '1'..'4' to force that many components per pixel
-//    // ... but 'n' will always be the number that it would have been if you said 0
-//    stbi_image_free(data)
-//
-// Standard parameters:
-//    int *x       -- outputs image width in pixels
-//    int *y       -- outputs image height in pixels
-//    int *comp    -- outputs # of image components in image file
-//    int req_comp -- if non-zero, # of image components requested in result
-//
-// The return value from an image loader is an 'unsigned char *' which points
-// to the pixel data. The pixel data consists of *y scanlines of *x pixels,
-// with each pixel consisting of N interleaved 8-bit components; the first
-// pixel pointed to is top-left-most in the image. There is no padding between
-// image scanlines or between pixels, regardless of format. The number of
-// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise.
-// If req_comp is non-zero, *comp has the number of components that _would_
-// have been output otherwise. E.g. if you set req_comp to 4, you will always
-// get RGBA output, but you can check *comp to easily see if it's opaque.
-//
-// An output image with N components has the following components interleaved
-// in this order in each pixel:
-//
-//     N=#comp     components
-//       1           grey
-//       2           grey, alpha
-//       3           red, green, blue
-//       4           red, green, blue, alpha
-//
-// If image loading fails for any reason, the return value will be NULL,
-// and *x, *y, *comp will be unchanged. The function stbi_failure_reason()
-// can be queried for an extremely brief, end-user unfriendly explanation
-// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid
-// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
-// more user-friendly ones.
-//
-// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.
-//
-// ===========================================================================
-//
-// iPhone PNG support:
-//
-// By default we convert iphone-formatted PNGs back to RGB; nominally they
-// would silently load as BGR, except the existing code should have just
-// failed on such iPhone PNGs. But you can disable this conversion by
-// by calling stbi_convert_iphone_png_to_rgb(0), in which case
-// you will always just get the native iphone "format" through.
-//
-// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per
-// pixel to remove any premultiplied alpha *only* if the image file explicitly
-// says there's premultiplied data (currently only happens in iPhone images,
-// and only if iPhone convert-to-rgb processing is on).
-//
-// ===========================================================================
-//
-// HDR image support   (disable by defining STBI_NO_HDR)
-//
-// stb_image now supports loading HDR images in general, and currently
-// the Radiance .HDR file format, although the support is provided
-// generically. You can still load any file through the existing interface;
-// if you attempt to load an HDR file, it will be automatically remapped to
-// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;
-// both of these constants can be reconfigured through this interface:
-//
-//     stbi_hdr_to_ldr_gamma(2.2f);
-//     stbi_hdr_to_ldr_scale(1.0f);
-//
-// (note, do not use _inverse_ constants; stbi_image will invert them
-// appropriately).
-//
-// Additionally, there is a new, parallel interface for loading files as
-// (linear) floats to preserve the full dynamic range:
-//
-//    float *data = stbi_loadf(filename, &x, &y, &n, 0);
-// 
-// If you load LDR images through this interface, those images will
-// be promoted to floating point values, run through the inverse of
-// constants corresponding to the above:
-//
-//     stbi_ldr_to_hdr_scale(1.0f);
-//     stbi_ldr_to_hdr_gamma(2.2f);
-//
-// Finally, given a filename (or an open file or memory block--see header
-// file for details) containing image data, you can query for the "most
-// appropriate" interface to use (that is, whether the image is HDR or
-// not), using:
-//
-//     stbi_is_hdr(char *filename);
-//
-// ===========================================================================
-//
-// I/O callbacks
-//
-// I/O callbacks allow you to read from arbitrary sources, like packaged
-// files or some other source. Data read from callbacks are processed
-// through a small internal buffer (currently 128 bytes) to try to reduce
-// overhead. 
-//
-// The three functions you must define are "read" (reads some bytes of data),
-// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end).
-
-
-#ifndef STBI_NO_STDIO
-
-#if defined(_MSC_VER) && _MSC_VER >= 0x1400
-#define _CRT_SECURE_NO_WARNINGS // suppress bogus warnings about fopen()
-#endif
-
-#include <stdio.h>
-#endif
-
-#define STBI_VERSION 1
-
-enum
-{
-   STBI_default = 0, // only used for req_comp
-
-   STBI_grey       = 1,
-   STBI_grey_alpha = 2,
-   STBI_rgb        = 3,
-   STBI_rgb_alpha  = 4
-};
-
-typedef unsigned char stbi_uc;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-//
-// PRIMARY API - works on images of any type
-//
-
-//
-// load image by filename, open file, or memory buffer
-//
-
-extern stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
-
-#ifndef STBI_NO_STDIO
-extern stbi_uc *stbi_load            (char const *filename,     int *x, int *y, int *comp, int req_comp);
-extern stbi_uc *stbi_load_from_file  (FILE *f,                  int *x, int *y, int *comp, int req_comp);
-// for stbi_load_from_file, file pointer is left pointing immediately after image
-#endif
-
-typedef struct
-{
-   int      (*read)  (void *user,char *data,int size);   // fill 'data' with 'size' bytes.  return number of bytes actually read 
-   void     (*skip)  (void *user,unsigned n);            // skip the next 'n' bytes
-   int      (*eof)   (void *user);                       // returns nonzero if we are at end of file/data
-} stbi_io_callbacks;
-
-extern stbi_uc *stbi_load_from_callbacks  (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp);
-
-#ifndef STBI_NO_HDR
-   extern float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
-
-   #ifndef STBI_NO_STDIO
-   extern float *stbi_loadf            (char const *filename,   int *x, int *y, int *comp, int req_comp);
-   extern float *stbi_loadf_from_file  (FILE *f,                int *x, int *y, int *comp, int req_comp);
-   #endif
-   
-   extern float *stbi_loadf_from_callbacks  (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp);
-
-   extern void   stbi_hdr_to_ldr_gamma(float gamma);
-   extern void   stbi_hdr_to_ldr_scale(float scale);
-
-   extern void   stbi_ldr_to_hdr_gamma(float gamma);
-   extern void   stbi_ldr_to_hdr_scale(float scale);
-#endif // STBI_NO_HDR
-
-// stbi_is_hdr is always defined
-extern int    stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);
-extern int    stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);
-#ifndef STBI_NO_STDIO
-extern int      stbi_is_hdr          (char const *filename);
-extern int      stbi_is_hdr_from_file(FILE *f);
-#endif // STBI_NO_STDIO
-
-
-// get a VERY brief reason for failure
-// NOT THREADSAFE
-extern const char *stbi_failure_reason  (void); 
-
-// free the loaded image -- this is just free()
-extern void     stbi_image_free      (void *retval_from_stbi_load);
-
-// get image dimensions & components without fully decoding
-extern int      stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
-extern int      stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
-
-#ifndef STBI_NO_STDIO
-extern int      stbi_info            (char const *filename,     int *x, int *y, int *comp);
-extern int      stbi_info_from_file  (FILE *f,                  int *x, int *y, int *comp);
-
-#endif
-
-
-
-// for image formats that explicitly notate that they have premultiplied alpha,
-// we just return the colors as stored in the file. set this flag to force
-// unpremultiplication. results are undefined if the unpremultiply overflow.
-extern void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply);
-
-// indicate whether we should process iphone images back to canonical format,
-// or just pass them through "as-is"
-extern void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);
-
-
-// ZLIB client - used by PNG, available for other purposes
-
-extern char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);
-extern char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);
-extern int   stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
-
-extern char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);
-extern int   stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
-
-
-// define faster low-level operations (typically SIMD support)
-#ifdef STBI_SIMD
-typedef void (*stbi_idct_8x8)(stbi_uc *out, int out_stride, Sint16 data[64], Uint16 *dequantize);
-// compute an integer IDCT on "input"
-//     input[x] = data[x] * dequantize[x]
-//     write results to 'out': 64 samples, each run of 8 spaced by 'out_stride'
-//                             CLAMP results to 0..255
-typedef void (*stbi_YCbCr_to_RGB_run)(stbi_uc *output, stbi_uc const  *y, stbi_uc const *cb, stbi_uc const *cr, int count, int step);
-// compute a conversion from YCbCr to RGB
-//     'count' pixels
-//     write pixels to 'output'; each pixel is 'step' bytes (either 3 or 4; if 4, write '255' as 4th), order R,G,B
-//     y: Y input channel
-//     cb: Cb input channel; scale/biased to be 0..255
-//     cr: Cr input channel; scale/biased to be 0..255
-
-extern void stbi_install_idct(stbi_idct_8x8 func);
-extern void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func);
-#endif // STBI_SIMD
-
-
-#ifdef __cplusplus
-}
-#endif
-
-//
-//
-////   end header file   /////////////////////////////////////////////////////
-#endif // STBI_INCLUDE_STB_IMAGE_H
-
-#ifndef STBI_HEADER_FILE_ONLY
-
-#ifndef STBI_NO_HDR
-#include <math.h>  // ldexp
-#include <string.h> // strcmp, strtok
-#endif
-
-#ifndef STBI_NO_STDIO
-#include <stdio.h>
-#endif
-#include <stdlib.h>
-#include <memory.h>
-#include <assert.h>
-#include <stdarg.h>
-
-#ifndef _MSC_VER
-   #ifdef __cplusplus
-   #define stbi_inline inline
-   #else
-   #define stbi_inline
-   #endif
-#else
-   #define stbi_inline __forceinline
-#endif
-
-typedef unsigned int Uint;
-
-#if defined(STBI_NO_STDIO) && !defined(STBI_NO_WRITE)
-#define STBI_NO_WRITE
-#endif
-
-#define STBI_NOTUSED(v)  (void)sizeof(v)
-
-#ifdef _MSC_VER
-#define STBI_HAS_LROTL
-#endif
-
-#ifdef STBI_HAS_LROTL
-   #define stbi_lrot(x,y)  _lrotl(x,y)
-#else
-   #define stbi_lrot(x,y)  (((x) << (y)) | ((x) >> (32 - (y))))
-#endif
-
-///////////////////////////////////////////////
-//
-//  stbi struct and start_xxx functions
-
-// stbi structure is our basic context used by all images, so it
-// contains all the IO context, plus some basic image information
-typedef struct
-{
-   Uint32 img_x, img_y;
-   int img_n, img_out_n;
-   
-   stbi_io_callbacks io;
-   void *io_user_data;
-
-   int read_from_callbacks;
-   int buflen;
-   Uint8 buffer_start[128];
-
-   Uint8 *img_buffer, *img_buffer_end;
-   Uint8 *img_buffer_original;
-} stbi;
-
-
-static void refill_buffer(stbi *s);
-
-// initialize a memory-decode context
-static void start_mem(stbi *s, Uint8 const *buffer, int len)
-{
-   s->io.read = NULL;
-   s->read_from_callbacks = 0;
-   s->img_buffer = s->img_buffer_original = (Uint8 *) buffer;
-   s->img_buffer_end = (Uint8 *) buffer+len;
-}
-
-// initialize a callback-based context
-static void start_callbacks(stbi *s, stbi_io_callbacks *c, void *user)
-{
-   s->io = *c;
-   s->io_user_data = user;
-   s->buflen = sizeof(s->buffer_start);
-   s->read_from_callbacks = 1;
-   s->img_buffer_original = s->buffer_start;
-   refill_buffer(s);
-}
-
-#ifndef STBI_NO_STDIO
-
-static int stdio_read(void *user, char *data, int size)
-{
-   return (int) fread(data,1,size,(FILE*) user);
-}
-
-static void stdio_skip(void *user, unsigned n)
-{
-   fseek((FILE*) user, n, SEEK_CUR);
-}
-
-static int stdio_eof(void *user)
-{
-   return feof((FILE*) user);
-}
-
-static stbi_io_callbacks stbi_stdio_callbacks =
-{
-   stdio_read,
-   stdio_skip,
-   stdio_eof,
-};
-
-static void start_file(stbi *s, FILE *f)
-{
-   start_callbacks(s, &stbi_stdio_callbacks, (void *) f);
-}
-
-//static void stop_file(stbi *s) { }
-
-#endif // !STBI_NO_STDIO
-
-static void stbi_rewind(stbi *s)
-{
-   // conceptually rewind SHOULD rewind to the beginning of the stream,
-   // but we just rewind to the beginning of the initial buffer, because
-   // we only use it after doing 'test', which only ever looks at at most 92 bytes
-   s->img_buffer = s->img_buffer_original;
-}
-
-static int      stbi_jpeg_test(stbi *s);
-static stbi_uc *stbi_jpeg_load(stbi *s, int *x, int *y, int *comp, int req_comp);
-static int      stbi_jpeg_info(stbi *s, int *x, int *y, int *comp);
-static int      stbi_png_test(stbi *s);
-static stbi_uc *stbi_png_load(stbi *s, int *x, int *y, int *comp, int req_comp);
-static int      stbi_png_info(stbi *s, int *x, int *y, int *comp);
-#ifdef STBI_CRAP_FORMATS
-static int      stbi_bmp_test(stbi *s);
-static stbi_uc *stbi_bmp_load(stbi *s, int *x, int *y, int *comp, int req_comp);
-static int      stbi_tga_test(stbi *s);
-static stbi_uc *stbi_tga_load(stbi *s, int *x, int *y, int *comp, int req_comp);
-static int      stbi_tga_info(stbi *s, int *x, int *y, int *comp);
-static int      stbi_psd_test(stbi *s);
-static stbi_uc *stbi_psd_load(stbi *s, int *x, int *y, int *comp, int req_comp);
-static int      stbi_pic_test(stbi *s);
-static stbi_uc *stbi_pic_load(stbi *s, int *x, int *y, int *comp, int req_comp);
-static int      stbi_gif_test(stbi *s);
-static stbi_uc *stbi_gif_load(stbi *s, int *x, int *y, int *comp, int req_comp);
-static int      stbi_gif_info(stbi *s, int *x, int *y, int *comp);
-#endif
-
-#ifndef STBI_NO_HDR
-static int      stbi_hdr_test(stbi *s);
-static float   *stbi_hdr_load(stbi *s, int *x, int *y, int *comp, int req_comp);
-#endif
-
-// this is not threadsafe
-static const char *failure_reason;
-
-const char *stbi_failure_reason(void)
-{
-   return failure_reason;
-}
-
-static int e(const char *str)
-{
-   failure_reason = str;
-   return 0;
-}
-
-// e - error
-// epf - error returning pointer to float
-// epuc - error returning pointer to unsigned char
-
-#ifdef STBI_NO_FAILURE_STRINGS
-   #define e(x,y)  0
-#elif defined(STBI_FAILURE_USERMSG)
-   #define e(x,y)  e(y)
-#else
-   #define e(x,y)  e(x)
-#endif
-
-#define epf(x,y)   ((float *) (e(x,y)?NULL:NULL))
-#define epuc(x,y)  ((unsigned char *) (e(x,y)?NULL:NULL))
-
-void stbi_image_free(void *retval_from_stbi_load)
-{
-   free(retval_from_stbi_load);
-}
-
-#ifndef STBI_NO_HDR
-static float   *ldr_to_hdr(stbi_uc *data, int x, int y, int comp);
-static stbi_uc *hdr_to_ldr(float   *data, int x, int y, int comp);
-#endif
-
-static unsigned char *stbi_load_main(stbi *s, int *x, int *y, int *comp, int req_comp)
-{
-   if (stbi_jpeg_test(s)) return stbi_jpeg_load(s,x,y,comp,req_comp);
-   if (stbi_png_test(s))  return stbi_png_load(s,x,y,comp,req_comp);
-#ifdef STBI_CRAP_FORMATS
-   if (stbi_bmp_test(s))  return stbi_bmp_load(s,x,y,comp,req_comp);
-   if (stbi_gif_test(s))  return stbi_gif_load(s,x,y,comp,req_comp);
-   if (stbi_psd_test(s))  return stbi_psd_load(s,x,y,comp,req_comp);
-   if (stbi_pic_test(s))  return stbi_pic_load(s,x,y,comp,req_comp);
-#endif
-
-   #ifndef STBI_NO_HDR
-   if (stbi_hdr_test(s)) {
-      float *hdr = stbi_hdr_load(s, x,y,comp,req_comp);
-      return hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp);
-   }
-   #endif
-
-#ifdef STBI_CRAP_FORMATS
-   // test tga last because it's a crappy test!
-   if (stbi_tga_test(s))
-      return stbi_tga_load(s,x,y,comp,req_comp);
-#endif
-
-   return epuc("unknown image type", "Image not of any known type, or corrupt");
-}
-
-#ifndef STBI_NO_STDIO
-unsigned char *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp)
-{
-   FILE *f = fopen(filename, "rb");
-   unsigned char *result;
-   if (!f) return epuc("can't fopen", "Unable to open file");
-   result = stbi_load_from_file(f,x,y,comp,req_comp);
-   fclose(f);
-   return result;
-}
-
-unsigned char *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)
-{
-   stbi s;
-   start_file(&s,f);
-   return stbi_load_main(&s,x,y,comp,req_comp);
-}
-#endif //!STBI_NO_STDIO
-
-unsigned char *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
-{
-   stbi s;
-   start_mem(&s,buffer,len);
-   return stbi_load_main(&s,x,y,comp,req_comp);
-}
-
-unsigned char *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
-{
-   stbi s;
-   start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
-   return stbi_load_main(&s,x,y,comp,req_comp);
-}
-
-#ifndef STBI_NO_HDR
-
-float *stbi_loadf_main(stbi *s, int *x, int *y, int *comp, int req_comp)
-{
-   unsigned char *data;
-   #ifndef STBI_NO_HDR
-   if (stbi_hdr_test(s))
-      return stbi_hdr_load(s,x,y,comp,req_comp);
-   #endif
-   data = stbi_load_main(s, x, y, comp, req_comp);
-   if (data)
-      return ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp);
-   return epf("unknown image type", "Image not of any known type, or corrupt");
-}
-
-float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
-{
-   stbi s;
-   start_mem(&s,buffer,len);
-   return stbi_loadf_main(&s,x,y,comp,req_comp);
-}
-
-float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
-{
-   stbi s;
-   start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
-   return stbi_loadf_main(&s,x,y,comp,req_comp);
-}
-
-#ifndef STBI_NO_STDIO
-float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp)
-{
-   FILE *f = fopen(filename, "rb");
-   float *result;
-   if (!f) return epf("can't fopen", "Unable to open file");
-   result = stbi_loadf_from_file(f,x,y,comp,req_comp);
-   fclose(f);
-   return result;
-}
-
-float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)
-{
-   stbi s;
-   start_file(&s,f);
-   return stbi_loadf_main(&s,x,y,comp,req_comp);
-}
-#endif // !STBI_NO_STDIO
-
-#endif // !STBI_NO_HDR
-
-// these is-hdr-or-not is defined independent of whether STBI_NO_HDR is
-// defined, for API simplicity; if STBI_NO_HDR is defined, it always
-// reports false!
-
-int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len)
-{
-   #ifndef STBI_NO_HDR
-   stbi s;
-   start_mem(&s,buffer,len);
-   return stbi_hdr_test(&s);
-   #else
-   STBI_NOTUSED(buffer);
-   STBI_NOTUSED(len);
-   return 0;
-   #endif
-}
-
-#ifndef STBI_NO_STDIO
-extern int      stbi_is_hdr          (char const *filename)
-{
-   FILE *f = fopen(filename, "rb");
-   int result=0;
-   if (f) {
-      result = stbi_is_hdr_from_file(f);
-      fclose(f);
-   }
-   return result;
-}
-
-extern int      stbi_is_hdr_from_file(FILE *f)
-{
-   #ifndef STBI_NO_HDR
-   stbi s;
-   start_file(&s,f);
-   return stbi_hdr_test(&s);
-   #else
-   return 0;
-   #endif
-}
-#endif // !STBI_NO_STDIO
-
-extern int      stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user)
-{
-   #ifndef STBI_NO_HDR
-   stbi s;
-   start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
-   return stbi_hdr_test(&s);
-   #else
-   (void) clbk;
-   (void) user;
-   return 0;
-   #endif
-}
-
-#ifndef STBI_NO_HDR
-static float h2l_gamma_i=1.0f/2.2f, h2l_scale_i=1.0f;
-static float l2h_gamma=2.2f, l2h_scale=1.0f;
-
-void   stbi_hdr_to_ldr_gamma(float gamma) { h2l_gamma_i = 1/gamma; }
-void   stbi_hdr_to_ldr_scale(float scale) { h2l_scale_i = 1/scale; }
-
-void   stbi_ldr_to_hdr_gamma(float gamma) { l2h_gamma = gamma; }
-void   stbi_ldr_to_hdr_scale(float scale) { l2h_scale = scale; }
-#endif
-
-
-//////////////////////////////////////////////////////////////////////////////
-//
-// Common code used by all image loaders
-//
-
-enum
-{
-   SCAN_load=0,
-   SCAN_type,
-   SCAN_header
-};
-
-static void refill_buffer(stbi *s)
-{
-   int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen);
-   if (n == 0) {
-      // at end of file, treat same as if from memory
-      s->read_from_callbacks = 0;
-      s->img_buffer = s->img_buffer_end-1;
-      *s->img_buffer = 0;
-   } else {
-      s->img_buffer = s->buffer_start;
-      s->img_buffer_end = s->buffer_start + n;
-   }
-}
-
-stbi_inline static int get8(stbi *s)
-{
-   if (s->img_buffer < s->img_buffer_end)
-      return *s->img_buffer++;
-   if (s->read_from_callbacks) {
-      refill_buffer(s);
-      return *s->img_buffer++;
-   }
-   return 0;
-}
-
-stbi_inline static int at_eof(stbi *s)
-{
-   if (s->io.read) {
-      if (!(s->io.eof)(s->io_user_data)) return 0;
-      // if feof() is true, check if buffer = end
-      // special case: we've only got the special 0 character at the end
-      if (s->read_from_callbacks == 0) return 1;
-   }
-
-   return s->img_buffer >= s->img_buffer_end;   
-}
-
-stbi_inline static Uint8 get8u(stbi *s)
-{
-   return (Uint8) get8(s);
-}
-
-static void skip(stbi *s, int n)
-{
-   if (s->io.read) {
-      int blen = s->img_buffer_end - s->img_buffer;
-      if (blen < n) {
-         s->img_buffer = s->img_buffer_end;
-         (s->io.skip)(s->io_user_data, n - blen);
-         return;
-      }
-   }
-   s->img_buffer += n;
-}
-
-static int getn(stbi *s, stbi_uc *buffer, int n)
-{
-   if (s->io.read) {
-      int blen = s->img_buffer_end - s->img_buffer;
-      if (blen < n) {
-         int res, count;
-
-         memcpy(buffer, s->img_buffer, blen);
-         
-         count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen);
-         res = (count == (n-blen));
-         s->img_buffer = s->img_buffer_end;
-         return res;
-      }
-   }
-
-   if (s->img_buffer+n <= s->img_buffer_end) {
-      memcpy(buffer, s->img_buffer, n);
-      s->img_buffer += n;
-      return 1;
-   } else
-      return 0;
-}
-
-static int get16(stbi *s)
-{
-   int z = get8(s);
-   return (z << 8) + get8(s);
-}
-
-static Uint32 get32(stbi *s)
-{
-   Uint32 z = get16(s);
-   return (z << 16) + get16(s);
-}
-
-#ifdef STBI_CRAP_FORMATS
-static int get16le(stbi *s)
-{
-   int z = get8(s);
-   return z + (get8(s) << 8);
-}
-
-static Uint32 get32le(stbi *s)
-{
-   Uint32 z = get16le(s);
-   return z + (get16le(s) << 16);
-}
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-//
-//  generic converter from built-in img_n to req_comp
-//    individual types do this automatically as much as possible (e.g. jpeg
-//    does all cases internally since it needs to colorspace convert anyway,
-//    and it never has alpha, so very few cases ). png can automatically
-//    interleave an alpha=255 channel, but falls back to this for other cases
-//
-//  assume data buffer is malloced, so malloc a new one and free that one
-//  only failure mode is malloc failing
-
-static Uint8 compute_y(int r, int g, int b)
-{
-   return (Uint8) (((r*77) + (g*150) +  (29*b)) >> 8);
-}
-
-static unsigned char *convert_format(unsigned char *data, int img_n, int req_comp, Uint x, Uint y)
-{
-   int i,j;
-   unsigned char *good;
-
-   if (req_comp == img_n) return data;
-   assert(req_comp >= 1 && req_comp <= 4);
-
-   good = (unsigned char *) malloc(req_comp * x * y);
-   if (good == NULL) {
-      free(data);
-      return epuc("outofmem", "Out of memory");
-   }
-
-   for (j=0; j < (int) y; ++j) {
-      unsigned char *src  = data + j * x * img_n   ;
-      unsigned char *dest = good + j * x * req_comp;
-
-      #define COMBO(a,b)  ((a)*8+(b))
-      #define CASE(a,b)   case COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
-      // convert source image with img_n components to one with req_comp components;
-      // avoid switch per pixel, so use switch per scanline and massive macros
-      switch (COMBO(img_n, req_comp)) {
-         CASE(1,2) dest[0]=src[0], dest[1]=255; break;
-         CASE(1,3) dest[0]=dest[1]=dest[2]=src[0]; break;
-         CASE(1,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; break;
-         CASE(2,1) dest[0]=src[0]; break;
-         CASE(2,3) dest[0]=dest[1]=dest[2]=src[0]; break;
-         CASE(2,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; break;
-         CASE(3,4) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; break;
-         CASE(3,1) dest[0]=compute_y(src[0],src[1],src[2]); break;
-         CASE(3,2) dest[0]=compute_y(src[0],src[1],src[2]), dest[1] = 255; break;
-         CASE(4,1) dest[0]=compute_y(src[0],src[1],src[2]); break;
-         CASE(4,2) dest[0]=compute_y(src[0],src[1],src[2]), dest[1] = src[3]; break;
-         CASE(4,3) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; break;
-         default: assert(0);
-      }
-      #undef CASE
-   }
-
-   free(data);
-   return good;
-}
-
-#ifndef STBI_NO_HDR
-static float   *ldr_to_hdr(stbi_uc *data, int x, int y, int comp)
-{
-   int i,k,n;
-   float *output = (float *) malloc(x * y * comp * sizeof(float));
-   if (output == NULL) { free(data); return epf("outofmem", "Out of memory"); }
-   // compute number of non-alpha components
-   if (comp & 1) n = comp; else n = comp-1;
-   for (i=0; i < x*y; ++i) {
-      for (k=0; k < n; ++k) {
-         output[i*comp + k] = (float) pow(data[i*comp+k]/255.0f, l2h_gamma) * l2h_scale;
-      }
-      if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f;
-   }
-   free(data);
-   return output;
-}
-
-#define float2int(x)   ((int) (x))
-static stbi_uc *hdr_to_ldr(float   *data, int x, int y, int comp)
-{
-   int i,k,n;
-   stbi_uc *output = (stbi_uc *) malloc(x * y * comp);
-   if (output == NULL) { free(data); return epuc("outofmem", "Out of memory"); }
-   // compute number of non-alpha components
-   if (comp & 1) n = comp; else n = comp-1;
-   for (i=0; i < x*y; ++i) {
-      for (k=0; k < n; ++k) {
-         float z = (float) pow(data[i*comp+k]*h2l_scale_i, h2l_gamma_i) * 255 + 0.5f;
-         if (z < 0) z = 0;
-         if (z > 255) z = 255;
-         output[i*comp + k] = (Uint8) float2int(z);
-      }
-      if (k < comp) {
-         float z = data[i*comp+k] * 255 + 0.5f;
-         if (z < 0) z = 0;
-         if (z > 255) z = 255;
-         output[i*comp + k] = (Uint8) float2int(z);
-      }
-   }
-   free(data);
-   return output;
-}
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-//
-//  "baseline" JPEG/JFIF decoder (not actually fully baseline implementation)
-//
-//    simple implementation
-//      - channel subsampling of at most 2 in each dimension
-//      - doesn't support delayed output of y-dimension
-//      - simple interface (only one output format: 8-bit interleaved RGB)
-//      - doesn't try to recover corrupt jpegs
-//      - doesn't allow partial loading, loading multiple at once
-//      - still fast on x86 (copying globals into locals doesn't help x86)
-//      - allocates lots of intermediate memory (full size of all components)
-//        - non-interleaved case requires this anyway
-//        - allows good upsampling (see next)
-//    high-quality
-//      - upsampled channels are bilinearly interpolated, even across blocks
-//      - quality integer IDCT derived from IJG's 'slow'
-//    performance
-//      - fast huffman; reasonable integer IDCT
-//      - uses a lot of intermediate memory, could cache poorly
-//      - load http://nothings.org/remote/anemones.jpg 3 times on 2.8Ghz P4
-//          stb_jpeg:   1.34 seconds (MSVC6, default release build)
-//          stb_jpeg:   1.06 seconds (MSVC6, processor = Pentium Pro)
-//          IJL11.dll:  1.08 seconds (compiled by intel)
-//          IJG 1998:   0.98 seconds (MSVC6, makefile provided by IJG)
-//          IJG 1998:   0.95 seconds (MSVC6, makefile + proc=PPro)
-
-// huffman decoding acceleration
-#define FAST_BITS   9  // larger handles more cases; smaller stomps less cache
-
-typedef struct
-{
-   Uint8  fast[1 << FAST_BITS];
-   // weirdly, repacking this into AoS is a 10% speed loss, instead of a win
-   Uint16 code[256];
-   Uint8  values[256];
-   Uint8  size[257];
-   unsigned int maxcode[18];
-   int    delta[17];   // old 'firstsymbol' - old 'firstcode'
-} huffman;
-
-typedef struct
-{
-   #ifdef STBI_SIMD
-   Uint16 dequant2[4][64];
-   #endif
-   stbi *s;
-   huffman huff_dc[4];
-   huffman huff_ac[4];
-   Uint8 dequant[4][64];
-
-// sizes for components, interleaved MCUs
-   int img_h_max, img_v_max;
-   int img_mcu_x, img_mcu_y;
-   int img_mcu_w, img_mcu_h;
-
-// definition of jpeg image component
-   struct
-   {
-      int id;
-      int h,v;
-      int tq;
-      int hd,ha;
-      int dc_pred;
-
-      int x,y,w2,h2;
-      Uint8 *data;
-      void *raw_data;
-      Uint8 *linebuf;
-   } img_comp[4];
-
-   Uint32         code_buffer; // jpeg entropy-coded buffer
-   int            code_bits;   // number of valid bits
-   unsigned char  marker;      // marker seen while filling entropy buffer
-   int            nomore;      // flag if we saw a marker so must stop
-
-   int scan_n, order[4];
-   int restart_interval, todo;
-} jpeg;
-
-static int build_huffman(huffman *h, int *count)
-{
-   int i,j,k=0,code;
-   // build size list for each symbol (from JPEG spec)
-   for (i=0; i < 16; ++i)
-      for (j=0; j < count[i]; ++j)
-         h->size[k++] = (Uint8) (i+1);
-   h->size[k] = 0;
-
-   // compute actual symbols (from jpeg spec)
-   code = 0;
-   k = 0;
-   for(j=1; j <= 16; ++j) {
-      // compute delta to add to code to compute symbol id
-      h->delta[j] = k - code;
-      if (h->size[k] == j) {
-         while (h->size[k] == j)
-            h->code[k++] = (Uint16) (code++);
-         if (code-1 >= (1 << j)) return e("bad code lengths","Corrupt JPEG");
-      }
-      // compute largest code + 1 for this size, preshifted as needed later
-      h->maxcode[j] = code << (16-j);
-      code <<= 1;
-   }
-   h->maxcode[j] = 0xffffffff;
-
-   // build non-spec acceleration table; 255 is flag for not-accelerated
-   memset(h->fast, 255, 1 << FAST_BITS);
-   for (i=0; i < k; ++i) {
-      int s = h->size[i];
-      if (s <= FAST_BITS) {
-         int c = h->code[i] << (FAST_BITS-s);
-         int m = 1 << (FAST_BITS-s);
-         for (j=0; j < m; ++j) {
-            h->fast[c+j] = (Uint8) i;
-         }
-      }
-   }
-   return 1;
-}
-
-static void grow_buffer_unsafe(jpeg *j)
-{
-   do {
-      int b = j->nomore ? 0 : get8(j->s);
-      if (b == 0xff) {
-         int c = get8(j->s);
-         if (c != 0) {
-            j->marker = (unsigned char) c;
-            j->nomore = 1;
-            return;
-         }
-      }
-      j->code_buffer |= b << (24 - j->code_bits);
-      j->code_bits += 8;
-   } while (j->code_bits <= 24);
-}
-
-// (1 << n) - 1
-static Uint32 bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};
-
-// decode a jpeg huffman value from the bitstream
-stbi_inline static int decode(jpeg *j, huffman *h)
-{
-   unsigned int temp;
-   int c,k;
-
-   if (j->code_bits < 16) grow_buffer_unsafe(j);
-
-   // look at the top FAST_BITS and determine what symbol ID it is,
-   // if the code is <= FAST_BITS
-   c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
-   k = h->fast[c];
-   if (k < 255) {
-      int s = h->size[k];
-      if (s > j->code_bits)
-         return -1;
-      j->code_buffer <<= s;
-      j->code_bits -= s;
-      return h->values[k];
-   }
-
-   // naive test is to shift the code_buffer down so k bits are
-   // valid, then test against maxcode. To speed this up, we've
-   // preshifted maxcode left so that it has (16-k) 0s at the
-   // end; in other words, regardless of the number of bits, it
-   // wants to be compared against something shifted to have 16;
-   // that way we don't need to shift inside the loop.
-   temp = j->code_buffer >> 16;
-   for (k=FAST_BITS+1 ; ; ++k)
-      if (temp < h->maxcode[k])
-         break;
-   if (k == 17) {
-      // error! code not found
-      j->code_bits -= 16;
-      return -1;
-   }
-
-   if (k > j->code_bits)
-      return -1;
-
-   // convert the huffman code to the symbol id
-   c = ((j->code_buffer >> (32 - k)) & bmask[k]) + h->delta[k];
-   assert((((j->code_buffer) >> (32 - h->size[c])) & bmask[h->size[c]]) == h->code[c]);
-
-   // convert the id to a symbol
-   j->code_bits -= k;
-   j->code_buffer <<= k;
-   return h->values[c];
-}
-
-// combined JPEG 'receive' and JPEG 'extend', since baseline
-// always extends everything it receives.
-stbi_inline static int extend_receive(jpeg *j, int n)
-{
-   unsigned int m = 1 << (n-1);
-   unsigned int k;
-   if (j->code_bits < n) grow_buffer_unsafe(j);
-
-   #if 1
-   k = stbi_lrot(j->code_buffer, n);
-   j->code_buffer = k & ~bmask[n];
-   k &= bmask[n];
-   j->code_bits -= n;
-   #else
-   k = (j->code_buffer >> (32 - n)) & bmask[n];
-   j->code_bits -= n;
-   j->code_buffer <<= n;
-   #endif
-   // the following test is probably a random branch that won't
-   // predict well. I tried to table accelerate it but failed.
-   // maybe it's compiling as a conditional move?
-   if (k < m)
-      return (-1 << n) + k + 1;
-   else
-      return k;
-}
-
-// given a value that's at position X in the zigzag stream,
-// where does it appear in the 8x8 matrix coded as row-major?
-static Uint8 dezigzag[64+15] =
-{
-    0,  1,  8, 16,  9,  2,  3, 10,
-   17, 24, 32, 25, 18, 11,  4,  5,
-   12, 19, 26, 33, 40, 48, 41, 34,
-   27, 20, 13,  6,  7, 14, 21, 28,
-   35, 42, 49, 56, 57, 50, 43, 36,
-   29, 22, 15, 23, 30, 37, 44, 51,
-   58, 59, 52, 45, 38, 31, 39, 46,
-   53, 60, 61, 54, 47, 55, 62, 63,
-   // let corrupt input sample past end
-   63, 63, 63, 63, 63, 63, 63, 63,
-   63, 63, 63, 63, 63, 63, 63
-};
-
-// decode one 64-entry block--
-static int decode_block(jpeg *j, Sint16 data[64], huffman *hdc, huffman *hac, int b)
-{
-   int diff,dc,k;
-   int t = decode(j, hdc);
-   if (t < 0) return e("bad huffman code","Corrupt JPEG");
-
-   // 0 all the ac values now so we can do it 32-bits at a time
-   memset(data,0,64*sizeof(data[0]));
-
-   diff = t ? extend_receive(j, t) : 0;
-   dc = j->img_comp[b].dc_pred + diff;
-   j->img_comp[b].dc_pred = dc;
-   data[0] = (Sint16) dc;
-
-   // decode AC components, see JPEG spec
-   k = 1;
-   do {
-      int r,s;
-      int rs = decode(j, hac);
-      if (rs < 0) return e("bad huffman code","Corrupt JPEG");
-      s = rs & 15;
-      r = rs >> 4;
-      if (s == 0) {
-         if (rs != 0xf0) break; // end block
-         k += 16;
-      } else {
-         k += r;
-         // decode into unzigzag'd location
-         data[dezigzag[k++]] = (Sint16) extend_receive(j,s);
-      }
-   } while (k < 64);
-   return 1;
-}
-
-// take a -128..127 value and clamp it and convert to 0..255
-stbi_inline static Uint8 clamp(int x)
-{
-   // trick to use a single test to catch both cases
-   if ((unsigned int) x > 255) {
-      if (x < 0) return 0;
-      if (x > 255) return 255;
-   }
-   return (Uint8) x;
-}
-
-#define f2f(x)  (int) (((x) * 4096 + 0.5))
-#define fsh(x)  ((x) << 12)
-
-// derived from jidctint -- DCT_ISLOW
-#define IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7)       \
-   int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \
-   p2 = s2;                                    \
-   p3 = s6;                                    \
-   p1 = (p2+p3) * f2f(0.5411961f);             \
-   t2 = p1 + p3*f2f(-1.847759065f);            \
-   t3 = p1 + p2*f2f( 0.765366865f);            \
-   p2 = s0;                                    \
-   p3 = s4;                                    \
-   t0 = fsh(p2+p3);                            \
-   t1 = fsh(p2-p3);                            \
-   x0 = t0+t3;                                 \
-   x3 = t0-t3;                                 \
-   x1 = t1+t2;                                 \
-   x2 = t1-t2;                                 \
-   t0 = s7;                                    \
-   t1 = s5;                                    \
-   t2 = s3;                                    \
-   t3 = s1;                                    \
-   p3 = t0+t2;                                 \
-   p4 = t1+t3;                                 \
-   p1 = t0+t3;                                 \
-   p2 = t1+t2;                                 \
-   p5 = (p3+p4)*f2f( 1.175875602f);            \
-   t0 = t0*f2f( 0.298631336f);                 \
-   t1 = t1*f2f( 2.053119869f);                 \
-   t2 = t2*f2f( 3.072711026f);                 \
-   t3 = t3*f2f( 1.501321110f);                 \
-   p1 = p5 + p1*f2f(-0.899976223f);            \
-   p2 = p5 + p2*f2f(-2.562915447f);            \
-   p3 = p3*f2f(-1.961570560f);                 \
-   p4 = p4*f2f(-0.390180644f);                 \
-   t3 += p1+p4;                                \
-   t2 += p2+p3;                                \
-   t1 += p2+p4;                                \
-   t0 += p1+p3;
-
-#ifdef STBI_SIMD
-typedef Uint16 stbi_dequantize_t;
-#else
-typedef Uint8 stbi_dequantize_t;
-#endif
-
-// .344 seconds on 3*anemones.jpg
-static void idct_block(Uint8 *out, int out_stride, Sint16 data[64], stbi_dequantize_t *dequantize)
-{
-   int i,val[64],*v=val;
-   stbi_dequantize_t *dq = dequantize;
-   Uint8 *o;
-   Sint16 *d = data;
-
-   // columns
-   for (i=0; i < 8; ++i,++d,++dq, ++v) {
-      // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing
-      if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0
-           && d[40]==0 && d[48]==0 && d[56]==0) {
-         //    no shortcut                 0     seconds
-         //    (1|2|3|4|5|6|7)==0          0     seconds
-         //    all separate               -0.047 seconds
-         //    1 && 2|3 && 4|5 && 6|7:    -0.047 seconds
-         int dcterm = d[0] * dq[0] << 2;
-         v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;
-      } else {
-         IDCT_1D(d[ 0]*dq[ 0],d[ 8]*dq[ 8],d[16]*dq[16],d[24]*dq[24],
-                 d[32]*dq[32],d[40]*dq[40],d[48]*dq[48],d[56]*dq[56])
-         // constants scaled things up by 1<<12; let's bring them back
-         // down, but keep 2 extra bits of precision
-         x0 += 512; x1 += 512; x2 += 512; x3 += 512;
-         v[ 0] = (x0+t3) >> 10;
-         v[56] = (x0-t3) >> 10;
-         v[ 8] = (x1+t2) >> 10;
-         v[48] = (x1-t2) >> 10;
-         v[16] = (x2+t1) >> 10;
-         v[40] = (x2-t1) >> 10;
-         v[24] = (x3+t0) >> 10;
-         v[32] = (x3-t0) >> 10;
-      }
-   }
-
-   for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) {
-      // no fast case since the first 1D IDCT spread components out
-      IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7])
-      // constants scaled things up by 1<<12, plus we had 1<<2 from first
-      // loop, plus horizontal and vertical each scale by sqrt(8) so together
-      // we've got an extra 1<<3, so 1<<17 total we need to remove.
-      // so we want to round that, which means adding 0.5 * 1<<17,
-      // aka 65536. Also, we'll end up with -128 to 127 that we want
-      // to encode as 0..255 by adding 128, so we'll add that before the shift
-      x0 += 65536 + (128<<17);
-      x1 += 65536 + (128<<17);
-      x2 += 65536 + (128<<17);
-      x3 += 65536 + (128<<17);
-      // tried computing the shifts into temps, or'ing the temps to see
-      // if any were out of range, but that was slower
-      o[0] = clamp((x0+t3) >> 17);
-      o[7] = clamp((x0-t3) >> 17);
-      o[1] = clamp((x1+t2) >> 17);
-      o[6] = clamp((x1-t2) >> 17);
-      o[2] = clamp((x2+t1) >> 17);
-      o[5] = clamp((x2-t1) >> 17);
-      o[3] = clamp((x3+t0) >> 17);
-      o[4] = clamp((x3-t0) >> 17);
-   }
-}
-
-#ifdef STBI_SIMD
-static stbi_idct_8x8 stbi_idct_installed = idct_block;
-
-void stbi_install_idct(stbi_idct_8x8 func)
-{
-   stbi_idct_installed = func;
-}
-#endif
-
-#define MARKER_none  0xff
-// if there's a pending marker from the entropy stream, return that
-// otherwise, fetch from the stream and get a marker. if there's no
-// marker, return 0xff, which is never a valid marker value
-static Uint8 get_marker(jpeg *j)
-{
-   Uint8 x;
-   if (j->marker != MARKER_none) { x = j->marker; j->marker = MARKER_none; return x; }
-   x = get8u(j->s);
-   if (x != 0xff) return MARKER_none;
-   while (x == 0xff)
-      x = get8u(j->s);
-   return x;
-}
-
-// in each scan, we'll have scan_n components, and the order
-// of the components is specified by order[]
-#define RESTART(x)     ((x) >= 0xd0 && (x) <= 0xd7)
-
-// after a restart interval, reset the entropy decoder and
-// the dc prediction
-static void reset(jpeg *j)
-{
-   j->code_bits = 0;
-   j->code_buffer = 0;
-   j->nomore = 0;
-   j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = 0;
-   j->marker = MARKER_none;
-   j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff;
-   // no more than 1<<31 MCUs if no restart_interal? that's plenty safe,
-   // since we don't even allow 1<<30 pixels
-}
-
-static int parse_entropy_coded_data(jpeg *z)
-{
-   reset(z);
-   if (z->scan_n == 1) {
-      int i,j;
-      #ifdef STBI_SIMD
-      __declspec(align(16))
-      #endif
-      Sint16 data[64];
-      int n = z->order[0];
-      // non-interleaved data, we just need to process one block at a time,
-      // in trivial scanline order
-      // number of blocks to do just depends on how many actual "pixels" this
-      // component has, independent of interleaved MCU blocking and such
-      int w = (z->img_comp[n].x+7) >> 3;
-      int h = (z->img_comp[n].y+7) >> 3;
-      for (j=0; j < h; ++j) {
-         for (i=0; i < w; ++i) {
-            if (!decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+z->img_comp[n].ha, n)) return 0;
-            #ifdef STBI_SIMD
-            stbi_idct_installed(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data, z->dequant2[z->img_comp[n].tq]);
-            #else
-            idct_block(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data, z->dequant[z->img_comp[n].tq]);
-            #endif
-            // every data block is an MCU, so countdown the restart interval
-            if (--z->todo <= 0) {
-               if (z->code_bits < 24) grow_buffer_unsafe(z);
-               // if it's NOT a restart, then just bail, so we get corrupt data
-               // rather than no data
-               if (!RESTART(z->marker)) return 1;
-               reset(z);
-            }
-         }
-      }
-   } else { // interleaved!
-      int i,j,k,x,y;
-      Sint16 data[64];
-      for (j=0; j < z->img_mcu_y; ++j) {
-         for (i=0; i < z->img_mcu_x; ++i) {
-            // scan an interleaved mcu... process scan_n components in order
-            for (k=0; k < z->scan_n; ++k) {
-               int n = z->order[k];
-               // scan out an mcu's worth of this component; that's just determined
-               // by the basic H and V specified for the component
-               for (y=0; y < z->img_comp[n].v; ++y) {
-                  for (x=0; x < z->img_comp[n].h; ++x) {
-                     int x2 = (i*z->img_comp[n].h + x)*8;
-                     int y2 = (j*z->img_comp[n].v + y)*8;
-                     if (!decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+z->img_comp[n].ha, n)) return 0;
-                     #ifdef STBI_SIMD
-                     stbi_idct_installed(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data, z->dequant2[z->img_comp[n].tq]);
-                     #else
-                     idct_block(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data, z->dequant[z->img_comp[n].tq]);
-                     #endif
-                  }
-               }
-            }
-            // after all interleaved components, that's an interleaved MCU,
-            // so now count down the restart interval
-            if (--z->todo <= 0) {
-               if (z->code_bits < 24) grow_buffer_unsafe(z);
-               // if it's NOT a restart, then just bail, so we get corrupt data
-               // rather than no data
-               if (!RESTART(z->marker)) return 1;
-               reset(z);
-            }
-         }
-      }
-   }
-   return 1;
-}
-
-static int process_marker(jpeg *z, int m)
-{
-   int L;
-   switch (m) {
-      case MARKER_none: // no marker found
-         return e("expected marker","Corrupt JPEG");
-
-      case 0xC2: // SOF - progressive
-         return e("progressive jpeg","JPEG format not supported (progressive)");
-
-      case 0xDD: // DRI - specify restart interval
-         if (get16(z->s) != 4) return e("bad DRI len","Corrupt JPEG");
-         z->restart_interval = get16(z->s);
-         return 1;
-
-      case 0xDB: // DQT - define quantization table
-         L = get16(z->s)-2;
-         while (L > 0) {
-            int q = get8(z->s);
-            int p = q >> 4;
-            int t = q & 15,i;
-            if (p != 0) return e("bad DQT type","Corrupt JPEG");
-            if (t > 3) return e("bad DQT table","Corrupt JPEG");
-            for (i=0; i < 64; ++i)
-               z->dequant[t][dezigzag[i]] = get8u(z->s);
-            #ifdef STBI_SIMD
-            for (i=0; i < 64; ++i)
-               z->dequant2[t][i] = z->dequant[t][i];
-            #endif
-            L -= 65;
-         }
-         return L==0;
-
-      case 0xC4: // DHT - define huffman table
-         L = get16(z->s)-2;
-         while (L > 0) {
-            Uint8 *v;
-            int sizes[16],i,m=0;
-            int q = get8(z->s);
-            int tc = q >> 4;
-            int th = q & 15;
-            if (tc > 1 || th > 3) return e("bad DHT header","Corrupt JPEG");
-            for (i=0; i < 16; ++i) {
-               sizes[i] = get8(z->s);
-               m += sizes[i];
-            }
-            L -= 17;
-            if (tc == 0) {
-               if (!build_huffman(z->huff_dc+th, sizes)) return 0;
-               v = z->huff_dc[th].values;
-            } else {
-               if (!build_huffman(z->huff_ac+th, sizes)) return 0;
-               v = z->huff_ac[th].values;
-            }
-            for (i=0; i < m; ++i)
-               v[i] = get8u(z->s);
-            L -= m;
-         }
-         return L==0;
-   }
-   // check for comment block or APP blocks
-   if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) {
-      skip(z->s, get16(z->s)-2);
-      return 1;
-   }
-   return 0;
-}
-
-// after we see SOS
-static int process_scan_header(jpeg *z)
-{
-   int i;
-   int Ls = get16(z->s);
-   z->scan_n = get8(z->s);
-   if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return e("bad SOS component count","Corrupt JPEG");
-   if (Ls != 6+2*z->scan_n) return e("bad SOS len","Corrupt JPEG");
-   for (i=0; i < z->scan_n; ++i) {
-      int id = get8(z->s), which;
-      int q = get8(z->s);
-      for (which = 0; which < z->s->img_n; ++which)
-         if (z->img_comp[which].id == id)
-            break;
-      if (which == z->s->img_n) return 0;
-      z->img_comp[which].hd = q >> 4;   if (z->img_comp[which].hd > 3) return e("bad DC huff","Corrupt JPEG");
-      z->img_comp[which].ha = q & 15;   if (z->img_comp[which].ha > 3) return e("bad AC huff","Corrupt JPEG");
-      z->order[i] = which;
-   }
-   if (get8(z->s) != 0) return e("bad SOS","Corrupt JPEG");
-   get8(z->s); // should be 63, but might be 0
-   if (get8(z->s) != 0) return e("bad SOS","Corrupt JPEG");
-
-   return 1;
-}
-
-static int process_frame_header(jpeg *z, int scan)
-{
-   stbi *s = z->s;
-   int Lf,p,i,q, h_max=1,v_max=1,c;
-   Lf = get16(s);         if (Lf < 11) return e("bad SOF len","Corrupt JPEG"); // JPEG
-   p  = get8(s);          if (p != 8) return e("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline
-   s->img_y = get16(s);   if (s->img_y == 0) return e("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG
-   s->img_x = get16(s);   if (s->img_x == 0) return e("0 width","Corrupt JPEG"); // JPEG requires
-   c = get8(s);
-   if (c != 3 && c != 1) return e("bad component count","Corrupt JPEG");    // JFIF requires
-   s->img_n = c;
-   for (i=0; i < c; ++i) {
-      z->img_comp[i].data = NULL;
-      z->img_comp[i].linebuf = NULL;
-   }
-
-   if (Lf != 8+3*s->img_n) return e("bad SOF len","Corrupt JPEG");
-
-   for (i=0; i < s->img_n; ++i) {
-      z->img_comp[i].id = get8(s);
-      if (z->img_comp[i].id != i+1)   // JFIF requires
-         if (z->img_comp[i].id != i)  // some version of jpegtran outputs non-JFIF-compliant files!
-            return e("bad component ID","Corrupt JPEG");
-      q = get8(s);
-      z->img_comp[i].h = (q >> 4);  if (!z->img_comp[i].h || z->img_comp[i].h > 4) return e("bad H","Corrupt JPEG");
-      z->img_comp[i].v = q & 15;    if (!z->img_comp[i].v || z->img_comp[i].v > 4) return e("bad V","Corrupt JPEG");
-      z->img_comp[i].tq = get8(s);  if (z->img_comp[i].tq > 3) return e("bad TQ","Corrupt JPEG");
-   }
-
-   if (scan != SCAN_load) return 1;
-
-   if ((1 << 30) / s->img_x / s->img_n < s->img_y) return e("too large", "Image too large to decode");
-
-   for (i=0; i < s->img_n; ++i) {
-      if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h;
-      if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v;
-   }
-
-   // compute interleaved mcu info
-   z->img_h_max = h_max;
-   z->img_v_max = v_max;
-   z->img_mcu_w = h_max * 8;
-   z->img_mcu_h = v_max * 8;
-   z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w;
-   z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h;
-
-   for (i=0; i < s->img_n; ++i) {
-      // number of effective pixels (e.g. for non-interleaved MCU)
-      z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max;
-      z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max;
-      // to simplify generation, we'll allocate enough memory to decode
-      // the bogus oversized data from using interleaved MCUs and their
-      // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't
-      // discard the extra data until colorspace conversion
-      z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8;
-      z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8;
-      z->img_comp[i].raw_data = malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15);
-      if (z->img_comp[i].raw_data == NULL) {
-         for(--i; i >= 0; --i) {
-            free(z->img_comp[i].raw_data);
-            z->img_comp[i].data = NULL;
-         }
-         return e("outofmem", "Out of memory");
-      }
-      // align blocks for installable-idct using mmx/sse
-      z->img_comp[i].data = (Uint8*) (((size_t) z->img_comp[i].raw_data + 15) & ~15);
-      z->img_comp[i].linebuf = NULL;
-   }
-
-   return 1;
-}
-
-// use comparisons since in some cases we handle more than one case (e.g. SOF)
-#define DNL(x)         ((x) == 0xdc)
-#define SOI(x)         ((x) == 0xd8)
-#define EOI(x)         ((x) == 0xd9)
-#define SOF(x)         ((x) == 0xc0 || (x) == 0xc1)
-#define SOS(x)         ((x) == 0xda)
-
-static int decode_jpeg_header(jpeg *z, int scan)
-{
-   int m;
-   z->marker = MARKER_none; // initialize cached marker to empty
-   m = get_marker(z);
-   if (!SOI(m)) return e("no SOI","Corrupt JPEG");
-   if (scan == SCAN_type) return 1;
-   m = get_marker(z);
-   while (!SOF(m)) {
-      if (!process_marker(z,m)) return 0;
-      m = get_marker(z);
-      while (m == MARKER_none) {
-         // some files have extra padding after their blocks, so ok, we'll scan
-         if (at_eof(z->s)) return e("no SOF", "Corrupt JPEG");
-         m = get_marker(z);
-      }
-   }
-   if (!process_frame_header(z, scan)) return 0;
-   return 1;
-}
-
-static int decode_jpeg_image(jpeg *j)
-{
-   int m;
-   j->restart_interval = 0;
-   if (!decode_jpeg_header(j, SCAN_load)) return 0;
-   m = get_marker(j);
-   while (!EOI(m)) {
-      if (SOS(m)) {
-         if (!process_scan_header(j)) return 0;
-         if (!parse_entropy_coded_data(j)) return 0;
-         if (j->marker == MARKER_none ) {
-            // handle 0s at the end of image data from IP Kamera 9060
-            while (!at_eof(j->s)) {
-               int x = get8(j->s);
-               if (x == 255) {
-                  j->marker = get8u(j->s);
-                  break;
-               } else if (x != 0) {
-                  return 0;
-               }
-            }
-            // if we reach eof without hitting a marker, get_marker() below will fail and we'll eventually return 0
-         }
-      } else {
-         if (!process_marker(j, m)) return 0;
-      }
-      m = get_marker(j);
-   }
-   return 1;
-}
-
-// static jfif-centered resampling (across block boundaries)
-
-typedef Uint8 *(*resample_row_func)(Uint8 *out, Uint8 *in0, Uint8 *in1,
-                                    int w, int hs);
-
-#define div4(x) ((Uint8) ((x) >> 2))
-
-static Uint8 *resample_row_1(Uint8 *out, Uint8 *in_near, Uint8 *in_far, int w, int hs)
-{
-   STBI_NOTUSED(out);
-   STBI_NOTUSED(in_far);
-   STBI_NOTUSED(w);
-   STBI_NOTUSED(hs);
-   return in_near;
-}
-
-static Uint8* resample_row_v_2(Uint8 *out, Uint8 *in_near, Uint8 *in_far, int w, int hs)
-{
-   // need to generate two samples vertically for every one in input
-   int i;
-   STBI_NOTUSED(hs);
-   for (i=0; i < w; ++i)
-      out[i] = div4(3*in_near[i] + in_far[i] + 2);
-   return out;
-}
-
-static Uint8*  resample_row_h_2(Uint8 *out, Uint8 *in_near, Uint8 *in_far, int w, int hs)
-{
-   // need to generate two samples horizontally for every one in input
-   int i;
-   Uint8 *input = in_near;
-
-   if (w == 1) {
-      // if only one sample, can't do any interpolation
-      out[0] = out[1] = input[0];
-      return out;
-   }
-
-   out[0] = input[0];
-   out[1] = div4(input[0]*3 + input[1] + 2);
-   for (i=1; i < w-1; ++i) {
-      int n = 3*input[i]+2;
-      out[i*2+0] = div4(n+input[i-1]);
-      out[i*2+1] = div4(n+input[i+1]);
-   }
-   out[i*2+0] = div4(input[w-2]*3 + input[w-1] + 2);
-   out[i*2+1] = input[w-1];
-
-   STBI_NOTUSED(in_far);
-   STBI_NOTUSED(hs);
-
-   return out;
-}
-
-#define div16(x) ((Uint8) ((x) >> 4))
-
-static Uint8 *resample_row_hv_2(Uint8 *out, Uint8 *in_near, Uint8 *in_far, int w, int hs)
-{
-   // need to generate 2x2 samples for every one in input
-   int i,t0,t1;
-   if (w == 1) {
-      out[0] = out[1] = div4(3*in_near[0] + in_far[0] + 2);
-      return out;
-   }
-
-   t1 = 3*in_near[0] + in_far[0];
-   out[0] = div4(t1+2);
-   for (i=1; i < w; ++i) {
-      t0 = t1;
-      t1 = 3*in_near[i]+in_far[i];
-      out[i*2-1] = div16(3*t0 + t1 + 8);
-      out[i*2  ] = div16(3*t1 + t0 + 8);
-   }
-   out[w*2-1] = div4(t1+2);
-
-   STBI_NOTUSED(hs);
-
-   return out;
-}
-
-static Uint8 *resample_row_generic(Uint8 *out, Uint8 *in_near, Uint8 *in_far, int w, int hs)
-{
-   // resample with nearest-neighbor
-   int i,j;
-   (void) in_far;
-   for (i=0; i < w; ++i)
-      for (j=0; j < hs; ++j)
-         out[i*hs+j] = in_near[i];
-   return out;
-}
-
-#define float2fixed(x)  ((int) ((x) * 65536 + 0.5))
-
-// 0.38 seconds on 3*anemones.jpg   (0.25 with processor = Pro)
-// VC6 without processor=Pro is generating multiple LEAs per multiply!
-static void YCbCr_to_RGB_row(Uint8 *out, const Uint8 *y, const Uint8 *pcb, const Uint8 *pcr, int count, int step)
-{
-   int i;
-   for (i=0; i < count; ++i) {
-      int y_fixed = (y[i] << 16) + 32768; // rounding
-      int r,g,b;
-      int cr = pcr[i] - 128;
-      int cb = pcb[i] - 128;
-      r = y_fixed + cr*float2fixed(1.40200f);
-      g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f);
-      b = y_fixed                            + cb*float2fixed(1.77200f);
-      r >>= 16;
-      g >>= 16;
-      b >>= 16;
-      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }
-      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }
-      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }
-      out[0] = (Uint8)r;
-      out[1] = (Uint8)g;
-      out[2] = (Uint8)b;
-      out[3] = 255;
-      out += step;
-   }
-}
-
-#ifdef STBI_SIMD
-static stbi_YCbCr_to_RGB_run stbi_YCbCr_installed = YCbCr_to_RGB_row;
-
-void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func)
-{
-   stbi_YCbCr_installed = func;
-}
-#endif
-
-
-// clean up the temporary component buffers
-static void cleanup_jpeg(jpeg *j)
-{
-   int i;
-   for (i=0; i < j->s->img_n; ++i) {
-      if (j->img_comp[i].data) {
-         free(j->img_comp[i].raw_data);
-         j->img_comp[i].data = NULL;
-      }
-      if (j->img_comp[i].linebuf) {
-         free(j->img_comp[i].linebuf);
-         j->img_comp[i].linebuf = NULL;
-      }
-   }
-}
-
-typedef struct
-{
-   resample_row_func resample;
-   Uint8 *line0,*line1;
-   int hs,vs;   // expansion factor in each axis
-   int w_lores; // horizontal pixels pre-expansion 
-   int ystep;   // how far through vertical expansion we are
-   int ypos;    // which pre-expansion row we're on
-} stbi_resample;
-
-static Uint8 *load_jpeg_image(jpeg *z, int *out_x, int *out_y, int *comp, int req_comp)
-{
-   int n, decode_n;
-   // validate req_comp
-   if (req_comp < 0 || req_comp > 4) return epuc("bad req_comp", "Internal error");
-   z->s->img_n = 0;
-
-   // load a jpeg image from whichever source
-   if (!decode_jpeg_image(z)) { cleanup_jpeg(z); return NULL; }
-
-   // determine actual number of components to generate
-   n = req_comp ? req_comp : z->s->img_n;
-
-   if (z->s->img_n == 3 && n < 3)
-      decode_n = 1;
-   else
-      decode_n = z->s->img_n;
-
-   // resample and color-convert
-   {
-      int k;
-      Uint i,j;
-      Uint8 *output;
-      Uint8 *coutput[4];
-
-      stbi_resample res_comp[4];
-
-      for (k=0; k < decode_n; ++k) {
-         stbi_resample *r = &res_comp[k];
-
-         // allocate line buffer big enough for upsampling off the edges
-         // with upsample factor of 4
-         z->img_comp[k].linebuf = (Uint8 *) malloc(z->s->img_x + 3);
-         if (!z->img_comp[k].linebuf) { cleanup_jpeg(z); return epuc("outofmem", "Out of memory"); }
-
-         r->hs      = z->img_h_max / z->img_comp[k].h;
-         r->vs      = z->img_v_max / z->img_comp[k].v;
-         r->ystep   = r->vs >> 1;
-         r->w_lores = (z->s->img_x + r->hs-1) / r->hs;
-         r->ypos    = 0;
-         r->line0   = r->line1 = z->img_comp[k].data;
-
-         if      (r->hs == 1 && r->vs == 1) r->resample = resample_row_1;
-         else if (r->hs == 1 && r->vs == 2) r->resample = resample_row_v_2;
-         else if (r->hs == 2 && r->vs == 1) r->resample = resample_row_h_2;
-         else if (r->hs == 2 && r->vs == 2) r->resample = resample_row_hv_2;
-         else                               r->resample = resample_row_generic;
-      }
-
-      // can't error after this so, this is safe
-      output = (Uint8 *) malloc(n * z->s->img_x * z->s->img_y + 1);
-      if (!output) { cleanup_jpeg(z); return epuc("outofmem", "Out of memory"); }
-
-      // now go ahead and resample
-      for (j=0; j < z->s->img_y; ++j) {
-         Uint8 *out = output + n * z->s->img_x * j;
-         for (k=0; k < decode_n; ++k) {
-            stbi_resample *r = &res_comp[k];
-            int y_bot = r->ystep >= (r->vs >> 1);
-            coutput[k] = r->resample(z->img_comp[k].linebuf,
-                                     y_bot ? r->line1 : r->line0,
-                                     y_bot ? r->line0 : r->line1,
-                                     r->w_lores, r->hs);
-            if (++r->ystep >= r->vs) {
-               r->ystep = 0;
-               r->line0 = r->line1;
-               if (++r->ypos < z->img_comp[k].y)
-                  r->line1 += z->img_comp[k].w2;
-            }
-         }
-         if (n >= 3) {
-            Uint8 *y = coutput[0];
-            if (z->s->img_n == 3) {
-               #ifdef STBI_SIMD
-               stbi_YCbCr_installed(out, y, coutput[1], coutput[2], z->s.img_x, n);
-               #else
-               YCbCr_to_RGB_row(out, y, coutput[1], coutput[2], z->s->img_x, n);
-               #endif
-            } else
-               for (i=0; i < z->s->img_x; ++i) {
-                  out[0] = out[1] = out[2] = y[i];
-                  out[3] = 255; // not used if n==3
-                  out += n;
-               }
-         } else {
-            Uint8 *y = coutput[0];
-            if (n == 1)
-               for (i=0; i < z->s->img_x; ++i) out[i] = y[i];
-            else
-               for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255;
-         }
-      }
-      cleanup_jpeg(z);
-      *out_x = z->s->img_x;
-      *out_y = z->s->img_y;
-      if (comp) *comp  = z->s->img_n; // report original components, not output
-      return output;
-   }
-}
-
-static unsigned char *stbi_jpeg_load(stbi *s, int *x, int *y, int *comp, int req_comp)
-{
-   jpeg j;
-   j.s = s;
-   return load_jpeg_image(&j, x,y,comp,req_comp);
-}
-
-static int stbi_jpeg_test(stbi *s)
-{
-   int r;
-   jpeg j;
-   j.s = s;
-   r = decode_jpeg_header(&j, SCAN_type);
-   stbi_rewind(s);
-   return r;
-}
-
-static int stbi_jpeg_info_raw(jpeg *j, int *x, int *y, int *comp)
-{
-   if (!decode_jpeg_header(j, SCAN_header)) {
-      stbi_rewind( j->s );
-      return 0;
-   }
-   if (x) *x = j->s->img_x;
-   if (y) *y = j->s->img_y;
-   if (comp) *comp = j->s->img_n;
-   return 1;
-}
-
-static int stbi_jpeg_info(stbi *s, int *x, int *y, int *comp)
-{
-   jpeg j;
-   j.s = s;
-   return stbi_jpeg_info_raw(&j, x, y, comp);
-}
-
-// public domain zlib decode    v0.2  Sean Barrett 2006-11-18
-//    simple implementation
-//      - all input must be provided in an upfront buffer
-//      - all output is written to a single output buffer (can malloc/realloc)
-//    performance
-//      - fast huffman
-
-// fast-way is faster to check than jpeg huffman, but slow way is slower
-#define ZFAST_BITS  9 // accelerate all cases in default tables
-#define ZFAST_MASK  ((1 << ZFAST_BITS) - 1)
-
-// zlib-style huffman encoding
-// (jpegs packs from left, zlib from right, so can't share code)
-typedef struct
-{
-   Uint16 fast[1 << ZFAST_BITS];
-   Uint16 firstcode[16];
-   int maxcode[17];
-   Uint16 firstsymbol[16];
-   Uint8  size[288];
-   Uint16 value[288]; 
-} zhuffman;
-
-stbi_inline static int bitreverse16(int n)
-{
-  n = ((n & 0xAAAA) >>  1) | ((n & 0x5555) << 1);
-  n = ((n & 0xCCCC) >>  2) | ((n & 0x3333) << 2);
-  n = ((n & 0xF0F0) >>  4) | ((n & 0x0F0F) << 4);
-  n = ((n & 0xFF00) >>  8) | ((n & 0x00FF) << 8);
-  return n;
-}
-
-stbi_inline static int bit_reverse(int v, int bits)
-{
-   assert(bits <= 16);
-   // to bit reverse n bits, reverse 16 and shift
-   // e.g. 11 bits, bit reverse and shift away 5
-   return bitreverse16(v) >> (16-bits);
-}
-
-static int zbuild_huffman(zhuffman *z, Uint8 *sizelist, int num)
-{
-   int i,k=0;
-   int code, next_code[16], sizes[17];
-
-   // DEFLATE spec for generating codes
-   memset(sizes, 0, sizeof(sizes));
-   memset(z->fast, 255, sizeof(z->fast));
-   for (i=0; i < num; ++i) 
-      ++sizes[sizelist[i]];
-   sizes[0] = 0;
-   for (i=1; i < 16; ++i)
-      assert(sizes[i] <= (1 << i));
-   code = 0;
-   for (i=1; i < 16; ++i) {
-      next_code[i] = code;
-      z->firstcode[i] = (Uint16) code;
-      z->firstsymbol[i] = (Uint16) k;
-      code = (code + sizes[i]);
-      if (sizes[i])
-         if (code-1 >= (1 << i)) return e("bad codelengths","Corrupt JPEG");
-      z->maxcode[i] = code << (16-i); // preshift for inner loop
-      code <<= 1;
-      k += sizes[i];
-   }
-   z->maxcode[16] = 0x10000; // sentinel
-   for (i=0; i < num; ++i) {
-      int s = sizelist[i];
-      if (s) {
-         int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s];
-         z->size[c] = (Uint8)s;
-         z->value[c] = (Uint16)i;
-         if (s <= ZFAST_BITS) {
-            int k = bit_reverse(next_code[s],s);
-            while (k < (1 << ZFAST_BITS)) {
-               z->fast[k] = (Uint16) c;
-               k += (1 << s);
-            }
-         }
-         ++next_code[s];
-      }
-   }
-   return 1;
-}
-
-// zlib-from-memory implementation for PNG reading
-//    because PNG allows splitting the zlib stream arbitrarily,
-//    and it's annoying structurally to have PNG call ZLIB call PNG,
-//    we require PNG read all the IDATs and combine them into a single
-//    memory buffer
-
-typedef struct
-{
-   Uint8 *zbuffer, *zbuffer_end;
-   int num_bits;
-   Uint32 code_buffer;
-
-   char *zout;
-   char *zout_start;
-   char *zout_end;
-   int   z_expandable;
-
-   zhuffman z_length, z_distance;
-} zbuf;
-
-stbi_inline static int zget8(zbuf *z)
-{
-   if (z->zbuffer >= z->zbuffer_end) return 0;
-   return *z->zbuffer++;
-}
-
-static void fill_bits(zbuf *z)
-{
-   do {
-      assert(z->code_buffer < (1U << z->num_bits));
-      z->code_buffer |= zget8(z) << z->num_bits;
-      z->num_bits += 8;
-   } while (z->num_bits <= 24);
-}
-
-stbi_inline static unsigned int zreceive(zbuf *z, int n)
-{
-   unsigned int k;
-   if (z->num_bits < n) fill_bits(z);
-   k = z->code_buffer & ((1 << n) - 1);
-   z->code_buffer >>= n;
-   z->num_bits -= n;
-   return k;   
-}
-
-stbi_inline static int zhuffman_decode(zbuf *a, zhuffman *z)
-{
-   int b,s,k;
-   if (a->num_bits < 16) fill_bits(a);
-   b = z->fast[a->code_buffer & ZFAST_MASK];
-   if (b < 0xffff) {
-      s = z->size[b];
-      a->code_buffer >>= s;
-      a->num_bits -= s;
-      return z->value[b];
-   }
-
-   // not resolved by fast table, so compute it the slow way
-   // use jpeg approach, which requires MSbits at top
-   k = bit_reverse(a->code_buffer, 16);
-   for (s=ZFAST_BITS+1; ; ++s)
-      if (k < z->maxcode[s])
-         break;
-   if (s == 16) return -1; // invalid code!
-   // code size is s, so:
-   b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s];
-   assert(z->size[b] == s);
-   a->code_buffer >>= s;
-   a->num_bits -= s;
-   return z->value[b];
-}
-
-static int expand(zbuf *z, int n)  // need to make room for n bytes
-{
-   char *q;
-   int cur, limit;
-   if (!z->z_expandable) return e("output buffer limit","Corrupt PNG");
-   cur   = (int) (z->zout     - z->zout_start);
-   limit = (int) (z->zout_end - z->zout_start);
-   while (cur + n > limit)
-      limit *= 2;
-   q = (char *) realloc(z->zout_start, limit);
-   if (q == NULL) return e("outofmem", "Out of memory");
-   z->zout_start = q;
-   z->zout       = q + cur;
-   z->zout_end   = q + limit;
-   return 1;
-}
-
-static int length_base[31] = {
-   3,4,5,6,7,8,9,10,11,13,
-   15,17,19,23,27,31,35,43,51,59,
-   67,83,99,115,131,163,195,227,258,0,0 };
-
-static int length_extra[31]= 
-{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
-
-static int dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,
-257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
-
-static int dist_extra[32] =
-{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
-
-static int parse_huffman_block(zbuf *a)
-{
-   for(;;) {
-      int z = zhuffman_decode(a, &a->z_length);
-      if (z < 256) {
-         if (z < 0) return e("bad huffman code","Corrupt PNG"); // error in huffman codes
-         if (a->zout >= a->zout_end) if (!expand(a, 1)) return 0;
-         *a->zout++ = (char) z;
-      } else {
-         Uint8 *p;
-         int len,dist;
-         if (z == 256) return 1;
-         z -= 257;
-         len = length_base[z];
-         if (length_extra[z]) len += zreceive(a, length_extra[z]);
-         z = zhuffman_decode(a, &a->z_distance);
-         if (z < 0) return e("bad huffman code","Corrupt PNG");
-         dist = dist_base[z];
-         if (dist_extra[z]) dist += zreceive(a, dist_extra[z]);
-         if (a->zout - a->zout_start < dist) return e("bad dist","Corrupt PNG");
-         if (a->zout + len > a->zout_end) if (!expand(a, len)) return 0;
-         p = (Uint8 *) (a->zout - dist);
-         while (len--)
-            *a->zout++ = *p++;
-      }
-   }
-}
-
-static int compute_huffman_codes(zbuf *a)
-{
-   static Uint8 length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
-   zhuffman z_codelength;
-   Uint8 lencodes[286+32+137];//padding for maximum single op
-   Uint8 codelength_sizes[19];
-   int i,n;
-
-   int hlit  = zreceive(a,5) + 257;
-   int hdist = zreceive(a,5) + 1;
-   int hclen = zreceive(a,4) + 4;
-
-   memset(codelength_sizes, 0, sizeof(codelength_sizes));
-   for (i=0; i < hclen; ++i) {
-      int s = zreceive(a,3);
-      codelength_sizes[length_dezigzag[i]] = (Uint8) s;
-   }
-   if (!zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0;
-
-   n = 0;
-   while (n < hlit + hdist) {
-      int c = zhuffman_decode(a, &z_codelength);
-      assert(c >= 0 && c < 19);
-      if (c < 16)
-         lencodes[n++] = (Uint8) c;
-      else if (c == 16) {
-         c = zreceive(a,2)+3;
-         memset(lencodes+n, lencodes[n-1], c);
-         n += c;
-      } else if (c == 17) {
-         c = zreceive(a,3)+3;
-         memset(lencodes+n, 0, c);
-         n += c;
-      } else {
-         assert(c == 18);
-         c = zreceive(a,7)+11;
-         memset(lencodes+n, 0, c);
-         n += c;
-      }
-   }
-   if (n != hlit+hdist) return e("bad codelengths","Corrupt PNG");
-   if (!zbuild_huffman(&a->z_length, lencodes, hlit)) return 0;
-   if (!zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0;
-   return 1;
-}
-
-static int parse_uncompressed_block(zbuf *a)
-{
-   Uint8 header[4];
-   int len,nlen,k;
-   if (a->num_bits & 7)
-      zreceive(a, a->num_bits & 7); // discard
-   // drain the bit-packed data into header
-   k = 0;
-   while (a->num_bits > 0) {
-      header[k++] = (Uint8) (a->code_buffer & 255); // wtf this warns?
-      a->code_buffer >>= 8;
-      a->num_bits -= 8;
-   }
-   assert(a->num_bits == 0);
-   // now fill header the normal way
-   while (k < 4)
-      header[k++] = (Uint8) zget8(a);
-   len  = header[1] * 256 + header[0];
-   nlen = header[3] * 256 + header[2];
-   if (nlen != (len ^ 0xffff)) return e("zlib corrupt","Corrupt PNG");
-   if (a->zbuffer + len > a->zbuffer_end) return e("read past buffer","Corrupt PNG");
-   if (a->zout + len > a->zout_end)
-      if (!expand(a, len)) return 0;
-   memcpy(a->zout, a->zbuffer, len);
-   a->zbuffer += len;
-   a->zout += len;
-   return 1;
-}
-
-static int parse_zlib_header(zbuf *a)
-{
-   int cmf   = zget8(a);
-   int cm    = cmf & 15;
-   // int cinfo = cmf >> 4;
-   int flg   = zget8(a);
-   if ((cmf*256+flg) % 31 != 0) return e("bad zlib header","Corrupt PNG"); // zlib spec
-   if (flg & 32) return e("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png
-   if (cm != 8) return e("bad compression","Corrupt PNG"); // DEFLATE required for png
-   // window = 1 << (8 + cinfo)... but who cares, we fully buffer output
-   return 1;
-}
-
-// @TODO: should statically initialize these for optimal thread safety
-static Uint8 default_length[288], default_distance[32];
-static void init_defaults(void)
-{
-   int i;   // use <= to match clearly with spec
-   for (i=0; i <= 143; ++i)     default_length[i]   = 8;
-   for (   ; i <= 255; ++i)     default_length[i]   = 9;
-   for (   ; i <= 279; ++i)     default_length[i]   = 7;
-   for (   ; i <= 287; ++i)     default_length[i]   = 8;
-
-   for (i=0; i <=  31; ++i)     default_distance[i] = 5;
-}
-
-int stbi_png_partial; // a quick hack to only allow decoding some of a PNG... I should implement real streaming support instead
-static int parse_zlib(zbuf *a, int parse_header)
-{
-   int final, type;
-   if (parse_header)
-      if (!parse_zlib_header(a)) return 0;
-   a->num_bits = 0;
-   a->code_buffer = 0;
-   do {
-      final = zreceive(a,1);
-      type = zreceive(a,2);
-      if (type == 0) {
-         if (!parse_uncompressed_block(a)) return 0;
-      } else if (type == 3) {
-         return 0;
-      } else {
-         if (type == 1) {
-            // use fixed code lengths
-            if (!default_distance[31]) init_defaults();
-            if (!zbuild_huffman(&a->z_length  , default_length  , 288)) return 0;
-            if (!zbuild_huffman(&a->z_distance, default_distance,  32)) return 0;
-         } else {
-            if (!compute_huffman_codes(a)) return 0;
-         }
-         if (!parse_huffman_block(a)) return 0;
-      }
-      if (stbi_png_partial && a->zout - a->zout_start > 65536)
-         break;
-   } while (!final);
-   return 1;
-}
-
-static int do_zlib(zbuf *a, char *obuf, int olen, int exp, int parse_header)
-{
-   a->zout_start = obuf;
-   a->zout       = obuf;
-   a->zout_end   = obuf + olen;
-   a->z_expandable = exp;
-
-   return parse_zlib(a, parse_header);
-}
-
-char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen)
-{
-   zbuf a;
-   char *p = (char *) malloc(initial_size);
-   if (p == NULL) return NULL;
-   a.zbuffer = (Uint8 *) buffer;
-   a.zbuffer_end = (Uint8 *) buffer + len;
-   if (do_zlib(&a, p, initial_size, 1, 1)) {
-      if (outlen) *outlen = (int) (a.zout - a.zout_start);
-      return a.zout_start;
-   } else {
-      free(a.zout_start);
-      return NULL;
-   }
-}
-
-char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen)
-{
-   return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen);
-}
-
-char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header)
-{
-   zbuf a;
-   char *p = (char *) malloc(initial_size);
-   if (p == NULL) return NULL;
-   a.zbuffer = (Uint8 *) buffer;
-   a.zbuffer_end = (Uint8 *) buffer + len;
-   if (do_zlib(&a, p, initial_size, 1, parse_header)) {
-      if (outlen) *outlen = (int) (a.zout - a.zout_start);
-      return a.zout_start;
-   } else {
-      free(a.zout_start);
-      return NULL;
-   }
-}
-
-int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen)
-{
-   zbuf a;
-   a.zbuffer = (Uint8 *) ibuffer;
-   a.zbuffer_end = (Uint8 *) ibuffer + ilen;
-   if (do_zlib(&a, obuffer, olen, 0, 1))
-      return (int) (a.zout - a.zout_start);
-   else
-      return -1;
-}
-
-char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen)
-{
-   zbuf a;
-   char *p = (char *) malloc(16384);
-   if (p == NULL) return NULL;
-   a.zbuffer = (Uint8 *) buffer;
-   a.zbuffer_end = (Uint8 *) buffer+len;
-   if (do_zlib(&a, p, 16384, 1, 0)) {
-      if (outlen) *outlen = (int) (a.zout - a.zout_start);
-      return a.zout_start;
-   } else {
-      free(a.zout_start);
-      return NULL;
-   }
-}
-
-int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen)
-{
-   zbuf a;
-   a.zbuffer = (Uint8 *) ibuffer;
-   a.zbuffer_end = (Uint8 *) ibuffer + ilen;
-   if (do_zlib(&a, obuffer, olen, 0, 0))
-      return (int) (a.zout - a.zout_start);
-   else
-      return -1;
-}
-
-// public domain "baseline" PNG decoder   v0.10  Sean Barrett 2006-11-18
-//    simple implementation
-//      - only 8-bit samples
-//      - no CRC checking
-//      - allocates lots of intermediate memory
-//        - avoids problem of streaming data between subsystems
-//        - avoids explicit window management
-//    performance
-//      - uses stb_zlib, a PD zlib implementation with fast huffman decoding
-
-
-typedef struct
-{
-   Uint32 length;
-   Uint32 type;
-} chunk;
-
-#define PNG_TYPE(a,b,c,d)  (((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
-
-static chunk get_chunk_header(stbi *s)
-{
-   chunk c;
-   c.length = get32(s);
-   c.type   = get32(s);
-   return c;
-}
-
-static int check_png_header(stbi *s)
-{
-   static Uint8 png_sig[8] = { 137,80,78,71,13,10,26,10 };
-   int i;
-   for (i=0; i < 8; ++i)
-      if (get8u(s) != png_sig[i]) return e("bad png sig","Not a PNG");
-   return 1;
-}
-
-typedef struct
-{
-   stbi *s;
-   Uint8 *idata, *expanded, *out;
-} png;
-
-
-enum {
-   F_none=0, F_sub=1, F_up=2, F_avg=3, F_paeth=4,
-   F_avg_first, F_paeth_first
-};
-
-static Uint8 first_row_filter[5] =
-{
-   F_none, F_sub, F_none, F_avg_first, F_paeth_first
-};
-
-static int paeth(int a, int b, int c)
-{
-   int p = a + b - c;
-   int pa = abs(p-a);
-   int pb = abs(p-b);
-   int pc = abs(p-c);
-   if (pa <= pb && pa <= pc) return a;
-   if (pb <= pc) return b;
-   return c;
-}
-
-// create the png data from post-deflated data
-static int create_png_image_raw(png *a, Uint8 *raw, Uint32 raw_len, int out_n, Uint32 x, Uint32 y)
-{
-   stbi *s = a->s;
-   Uint32 i,j,stride = x*out_n;
-   int k;
-   int img_n = s->img_n; // copy it into a local for later
-   assert(out_n == s->img_n || out_n == s->img_n+1);
-   if (stbi_png_partial) y = 1;
-   a->out = (Uint8 *) malloc(x * y * out_n);
-   if (!a->out) return e("outofmem", "Out of memory");
-   if (!stbi_png_partial) {
-      if (s->img_x == x && s->img_y == y) {
-         if (raw_len != (img_n * x + 1) * y) return e("not enough pixels","Corrupt PNG");
-      } else { // interlaced:
-         if (raw_len < (img_n * x + 1) * y) return e("not enough pixels","Corrupt PNG");
-      }
-   }
-   for (j=0; j < y; ++j) {
-      Uint8 *cur = a->out + stride*j;
-      Uint8 *prior = cur - stride;
-      int filter = *raw++;
-      if (filter > 4) return e("invalid filter","Corrupt PNG");
-      // if first row, use special filter that doesn't sample previous row
-      if (j == 0) filter = first_row_filter[filter];
-      // handle first pixel explicitly
-      for (k=0; k < img_n; ++k) {
-         switch (filter) {
-            case F_none       : cur[k] = raw[k]; break;
-            case F_sub        : cur[k] = raw[k]; break;
-            case F_up         : cur[k] = raw[k] + prior[k]; break;
-            case F_avg        : cur[k] = raw[k] + (prior[k]>>1); break;
-            case F_paeth      : cur[k] = (Uint8) (raw[k] + paeth(0,prior[k],0)); break;
-            case F_avg_first  : cur[k] = raw[k]; break;
-            case F_paeth_first: cur[k] = raw[k]; break;
-         }
-      }
-      if (img_n != out_n) cur[img_n] = 255;
-      raw += img_n;
-      cur += out_n;
-      prior += out_n;
-      // this is a little gross, so that we don't switch per-pixel or per-component
-      if (img_n == out_n) {
-         #define CASE(f) \
-             case f:     \
-                for (i=x-1; i >= 1; --i, raw+=img_n,cur+=img_n,prior+=img_n) \
-                   for (k=0; k < img_n; ++k)
-         switch (filter) {
-            CASE(F_none)  cur[k] = raw[k]; break;
-            CASE(F_sub)   cur[k] = raw[k] + cur[k-img_n]; break;
-            CASE(F_up)    cur[k] = raw[k] + prior[k]; break;
-            CASE(F_avg)   cur[k] = raw[k] + ((prior[k] + cur[k-img_n])>>1); break;
-            CASE(F_paeth)  cur[k] = (Uint8) (raw[k] + paeth(cur[k-img_n],prior[k],prior[k-img_n])); break;
-            CASE(F_avg_first)    cur[k] = raw[k] + (cur[k-img_n] >> 1); break;
-            CASE(F_paeth_first)  cur[k] = (Uint8) (raw[k] + paeth(cur[k-img_n],0,0)); break;
-         }
-         #undef CASE
-      } else {
-         assert(img_n+1 == out_n);
-         #define CASE(f) \
-             case f:     \
-                for (i=x-1; i >= 1; --i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \
-                   for (k=0; k < img_n; ++k)
-         switch (filter) {
-            CASE(F_none)  cur[k] = raw[k]; break;
-            CASE(F_sub)   cur[k] = raw[k] + cur[k-out_n]; break;
-            CASE(F_up)    cur[k] = raw[k] + prior[k]; break;
-            CASE(F_avg)   cur[k] = raw[k] + ((prior[k] + cur[k-out_n])>>1); break;
-            CASE(F_paeth)  cur[k] = (Uint8) (raw[k] + paeth(cur[k-out_n],prior[k],prior[k-out_n])); break;
-            CASE(F_avg_first)    cur[k] = raw[k] + (cur[k-out_n] >> 1); break;
-            CASE(F_paeth_first)  cur[k] = (Uint8) (raw[k] + paeth(cur[k-out_n],0,0)); break;
-         }
-         #undef CASE
-      }
-   }
-   return 1;
-}
-
-static int create_png_image(png *a, Uint8 *raw, Uint32 raw_len, int out_n, int interlaced)
-{
-   Uint8 *final;
-   int p;
-   int save;
-   if (!interlaced)
-      return create_png_image_raw(a, raw, raw_len, out_n, a->s->img_x, a->s->img_y);
-   save = stbi_png_partial;
-   stbi_png_partial = 0;
-
-   // de-interlacing
-   final = (Uint8 *) malloc(a->s->img_x * a->s->img_y * out_n);
-   for (p=0; p < 7; ++p) {
-      int xorig[] = { 0,4,0,2,0,1,0 };
-      int yorig[] = { 0,0,4,0,2,0,1 };
-      int xspc[]  = { 8,8,4,4,2,2,1 };
-      int yspc[]  = { 8,8,8,4,4,2,2 };
-      int i,j,x,y;
-      // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1
-      x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p];
-      y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p];
-      if (x && y) {
-         if (!create_png_image_raw(a, raw, raw_len, out_n, x, y)) {
-            free(final);
-            return 0;
-         }
-         for (j=0; j < y; ++j)
-            for (i=0; i < x; ++i)
-               memcpy(final + (j*yspc[p]+yorig[p])*a->s->img_x*out_n + (i*xspc[p]+xorig[p])*out_n,
-                      a->out + (j*x+i)*out_n, out_n);
-         free(a->out);
-         raw += (x*out_n+1)*y;
-         raw_len -= (x*out_n+1)*y;
-      }
-   }
-   a->out = final;
-
-   stbi_png_partial = save;
-   return 1;
-}
-
-static int compute_transparency(png *z, Uint8 tc[3], int out_n)
-{
-   stbi *s = z->s;
-   Uint32 i, pixel_count = s->img_x * s->img_y;
-   Uint8 *p = z->out;
-
-   // compute color-based transparency, assuming we've
-   // already got 255 as the alpha value in the output
-   assert(out_n == 2 || out_n == 4);
-
-   if (out_n == 2) {
-      for (i=0; i < pixel_count; ++i) {
-         p[1] = (p[0] == tc[0] ? 0 : 255);
-         p += 2;
-      }
-   } else {
-      for (i=0; i < pixel_count; ++i) {
-         if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
-            p[3] = 0;
-         p += 4;
-      }
-   }
-   return 1;
-}
-
-static int expand_palette(png *a, Uint8 *palette, int len, int pal_img_n)
-{
-   Uint32 i, pixel_count = a->s->img_x * a->s->img_y;
-   Uint8 *p, *temp_out, *orig = a->out;
-
-   p = (Uint8 *) malloc(pixel_count * pal_img_n);
-   if (p == NULL) return e("outofmem", "Out of memory");
-
-   // between here and free(out) below, exitting would leak
-   temp_out = p;
-
-   if (pal_img_n == 3) {
-      for (i=0; i < pixel_count; ++i) {
-         int n = orig[i]*4;
-         p[0] = palette[n  ];
-         p[1] = palette[n+1];
-         p[2] = palette[n+2];
-         p += 3;
-      }
-   } else {
-      for (i=0; i < pixel_count; ++i) {
-         int n = orig[i]*4;
-         p[0] = palette[n  ];
-         p[1] = palette[n+1];
-         p[2] = palette[n+2];
-         p[3] = palette[n+3];
-         p += 4;
-      }
-   }
-   free(a->out);
-   a->out = temp_out;
-
-   STBI_NOTUSED(len);
-
-   return 1;
-}
-
-static int stbi_unpremultiply_on_load = 0;
-static int stbi_de_iphone_flag = 0;
-
-void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply)
-{
-   stbi_unpremultiply_on_load = flag_true_if_should_unpremultiply;
-}
-void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)
-{
-   stbi_de_iphone_flag = flag_true_if_should_convert;
-}
-
-static void stbi_de_iphone(png *z)
-{
-   stbi *s = z->s;
-   Uint32 i, pixel_count = s->img_x * s->img_y;
-   Uint8 *p = z->out;
-
-   if (s->img_out_n == 3) {  // convert bgr to rgb
-      for (i=0; i < pixel_count; ++i) {
-         Uint8 t = p[0];
-         p[0] = p[2];
-         p[2] = t;
-         p += 3;
-      }
-   } else {
-      assert(s->img_out_n == 4);
-      if (stbi_unpremultiply_on_load) {
-         // convert bgr to rgb and unpremultiply
-         for (i=0; i < pixel_count; ++i) {
-            Uint8 a = p[3];
-            Uint8 t = p[0];
-            if (a) {
-               p[0] = p[2] * 255 / a;
-               p[1] = p[1] * 255 / a;
-               p[2] =  t   * 255 / a;
-            } else {
-               p[0] = p[2];
-               p[2] = t;
-            } 
-            p += 4;
-         }
-      } else {
-         // convert bgr to rgb
-         for (i=0; i < pixel_count; ++i) {
-            Uint8 t = p[0];
-            p[0] = p[2];
-            p[2] = t;
-            p += 4;
-         }
-      }
-   }
-}
-
-static int parse_png_file(png *z, int scan, int req_comp)
-{
-   Uint8 palette[1024], pal_img_n=0;
-   Uint8 has_trans=0, tc[3];
-   Uint32 ioff=0, idata_limit=0, i, pal_len=0;
-   int first=1,k,interlace=0, iphone=0;
-   stbi *s = z->s;
-
-   z->expanded = NULL;
-   z->idata = NULL;
-   z->out = NULL;
-
-   if (!check_png_header(s)) return 0;
-
-   if (scan == SCAN_type) return 1;
-
-   for (;;) {
-      chunk c = get_chunk_header(s);
-      switch (c.type) {
-         case PNG_TYPE('C','g','B','I'):
-            iphone = stbi_de_iphone_flag;
-            skip(s, c.length);
-            break;
-         case PNG_TYPE('I','H','D','R'): {
-            int depth,color,comp,filter;
-            if (!first) return e("multiple IHDR","Corrupt PNG");
-            first = 0;
-            if (c.length != 13) return e("bad IHDR len","Corrupt PNG");
-            s->img_x = get32(s); if (s->img_x > (1 << 24)) return e("too large","Very large image (corrupt?)");
-            s->img_y = get32(s); if (s->img_y > (1 << 24)) return e("too large","Very large image (corrupt?)");
-            depth = get8(s);  if (depth != 8)        return e("8bit only","PNG not supported: 8-bit only");
-            color = get8(s);  if (color > 6)         return e("bad ctype","Corrupt PNG");
-            if (color == 3) pal_img_n = 3; else if (color & 1) return e("bad ctype","Corrupt PNG");
-            comp  = get8(s);  if (comp) return e("bad comp method","Corrupt PNG");
-            filter= get8(s);  if (filter) return e("bad filter method","Corrupt PNG");
-            interlace = get8(s); if (interlace>1) return e("bad interlace method","Corrupt PNG");
-            if (!s->img_x || !s->img_y) return e("0-pixel image","Corrupt PNG");
-            if (!pal_img_n) {
-               s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);
-               if ((1 << 30) / s->img_x / s->img_n < s->img_y) return e("too large", "Image too large to decode");
-               if (scan == SCAN_header) return 1;
-            } else {
-               // if paletted, then pal_n is our final components, and
-               // img_n is # components to decompress/filter.
-               s->img_n = 1;
-               if ((1 << 30) / s->img_x / 4 < s->img_y) return e("too large","Corrupt PNG");
-               // if SCAN_header, have to scan to see if we have a tRNS
-            }
-            break;
-         }
-
-         case PNG_TYPE('P','L','T','E'):  {
-            if (first) return e("first not IHDR", "Corrupt PNG");
-            if (c.length > 256*3) return e("invalid PLTE","Corrupt PNG");
-            pal_len = c.length / 3;
-            if (pal_len * 3 != c.length) return e("invalid PLTE","Corrupt PNG");
-            for (i=0; i < pal_len; ++i) {
-               palette[i*4+0] = get8u(s);
-               palette[i*4+1] = get8u(s);
-               palette[i*4+2] = get8u(s);
-               palette[i*4+3] = 255;
-            }
-            break;
-         }
-
-         case PNG_TYPE('t','R','N','S'): {
-            if (first) return e("first not IHDR", "Corrupt PNG");
-            if (z->idata) return e("tRNS after IDAT","Corrupt PNG");
-            if (pal_img_n) {
-               if (scan == SCAN_header) { s->img_n = 4; return 1; }
-               if (pal_len == 0) return e("tRNS before PLTE","Corrupt PNG");
-               if (c.length > pal_len) return e("bad tRNS len","Corrupt PNG");
-               pal_img_n = 4;
-               for (i=0; i < c.length; ++i)
-                  palette[i*4+3] = get8u(s);
-            } else {
-               if (!(s->img_n & 1)) return e("tRNS with alpha","Corrupt PNG");
-               if (c.length != (Uint32) s->img_n*2) return e("bad tRNS len","Corrupt PNG");
-               has_trans = 1;
-               for (k=0; k < s->img_n; ++k)
-                  tc[k] = (Uint8) get16(s); // non 8-bit images will be larger
-            }
-            break;
-         }
-
-         case PNG_TYPE('I','D','A','T'): {
-            if (first) return e("first not IHDR", "Corrupt PNG");
-            if (pal_img_n && !pal_len) return e("no PLTE","Corrupt PNG");
-            if (scan == SCAN_header) { s->img_n = pal_img_n; return 1; }
-            if (ioff + c.length > idata_limit) {
-               Uint8 *p;
-               if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;
-               while (ioff + c.length > idata_limit)
-                  idata_limit *= 2;
-               p = (Uint8 *) realloc(z->idata, idata_limit); if (p == NULL) return e("outofmem", "Out of memory");
-               z->idata = p;
-            }
-            if (!getn(s, z->idata+ioff,c.length)) return e("outofdata","Corrupt PNG");
-            ioff += c.length;
-            break;
-         }
-
-         case PNG_TYPE('I','E','N','D'): {
-            Uint32 raw_len;
-            if (first) return e("first not IHDR", "Corrupt PNG");
-            if (scan != SCAN_load) return 1;
-            if (z->idata == NULL) return e("no IDAT","Corrupt PNG");
-            z->expanded = (Uint8 *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, 16384, (int *) &raw_len, !iphone);
-            if (z->expanded == NULL) return 0; // zlib should set error
-            free(z->idata); z->idata = NULL;
-            if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans)
-               s->img_out_n = s->img_n+1;
-            else
-               s->img_out_n = s->img_n;
-            if (!create_png_image(z, z->expanded, raw_len, s->img_out_n, interlace)) return 0;
-            if (has_trans)
-               if (!compute_transparency(z, tc, s->img_out_n)) return 0;
-            if (iphone && s->img_out_n > 2)
-               stbi_de_iphone(z);
-            if (pal_img_n) {
-               // pal_img_n == 3 or 4
-               s->img_n = pal_img_n; // record the actual colors we had
-               s->img_out_n = pal_img_n;
-               if (req_comp >= 3) s->img_out_n = req_comp;
-               if (!expand_palette(z, palette, pal_len, s->img_out_n))
-                  return 0;
-            }
-            free(z->expanded); z->expanded = NULL;
-            return 1;
-         }
-
-         default:
-            // if critical, fail
-            if (first) return e("first not IHDR", "Corrupt PNG");
-            if ((c.type & (1 << 29)) == 0) {
-               #if !defined(STBI_NO_FAILURE_STRINGS) && !defined(STBI_FAILURE_USERMSG)
-               // not threadsafe
-               static char invalid_chunk[] = "XXXX chunk not known";
-               invalid_chunk[0] = (Uint8) (c.type >> 24);
-               invalid_chunk[1] = (Uint8) (c.type >> 16);
-               invalid_chunk[2] = (Uint8) (c.type >>  8);
-               invalid_chunk[3] = (Uint8) (c.type >>  0);
-               #endif
-               return e(invalid_chunk, "PNG not supported: unknown chunk type");
-            }
-            skip(s, c.length);
-            break;
-      }
-      // end of chunk, read and skip CRC
-      get32(s);
-   }
-}
-
-static unsigned char *do_png(png *p, int *x, int *y, int *n, int req_comp)
-{
-   unsigned char *result=NULL;
-   if (req_comp < 0 || req_comp > 4) return epuc("bad req_comp", "Internal error");
-   if (parse_png_file(p, SCAN_load, req_comp)) {
-      result = p->out;
-      p->out = NULL;
-      if (req_comp && req_comp != p->s->img_out_n) {
-         result = convert_format(result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
-         p->s->img_out_n = req_comp;
-         if (result == NULL) return result;
-      }
-      *x = p->s->img_x;
-      *y = p->s->img_y;
-      if (n) *n = p->s->img_n;
-   }
-   free(p->out);      p->out      = NULL;
-   free(p->expanded); p->expanded = NULL;
-   free(p->idata);    p->idata    = NULL;
-
-   return result;
-}
-
-static unsigned char *stbi_png_load(stbi *s, int *x, int *y, int *comp, int req_comp)
-{
-   png p;
-   p.s = s;
-   return do_png(&p, x,y,comp,req_comp);
-}
-
-static int stbi_png_test(stbi *s)
-{
-   int r;
-   r = check_png_header(s);
-   stbi_rewind(s);
-   return r;
-}
-
-static int stbi_png_info_raw(png *p, int *x, int *y, int *comp)
-{
-   if (!parse_png_file(p, SCAN_header, 0)) {
-      stbi_rewind( p->s );
-      return 0;
-   }
-   if (x) *x = p->s->img_x;
-   if (y) *y = p->s->img_y;
-   if (comp) *comp = p->s->img_n;
-   return 1;
-}
-
-static int      stbi_png_info(stbi *s, int *x, int *y, int *comp)
-{
-   png p;
-   p.s = s;
-   return stbi_png_info_raw(&p, x, y, comp);
-}
-
-#ifdef STBI_CRAP_FORMATS
-
-// Microsoft/Windows BMP image
-
-static int bmp_test(stbi *s)
-{
-   int sz;
-   if (get8(s) != 'B') return 0;
-   if (get8(s) != 'M') return 0;
-   get32le(s); // discard filesize
-   get16le(s); // discard reserved
-   get16le(s); // discard reserved
-   get32le(s); // discard data offset
-   sz = get32le(s);
-   if (sz == 12 || sz == 40 || sz == 56 || sz == 108) return 1;
-   return 0;
-}
-
-static int stbi_bmp_test(stbi *s)
-{
-   int r = bmp_test(s);
-   stbi_rewind(s);
-   return r;
-}
-
-
-// returns 0..31 for the highest set bit
-static int high_bit(unsigned int z)
-{
-   int n=0;
-   if (z == 0) return -1;
-   if (z >= 0x10000) n += 16, z >>= 16;
-   if (z >= 0x00100) n +=  8, z >>=  8;
-   if (z >= 0x00010) n +=  4, z >>=  4;
-   if (z >= 0x00004) n +=  2, z >>=  2;
-   if (z >= 0x00002) n +=  1, z >>=  1;
-   return n;
-}
-
-static int bitcount(unsigned int a)
-{
-   a = (a & 0x55555555) + ((a >>  1) & 0x55555555); // max 2
-   a = (a & 0x33333333) + ((a >>  2) & 0x33333333); // max 4
-   a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits
-   a = (a + (a >> 8)); // max 16 per 8 bits
-   a = (a + (a >> 16)); // max 32 per 8 bits
-   return a & 0xff;
-}
-
-static int shiftsigned(int v, int shift, int bits)
-{
-   int result;
-   int z=0;
-
-   if (shift < 0) v <<= -shift;
-   else v >>= shift;
-   result = v;
-
-   z = bits;
-   while (z < 8) {
-      result += v >> z;
-      z += bits;
-   }
-   return result;
-}
-
-static stbi_uc *bmp_load(stbi *s, int *x, int *y, int *comp, int req_comp)
-{
-   Uint8 *out;
-   unsigned int mr=0,mg=0,mb=0,ma=0, fake_a=0;
-   stbi_uc pal[256][4];
-   int psize=0,i,j,compress=0,width;
-   int bpp, flip_vertically, pad, target, offset, hsz;
-   if (get8(s) != 'B' || get8(s) != 'M') return epuc("not BMP", "Corrupt BMP");
-   get32le(s); // discard filesize
-   get16le(s); // discard reserved
-   get16le(s); // discard reserved
-   offset = get32le(s);
-   hsz = get32le(s);
-   if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108) return epuc("unknown BMP", "BMP type not supported: unknown");
-   if (hsz == 12) {
-      s->img_x = get16le(s);
-      s->img_y = get16le(s);
-   } else {
-      s->img_x = get32le(s);
-      s->img_y = get32le(s);
-   }
-   if (get16le(s) != 1) return epuc("bad BMP", "bad BMP");
-   bpp = get16le(s);
-   if (bpp == 1) return epuc("monochrome", "BMP type not supported: 1-bit");
-   flip_vertically = ((int) s->img_y) > 0;
-   s->img_y = abs((int) s->img_y);
-   if (hsz == 12) {
-      if (bpp < 24)
-         psize = (offset - 14 - 24) / 3;
-   } else {
-      compress = get32le(s);
-      if (compress == 1 || compress == 2) return epuc("BMP RLE", "BMP type not supported: RLE");
-      get32le(s); // discard sizeof
-      get32le(s); // discard hres
-      get32le(s); // discard vres
-      get32le(s); // discard colorsused
-      get32le(s); // discard max important
-      if (hsz == 40 || hsz == 56) {
-         if (hsz == 56) {
-            get32le(s);
-            get32le(s);
-            get32le(s);
-            get32le(s);
-         }
-         if (bpp == 16 || bpp == 32) {
-            mr = mg = mb = 0;
-            if (compress == 0) {
-               if (bpp == 32) {
-                  mr = 0xffu << 16;
-                  mg = 0xffu <<  8;
-                  mb = 0xffu <<  0;
-                  ma = 0xffu << 24;
-                  fake_a = 1; // @TODO: check for cases like alpha value is all 0 and switch it to 255
-               } else {
-                  mr = 31u << 10;
-                  mg = 31u <<  5;
-                  mb = 31u <<  0;
-               }
-            } else if (compress == 3) {
-               mr = get32le(s);
-               mg = get32le(s);
-               mb = get32le(s);
-               // not documented, but generated by photoshop and handled by mspaint
-               if (mr == mg && mg == mb) {
-                  // ?!?!?
-                  return epuc("bad BMP", "bad BMP");
-               }
-            } else
-               return epuc("bad BMP", "bad BMP");
-         }
-      } else {
-         assert(hsz == 108);
-         mr = get32le(s);
-         mg = get32le(s);
-         mb = get32le(s);
-         ma = get32le(s);
-         get32le(s); // discard color space
-         for (i=0; i < 12; ++i)
-            get32le(s); // discard color space parameters
-      }
-      if (bpp < 16)
-         psize = (offset - 14 - hsz) >> 2;
-   }
-   s->img_n = ma ? 4 : 3;
-   if (req_comp && req_comp >= 3) // we can directly decode 3 or 4
-      target = req_comp;
-   else
-      target = s->img_n; // if they want monochrome, we'll post-convert
-   out = (stbi_uc *) malloc(target * s->img_x * s->img_y);
-   if (!out) return epuc("outofmem", "Out of memory");
-   if (bpp < 16) {
-      int z=0;
-      if (psize == 0 || psize > 256) { free(out); return epuc("invalid", "Corrupt BMP"); }
-      for (i=0; i < psize; ++i) {
-         pal[i][2] = get8u(s);
-         pal[i][1] = get8u(s);
-         pal[i][0] = get8u(s);
-         if (hsz != 12) get8(s);
-         pal[i][3] = 255;
-      }
-      skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4));
-      if (bpp == 4) width = (s->img_x + 1) >> 1;
-      else if (bpp == 8) width = s->img_x;
-      else { free(out); return epuc("bad bpp", "Corrupt BMP"); }
-      pad = (-width)&3;
-      for (j=0; j < (int) s->img_y; ++j) {
-         for (i=0; i < (int) s->img_x; i += 2) {
-            int v=get8(s),v2=0;
-            if (bpp == 4) {
-               v2 = v & 15;
-               v >>= 4;
-            }
-            out[z++] = pal[v][0];
-            out[z++] = pal[v][1];
-            out[z++] = pal[v][2];
-            if (target == 4) out[z++] = 255;
-            if (i+1 == (int) s->img_x) break;
-            v = (bpp == 8) ? get8(s) : v2;
-            out[z++] = pal[v][0];
-            out[z++] = pal[v][1];
-            out[z++] = pal[v][2];
-            if (target == 4) out[z++] = 255;
-         }
-         skip(s, pad);
-      }
-   } else {
-      int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;
-      int z = 0;
-      int easy=0;
-      skip(s, offset - 14 - hsz);
-      if (bpp == 24) width = 3 * s->img_x;
-      else if (bpp == 16) width = 2*s->img_x;
-      else /* bpp = 32 and pad = 0 */ width=0;
-      pad = (-width) & 3;
-      if (bpp == 24) {
-         easy = 1;
-      } else if (bpp == 32) {
-         if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)
-            easy = 2;
-      }
-      if (!easy) {
-         if (!mr || !mg || !mb) { free(out); return epuc("bad masks", "Corrupt BMP"); }
-         // right shift amt to put high bit in position #7
-         rshift = high_bit(mr)-7; rcount = bitcount(mr);
-         gshift = high_bit(mg)-7; gcount = bitcount(mr);
-         bshift = high_bit(mb)-7; bcount = bitcount(mr);
-         ashift = high_bit(ma)-7; acount = bitcount(mr);
-      }
-      for (j=0; j < (int) s->img_y; ++j) {
-         if (easy) {
-            for (i=0; i < (int) s->img_x; ++i) {
-               int a;
-               out[z+2] = get8u(s);
-               out[z+1] = get8u(s);
-               out[z+0] = get8u(s);
-               z += 3;
-               a = (easy == 2 ? get8(s) : 255);
-               if (target == 4) out[z++] = (Uint8) a;
-            }
-         } else {
-            for (i=0; i < (int) s->img_x; ++i) {
-               Uint32 v = (bpp == 16 ? get16le(s) : get32le(s));
-               int a;
-               out[z++] = (Uint8) shiftsigned(v & mr, rshift, rcount);
-               out[z++] = (Uint8) shiftsigned(v & mg, gshift, gcount);
-               out[z++] = (Uint8) shiftsigned(v & mb, bshift, bcount);
-               a = (ma ? shiftsigned(v & ma, ashift, acount) : 255);
-               if (target == 4) out[z++] = (Uint8) a; 
-            }
-         }
-         skip(s, pad);
-      }
-   }
-   if (flip_vertically) {
-      stbi_uc t;
-      for (j=0; j < (int) s->img_y>>1; ++j) {
-         stbi_uc *p1 = out +      j     *s->img_x*target;
-         stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target;
-         for (i=0; i < (int) s->img_x*target; ++i) {
-            t = p1[i], p1[i] = p2[i], p2[i] = t;
-         }
-      }
-   }
-
-   if (req_comp && req_comp != target) {
-      out = convert_format(out, target, req_comp, s->img_x, s->img_y);
-      if (out == NULL) return out; // convert_format frees input on failure
-   }
-
-   *x = s->img_x;
-   *y = s->img_y;
-   if (comp) *comp = s->img_n;
-   return out;
-}
-
-static stbi_uc *stbi_bmp_load(stbi *s,int *x, int *y, int *comp, int req_comp)
-{
-   return bmp_load(s, x,y,comp,req_comp);
-}
-
-
-// Targa Truevision - TGA
-// by Jonathan Dummer
-
-static int tga_info(stbi *s, int *x, int *y, int *comp)
-{
-    int tga_w, tga_h, tga_comp;
-    int sz;
-    get8u(s);                   // discard Offset
-    sz = get8u(s);              // color type
-    if( sz > 1 ) {
-        stbi_rewind(s);
-        return 0;      // only RGB or indexed allowed
-    }
-    sz = get8u(s);              // image type
-    // only RGB or grey allowed, +/- RLE
-    if ((sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11)) return 0;
-    skip(s,9);
-    tga_w = get16le(s);
-    if( tga_w < 1 ) {
-        stbi_rewind(s);
-        return 0;   // test width
-    }
-    tga_h = get16le(s);
-    if( tga_h < 1 ) {
-        stbi_rewind(s);
-        return 0;   // test height
-    }
-    sz = get8(s);               // bits per pixel
-    // only RGB or RGBA or grey allowed
-    if ((sz != 8) && (sz != 16) && (sz != 24) && (sz != 32)) {
-        stbi_rewind(s);
-        return 0;
-    }
-    tga_comp = sz;
-    if (x) *x = tga_w;
-    if (y) *y = tga_h;
-    if (comp) *comp = tga_comp / 8;
-    return 1;                   // seems to have passed everything
-}
-
-int stbi_tga_info(stbi *s, int *x, int *y, int *comp)
-{
-    return tga_info(s, x, y, comp);
-}
-
-static int tga_test(stbi *s)
-{
-   int sz;
-   get8u(s);      //   discard Offset
-   sz = get8u(s);   //   color type
-   if ( sz > 1 ) return 0;   //   only RGB or indexed allowed
-   sz = get8u(s);   //   image type
-   if ( (sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11) ) return 0;   //   only RGB or grey allowed, +/- RLE
-   get16(s);      //   discard palette start
-   get16(s);      //   discard palette length
-   get8(s);         //   discard bits per palette color entry
-   get16(s);      //   discard x origin
-   get16(s);      //   discard y origin
-   if ( get16(s) < 1 ) return 0;      //   test width
-   if ( get16(s) < 1 ) return 0;      //   test height
-   sz = get8(s);   //   bits per pixel
-   if ( (sz != 8) && (sz != 16) && (sz != 24) && (sz != 32) ) return 0;   //   only RGB or RGBA or grey allowed
-   return 1;      //   seems to have passed everything
-}
-
-static int stbi_tga_test(stbi *s)
-{
-   int res = tga_test(s);
-   stbi_rewind(s);
-   return res;
-}
-
-static stbi_uc *tga_load(stbi *s, int *x, int *y, int *comp, int req_comp)
-{
-   //   read in the TGA header stuff
-   int tga_offset = get8u(s);
-   int tga_indexed = get8u(s);
-   int tga_image_type = get8u(s);
-   int tga_is_RLE = 0;
-   int tga_palette_start = get16le(s);
-   int tga_palette_len = get16le(s);
-   int tga_palette_bits = get8u(s);
-   int tga_x_origin = get16le(s);
-   int tga_y_origin = get16le(s);
-   int tga_width = get16le(s);
-   int tga_height = get16le(s);
-   int tga_bits_per_pixel = get8u(s);
-   int tga_inverted = get8u(s);
-   //   image data
-   unsigned char *tga_data;
-   unsigned char *tga_palette = NULL;
-   int i, j;
-   unsigned char raw_data[4];
-   unsigned char trans_data[4];
-   int RLE_count = 0;
-   int RLE_repeating = 0;
-   int read_next_pixel = 1;
-
-   //   do a tiny bit of precessing
-   if ( tga_image_type >= 8 )
-   {
-      tga_image_type -= 8;
-      tga_is_RLE = 1;
-   }
-   // int tga_alpha_bits = tga_inverted & 15;
-   tga_inverted = 1 - ((tga_inverted >> 5) & 1);
-
-   //   error check
-   if ( //(tga_indexed) ||
-      (tga_width < 1) || (tga_height < 1) ||
-      (tga_image_type < 1) || (tga_image_type > 3) ||
-      ((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16) &&
-      (tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32))
-      )
-   {
-      return NULL; // we don't report this as a bad TGA because we don't even know if it's TGA
-   }
-
-   //   If I'm paletted, then I'll use the number of bits from the palette
-   if ( tga_indexed )
-   {
-      tga_bits_per_pixel = tga_palette_bits;
-   }
-
-   //   tga info
-   *x = tga_width;
-   *y = tga_height;
-   if ( (req_comp < 1) || (req_comp > 4) )
-   {
-      //   just use whatever the file was
-      req_comp = tga_bits_per_pixel / 8;
-      *comp = req_comp;
-   } else
-   {
-      //   force a new number of components
-      *comp = tga_bits_per_pixel/8;
-   }
-   tga_data = (unsigned char*)malloc( tga_width * tga_height * req_comp );
-   if (!tga_data) return epuc("outofmem", "Out of memory");
-
-   //   skip to the data's starting position (offset usually = 0)
-   skip(s, tga_offset );
-   //   do I need to load a palette?
-   if ( tga_indexed )
-   {
-      //   any data to skip? (offset usually = 0)
-      skip(s, tga_palette_start );
-      //   load the palette
-      tga_palette = (unsigned char*)malloc( tga_palette_len * tga_palette_bits / 8 );
-      if (!tga_palette) return epuc("outofmem", "Out of memory");
-      if (!getn(s, tga_palette, tga_palette_len * tga_palette_bits / 8 )) {
-         free(tga_data);
-         free(tga_palette);
-         return epuc("bad palette", "Corrupt TGA");
-      }
-   }
-   //   load the data
-   trans_data[0] = trans_data[1] = trans_data[2] = trans_data[3] = 0;
-   for (i=0; i < tga_width * tga_height; ++i)
-   {
-      //   if I'm in RLE mode, do I need to get a RLE chunk?
-      if ( tga_is_RLE )
-      {
-         if ( RLE_count == 0 )
-         {
-            //   yep, get the next byte as a RLE command
-            int RLE_cmd = get8u(s);
-            RLE_count = 1 + (RLE_cmd & 127);
-            RLE_repeating = RLE_cmd >> 7;
-            read_next_pixel = 1;
-         } else if ( !RLE_repeating )
-         {
-            read_next_pixel = 1;
-         }
-      } else
-      {
-         read_next_pixel = 1;
-      }
-      //   OK, if I need to read a pixel, do it now
-      if ( read_next_pixel )
-      {
-         //   load however much data we did have
-         if ( tga_indexed )
-         {
-            //   read in 1 byte, then perform the lookup
-            int pal_idx = get8u(s);
-            if ( pal_idx >= tga_palette_len )
-            {
-               //   invalid index
-               pal_idx = 0;
-            }
-            pal_idx *= tga_bits_per_pixel / 8;
-            for (j = 0; j*8 < tga_bits_per_pixel; ++j)
-            {
-               raw_data[j] = tga_palette[pal_idx+j];
-            }
-         } else
-         {
-            //   read in the data raw
-            for (j = 0; j*8 < tga_bits_per_pixel; ++j)
-            {
-               raw_data[j] = get8u(s);
-            }
-         }
-         //   convert raw to the intermediate format
-         switch (tga_bits_per_pixel)
-         {
-         case 8:
-            //   Luminous => RGBA
-            trans_data[0] = raw_data[0];
-            trans_data[1] = raw_data[0];
-            trans_data[2] = raw_data[0];
-            trans_data[3] = 255;
-            break;
-         case 16:
-            //   Luminous,Alpha => RGBA
-            trans_data[0] = raw_data[0];
-            trans_data[1] = raw_data[0];
-            trans_data[2] = raw_data[0];
-            trans_data[3] = raw_data[1];
-            break;
-         case 24:
-            //   BGR => RGBA
-            trans_data[0] = raw_data[2];
-            trans_data[1] = raw_data[1];
-            trans_data[2] = raw_data[0];
-            trans_data[3] = 255;
-            break;
-         case 32:
-            //   BGRA => RGBA
-            trans_data[0] = raw_data[2];
-            trans_data[1] = raw_data[1];
-            trans_data[2] = raw_data[0];
-            trans_data[3] = raw_data[3];
-            break;
-         }
-         //   clear the reading flag for the next pixel
-         read_next_pixel = 0;
-      } // end of reading a pixel
-      //   convert to final format
-      switch (req_comp)
-      {
-      case 1:
-         //   RGBA => Luminance
-         tga_data[i*req_comp+0] = compute_y(trans_data[0],trans_data[1],trans_data[2]);
-         break;
-      case 2:
-         //   RGBA => Luminance,Alpha
-         tga_data[i*req_comp+0] = compute_y(trans_data[0],trans_data[1],trans_data[2]);
-         tga_data[i*req_comp+1] = trans_data[3];
-         break;
-      case 3:
-         //   RGBA => RGB
-         tga_data[i*req_comp+0] = trans_data[0];
-         tga_data[i*req_comp+1] = trans_data[1];
-         tga_data[i*req_comp+2] = trans_data[2];
-         break;
-      case 4:
-         //   RGBA => RGBA
-         tga_data[i*req_comp+0] = trans_data[0];
-         tga_data[i*req_comp+1] = trans_data[1];
-         tga_data[i*req_comp+2] = trans_data[2];
-         tga_data[i*req_comp+3] = trans_data[3];
-         break;
-      }
-      //   in case we're in RLE mode, keep counting down
-      --RLE_count;
-   }
-   //   do I need to invert the image?
-   if ( tga_inverted )
-   {
-      for (j = 0; j*2 < tga_height; ++j)
-      {
-         int index1 = j * tga_width * req_comp;
-         int index2 = (tga_height - 1 - j) * tga_width * req_comp;
-         for (i = tga_width * req_comp; i > 0; --i)
-         {
-            unsigned char temp = tga_data[index1];
-            tga_data[index1] = tga_data[index2];
-            tga_data[index2] = temp;
-            ++index1;
-            ++index2;
-         }
-      }
-   }
-   //   clear my palette, if I had one
-   if ( tga_palette != NULL )
-   {
-      free( tga_palette );
-   }
-   //   the things I do to get rid of an error message, and yet keep
-   //   Microsoft's C compilers happy... [8^(
-   tga_palette_start = tga_palette_len = tga_palette_bits =
-         tga_x_origin = tga_y_origin = 0;
-   //   OK, done
-   return tga_data;
-}
-
-static stbi_uc *stbi_tga_load(stbi *s, int *x, int *y, int *comp, int req_comp)
-{
-   return tga_load(s,x,y,comp,req_comp);
-}
-
-
-// *************************************************************************************************
-// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB
-
-static int psd_test(stbi *s)
-{
-   if (get32(s) != 0x38425053) return 0;   // "8BPS"
-   else return 1;
-}
-
-static int stbi_psd_test(stbi *s)
-{
-   int r = psd_test(s);
-   stbi_rewind(s);
-   return r;
-}
-
-static stbi_uc *psd_load(stbi *s, int *x, int *y, int *comp, int req_comp)
-{
-   int   pixelCount;
-   int channelCount, compression;
-   int channel, i, count, len;
-   int w,h;
-   Uint8 *out;
-
-   // Check identifier
-   if (get32(s) != 0x38425053)   // "8BPS"
-      return epuc("not PSD", "Corrupt PSD image");
-
-   // Check file type version.
-   if (get16(s) != 1)
-      return epuc("wrong version", "Unsupported version of PSD image");
-
-   // Skip 6 reserved bytes.
-   skip(s, 6 );
-
-   // Read the number of channels (R, G, B, A, etc).
-   channelCount = get16(s);
-   if (channelCount < 0 || channelCount > 16)
-      return epuc("wrong channel count", "Unsupported number of channels in PSD image");
-
-   // Read the rows and columns of the image.
-   h = get32(s);
-   w = get32(s);
-   
-   // Make sure the depth is 8 bits.
-   if (get16(s) != 8)
-      return epuc("unsupported bit depth", "PSD bit depth is not 8 bit");
-
-   // Make sure the color mode is RGB.
-   // Valid options are:
-   //   0: Bitmap
-   //   1: Grayscale
-   //   2: Indexed color
-   //   3: RGB color
-   //   4: CMYK color
-   //   7: Multichannel
-   //   8: Duotone
-   //   9: Lab color
-   if (get16(s) != 3)
-      return epuc("wrong color format", "PSD is not in RGB color format");
-
-   // Skip the Mode Data.  (It's the palette for indexed color; other info for other modes.)
-   skip(s,get32(s) );
-
-   // Skip the image resources.  (resolution, pen tool paths, etc)
-   skip(s, get32(s) );
-
-   // Skip the reserved data.
-   skip(s, get32(s) );
-
-   // Find out if the data is compressed.
-   // Known values:
-   //   0: no compression
-   //   1: RLE compressed
-   compression = get16(s);
-   if (compression > 1)
-      return epuc("bad compression", "PSD has an unknown compression format");
-
-   // Create the destination image.
-   out = (stbi_uc *) malloc(4 * w*h);
-   if (!out) return epuc("outofmem", "Out of memory");
-   pixelCount = w*h;
-
-   // Initialize the data to zero.
-   //memset( out, 0, pixelCount * 4 );
-   
-   // Finally, the image data.
-   if (compression) {
-      // RLE as used by .PSD and .TIFF
-      // Loop until you get the number of unpacked bytes you are expecting:
-      //     Read the next source byte into n.
-      //     If n is between 0 and 127 inclusive, copy the next n+1 bytes literally.
-      //     Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times.
-      //     Else if n is 128, noop.
-      // Endloop
-
-      // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data,
-      // which we're going to just skip.
-      skip(s, h * channelCount * 2 );
-
-      // Read the RLE data by channel.
-      for (channel = 0; channel < 4; channel++) {
-         Uint8 *p;
-         
-         p = out+channel;
-         if (channel >= channelCount) {
-            // Fill this channel with default data.
-            for (i = 0; i < pixelCount; i++) *p = (channel == 3 ? 255 : 0), p += 4;
-         } else {
-            // Read the RLE data.
-            count = 0;
-            while (count < pixelCount) {
-               len = get8(s);
-               if (len == 128) {
-                  // No-op.
-               } else if (len < 128) {
-                  // Copy next len+1 bytes literally.
-                  len++;
-                  count += len;
-                  while (len) {
-                     *p = get8u(s);
-                     p += 4;
-                     len--;
-                  }
-               } else if (len > 128) {
-                  Uint8   val;
-                  // Next -len+1 bytes in the dest are replicated from next source byte.
-                  // (Interpret len as a negative 8-bit int.)
-                  len ^= 0x0FF;
-                  len += 2;
-                  val = get8u(s);
-                  count += len;
-                  while (len) {
-                     *p = val;
-                     p += 4;
-                     len--;
-                  }
-               }
-            }
-         }
-      }
-      
-   } else {
-      // We're at the raw image data.  It's each channel in order (Red, Green, Blue, Alpha, ...)
-      // where each channel consists of an 8-bit value for each pixel in the image.
-      
-      // Read the data by channel.
-      for (channel = 0; channel < 4; channel++) {
-         Uint8 *p;
-         
-         p = out + channel;
-         if (channel > channelCount) {
-            // Fill this channel with default data.
-            for (i = 0; i < pixelCount; i++) *p = channel == 3 ? 255 : 0, p += 4;
-         } else {
-            // Read the data.
-            for (i = 0; i < pixelCount; i++)
-               *p = get8u(s), p += 4;
-         }
-      }
-   }
-
-   if (req_comp && req_comp != 4) {
-      out = convert_format(out, 4, req_comp, w, h);
-      if (out == NULL) return out; // convert_format frees input on failure
-   }
-
-   if (comp) *comp = channelCount;
-   *y = h;
-   *x = w;
-   
-   return out;
-}
-
-static stbi_uc *stbi_psd_load(stbi *s, int *x, int *y, int *comp, int req_comp)
-{
-   return psd_load(s,x,y,comp,req_comp);
-}
-
-// *************************************************************************************************
-// Softimage PIC loader
-// by Tom Seddon
-//
-// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format
-// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/
-
-static int pic_is4(stbi *s,const char *str)
-{
-   int i;
-   for (i=0; i<4; ++i)
-      if (get8(s) != (stbi_uc)str[i])
-         return 0;
-
-   return 1;
-}
-
-static int pic_test(stbi *s)
-{
-   int i;
-
-   if (!pic_is4(s,"\x53\x80\xF6\x34"))
-      return 0;
-
-   for(i=0;i<84;++i)
-      get8(s);
-
-   if (!pic_is4(s,"PICT"))
-      return 0;
-
-   return 1;
-}
-
-typedef struct
-{
-   stbi_uc size,type,channel;
-} pic_packet_t;
-
-static stbi_uc *pic_readval(stbi *s, int channel, stbi_uc *dest)
-{
-   int mask=0x80, i;
-
-   for (i=0; i<4; ++i, mask>>=1) {
-      if (channel & mask) {
-         if (at_eof(s)) return epuc("bad file","PIC file too short");
-         dest[i]=get8u(s);
-      }
-   }
-
-   return dest;
-}
-
-static void pic_copyval(int channel,stbi_uc *dest,const stbi_uc *src)
-{
-   int mask=0x80,i;
-
-   for (i=0;i<4; ++i, mask>>=1)
-      if (channel&mask)
-         dest[i]=src[i];
-}
-
-static stbi_uc *pic_load2(stbi *s,int width,int height,int *comp, stbi_uc *result)
-{
-   int act_comp=0,num_packets=0,y,chained;
-   pic_packet_t packets[10];
-
-   // this will (should...) cater for even some bizarre stuff like having data
-    // for the same channel in multiple packets.
-   do {
-      pic_packet_t *packet;
-
-      if (num_packets==sizeof(packets)/sizeof(packets[0]))
-         return epuc("bad format","too many packets");
-
-      packet = &packets[num_packets++];
-
-      chained = get8(s);
-      packet->size    = get8u(s);
-      packet->type    = get8u(s);
-      packet->channel = get8u(s);
-
-      act_comp |= packet->channel;
-
-      if (at_eof(s))          return epuc("bad file","file too short (reading packets)");
-      if (packet->size != 8)  return epuc("bad format","packet isn't 8bpp");
-   } while (chained);
-
-   *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel?
-
-   for(y=0; y<height; ++y) {
-      int packet_idx;
-
-      for(packet_idx=0; packet_idx < num_packets; ++packet_idx) {
-         pic_packet_t *packet = &packets[packet_idx];
-         stbi_uc *dest = result+y*width*4;
-
-         switch (packet->type) {
-            default:
-               return epuc("bad format","packet has bad compression type");
-
-            case 0: {//uncompressed
-               int x;
-
-               for(x=0;x<width;++x, dest+=4)
-                  if (!pic_readval(s,packet->channel,dest))
-                     return 0;
-               break;
-            }
-
-            case 1://Pure RLE
-               {
-                  int left=width, i;
-
-                  while (left>0) {
-                     stbi_uc count,value[4];
-
-                     count=get8u(s);
-                     if (at_eof(s))   return epuc("bad file","file too short (pure read count)");
-
-                     if (count > left)
-                        count = (Uint8) left;
-
-                     if (!pic_readval(s,packet->channel,value))  return 0;
-
-                     for(i=0; i<count; ++i,dest+=4)
-                        pic_copyval(packet->channel,dest,value);
-                     left -= count;
-                  }
-               }
-               break;
-
-            case 2: {//Mixed RLE
-               int left=width;
-               while (left>0) {
-                  int count = get8(s), i;
-                  if (at_eof(s))  return epuc("bad file","file too short (mixed read count)");
-
-                  if (count >= 128) { // Repeated
-                     stbi_uc value[4];
-                     int i;
-
-                     if (count==128)
-                        count = get16(s);
-                     else
-                        count -= 127;
-                     if (count > left)
-                        return epuc("bad file","scanline overrun");
-
-                     if (!pic_readval(s,packet->channel,value))
-                        return 0;
-
-                     for(i=0;i<count;++i, dest += 4)
-                        pic_copyval(packet->channel,dest,value);
-                  } else { // Raw
-                     ++count;
-                     if (count>left) return epuc("bad file","scanline overrun");
-
-                     for(i=0;i<count;++i, dest+=4)
-                        if (!pic_readval(s,packet->channel,dest))
-                           return 0;
-                  }
-                  left-=count;
-               }
-               break;
-            }
-         }
-      }
-   }
-
-   return result;
-}
-
-static stbi_uc *pic_load(stbi *s,int *px,int *py,int *comp,int req_comp)
-{
-   stbi_uc *result;
-   int i, x,y;
-
-   for (i=0; i<92; ++i)
-      get8(s);
-
-   x = get16(s);
-   y = get16(s);
-   if (at_eof(s))  return epuc("bad file","file too short (pic header)");
-   if ((1 << 28) / x < y) return epuc("too large", "Image too large to decode");
-
-   get32(s); //skip `ratio'
-   get16(s); //skip `fields'
-   get16(s); //skip `pad'
-
-   // intermediate buffer is RGBA
-   result = (stbi_uc *) malloc(x*y*4);
-   memset(result, 0xff, x*y*4);
-
-   if (!pic_load2(s,x,y,comp, result)) {
-      free(result);
-      result=0;
-   }
-   *px = x;
-   *py = y;
-   if (req_comp == 0) req_comp = *comp;
-   result=convert_format(result,4,req_comp,x,y);
-
-   return result;
-}
-
-static int stbi_pic_test(stbi *s)
-{
-   int r = pic_test(s);
-   stbi_rewind(s);
-   return r;
-}
-
-static stbi_uc *stbi_pic_load(stbi *s, int *x, int *y, int *comp, int req_comp)
-{
-   return pic_load(s,x,y,comp,req_comp);
-}
-
-// *************************************************************************************************
-// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb
-typedef struct stbi_gif_lzw_struct {
-   int16 prefix;
-   Uint8 first;
-   Uint8 suffix;
-} stbi_gif_lzw;
-
-typedef struct stbi_gif_struct
-{
-   int w,h;
-   stbi_uc *out;                 // output buffer (always 4 components)
-   int flags, bgindex, ratio, transparent, eflags;
-   Uint8  pal[256][4];
-   Uint8 lpal[256][4];
-   stbi_gif_lzw codes[4096];
-   Uint8 *color_table;
-   int parse, step;
-   int lflags;
-   int start_x, start_y;
-   int max_x, max_y;
-   int cur_x, cur_y;
-   int line_size;
-} stbi_gif;
-
-static int gif_test(stbi *s)
-{
-   int sz;
-   if (get8(s) != 'G' || get8(s) != 'I' || get8(s) != 'F' || get8(s) != '8') return 0;
-   sz = get8(s);
-   if (sz != '9' && sz != '7') return 0;
-   if (get8(s) != 'a') return 0;
-   return 1;
-}
-
-static int stbi_gif_test(stbi *s)
-{
-   int r = gif_test(s);
-   stbi_rewind(s);
-   return r;
-}
-
-static void stbi_gif_parse_colortable(stbi *s, Uint8 pal[256][4], int num_entries, int transp)
-{
-   int i;
-   for (i=0; i < num_entries; ++i) {
-      pal[i][2] = get8u(s);
-      pal[i][1] = get8u(s);
-      pal[i][0] = get8u(s);
-      pal[i][3] = transp ? 0 : 255;
-   }   
-}
-
-static int stbi_gif_header(stbi *s, stbi_gif *g, int *comp, int is_info)
-{
-   Uint8 version;
-   if (get8(s) != 'G' || get8(s) != 'I' || get8(s) != 'F' || get8(s) != '8')
-      return e("not GIF", "Corrupt GIF");
-
-   version = get8u(s);
-   if (version != '7' && version != '9')    return e("not GIF", "Corrupt GIF");
-   if (get8(s) != 'a')                      return e("not GIF", "Corrupt GIF");
- 
-   failure_reason = "";
-   g->w = get16le(s);
-   g->h = get16le(s);
-   g->flags = get8(s);
-   g->bgindex = get8(s);
-   g->ratio = get8(s);
-   g->transparent = -1;
-
-   if (comp != 0) *comp = 4;  // can't actually tell whether it's 3 or 4 until we parse the comments
-
-   if (is_info) return 1;
-
-   if (g->flags & 0x80)
-      stbi_gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1);
-
-   return 1;
-}
-
-static int stbi_gif_info_raw(stbi *s, int *x, int *y, int *comp)
-{
-   stbi_gif g;   
-   if (!stbi_gif_header(s, &g, comp, 1)) {
-      stbi_rewind( s );
-      return 0;
-   }
-   if (x) *x = g.w;
-   if (y) *y = g.h;
-   return 1;
-}
-
-static void stbi_out_gif_code(stbi_gif *g, Uint16 code)
-{
-   Uint8 *p, *c;
-
-   // recurse to decode the prefixes, since the linked-list is backwards,
-   // and working backwards through an interleaved image would be nasty
-   if (g->codes[code].prefix >= 0)
-      stbi_out_gif_code(g, g->codes[code].prefix);
-
-   if (g->cur_y >= g->max_y) return;
-  
-   p = &g->out[g->cur_x + g->cur_y];
-   c = &g->color_table[g->codes[code].suffix * 4];
-
-   if (c[3] >= 128) {
-      p[0] = c[2];
-      p[1] = c[1];
-      p[2] = c[0];
-      p[3] = c[3];
-   }
-   g->cur_x += 4;
-
-   if (g->cur_x >= g->max_x) {
-      g->cur_x = g->start_x;
-      g->cur_y += g->step;
-
-      while (g->cur_y >= g->max_y && g->parse > 0) {
-         g->step = (1 << g->parse) * g->line_size;
-         g->cur_y = g->start_y + (g->step >> 1);
-         --g->parse;
-      }
-   }
-}
-
-static Uint8 *stbi_process_gif_raster(stbi *s, stbi_gif *g)
-{
-   Uint8 lzw_cs;
-   int32 len, code;
-   Uint32 first;
-   int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear;
-   stbi_gif_lzw *p;
-
-   lzw_cs = get8u(s);
-   clear = 1 << lzw_cs;
-   first = 1;
-   codesize = lzw_cs + 1;
-   codemask = (1 << codesize) - 1;
-   bits = 0;
-   valid_bits = 0;
-   for (code = 0; code < clear; code++) {
-      g->codes[code].prefix = -1;
-      g->codes[code].first = (Uint8) code;
-      g->codes[code].suffix = (Uint8) code;
-   }
-
-   // support no starting clear code
-   avail = clear+2;
-   oldcode = -1;
-
-   len = 0;
-   for(;;) {
-      if (valid_bits < codesize) {
-         if (len == 0) {
-            len = get8(s); // start new block
-            if (len == 0) 
-               return g->out;
-         }
-         --len;
-         bits |= (int32) get8(s) << valid_bits;
-         valid_bits += 8;
-      } else {
-         int32 code = bits & codemask;
-         bits >>= codesize;
-         valid_bits -= codesize;
-         // @OPTIMIZE: is there some way we can accelerate the non-clear path?
-         if (code == clear) {  // clear code
-            codesize = lzw_cs + 1;
-            codemask = (1 << codesize) - 1;
-            avail = clear + 2;
-            oldcode = -1;
-            first = 0;
-         } else if (code == clear + 1) { // end of stream code
-            skip(s, len);
-            while ((len = get8(s)) > 0)
-               skip(s,len);
-            return g->out;
-         } else if (code <= avail) {
-            if (first) return epuc("no clear code", "Corrupt GIF");
-
-            if (oldcode >= 0) {
-               p = &g->codes[avail++];
-               if (avail > 4096)        return epuc("too many codes", "Corrupt GIF");
-               p->prefix = (int16) oldcode;
-               p->first = g->codes[oldcode].first;
-               p->suffix = (code == avail) ? p->first : g->codes[code].first;
-            } else if (code == avail)
-               return epuc("illegal code in raster", "Corrupt GIF");
-
-            stbi_out_gif_code(g, (Uint16) code);
-
-            if ((avail & codemask) == 0 && avail <= 0x0FFF) {
-               codesize++;
-               codemask = (1 << codesize) - 1;
-            }
-
-            oldcode = code;
-         } else {
-            return epuc("illegal code in raster", "Corrupt GIF");
-         }
-      } 
-   }
-}
-
-static void stbi_fill_gif_background(stbi_gif *g)
-{
-   int i;
-   Uint8 *c = g->pal[g->bgindex];
-   // @OPTIMIZE: write a dword at a time
-   for (i = 0; i < g->w * g->h * 4; i += 4) {
-      Uint8 *p  = &g->out[i];
-      p[0] = c[2];
-      p[1] = c[1];
-      p[2] = c[0];
-      p[3] = c[3];
-   }
-}
-
-// this function is designed to support animated gifs, although stb_image doesn't support it
-static Uint8 *stbi_gif_load_next(stbi *s, stbi_gif *g, int *comp, int req_comp)
-{
-   int i;
-   Uint8 *old_out = 0;
-
-   if (g->out == 0) {
-      if (!stbi_gif_header(s, g, comp,0))     return 0; // failure_reason set by stbi_gif_header
-      g->out = (Uint8 *) malloc(4 * g->w * g->h);
-      if (g->out == 0)                      return epuc("outofmem", "Out of memory");
-      stbi_fill_gif_background(g);
-   } else {
-      // animated-gif-only path
-      if (((g->eflags & 0x1C) >> 2) == 3) {
-         old_out = g->out;
-         g->out = (Uint8 *) malloc(4 * g->w * g->h);
-         if (g->out == 0)                   return epuc("outofmem", "Out of memory");
-         memcpy(g->out, old_out, g->w*g->h*4);
-      }
-   }
-    
-   for (;;) {
-      switch (get8(s)) {
-         case 0x2C: // Image Descriptor
-         {
-            int32 x, y, w, h;
-            Uint8 *o;
-
-            x = get16le(s);
-            y = get16le(s);
-            w = get16le(s);
-            h = get16le(s);
-            if (((x + w) > (g->w)) || ((y + h) > (g->h)))
-               return epuc("bad Image Descriptor", "Corrupt GIF");
-
-            g->line_size = g->w * 4;
-            g->start_x = x * 4;
-            g->start_y = y * g->line_size;
-            g->max_x   = g->start_x + w * 4;
-            g->max_y   = g->start_y + h * g->line_size;
-            g->cur_x   = g->start_x;
-            g->cur_y   = g->start_y;
-
-            g->lflags = get8(s);
-
-            if (g->lflags & 0x40) {
-               g->step = 8 * g->line_size; // first interlaced spacing
-               g->parse = 3;
-            } else {
-               g->step = g->line_size;
-               g->parse = 0;
-            }
-
-            if (g->lflags & 0x80) {
-               stbi_gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1);
-               g->color_table = (Uint8 *) g->lpal;       
-            } else if (g->flags & 0x80) {
-               for (i=0; i < 256; ++i)  // @OPTIMIZE: reset only the previous transparent
-                  g->pal[i][3] = 255; 
-               if (g->transparent >= 0 && (g->eflags & 0x01))
-                  g->pal[g->transparent][3] = 0;
-               g->color_table = (Uint8 *) g->pal;
-            } else
-               return epuc("missing color table", "Corrupt GIF");
-   
-            o = stbi_process_gif_raster(s, g);
-            if (o == NULL) return NULL;
-
-            if (req_comp && req_comp != 4)
-               o = convert_format(o, 4, req_comp, g->w, g->h);
-            return o;
-         }
-
-         case 0x21: // Comment Extension.
-         {
-            int len;
-            if (get8(s) == 0xF9) { // Graphic Control Extension.
-               len = get8(s);
-               if (len == 4) {
-                  g->eflags = get8(s);
-                  get16le(s); // delay
-                  g->transparent = get8(s);
-               } else {
-                  skip(s, len);
-                  break;
-               }
-            }
-            while ((len = get8(s)) != 0)
-               skip(s, len);
-            break;
-         }
-
-         case 0x3B: // gif stream termination code
-            return (Uint8 *) 1;
-
-         default:
-            return epuc("unknown code", "Corrupt GIF");
-      }
-   }
-}
-
-static stbi_uc *stbi_gif_load(stbi *s, int *x, int *y, int *comp, int req_comp)
-{
-   Uint8 *u = 0;
-   stbi_gif g={0};
-
-   u = stbi_gif_load_next(s, &g, comp, req_comp);
-   if (u == (void *) 1) u = 0;  // end of animated gif marker
-   if (u) {
-      *x = g.w;
-      *y = g.h;
-   }
-
-   return u;
-}
-
-static int stbi_gif_info(stbi *s, int *x, int *y, int *comp)
-{
-   return stbi_gif_info_raw(s,x,y,comp);
-}
-
-#endif
-
-// *************************************************************************************************
-// Radiance RGBE HDR loader
-// originally by Nicolas Schulz
-#ifndef STBI_NO_HDR
-static int hdr_test(stbi *s)
-{
-   const char *signature = "#?RADIANCE\n";
-   int i;
-   for (i=0; signature[i]; ++i)
-      if (get8(s) != signature[i])
-         return 0;
-   return 1;
-}
-
-static int stbi_hdr_test(stbi* s)
-{
-   int r = hdr_test(s);
-   stbi_rewind(s);
-   return r;
-}
-
-#define HDR_BUFLEN  1024
-static char *hdr_gettoken(stbi *z, char *buffer)
-{
-   int len=0;
-   char c = '\0';
-
-   c = (char) get8(z);
-
-   while (!at_eof(z) && c != '\n') {
-      buffer[len++] = c;
-      if (len == HDR_BUFLEN-1) {
-         // flush to end of line
-         while (!at_eof(z) && get8(z) != '\n')
-            ;
-         break;
-      }
-      c = (char) get8(z);
-   }
-
-   buffer[len] = 0;
-   return buffer;
-}
-
-static void hdr_convert(float *output, stbi_uc *input, int req_comp)
-{
-   if ( input[3] != 0 ) {
-      float f1;
-      // Exponent
-      f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8));
-      if (req_comp <= 2)
-         output[0] = (input[0] + input[1] + input[2]) * f1 / 3;
-      else {
-         output[0] = input[0] * f1;
-         output[1] = input[1] * f1;
-         output[2] = input[2] * f1;
-      }
-      if (req_comp == 2) output[1] = 1;
-      if (req_comp == 4) output[3] = 1;
-   } else {
-      switch (req_comp) {
-         case 4: output[3] = 1; // fallthrough
-         case 3: output[0] = output[1] = output[2] = 0;
-                 break;
-         case 2: output[1] = 1; // fallthrough
-         case 1: output[0] = 0;
-                 break;
-      }
-   }
-}
-
-static float *hdr_load(stbi *s, int *x, int *y, int *comp, int req_comp)
-{
-   char buffer[HDR_BUFLEN];
-   char *token;
-   int valid = 0;
-   int width, height;
-   stbi_uc *scanline;
-   float *hdr_data;
-   int len;
-   unsigned char count, value;
-   int i, j, k, c1,c2, z;
-
-
-   // Check identifier
-   if (strcmp(hdr_gettoken(s,buffer), "#?RADIANCE") != 0)
-      return epf("not HDR", "Corrupt HDR image");
-   
-   // Parse header
-   for(;;) {
-      token = hdr_gettoken(s,buffer);
-      if (token[0] == 0) break;
-      if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1;
-   }
-
-   if (!valid)    return epf("unsupported format", "Unsupported HDR format");
-
-   // Parse width and height
-   // can't use sscanf() if we're not using stdio!
-   token = hdr_gettoken(s,buffer);
-   if (strncmp(token, "-Y ", 3))  return epf("unsupported data layout", "Unsupported HDR format");
-   token += 3;
-   height = strtol(token, &token, 10);
-   while (*token == ' ') ++token;
-   if (strncmp(token, "+X ", 3))  return epf("unsupported data layout", "Unsupported HDR format");
-   token += 3;
-   width = strtol(token, NULL, 10);
-
-   *x = width;
-   *y = height;
-
-   *comp = 3;
-   if (req_comp == 0) req_comp = 3;
-
-   // Read data
-   hdr_data = (float *) malloc(height * width * req_comp * sizeof(float));
-
-   // Load image data
-   // image data is stored as some number of sca
-   if ( width < 8 || width >= 32768) {
-      // Read flat data
-      for (j=0; j < height; ++j) {
-         for (i=0; i < width; ++i) {
-            stbi_uc rgbe[4];
-           main_decode_loop:
-            getn(s, rgbe, 4);
-            hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp);
-         }
-      }
-   } else {
-      // Read RLE-encoded data
-      scanline = NULL;
-
-      for (j = 0; j < height; ++j) {
-         c1 = get8(s);
-         c2 = get8(s);
-         len = get8(s);
-         if (c1 != 2 || c2 != 2 || (len & 0x80)) {
-            // not run-length encoded, so we have to actually use THIS data as a decoded
-            // pixel (note this can't be a valid pixel--one of RGB must be >= 128)
-            Uint8 rgbe[4];
-            rgbe[0] = (Uint8) c1;
-            rgbe[1] = (Uint8) c2;
-            rgbe[2] = (Uint8) len;
-            rgbe[3] = (Uint8) get8u(s);
-            hdr_convert(hdr_data, rgbe, req_comp);
-            i = 1;
-            j = 0;
-            free(scanline);
-            goto main_decode_loop; // yes, this makes no sense
-         }
-         len <<= 8;
-         len |= get8(s);
-         if (len != width) { free(hdr_data); free(scanline); return epf("invalid decoded scanline length", "corrupt HDR"); }
-         if (scanline == NULL) scanline = (stbi_uc *) malloc(width * 4);
-            
-         for (k = 0; k < 4; ++k) {
-            i = 0;
-            while (i < width) {
-               count = get8u(s);
-               if (count > 128) {
-                  // Run
-                  value = get8u(s);
-                  count -= 128;
-                  for (z = 0; z < count; ++z)
-                     scanline[i++ * 4 + k] = value;
-               } else {
-                  // Dump
-                  for (z = 0; z < count; ++z)
-                     scanline[i++ * 4 + k] = get8u(s);
-               }
-            }
-         }
-         for (i=0; i < width; ++i)
-            hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp);
-      }
-      free(scanline);
-   }
-
-   return hdr_data;
-}
-
-static float *stbi_hdr_load(stbi *s, int *x, int *y, int *comp, int req_comp)
-{
-   return hdr_load(s,x,y,comp,req_comp);
-}
-
-static int stbi_hdr_info(stbi *s, int *x, int *y, int *comp)
-{
-   char buffer[HDR_BUFLEN];
-   char *token;
-   int valid = 0;
-
-   if (strcmp(hdr_gettoken(s,buffer), "#?RADIANCE") != 0) {
-       stbi_rewind( s );
-       return 0;
-   }
-
-   for(;;) {
-      token = hdr_gettoken(s,buffer);
-      if (token[0] == 0) break;
-      if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1;
-   }
-
-   if (!valid) {
-       stbi_rewind( s );
-       return 0;
-   }
-   token = hdr_gettoken(s,buffer);
-   if (strncmp(token, "-Y ", 3)) {
-       stbi_rewind( s );
-       return 0;
-   }
-   token += 3;
-   *y = strtol(token, &token, 10);
-   while (*token == ' ') ++token;
-   if (strncmp(token, "+X ", 3)) {
-       stbi_rewind( s );
-       return 0;
-   }
-   token += 3;
-   *x = strtol(token, NULL, 10);
-   *comp = 3;
-   return 1;
-}
-#endif // STBI_NO_HDR
-
-#ifdef STBI_CRAP_FORMATS
-
-static int stbi_bmp_info(stbi *s, int *x, int *y, int *comp)
-{
-   int hsz;
-   if (get8(s) != 'B' || get8(s) != 'M') {
-       stbi_rewind( s );
-       return 0;
-   }
-   skip(s,12);
-   hsz = get32le(s);
-   if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108) {
-       stbi_rewind( s );
-       return 0;
-   }
-   if (hsz == 12) {
-      *x = get16le(s);
-      *y = get16le(s);
-   } else {
-      *x = get32le(s);
-      *y = get32le(s);
-   }
-   if (get16le(s) != 1) {
-       stbi_rewind( s );
-       return 0;
-   }
-   *comp = get16le(s) / 8;
-   return 1;
-}
-
-static int stbi_psd_info(stbi *s, int *x, int *y, int *comp)
-{
-   int channelCount;
-   if (get32(s) != 0x38425053) {
-       stbi_rewind( s );
-       return 0;
-   }
-   if (get16(s) != 1) {
-       stbi_rewind( s );
-       return 0;
-   }
-   skip(s, 6);
-   channelCount = get16(s);
-   if (channelCount < 0 || channelCount > 16) {
-       stbi_rewind( s );
-       return 0;
-   }
-   *y = get32(s);
-   *x = get32(s);
-   if (get16(s) != 8) {
-       stbi_rewind( s );
-       return 0;
-   }
-   if (get16(s) != 3) {
-       stbi_rewind( s );
-       return 0;
-   }
-   *comp = 4;
-   return 1;
-}
-
-static int stbi_pic_info(stbi *s, int *x, int *y, int *comp)
-{
-   int act_comp=0,num_packets=0,chained;
-   pic_packet_t packets[10];
-
-   skip(s, 92);
-
-   *x = get16(s);
-   *y = get16(s);
-   if (at_eof(s))  return 0;
-   if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) {
-       stbi_rewind( s );
-       return 0;
-   }
-
-   skip(s, 8);
-
-   do {
-      pic_packet_t *packet;
-
-      if (num_packets==sizeof(packets)/sizeof(packets[0]))
-         return 0;
-
-      packet = &packets[num_packets++];
-      chained = get8(s);
-      packet->size    = get8u(s);
-      packet->type    = get8u(s);
-      packet->channel = get8u(s);
-      act_comp |= packet->channel;
-
-      if (at_eof(s)) {
-          stbi_rewind( s );
-          return 0;
-      }
-      if (packet->size != 8) {
-          stbi_rewind( s );
-          return 0;
-      }
-   } while (chained);
-
-   *comp = (act_comp & 0x10 ? 4 : 3);
-
-   return 1;
-}
-#endif
-
-
-static int stbi_info_main(stbi *s, int *x, int *y, int *comp)
-{
-   if (stbi_jpeg_info(s, x, y, comp))
-       return 1;
-   if (stbi_png_info(s, x, y, comp))
-       return 1;
-#ifdef STBI_CRAP_FORMATS
-   if (stbi_gif_info(s, x, y, comp))
-       return 1;
-   if (stbi_bmp_info(s, x, y, comp))
-       return 1;
-   if (stbi_psd_info(s, x, y, comp))
-       return 1;
-   if (stbi_pic_info(s, x, y, comp))
-       return 1;
-   #ifndef STBI_NO_HDR
-   if (stbi_hdr_info(s, x, y, comp))
-       return 1;
-   #endif
-   // test tga last because it's a crappy test!
-   if (stbi_tga_info(s, x, y, comp))
-       return 1;
-#endif
-   return e("unknown image type", "Image not of any known type, or corrupt");
-}
-
-#ifndef STBI_NO_STDIO
-int stbi_info(char const *filename, int *x, int *y, int *comp)
-{
-    FILE *f = fopen(filename, "rb");
-    int result;
-    if (!f) return e("can't fopen", "Unable to open file");
-    result = stbi_info_from_file(f, x, y, comp);
-    fclose(f);
-    return result;
-}
-
-int stbi_info_from_file(FILE *f, int *x, int *y, int *comp)
-{
-   int r;
-   stbi s;
-   long pos = ftell(f);
-   start_file(&s, f);
-   r = stbi_info_main(&s,x,y,comp);
-   fseek(f,pos,SEEK_SET);
-   return r;
-}
-#endif // !STBI_NO_STDIO
-
-int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp)
-{
-   stbi s;
-   start_mem(&s,buffer,len);
-   return stbi_info_main(&s,x,y,comp);
-}
-
-int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp)
-{
-   stbi s;
-   start_callbacks(&s, (stbi_io_callbacks *) c, user);
-   return stbi_info_main(&s,x,y,comp);
-}
-
-#endif // STBI_HEADER_FILE_ONLY
-
-/*
-   revision history:
-      1.33 (2011-07-14)
-             make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements
-      1.32 (2011-07-13)
-             support for "info" function for all supported filetypes (SpartanJ)
-      1.31 (2011-06-20)
-             a few more leak fixes, bug in PNG handling (SpartanJ)
-      1.30 (2011-06-11)
-             added ability to load files via callbacks to accomidate custom input streams (Ben Wenger)
-             removed deprecated format-specific test/load functions
-             removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway
-             error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha)
-             fix inefficiency in decoding 32-bit BMP (David Woo)
-      1.29 (2010-08-16)
-             various warning fixes from Aurelien Pocheville 
-      1.28 (2010-08-01)
-             fix bug in GIF palette transparency (SpartanJ)
-      1.27 (2010-08-01)
-             cast-to-Uint8 to fix warnings
-      1.26 (2010-07-24)
-             fix bug in file buffering for PNG reported by SpartanJ
-      1.25 (2010-07-17)
-             refix trans_data warning (Won Chun)
-      1.24 (2010-07-12)
-             perf improvements reading from files on platforms with lock-heavy fgetc()
-             minor perf improvements for jpeg
-             deprecated type-specific functions so we'll get feedback if they're needed
-             attempt to fix trans_data warning (Won Chun)
-      1.23   fixed bug in iPhone support
-      1.22 (2010-07-10)
-             removed image *writing* support
-             stbi_info support from Jetro Lauha
-             GIF support from Jean-Marc Lienher
-             iPhone PNG-extensions from James Brown
-             warning-fixes from Nicolas Schulz and Janez Zemva (i.e. Janez (U+017D)emva)
-      1.21   fix use of 'Uint8' in header (reported by jon blow)
-      1.20   added support for Softimage PIC, by Tom Seddon
-      1.19   bug in interlaced PNG corruption check (found by ryg)
-      1.18 2008-08-02
-             fix a threading bug (local mutable static)
-      1.17   support interlaced PNG
-      1.16   major bugfix - convert_format converted one too many pixels
-      1.15   initialize some fields for thread safety
-      1.14   fix threadsafe conversion bug
-             header-file-only version (#define STBI_HEADER_FILE_ONLY before including)
-      1.13   threadsafe
-      1.12   const qualifiers in the API
-      1.11   Support installable IDCT, colorspace conversion routines
-      1.10   Fixes for 64-bit (don't use "unsigned long")
-             optimized upsampling by Fabian "ryg" Giesen
-      1.09   Fix format-conversion for PSD code (bad global variables!)
-      1.08   Thatcher Ulrich's PSD code integrated by Nicolas Schulz
-      1.07   attempt to fix C++ warning/errors again
-      1.06   attempt to fix C++ warning/errors again
-      1.05   fix TGA loading to return correct *comp and use good luminance calc
-      1.04   default float alpha is 1, not 255; use 'void *' for stbi_image_free
-      1.03   bugfixes to STBI_NO_STDIO, STBI_NO_HDR
-      1.02   support for (subset of) HDR files, float interface for preferred access to them
-      1.01   fix bug: possible bug in handling right-side up bmps... not sure
-             fix bug: the stbi_bmp_load() and stbi_tga_load() functions didn't work at all
-      1.00   interface to zlib that skips zlib header
-      0.99   correct handling of alpha in palette
-      0.98   TGA loader by lonesock; dynamically add loaders (untested)
-      0.97   jpeg errors on too large a file; also catch another malloc failure
-      0.96   fix detection of invalid v value - particleman@mollyrocket forum
-      0.95   during header scan, seek to markers in case of padding
-      0.94   STBI_NO_STDIO to disable stdio usage; rename all #defines the same
-      0.93   handle jpegtran output; verbose errors
-      0.92   read 4,8,16,24,32-bit BMP files of several formats
-      0.91   output 24-bit Windows 3.0 BMP files
-      0.90   fix a few more warnings; bump version number to approach 1.0
-      0.61   bugfixes due to Marc LeBlanc, Christopher Lloyd
-      0.60   fix compiling as c++
-      0.59   fix warnings: merge Dave Moore's -Wall fixes
-      0.58   fix bug: zlib uncompressed mode len/nlen was wrong endian
-      0.57   fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available
-      0.56   fix bug: zlib uncompressed mode len vs. nlen
-      0.55   fix bug: restart_interval not initialized to 0
-      0.54   allow NULL for 'int *comp'
-      0.53   fix bug in png 3->4; speedup png decoding
-      0.52   png handles req_comp=3,4 directly; minor cleanup; jpeg comments
-      0.51   obey req_comp requests, 1-component jpegs return as 1-component,
-             on 'test' only check type, not whether we support this variant
-      0.50   first released version
-*/