Mercurial > hg > dmlib
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, ¤t_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, ¶m->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, ¶m->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, ¤t_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, ¶m->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, ¶m->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 -*/