From 8a35211f7349da396962a13c680144c1fbef9802 Mon Sep 17 00:00:00 2001 From: meep-eep Date: Fri, 10 Jan 2003 15:58:25 +0000 Subject: [PATCH] Tool for making mng animations, for later, from fOSSiL. git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@539 8092fc87-c524-0410-9efc-e669fe64eaf9 --- tools/mng/Makefile | 37 + tools/mng/Release/makemng.exe | Bin 0 -> 65505 bytes tools/mng/filelist.c | 276 ++++++ tools/mng/makemng.c | 1765 +++++++++++++++++++++++++++++++++ tools/mng/makemng.dsp | 114 +++ tools/mng/makemng.dsw | 29 + 6 files changed, 2221 insertions(+) create mode 100755 tools/mng/Makefile create mode 100755 tools/mng/Release/makemng.exe create mode 100755 tools/mng/filelist.c create mode 100755 tools/mng/makemng.c create mode 100755 tools/mng/makemng.dsp create mode 100755 tools/mng/makemng.dsw diff --git a/tools/mng/Makefile b/tools/mng/Makefile new file mode 100755 index 000000000..3729cfd1b --- /dev/null +++ b/tools/mng/Makefile @@ -0,0 +1,37 @@ +######################################################################## +# This is a GNU makefile - tested on CYGWIN only though. +# +# You may need to compile or install libmng before compiling this. +# Libmng also requires zlib, jpeg and lcms +# + +TARGET = makemng +# These flags are needed to get it to compile with libmng.dll on CYGWIN +# CYGWINFLAGS = -DMNG_USE_DLL +CYGWINFLAGS = +MNGFLAGS = -I. -DMNG_SKIP_LCMS -DMNG_SKIP_IJG6B \ + -DMNG_SUPPORT_READ -DMNG_SUPPORT_WRITE -DMNG_SUPPORT_DISPLAY \ + -DMNG_ACCESS_CHUNKS + +CC = gcc +CFLAGS = -W -Wall -O0 # -g +LIBS = -L/usr/local/lib -lmng -lm -lz -ljpeg -llcms +LDFLAGS= + +BINS = $(TARGET) $(TARGET).exe +SRCS = makemng.c filelist.c +OBJS = makemng.o filelist.o + +.SUFFIXES: .c .o + +.c.o: + $(CC) -c $(CFLAGS) -o $@ $*.c $(MNGFLAGS) $(CYGWINFLAGS) + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(CC) -o $(TARGET) $(OBJS) $(LIBS) $(LDFLAGS) + +clean: + rm -f $(BINS) *.o + diff --git a/tools/mng/Release/makemng.exe b/tools/mng/Release/makemng.exe new file mode 100755 index 0000000000000000000000000000000000000000..8348ce60b683942483e1757df4eb50e2afb11682 GIT binary patch literal 65505 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 +#include +#include +#include + +char** +make_file_list (const char* pattern, int* pnum_entries) +{ + int num_entries, length; + char** StringTable; + char** lpLastOffs; + + num_entries = 0; + StringTable = 0; + do + { + int slen; + long handle; + struct _finddata_t f; + + if (num_entries == 0) + length = 0; + else + { + slen = (num_entries + 1) * sizeof (char*); + StringTable = (char**) malloc (slen + length); + if (StringTable == 0) + break; + + lpLastOffs = StringTable; + *lpLastOffs = (char*)StringTable + slen; + + num_entries = 0; + length = slen; + } + + handle = _findfirst (pattern, &f); + if (handle != -1) + { + do + { + if (f.attrib & (_A_HIDDEN | _A_SUBDIR | _A_SYSTEM)) + continue; + + slen = strlen (f.name) + 1; + length += slen; + + if (StringTable) + { + char *lpStr; + char **lpLo, **lpHi; + + lpLo = StringTable; + lpHi = lpLastOffs - 1; + while (lpLo <= lpHi) + { + char c1, c2; + char *pStr; + int LocLen; + char **lpMid; + + lpMid = lpLo + ((lpHi - lpLo) >> 1); + + LocLen = lpMid[1] - lpMid[0]; + if (LocLen > slen) + LocLen = slen; + + lpStr = lpMid[0]; + pStr = f.name; + while (LocLen-- + && (c1 = toupper (*lpStr++)) + == (c2 = toupper (*pStr++))) + ; + + if (c1 <= c2) + lpLo = lpMid + 1; + else + lpHi = lpMid - 1; + } + + lpStr = lpLo[0]; + memmove (lpStr + slen, lpStr, lpLastOffs[0] - lpLo[0]); + strcpy (lpStr, f.name); + + for (lpHi = lpLastOffs++; lpHi >= lpLo; --lpHi) + lpHi[1] = lpHi[0] + slen; + } + + ++num_entries; + + } while (_findnext (handle, &f) == 0); + + _findclose (handle); + } + } while (num_entries && StringTable == 0); + + if (StringTable == 0) + *pnum_entries = 0; + else + *pnum_entries = num_entries; + + return StringTable; +} + +#else /* ! defined(WIN32) */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char** +make_file_list (const char* pattern, int* pnum_entries) +{ + size_t num_entries, length; + char** StringTable; + char** lpLastOffs; + char* slash; // Pointer inside pattern to the last / + char path[PATH_MAX]; // buffer for a filename with path + char* file; // Pointer inside path to the filename + size_t pathlen; // length of path, excluding last / and filename + + slash = (char*) strrchr ((const char *) pattern, '/'); + if (slash == NULL) + { + pathlen = 1; + path[0] = '.'; + } + else + { + pathlen = slash - pattern; + memcpy (path, pattern, pathlen); + pattern = slash + 1; + } + file = path + pathlen + 1; + + num_entries = 0; + StringTable = 0; + do + { + int slen; + DIR *handle; + + if (num_entries == 0) + length = 0; + else + { + slen = (num_entries + 1) * sizeof (char*); + StringTable = (char**) malloc (slen + length); + if (StringTable == 0) + break; + + lpLastOffs = StringTable; + *lpLastOffs = (char*)StringTable + slen; + + num_entries = 0; + length = slen; + } + + path[pathlen] = '\0'; // strip any file part + handle = opendir((const char *) path); + if (handle != NULL) + { + path[pathlen] = '/'; + // change the 0 char to a slash; a filename will be + // attached here. + while (1) + { + struct dirent *de; + struct stat sb; + + de = readdir(handle); + if (de == NULL) + break; + if (de->d_name[0] == '.') + continue; + strcpy (file, de->d_name); + // attach the filename to path + if (stat(path, &sb) == -1) + continue; + if (!S_ISREG(sb.st_mode)) + continue; + if (fnmatch(pattern, de->d_name, 0) != 0) + continue; + + slen = strlen (de->d_name) + 1; + length += slen; + + if (StringTable) + { + char *lpStr; + char **lpLo, **lpHi; + + lpLo = StringTable; + lpHi = lpLastOffs - 1; + while (lpLo <= lpHi) + { + char c1, c2; + char *pStr; + int LocLen; + char **lpMid; + + lpMid = lpLo + ((lpHi - lpLo) >> 1); + + LocLen = lpMid[1] - lpMid[0]; + if (LocLen > slen) + LocLen = slen; + + lpStr = lpMid[0]; + pStr = de->d_name; + while (LocLen-- + && (c1 = toupper (*lpStr++)) + == (c2 = toupper (*pStr++))) + ; + + if (c1 <= c2) + lpLo = lpMid + 1; + else + lpHi = lpMid - 1; + } + + lpStr = lpLo[0]; + memmove (lpStr + slen, lpStr, lpLastOffs[0] - lpLo[0]); + strcpy (lpStr, de->d_name); + + for (lpHi = lpLastOffs++; lpHi >= lpLo; --lpHi) + lpHi[1] = lpHi[0] + slen; + } + + ++num_entries; + } + closedir(handle); + } + } while (num_entries && StringTable == 0); + + if (StringTable == 0) + *pnum_entries = 0; + else + *pnum_entries = num_entries; + + return StringTable; +} + +#endif + +void +free_file_list (char** list) +{ + if (list) + free(list); +} diff --git a/tools/mng/makemng.c b/tools/mng/makemng.c new file mode 100755 index 000000000..878b07134 --- /dev/null +++ b/tools/mng/makemng.c @@ -0,0 +1,1765 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef WIN32 +# include +#else +# include +#endif + + +struct options +{ + char *inmask; + char *inpath; + char *outfile; + int framerate; + char verbose; + char backimage; + char deltamask; + int sectorsize; + int fullrects; +} opts; + +// externals +char** make_file_list (const char* pattern, int* pnum_entries); +void free_file_list (char** list); + +// internals +int error (int errn, const char* fmt, const char* s); +void verbose (const char* fmt, const char* s); +void verbose_d (const char* fmt, int val); +void parse_arguments (int argc, char *argv[], struct options *opts); +int read_file_list (void); +void calc_mng_dims (void); +void select_back_image (void); +void delta_images (void); +int write_mng_file (void); + +typedef union +{ + struct + { + unsigned char r, g, b, a; + } bchan; + unsigned char channels[4]; + unsigned int value; +} RGBA; + +typedef struct _file_info +{ + FILE* f; + char* fname; + char* fmode; + int w, h; + int x, y; + RGBA* image; + unsigned char* indimg; + int delay; + int identical; + unsigned short objid; + unsigned short cloneid; + int clone; + unsigned short precloneid; + int preclone; + struct _file_info* next; +} file_info; + +void file_info_free (); + +// MNG callbacks +mng_ptr MNG_DECL mng_alloc (mng_size_t iLen); +void MNG_DECL mng_free (mng_ptr pPtr, mng_size_t iLen); +mng_bool MNG_DECL mng_open_stream(mng_handle mng); +mng_bool MNG_DECL mng_close_stream(mng_handle mng); +mng_bool MNG_DECL mng_read_stream(mng_handle mng, mng_ptr buffer, mng_uint32 size, mng_uint32p bytes); +mng_bool MNG_DECL mng_write_stream (mng_handle mng, mng_ptr buffer, mng_uint32 size, mng_uint32p bytes); +mng_bool MNG_DECL mng_process_header(mng_handle mng, mng_uint32 width, mng_uint32 height); +mng_ptr MNG_DECL mng_get_canvasline_read(mng_handle mng, mng_uint32 line); +mng_ptr MNG_DECL mng_get_canvasline_write(mng_handle mng, mng_uint32 line); +mng_bool MNG_DECL mng_refresh_display(mng_handle mng, mng_uint32 x, mng_uint32 y, mng_uint32 w, mng_uint32 h); +mng_uint32 MNG_DECL mng_get_tickcount(mng_handle mng); +mng_bool MNG_DECL mng_set_timer(mng_handle mng, mng_uint32 msecs); + +#define MAX_COLORS 0x100 + +// global png/mng data +char** Files = 0; +int cFiles = 0; +file_info* Infos = 0; +mng_palette8 Pal; +int cPalClr = 0; +int mngw = 0, mngh = 0; +int iback = 0; +int timerate = 100; // default 100 ticks per second +int framedelay = 20; // default 5 fps +int _curframe = -1; +int _curdeltaframe = -1; + +int +main(int argc, char* argv[]) +{ + int ret = 0; + + parse_arguments (argc, argv, &opts); + + if (opts.framerate) // update delay + framedelay = timerate / opts.framerate; + + if (!opts.inpath && (strchr (opts.inmask, '/') || strchr (opts.inmask, '\\'))) + { + char *pch1, *pch2; + + opts.inpath = (char*) calloc (strlen (opts.inmask), 1); + if (!opts.inpath) + return error (EXIT_FAILURE, "No memory", 0); + + strcpy (opts.inpath, opts.inmask); + pch1 = strrchr (opts.inpath, '/'); + pch2 = strrchr (opts.inpath, '\\'); + if (pch2 > pch1) + pch1 = pch2; + + pch1[1] = 0; // term the path + + verbose ("Frame files in dir: %s\n", opts.inpath); + } + + if (!opts.outfile) + { + char* pch; + + opts.outfile = (char*) calloc (strlen(opts.inmask) + 6, 1); + if (!opts.outfile) + return error (EXIT_FAILURE, "No memory", 0); + + strcpy (opts.outfile, opts.inmask); + while ((pch = strchr (opts.outfile, '*')) != 0) + strcpy (pch, pch + 1); + + pch = strstr (opts.outfile, ".png"); + if (!pch) + pch = opts.outfile + strlen (opts.outfile); + strcpy (pch, ".mng"); + + if (pch == opts.outfile || pch[-1] == '/' || pch[-1] == '\\') + { // have to fix blank name + memmove (pch + 1, pch, strlen(pch) + 1); + *pch = '1'; + } + + verbose ("Output file: %s\n", opts.outfile); + } + + fprintf (stderr, "using timerate of %d and framedelay of %d\n", timerate, framedelay); + + ret = read_file_list (); + if (!ret) + { + calc_mng_dims (); + if (opts.backimage) + select_back_image (); + delta_images (); + + ret = write_mng_file (); + } + + file_info_free (); + free_file_list (Files); + + return ret; +} + +int +error(int errn, const char* fmt, const char* s) +{ + fprintf(stderr, fmt, s); + return errn; +} + +void +verbose(const char* fmt, const char* s) +{ + if (!opts.verbose) + return; + + fprintf(stderr, fmt, s); +} + +void verbose_d (const char* fmt, int val) +{ + if (!opts.verbose) + return; + + fprintf(stderr, fmt, val); +} + +void +usage() +{ + fprintf(stderr, "usage: makemng [-v] [-f rate] [-r] [-s size] [-o outputfile] \n"); + fprintf(stderr, "produces an MNG animation from a bunch of frame images\n"); + fprintf(stderr, "options:\n"); + fprintf(stderr, " -v\t\t : be verbose, explains things no human should know\n"); + fprintf(stderr, " -f rate\t : sets the framerate; rate is 1..100 per second (default 5)\n"); + fprintf(stderr, " -b\t\t : auto-select background frame (instead of frame0)\n"); + fprintf(stderr, " -r\t\t : split delta frames into full rectangles only\n"); + fprintf(stderr, " -s size\t : enable sector cleanup and set sector size (8..64)\n"); + fprintf(stderr, "diagnostical options:\n"); + fprintf(stderr, " -d\t\t : generate delta-mask PNGs (form: mask_FRM1_FRM2.png)\n"); +} + +void +parse_arguments(int argc, char *argv[], struct options *opts) +{ + char ch; + + memset(opts, '\0', sizeof (struct options)); + while ((ch = getopt(argc, argv, "?hvbdrf:s:o:")) != -1) + { + switch(ch) + { + case 'o': + opts->outfile = optarg; + break; + case 'f': + opts->framerate = atoi(optarg); + if (opts->framerate < 1 || opts->framerate > 100) + { + fprintf(stderr, "invalid -f option value\n"); + usage(); + exit(EXIT_FAILURE); + } + break; + case 'd': + opts->deltamask = 1; + break; + case 'b': + opts->backimage = 1; + break; + case 'r': + opts->fullrects = 1; + break; + case 's': + opts->sectorsize = atoi(optarg); + if (opts->sectorsize < 8 || opts->sectorsize > 64) + { + fprintf(stderr, "invalid -r option value\n"); + usage(); + exit(EXIT_FAILURE); + } + break; + case 'v': + opts->verbose = 1; + break; + case '?': + case 'h': + default: + usage(); + exit(EXIT_FAILURE); + } + } + + argc -= optind; + argv += optind; + if (argc != 1) + { + usage(); + exit(EXIT_FAILURE); + } + + opts->inmask = argv[0]; +} + +void +make_file_name(int index, char* buf) +{ + if (opts.inpath) + strcpy(buf, opts.inpath); + else + *buf = 0; + + strcat(buf, Files[index]); +} + +void +file_info_init (file_info* ms) +{ + memset(ms, 0, sizeof(*ms)); + ms->identical = -1; + ms->clone = -1; + ms->preclone = -1; +} + +void +file_info_cleanup (file_info* ms) +{ + file_info* fi = ms; + + while (fi) + { + file_info* tempi = fi; + + if (fi->image) + { + free(fi->image); + fi->image = 0; + } + + if (fi->indimg) + { + free(fi->indimg); + fi->indimg = 0; + } + + if (fi->f) + { + fclose(fi->f); + fi->f = 0; + } + + + fi = fi->next; + if (tempi != ms) + free (tempi); + } +} + +void +file_info_free () +{ + int i; + + if (Infos) + { + for (i = 0; i < cFiles; i++) + file_info_cleanup (Infos + i); + + free (Infos); + Infos = 0; + } +} + +int +equal_colors (RGBA rgba, mng_palette8e mng_clr) +{ + return rgba.bchan.r == mng_clr.iRed && + rgba.bchan.g == mng_clr.iGreen && + rgba.bchan.b == mng_clr.iBlue; +} + +int +lookup_palette (RGBA rgba) +{ + int i; + + for (i = 0; i < cPalClr && !equal_colors(rgba, Pal[i]); i++) + ; + + return i < cPalClr ? i : -1; +} + +int +update_palette (file_info* ms) +{ + int i; + + for (i = 0; i < ms->w * ms->h; i++) + { + RGBA rgba = ms->image[i]; + int ipal = lookup_palette (rgba); + if (ipal == -1) + { // add color + if (cPalClr >= MAX_COLORS) + return 1; + + Pal[cPalClr].iRed = rgba.bchan.r; + Pal[cPalClr].iGreen = rgba.bchan.g; + Pal[cPalClr].iBlue = rgba.bchan.b; + cPalClr++; + } + } + return 0; +} + +int +convert_image_indexed (file_info* ms) +{ + int i; + + ms->indimg = (unsigned char*) malloc (ms->w * ms->h); + if (!ms->indimg) + return 230; + + for (i = 0; i < ms->w * ms->h; i++) + { + int ipal = lookup_palette (ms->image[i]); + + if (ipal == -1) + return 1; // something is screwed + + ms->indimg[i] = ipal; + } + + free (ms->image); + ms->image = 0; + + return 0; +} + +int +read_file_list (void) +{ + int ret = 0; + mng_handle mng; + char namebuf[260]; + int i; + + cFiles = 0; + Files = make_file_list(opts.inmask, &cFiles); + + if (!Files || cFiles == 0) + { + fprintf (stderr, "No frame files found\n"); + return 1; + } + + Infos = (file_info*) malloc (sizeof(file_info) * cFiles); + if (!Infos) + return 251; + + memset(Infos, 0, sizeof(file_info) * cFiles); + + mng = mng_initialize (MNG_NULL, mng_alloc, mng_free, MNG_NULL); + if (mng == MNG_NULL) + return 250; + + // set the callbacks + mng_setcb_openstream(mng, mng_open_stream); + mng_setcb_closestream(mng, mng_close_stream); + mng_setcb_readdata(mng, mng_read_stream); + mng_setcb_processheader(mng, mng_process_header); + mng_setcb_getcanvasline(mng, mng_get_canvasline_read); + mng_setcb_gettickcount(mng, mng_get_tickcount); + mng_setcb_settimer(mng, mng_set_timer); + mng_setcb_refresh(mng, mng_refresh_display); + + for (i = 0; i < cFiles && !ret; i++) + { + file_info* rf = Infos + i; + + file_info_init (rf); + make_file_name (i, namebuf); + rf->fname = namebuf; + rf->fmode = "rb"; + + verbose_d ("%03d ", i); verbose ("reading '%s'...", rf->fname); + + mng_reset (mng); + mng_set_userdata (mng, rf); + + for (ret = mng_readdisplay (mng); + ret == MNG_NEEDMOREDATA || ret == MNG_NEEDTIMERWAIT; + ret = mng_display_resume (mng)) + { + if (ret == MNG_NEEDTIMERWAIT) + rf->delay = 0; + } + + if (ret) + { + fprintf (stderr, "Could not read '%s'\n", rf->fname); + ret = 2; + } + + ret = update_palette (rf); + if (ret) + { + fprintf (stderr, "Too many unique colors (%d processed), giving up\n", i); + ret = 3; + } + + ret = convert_image_indexed (rf); + if (ret) + { + fprintf (stderr, "Image conversion failed on '%s'\n", rf->fname); + ret = 4; + } + + verbose (" done\n", 0); + } + + mng_cleanup (&mng); + + if (ret == MNG_NOERROR) + fprintf (stderr, "%d animation frames\n", cFiles); + + return ret; +} + +void +calc_mng_dims (void) +{ + int i; + + mngw = mngh = -1; + + // get max dims + for (i = 0; i < cFiles; i++) + { + if (Infos[i].w > mngw) + mngw = Infos[i].w; + + if (Infos[i].h > mngh) + mngh = Infos[i].h; + } + + // adjust images - center + for (i = 0; i < cFiles; i++) + { + if (Infos[i].w < mngw) + Infos[i].x = (mngw - Infos[i].w) >> 1; + + if (Infos[i].h < mngh) + Infos[i].y = (mngh - Infos[i].h) >> 1; + } +} + +int +compare_images (file_info* i1, file_info* i2) +{ + int cnt = 0; + int w, h, x, y; + int dx1, dx2, dy1, dy2; + + if (i1->w > i2->w) + { + w = i2->w; + dx1 = i2->x; + dx2 = 0; + } + else if (i1->w < i2->w) + { + w = i1->w; + dx1 = 0; + dx2 = i1->x; + } + else + { + w = i1->w; + dx1 = dx2 = 0; + } + + if (i1->h > i2->h) + { + h = i2->h; + dy1 = i2->y; + dy2 = 0; + } + else if (i1->h < i2->h) + { + h = i1->h; + dy1 = 0; + dy2 = i1->y; + } + else + { + h = i1->h; + dy1 = dy2 = 0; + } + + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + if (i1->indimg[(y + dy1) * i1->w + x + dx1] != i2->indimg[(y + dy2) * i2->w + x + dx2]) + cnt++; + } + } + return cnt; +} + +void +select_back_image (void) +{ + int i; + int* cdiff; + int max; + + cdiff = (int*) calloc (cFiles, sizeof(int)); + if (!cdiff) + return; + + verbose ("selecting optimal background image...", 0); + + for (i = 2; i < cFiles; i++) + { + if (Infos[i].w == mngw && Infos[i].h == mngh) + { + cdiff[i] = compare_images (Infos + i, Infos + i - 1) - + compare_images (Infos + i, Infos + 0); + } + else + { + // image is smaller than animation and cannot be background + cdiff[i] = 0x7fffffff; + } + } + + // the difference has to be big enough + // or it will be useless + iback = 0; + max = mngw * mngh / 32; + + for (i = 2; i < cFiles; i++) + { + if (cdiff[i] > max) + { + iback = i; + max = cdiff[i]; + } + } + + verbose (" done\n", 0); + fprintf(stderr, "frame %03d selected as background\n", iback); +} + +int +equal_images (int i1, int i2) +{ + // deference identical chain + while (Infos[i1].identical != -1) + i1 = Infos[i1].identical; + while (Infos[i2].identical != -1) + i2 = Infos[i2].identical; + + if (i1 == i2) + return 1; + + if (Infos[i1].x != Infos[i2].x || Infos[i1].y != Infos[i2].y + || Infos[i1].w != Infos[i2].w || Infos[i1].h != Infos[i2].h) + return 0; + + return compare_images (Infos + i1, Infos + i2) == 0; +} + +int +delta_adjust_positions (int* pos1, int* pos2) +{ + if (*pos1 <= *pos2) + return 1; + else + { + (*pos1)--; + (*pos2)--; + return -1; + } +} + +void +clean_expansion_horz (unsigned char* mask, int w, int x1, int y1, int x2, int y2, int threshold) +{ + int x, y, dx, dy; + // assume anything out of bounds is cleared + int prevclear = threshold + 1; + + dy = delta_adjust_positions (&y1, &y2); + dx = delta_adjust_positions (&x1, &x2); + + for (y = y1; y != y2; y += dy) + { + int dcnt, ecnt; + + dcnt = ecnt = 0; + + for (x = x1; x != x2; x += dx) + { + if (mask[y * w + x] == 1) + dcnt++; + else if (mask[y * w + x] == 2 || mask[y * w + x] == 3) + ecnt++; + } + + if (dcnt == 0 && ecnt == 0) + { // line is clear + prevclear++; + } + else if (dcnt == 0) + { + if (prevclear >= threshold) + { // it's not clear yet, but it will be in a moment ;) + int lx, ly = y; + + if (prevclear == threshold) + { // need to clean everything we just checked + ly = y - prevclear * dy; + } + + for (ly = ly; ly != y + dy; ly += dy) + for (lx = x1; lx != x2; lx += dx) + mask[ly * w + lx] = 0; + } + prevclear++; + } + else + { // line is dirty + prevclear = 0; + } + } +} + +void +clean_expansion_vert (unsigned char* mask, int w, int x1, int y1, int x2, int y2, int threshold) +{ + int x, y, dx, dy; + // assume anything out of bounds is cleared + int prevclear = threshold + 1; + + dy = delta_adjust_positions (&y1, &y2); + dx = delta_adjust_positions (&x1, &x2); + + for (x = x1; x != x2; x += dx) + { + int dcnt, ecnt; + + dcnt = ecnt = 0; + + for (y = y1; y != y2; y += dy) + { + if (mask[y * w + x] == 1) + dcnt++; + else if (mask[y * w + x] == 2 || mask[y * w + x] == 3) + ecnt++; + } + + if (dcnt == 0 && ecnt == 0) + { // line is clear + prevclear++; + } + else if (dcnt == 0) + { + if (prevclear >= threshold) + { // it's not clear yet, but it will be in a moment ;) + int ly, lx = x; + + if (prevclear == threshold) + { // need to clean everything we just checked + lx = x - prevclear * dx; + } + + for (lx = lx; lx != x + dx; lx += dx) + for (ly = y1; ly != y2; ly += dy) + mask[ly * w + lx] = 0; + } + prevclear++; + } + else + { // line is dirty + prevclear = 0; + } + } +} + +struct _expand_corner +{ + int x, y; + int tx1, ty1; + int tx2, ty2; +} +const expand_corner [] = +{ + {0, 0, 1, 0, 0, 1}, // top-left + {1, 0, 0, 0, 0, 1}, // top-mid, from left + {1, 0, 2, 0, 2, 1}, // top-mid, from right + {2, 0, 1, 0, 2, 1}, // top-right + {0, 1, 0, 0, 1, 0}, // mid-left, from top + {0, 1, 0, 2, 1, 2}, // mid-left, from bottom + {2, 1, 1, 0, 2, 0}, // mid-right, from top + {2, 1, 1, 2, 2, 2}, // mid-right, from bottom + {0, 2, 1, 2, 0, 1}, // bot-left + {1, 2, 0, 1, 0, 2}, // bot-mid, from left + {1, 2, 2, 1, 2, 2}, // bot-mid, from right + {2, 2, 1, 2, 2, 1}, // bot-right + + {-1,-1, -1,-1, -1,-1} // term +}; + +// this will recursively expand the missing corner pixels +// recursion is limited so we dont overflow the stack +int +expand_rect (char* mask, int x, int y, int w, int h) +{ + static int level = 0; + int x1, y1, x2, y2, i, lx, ly; + const struct _expand_corner* pc; + signed char matrix[3][3]; + int cnt = 0; + + if (level > 99) + return 1; // make sure parent knows it failed + + level++; + + if (x > 0) + x1 = x - 1; + else + { + for (i = 0; i < 3; i++) + matrix[0][i] = -1; + + x1 = x; + } + + if (y > 0) + y1 = y - 1; + else + { + for (i = 0; i < 3; i++) + matrix[i][0] = -1; + + y1 = y; + } + + if (x + 1 < w) + x2 = x + 2; + else + { + for (i = 0; i < 3; i++) + matrix[2][i] = -1; + + x2 = x + 1; + } + + if (y + 1 < h) + y2 = y + 2; + else + { + for (i = 0; i < 3; i++) + matrix[i][2] = -1; + + y2 = y + 1; + } + + for (ly = y1; ly < y2; ly++) + for (lx = x1; lx < x2; lx++) + matrix[lx - x + 1][ly - y + 1] = mask[ly * w + lx]; + + // check corner pixels + for (pc = expand_corner; pc->x != -1; pc++) + { + if (matrix[pc->x][pc->y] == 0 && matrix[pc->tx1][pc->ty1] > 0 && matrix[pc->tx2][pc->ty2] > 0) + { // corner pixel missing + int ofs = (y - 1 + pc->y) * w + (x - 1 + pc->x); + + matrix[pc->x][pc->y] = 3; + + // but it may already be present in the mask (recursive) + if (mask[ofs] == 0) + { + mask[ofs] = 3; + cnt += 1 + expand_rect (mask, x - 1 + pc->x, y - 1 + pc->y, w, h); + } + } + } + + level--; + + return cnt; +} + +file_info* +file_info_add_image (file_info* fi) +{ + file_info* ni; + + ni = (file_info*) malloc (sizeof(file_info)); + if (!ni) + return 0; + + file_info_init (ni); + + while (fi->next) + fi = fi->next; + + return fi->next = ni; +} + +int +is_multi_delta_image (file_info* fi) +{ + return fi && fi->next; +} + +#define MASK_COLORS 4 +mng_palette8e mask_pal[MASK_COLORS] = +{ + {0x00, 0x00, 0x00}, + {0xff, 0xff, 0xff}, + {0x00, 0xff, 0x00}, + {0x00, 0x00, 0xff} +}; + +void +create_mask_png (char* mask, int w, int h) +{ + int ret = 0; + mng_handle mng; + file_info wf; + char fname[260]; + mng_ptr imgdata; + unsigned char* tempdata; + unsigned char* p; + uLong srcLen; + uLong dstLen; + int i; + + file_info_init (&wf); + sprintf(fname, "mask_%03d_%03d.png", _curframe, _curdeltaframe); + + wf.fname = fname; + wf.fmode = "wb"; + + // extra byte in front of each line for filter type + srcLen = w * h + h; + tempdata = (mng_ptr) malloc(srcLen); + if (!tempdata) + return; + + // maximum necessary space + // deflated data can be 100.1% + 12 bytes in worst case + dstLen = srcLen + srcLen / 100 + 20; // extra 8 for safety + imgdata = (mng_ptr) malloc(dstLen); + if (!imgdata) + return; + + for (i = 0, p = tempdata; i < w * h; i++, p++) + { + if (i % w == 0) + { // write filter byte + *p++ = 0; + } + + *p = mask[i]; + } + + if (Z_OK != compress2(imgdata, &dstLen, tempdata, srcLen, 9)) + return; + + free(tempdata); + + mng = mng_initialize (&wf, mng_alloc, mng_free, MNG_NULL); + if (mng == MNG_NULL) + return; + + // set the callbacks + mng_setcb_openstream(mng, mng_open_stream); + mng_setcb_closestream(mng, mng_close_stream); + mng_setcb_writedata(mng, mng_write_stream); + + ret = mng_create (mng); + + ret = mng_putchunk_ihdr (mng, w, h, + MNG_BITDEPTH_8, MNG_COLORTYPE_INDEXED, MNG_COMPRESSION_DEFLATE, + MNG_FILTER_ADAPTIVE, MNG_INTERLACE_NONE); + + if (ret == MNG_NOERROR) + ret = mng_putchunk_plte (mng, 4, mask_pal); + if (ret == MNG_NOERROR) + ret = mng_putchunk_idat (mng, dstLen, imgdata); + if (ret == MNG_NOERROR) + ret = mng_putchunk_iend (mng); + + free (imgdata); + + if (ret == MNG_NOERROR) + ret = mng_write (mng); + + mng_cleanup (&mng); + + file_info_cleanup (&wf); +} + +int +build_delta (file_info* i1, file_info* i2) +{ + int w, h, x, y; + int dx1, dx2, dy1, dy2; + int cnt; + char* mask = 0; + + if (i1->w > i2->w) + { + w = i2->w; + dx1 = i2->x; + dx2 = 0; + } + else if (i1->w < i2->w) + { + w = i1->w; + dx1 = 0; + dx2 = i1->x; + } + else + { + w = i1->w; + dx1 = dx2 = 0; + } + + if (i1->h > i2->h) + { + h = i2->h; + dy1 = i2->y; + dy2 = 0; + } + else if (i1->h < i2->h) + { + h = i1->h; + dy1 = 0; + dy2 = i1->y; + } + else + { + h = i1->h; + dy1 = dy2 = 0; + } + + mask = (char*) malloc (w * h); + if (!mask) + return 220; + memset(mask, 0, w * h); + + // build diff mask first + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + if (i1->indimg[(y + dy1) * i1->w + x + dx1] != i2->indimg[(y + dy2) * i2->w + x + dx2]) + // diff pixel + mask[y * w + x] = 1; + } + } + + // coarse expand the diff pixels + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + if (mask[y * w + x] == 1) + { + int x1 = x - 2; + int x2 = x + 3; + int y1 = y - 2; + int y2 = y + 3; + int lx; + if (x1 < 0) + x1 = 0; + if (x2 > w) + x2 = w; + if (y1 < 0) + y1 = 0; + if (y2 > h) + y2 = h; + + for (y1 = y1; y1 < y2; y1++) + for (lx = x1; lx < x2; lx++) + if (mask[y1 * w + lx] == 0) + mask[y1 * w + lx] = 2; + } + } + } + + // scan and remove extra expansion horizontally and vertically + clean_expansion_vert (mask, w, 0, 0, w, h, 1); + clean_expansion_vert (mask, w, w, 0, 0, h, 1); + clean_expansion_horz (mask, w, 0, 0, w, h, 1); + clean_expansion_horz (mask, w, 0, h, w, 0, 1); + + + do // coarse expand the diff pixels + { // merge would-be diff rectangles in the process + cnt = 0; + + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + if (mask[y * w + x] != 0) + cnt += expand_rect (mask, x, y, w, h); + } + } + // repeat is something was expanded + } while (cnt != 0); + + // at this point we should have guaranteed non-overlapping + // rectangles that cover all of the delta areas + + if (opts.sectorsize) + { // final expansion cleanup + for (y = 0; y < h; y += opts.sectorsize) + { + for (x = 0; x < w; x += opts.sectorsize) + { + int x2, y2; + + cnt = 0; + for (y2 = y; y2 < y + opts.sectorsize && y2 < h; y2++) + for (x2 = x; x2 < x + opts.sectorsize && x2 < w; x2++) + if (mask[y2 * w + x2] == 1) + cnt++; + + if (cnt > 0) + continue; // dirty sector + + // clean up sector + for (y2 = y; y2 < y + opts.sectorsize && y2 < h; y2++) + for (x2 = x; x2 < x + opts.sectorsize && x2 < w; x2++) + mask[y2 * w + x2] = 0; + + } + } + } + + // check how muany pixels have to be replaced + for (x = 0, cnt = 0; x < w * h; x++) + if (mask[x]) + cnt++; + + if (opts.deltamask) + create_mask_png (mask, w, h); + + // generate delta images + if (cnt != w * h) + { + int ofs; + + for (y = 0, ofs = 0; y < h; y++) + { + for (x = 0; x < w; x++, ofs++) + { + if (mask[ofs] != 0) + { // copy masked rectangle into a new image + // and clear the mask + int i; + int rw, rh; + int x2, y2; + unsigned char* src; + unsigned char* dst; + file_info* ni; + + ni = file_info_add_image (i1); + if (!ni) + { + x = w; + y = h; + break; + } + + + // lookup delta rectangle + for (i = x, src = mask + ofs; i < w && *src != 0; i++, src++) + ; + ni->w = rw = i - x; + + if (opts.fullrects) + { // locate only complete rectangles + y2 = y + 1; + for (i = y + 1, src = mask + ofs; i < h && *src != 0; i++, src += w) + { + unsigned char* src2; + + y2 = i; + for (x2 = x, src2 = src; x2 < x + rw && *src2 != 0; x2++, src2++) + ; + + if (x2 < x + rw) + break; + } + } + else + { // any rectangles + for (y2 = y + 1, src = mask + ofs; y2 < h && *src != 0; y2++, src += w) + ; + } + + ni->h = rh = y2 - y; + + ni->indimg = (unsigned char*) malloc (rw * rh); + if (!ni->indimg) + { + x = w; + y = h; + break; + } + + // copy the pixels + for (i = 0, src = i1->indimg + (dy1 + y) * i1->w + dx1 + x, dst = ni->indimg; + i < rh; + i++, src += i1->w, dst += rw + ) + { + memcpy (dst, src, rw); + memset (mask + ofs + i * w, 0, rw); + } + + ni->x = i1->x + dx1 + x; + ni->y = i1->y + dy1 + y; + } + } + } + + if (i1->next) + { // dispose of the original + file_info* ni = i1->next; + free (i1->indimg); + i1->indimg = ni->indimg; + i1->x = ni->x; + i1->y = ni->y; + i1->w = ni->w; + i1->h = ni->h; + i1->next = ni->next; + + free (ni); + } + } + else + { // break here + cnt = 1; + } + + if (mask) + free (mask); + + return 0; +} + +void +delta_images (void) +{ + int i; + unsigned short nextid = 0x101; + + verbose ("calculating frame image deltas", 0); + + Infos[iback].objid = nextid++; + if (iback != 0) + { // set the first frame objid different + // from back id + Infos[0].objid = nextid++; + } + + // remove dupes + for (i = 1; i < cFiles; i++) + { + int i2; + + if (i == iback) + continue; + + Infos[i].objid = Infos[i - 1].objid; + + for (i2 = i - 1; i2 >= 0 && Infos[i].identical == -1; i2--) + { + int orgi2 = i2; + + // deference identical chain + while (Infos[i2].identical != -1) + i2 = Infos[i2].identical; + + if (equal_images (i, i2)) + { + Infos[i].identical = i2; + // dont need image data anymore + if (Infos[i].indimg) + { + free (Infos[i].indimg); + Infos[i].indimg = 0; + } + + if (orgi2 != i - 1) + { // detached descendant + // clone the object for it + if (Infos[i2].clone == -1) + { // no clones yet + Infos[i2].cloneid = nextid++; + Infos[i2].clone = i; + Infos[i].objid = Infos[i2].cloneid; + } + else + { // already cloned for another frame + // tell the frame to preclone it for + // this frame too + // dereference preclone chain first + for (i2 = Infos[i2].clone; Infos[i2].preclone != -1; i2 = Infos[i2].preclone) + ; + Infos[i2].preclone = i; + Infos[i2].precloneid = nextid++; + Infos[i].objid = Infos[i2].precloneid; + } + } + } + } + verbose (".", 0); + } + verbose ("|", 0); + + // compute deltas + for (i = cFiles - 1; i >= 0; i--) + { + int i2; + + if (i == iback || Infos[i].identical != -1) + // no delta needed + continue; + else + { + if (i == 0 && i != iback) + { // delta against original background + i2 = iback; + } + else + { // deref indentical chain + for (i2 = i - 1; i2 >= 0 && Infos[i2].identical != -1; i2 = Infos[i2].identical) + ; + + // sanity check + if (Infos[i2].objid != Infos[i].objid) + { + fprintf (stderr, "delta_images: logical error 1\n"); + exit(EXIT_FAILURE); + } + } + + // debug info + _curframe = i; + _curdeltaframe = i2; + + build_delta (Infos + i, Infos + i2); + } + verbose (".", 0); + } + + verbose ("\n", 0); +} + +int +get_png_image_data (file_info* ms, unsigned char* imgdata) +{ + int i; + + for (i = 0; i < ms->w * ms->h; i++, imgdata++) + { + if (i % ms->w == 0) + { // write filter byte + *imgdata++ = 0; + } + + *imgdata = ms->indimg[i]; + } + return 0; +} + +int +compress_png (file_info* ms, mng_ptr imgdata, mng_uint32 imglen, mng_uint32p bytes) +{ + int ret = 0; + unsigned char* tempdata; + uLong srcLen; + + *bytes = 0; + + // extra byte in front of each line for filter type + srcLen = ms->w * ms->h + ms->h; + tempdata = (mng_ptr) malloc(srcLen); + if (!tempdata) + return 241; + + ret = get_png_image_data (ms, tempdata); + if (!ret) + { + uLong dstLen = imglen; + + if (Z_OK == compress2(imgdata, &dstLen, tempdata, srcLen, 9)) + *bytes = dstLen; + else + ret = 253; + } + + free(tempdata); + + return ret; +} + +int +output_png (mng_handle mng, file_info* rf, int delta) +{ + int ret = 0; + mng_ptr imgdata; + mng_uint32 imglen; + mng_uint32 cbcomp; + unsigned short objid = rf->objid; + + // maximum necessary space + // deflated data can be 100.1% + 12 bytes in worst case + imglen = mngw * mngh + mngh; + imglen += imglen / 100 + 20; // extra 8 for safety + imgdata = (mng_ptr) malloc(imglen); + if (!imgdata) + return 252; + + do + { + if (delta) + { // output delta + ret = mng_putchunk_dhdr (mng, objid, + MNG_IMAGETYPE_PNG, MNG_DELTATYPE_BLOCKPIXELREPLACE, + rf->w, rf->h, rf->x, rf->y); + } + else + { // output image verbatim + ret = mng_putchunk_ihdr (mng, rf->w, rf->h, + MNG_BITDEPTH_8, MNG_COLORTYPE_INDEXED, MNG_COMPRESSION_DEFLATE, + MNG_FILTER_ADAPTIVE, MNG_INTERLACE_NONE); + + if (ret == MNG_NOERROR) + { // write empty PLTE to use the global PLTE + ret = mng_putchunk_plte (mng, 0, Pal); + //ret = mng_putchunk_plte (mng, cPalClr, Pal); // enable to write plain PNG + } + } + + if (ret == MNG_NOERROR) + ret = compress_png (rf, imgdata, imglen, &cbcomp); + + if (ret == MNG_NOERROR) + ret = mng_putchunk_idat (mng, cbcomp, imgdata); + + if (ret == MNG_NOERROR) + ret = mng_putchunk_iend (mng); + + } while ((rf = rf->next) != 0 && ret == MNG_NOERROR); + + free (imgdata); + + return ret; +} + +int +write_mng_file (void) +{ + int ret = 0; + mng_handle mng; + file_info wf; + file_info rf; + file_info backf; + int i; + unsigned short lastobjid; + char curframemode, newframemode; + + mng = mng_initialize (MNG_NULL, mng_alloc, mng_free, MNG_NULL); + if (mng == MNG_NULL) + { + fprintf (stderr, "libmng did not init properly\n"); + return 250; + } + + // set the callbacks + mng_setcb_openstream(mng, mng_open_stream); + mng_setcb_closestream(mng, mng_close_stream); + mng_setcb_writedata(mng, mng_write_stream); + + file_info_init (&wf); + wf.fname = opts.outfile; + wf.fmode = "wb"; + mng_set_userdata (mng, &wf); + + ret = mng_create (mng); + if (ret != MNG_NOERROR) + fprintf (stderr, "Could not create '%s'\n", wf.fname); + else + verbose ("writing MNG file '%s'", wf.fname); + + ret = mng_putchunk_mhdr (mng, mngw, mngh, timerate, 0, 0, 0, + MNG_SIMPLICITY_VALID | MNG_SIMPLICITY_SIMPLEFEATURES | + MNG_SIMPLICITY_COMPLEXFEATURES | MNG_SIMPLICITY_DELTAPNG | 0x240); + + //ret = mng_putchunk_term (mng, MNG_TERMACTION_LASTFRAME, MNG_ITERACTION_LASTFRAME, 0, 0); + + ret = mng_putchunk_plte (mng, cPalClr, Pal); + + ret = mng_putchunk_back (mng, 0,0,0, 0, 0, MNG_BACKGROUNDIMAGE_NOTILE); + + curframemode = MNG_FRAMINGMODE_1; + ret = mng_putchunk_fram (mng, MNG_FALSE, curframemode, 0,MNG_NULL, + MNG_CHANGEDELAY_DEFAULT, MNG_CHANGETIMOUT_NO, MNG_CHANGECLIPPING_NO, MNG_CHANGESYNCID_NO, + framedelay, 0,0,0,0,0,0, MNG_NULL,0); + + // define the staring image/object + backf = Infos[iback]; + ret = mng_putchunk_defi (mng, backf.objid, MNG_DONOTSHOW_NOTVISIBLE, MNG_CONCRETE, MNG_FALSE, 0,0, MNG_FALSE, 0,0,0,0); + ret = output_png (mng, &backf, 0); + + //ret = mng_putchunk_save (mng, MNG_TRUE, 0,0); + //ret = mng_putchunk_seek (mng, 5, "start"); + + if (iback != 0) + { // clone the starting object for the first frame + ret = mng_putchunk_clon (mng, backf.objid, Infos[0].objid, + MNG_FULL_CLONE, MNG_DONOTSHOW_NOTVISIBLE, MNG_CONCRETE_ASPARENT, + MNG_FALSE, 0,0,0); + } + + lastobjid = 0; + + for (i = 0; i < cFiles && ret == MNG_NOERROR; i++) + { + rf = Infos[i]; + + if (rf.precloneid != 0) + { // pre-clone the object for another frame + ret = mng_putchunk_clon (mng, rf.objid, rf.precloneid, + MNG_FULL_CLONE, MNG_DONOTSHOW_NOTVISIBLE, MNG_CONCRETE_ASPARENT, + MNG_FALSE, 0,0,0); + } + + if (is_multi_delta_image (&rf)) + // multi-delta png; frame mode: 0-delay for subframe + newframemode = MNG_FRAMINGMODE_2; + else + // frame mode: 1 image per frame + newframemode = MNG_FRAMINGMODE_1; + + + if (newframemode != curframemode) + { // change framing mode only + ret = mng_putchunk_fram (mng, MNG_FALSE, newframemode, 0,MNG_NULL, + MNG_CHANGEDELAY_NO, MNG_CHANGETIMOUT_NO, MNG_CHANGECLIPPING_NO, MNG_CHANGESYNCID_NO, + 0,0,0,0,0,0,0, MNG_NULL,0); + curframemode = newframemode; + } + else if (curframemode == MNG_FRAMINGMODE_2) + { // start new subframe + ret = mng_putchunk_fram (mng, MNG_TRUE, 0,0,MNG_NULL,0,0,0,0,0,0,0,0,0,0,0,0,0); + } + + if (rf.indimg != 0 && i != iback) + { // display a delta png + ret = output_png (mng, &rf, 1); + } + + if (rf.cloneid != 0) + { // post-clone the object for another frame + ret = mng_putchunk_clon (mng, rf.objid, rf.cloneid, + MNG_FULL_CLONE, MNG_DONOTSHOW_NOTVISIBLE, MNG_CONCRETE_ASPARENT, + MNG_FALSE, 0,0,0); + } + + if (rf.objid != lastobjid || rf.identical != -1) + { // show the object for this frame + ret = mng_putchunk_show (mng, MNG_FALSE, rf.objid, rf.objid, MNG_SHOWMODE_0); + lastobjid = rf.objid; + } + + verbose (".", 0); + } + + //ret = mng_putchunk_seek (mng, 3, "end"); + ret = mng_putchunk_mend (mng); + + ret = mng_write (mng); + + file_info_cleanup (&wf); + + mng_cleanup (&mng); + + if (ret == MNG_NOERROR) + verbose ("finished.\n", 0); + else + fprintf (stderr, "Could not create MNG file\n"); + + return ret; +} + +mng_ptr MNG_DECL +mng_alloc (mng_size_t iLen) +{ + mng_ptr ptr; + + if (iLen & 0x80000000) + return 0; // MNG error! + + ptr = malloc (iLen); + if (ptr) + memset(ptr, 0, iLen); + + return ptr; +} + +void MNG_DECL +mng_free (mng_ptr pPtr, mng_size_t iLen) +{ + if (iLen) + free (pPtr); +} + +mng_bool MNG_DECL +mng_open_stream (mng_handle mng) +{ + file_info* ms; + + ms = (file_info*) mng_get_userdata (mng); + + ms->f = fopen (ms->fname, ms->fmode); + if (!ms->f) + { + fprintf(stderr, "unable to open '%s'\n", ms->fname); + return MNG_FALSE; + } + + return MNG_TRUE; +} + +mng_bool MNG_DECL +mng_close_stream (mng_handle mng) +{ + file_info* ms; + + ms = (file_info*) mng_get_userdata (mng); + + fclose(ms->f); + ms->f = NULL; + + return MNG_TRUE; +} + +mng_bool MNG_DECL +mng_read_stream (mng_handle mng, mng_ptr buffer, mng_uint32 size, mng_uint32p bytes) +{ + file_info* ms; + + ms = (file_info*) mng_get_userdata (mng); + + *bytes = fread(buffer, 1, size, ms->f); + + return MNG_TRUE; +} + +mng_bool MNG_DECL +mng_write_stream (mng_handle mng, mng_ptr buffer, mng_uint32 size, mng_uint32p bytes) +{ + file_info* ms; + + ms = (file_info*) mng_get_userdata (mng); + + *bytes = fwrite(buffer, 1, size, ms->f); + + return MNG_TRUE; +} + +mng_bool MNG_DECL +mng_process_header (mng_handle mng, mng_uint32 width, mng_uint32 height) +{ + file_info* ms; + + ms = (file_info*) mng_get_userdata (mng); + ms->w = width; + ms->h = height; + ms->image = (RGBA*) malloc(sizeof(RGBA) * width * height); + if (!ms->image) + return MNG_FALSE; + + mng_set_canvasstyle(mng, MNG_CANVAS_RGBA8); + + return MNG_TRUE; +} + +mng_ptr MNG_DECL +mng_get_canvasline_read (mng_handle mng, mng_uint32 line) +{ + file_info* ms; + mng_ptr row; + + ms = (file_info*) mng_get_userdata (mng); + + row = ms->image + ms->w * line; + + return row; +} + +mng_ptr MNG_DECL +mng_get_canvasline_write (mng_handle mng, mng_uint32 line) +{ + file_info* ms; + + ms = (file_info*) mng_get_userdata (mng); + + //if (!ms->rowdata) + // ms->rowdata = (unsigned char*) malloc (ms->w); + //if (!ms->rowdata) + // return MNG_NULL; + + //make_pal_row (ms, line, ms->rowdata); + + // satisfying compiler + line = 0; + + return MNG_NULL; +} + +mng_bool MNG_DECL +mng_refresh_display (mng_handle mng, mng_uint32 x, mng_uint32 y, mng_uint32 w, mng_uint32 h) +{ + // not implemented + file_info* ms; + + ms = (file_info*) mng_get_userdata (mng); + + // satisfying compiler + x = y = w = h = 0; + + return MNG_TRUE; +} + +mng_uint32 MNG_DECL +mng_get_tickcount (mng_handle mng) +{ + // not implemented + file_info* ms; + static int tick = 0; + + ms = (file_info*) mng_get_userdata (mng); + + return tick += 50; +} + +mng_bool MNG_DECL +mng_set_timer (mng_handle mng, mng_uint32 msecs) +{ + // not implemented + file_info* ms; + + ms = (file_info*) mng_get_userdata (mng); + ms->delay = msecs; + + return MNG_TRUE; +} diff --git a/tools/mng/makemng.dsp b/tools/mng/makemng.dsp new file mode 100755 index 000000000..c5b5aca22 --- /dev/null +++ b/tools/mng/makemng.dsp @@ -0,0 +1,114 @@ +# Microsoft Developer Studio Project File - Name="makemng" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=makemng - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "makemng.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "makemng.mak" CFG="makemng - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "makemng - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "makemng - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=xicl6.exe +RSC=rc.exe + +!IF "$(CFG)" == "makemng - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "." /I "..\..\src" /I "..\..\src\msvc++" /I "..\..\src\getopt" /D "NDEBUG" /D "WINDOWS" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "MNG_USE_DLL" /D "MNG_SKIP_LCMS" /D "MNG_SKIP_IJG6B" /D "ZLIB_DLL" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=xilink6.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib uuid.lib zlib.lib libmng.lib /nologo /subsystem:console /machine:I386 /libpath:"." + +!ELSEIF "$(CFG)" == "makemng - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "." /I "..\..\src" /I "..\..\src\msvc++" /I "..\..\src\getopt" /D "_DEBUG" /D "ZLIB_DLL" /D "WINDOWS" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "MNG_USE_DLL" /D "MNG_SKIP_LCMS" /D "MNG_SKIP_IJG6B" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=xilink6.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib uuid.lib zlib.lib libmng.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"." + +!ENDIF + +# Begin Target + +# Name "makemng - Win32 Release" +# Name "makemng - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\filelist.c +# End Source File +# Begin Source File + +SOURCE=..\..\src\getopt\getopt.c +# End Source File +# Begin Source File + +SOURCE=.\makemng.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\getopt.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/tools/mng/makemng.dsw b/tools/mng/makemng.dsw new file mode 100755 index 000000000..ab12fac01 --- /dev/null +++ b/tools/mng/makemng.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "makemng"=.\makemng.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### +