From e7eabd46b92a53cef71e2e4870ac60d37db5c2a9 Mon Sep 17 00:00:00 2001 From: meep-eep Date: Sat, 19 Feb 2005 00:38:46 +0000 Subject: [PATCH] Old tools that got removed a long time ago. git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1545 8092fc87-c524-0410-9efc-e669fe64eaf9 --- tools/old/INDEX/COMBINE.C | 38 + tools/old/INDEX/MAKEFILE | 23 + tools/old/INDEX/MAKEFILE.MSC | 70 + tools/old/INDEX/NDX.C | 926 ++++++++ tools/old/INDEX/PKG.C | 267 +++ tools/old/INDEX/SPLIT.C | 40 + tools/old/INDEX/UNPKG.C | 129 ++ tools/old/anm/ANIM.H | 91 + tools/old/anm/ANIM.INC | 22 + tools/old/anm/ANIM2PCX.C | 296 +++ tools/old/anm/ANIM2PCX.LNK | 5 + tools/old/anm/ANIMA.ASM | 1095 ++++++++++ tools/old/anm/ANIMFILE.TXT | 138 ++ tools/old/anm/ANIMIO.C | 530 +++++ tools/old/anm/ASM.INC | 151 ++ tools/old/anm/DALLOC.ASM | 101 + tools/old/anm/EGA.INC | 42 + tools/old/anm/GIO.C | 197 ++ tools/old/anm/LPFILE.C | 1928 +++++++++++++++++ tools/old/anm/MAIN.H | 162 ++ tools/old/anm/MAIN.INC | 100 + tools/old/anm/MISC.C | 255 +++ tools/old/anm/MISCA.ASM | 848 ++++++++ tools/old/anm/PBIO.C | 387 ++++ tools/old/anm/READFRST.TXT | 27 + tools/old/anm/README.TXT | 50 + tools/old/anm/anmformt/ANIMFILE.TXT | 138 ++ tools/old/anm/anmformt/CGRAPH.ASM | 351 +++ tools/old/anm/anmformt/MAKESHOW.M | 8 + tools/old/anm/anmformt/SHOWANIM.C | 323 +++ tools/old/anm/anmformt/SHOWANIM.H | 69 + tools/old/anm/anmformu/ANIMFILE.TXT | 138 ++ tools/old/anm/anmformu/CGRAPH.ASM | 351 +++ tools/old/anm/anmformu/MAKESHOW.M | 8 + tools/old/anm/anmformu/SHOWANIM.C | 323 +++ tools/old/anm/anmformu/SHOWANIM.H | 69 + tools/old/anm/anmformu/anmformt.txt | 5 + tools/old/anm/cnv1.bat | 2 + tools/old/anm/cnvrtanm.bat | 2 + tools/old/anm/msvc++/anm2pcx.dsp | 96 + tools/old/anm/msvc++/anm2pcx.dsw | 29 + tools/old/font test/fonts.c | 158 ++ tools/old/ndxscripts/ndxcomms.bat | 74 + tools/old/ndxscripts/ndxships.bat | 86 + .../palette test/Palette Shifting Test.dsp | 111 + .../palette test/Palette Shifting Test.dsw | 29 + tools/old/palette test/main.cpp | 506 +++++ tools/old/pcx2png/msvc++/pcx2png.dsp | 118 + tools/old/pcx2png/msvc++/pcx2png.dsw | 29 + tools/old/pcx2png/pcx2png.exe | Bin 0 -> 155710 bytes tools/old/pcx2png/src/main.cpp | 47 + 51 files changed, 10988 insertions(+) create mode 100644 tools/old/INDEX/COMBINE.C create mode 100644 tools/old/INDEX/MAKEFILE create mode 100644 tools/old/INDEX/MAKEFILE.MSC create mode 100644 tools/old/INDEX/NDX.C create mode 100644 tools/old/INDEX/PKG.C create mode 100644 tools/old/INDEX/SPLIT.C create mode 100644 tools/old/INDEX/UNPKG.C create mode 100644 tools/old/anm/ANIM.H create mode 100644 tools/old/anm/ANIM.INC create mode 100644 tools/old/anm/ANIM2PCX.C create mode 100644 tools/old/anm/ANIM2PCX.LNK create mode 100644 tools/old/anm/ANIMA.ASM create mode 100644 tools/old/anm/ANIMFILE.TXT create mode 100644 tools/old/anm/ANIMIO.C create mode 100644 tools/old/anm/ASM.INC create mode 100644 tools/old/anm/DALLOC.ASM create mode 100644 tools/old/anm/EGA.INC create mode 100644 tools/old/anm/GIO.C create mode 100644 tools/old/anm/LPFILE.C create mode 100644 tools/old/anm/MAIN.H create mode 100644 tools/old/anm/MAIN.INC create mode 100644 tools/old/anm/MISC.C create mode 100644 tools/old/anm/MISCA.ASM create mode 100644 tools/old/anm/PBIO.C create mode 100644 tools/old/anm/READFRST.TXT create mode 100644 tools/old/anm/README.TXT create mode 100644 tools/old/anm/anmformt/ANIMFILE.TXT create mode 100644 tools/old/anm/anmformt/CGRAPH.ASM create mode 100644 tools/old/anm/anmformt/MAKESHOW.M create mode 100644 tools/old/anm/anmformt/SHOWANIM.C create mode 100644 tools/old/anm/anmformt/SHOWANIM.H create mode 100644 tools/old/anm/anmformu/ANIMFILE.TXT create mode 100644 tools/old/anm/anmformu/CGRAPH.ASM create mode 100644 tools/old/anm/anmformu/MAKESHOW.M create mode 100644 tools/old/anm/anmformu/SHOWANIM.C create mode 100644 tools/old/anm/anmformu/SHOWANIM.H create mode 100644 tools/old/anm/anmformu/anmformt.txt create mode 100755 tools/old/anm/cnv1.bat create mode 100755 tools/old/anm/cnvrtanm.bat create mode 100644 tools/old/anm/msvc++/anm2pcx.dsp create mode 100644 tools/old/anm/msvc++/anm2pcx.dsw create mode 100644 tools/old/font test/fonts.c create mode 100755 tools/old/ndxscripts/ndxcomms.bat create mode 100755 tools/old/ndxscripts/ndxships.bat create mode 100644 tools/old/palette test/Palette Shifting Test.dsp create mode 100644 tools/old/palette test/Palette Shifting Test.dsw create mode 100644 tools/old/palette test/main.cpp create mode 100644 tools/old/pcx2png/msvc++/pcx2png.dsp create mode 100644 tools/old/pcx2png/msvc++/pcx2png.dsw create mode 100755 tools/old/pcx2png/pcx2png.exe create mode 100644 tools/old/pcx2png/src/main.cpp diff --git a/tools/old/INDEX/COMBINE.C b/tools/old/INDEX/COMBINE.C new file mode 100644 index 000000000..6df600cb8 --- /dev/null +++ b/tools/old/INDEX/COMBINE.C @@ -0,0 +1,38 @@ +#include +#include "compiler.h" + +main (argc, argv) +int argc; +char *argv[]; +{ + FILE *infp, *outfp; + COUNT bytes_read; + DWORD filelen; + static char buf[512]; + + outfp = fopen (argv[1], "wb"); + + infp = fopen (argv[2], BUFFERED_BINREAD); + ffilelength (infp, &filelen); + while (filelen) + { + bytes_read = filelen >= sizeof (buf) ? + sizeof (buf) : (COUNT)filelen; + fwrite (buf, 1, fread (buf, 1, bytes_read, infp), outfp); + filelen -= bytes_read; + } + fclose (infp); + + infp = fopen (argv[3], BUFFERED_BINREAD); + ffilelength (infp, &filelen); + while (filelen) + { + bytes_read = filelen >= sizeof (buf) ? + sizeof (buf) : (COUNT)filelen; + fwrite (buf, 1, fread (buf, 1, bytes_read, infp), outfp); + filelen -= bytes_read; + } + fclose (infp); + + fclose (outfp); +} diff --git a/tools/old/INDEX/MAKEFILE b/tools/old/INDEX/MAKEFILE new file mode 100644 index 000000000..9dfad5c5d --- /dev/null +++ b/tools/old/INDEX/MAKEFILE @@ -0,0 +1,23 @@ +LIB_LIST = \ + \src\libs\video\watcom\video.lib \ + \src\libs\graphics\watcom\graphics.lib \ + \src\libs\memory\watcom\memory.lib \ + \src\libs\resource\watcom\resource.lib \ + \src\libs\input\watcom\input.lib \ + \src\libs\sound\watcom\sound.lib \ + \src\libs\decomp\watcom\decomp.lib \ + \src\libs\strings\watcom\strings.lib \ + \src\libs\task\watcom\task.lib \ + \src\libs\math\watcom\math.lib + +FLAGS = $(CFLAGS) -DPACKAGING -I\src\libs\resource + +ndx.exe pkg.exe unpkg.exe: $(@R).obj $(LIB_LIST) + @echo "Loading $@ ... " + @$(LINKER) @$(@R).lnk + @4gwbind 4gwpro t.exe $@ -V + @echo "done" + +ndx.obj pkg.obj unpkg.obj: $(@R).c + $(CC) $(FLAGS) $? + diff --git a/tools/old/INDEX/MAKEFILE.MSC b/tools/old/INDEX/MAKEFILE.MSC new file mode 100644 index 000000000..c3a2b201b --- /dev/null +++ b/tools/old/INDEX/MAKEFILE.MSC @@ -0,0 +1,70 @@ +MODEL = M +INC1 = .. +INC2 = ..\resource +#DFLAGS = /Ox /Gc /Gr +DFLAGS = /Zi /Od /Gs /Gc /Gr +CFLAGS = $(DFLAGS) -DPACKAGING /W4 /A$(MODEL) /NT RESSEG -I$(INC1) -I$(INC2) +DEST = \bin +EXTHDRS = +FFLAGS = +HDRS = +LDFLAGS = /ST:8192 /CO /NOE +LDMAP = $(@R) +LIBS = \ + ..\task\task.lib \ + ..\sound\sound.lib \ + ..\input\input.lib \ + ..\resource\resource.lib \ + ..\error\error.lib \ + ..\memory\memory.lib +LINKER = link +MAKEFILE = Makefile +INDEX_OBJS = ndx.obj +PACKAGE_OBJS = init.obj getres.obj +RES_OBJS = $(INC2)\init.obj $(INC2)\getres.obj +SPLIT_OBJS = split.obj combine.obj +COMBINE_OBJS = combine.o +PRINT = print +PROGRAMS = unpkg.exe ndx.exe pkg.exe +SETARGV = \lib\${MODEL}setargv +INDEX_SRCS = ndx.c +PACKAGE_SRCS = pkg.c + +all: $(PROGRAMS) + +ndx.exe: $(INDEX_OBJS) $(LIBS) + @echo "Loading $@ ... " + @$(LINKER) $(INDEX_OBJS), $@, $(LDMAP), $(LIBS) $(LDFLAGS); + @echo "done" + +pkg.exe: $(@R).obj $(PACKAGE_OBJS) $(LIBS) + @echo "Loading $@ ... " + @$(LINKER) $(@R).obj $(PACKAGE_OBJS), $@, $(LDMAP), $(LIBS) $(LDFLAGS); + @echo "done" + +unpkg.exe: $(@R).obj $(RES_OBJS) $(LIBS) + @echo "Loading $@ ... " + @$(LINKER) $(@R).obj $(RES_OBJS), $@, $(LDMAP), $(LIBS) $(LDFLAGS); + @echo "done" + +split.exe combine.exe: $(@:.exe=.obj) + @echo "Loading $@ ... " + @$(LINKER) $(@:.exe=.obj), $@, $(LDMAP), $(LDFLAGS); + @echo "done" + +combine: $(COMBINE_OBJS) + @echo "Loading $@ ... " + @blink /lc/lib/c.o,$(COMBINE_OBJS) TO $(@) LIB /lc/lib/lc.lib + @echo "done" + +backup: + (md b:index; ct [*.c,*.h,makefile] b:index) + +init.obj getres.obj: ../resource/$(@:.obj=.c) + $(CC) $(CFLAGS) -c $? + +.BEFORE: +.AFTER: + +combine.o: combine.c + lc -i/src/libs combine.c diff --git a/tools/old/INDEX/NDX.C b/tools/old/INDEX/NDX.C new file mode 100644 index 000000000..756b10628 --- /dev/null +++ b/tools/old/INDEX/NDX.C @@ -0,0 +1,926 @@ +#include +#include +#include +#include +#include "reslib.h" +#include "resource/index.h" + +INDEX_HEADER index_header; +TYPE_DESC type_list[MAX_TYPES]; +char workbuf[8192]; + +typedef union +{ + UWORD data_len; + UWORD filename_index; +} INSTANCE_INFO; + +typedef enum +{ + BOC_TOKEN, + EOC_TOKEN, + EOL_TOKEN, + STRING_TOKEN +} TOKEN_TYPE; + +typedef enum +{ + RESTART_STATE, + COMMENT_STATE, + ERROR_STATE, + + TYPE_CONTROL_STATE, + PATH_STATE, + PACKAGE_PATH_STATE, + PACKAGE_STATE, + INCLUDE_STATE, + + RESOURCE_STATE +} LINE_STATE; +#define FIRST_KEYWORD TYPE_CONTROL_STATE +#define FIRST_TYPE RESOURCE_STATE + +static char *keyword_tab[] = +{ + "TYPE", + "PATH", + "PACKAGE_PATH", + "PACKAGE", + "INCLUDE", +}; +#define NUM_KEYWORDS (sizeof (keyword_tab) / sizeof (keyword_tab[0])) + +typedef struct +{ + TOKEN_TYPE type; + char string[256]; +} TOKEN; + +typedef struct +{ + COUNT string_count, index; + MEM_HANDLE hBuf; +} STRING_TAB; + +static char type_names[MAX_TYPES][20]; +static STRING_TAB type_string_tab[MAX_TYPES], package_string_tab; +static STRING_TAB instance_file_string_tab, instance_path_string_tab; +static STRING_TAB package_file_string_tab, package_path_string_tab; +static COUNT last_instance_path_index = (COUNT)~0, + last_package_path_index = (COUNT)~0; + +PROC(STATIC +TOKEN_TYPE near get_token, (line_buf, ptoken, state), + ARG (char **line_buf) + ARG (TOKEN *ptoken) + ARG_END (LINE_STATE state) +) +{ + char ch, last_ch, *str; + + ptoken->type = EOL_TOKEN; +EatChars: + last_ch = '\0'; + while ((ch = *(*line_buf)++) == '\0' || + ch == ' ' || isspace (ch) || state == COMMENT_STATE || + ptoken->type == BOC_TOKEN) + { + if (ch == '\0' || ch == '\n') + return (ptoken->type); + else if (ch == '/' && last_ch == '*') + { + if (state == COMMENT_STATE) + return (ptoken->type = EOC_TOKEN); + else if (ptoken->type != BOC_TOKEN) + return (ERROR_STATE); + else + ptoken->type = EOL_TOKEN; + } + last_ch = ch; + } + + str = ptoken->string; + do + { + if ((*str++ = ch) == '*' && last_ch == '/') + { + if ((str -= 2) == ptoken->string) + { + ptoken->type = BOC_TOKEN; + + goto EatChars; + } + --*line_buf; + + break; + } + last_ch = ch; + } while ((ch = *(*line_buf)++) != '\0' && ch != ' ' && !isspace (ch)); + *str++ = '\0'; + + --*line_buf; + + return (ptoken->type = STRING_TOKEN); +} + +PROC(STATIC +LINE_STATE near GetKeywordState, (ptoken), + ARG_END (TOKEN *ptoken) +) +{ + int i; + + strupr (ptoken->string); + + for (i = 0; i < NUM_KEYWORDS; ++i) + { + if (!strcmp (keyword_tab[i], ptoken->string)) + return (FIRST_KEYWORD + i); + } + + for (i = index_header.num_types - 1; i >= 0; --i) + { + if (!strcmp (type_names[i], ptoken->string)) + return (FIRST_TYPE + i); + } + + return (ERROR_STATE); +} + +#define TAB_SIZE (64*1024) +#define AllocStringTab() mem_request (TAB_SIZE) +#define LockStringTab(h) (LPSTR)mem_lock (h) +#define UnlockStringTab(h) mem_unlock (h) + +PROC(STATIC +COUNT near add_string, (buf, pstring_tab, length), + ARG (char *buf) + ARG (STRING_TAB *pstring_tab) + ARG_END (int length) +) +{ + if (length > 0) + { + LPSTR lpStr; + + if (pstring_tab->hBuf == NULL_HANDLE) + pstring_tab->hBuf = AllocStringTab (); + + lpStr = LockStringTab (pstring_tab->hBuf); + lpStr += pstring_tab->index; + pstring_tab->index += length; + do + *lpStr++ = *buf++; + while (--length); + UnlockStringTab (pstring_tab->hBuf); + } + + return (pstring_tab->index); +} + +PROC(STATIC +COUNT near get_string, (buf, pstring_tab, index, length), + ARG (char *buf) + ARG (STRING_TAB *pstring_tab) + ARG (COUNT index) + ARG_END (int length) +) +{ + LPSTR lpStr; + + if (index >= pstring_tab->index) + { + *buf = '\0'; + return (0); + } + + lpStr = LockStringTab (pstring_tab->hBuf); + lpStr += index; + + if (length == -1) + { + do + ++index; + while (*buf++ = *lpStr++); + } + else if (length > 0) + { + index += length; + do + *buf++ = *lpStr++; + while (--length); + } + + UnlockStringTab (pstring_tab->hBuf); + + return (index); +} + +PROC(STATIC +COUNT near find_string, (ppath_index, string, pstring_tab), + ARG (PCOUNT ppath_index) + ARG (char *string) + ARG_END (STRING_TAB *pstring_tab) +) +{ + COUNT i, string_index; + + for (i = string_index = 0; i < pstring_tab->string_count; ++i) + { + COUNT pi; + BYTE buf[128]; + + if (ppath_index == 0) + { + pi = string_index; + string_index = get_string (buf, + pstring_tab, string_index, -1); + if (!strcmp (buf, string)) + return (pi); + } + else + { + string_index = get_string ((char *)&pi, + pstring_tab, string_index, sizeof (pi)); + string_index = get_string (buf, + pstring_tab, string_index, -1); + if (pi == *ppath_index && !strcmp (buf, string)) + return (i); + } + } + + if (ppath_index == 0) + { + ++pstring_tab->string_count; + add_string (string, + pstring_tab, + strlen (string) + 1); + return (string_index); + } + else + { + add_string ((char *)ppath_index, + pstring_tab, + sizeof (*ppath_index)); + add_string (string, + pstring_tab, + strlen (string) + 1); + + return (pstring_tab->string_count++); + } +} + +#define MAX_NUM_FILES 20 +static COUNT top_file_stack; +static FILE *file_stack[MAX_NUM_FILES]; + +PROC(STATIC +FILE * near pop_file, (), + ARG_VOID +) +{ + if (top_file_stack == 0) + return ((FILE *)NULL); + else + return (file_stack[--top_file_stack]); +} + +PROC(STATIC +BOOLEAN near push_file, (fp), + ARG_END (FILE *fp) +) +{ + if (top_file_stack == MAX_NUM_FILES) + return (FALSE); + else + { + file_stack[top_file_stack++] = fp; + return (TRUE); + } +} + +PROC(STATIC +void near create_headers, (), + ARG_VOID +) +{ + COUNT i, file_index; + FILE *fp, *inst_fp; + + fp = fopen ("restypes.h", "w"); + fprintf (fp, "#ifndef _RESTYPES_H\n"); + fprintf (fp, "#define _RESTYPES_H\n\n"); + + fprintf (fp, "enum\n{\n"); + for (i = 0; i < index_header.num_types; ++i) + { + if (i == 0) + fprintf (fp, " %s = 1", type_names[i]); + else + fprintf (fp, " %s", type_names[i]); + if (i < index_header.num_types - 1) + fprintf (fp, ","); + fprintf (fp, "\n"); + } + fprintf (fp, "};\n\n"); + fprintf (fp, "#endif /* _RESTYPES_H */\n\n"); + fclose (fp); + + fp = fopen ("respkg.h", "w"); + + fprintf (fp, "enum\n{\n"); + for (i = 0, file_index = 0; i < index_header.num_packages; ++i) + { + COUNT index; + + file_index = get_string ((char *)&index, + &package_string_tab, + file_index, sizeof (index)); + file_index = get_string (workbuf, + &package_string_tab, file_index, -1); + + if (i == 0) + fprintf (fp, " %s = 1", workbuf); + else + fprintf (fp, " %s", workbuf); + if (i < index_header.num_packages - 1) + fprintf (fp, ","); + fprintf (fp, "\n"); + } + fprintf (fp, "};\n\n"); + fclose (fp); + + inst_fp = fopen ("resinst.h", "w"); + + for (i = 0; i < index_header.num_types; ++i) + { + if (type_list[i].instance_count > 0) + { + COUNT j, type_index; + + sprintf (workbuf, "i%.7s.h", type_names[i]); + strlwr (workbuf); + fprintf (inst_fp, "#include \"%s\"\n", workbuf); + + fp = fopen (workbuf, "w"); + + for (j = 0, type_index = 0; j < type_list[i].instance_count; ++j) + { + RES_PACKAGE pack_id; + COUNT file_index; + + type_index = get_string ((char *)&pack_id, + &type_string_tab[i], type_index, sizeof (pack_id)); + type_index = get_string ((char *)&file_index, + &type_string_tab[i], type_index, sizeof (file_index)); + type_index = get_string (workbuf, + &type_string_tab[i], type_index, -1); + fprintf (fp, "#define %s\t0x%08lxL\n", + workbuf, MAKE_RESOURCE (pack_id, i + 1, j)); + } + +#ifdef OLD + fprintf (fp, "\ntypedef RESOURCE %s_INSTANCE;\n\n", type_names[i]); +#else /* !OLD */ + fprintf (fp, "\n\n"); +#endif /* OLD */ + fclose (fp); + } + } + + fclose (inst_fp); +} + +PROC(STATIC +void near create_index_file, (file_out), + ARG_END (char *file_out) +) +{ + COUNT i; + FILE *fp; + DWORD package_path_list_offs, package_file_list_offs; + + fp = fopen (file_out, "wb"); + fseek (fp, (long)sizeof (index_header) - 6, SEEK_SET); + +printf ("Writing out package descriptions\n"); + { + COUNT file_index; + PACKAGE_DESC package; + + package.flags_and_data_loc = 0xFF000000L; + for (i = 0, file_index = 0; i < index_header.num_packages; ++i) + { + COUNT j, index, num_types, num_instances; + + num_types = num_instances = 0; + for (j = 0; j < index_header.num_types; ++j) + { + COUNT instance_index[MAX_TYPES]; + RES_PACKAGE pack_id; + + if (i == 0) + instance_index[j] = 0; + + index = get_string ((char *)&pack_id, + &type_string_tab[j], + instance_index[j], sizeof (pack_id)); + if (index > 0 && pack_id == (RES_PACKAGE)(i + 1)) + { + ++num_types; + do + { + INSTANCE_INFO info; + + ++num_instances; + instance_index[j] = index; + instance_index[j] = get_string ((char *)&info.filename_index, + &type_string_tab[j], + instance_index[j], sizeof (info.filename_index)); + instance_index[j] = get_string (workbuf, + &type_string_tab[j], instance_index[j], -1); + + index = get_string ((char *)&pack_id, + &type_string_tab[j], + instance_index[j], sizeof (pack_id)); + } while (index > 0 && pack_id == (RES_PACKAGE)(i + 1)); + } + } + + file_index = get_string ((char *)&index, + &package_string_tab, + file_index, sizeof (index)); + file_index = get_string (workbuf, + &package_string_tab, file_index, -1); +printf ("\t%u total types, %u total instances in package %u -- <0x%lx>\n", num_types, num_instances, i + 1, package.flags_and_data_loc); + package.packmem_info = MAKE_RESOURCE (index, num_types, num_instances); + fwrite (&package, sizeof (PACKAGE_DESC), 1, fp); + } + } + +printf ("Writing out instance counts for %d types\n", index_header.num_types); + { + for (i = 0; i < index_header.num_types; ++i) + fwrite (&type_list[i].instance_count, + sizeof (type_list[i].instance_count), 1, fp); + } + + index_header.packmem_list_offs = (DWORD)ftell (fp); + +printf ("Writing out package member list\n"); + { /* write out resource list */ + for (i = 0; i < index_header.num_packages; ++i) + { + COUNT index, instance_index[MAX_TYPES]; + RES_INSTANCE first_instance[MAX_TYPES]; + RES_PACKAGE pack_id; + COUNT j; + +printf ("PACKAGE %u\n", i + 1); + for (j = 0; j < index_header.num_types; ++j) + { + DWORD encoding; + + if (i == 0) + { + instance_index[j] = 0; + first_instance[j] = 0; + } + + index = get_string ((char *)&pack_id, + &type_string_tab[j], + instance_index[j], sizeof (pack_id)); + if (index > 0 && pack_id == (RES_PACKAGE)(i + 1)) + { + COUNT instance_count; + + instance_count = 0; + do + { + INSTANCE_INFO info; + + ++instance_count; + index = get_string ((char *)&info.filename_index, + &type_string_tab[j], + index, sizeof (info.filename_index)); + index = get_string (workbuf, + &type_string_tab[j], index, -1); + + index = get_string ((char *)&pack_id, + &type_string_tab[j], + index, sizeof (pack_id)); + } while (index > 0 && pack_id == (RES_PACKAGE)(i + 1)); + + encoding = MAKE_RESOURCE (instance_count, + j + 1, first_instance[j]); +printf ("\ttype = %u, first_instance = %u, num_instances = %u\n", j + 1, first_instance[j], instance_count); + first_instance[j] += instance_count; + fwrite (&encoding, sizeof (DWORD), 1, fp); + } + } + +printf ("\n"); + for (j = 0; j < index_header.num_types; ++j) + { + index = get_string ((char *)&pack_id, + &type_string_tab[j], + instance_index[j], sizeof (pack_id)); + if (index > 0 && pack_id == (RES_PACKAGE)(i + 1)) + { + do + { + INSTANCE_INFO info; + + instance_index[j] = index; + instance_index[j] = get_string ((char *)&info.filename_index, + &type_string_tab[j], + instance_index[j], sizeof (info.filename_index)); + instance_index[j] = get_string (workbuf, + &type_string_tab[j], instance_index[j], -1); + +printf ("\tfilename = '%s'(%d)\n", workbuf, info.filename_index); + fwrite (&info, INSTANCE_LIST_SIZE, 1, fp); + index = get_string ((char *)&pack_id, + &type_string_tab[j], + instance_index[j], sizeof (pack_id)); + } while (index > 0 && pack_id == (RES_PACKAGE)(i + 1)); + } + } + } + } + + package_path_list_offs = (DWORD)ftell (fp); + +printf ("Writing out package path list\n"); + { + /* write out path list */ + COUNT path_index; + + for (i = path_index = 0; i < package_path_string_tab.string_count; ++i) + { + COUNT old_path_index; + BYTE buf[256]; + + old_path_index = path_index; + path_index = get_string (buf, + &package_path_string_tab, path_index, -1); + fwrite (buf, path_index - old_path_index, 1, fp); + } + } + + package_file_list_offs = (DWORD)ftell (fp); + +printf ("Writing out package file list\n"); + { /* write out file list */ + COUNT file_index; + BYTE buf[FILE_LIST_SIZE + 2]; /* account for '.' and + * null char in filename + */ + COUNT *ppath_offs = (COUNT *)&buf[0]; + BYTE *pfilename = &buf[sizeof (*ppath_offs)]; + BYTE *pext = &buf[sizeof (*ppath_offs) + FILE_NAME_SIZE]; + + for (i = file_index = 0; i < package_file_string_tab.string_count; ++i) + { + BYTE *pstr1, *pstr2; + + file_index = get_string ((char *)ppath_offs, + &package_file_string_tab, file_index, sizeof (*ppath_offs)); + file_index = get_string (pfilename, + &package_file_string_tab, file_index, -1); +printf ("\t'%s'\n", pfilename); + pstr1 = pfilename; + while (*pstr1 != '.') + ++pstr1; + pstr2 = pext; + + if (pstr1 == pstr2) + { + while (*pstr2++ = *++pstr1) + ; + } + else + { + COUNT j; + + *pstr1++ = '\0'; + + pstr1 += EXTENSION_SIZE - 1; + pstr2 += EXTENSION_SIZE - 1; + for (j = 0; j < EXTENSION_SIZE; ++j) + *pstr2-- = *pstr1--; + } + + fwrite (buf, FILE_LIST_SIZE, 1, fp); + } + } + + index_header.path_list_offs = (DWORD)ftell (fp); + +printf ("Writing out instance path list\n"); + { + /* write out path list */ + COUNT path_index; + + for (i = path_index = 0; i < instance_path_string_tab.string_count; ++i) + { + COUNT old_path_index; + BYTE buf[256]; + + old_path_index = path_index; + path_index = get_string (buf, + &instance_path_string_tab, path_index, -1); + fwrite (buf, path_index - old_path_index, 1, fp); + } + } + fwrite (&package_path_list_offs, sizeof (package_path_list_offs), 1, fp); + + index_header.file_list_offs = (DWORD)ftell (fp); + +printf ("Writing out instance file list\n"); + { /* write out file list */ + COUNT file_index; + BYTE buf[FILE_LIST_SIZE + 2]; /* account for '.' and + * null char in filename + */ + COUNT *ppath_offs = (COUNT *)&buf[0]; + BYTE *pfilename = &buf[sizeof (*ppath_offs)]; + BYTE *pext = &buf[sizeof (*ppath_offs) + FILE_NAME_SIZE]; + + for (i = file_index = 0; i < instance_file_string_tab.string_count; ++i) + { + BYTE *pstr1, *pstr2; + + file_index = get_string ((char *)ppath_offs, + &instance_file_string_tab, file_index, sizeof (*ppath_offs)); + file_index = get_string (pfilename, + &instance_file_string_tab, file_index, -1); + pstr1 = pfilename; + while (*pstr1 != '.') + ++pstr1; + pstr2 = pext; + + if (pstr1 == pstr2) + { + while (*pstr2++ = *++pstr1) + ; + } + else + { + COUNT j; + + *pstr1++ = '\0'; + + pstr1 += EXTENSION_SIZE - 1; + pstr2 += EXTENSION_SIZE - 1; + for (j = 0; j < EXTENSION_SIZE; ++j) + *pstr2-- = *pstr1--; + } + + fwrite (buf, FILE_LIST_SIZE, 1, fp); + } + } + fwrite (&package_file_list_offs, sizeof (package_file_list_offs), 1, fp); + + fseek (fp, 0L, SEEK_SET); + fwrite ((char *)&index_header + 2, sizeof (index_header) - 6, 1, fp); + fclose (fp); +printf ("%d\n", sizeof (index_header) - 6); +} + +PROC(STATIC +BOOLEAN near parse_args, (argc, argv, infile, outfile), + ARG (int argc) + ARG (char *argv[]) + ARG (char infile[]) + ARG_END (char outfile[]) +) +{ + if (argc != 3) + return (FALSE); + + strcpy (infile, argv[1]); + strcpy (outfile, argv[2]); + + return (TRUE); +} + +PROC(STATIC +LINE_STATE near parse_line, (fp, line_buf, state), + ARG (FILE **fp) + ARG (char *line_buf) + ARG_END (LINE_STATE state) +) +{ + TOKEN_TYPE token_type; + TOKEN token; + + while ((token_type = get_token (&line_buf, &token, state)) != EOL_TOKEN) + { + char loc_buf[128]; + + switch (state) + { + case ERROR_STATE: + state = RESTART_STATE; + case RESTART_STATE: + if (token_type == BOC_TOKEN) + state = COMMENT_STATE; + else + { + switch (state = GetKeywordState (&token)) + { + case ERROR_STATE: + return (ERROR_STATE); + case PATH_STATE: + if (get_token (&line_buf, + &token, state) == STRING_TOKEN) + { + if (strcmp (token.string, ".") == 0) + last_instance_path_index = (COUNT)~0; + else +{ + last_instance_path_index = find_string ( + 0, token.string, + &instance_path_string_tab); +get_string (token.string, &instance_path_string_tab, last_instance_path_index, -1); +} + +printf ("PATH\n\t'%s'\n", token.string); + state = RESTART_STATE; + } + break; + case PACKAGE_PATH_STATE: + if (get_token (&line_buf, + &token, state) == STRING_TOKEN) + { + if (strcmp (token.string, ".") == 0) + last_package_path_index = (COUNT)~0; + else +{ + last_package_path_index = find_string ( + 0, token.string, + &package_path_string_tab); +get_string (token.string, &package_path_string_tab, last_package_path_index, -1); +} + +printf ("PACKAGE_PATH\n\t'%s'\n", token.string); + state = RESTART_STATE; + } + break; + case PACKAGE_STATE: + if (get_token (&line_buf, + &token, state) == STRING_TOKEN) + { + strcpy (loc_buf, token.string); + + if (get_token (&line_buf, + &token, state) == STRING_TOKEN) + { + COUNT which_string; + + if (index_header.num_packages == MAX_PACKAGES) + return (ERROR_STATE); + ++index_header.num_packages; + + which_string = find_string ( + &last_package_path_index, + token.string, + &package_file_string_tab); + + ++package_string_tab.string_count; + add_string ((char *)&which_string, + &package_string_tab, + sizeof (which_string)); + add_string (loc_buf, + &package_string_tab, + strlen (loc_buf) + 1); + +printf ("PACKAGE\n\t'%s'\n", loc_buf); + state = RESTART_STATE; + } + } + break; + case INCLUDE_STATE: + if (get_token (&line_buf, + &token, state) == STRING_TOKEN) + { + if (get_string (loc_buf, + &instance_path_string_tab, last_instance_path_index, -1)) + strcat (loc_buf, "/"); + strcat (loc_buf, token.string); + if (push_file (*fp) && + (*fp = fopen (loc_buf, "r")) != NULL) + { +printf ("INCLUDE\n\t'%s'\n", loc_buf); + state = RESTART_STATE; + } + } + break; + case TYPE_CONTROL_STATE: + if (get_token (&line_buf, + &token, state) == STRING_TOKEN) + { + if (GetKeywordState (&token) == ERROR_STATE && + index_header.num_types < MAX_TYPES) + { + strcpy (type_names[index_header.num_types++], + token.string); +printf ("TYPE\n\t'%s'\n", token.string); + state = RESTART_STATE; + } + } + break; + default: + { + COUNT type; + + type = (COUNT)(state - RESOURCE_STATE); + if (type_list[type].instance_count == MAX_INSTANCES) + return (ERROR_STATE); + ++type_list[type].instance_count; + + if (get_token (&line_buf, + &token, state) == STRING_TOKEN) + { + ++type_string_tab[type].string_count; + add_string ((char *)&index_header.num_packages, + &type_string_tab[type], + sizeof (index_header.num_packages)); + add_string ((char *)&instance_file_string_tab.string_count, + &type_string_tab[type], + sizeof (instance_file_string_tab.string_count)); + add_string (token.string, + &type_string_tab[type], + strlen (token.string) + 1); + + if (get_token (&line_buf, + &token, state) == STRING_TOKEN) + { + ++instance_file_string_tab.string_count; + add_string ((char *)&last_instance_path_index, + &instance_file_string_tab, + sizeof (last_instance_path_index)); + add_string (token.string, + &instance_file_string_tab, + strlen (token.string) + 1); +printf ("INSTANCE\n\t'%s'\n", token.string); + state = RESTART_STATE; + } + } + break; + } + } + } + break; + case COMMENT_STATE: + if (token_type == EOC_TOKEN) + state = RESTART_STATE; + break; + } + } + + return (state <= COMMENT_STATE ? state : ERROR_STATE); +} + +PROC( +void CDECL main, (argc, argv), + ARG (int argc) + ARG_END (char *argv[]) +) +{ + char outfile[80]; + FILE *fp; + LINE_STATE state; + + mem_init ((MEM_SIZE)0, 0, NULL_PTR); + + state = ERROR_STATE; + if (parse_args (argc, argv, workbuf, outfile) && + (fp = fopen (workbuf, "r")) != NULL) + { + do + { + while (fgets (workbuf, sizeof (workbuf) - 1, fp) != NULL && + (state = parse_line (&fp, workbuf, state)) != ERROR_STATE) + ; + fclose (fp); + } while (state != ERROR_STATE && (fp = pop_file ()) != NULL); + + if (state != ERROR_STATE) + { +printf ("creating headers\n"); + create_headers (); +printf ("creating index file\n"); + create_index_file (outfile); +printf ("done\n"); + } + } + + mem_uninit (); + + if (state != ERROR_STATE) + exit (0); + else + exit (1); +} diff --git a/tools/old/INDEX/PKG.C b/tools/old/INDEX/PKG.C new file mode 100644 index 000000000..7880b3a56 --- /dev/null +++ b/tools/old/INDEX/PKG.C @@ -0,0 +1,267 @@ +#include +#include +#include +#include +#include +#include "resource/resintrn.h" + +static FILE *package_fp; +static BOOLEAN sanity_check; +char workbuf[8192]; +char file_buf[256]; +static long package_offset; + +PROC_GLOBAL( +MEM_HANDLE near load_package, (ResHeaderPtr, res_package), + ARG (INDEX_HEADERPTR ResHeaderPtr) + ARG_END (RES_PACKAGE res_package) +); +PROC_GLOBAL( +void near get_resource_filename, (ResHeaderPtr, pbuf, file_index), + ARG (INDEX_HEADERPTR ResHeaderPtr) + ARG (PSTR pbuf) + ARG_END (COUNT file_index) +); +PROC_GLOBAL( +DWORD near get_packmem_offs, (ResHeaderPtr, res_package), + ARG (INDEX_HEADERPTR ResHeaderPtr) + ARG_END (RES_PACKAGE res_package) +); + +PROC(STATIC +void near copy_data, (in_fp, out_fp, length), + ARG (FILE *in_fp) + ARG (FILE *out_fp) + ARG_END (DWORD length) +) +{ + do + { + COUNT num_bytes; + + num_bytes = length >= (DWORD)sizeof (workbuf) ? + sizeof (workbuf) : (COUNT)length; + fread (workbuf, num_bytes, 1, in_fp); + fwrite (workbuf, num_bytes, 1, out_fp); + length -= num_bytes; + } while (length); +} + +PROC(STATIC +MEM_HANDLE write_resource, (in_fp, length), + ARG (FILE *in_fp) + ARG_END (DWORD length) +) +{ + length = (length + 3) & ~3L; + if (strcmp (workbuf, file_buf)) + { + if (!sanity_check) + copy_data (in_fp, package_fp, length); + } + else + { + printf ("FILE NAMES THE SAME -- COPY ABORTED!!!\n"); + package_offset = 0L; + } + + return ((MEM_HANDLE)(length >> 2)); +} + +PROC(STATIC +BOOLEAN file_error, (pFileName), + ARG_END (PSTR pFileName) +) +{ + printf ("UNABLE TO FIND '%s'\n", pFileName); + if (!sanity_check) + exit (1); + + return (TRUE); +} + +PROC(STATIC +BOOLEAN near parse_args, (argc, argv, infile, outfile), + ARG (int argc) + ARG (char *argv[]) + ARG (char infile[]) + ARG_END (char outfile[]) +) +{ + while (--argc > 0) + { + ++argv; + if ((*argv)[0] == '-' + && toupper ((*argv)[1]) == 'S') + sanity_check = TRUE; + else if (infile[0] == '\0') + strcpy (infile, *argv); + else if (outfile[0] == '\0') + strcpy (outfile, *argv); + } + + return (infile[0] != '\0' && outfile[0] != '\0'); +} + +PROC( +void CDECL main, (argc, argv), + ARG (int argc) + ARG_END (char *argv[]) +) +{ + char outfile[80]; + + mem_init ((MEM_SIZE)0, 0, NULL_PTR); + + if (parse_args (argc, argv, workbuf, outfile)) + { + long file_offs; + FILE *out_fp; + COUNT i, num_types; + DWORD old_path_list_offs, old_file_list_offs, + package_path_list_offs, package_file_list_offs, + header_len; + FILE *res_fp; + INDEX_HEADERPTR ResHeaderPtr; + MEM_HANDLE hList; + RES_HANDLE_LISTPTR ResourceHandleListPtr; + ENCODEPTR TypeEncodePtr; + DATAPTR DataPtr; + + if (InitResourceSystem (workbuf, 0, file_error) == 0) + exit (1); + res_fp = fopen (workbuf, "rb"); + + ResHeaderPtr = _get_current_index_header (); + ResHeaderPtr->res_fp = res_fp; + old_path_list_offs = ResHeaderPtr->path_list_offs; + old_file_list_offs = ResHeaderPtr->file_list_offs; + + /* subtract char index_file_name[36]; DWORD data_offs; MEM_HANDLE hPredHeader, hSuccHeader; */ + header_len = old_path_list_offs; +printf ("INDEX HEADER SIZE: %lu -- (0x%04x)\n", header_len, res_fp); + + if (!sanity_check) + { + out_fp = fopen (outfile, "wb"); + fseek (res_fp, 0L, SEEK_SET); + copy_data (res_fp, out_fp, header_len); + fclose (out_fp); + } + + num_types = CountResourceTypes (); + for (i = 1; i <= num_types; ++i) + InstallResTypeVectors (i, write_resource, NULL_PTR); + + fseek (res_fp, old_file_list_offs - + sizeof (package_path_list_offs), SEEK_SET); + fread (&package_path_list_offs, + sizeof (package_path_list_offs), 1, res_fp); + fseek (res_fp, filelength (fileno (res_fp)) - + sizeof (package_file_list_offs), SEEK_SET); + fread (&package_file_list_offs, + sizeof (package_file_list_offs), 1, res_fp); + for (i = 1; i <= ResHeaderPtr->num_packages; ++i) + { + COUNT file_index; + + file_index = GET_PACKAGE ( + ResHeaderPtr->PackageList[i - 1].packmem_info + ); + ResHeaderPtr->path_list_offs = package_path_list_offs; + ResHeaderPtr->file_list_offs = package_file_list_offs; + get_resource_filename (ResHeaderPtr, workbuf, file_index); + ResHeaderPtr->path_list_offs = old_path_list_offs; + ResHeaderPtr->file_list_offs = old_file_list_offs; + + if (!sanity_check && strcmp (workbuf, outfile) == 0) + { + out_fp = fopen (outfile, "r+b"); + file_offs = (long)package_file_list_offs + + (long)file_index * FILE_LIST_SIZE + + sizeof (UWORD); /* skip path_offset */ + fseek (out_fp, file_offs, 0); + putc ('\0', out_fp); + fclose (out_fp); + } + + package_fp = fopen (workbuf, "ab"); + package_offset = LengthResFile (package_fp); +printf ("Packaging '%s' at offset %ld . . .\n", workbuf, package_offset); + hList = load_package (ResHeaderPtr, i); + fclose (package_fp); + + ResHeaderPtr->PackageList[i - 1].flags_and_data_loc = + MAKE_DWORD (hList, 0); + if (hList) + { + LockResourceHandleList (ResHeaderPtr, hList, i, + &ResourceHandleListPtr, &TypeEncodePtr, &DataPtr); + ResourceHandleListPtr->flags_and_data_loc = 0xFF000000 | package_offset; + UnlockResourceHandleList (hList); + } + } + + if (!sanity_check) + out_fp = fopen (outfile, "r+b"); + + for (i = 1; i <= ResHeaderPtr->num_packages; ++i) + { + COUNT num_types, num_instances; + + num_types = CountPackageTypes (ResHeaderPtr, i); + num_instances = CountPackageInstances (ResHeaderPtr, i); + + hList = (MEM_HANDLE)LOWORD ( + ResHeaderPtr->PackageList[i - 1].flags_and_data_loc); + + if (hList) + { + LockResourceHandleList (ResHeaderPtr, hList, i, + &ResourceHandleListPtr, &TypeEncodePtr, &DataPtr); + ResHeaderPtr->PackageList[i - 1].flags_and_data_loc = + ResourceHandleListPtr->flags_and_data_loc; + } + + if (!sanity_check) + { + file_offs = (long)get_packmem_offs (ResHeaderPtr, i) + + (num_types * PACKMEM_LIST_SIZE); + fseek (out_fp, file_offs, SEEK_SET); + while (num_instances--) + { + COUNT length; + + length = hList ? MAKE_WORD (DataPtr[0], DataPtr[1]) : 0; + DataPtr += 2; + fwrite (&length, sizeof (length), 1, out_fp); + } + } + + if (hList) + { + UnlockResourceHandleList (hList); + FreeResourceHandleList (hList); + } + } + + if (!sanity_check) + { + ResHeaderPtr->res_fp = (FILE *)~0; + ResHeaderPtr->path_list_offs = package_path_list_offs; + ResHeaderPtr->file_list_offs = package_file_list_offs; + ResHeaderPtr->index_info.header_len = header_len; + + fseek (out_fp, 0L, SEEK_SET); + fwrite (ResHeaderPtr, sizeof (INDEX_HEADER) + + ResHeaderPtr->num_packages * sizeof (PACKAGE_DESC), 1, out_fp); + fclose (out_fp); + } + + UninitResourceSystem (); + } + + mem_uninit (); + + exit (0); +} diff --git a/tools/old/INDEX/SPLIT.C b/tools/old/INDEX/SPLIT.C new file mode 100644 index 000000000..049901887 --- /dev/null +++ b/tools/old/INDEX/SPLIT.C @@ -0,0 +1,40 @@ +#include +#include "compiler.h" + +main (argc, argv) +int argc; +char *argv[]; +{ + FILE *infp, *outfp; + COUNT bytes_read; + DWORD filelen, halflen; + static char buf[512]; + + infp = fopen (argv[1], "rb"); + + ffilelength (infp, &filelen); + halflen = filelen >> 1; + filelen -= halflen; + + outfp = fopen (argv[2], "wb"); + while (halflen) + { + bytes_read = halflen >= sizeof (buf) ? + sizeof (buf) : (COUNT)halflen; + fwrite (buf, 1, fread (buf, 1, bytes_read, infp), outfp); + halflen -= bytes_read; + } + fclose (outfp); + + outfp = fopen (argv[3], "wb"); + while (filelen) + { + bytes_read = filelen >= sizeof (buf) ? + sizeof (buf) : (COUNT)filelen; + fwrite (buf, 1, fread (buf, 1, bytes_read, infp), outfp); + filelen -= bytes_read; + } + fclose (outfp); + + fclose (infp); +} diff --git a/tools/old/INDEX/UNPKG.C b/tools/old/INDEX/UNPKG.C new file mode 100644 index 000000000..e1e88b278 --- /dev/null +++ b/tools/old/INDEX/UNPKG.C @@ -0,0 +1,129 @@ +#include +#include +#include +#include "resource/resintrn.h" + +STATIC RES_PACKAGE res_package; +STATIC COUNT name_index; +STATIC char file_name[100][80]; +char workbuf[8 * 1024]; + +PROC(STATIC +MEM_HANDLE WriteData, (fp, len), + ARG (FILE *fp) + ARG_END (DWORD len) +) +{ + COUNT num_bytes; + FILE *out_fp; + INDEX_HEADERPTR ResHeaderPtr; + +printf ("\tEXTRACTING %lu bytes @ '%s'\n", len, file_name[name_index]); + ResHeaderPtr = _get_current_index_header (); + if (CountPackageInstances (ResHeaderPtr, res_package) == 1) + { + RES_PACKAGE r; + + r = res_package; + do + { + if (r == ResHeaderPtr->num_packages) + len = LengthResFile (fp); + else if (GET_PACKAGE ( + ResHeaderPtr->PackageList[r].packmem_info + ) != GET_PACKAGE ( + ResHeaderPtr->PackageList[res_package - 1].packmem_info + )) + len = 0; + else + len = (ResHeaderPtr->PackageList[r].flags_and_data_loc + & ~0xFF000000); + ++r; + } while (len == 0); + + len -= ftell (fp); +printf ("\t\tOVERRIDING length (%lu)\n", len); +#ifdef DEBUG +{ +#include +while (!kbhit ()); +getch (); +} +#endif /* DEBUG */ + } + + out_fp = fopen (file_name[name_index++], "wb"); + do + { + num_bytes = len <= sizeof (workbuf) ? (COUNT)len : sizeof (workbuf); + fread (workbuf, num_bytes, 1, fp); + fwrite (workbuf, num_bytes, 1, out_fp); + } while (len -= num_bytes); + fclose (out_fp); + return (0); +} + +PROC(STATIC +MEM_HANDLE GetFileName, (fp, len), + ARG (FILE *fp) + ARG_END (DWORD len) +) +{ +printf ("FOUND '%s'\n", _cur_resfile_name); + strcpy (file_name[name_index++], _cur_resfile_name); + return (0); +} + +PROC( +void CDECL main, (argc, argv), + ARG (int argc) + ARG_END (char **argv) +) +{ + COUNT i, num_types; + MEM_HANDLE hPkg, hNdx; + INDEX_HEADERPTR ResHeaderPtr; + + mem_init ((MEM_SIZE)0, 0, NULL_PTR); + + hPkg = InitResourceSystem (argv[1], 0, NULL_PTR); + ResHeaderPtr = _get_current_index_header (); + num_types = CountResourceTypes (); + for (i = 1; i <= num_types; ++i) + { + InstallResTypeVectors (i, WriteData, NULL_PTR); + } + + hNdx = OpenResourceIndexFile (argv[2]); + SetResourceIndex (hNdx); + for (i = 1; i <= num_types; ++i) + { + InstallResTypeVectors (i, GetFileName, NULL_PTR); + } + + for (res_package = 1; + res_package <= ResHeaderPtr->num_packages; + ++res_package) + { + PROC_GLOBAL( + MEM_HANDLE near load_package, (ResHeaderPtr, res_package), + ARG (INDEX_HEADERPTR ResHeaderPtr) + ARG_END (RES_PACKAGE res_package) + ); + + name_index = 0; + SetResourceIndex (hNdx); + load_package (_get_current_index_header (), res_package); + + name_index = 0; + SetResourceIndex (hPkg); + load_package (_get_current_index_header (), res_package); + } + + CloseResourceIndex (hNdx); + UninitResourceSystem (); + + mem_uninit (); + + exit (0); +} diff --git a/tools/old/anm/ANIM.H b/tools/old/anm/ANIM.H new file mode 100644 index 000000000..7fe8dc135 --- /dev/null +++ b/tools/old/anm/ANIM.H @@ -0,0 +1,91 @@ +/*--anim.h---------------------------------------------------------- + * anim definitions for ANIM2PCX. + */ + +/* --- DeluxePaint Animation currently imposes this limit, though + * file format is capable of more. + */ +#define MAX_SUPPORTED_FRAMES (UWORD)9999 +#define MAX_FRAME_CHARS 4 /* # digits in MAX_SUPPORTED_FRAMES */ + +#define MAX_FRAMES (UWORD)65534 + /* Maximum # frames supported by current anim format. + * "65534": 1 left at end for "last-to-first" delta. + * NOTE: can't usefully be this large, as need free lp's during editting. + * Most anim's won't fit 255 pages per lp, so until we allow more than + * 255 lp's, won't reach MAX_FRAMES anyway. + */ +#define MAX_RECORDS (UWORD)65535 + +#define FASTEST_RATE 70 /* Fastest rate anim can be played at. */ + +#define MAX_LARGE_PAGE_SIZE (UWORD)(320*203) + /* WARNING: this may be stored in DP Animation's picture buffer, + * ASSUMES we've allocated three extra lines to the buffer. + * This allows us to come close to 64 KB, to minimize file wastage. + */ + +#define NBYTES_IN_BITMAP(bm) ((UWORD)(bm)->width * (UWORD)(bm)->box.h) + /* TBD: ASSUMES < 64 KB. Won't be true for Super-VGA. */ + +#define BSEG(bitmap) (bitmap)->seg[0] + +#define PALETTE_SIZE (MAX_COLORS * sizeof(LONG)) + +#define FIRST_FRAME_N 1 /* Frame #s start at 1. */ +#define LAST_DELTA_N (FIRST_FRAME_N-1) + /* Frame # used to store delta from last-frame to first. */ +#define LAST_FRAME_N (animFrames-1+FIRST_FRAME_N) +extern UWORD animFrames; + +/* --------------- from IFF.H (Interchange File Format) --------------- + */ +/* --- Four-character IDentifier builder. */ +#define MakeID(d,c,b,a) ((LONG)(a)<<24 | (LONG)(b)<<16 | \ + (LONG)(c)<<8 | (LONG)(d) ) + + +/* --------------- anim file format -------------------- */ + +#define CCYCLE70 0 /* 70 Hz color-cycle interrupt */ + /* P:Caused performance problems on slow machines, especially with cache on. + */ + +/* ---Bitmap body types. */ +#define BMBODY_UNCOMPRESSED 0 +#define BMBODY_RUNSKIPDUMP 1 /* Must match ANIMA.ASM/MakeRunSkipDump. */ + +/* --- RunSkipDump Bitmap body format. Matches ANIM.INC*/ +#define OP_DUMP 0x00 /* | cnt */ +#define OP_RUN 0x00 /* Cnt in separate byte. */ +#define OP_SKIP 0x80 /* | cnt */ +#define LONG_OP 0x80 +#define LONG_SKIP 0x00 /* sub-ops for LONG_OP */ +#define LONG_DUMP 0x80 +#define LONG_RUN 0xC0 +#define MAX_SHORT_DUMP 127 +#define MAX_LONG_DUMP 0x3fff +#define MAX_SHORT_RUN 255 +#define MAX_LONG_RUN 0x3fff +#define MAX_SHORT_SKIP 127 +#define MAX_LONG_SKIP 0x7fff +#define MIN_RUN 4 /* When in Dump, minimum worthwhile Run. */ +#define MIN_SKIP 2 /* When in Dump, minimum worthwhile Skip. */ +#define MIN_RUN_SKIP 4 /* When in Run, minimum worthwhile Skip. */ + /* Note: deltaX.nBytes shorter if can subsume Skip in the Run, + * but PC screen i/o is slow enough that it is worth time-saving + * of having the Skip. + */ + +/*----------------------------------------------------------------------*/ +/* Color Cycles */ +/*----------------------------------------------------------------------*/ + +#define MAXNCYCS 16 +/* lpfile depends on the size of this structure */ +typedef struct { + WORD count; + WORD rate; + WORD flags; + UBYTE low, high; /* bounds of range */ + } Range; diff --git a/tools/old/anm/ANIM.INC b/tools/old/anm/ANIM.INC new file mode 100644 index 000000000..744fe7e2d --- /dev/null +++ b/tools/old/anm/ANIM.INC @@ -0,0 +1,22 @@ +; ANIM.INC. RunSkipDump fields used in ANIMA.ASM. MUST MATCH ANIM.H. + +BMBODY_RUNSKIPDUMP = 1 ; RunSkipDump body header. + +; --- RunSkipDump Bitmap body format. +OP_DUMP = 000h +OP_RUN = 000h +OP_SKIP = 080h +LONG_OP = 080h +LONG_SKIP = 000h ; sub-ops for LONG_OP. +LONG_DUMP = 080h +LONG_RUN = 0C0h +MAX_SHORT_DUMP = 127 +MAX_LONG_DUMP = 03fffh +MAX_SHORT_RUN = 255 +MAX_LONG_RUN = 03fffh +MAX_SHORT_SKIP = 127 +MAX_LONG_SKIP = 07fffh +MIN_RUN = 4 ; When in Dump, minimum worthwhile Run. */ +MIN_SKIP = 2 ; When in Dump, minimum worthwhile Skip. */ +MIN_RUN_SKIP = 4 ; When in Run, minimum worthwhile Skip. */ + diff --git a/tools/old/anm/ANIM2PCX.C b/tools/old/anm/ANIM2PCX.C new file mode 100644 index 000000000..63105c5c9 --- /dev/null +++ b/tools/old/anm/ANIM2PCX.C @@ -0,0 +1,296 @@ +/*--anim2pcx.c---------------------------------------------------------- + * + * Program to translate an anim into a series of PCX picture files, + * and back from picture files into an anim. + * Note: all pictures are assumed to have the same 256 palette colors. + * + * This code is intended to be used as a starting point for programmers + * needing to convert anims to/from other formats, or to read/write + * anim files from their own applications. + * + * The source code for ANIM2PCX may be freely incorporated into + * commercial programs. + * + * Disclaimer: + * THIS PROGRAM IS PROVIDED WITHOUT SEPARATE CHARGE AND IS + * PROVIDED AS IS. ELECTRONIC ARTS DISCLAIMS ALL WARRANTIES, + * INCLUDING IMPLIED WARRANTIES AND WARRANTIES OF + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * + * *** History ********* + * Date Who Changes + * --------- --- --------------------------------------------------- + * 24-Oct-90 ss Original release. + *------------------------------------------------------------------ + * Note: all files editted with tab stops every 4 spaces. + */ + +#include "main.h" +#include "anim.h" + +#include +#include +#include +#include +#include + +#define local static + +extern char lpfSuffix[]; +local char pcxSuffix[]= "PCX"; + +BOOL FileError = FALSE; /* error reading or writing a file */ +BOOL EscFlag = FALSE; /* set TRUE when Esc key detected */ + +LONG curpal[MAX_COLORS]; /* palette */ + +/*-----------------------------------------------------------------*/ + +/* --- array of bit masks for one byte */ +BYTE bit_masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; + +BOOL toAnim; +UWORD animFrames = 10; +WORD curFrame = FIRST_FRAME_N; /* Frame currently in hidbm. */ +char animName[FILENAME_ROOT_LENGTH], pictRoot[FILENAME_ROOT_LENGTH]; + +BITMAP hidbm, prevFrame; /* Bitmap describing current & previous frames.*/ +UWORD lpSeg = NULL; /* Segment of lp buffer. */ +UWORD allocSeg = NULL; /* Segment allocated for delta buffer. */ + +/*-----------------------------------------------------------------*/ +/* forward procedure definitions */ + + +/* --------------- main --------------- + */ +main(argc, argv) +WORD argc; +char *argv[]; +{ + WORD result; + BITMAP bitmap; + + /* ---------------------------------------- + * Analyze arguments. + */ + switch (argc) { + case 1+1: /* anim => pcx */ + if (strlen(argv[1]) > FILENAME_ROOT_LENGTH) + goto usage; + strcpy(animName, argv[1]); + toAnim = FALSE; + break; + case 2+1: /* pcx => anim */ + if (strcmp(argv[1],"join") != SUCCESS && + strcmp(argv[1],"j") != SUCCESS) + goto usage; + if (strlen(argv[2]) > FILENAME_ROOT_LENGTH) + goto usage; + strcpy(animName, argv[2]); + toAnim = TRUE; + break; + default: /* Bad arguments. */ +usage: +#define PR(s) printf(s) + PR("\nUsage:\n"); + PR(" \"anim2pcx name\" to split anim name.ANM into a group of\n"); + PR(" picture files name0001.PCX, name0002.PCX...\n"); + PR(" \"anim2pcx j name\" or\n"); + PR(" \"anim2pcx join name\" to join a group of picture files\n"); + PR(" name0001.PCX, name0002.PCX, into an anim.\n"); + PR("\n"); + PR("NOTE: Only the first four letters of \"name\" are used \n"); + PR("in the picture file names.\n"); + PR(" \"anim2pcx foobar\" splits FOOBAR.ANM into FOOB0001.PCX...\n"); + PR(" \"anim2pcx j foobar\" joins FOOB0001.PCX... into FOOBAR.ANM.\n"); + exit(1); + } + + /* ---------------------------------------- + * Prepare for conversion. + */ + + /* --- Pict name's suffix is first four characters of anim name. + * Note: pictRoot may be shorter than four characters. + */ + strcpy(pictRoot, animName); + pictRoot[SEQUENCE_ROOT_LENGTH] = NULL; + + NewBitMap(&hidbm, N_COLUMNS, N_LINES); + NewBitMap(&prevFrame, N_COLUMNS, N_LINES); + allocSeg = DAlloc(MAX_LARGE_PAGE_SIZE); + lpSeg = DAlloc(MAX_LARGE_PAGE_SIZE); + if (!allocSeg || !lpSeg) + NotEnoughMemExit(); + + if (toAnim) + result = PCXFilesToAnimFile(); + else + result = AnimFileToPCXFiles(); + + /* ASSUME DAlloc'd memory automatically freed. */ + + if (EscFlag == TRUE) + EmergencyExit("Terminated at user's request"); + if (FileError) + EmergencyExit("File error"); + if (result != SUCCESS) + EmergencyExit("Failed to complete operation"); + printf("File(s) successfully converted.\n"); +} + +/* --------------- save_picture0 --------------- + */ +UWORD save_picture0(char *filename) +{ + UWORD result, file; + + file = CreateFile(filename, pcxSuffix); + if (!file) return FAIL; + + OpenIOBuffer(TRUE); + result = WritePCX_Header(file, &hidbm, curpal); + if (result != SUCCESS) goto done; + result = WritePCX_BODY(file, &hidbm); + if (result != SUCCESS) goto done; + result = WritePCX_256Palette(file, curpal); + +done: + WritePCX_Done(); + CloseIOBuffer(file); + closedos(file); + return result; +} + +/* --------------- AnimFileToPCXFiles --------------- + * ASSUMES "animName" already set to the root part of the animation file's + * name. (Note: don't include ".ANM" in "animName".) + */ +WORD AnimFileToPCXFiles() +{ + WORD i, len, result = FAIL; + char nm[FILENAME_LENGTH+1]; + char nstr[SEQUENCE_DIGITS_LENGTH+1]; + + if (OpenLpFile() == FAIL) { + printf("File \"%s.%s\" not found.\n", animName, lpfSuffix); + exit(1); + } + + printf("Creating %d PCX files from \"%s.%s\".\n", + animFrames, animName, lpfSuffix); + + FirstAnimFrame0(); + for (i = 0; i < animFrames; i++) { + strcpy(nm, pictRoot); + num_to_string_zeroes(curFrame, nstr, SEQUENCE_DIGITS_LENGTH); + strcat(nm, nstr); + if (save_picture0(nm) == FAIL) + goto done; /* TBD: message to user? */ + printf("."); /* Inform user of progress. */ + NextAnimFrame0(); + if (CheckAbort()) + goto done; + } + printf("\n"); /* Inform user of progress. */ + result = SUCCESS; + +done: + return result; +} + +/* --------------- load_picture0 --------------- + */ +UWORD load_picture0(char *filename) +{ + UWORD result, file; + BitMapHeader bmHdr; + + file = OpenFile(filename, pcxSuffix); + if (!file) return FAIL; + + OpenIOBuffer(FALSE); + result = ReadPCX_Header(file, &hidbm, curpal, &bmHdr); + if (result != SUCCESS) goto done; + result = ReadPCX_BODY(file, &hidbm, &bmHdr); + +done: + ReadPCX_Done(); + CloseIOBuffer(file); + closedos(file); + return result; +} + +/* --------------- PCXFilesToAnimFile --------------- + * ASSUMES "animName" already set to the root part of the animation file's + * name. (Note: don't include ".ANM" in "animName".) + */ +WORD PCXFilesToAnimFile() +{ + WORD i, file, len, result = FAIL; + char nm[FILENAME_LENGTH+1]; + char nstr[SEQUENCE_DIGITS_LENGTH+1]; + + for (i = 0; i < MAX_SUPPORTED_FRAMES; i++) { + strcpy(nm, pictRoot); + num_to_string_zeroes(i+FIRST_FRAME_N, nstr, SEQUENCE_DIGITS_LENGTH); + strcat(nm, nstr); + /* --- Verify file exists, then inform user of operation.*/ + file = OpenFile(nm, pcxSuffix); + if (!file) { + if (i == 0) { + printf("File \"%s.%s\" not found.\n", nm, pcxSuffix); + exit(1); + } else + break; /* Exit "for i" loop that was adding frames. */ + } + CloseFile(file); + if (i == 0) { + CreateLpFile(); + FirstAnimFrame0(); + printf("Creating \"%s.%s\" from PCX files.\n", + animName, lpfSuffix); + } else { + AddFrame(); /* And make that frame current. */ + far_movmem(BSEG(&hidbm), 0, BSEG(&prevFrame), 0, + N_BYTES_IN_BITMAP); + /* New frame's "previous frame" has identical contents. */ + } + if (load_picture0(nm) == FAIL) + break; /* No more pictures to load. NOT an error, + * TBD: but should delete last added frame! */ + printf("."); /* Inform user of progress. */ + WriteFinalAnimFrame(); + if (CheckAbort()) { + result = SUCCESS; /* So anim so far will be kept. */ + i++; /* So correct notion of frame count. */ + goto done; + } + } + + /* Create last-to-first delta. + * First create it as a new frame at the end of the anim, + * then remove it from the frame count and mark the anim + * as containing a last-to-first delta. + */ + strcpy(nm, pictRoot); + num_to_string_zeroes(FIRST_FRAME_N, nstr, SEQUENCE_DIGITS_LENGTH); + strcat(nm, nstr); + AddFrame(); /* And make that frame current. */ + far_movmem(BSEG(&hidbm), 0, BSEG(&prevFrame), 0, + N_BYTES_IN_BITMAP); + load_picture0(nm); + WriteFinalAnimFrame(); + ConvertFinalFrameToLastDelta(); + + result = SUCCESS; + +done: + WriteHdrAndCloseLpFile(); + if (result == SUCCESS) + printf("\nAnim has %d frames.\n", i); /* Inform user of progress. */ + else + DeleteFile(animName, lpfSuffix); + return result; +} diff --git a/tools/old/anm/ANIM2PCX.LNK b/tools/old/anm/ANIM2PCX.LNK new file mode 100644 index 000000000..e2e685b7f --- /dev/null +++ b/tools/old/anm/ANIM2PCX.LNK @@ -0,0 +1,5 @@ +anim2pcx anima dalloc gio misc misca lpfile pbio +anim2pcx.exe + + + \ No newline at end of file diff --git a/tools/old/anm/ANIMA.ASM b/tools/old/anm/ANIMA.ASM new file mode 100644 index 000000000..80edc4257 --- /dev/null +++ b/tools/old/anm/ANIMA.ASM @@ -0,0 +1,1095 @@ +;----------------------------------------------------------------- +; anima.asm +; --------- +; Assembly Anim stuff. +;----------------------------------------------------------------- + + include asm.inc + include anim.inc + + HEADER anima + + extrn _printf:far +;----------------------------------------------------------------- + + DSEG + IF 0 + extrn _doDump:byte + public _TotBytes +runMsg db 'run %x',13,0 +dumpMsg db 'dump %x',13,0 +skipMsg db 'skip %x',13,0 +clipMsg db '---dest:%x ',0 +finalMsg db '---dest:%x last-row-bytes:%x--- ',0 +_TotBytes dw 0 + ENDIF + ENDDS + + PSEG anima + +;----------------------------------------------------------------- +; void ShortDelay(UWORD delay); +; Does a high-speed delay loop. +;----------------------------------------------------------------- + + public _ShortDelay + STARTPROC _ShortDelay + +SD_DELAY = ARGB + + push bp + mov bp,sp + + mov cx,SD_DELAY[bp] +sd_loop: + loop sd_loop + + pop bp + ret + + ENDPROC _ShortDelay + + + IF 1 ; RunSkipDump format. +;----------------------------------------------------------------- +; UWORD PlayRunSkipDump(UWORD nBytes, srcSeg, srcAddr, dstSeg, dstAddr); +; Finishes playing the Bitmap body with type==RunSkipDump. +; RETURN final dstAddr (one byte past last pixel written). +; NOTE: since a final skip is omitted, this could be anywhere on the screen. +; If there is no final skip, it will be one past the last pixel on the screen. +; For a screen starting at address (offset) 0, its greatest value is +; the # pixels on the screen. +; NOTE: we're ignoring nBytes. Bad data could cause this to write past +; end of dst buffer, or even to loop forever. +;----------------------------------------------------------------- + + public _PlayRunSkipDump + STARTPROC _PlayRunSkipDump + +PR_N_BYTES = ARGB +PR_SRC_SEG = ARGB+2 +PR_SRC_ADDR = ARGB+4 +PR_DST_SEG = ARGB+6 +PR_DST_ADDR = ARGB+8 + + push bp + mov bp,sp + push si + push di + push es + + mov si,PR_SRC_ADDR[bp] + mov di,PR_DST_ADDR[bp] + mov es,PR_DST_SEG[bp] + + push ds ; Save DS:DGROUP. + mov ds,PR_SRC_SEG[bp] ; SET DS:dstSeg. NOT DGROUP. + + sub ch,ch ; SET CH = 0. + jmp short nextOp + +skip: + sub cl,80h ; Strip off sign bit, leaving skip cnt. + jz longOp ; cnt==0 indicates a long op. +; --- shortSkip --- + add di,cx ; skip # pixels. (CH=0) +; --- variation on NEXTOP inline to minimize jmp's --- +nextOp: ; Get and decode next op. + mov cl,[si] + inc si + jcxz run + or cl,cl ; Test CL's sign bit. + jl skip +dump: + rep movsb ; copy # pixels. (CH=0) +; --- variation on NEXTOP inline to minimize jmp's --- + mov cl,[si] + inc si + or cl,cl ; Test CL's sign bit. + jl skip + jg dump +run: + mov cl,[si] ; 8-bit unsigned count. + inc si + lodsb ; pixel value. + rep stosb ; set # pixels to value. (CH=0) +; --- variation on NEXTOP inline to minimize jmp's --- + mov cl,[si] + inc si + jcxz run + or cl,cl ; Test CL's sign bit. + jl skip + jmp short dump + +longOp: ; NOTE: if load into CX, must clear CH afterwards. + lodsw ; 16-bit unsigned count. + or ax,ax ; set flags. + jle notLongSkip +;longSkip: + add di,ax ; skip # pixels. + jmp short nextOp + ; longSkip only used for > 2*127, so can't be very many, + ; so don't bother saving one jmp with inline NEXTOP. + +notLongSkip: + jz stop ; long count of zero means "stop code". + mov cx,ax ; may SET CH non-zero. + sub ch,80h ; Clear sign bit. + cmp ch,40h + jge longRun +; --- For maximum speed on longDump, caller should insure src & dst are +; aligned. To do so, caller must calculate whether +; src DATA will begin on same (odd or even) alignment as dst data. +; If not, first put a 1-byte Dump, which occupies 2 src bytes, thereby +; shifting relative alignment (src moves 2, dst moves 1). +;longDump + test si,1 ; Insure src word-aligned. + ; In case caller didn't sync src & dst, we chose + ; to align src because we know it is of benefit -- + ; aligning dst on 8-bit video cards might not be of + ; any benefit. + jz dumpWordAligned + movsb ; get to word boundary. + dec cx +dumpWordAligned: + shr cx,1 ; Convert byte count to word count. + jc dumpOddByte + rep movsw ; Word-aligned. +longOpDone: + sub ch,ch ; SET CH = 0. + jmp short nextOp + +dumpOddByte: + rep movsw ; Word-aligned. + movsb + jmp short longOpDone + +longRun: + sub ch,40h ; Clear "longRun" bit. + lodsb + mov ah,al ; Replicate byte to word value. + test di,1 ; Insure dst word-aligned. + jz runWordAligned + stosb + dec cx +runWordAligned: + shr cx,1 ; Convert byte count to word count. + jc runOddByte + rep stosw ; Word-aligned. + jmp short longOpDone + +runOddByte: + rep stosw ; Word-aligned. + stosb + jmp short longOpDone + +stop: + pop ds ; Restore DS:DGROUP. + + mov ax,di ; RETURN final dstAddr. + pop es + pop di + pop si + pop bp + ret + + ENDPROC _PlayRunSkipDump + + +;----------------------------------------------------------------- +; UWORD MakeRunSkipDump(UWORD src1Seg, src2Seg, finalPixelAddr, +; UWORD dstSeg, dstAddr, dstLimit, UWORD *nBytesP, +; UWORD srcWidth, finalRowAddr, finalRowWidth, +; BOOL inFinalRow, skipPermitted); +; Finishes making the Bitmap body with type==RunSkipDump. +; RETURN TRUE if fit in deltaX. +; SIDE_EFFECT: set deltaX.nBytes, store that many bytes at deltaX.(seg:addr). +; ASSUMES srcs start at Addr=0. +;----------------------------------------------------------------- + +ADDR = 0 ; Field-offsets within a far ptr. 16-bit-offset. +SEGM = 2 ; Segment. + +; --- registers --- +; AL: pixel. Value of current src2 pixel. +; AH: runPix. Value of pixels in current Run. +; BL: skipInDump. # skippable bytes in Dump or Run. +; BH: runInDump. # runnable bytes in Dump. +; CX: wordCnt. # pixels processed for current op. +; DX: -- temporary. +; DS:SI: src2. +; ES:DI: src1 or dst. -- careful, ES:DI used for two purposes. + + public _MakeRunSkipDump + STARTPROC _MakeRunSkipDump + +MR_SRC1_SEG = ARGB +MR_SRC2_SEG = ARGB+2 +MR_FINAL_PIXEL_ADDR = ARGB+4 +MR_DST_SEG = ARGB+6 +MR_DST_ADDR = ARGB+8 ; dst0 -- save so can calculate size. +MR_DST_LIMIT = ARGB+10 ; dstLimit => dstAddr musn't pass this. +MR_N_BYTES_PTR = ARGB+12 +MR_SRC_WIDTH = ARGB+14 +MR_FINAL_ROW_ADDR = ARGB+16 +MR_FINAL_ROW_WIDTH = ARGB+18 +MR_IN_FINAL_ROW = ARGB+20 +MR_SKIP_PERMITTED = ARGB+22 +; --- locals +MR_SRC1_FAR = -4 ; ES:DI when addressing src1. +MR_DST_FAR = -8 ; ES:DI when addressing dst. +MR_MUST_STOP = -9 ; BOOL mustStop. Have reached end of src data. +;unused byte... MR_??? = -10 ; BOOL ??? +MR_X = -12 ; current x-coordinate. +MR_LARGE_SKIP_LIMIT = -14 ; At or beyond here, don't try to do large skip. +MR_WAS_X = -16 ; x-coordinate where op's data started. +mLOCALS = 16 ; Total local space to save. + + push bp + mov bp,sp + sub sp,mLOCALS + push si + push di + push es + + IF 0 ; debugging + mov _TotBytes,0 + ENDIF +; --- Simplify "incompressible" checking. We don't care if we are +; slightly over-conservative. 7 allows 3B for long skip, 4B for any +; other op. This allows us to not check at all on a short skip +; (a >4B series of short skips would never be done -- long skip done instead), +; and to check run or dump overhead without subtracting the size of the +; overhead. + sub word ptr MR_DST_LIMIT[bp],7 + + +; --- Simplify check of limit for "large skip" code. The limit is determined +; by the need to have CLIP_X see the transition to the final scan row. + mov dx,MR_FINAL_ROW_ADDR[bp] + sub dx,MR_SRC_WIDTH[bp] ; Paranoia -- a whole row before final. + sub dx,4 ; Make sure CLIP_X gets a chance. + mov MR_LARGE_SKIP_LIMIT[bp],dx + + +; --- Prepare far ptrs for "les di,...". + sub di,di ; SET src1. + mov ax,MR_SRC1_SEG[bp] + mov MR_SRC1_FAR+ADDR[bp],di + mov MR_SRC1_FAR+SEGM[bp],ax + mov di,MR_DST_ADDR[bp] ; SET dst. SET DI:dstAddr. + mov ax,MR_DST_SEG[bp] + mov MR_DST_FAR+ADDR[bp],di + mov MR_DST_FAR+SEGM[bp],ax + +; --- ASSUME srcs start at Addr=0. + sub si,si ; SET (DS:SI):src2. + push ds ; Save DS:DGROUP. + mov ds,MR_SRC2_SEG[bp] ; SET DS:dstSeg. NOT DGROUP. +; --- DGROUP NOT ACCESSIBLE VIA DS BELOW. USE SS IF NEED DGROUP. --- + + les di,MR_DST_FAR[bp] ; SET ES:DI:dst. + mov ax,BMBODY_RUNSKIPDUMP + stosw ; *(UWORD far *)dst++ = + ; 2-byte header containing type. + mov MR_DST_FAR+ADDR[bp],di ; Save dstAddr, so DI can be re-used. + + les di,MR_SRC1_FAR[bp] ; *** SET ES:DI:src1 for loops *** + + sub dx,dx ; 0. + mov MR_X[bp],dx ; "x=0;" + mov MR_MUST_STOP[bp],dl ; "mustStop = FALSE;" + +notInASequence: + sub cx,cx ; CX:wordCnt=0. + +; ----------------------- Dump ------------------------------------------- +; ASSUME ES:DI: src1. +; "pixel" must be set when jump to beDump with "wordCnt != 0". +beDump: + mov dx,MR_X[bp] ; + sub dx,cx ; CX:wordCnt. + jge Dxw + add dx,MR_SRC_WIDTH[bp] ; started on previous line +Dxw: mov MR_WAS_X[bp],dx + + sub bx,bx ; SET BL:skipInDump=0, BH:runInDump=0. + or cx,cx ; test CX:wordCnt. + jz DnoCnt + inc bh ; BH:runInDump. Any pixel is run==1. +DnoCnt: +inDump: + mov dx,MR_X[bp] + cmp dx,MR_SRC_WIDTH[bp] + jne DnoClip + call ClipX ; "CLIP_X(stopDump);" + jnz stopDump +DnoClip: + + mov ah,al ; AH,AL: "runPix = pixel;" + lodsb ; "pixel = *src2++;" Get&count byte + inc word ptr MR_X[bp] ; "x++;" + inc cx ; CX: "wordCnt++;" + + cmp al,es:[di] ; AL:pixel. ES:DI:src1. + je DSkip ; "if (pixel != *src1)" + mov bl,0ffh ; "-1" & inc below => "skipInDump=0" +DSkip: + inc bl ; BL: "skipInDump++;" + inc di ; DI: "src1++;" + + cmp al,ah ; "if (pixel != runPix)" + je DRun + sub bh,bh ; "0" & inc below => "runInDump=1" + ; Any pixel is a run of 1. +DRun: + inc bh ; BH: "runInDump++;" + + cmp bl,MIN_SKIP ; "if (skipInDump == MIN_SKIP" + jne DnoSkip + test byte ptr MR_SKIP_PERMITTED[bp],1 ; " && skipPermitted)" + jz DnoSkip +; --- "PUT_DUMP(src2-wordCnt, wordCnt-MIN_SKIP);" + push bx + push cx + mov bx,si ; SET BX:param1. SI:src2Addr. + sub bx,cx ; CX:wordCnt. + sub cx,MIN_SKIP ; SET CX:param2 = CX:wordCnt-MIN_SKIP. + call PutDump + pop cx + pop bx + + mov cx,MIN_SKIP ; CX:wordCnt. + jmp beSkip +DnoSkip: + + cmp bh,MIN_RUN ; "if (runInDump == MIN_RUN)" + jne noRID +; --- "PUT_DUMP(src2-wordCnt, wordCnt-MIN_RUN);" + push bx + push cx + mov bx,si ; SET BX:param1. SI:src2Addr. + sub bx,cx ; CX:wordCnt. + sub cx,MIN_RUN ; SET CX:param2 = CX:wordCnt-MIN_RUN. + call PutDump + pop cx + pop bx + + mov cx,MIN_RUN ; CX:wordCnt. + jmp short beRun +noRID: + +; --- Byte still in Dump. + cmp cx,MAX_LONG_DUMP ; "if (wordCnt == MAX_LONG_DUMP)" + jne inDump +stopDump: +; --- "PUT_DUMP(src2-wordCnt, wordCnt);" + push bx + push cx + mov bx,si ; SET BX:param1. SI:src2Addr. + sub bx,cx ; CX:wordCnt. + ; ; SET CX:param2 = CX:wordCnt. + call PutDump + pop cx + pop bx + + test byte ptr MR_MUST_STOP[bp],1 + jnz Dstop + jmp notInASequence +Dstop: jmp beStop + + +; ----------------------- Run ------------------------------------------- +; ASSUME ES:DI: src1. +beRun: + mov dx,MR_X[bp] ; + sub dx,cx ; CX:wordCnt. + jge Rxw + add dx,MR_SRC_WIDTH[bp] ; started on previous line +Rxw: mov MR_WAS_X[bp],dx + + sub bx,bx ; SET BL:skipInDump=0. + mov ah,al ; "runPix = pixel;" +inRun: + mov dx,MR_X[bp] + cmp dx,MR_SRC_WIDTH[bp] + jne RnoClip + call ClipX ; "CLIP_X(stopRun);" + jnz stopRun +RnoClip: + + lodsb ; "pixel = *src2++;" Get&count byte + inc word ptr MR_X[bp] ; "x++;" + inc cx ; CX: "wordCnt++;" + + cmp al,es:[di] ; AL:pixel. ES:DI:src1. + je RSkip ; "if (pixel != *src1)" + mov bl,0ffh ; "-1" & inc below => "skipInDump=0" +RSkip: + inc bl ; BL: "skipInDump++;" + inc di ; DI: "src1++;" + +; Note: check for byte runnable comes later. + + cmp bl,MIN_RUN_SKIP ; "if (skipInDump == MIN_RUN_SKIP" + jne RnoSkip + test byte ptr MR_SKIP_PERMITTED[bp],1 ; " && skipPermitted)" + jz RnoSkip + sub cx,MIN_RUN_SKIP ; retract skip bytes from wordCnt. +; --- "PUT_RUN(wordCnt, runPix);" + call PutRun ; CX:wordCnt, AH:runPix. Must Preserve. + + mov cx,MIN_RUN_SKIP ; CX:wordCnt. + jmp short beSkip +RnoSkip: + + cmp al,ah ; "if (pixel != runPix)" + je Rrun + dec cx ; Retract pixel from Run. +; --- "PUT_RUN(wordCnt, runPix);" + call PutRun ; CX:wordCnt, AH:runPix. Must Preserve. + + mov cx,1 ; CX:wordCnt. + jmp beDump + +; --- Byte runnable. +Rrun: + cmp cx,MAX_LONG_RUN ; "if (wordCnt == MAX_LONG_RUN)" + jne inRun +stopRun: +; --- "PUT_RUN(wordCnt, runPix);" + call PutRun ; CX:wordCnt, AH:runPix. Must Preserve. + + test byte ptr MR_MUST_STOP[bp],1 + jnz Dstop ; ("jmp beStop" was out of range.) + jmp notInASequence + + +; ----------------------- Skip ------------------------------------------- +beSkip: + +; ---------------- Attempt to quickly skip a long ways forward. + mov dx,MR_LARGE_SKIP_LIMIT[bp] + sub dx,si + jb inSkip0 ; Too close to end. + + push cx ; Hold CX:wordCnt. + mov cx,dx ; Permit skip up to skipLimit. + shr cx,1 ; As # words. + mov dx,cx ; SET DX: # words to cnt down. + jcxz skippedAll + repe cmpsw + + je skippedAll ; last words eql; cnt stopped us. + sub si,2 ; Retract the non-matching word. + sub di,2 + inc cx +skippedAll: + sub dx,cx ; # skip words found. + shl dx,1 ; # skip bytes found. + + pop cx ; Restore CX:wordCnt. + add cx,dx ; wordCnt now reflects new skip bytes. + add dx,MR_X[bp] ; x += bytes found, mod width. +SmodX: sub dx,MR_SRC_WIDTH[bp] ; force it to underflow. + jnb SmodX + add dx,MR_SRC_WIDTH[bp] ; compensate for underflow. +SxOk: mov MR_X[bp],dx +; ---------------- + jmp short inSkip + + +; --- Byte skippable. Final Skip is NOT output prior to Stop. +skippable: + inc di ; DI: "src1++;" + +inSkip0: + mov dx,MR_X[bp] + cmp dx,MR_SRC_WIDTH[bp] + je Sclip +; --- fall through to "inSkip". + +inSkip: + lodsb ; "pixel = *src2++;" Get&count byte + inc word ptr MR_X[bp] ; "x++;" + inc cx ; CX: "wordCnt++;" + + cmp al,es:[di] ; AL:pixel. ES:DI:src1. + je skippable ; "if (pixel != *src1)" +; --- Byte not skippable. Put the Skip. *** AX:temporary.*** +; NOTE: Subtracted enough from dstLimit, that we're not bothering to +; check for incompressible (destination buffer overflow) on short skips. + inc di ; DI: "src1++;" + push ax ; Hold AX. "jmp SOutDone" for POP.*** +; IF CHANGE # regs pushed, must change SOutDone & Sincompressible. + + mov MR_SRC1_FAR+ADDR[bp],di ; Update src1Addr from DI. + les di,MR_DST_FAR[bp] ; SET ES:DI:dst. + + dec cx ; "wordCnt--;" Retract pixel. + IF 0 + call DumpPutSkip + ENDIF + cmp cx,MAX_SHORT_SKIP + ja SnotShort +; --- One Short Skip. + mov al,OP_SKIP ; "*dst++ = OP_SKIP | wordCnt;" + or al,cl + stosb + jmp short SOutDone + +SnotShort: + cmp cx,2*MAX_SHORT_SKIP + ja Slong +; --- Two Short Skips. + mov al,OP_SKIP ; "*dst++ = OP_SKIP | MAX_SHORT_SKIP;" + or al,MAX_SHORT_SKIP + stosb + sub cx,MAX_SHORT_SKIP ; "wordCnt-= MAX_SHORT_SKIP;" + mov al,OP_SKIP ; "*dst++ = OP_SKIP | wordCnt;" + or al,cl + stosb + jmp short SOutDone +Slong: + mov dx,cx ; SET DX:wordCnt0 = wordCnt. +Slong0: mov cx,dx ; "while (wordCnt0) {..." + jcxz SOutDone + cmp di,MR_DST_LIMIT[bp] ; Check for incompressible. + ja Sincompressible + cmp cx,MAX_LONG_SKIP ; "wordCnt = MIN(wordCnt0,MAX_LONG_SKIP);" + jbe Sfits + mov cx,MAX_LONG_SKIP +Sfits: sub dx,cx ; "wordCnt0 -= wordCnt;" + mov al,LONG_OP ; "*dst++ = LONG_OP;" + stosb + mov ax,cx ; "*((UWORD far *)dst++ = wordCnt;" + stosw + jmp short Slong0 + +SOutDone: + mov MR_DST_FAR+ADDR[bp],di ; Update dstAddr. + les di,MR_SRC1_FAR[bp] ; SET ES:DI:src1. + pop ax ; Restore AX. *** + mov cx,1 ; CX:wordCnt. + jmp beDump + +Sclip: call ClipX ; "CLIP_X(beStop);" + jnz beStop + jmp short inSkip ; Skip may be any length up to 64KB-1. + +Sincompressible: + pop ax ; Match "push ax". + jmp incompressible + +; ----------------------- Stop ------------------------------------------- +beStop: + mov MR_SRC1_FAR+ADDR[bp],di ; Update src1Addr from DI. + les di,MR_DST_FAR[bp] ; SET ES:DI:dst. + cmp di,MR_DST_LIMIT[bp] ; Check for incompressible. + ja incompressible + mov al,LONG_OP ; "*dst++ = LONG_OP;" + stosb ; Stop is "LongOp #0". + sub ax,ax ; 0. + stosw ; "*(UWORD far *)dst++ = 0;" + + mov ax,di ; "*nBytesP = dst - dst0;" + sub ax,MR_DST_ADDR[bp] + mov bx,MR_N_BYTES_PTR[bp] + mov ss:[bx],ax ; ASSUME SS=DGROUP. + + mov ax,1 ; RETURN TRUE. + jmp short done + +; --- Body could not be compressed into given buffer size. +; Consider it incompressible. (Actually, client may have given a small +; buffer, and may wish to re-try with a larger buffer.) +incompressible: + sub ax,ax ; RETURN FALSE. +done: + pop ds ; Restore DS: DGROUP. + + pop es + pop di + pop si + mov sp,bp + pop bp + ret ; FAR back to client. + + +; ------ CLIP_X() ----------------------------------------------------------- +; No parameters, returns flags according to "test inFinalRow". +; DX: -- temporary. ASSUME caller allows destruction. +; NOTE: moved per-pixel test into each caller, to save time per pixel. +; Therefore, must already know at line end when call ClipX. +ClipX: mov word ptr MR_X[bp],0 + test byte ptr MR_IN_FINAL_ROW[bp],1 + jz notDone + mov byte ptr MR_MUST_STOP[bp],1 + IF 0 + call DumpFinal + ENDIF + mov dx,1 + or dx,dx ; clear zero flag. + retn ; NEAR. +notDone: cmp si,MR_FINAL_ROW_ADDR[bp] ; "if (src2Addr == finalRowAddr)" + jne notStartingLastLine + mov dx,MR_FINAL_ROW_WIDTH[bp] ; "w = finalRowWidth;" + mov MR_SRC_WIDTH[bp],dx + mov byte ptr MR_IN_FINAL_ROW[bp],1 ; "inFinalRow = TRUE;" +notStartingLastLine: + IF 0 + call DumpClipX + ENDIF + sub dx,dx ; set zero flag. + retn ; NEAR. + + +; ------ Assembly level routines, with same registers & BP as above, except: +; AX: -- temporary. Each routine must SAVE/RESTORE. +; DX: -- temporary. ASSUME caller allows destruction. +; REMEMBER, DS:src2Seg, NOT DGROUP. +; REMEMBER, ES:DI: src1. DI must be updated to MR_SRC1_FAR+ADDR[bp], if +; need to use it for dst. + + +; ------ PutRun(CX:wordCnt, AH:runPix) -------------------------------------- +; Must Preserve all registers, including parameters. +PutRun: + jcxz noRun + IF 0 + call DumpPutRun + ENDIF + push ax ; Hold AX. Last, so can access runPix. +; IF CHANGE # regs pushed, must change PutRun & PutDump & Rincompressible. + + mov MR_SRC1_FAR+ADDR[bp],di ; Update src1Addr from DI. + les di,MR_DST_FAR[bp] ; SET ES:DI:dst. + cmp di,MR_DST_LIMIT[bp] ; Check for incompressible. + ja Rincompressible + cmp cx,MAX_SHORT_RUN ; + ja lRun ; "wordCnt > MAX_SHORT_RUN" + mov ax,MR_WAS_X[bp] + add ax,cx + cmp ax,MR_SRC_WIDTH[bp] + ja lRun ; "CROSSED_W(wordCnt)" + mov al,OP_RUN ; "*dst++ = OP_RUN;" + stosb + mov al,cl ; "*dst++ = wordCnt;" + stosb + jmp short rBody +lRun: ; longRun op. + mov al,LONG_OP ; "*dst++ = LONG_OP;" + stosb + mov ax,cx ; "*((UWORD far *)dst++ = " + or ah,LONG_RUN ; " (LONG_RUN<<8) | wordCnt);" + stosw +rBody: + pop ax ; ACCESS AH:runPix. + push ax + mov al,ah + stosb ; "*dst++ = runPix;" + + mov MR_DST_FAR+ADDR[bp],di ; Update dstAddr. + les di,MR_SRC1_FAR[bp] ; SET ES:DI:src1. + + pop ax ; Restore AX. +noRun: retn ; NEAR. + +Dincompressible: + ; NOTE: since we're throwing everything away, doesn't matter that + ; bx & cx aren't the top two items at this point. + pop ax ; Balance CALLER'S PUSH BX & CX. + pop ax +Rincompressible: + pop ax ; Balances "push ax". + pop ax ; Remove (near) return address. + jmp short incompressible + +; --- PutDump(DS:BX:body, CX:cnt). +; BX: param1. ASSUME caller allows destruction. +; CX: param2. ASSUME caller allows destruction. +; Dump's data is at "body" -- a sequence of pixels in src2seg. +; ALL CALLER'S MUST PUSH BX & CX, AND ONLY those registers, so that +; "Dincompressible" will pop correct #words. +PutDump: + jcxz noDump ; No data to dump. + IF 0 + call DumpPutDump + ENDIF + push ax ; Hold AX. +; IF CHANGE # regs pushed, must change PutRun & PutDump & Rincompressible. + + mov MR_SRC1_FAR+ADDR[bp],di ; Update src1Addr from DI. + les di,MR_DST_FAR[bp] ; SET ES:DI:dst. + + mov dx,MR_DST_LIMIT[bp] ; Check for incompressible. + sub dx,cx + jb Dincompressible ; (underflow -- "dstLimit < wordCnt") + cmp di,dx + ja Dincompressible ; "dstAddr > dstLimit-wordCnt" + ; "Rinc..." because "incompressible" was out of range. + ; It must be same condition test ("ja")! + + cmp cx,MAX_SHORT_DUMP ; + ja lDump ; "cnt > MAX_SHORT_DUMP" + mov ax,MR_WAS_X[bp] + add ax,cx + cmp ax,MR_SRC_WIDTH[bp] + ja lDump ; "CROSSED_W(cnt)" + mov al,OP_DUMP ; "*dst++ = OP_DUMP | cnt;" + add al,cl + stosb + jmp short dBody +lDump: ; longDump op. + mov al,LONG_OP ; "*dst++ = LONG_OP;" + stosb + mov ax,cx ; "*((UWORD far *)dst++ = " + or ah,LONG_DUMP ; " (LONG_DUMP<<8) | cnt);" + stosw +dBody: + xchg bx,si ; Hold SI:src2. SET BX:body. + rep movsb ; DS:SI:body, ES:DI:dst, CX:cnt. + ; Note: dst is ++ past the new data. + xchg bx,si ; Restore SI:src2. + + mov MR_DST_FAR+ADDR[bp],di ; Update dstAddr. + les di,MR_SRC1_FAR[bp] ; SET ES:DI:src1. + pop ax ; Restore AX. +noDump: retn ; NEAR. + + IF 0 ; debugging +DumpPutRun: + push ds + push es + push ax + push bx + push cx + push dx + mov al,ah + sub ah,ah + push ax + push cx + mov ax,ss + mov ds,ax + mov es,ax + lea ax,DGROUP:runMsg + push ax + test _doDump,0ffh + jz noR + add _TotBytes,cx + call _printf +noR: + add sp,6 + pop dx + pop cx + pop bx + pop ax + pop es + pop ds + retn + +DumpPutDump: + push ds + push es + push ax + push bx + push cx + push dx + push cx + mov ax,ss + mov ds,ax + mov es,ax + lea ax,DGROUP:dumpMsg + push ax + test _doDump,0ffh + jz noD + add _TotBytes,cx + call _printf +noD: + add sp,4 + pop dx + pop cx + pop bx + pop ax + pop es + pop ds + retn + +DumpPutSkip: + push ds + push es + push ax + push bx + push cx + push dx + push cx + mov ax,ss + mov ds,ax + mov es,ax + lea ax,DGROUP:skipMsg + push ax + test _doDump,0ffh + jz noS + add _TotBytes,cx + call _printf +noS: + add sp,4 + pop dx + pop cx + pop bx + pop ax + pop es + pop ds + retn + +DumpClipX: + push ds + push es + push ax + push bx + push cx + push dx + mov ax,ss + mov ds,ax + mov es,ax + push di ; dest + lea ax,DGROUP:clipMsg + push ax + test _doDump,0ffh + jz noC + call _printf +noC: + add sp,4 + pop dx + pop cx + pop bx + pop ax + pop es + pop ds + retn + +DumpFinal: + push ds + push es + push ax + push bx + push cx + push dx + mov ax,ss + mov ds,ax + mov es,ax + mov ax,MR_FINAL_ROW_WIDTH[bp] + push ax + push di ; dest + lea ax,DGROUP:finalMsg + push ax + test _doDump,0ffh + jz noF + call _printf +noF: + add sp,6 + pop dx + pop cx + pop bx + pop ax + pop es + pop ds + retn + ENDIF ; Debugging + ENDPROC _MakeRunSkipDump + ENDIF ; RunSkipDump format. + + + IF 0 ; simple dump format. +;----------------------------------------------------------------- +; void AsmPlayDelta(UWORD picSeg, deltaSeg, deltaAddr, deltaBytes); +; Finishes playing the current delta-encoding format. +;----------------------------------------------------------------- + + public _AsmPlayDelta + STARTPROC _AsmPlayDelta + +APD_PIC_SEG = ARGB +APD_DELTA_SEG = ARGB+2 +APD_DELTA_ADDR = ARGB+4 +APD_DELTA_BYTES = ARGB+6 + + push bp + mov bp,sp + push si + push di + push es + + mov si,APD_DELTA_ADDR[bp] + mov dx,APD_DELTA_BYTES[bp] + mov es,APD_PIC_SEG[bp] + + push ds ; Save DS:DGROUP. + mov ds,APD_DELTA_SEG[bp] ; SET DS:deltaSeg. NOT DGROUP. + + jmp short more ; In case no data. + +runLoop: + lodsw + mov di,ax ; SET DI:picAddr + lodsw + mov cx,ax ; SET CX:runCount + rep movsb ; far_movmem + +more: cmp si,dx ; while (deltaAddr < deltaBytes) + jb runLoop + + pop ds ; Restore DS:DGROUP. + + pop es + pop di + pop si + pop bp + ret + + ENDPROC _AsmPlayDelta + + +;----------------------------------------------------------------- +; UWORD MakeDeltaSequence(UWORD picSeg, prevSeg, minAddr, maxAddr, +; deltaSeg, deltaAddr, limitAddr); +; +; Given a sequence of bytes in the same position in two images, +; create a delta-description to convert one image to the other. +; +; Puts the delta at (deltaSeg,deltaAddr). +; RETURNS "deltaBytes" -- # bytes to describe the delta, INCLUDING +; the initial "deltaAddr" value. +; "limitAddr" is offset into deltaSeg that may not be overwritten. +; RETURNS "-1" if doesn't fit. +;----------------------------------------------------------------- + +DOESNT_FIT = -1 + +O_PIC_SEG = ARGB +O_PREV_SEG = ARGB+2 +O_MIN_ADDR = ARGB+4 +O_MAX_ADDR = ARGB+6 +O_DELTA_SEG = ARGB+8 +O_DELTA_ADDR = ARGB+10 +O_LIMIT_ADDR = ARGB+12 + + public _MakeDeltaSequence + STARTPROC _MakeDeltaSequence + + push bp + mov bp,sp + push si + push di + push es + + mov si,O_MIN_ADDR[bp] ; SET SI:picAddr = minAddr. + mov es,O_PREV_SEG[bp] ; SET ES:prevSeg + mov dx,O_DELTA_SEG[bp] ; SET DX:deltaSeg + mov di,O_DELTA_ADDR[bp] ; SET DI:deltaAddr + + push ds ; Save DS:DGROUP. + mov ds,O_PIC_SEG[bp] ; SET DS:picSeg. NOT DGROUP. + +; --- Not in a run. Look for differences. + sub cx,cx ; SET CX:runCount. + sub bx,bx ; SET BX:gapSize. + jmp short growGap0 + +gapStarted: +growGap: + inc bx ; BX:gapSize. + inc si +growGap0: + cmp si,O_MAX_ADDR[bp] + ja endWhileInGap + +; --- Cmp pic byte to prev byte. + mov al,es:[si] ; ES:prevSeg, SI:picAddr + cmp al,[si] ; DS:picSeg, SI:picAddr + je growGap + +; --- A run is starting. Determine whether to append to previous run, +; or to output previous run. + jcxz noPreviousRun ; So won't append initial gap to + ; non-existent run. + + cmp bx,4 ; BX:gapSize + jb smallGap + +endWhileInGap: + jcxz done ; NO RUN EVER FOUND. +; --- Output previous run. --- + + mov ax,di ; Test whether would reach limitAddr. + add ax,4 ; Run's addr & count. + add ax,cx ; runCount. + cmp ax,O_LIMIT_ADDR[bp] + jb fits + mov ax,DOESNT_FIT ; RETURN "DOESNT_FIT". + jmp short fail + +fits: + mov ax,es + xchg ax,dx + mov es,ax ; SET ES:deltaSeg, DX:prevSeg + + sub si,bx ; Move back past gap. + sub si,cx ; SET SI:runAddr = picAddr - runCount + mov ax,si ; *(WORD)(deltaSeg,deltaAddr)= runAddr, + stosw ; deltaAddr += 2. + mov ax,cx ; *(WORD)(deltaSeg,deltaAddr)= runCount, + stosw ; deltaAddr += 2. + rep movsb ; far_movmem picSeg|Addr => deltaSeg|Addr, + ; runCount bytes. When done, SI:picAddr set past run, + ; CX:runCount = 0. + add si,bx ; Move forward over gap. + mov ax,es + xchg ax,dx + mov es,ax ; SET ES:prevSeg, DX:deltaSeg + + cmp si,O_MAX_ADDR[bp] ; Extra check saved a few code bytes. + ja done + + jmp short gapConsumed + +smallGap: + add cx,bx ; Append gap to run. +; jmp short gapConsumed + +noPreviousRun: +gapConsumed: + sub bx,bx ; SET BX:gapSize + +; --- When reach here, have already found one byte of run. +; ASSUME SI:picAddr still pointing at byte, CX:runCount already is zero. + +continueRun: + inc si ; Move SI:picAddr past byte of run. + inc cx ; CX:runCount. + cmp si,O_MAX_ADDR[bp] + ja endWhileInRun + + mov al,es:[si] ; ES:prevSeg, SI:picAddr + cmp al,[si] ; DS:picSeg, SI:picAddr + jne continueRun +endWhileInRun: + jmp short gapStarted ; SI points to first byte of gap. + ; BX:gapSize = 0. + +done: + mov ax,di ; RETURN deltaBytes = DI:deltaAddr. +fail: + pop ds ; Restore DS:DGROUP. + + pop es + pop di + pop si + pop bp + ret + + ENDPROC _MakeDeltaSequence + ENDIF ; simple dump format. + + ENDPS anima + end diff --git a/tools/old/anm/ANIMFILE.TXT b/tools/old/anm/ANIMFILE.TXT new file mode 100644 index 000000000..a8d2b9308 --- /dev/null +++ b/tools/old/anm/ANIMFILE.TXT @@ -0,0 +1,138 @@ +DeluxePaint Animation ".ANM" files consist of a large header and a series of +structures that can be up to 64 KB long each. The programmer refers to these +structures as "Large Pages". Large Pages are a format for dividing a file +into 64 KB chunks that can be stored out-of-sequence in the file. That is, +a large page can be logically inserted into the file, without having to move +all the following data out of the way. + +Each large page holds one or more "records". A record represents one frame +of the original animation. A record is of any length from 0 to almost 64 KB. +The records in a large page are sequential. However, the first large page +may not contain the first frames of the anim file. Each large page contains +a sequential set of records but the large pages themselves are not in +sequential order. It is possible for the first large page in a file to +contain the last few frames of the animation. When you process the anim file +you must scan the large page structures to find which large page conatins the +frame you wish to display or process next. + +A DeluxePaint Animation "ANM" ("Anim") file is built on this mechanism, +so that as frames change in size, they can be maintained with a minimum +of extra file i/o, yet without loss of playback performance. +In addition, there is an optional special record which is the delta from +the last frame to the first frame, for smooth playback of looping anims. + +The following is the structure of a DeluxeAnimate anim file header. +Header size is exactly 2816 bytes. The first large page structure can be +reached by simply seeking to this location in the file. + + ULONG id; 4 character ID == "LPF " + + UWORD maxLps; max # largePages allowed. 256 FOR NOW. + + UWORD nLps; # largePages in this file. + + ULONG nRecords; # records in this file. 65534 is current limit plus + one for last-to-first delta for looping the animation + + UWORD maxRecsPerLp; # records permitted in an lp. 256 FOR NOW. + + UWORD lpfTableOffset; Absolute Seek position of lpfTable. 1280 FOR NOW. + The lpf Table is an array of 256 large page structures + that is used to facilitate finding records in an anim + file without having to seek through all of the Large + Pages to find which one a specific record lives in. + + ULONG contentType; 4 character ID == "ANIM" + + UWORD width; Width of screen in pixels. + UWORD height; Height of screen in pixels. + UBYTE variant; 0==ANIM. + UBYTE version; 0==frame rate is multiple of 18 cycles/sec. + 1==frame rate is multiple of 70 cycles/sec. + + UBYTE hasLastDelta; 1==Last record is a delta from last-to-first frame. + + UBYTE lastDeltaValid; 0==The last-to-first delta (if present) hasn't been + updated to match the current first&last frames, so it + should be ignored. + + UBYTE pixelType; 0==256 color. + + UBYTE CompressionType; 1==(RunSkipDump) Only one used FOR NOW. + + UBYTE otherRecsPerFrm; 0 FOR NOW. + + UBYTE bitmaptype; 1==320x200, 256-color. Only one implemented so far. + + UBYTE recordTypes[32]; Not yet implemented. + + ULONG nFrames; In case future version adds other records at end of + file, we still know how many actual frames. + NOTE: DOES include last-to-first delta when present. + + UWORD framesPerSecond; Number of frames to play per second. + + UWORD pad2[29]; 58 bytes of filler to round up to 128 bytes total. + + Range cycles[16]; Color cycling info (128 bytes long). + This is the format of a cycle structure. + typedef struct { + WORD count; + WORD rate; + WORD flags; + UBYTE low, high; /* bounds of range */ + } Range; + + + total is = 256 bytes. + + Following the anim file header is the color palette + + ULONG palette[256] Color palette arranged as 3 bytes each of Red Green + & Blue and one unused byte. + + Following the palette is an array of structures that are copies of the + large page headers. This array is loaded and used to find which large page + a given frame can be found in. + + Large_page LParay[256] Copies of all the Large Page structures in the anim + file. Each Large Page structure is 6 bytes long so + the total length of this table is 1536 bytes. Even if + the file only contains 1 large page there are still + 256 entries of 6 bytes each. + + The Large Pages follow the LParray and are in the sequence dictated by + their order of occurence in the LParray in the anim file header. + + The following is the structure of a single Large Page in an anim file. Each + Large Page is exactly 64k long in the anim file. The only exception is the + last large page wich is truncated to be only as long as necessary. + + UWORD baseRecord; Number of first record in this large page. + + UWORD nRecords; Number of records in lp. + bit 15 of "nRecords" == "has continuation from previous lp". + bit 14 of "nRecords" == "final record continues on next lp". + + UWORD nBytes; Total number of bytes of contents, excluding header. + + UWORD BytesContinued; The number of bytes of the last record of the + previous large page that extend into this large page. + This was never implemented and is always 0. + + UWORD RecordSizes[nRecords] Array of lengths of each record in the large page. + + The actual records start here. Each record has a variable length header that + is like the following structure. + + typedef struct{ + UBYTE IDnum; always 66 + UBYTE Flags; 0==no extra bytes field next + + UWORD extrabytes; if Flags is non zero this is # of bytes + to skip before compressed data starts + extrabytes does not include the size + of the 2 previous bytes. Also make + sure you round the final address up to + an even byte boundry. + } record_header; diff --git a/tools/old/anm/ANIMIO.C b/tools/old/anm/ANIMIO.C new file mode 100644 index 000000000..388457507 --- /dev/null +++ b/tools/old/anm/ANIMIO.C @@ -0,0 +1,530 @@ +/*----------------------------------------------------------------------*/ +/* */ +/* animio.c - Page-flip animation-- file io code. */ +/* */ +/*----------------------------------------------------------------------*/ + + +#include "main.h" +#include "anim.h" /* FIRST_FRAME_N */ +#include "dpiff.h" +#include "dialogmg.h" /* for LIST definition */ +#include "string.h" +#include +#include + +extern SHORT curDepth; +extern UWORD *ytable; +extern BITMAP hidbm; +extern AnimOb curAnimBr; +extern SHORT curfps, nPages, curPage; +extern animProcHandle *animOps; + +#define local static + +BOOL isAnimBrIO = NO; + +#if 0 +SHORT saveFrameNum; +SHORT saveStart, nSave, loadStart = 0; + +#endif + +typedef struct IntuiMessage IMsg; + + +DPAnimChunk dpAnimChnk; + +#if 0 +#define AnimOp(N) (*animOps[N])() +#endif + +FreeDelta(register Delta * del) +{ + register int p; + + for (p = 0; p < curDepth; p++) { + FP_SEG(del->plane[p]) = SFree(FP_SEG(del->plane[p])); + } +} + + +/*--------------------------------------------------------------*/ +/* Read In ANIM iff files */ +/*--------------------------------------------------------------*/ + + +#ifdef DBGDLTA +BOOL dbgdlta = YES; + +#endif + + +/*--------------------------------------------------------------*/ +/*- Read in a DPAN chunk -----------*/ +/*--------------------------------------------------------------*/ +IFFP GetDPAnimChunk(context) +GroupContext *context; +{ + IFFP iffp = IFFReadBytes( + context, (BYTE *) & dpAnimChnk, (LONG) sizeof(DPAnimChunk)); + + ByteFlipAnimChunk(&dpAnimChnk); +#ifdef DBGDLTA + if (dbgdlta) { + printf(" GetDPAnimChunk , vers = %d, nframes = %d, flags = %d \n", + dpAnimChnk.version, dpAnimChnk.nframes, dpAnimChnk.flags); + } +#endif + return (iffp); +} + + +/*--------------------------------------------------------------*/ +/*- Write out a DPAN chunk -----------*/ +/*--------------------------------------------------------------*/ +IFFP PutDPAN(context) +GroupContext *context; +{ + DPAnimChunk dpAnCh; + + setmem(&dpAnCh, sizeof(DPAnimChunk), 0); + dpAnCh.version = DPANIM_VERS3; + if (isAnimBrIO) { + dpAnCh.nframes = curAnimBr.nCels; + dpAnCh.duration = curAnimBr.duration; + dpAnCh.flags = curAnimBr.flags; + dpAnCh.rate = 0; + } +#if 0 /* Not supporting anims, just animbrushes. */ + else { + dpAnCh.nframes = nSave; + dpAnCh.rate = curfps; + } +#endif + ByteFlipAnimChunk(&dpAnCh); + return + PutCk(context, ID_DPAN, (LONG) sizeof(DPAnimChunk), (BYTE *) & dpAnCh); + /* NOTE: needn't flip back to IBM byte-order, since not using further. */ +} + +#if ANIMDISK +/*--------------------------------------------------------------*/ +/* Anim file IO */ +/*--------------------------------------------------------------*/ +typedef char FileName[FILENAME_LENGTH + 1]; +extern WORD curFrame; + +/*---------------------------------------------------------------*/ +/* Saving anim as separate ILBM's */ +/* */ +/* Assumes contains the desired file extension and that */ +/* 1 <= start <= animFrames, 1 <= end <= animFrames */ +/*---------------------------------------------------------------*/ +void SaveAnimAsILBMs(name, start, end) +char *name; +SHORT start, end; +{ + auto int i, len; + auto int nframes = end - start + 1; + FileName nm, bsname; + auto char nstr[SEQUENCE_SUFFIX_LENGTH], ext[FILENAME_SUFFIX_LENGTH + 2]; + auto struct stat filestat; + auto char *ptr; + auto BOOL overwrite = NO; + + /* seperate out the file extension, if any */ + strcpy(bsname, name); + ptr = strchr(bsname, '.'); + if (ptr) { + strncpy(ext, ptr, sizeof(ext)); + ext[sizeof(ext) - 1] = *ptr = '\0'; + } else + ext[0] = '\0'; + + len = strlen(bsname); + if (!len) { + NotAcceptableFileNameMsg(); + return; + } + if ((len + SEQUENCE_SUFFIX_LENGTH) > FILENAME_ROOT_LENGTH) { + BaseNameTooLongMsg(); + return; + } + AnimGoTo(start); + for (i = 0; i < nframes; i++) { + strcpy(nm, bsname); + num_to_string_zeroes(curFrame, nstr, SEQUENCE_SUFFIX_LENGTH); + strcat(nm, nstr); + strcat(nm, ext); + if (stat(nm, &filestat) != -1) { + if (filestat.st_mode & S_IFDIR) { + CantReplaceDirMsg(); + break; + } else if (!(filestat.st_mode & S_IWRITE)) { + FileIsWriteProtectedMsg(); + break; + } else if (!overwrite) { + if (!ReplaceSequence(nm)) + break; + else + overwrite = YES; + } + } + if (!save_picture0(nm)) + break; + AnimStepPage(1); + if (CheckAbort()) { + ClearAbortFlag(); + break; + } + } +} + +#endif /* ANIMDISK */ + + +/*--------------------------------------------------------------*/ +/* Loading ILBMs as Anim */ +/* tries to load a sequence of ilbm files (bname...bname+num-1) */ +/* as a new anim with frames. */ +/*--------------------------------------------------------------*/ +extern char **filename_strings; +extern char pict_dir[], dir_mark[]; + +LoadILBMsAsAnim(char *bname, SHORT num, BOOL insert, char *pictExtension) +{ + int i, starti, endi, off; + char *fname; + LIST list; + +#if 1 /* Prepare filenames */ + set_full_directory(pict_dir); + setmem(&list, sizeof(LIST), 0); + if (!AllocFilenameStrings()) + goto bail; + NewNames0(&list, pictExtension, FALSE); +#endif + + off = strlen(dir_mark); + starti = -1; + for (i = 0; i < list.num_items; i++) { + fname = filename_strings[i] + off; + if (strcmp(fname, bname) == 0) { + starti = i; + break; + } + } + if (starti == -1) + goto bail; + endi = starti + num - 1; + endi = MIN(endi, list.num_items - 1); + num = endi - starti + 1; + + if (insert) { + /* insert pages after curFrame */ + if (AddPages(num) == FAIL) + return; + AnimStepPage(1); /* go to first newly added frame */ + } else { + FreeStrings(&list); /* Make room for NewAnim/SaveAnim dialog. */ + FreeFilenameStrings(); + /* create a new untitled anim with the appropriate # of frames */ + if (NewAnim00(TRUE, num, TRUE) == FAIL) + return; /* couldn't create new anim or user aborted */ +#if 1 /* Prepare filenames */ + set_full_directory(pict_dir); + setmem(&list, sizeof(LIST), 0); + if (!AllocFilenameStrings()) + goto bail; + NewNames0(&list, pictExtension, FALSE); +#endif + } + + HideControls(); + ZZZCursor(); + for (i = starti; i <= endi; i++) { + fname = filename_strings[i]; + if (fname[0] == dir_mark[0]) { + DelPages(1); /* But suppose many pages left unfilled? */ + break; /* TBD: want to continue to find more + * dir's? */ + } + fname += off; + + if (!load_picture00(fname, TRUE, TRUE)) + break; + +#if comingSoon + ...remap picture(avoid doing on first picture, when getting + palette from first picture ?) + CopyPaletteFromFile(curpal, oldPaletteFileLetter); +#endif + + if (CheckAbort()) { + ClearAbortFlag(); + break; + } + AnimStepPage(1); + } + AnimGoTo(FIRST_FRAME_N); + UnZZZCursor(); + ShowControls(); +bail: + FreeStrings(&list); + FreeFilenameStrings(); +} + + +/* --------------- Set/Clear AnBrIO --------------- + */ +SetAnBrIO() +{ + isAnimBrIO = YES; +} + +ClearAnBrIO() +{ + isAnimBrIO = NO; +} + + +/*--------------------------------------------------------------*/ +/* Anim IFF IO routines */ +/*--------------------------------------------------------------*/ + +#if 0 +SHORT animLoadState; + +local void SetAnimLoadFail() +{ + animLoadState = FAIL; +} + +#endif /* 0 */ + + +#define IFF_MEMFAIL -10 + +IFFP AnimGetDLTA(context, bmHdr, animHdr, frameCnt, buffer, bufsize) +GroupContext *context; +BitMapHeader *bmHdr; +AnimHdr *animHdr; +SHORT frameCnt; +BYTE *buffer; +LONG bufsize; +{ + IFFP iffp; + BITMAP *tmp; + int res; + + if (isAnimBrIO) + return (GetAnBrDLTA(context, bmHdr, animHdr, frameCnt, buffer, bufsize)); +#if 1 + BugExit("AN1"); + /* "IFF format for Anim only implemented for brush so far"); */ +#else /* screen anim */ + if (frameCnt == 1) { + animLoadState = SUCCESS; + if (loadStart > 0) { +#if 0 /* TBD !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + if (AnimOp(ANIM_SAVECHGS) == FAIL) + return (IFF_MEMFAIL); +#endif + } else + AnimClearDirty(); + if (animHdr->interleave != 0 && animHdr->interleave != 2) { + NotValidAnimMsg(); +#if 0 /* TBD: Not moved over from Amiga. 1/30/90 */ + SkipErrorMsg(); /* tell dpio not to put another error req. + * up */ +#endif + return (BAD_FORM); + } +#if 0 /* TBD: Not moved over from Amiga. 1/30/90 */ + ShowLoadedPalette(); +#endif + } + if (CheckAbort()) { + ClearAbortFlag(); + return (IFF_DONE); + } + if (dpAnimChnk.version > DPANIM_VERS1) { + if (frameCnt >= dpAnimChnk.nframes) { + /* Skip remaining deltas: they are for circular play */ +#if 0 /* TBD: Not moved over from Amiga. 1/30/90 */ + /* TBD: Not an error !!!!!! */ + SkipErrorMsg(); /* tell dpio not to put an error req. up */ +#endif + return (IFF_DONE); + } + } +#if 0 /* TBD !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + res = (*animOps[ANIM_GETDLTA])(context, bmHdr, animHdr, frameCnt, buffer, bufsize); +#endif /* 0 */ + + return (res); +#endif /* screen anim */ +} + + +IFFP AnimPutDLTAs(context, buffer, bufsize) +GroupContext *context; +BYTE *buffer; +LONG bufsize; +{ + if (isAnimBrIO) + return (PutAnBrDLTAs(context, buffer, bufsize)); +#if 1 + else + return CLIENT_ERROR; /* Not ready to handle Anim yet. */ +#else + else + return ((*animOps[ANIM_PUTDLTAS])(context, buffer, bufsize)); +#endif /* 0 */ +} + + +#if 0 +IFFP AnimIFFDone() +{ + SHORT res = IFF_DONE; + + if (isAnimBrIO) + return (AnBrIFFDone()); + else { + if (dpAnimChnk.rate > 0) + SetRateFPS(dpAnimChnk.rate); + res = (*animOps[ANIM_IFF_DONE])(); + if (animLoadState == FAIL) + AnimLoadFailMsg(); + return (res); + } +} + +#endif /* 0 */ + + +#if 0 +/*------------------------------------------------------------*/ +/* assume the bitmap the delta applies to is in dbm: read the */ +/* Delta and apply it to dbm */ +/*------------------------------------------------------------*/ +IFFP ReadAndApplyDelta(context, bmHdr, animHdr, dbm, buffer, bufsize) +GroupContext *context; +BitMapHeader *bmHdr; +AnimHdr *animHdr; +BITMAP *dbm; +UBYTE *buffer; +ULONG bufsize; +{ + int i, op, bpr; + ULONG iffp = 0; + ULONG ploffs[16]; + ULONG planeSize[8], plast, plOffsSize; + SHORT depth = bmHdr->nPlanes; + + op = animHdr->operation; + if (op != ANIM_SHORTD && op != ANIM_RIFF && op != ANIM_RUNSKIP) { + NotValidAnimMsg(); + return (IFF_DONE); + } + plOffsSize = (op == ANIM_SHORTD ? 32 : 64); + + /*-------------------------------------------------------- + * NOTE: these ploffs are from the beginning of the chunk: + * the first one should have a value of 32 for short delta, 64 for riff, + * ?4? for ANIM_RUNSKIP. + */ + iffp = IFFReadBytes(context, (BYTE *) ploffs, plOffsSize); + CheckIFFP(); + +#ifdef DBGDLTA + if (dbgdlta) { + printf(" planeOffsets = "); + for (i = 0; i < 8; i++) + printf(" %d | ", ploffs[i]); + printf("\n"); + } +#endif + + /* Compute Size of the compressed planes */ + /* NOTE: ploffs[i] = 0 means no changes for that plane */ + + plast = ChunkMoreBytes(context) + plOffsSize; + setmem(planeSize, 8 * sizeof(LONG), 0); + for (i = depth - 1; i >= 0; i--) { + if (ploffs[i]) { + planeSize[i] = plast - ploffs[i]; + plast = ploffs[i]; + } + } +#ifdef DBGDLTA + if (dbgdlta) { + printf(" planeSize = "); + for (i = 0; i < 8; i++) + printf(" %d | ", planeSize[i]); + printf("\n"); + } +#endif + + + bpr = dbm->width; + for (i = 0; i < depth; i++) { + if (planeSize[i] != 0) { + /* FOR NOW, ONLY READ PLANE IF IT ALL FITS INTO BUFFER */ + if (planeSize[i] > bufsize) { +#ifdef DBGDLTA + InfoMessage("ReadAndApplyDLTA: plane too big", "for buffer"); /* ENGLISH */ +#endif + continue; + } + iffp = IFFReadBytes(context, buffer, planeSize[i]); + if (iffp != IFF_OKAY) { +#ifdef DBGDLTA + InfoMessage(" ReadBytes error", " in ReadAndApplyDLTA"); /* ENGLISH */ +#endif + return (iffp); + } + if (i < dbm->planes) + switch (op) { + case ANIM_SHORTD: + DecodeDLTA(dbm->seg[i], buffer); + break; + case ANIM_RIFF: + decode_vkplane(buffer, dbm->seg[i], bpr); + break; + } + } + } + return (IFF_OKAY); +} + +#endif /* 0 */ + + +#if 0 +/*--------------------------------------------------------------*/ +/* This Computes the RIFF delta between two bitmaps, abm and */ +/* bbm, and outputs it to the IFF stream */ +/*--------------------------------------------------------------*/ + +IFFP OutputRiffDelta(context, anhdr, abm, bbm, delbm) +GroupContext *context; +AnimHdr *anhdr; +BITMAP *abm, *bbm; /* two bitmaps to be compared */ +BITMAP *delbm; /* contains the resulting delta planes */ +{ + ULONG sizes[8]; + IFFP ifferror = 0; + int i; + SHORT bpr = abm->width; + + for (i = 0; i < abm->planes; i++) + sizes[i] = MkRIFF(abm->seg[i], bbm->seg[i], delbm->seg[i], + abm->Rows, bpr, bpr); + ifferror = WriteDelta(context, anhdr, delbm->seg, sizes); + return (ifferror); +} + +#endif /* 0 */ diff --git a/tools/old/anm/ASM.INC b/tools/old/anm/ASM.INC new file mode 100644 index 000000000..cf9a30f67 --- /dev/null +++ b/tools/old/anm/ASM.INC @@ -0,0 +1,151 @@ +;----------------------------------------------------------------- +; asm.inc +; ------- +; Standard macros for DPaint II MS-DOS ".asm" files. +;----------------------------------------------------------------- + +;----------------------------------------------------------------- +; Memory model configuration. +;----------------------------------------------------------------- + +LPROG equ 1 ; 1 means large (>64k) program segment +LDATA equ 0 ; 1 means large (>64k) data segment + +;----------------------------------------------------------------- +; After a standard procedure entry (push bp, mov bp,sp), the first +; parm on the stack can be accessed at ARGB[bp]. +;----------------------------------------------------------------- + + if LPROG +ARGB equ 6 + else +ARGB equ 4 + endif + +;----------------------------------------------------------------- +; File header: sets up groups, segment names, etc. +;----------------------------------------------------------------- + + if LPROG +HEADER macro module +module&_TEXT segment word public 'CODE' +module&_TEXT ends +_DATA segment word public 'DATA' +_DATA ends +CONST segment word public 'CONST' +CONST ends +_BSS segment word public 'BSS' +_BSS ends +DGROUP group CONST, _BSS, _DATA + assume cs:module&_TEXT, ds:DGROUP, ss:DGROUP, es:DGROUP + endm + else +HEADER macro +_TEXT segment word public 'CODE' +_TEXT ends +CONST segment word public 'CONST' +CONST ends +_BSS segment word public 'BSS' +_BSS ends +_DATA segment word public 'DATA' +_DATA ends +DGROUP group CONST, _BSS, _DATA + assume cs:_TEXT, ds:DGROUP, ss:DGROUP, es:DGROUP + endm + endif + +;----------------------------------------------------------------- +; Data segment start & end. +;----------------------------------------------------------------- + +DSEG macro +_DATA segment + endm + +;----------------------------------------------------------------- + +ENDDS macro +_DATA ends + endm + +;----------------------------------------------------------------- +; Program segment start & end. +;----------------------------------------------------------------- + + if LPROG +PSEG macro module +module&_TEXT segment + endm + else +PSEG macro +_TEXT segment + endm + endif + +;----------------------------------------------------------------- + + if LPROG +ENDPS macro module +module&_TEXT ends + endm + else +ENDPS macro module +_TEXT ends + endm + endif + +;----------------------------------------------------------------- +; Procedure start & end. +;----------------------------------------------------------------- + +STARTPROC macro proc_name + if LPROG +proc_name proc far + else +proc_name proc near + endif + endm + +;--- start a procedure and declare it public --- +STARTPROC_PUBLIC macro name + public name + if LPROG +name proc far + else +name proc near + endif + endm + +;----------------------------------------------------------------- + +ENDPROC macro proc_name +proc_name endp + endm + +;----------------------------------------------------------------- +; When the 80286 is in real mode, the POPF instruction may recognize +; a pending maskable interrupt even if interrupts were off before the +; corresponding PUSHF. This macro should be used instead of POPF. +; See "IBM Personal Computer Seminar Proceedings" v2, #4 (September '84) +; for info about the POPF bug. +;----------------------------------------------------------------- + +popflags macro + jmp $+3 ; jump around IRET + iret ; pop CS, IP, and flags + push cs + call $-2 ; call within segment + endm + +;----------------------------------------------------------------- +; Offsets to low byte & high byte of a word. +;----------------------------------------------------------------- +LO = 0 +HI = 1 + +;----------------------------------------------------------------- +; --- miscellaneous constants + +TRUE equ 1 +FALSE equ 0 + diff --git a/tools/old/anm/DALLOC.ASM b/tools/old/anm/DALLOC.ASM new file mode 100644 index 000000000..d0c7e609f --- /dev/null +++ b/tools/old/anm/DALLOC.ASM @@ -0,0 +1,101 @@ +;----------------------------------------------------------------- +; dalloc.asm +; ---------- +; Memory-allocation routines that operate OUTSIDE of the data segment. +; These work with SEGMENT addresses, NOT actual pointers. +; For allocation in the data segment, just use malloc () and free (). +;----------------------------------------------------------------- + + include asm.inc + + HEADER dalloc + + PSEG dalloc + +;----------------------------------------------------------------- +; WORD DAlloc (size); +; UWORD size; +; Allocate a block of "size" bytes and return its segment. If +; the allocation fails, return NULL. +; Since this uses DOS allocation, it will allocate just enough paragraphs +; for the number of bytes requested. +;----------------------------------------------------------------- + + public _DAlloc + STARTPROC _DAlloc + + push bp + mov bp,sp + + mov ah,048h ; function # + +; bx = number of paragraphs = (bytes >> 4) + (bytes & 0x0f) ? 1 : 0; + mov bx,ARGB[bp] + mov cl,4 + shr bx,cl + test word ptr ARGB[bp],0fh + je dalloc_p0 + inc bx +dalloc_p0: + + int 021h + jnc dalloc_p1 + xor ax,ax ; alloc failed, so return NULL +dalloc_p1: + + pop bp + ret + + ENDPROC _DAlloc + +;----------------------------------------------------------------- +; void SFree (seg); +; Was "DFree", but PLink said that conflicted with "dfree". +; Free the block at the given segment address. +; +; Okay to call with NULL, so safe to call on already freed segment +; variables. That DOESN'T mean it is okay to maintain two DIFFERENT +; segment variables, and try to free the same region twice through +; two different variables! Also, it is up to the caller to NULL +; his sgment variable when done. Maybe we should switch to a model +; where caller passes ADDRESS of segment variable! [sss] +; Always returns null, so can use to null a variable holding a +; segment address: +; "segname = SFree(segname);" +;----------------------------------------------------------------- + + public _SFree + STARTPROC _SFree + + push bp + mov bp,sp + push es + +; if (!seg), don't do anything + test word ptr ARGB[bp],0ffffh + jz dfree_done + +; free the segment + mov ah,049h + mov es,ARGB[bp] + int 021h +ifdef DEBUGGING + jnc dfree_1 + mov ax,9999 + push ax + call _crash +dfree_1: +endif + +dfree_done: + xor ax,ax ; NULL return value so can assign. + pop es + pop bp + ret + + ENDPROC _SFree + +;----------------------------------------------------------------- + + ENDPS dalloc + end diff --git a/tools/old/anm/EGA.INC b/tools/old/anm/EGA.INC new file mode 100644 index 000000000..f1c56a999 --- /dev/null +++ b/tools/old/anm/EGA.INC @@ -0,0 +1,42 @@ +;--------------------------------------------------------------------------- +; ega.mac +; This header file defines subroutines to do ega graphics from assembler. +;----------------------------------------------------------------- + +; EGA register equates + +TS_INDEX equ 3c4h ; Time Sequencer Index +TS_MASK equ 2 ; -- Map Mask (Enables CPU writes) +GDC_INDEX equ 3ceh ; Graphics Data Controller Index +GDC_MODE equ 5 ; -- Mode Register +GDC_RSEL equ 4 ; -- Read Map Select +CRTC_INDEX equ 3d4h ; CRT Controller Index +CRTC_OFFSET equ 13h ; -- Offset Register +CRTC_STARTH equ 0ch ; -- High Byte of Start Address +CRTC_STARTL equ 0dh ; -- Low Byte of Start Adrress +STATUS_REGISTER equ 3dah ; EGA status register +VSYNC_MASK equ 08h ; -- Vertical synch bit in status register + +;------------------------------------------------------------------------- +; SETREG macro to set internal register of chip with +; index register at to the value stored in AL +;----------------------------------------------------------------- + +; push dx +; mov dx,P1 +; mov ah,al +; mov al,P2 +; out dx,ax +; pop dx + +SETREG macro P1, P2 + push dx + mov dx,P1 + mov ah,al + mov al,P2 + out dx,al + mov al,ah + inc dx + out dx,al + pop dx + endm diff --git a/tools/old/anm/GIO.C b/tools/old/anm/GIO.C new file mode 100644 index 000000000..705722c6a --- /dev/null +++ b/tools/old/anm/GIO.C @@ -0,0 +1,197 @@ +/*--gio.c----------------------------------------------------------------- + * Buffered i/o. + */ + +#include "main.h" +#include +#include + +#define local static + +/* --- Segment of optional buffer for speeding-up i/o. */ +local UWORD ioBufferSeg = NULL; +local UWORD ioBufSize = 0, ioBufNext, ioBufLimit; +local BOOL ioWriting; + +/* ---------- OpenIOBuffer ---------- */ +void OpenIOBuffer(BOOL forWriting) +{ + register WORD bufSize; + auto WORD tempSeg; + + ioWriting = forWriting; + + /* --- Allocate i/o buffer. */ + if (ioBufferSeg == NULL) { + for (bufSize = 16 * 1024; bufSize >= 512; bufSize >>= 1) { + ioBufferSeg = DAlloc(bufSize); + if (ioBufferSeg) { + /* --- Leave at least 4 KB free for other uses. */ + tempSeg = DAlloc(4096); + if (tempSeg) { + tempSeg = SFree(tempSeg); + break; /* Success; leave loop. */ + } else + ioBufferSeg = SFree(ioBufferSeg); + } + } + if (ioBufferSeg != NULL) + ioBufSize = bufSize; + } + ioBufNext = ioBufLimit = 0; + /* Reading: When next==limit, buffer is empty. + * Writing: When next== 0, buffer is empty. + */ +} + +/* ---------- CloseIOBuffer ----------------- + * Writing: flush any remaining data to file. + * Free the i/o buffer. Do this whenever finish i/o, so RAM not tied up. + */ +void CloseIOBuffer(WORD file) +{ + if (ioWriting) + GFlush(file); /* TBD: ignoring error. */ + ioBufferSeg = SFree(ioBufferSeg); + ioBufSize = 0; +} + +/* ---------- GRead --------------------------------------------- + * Like DOS "read" function, RETURNS # bytes read, or 0 at EOF, + * or -1 at error. + */ +WORD GRead(WORD file, UBYTE *buffer, UWORD nBytes) +{ + UWORD nRemaining, nAvail, nThisTime; + + if (ioBufferSeg) { + nAvail = ioBufLimit - ioBufNext; + if (!nAvail && nBytes >= ioBufSize) + goto readDirectly; /* More efficient to read buffer directly. */ + + /* --- Remaining # bytes that need reading. */ + for (nRemaining = nBytes; nRemaining; nRemaining -= nThisTime) { + if (!nAvail) { + ioBufLimit = nAvail = + readdos(file, ioBufferSeg, 0, ioBufSize); + if (nAvail == 0xffff || nAvail == 0) { + ioBufLimit = 0; + return (nAvail); + } + ioBufNext = 0; + } + nThisTime = MIN(nRemaining, nAvail); + far_movmem(ioBufferSeg, ioBufNext, + dataseg(), (UWORD)buffer, + (UWORD)nThisTime); + buffer += nThisTime; + ioBufNext += nThisTime; + nAvail -= nThisTime; + } + return (nBytes); + } else /* No ioBuf */ +readDirectly: + return (read(file, buffer, nBytes)); +} + +/* --------------- GReadOne -------------------------------- + * Like "GRead", but read a single byte, with less overhead. + */ +WORD GReadOne(WORD file, UBYTE *buffer) +{ + if (!ioBufferSeg || ioBufLimit == ioBufNext) + return GRead(file, buffer, 1); + + *buffer = *BYTE_FAR_PTR(ioBufferSeg, ioBufNext); + ioBufNext++; + return (1); +} + +/* ---------- GFlush ------------------------------ + * Write out any bytes remaining in the buffer. + * Return what writedos does, or 0 if nothing to do. + */ +WORD GFlush(WORD file) +{ + auto WORD result = 0; + + if (ioBufferSeg && ioBufNext && ioWriting) { + result = writedos(file, ioBufferSeg, 0, ioBufNext); + if (result < ioBufNext) + result = -1; /* Disk must be full, turn it into an error. */ + ioBufNext = 0; /* Writing: buffer is empty. */ + } + return (result); +} + +/* ---------- GSeek ---------------------------------------------------- + * When reading, ASSUMES seeking forwards. + * When writing, flush buffer and use lseek. + * RETURNS 0 if succeeded in seeking w/i buffer. DIFFERENT THAN LSEEK. + */ +LONG GSeek(WORD file, LONG count, WORD seekType) +{ + UWORD nAvail; + + if (ioBufferSeg) { + if (ioWriting && ioBufNext) { + GFlush(file); /* TBD: Ignoring error code. */ + goto seekDirectly; + } + nAvail = ioBufLimit - ioBufNext; + + if (seekType != SEEK_CUR) { /* Check for absolute positioning */ + goto emptyAndSeekDirectly; + } + if (count > nAvail) { + count -= nAvail; /* Adjust seek for bytes already read ahead. */ +emptyAndSeekDirectly: + ioBufNext = ioBufLimit; /* Reading: buffer is empty. */ + goto seekDirectly; + } + ioBufNext += (UWORD)count; /* Seek within the buffer. */ + return (0); /* DIFFERENT THAN LSEEK */ + } else +seekDirectly: + return lseek(file, count, seekType); +} + +/* ---------- GWrite --------------------------------------------- + * Like DOS "write" function, RETURNS # bytes written, or -1 at error. + * DIFFERENCE: if can't write them all, returns -1 instead of # written, + * UNLESS "writeDirectly", which just uses write(). + */ +WORD GWrite(WORD file, UBYTE * buffer, UWORD nBytes) +{ + UWORD nRemaining, nUnused, nThisTime, nWritten; + + if (ioBufferSeg) { + if (!ioBufNext && nBytes >= ioBufSize) + goto writeDirectly; /* More efficient to write buffer directly. */ + + nUnused = ioBufSize - ioBufNext; /* # bytes unused in buffer. */ + + /* Remaining # bytes that need writing. */ + for (nRemaining = nBytes; nRemaining; nRemaining -= nThisTime) { + if (!nUnused) { + nWritten = writedos(file, ioBufferSeg, 0, ioBufNext); + if (nWritten != ioBufNext) { + ioBufNext = 0; /* Flush the data -- it is lost. */ + return (-1); /* ERROR */ + } + ioBufNext = 0; + nUnused = ioBufSize; + } + nThisTime = MIN(nRemaining, nUnused); + far_movmem(dataseg(), + (UWORD)buffer, ioBufferSeg, + ioBufNext, (UWORD)nThisTime); + buffer += nThisTime; + ioBufNext += nThisTime; + nUnused -= nThisTime; + } + return (nBytes); /* OKAY */ + } else /* No ioBuf */ +writeDirectly: + return (write(file, buffer, nBytes)); +} diff --git a/tools/old/anm/LPFILE.C b/tools/old/anm/LPFILE.C new file mode 100644 index 000000000..5993740a3 --- /dev/null +++ b/tools/old/anm/LPFILE.C @@ -0,0 +1,1928 @@ +/*--lpfile.c---------------------------------------------------------- + * + * Large Page File. This is a format for dividing a file into 64 KB + * "large pages" ("lp"s) that can be stored out-of-sequence in the file. + * That is, an lp can be logically inserted into the file, without + * having to move all the following data out of the way. + * + * Each lp holds one or more "records". A record is of any length from + * 0 to almost 64 KB. The records in the file are sequentially numbered + * starting with 0. The records in each lp are a sub-sequence; e.g., + * "3 records starting with #6" would be #6,#7,#8. + * + * A DeluxePaint Animation "ANM" ("Anim") file is built on this mechanism, + * so that as frames change in size, they can be maintained with a minimum + * of extra file i/o, yet without loss of playback performance. + * In addition, there is an optional special record which is the delta from + * the last frame to the first frame, for smooth playback of looping anims. + */ + +#include "main.h" +#include "anim.h" +#include +#include +#include /* chsize */ + +#define local static + +extern BOOL animDisk, outputLargePageFile, editting, cycling; +extern WORD curFrame; +extern UWORD animFrames, frameDelay, startFrame, endFrame, waitVerts, + gapLimitAddr; +extern Box screenBox, animBox, animMove; +extern BITMAP prevFrame, hidbm; + +extern LONG curpal[MAX_COLORS]; +extern void AnimVBlank(); + +#if U_COLORCYCLE +extern Range cycles[MAXNCYCS]; + +#endif + +/* --------------- forward declarations --------------- */ +UWORD DAllocBiggest(UWORD nBytes, UWORD * allocSizeP); +void ReadLargePage(UWORD nLp); +WORD WriteCurLp(void); +void ReadCurLp(void); +UWORD FindLargePageForRecord(register UWORD nRecord); +void WriteAnimFrameAndReadNext(void); + +/* --------------- --------------- */ + +WORD lpFile = NULL; /* Keep open so can access again. */ +char lpfSuffix[]= "ANM"; + +local Range cycles[MAXNCYCS]; + + /* Disk i/o sets after filling buffer, screen i/o clears after using. */ +UWORD nBuffers = 2; +UWORD useBuffers = 2; + + +extern char animName[]; + +local UWORD saveBitmapSeg = NULL; +#define prevFrameSeg BSEG(&prevFrame) +#define hidbmSeg BSEG(&hidbm) + +/* -------------------------------------------------------------------------- + * --------------- Description of "current record". --------------- + */ +typedef struct { + UWORD curRecord; /* record being accessed w/i lp. NOTE: ABSOLUTE rec + * #, not relative to lp baseRecord. */ + UWORD recAddr; /* Address of first byte of record, w/i lp buffer. */ + UWORD recBytes; /* # bytes in record. */ + UWORD bodyAddr; /* Address of Body of current frame. */ + UWORD bodyBytes; /* # bytes in Bitmap record's Body. */ + UWORD extraBytes; /* # bytes in Bitmap record prior to Body. + * ID+FLAGS & ExtraData, incl. count & pad. + * Used to skip over ExtraData. */ + UWORD extraDataCnt; /* # bytes of contents of ExtraData. */ +} BmRecX; /* Access to a Bitmap record. */ + +local BmRecX curRecX; /* Description of "current record". */ + +#define CUR_REC curRecX.curRecord + +/* --- These should be "CUR_REC_...", but the names get unreasonably long. */ +#define REC_ADDR curRecX.recAddr +#define REC_BYTES curRecX.recBytes +#define BODY_ADDR curRecX.bodyAddr +#define BODY_BYTES curRecX.bodyBytes +#define EXTRA_BYTES curRecX.extraBytes +#define EXTRA_DATA_CNT curRecX.extraDataCnt + +#define DEFAULT_BITMAP_ID_FLAGS ((0<<8) + 'B') + /* First byte is 'B'. On 8086 that's low byte. */ + +/* ----- Functions to manipulate "current record" w/i CUR_LP w/i lp buffer. */ +/* TBD: we're not actually using these, but doing the logic where needed. */ + +/* Shift data in buffer so there is room for "n" extraBytes, and set + * EXTRA_BYTES. NOTE: this is NOT "extraDataCount" -- it includes + * ID+FLAGS & extraDataCount in its size. + */ +local void CurRec_SetExtraBytes(UWORD n); + +/* Shift data in buffer so there is room for "n" bodyBytes, and set + * BODY_BYTES. + */ +local void CurRec_SetBodyBytes(UWORD n); + +/* Find & set CUR_REC. NOTE: "n" is absolute, not relative to baseRecord. + * This will put new lp in lp buffer if necessary. + */ +local void CurRec_Set(UWORD n); +UWORD NRecord2NFrame(WORD nRecord); + +/* -------------------------------------------------------------------------- + * --------------- buffering large pages --------------- + */ + +local UWORD preBufferSeg = NULL; +local UWORD preFrameAddr0 = 0; + +local UWORD nBuf, nNextBuf = 0, nNextPreBuf = 0, nPreLp = 0, nPreRecord; +local BOOL lastRecordInBuf, curLpIsDirty = FALSE; + + /* "lastRecordInBuf is not used during editing, so is not part of + * curRecX. + */ +#define LAST_RECORD_IN_BUF (LP_BASE_REC + LP_N_RECS - 1) + +/* -------------------- LargePage -------------------- */ +#define MAX_LARGE_PAGE 256 +typedef struct { + UWORD baseRecord; /* First record in lp. */ + UWORD nRecords; /* # records in lp. */ + /* bit 15 of "nRecords" == "has continuation from previous lp". + * bit 14 of "nRecords" == "final record continues on next lp". + * File format thus permits 16383 records/lp. + * Only MAX_RECORDS_PER_LP is currently supported by the code, + * to minimize table size in DGROUP in DP Animation. + * TBD: we're not handling non-zero bits 14&15. + */ + UWORD nBytes; /* # bytes of contents, excluding header. + * Gap of "64KB - nBytesUsed - headerSize" at end of lp. + * headerSize == "8 + 2*nRecords". + * Header is followed by record #baseRecord. */ +} LP_DESCRIPTOR; +local LP_DESCRIPTOR lpfTable[MAX_LARGE_PAGE]; + +#define LARGE_PAGE_SIZE 0x10000L + +#define MAX_RECORDS_PER_LP 256 /* TBD: why restrict, other than RAM usage? */ +#define LP_TABLE_ELEMENT UWORD /* # bytes for each record of curLp. */ + /* NOTE: lp's header must be accounted for separately.*/ + +local LP_TABLE_ELEMENT lpTable[MAX_RECORDS_PER_LP]; +local UWORD lpTableOffset = 0; /* So can pretend lpTable starts at some + * element other than 0, to fake out + * WriteCurLp. */ + +typedef struct { + LP_DESCRIPTOR x; /* Duplicate of lpfTable[CUR_LP]. NOT relied on, + * just here to help scavenge damaged files. + * "baseRecord" NOT kept up-to-date, because + * LP.AddRecord or DeleteRecord changes + * "baseRecord" of ALL following lps -- would be + * very slow to add one record near the start of a + * huge file! This field is accurate whenever the + * lp is written, but is not relied on after that. + * It still helps scavenging. Since "Optimize Anim" + * re-writes every lp, this field is accurate if + * Optimize after AddRecord/DeleteRecord. */ + UWORD nByteContinuation; /* ==0. FUTURE: allows record from + * previous lp to extend on to this lp, so + * don't waste file space. */ +} LPageHeaderFixed; + /* These fields precede the array giving "REC_BYTES" per record. */ + + +#define LP_HEADER_SIZE(nRecords) ( sizeof(LPageHeaderFixed) + \ + (nRecords) * sizeof(LP_TABLE_ELEMENT) ) + /* NOTE: if this changes, so must WriteLargePage0(). */ + +#define FIRST_RECORD_N 0 /* Records #d from 0. */ +#define LAST_RECORD_N (totalNRecords-1) + /* INCLUDES last-to-first delta if present! */ + +UWORD totalNRecords; /* Total # records in lpFile, including lastDelta. */ +UWORD nLps; /* # large pages in lpFile. */ + + +/* -------------------------------------------------------------------------- + * --------------- Description of "current lp". --------------- + * One lp at a time is present in a buffer of just under 64 KB. + * The contents of this buffer are maintained in the same form as on disk -- + * fixed header info, variable-length recordSizes table, data for records. + */ + +extern UWORD lpSeg; /* Segment of lp buffer. */ + +typedef struct { + UWORD nLp; /* lp's # w/i file */ + UWORD recAddr0; /* First byte of first record w/i lp. (after + * header). */ + LP_DESCRIPTOR x; /* Describes lp's contents. */ +} LpX; /* Access to an lp. */ + +local LpX curLpX; /* Description of "current lp". */ + +#define NO_LP ((UWORD)-1) +#define CUR_LP curLpX.nLp + +/* --- These should be "CUR_LP_...", but the names get unreasonably long. */ +#define LP_BASE_REC curLpX.x.baseRecord +#define LP_N_RECS curLpX.x.nRecords +#define LP_N_BYTES curLpX.x.nBytes +#define LP_REC_ADDR0 curLpX.recAddr0 + /* Location of first byte of frame data in lpBuffer. */ + +/* ASSUMES LP_REC_ADDR0 set for correct # records. */ +#define LP_TOTAL_BYTES (LP_REC_ADDR0 + LP_N_BYTES) +#define GAP_SIZE (MAX_LARGE_PAGE_SIZE - LP_TOTAL_BYTES) + +/* -------------------------------------------------------------------------- + * -------------------- LargePageFile -------------------- + * Lpf's Header size is 256 + 3 * 256 + 6 * maxLps. + * When lpf created, maxLps must be chosen. If file needs more lps, + * will have to move all data in file. By convention, set maxLps to + * 256 initially, increase in multiples of 256 as needed. + * FOR NOW: WON'T HANDLE FILE UNLESS SET TO 256. + * 256 * 64 KB == 16 MB. + */ + +local struct { + ULONG id; /* ID for LargePageFile == MakeID('L','P','F',' '). */ + UWORD maxLps; /* 256 FOR NOW. max # largePages allowed in this + * file. */ + UWORD nLps; /* # largePages currently in this file. 0..maxLps. + * lps #d from 0. + * NOTE: In RAM, we don't keep this field up to date. */ + ULONG nRecords; /* # records currently in this file. 65535 is + * current limit. Allowing one for last-to-first + * delta, that restricts to 65534 frames of lo-res + * animation. + * Records #d from 0. NOTE: In RAM, we + * don't keep this field up to date. */ + UWORD maxRecsPerLp; /* 256 FOR NOW. # records permitted in an lp. + * So reader knows table size to allocate. */ + UWORD lpfTableOffset; /* 1280 FOR NOW. Absolute Seek position of + * lpfTable. This allows content-specific + * header to be variable-size in the + * future. */ + ULONG contentType; /* for ANIM == MakeID('A','N','I','M'). All + * following info is specific to ANIM format. */ + UWORD width; /* in pixels. */ + UWORD height; /* in pixels. */ + UBYTE variant; /* 0==ANIM. */ + UBYTE version; /* 0== cycles stored for 18x/sec timer. + * 1== cycles stored for 70x/sec timer. */ + BOOL hasLastDelta; /* 1==Record(s) representing final frame are a + * delta from last-to-first frame. nFrames == + * (nRecords/recordsPerFrame)-hasLastDelta. */ + BOOL lastDeltaValid; /* So needn't actually remove delta. + * (When hasLastDelta==1) 0==there is a last + * delta, but it hasn't been updated to + * match the current first&last frames, so + * it should be ignored. This is done so + * don't have to physically remove the + * delta from the file when the first frame + * changes. */ + UBYTE pixelType; /* ==0 for 256-color. */ + UBYTE highestBBComp; /* 1 (RunSkipDump) FOR NOW. highest #d + * "Record Bitmap.Body.compressionType". + * So reader can determine whether it can + * handle this Anim. */ + UBYTE otherRecordsPerFrame; /* 0 FOR NOW. */ + UBYTE bitmapRecordsPerFrame;/* ==1 for 320x200,256-color. */ + UBYTE recordTypes[32]; /* Not yet implemented. */ + ULONG nFrames; /* In case future version adds other records at end + * of file, we still know how many frames. NOTE: + * DOES include last-to-first delta when present. + * NOTE: In RAM, we don't keep + * this field up to date. */ + UWORD framesPerSecond; /* # frames to play per second. */ + UWORD pad2[29]; +#if 0 /* read/write this directly, no need to waste DGROUP */ + Range cycles[MAXNCYCS]; +#endif +} lpfHdr; /* total is 128 words == 256 bytes. */ + +#if CCYCLE70 +#define LPF_VERSION 1 /* cycles stored for 70x/sec timer. */ +#else +#define LPF_VERSION 0 /* cycles stored for 18x/sec timer. */ +#endif + +#if 0 +UWORD checkFrames[32]; /* frame #s to checkpoint. each ==0 when not used. + * # non-zero * recsPerFrame == # records used for + * this purpose. Must subtract from nRecords to + * determine how many frames are really in file. + * TBD: Allocate fixed record #s for these? TBD: + * force to be one record per lp? NOTE: since frame + * #s, not record #s, seems okay to restrict to + * 16-bit. If lo-res file gets > 64 K frames, + * scale #s so can always span # frames. Ex: if + * 64K..127K frames, these #s are "*2". Recommend: + * # checkpoints proportional to # lps. Keep 1/8th + * anim-size in checkpoints. Every time file + * doubles in size, double # checks. */ + +#endif + +#define LARGE_PAGE_FILE_ID MakeID('L','P','F',' ') +#define ANIM_CONTENTS_ID MakeID('A','N','I','M') + +#define LPF_HEADER_HEAD_SIZE_IN_FILE 256 + /* First few fields at start of a Large Page File. */ + +#define SIZEOF_LPF_TABLE_IN_FILE (sizeof(LP_DESCRIPTOR) * MAX_LARGE_PAGE) + /* FUTURE: will be permitted to vary! */ + +#define LPF_HEADER_SIZE_IN_FILE ( LPF_HEADER_HEAD_SIZE_IN_FILE + \ + PALETTE_SIZE + SIZEOF_LPF_TABLE_IN_FILE ) + /* Everything in Large Page File before the first lp. */ + +#define LPF_TABLE_OFFSET (LPF_HEADER_HEAD_SIZE_IN_FILE + PALETTE_SIZE) +#define BBC_RUN_SKIP_DUMP 1 + + +/* ----------------------------------------------------------------------- */ +/* TBD: If you want better error handling, implement these. */ +#define DiskFullChangesLostExit() exit(1) +#define CantCreateAnimFileExit() exit(1) +#define InvalidAnimFileExit() exit(1) +#define TooManyPagesExit() exit(1) +#define BadBitmapRecordExit() exit(1) +#define UnrecognizedDeltaTypeExit() exit(1) + +#define LPageTooLargeMsg() +#define LpfTooLargeMsg() +#define TroubleWritingFileMsg() +#define LpfNotHandledByVersion() +#define TroubleReadingFileMsg() +#define NotAnAnimFileMsg() + + +/* ----------------------------------------------------------------------- */ + +/* --------------- GetFramesPerSecond --------------- + */ +UWORD GetFramesPerSecond() +{ + return lpfHdr.framesPerSecond; +} + + +/* --------------- DeclareFramesPerSecond --------------- + * Make sure all parties know what the (new) framesPerSecond play-rate is. + */ +DeclareFramesPerSecond(UWORD newFPS) +{ + if (newFPS == 0) + newFPS = FASTEST_RATE; + lpfHdr.framesPerSecond = newFPS; +} + + +/* --------------- AppendSuffix --------------- + */ +char sDot[] = "."; + +void AppendSuffix(char *name, char *baseName, char *suffix) +{ + strcpy(name, baseName); + strcat(name, sDot); + strcat(name, suffix); +} + + +/* --------------- OpenFile --------------- + */ +WORD OpenFile(char *baseName, char *suffix) +{ + WORD file; + char name[80]; + + AppendSuffix(name, baseName, suffix); + + file = opendos(name, O_RDWR); + if (file == -1) + file = NULL; /* No file open. */ + return file; +} + + +/* --------------- DeleteFile --------------- + */ + +void DeleteFile(char *baseName, char *suffix) +{ + char name[80]; + + AppendSuffix(name, baseName, suffix); + deletedos(name); +} + + +/* --------------- AnimFramesX --------------- + * Set "animFrames" to new value. + * This is a low-level routine. + */ +void AnimFramesX(WORD nFrames) +{ + animFrames = nFrames; +} + + +/* --------------- OpenLpFile --------------- + */ +BOOL OpenLpFile() +{ + register UWORD i; + + lpFile = OpenFile(animName, lpfSuffix); + + if (!lpFile) + return FAIL; + + /* --- Read lpfHdr. */ + CHECK_DOS(lseekdos(lpFile, (LONG) 0, SEEK_SET)); + CHECK_DOS(readfull(lpFile, (char *)&lpfHdr, sizeof(lpfHdr))); + + /* --- read cycle info */ + CHECK_DOS(readfull(lpFile, (char *)cycles, sizeof(cycles))); + + /* --- Read palette, after skipping future-expansion of lpfHdr. + * ASSUME PALETTE_SIZE == 3*256. + */ + CHECK_DOS(lseekdos(lpFile, (LONG) LPF_HEADER_HEAD_SIZE_IN_FILE, SEEK_SET)); + CHECK_DOS(readfull(lpFile, (char *)curpal, PALETTE_SIZE)); + + /* --- Read lpfTable, immediately after palette. */ + CHECK_DOS(readfull(lpFile, (char *)lpfTable, SIZEOF_LPF_TABLE_IN_FILE)); + + /* --- Check that it is a DPaint-Animate Anim. */ + if (lpfHdr.id != LARGE_PAGE_FILE_ID || + lpfHdr.contentType != ANIM_CONTENTS_ID) { + NotAnAnimFileMsg(); + goto badFile; + } + if (lpfHdr.maxLps != MAX_LARGE_PAGE || + lpfHdr.nRecords > (ULONG) MAX_RECORDS) { + LpfTooLargeMsg(); + goto badFile; + } + /* Note: maxLps may be too SMALL as well. */ + + if (lpfHdr.maxRecsPerLp > MAX_RECORDS_PER_LP) { + LPageTooLargeMsg(); + goto badFile; + } + /* --- Check that it is an Anim type we can handle. */ + if (lpfHdr.lpfTableOffset != LPF_TABLE_OFFSET || + lpfHdr.width != 320 || + lpfHdr.height != 200 || lpfHdr.highestBBComp > BBC_RUN_SKIP_DUMP || + lpfHdr.bitmapRecordsPerFrame != 1 || lpfHdr.otherRecordsPerFrame || + lpfHdr.pixelType) { + LpfNotHandledByVersion(); + goto badFile; + } + for (i = 0; i < lpfHdr.nLps; i++) { + if (lpfTable[i].nRecords > MAX_RECORDS_PER_LP || + lpfTable[i].nBytes > MAX_LARGE_PAGE_SIZE) { + LPageTooLargeMsg(); + goto badFile; + } + /* FUTURE: hi 2 bits of nRecords indicate continuation. */ + } + + nLps = lpfHdr.nLps; /* TBD: why not use fields in place? */ + totalNRecords = (UWORD) lpfHdr.nRecords; + + AnimFramesX(lpfHdr.nFrames - lpfHdr.hasLastDelta); + DeclareFramesPerSecond(lpfHdr.framesPerSecond); + + CUR_LP = NO_LP; /* None loaded. */ +/* ReadLpfFrame(FIRST_FRAME_N); --- So have valid, for InsureBuffer...*/ + return SUCCESS; + +doserr: + TroubleReadingFileMsg(); +badFile: + closedos(lpFile); + lpFile = NULL; + InvalidAnimFileExit(); + return FAIL; +} + + +/* --------------- SeekLargePage --------------- + * Seek lp file to the specified large page. + * Return FALSE on error. + */ +#define LP_FILE_OFFSET(nLp) \ + (LONG)((LONG)(nLp) * LARGE_PAGE_SIZE + LPF_HEADER_SIZE_IN_FILE) + +local LONG SeekLargePage(UWORD nLp) +{ + if (nLp > MAX_LARGE_PAGE) + BugExit("LP1"); /* "Invalid lp #"); */ + + /* Seek to lp. File has header, then lps #d from 0. */ + return (lseekdos(lpFile, LP_FILE_OFFSET(nLp), SEEK_SET)); +} + + +/* --------------- ReadLargePage00 --------------- + * Also reads HEADER into lpBuf, for read-ahead. + * When editing, don't want this. + * IMPLICIT PARAMETERS: preFrameAddr0, lpfTable. + */ +local ReadLargePage00(UWORD lpFile, WORD nLp, UWORD seg) +{ + UWORD nBytes; + + preFrameAddr0 = LP_HEADER_SIZE(lpfTable[nLp].nRecords); + + nBytes = preFrameAddr0 + lpfTable[nLp].nBytes; + if (readdos(lpFile, seg, 0, nBytes) != nBytes) + BugExit("LP2"); /* "ReadLargePage00: nBytes"); */ +} + + +/* --------------- MaybeWriteCurLp --------------- + */ +local void MaybeWriteCurLp(void) +{ + if (curLpIsDirty) { + WriteCurLp(); + } +} + + +/* --------------- ReadLargePage --------------- + */ +void ReadLargePage(UWORD nLp) +{ + MaybeWriteCurLp(); + SeekLargePage(nLp); + ReadLargePage00(lpFile, nLp, lpSeg); + + curLpX.x = lpfTable[nLp]; /* LP_BASE_REC, LP_N_RECS, LP_N_BYTES */ + + LP_REC_ADDR0 = LP_HEADER_SIZE(LP_N_RECS); + +/* far_movmem( lpSeg, 0, dataseg(), (UWORD)&LP_N_BYTES, 2 ); */ +/* "baseRecord" field ignored. */ +/* far_movmem( lpSeg, 4, dataseg(), (UWORD)&LP_N_RECS, 2 ); */ +/* "nByteContinuation" field not used. */ + + far_movmem(lpSeg, sizeof(LPageHeaderFixed), + dataseg(), (UWORD) lpTable, + LP_N_RECS * sizeof(LP_TABLE_ELEMENT)); + + CUR_LP = nLp; +} + + +/* --------------- NFrame2NRecord --------------- + * Given a frame #, compute the record # in the lpFile. + * ASSUME has a last-delta, which is the last record. + */ +local UWORD NFrame2NRecord(WORD nFrame) +{ + if (nFrame == LAST_DELTA_N) + return FIRST_RECORD_N; + return (nFrame - FIRST_FRAME_N + FIRST_RECORD_N); +} + + +/* --------------- NRecord2NFrame --------------- + * Given an lpfile record #, compute the frame #. + * ASSUME records are #d from 0. + */ +UWORD NRecord2NFrame(WORD nRecord) +{ + return nRecord + FIRST_FRAME_N; +} + + +/* --------------- FindLargePageForRecord --------------- + * Step through lp descriptions, looking for one that contains + * requested record. + * RETURN lp #. + * NOTE: it is possible for lpfTable[nLp].baseRecord to be non-zero + * even on an empty page. Fortunately, the "baseRecord <= nRecord < ..." + * tests will always reject pages with nRecords==0. + */ +local UWORD FindLargePageForRecord(register UWORD nRecord) +{ + register UWORD nLp, baseRecord; + + for (nLp = 0; nLp < nLps; nLp++) { + baseRecord = lpfTable[nLp].baseRecord; + if (baseRecord <= nRecord && + nRecord < baseRecord + lpfTable[nLp].nRecords) { +#if DEBUG_BUFS + if (!editting) + printf("Find lp:%d for rec:%d\n", nLp, nRecord); /* TESTING */ +#endif + return nLp; + } + } + BugExit("LP6"); /* "Didn't find record in lpfTable"); */ +} + + +/* --------------- ReadLargePageForRecord --------------- + * Find lp containing record, then read it. + */ +local void ReadLargePageForRecord(register UWORD nRecord) +{ + ReadLargePage(FindLargePageForRecord(nRecord)); +#if 0 + if (FALSE) { + PrepExit(); + printf("First ReadLargePageForRecord (%d) on playback.", nRecord); + + PrintLPFState(); + exit(1); + } +#endif /* 0 */ +} + + +/* --------------- ReadLpfFrame --------------- + * Transfer to temp buffer the specified delta-frame. + */ +ReadLpfFrame(WORD nFrame) +{ + register UWORD nRecord; + + nRecord = NFrame2NRecord(nFrame); + + if ((CUR_LP >= nLps) || /* No lp yet. */ + (nRecord < LP_BASE_REC) || /* record not in CUR_LP. */ + (nRecord >= LP_BASE_REC + LP_N_RECS)) { + if (nRecord >= totalNRecords) + BugExit("LP7"); /* "Impossible lp record."); */ + ReadLargePageForRecord(nRecord); + } + + /* --- Step through records in CUR_LP. */ + REC_ADDR = LP_REC_ADDR0; + CUR_REC = LP_BASE_REC; + while (nRecord > CUR_REC) { + REC_ADDR += lpTable[CUR_REC - LP_BASE_REC]; + CUR_REC++; + } + REC_BYTES = lpTable[CUR_REC - LP_BASE_REC]; + + if (REC_BYTES) { + UWORD far *ptr; + UBYTE bitmapId, bitmapFlags; + + ptr = WORD_FAR_PTR(lpSeg, REC_ADDR); + bitmapId = ((UBYTE far *) ptr)[0]; + if (bitmapId != 'B') +#if 0 /* TESTING */ + { + PrepExit(); + printf("BadB frame:%d id:%x exN:%d recN:%d bodyN:%d, addrs:%x %x, rec data:%x %x %x\n", + nFrame, bitmapId, EXTRA_BYTES, + REC_BYTES, BODY_BYTES, REC_ADDR, BODY_ADDR, ptr[0], ptr[1], ptr[2]); + exit(1); + } +#else + BadBitmapRecordExit(); +#endif + bitmapFlags = ((UBYTE far *) ptr)[1]; + EXTRA_DATA_CNT = ptr[1]; + EXTRA_BYTES = (bitmapFlags ? 4 + EVEN_UP(EXTRA_DATA_CNT) : 2); + } else { + EXTRA_BYTES = 0; /* No recData, therefore no extra data. */ + } + + BODY_ADDR = REC_ADDR + EXTRA_BYTES; + BODY_BYTES = REC_BYTES - EXTRA_BYTES; + + lastRecordInBuf = (CUR_REC == LAST_RECORD_IN_BUF); +} + + +/* --------------- PlayDeltaFrame0 --------------- + * Play the current delta info onto the specified frame bitmap. + * IMPLICIT INPUT: curRecX, lpSeg. + * NOTE: The 0 BODY_BYTES case isn't handled at this level. + */ +#define PRSD_ASM 1 /* Play RunSkipDump in assembly. */ +local void PlayDeltaFrame0(UWORD bmSeg) +{ +#if 1 + UWORD bodyType, nBytes; + +#else + register UWORD deltaAddr; + UWORD picSeg; + LONG frameType; + +#endif + + if (!BODY_BYTES) + return; /* empty body == no change */ + + if (BODY_BYTES < 2) + BugExit("LP8"); + /* "Short body of bitmap record"); + * TBD: return error code + */ + + /* --- runSkipDump or uncompressed */ +#define BODY_HEADER_LEN sizeof(UWORD) + /* UWORD holding body type precedes body data. */ + bodyType = *WORD_FAR_PTR(lpSeg, BODY_ADDR); + nBytes = BODY_BYTES - 2; + if (bodyType == BMBODY_UNCOMPRESSED) { + /* --- Direct dump of screen. */ + if (nBytes != N_BYTES_IN_BITMAP) + BugExit("LP9"); /* "Uncompressed body has wrong # bytes"); */ + far_movmem(lpSeg, BODY_ADDR + BODY_HEADER_LEN, + bmSeg, 0, nBytes); + } else if (bodyType == BMBODY_RUNSKIPDUMP) { /* --- RunSkipDump + * encoding of screen. */ +#if PRSD_ASM /* RunSkipDump in assembly. */ + UWORD dstAddr; + UBYTE far *srcP; + +#else /* RunSkipDump in C. */ + register signed char cnt; + UBYTE pixel; + UWORD wordCnt; + UBYTE far *srcP, far * dstP; + +#endif + + if (!nBytes) + return; /* empty delta == no change */ +#define BMBODY_STOP_CODE_LEN 3 +#define BBSTOP0 LONG_OP +#define BBSTOP1 0 +#define BBSTOP2 0 + srcP = BYTE_FAR_PTR(lpSeg, BODY_ADDR + BODY_BYTES - BMBODY_STOP_CODE_LEN); + if (nBytes < BMBODY_STOP_CODE_LEN || srcP[0] != BBSTOP0 || + srcP[1] != BBSTOP1 || srcP[2] != BBSTOP2) + BugExit("LPA"); /* "RunSkipDump body missing stop code"); */ + +#if PRSD_ASM /* RunSkipDump in assembly. */ + dstAddr = PlayRunSkipDump(nBytes, lpSeg, BODY_ADDR + BODY_HEADER_LEN, + bmSeg, 0); + if (dstAddr > N_BYTES_IN_BITMAP) +#else /* RunSkipDump in C. */ + /* --- Here is an algorithm to playback a 256-color Body, + * onto a same-size screen with rows in sequence, + * so don't have to test each sequence to see + * if it is on a new row. + * NOTE: Once it is working, you may remove all the references to + * "nBytes", as the stop code is sufficient to end processing. + */ + srcP = BYTE_FAR_PTR(lpSeg, BODY_ADDR + BODY_HEADER_LEN); + dstP = BYTE_FAR_PTR(bmSeg, 0); + /* srcP points at first sequence in Body, + * dstP points at pixel #0 on screen. + */ +nextOp: + if (nBytes < 3) + BugExit("LPB"); /* "RunSkipDump body elided stop code"); */ + cnt = (signed char) *srcP++; + if (cnt > 0) + goto dump; + if (cnt == 0) + goto run; + cnt -= 0x80; + if (cnt == 0) + goto longOp; +/* shortSkip */ + nBytes -= 1; /* length of shortSkip code */ + dstP += cnt; /* adding 7-bit count to 32-bit pointer */ + if (FP_OFF(dstP) > N_BYTES_IN_BITMAP) + goto stop; + goto nextOp; +dump: + nBytes -= 1 + cnt; /* length of dump code & data */ + /* ASM: ds:si=srcP, es:di=dstP, cx=cnt, then do "rep movsb". */ + /* Equivalent: "do { *dstP++ = *srcP++; } while (--cnt);" */ + far_movmem_ptrs(srcP, dstP, cnt); + dstP += cnt; + if (FP_OFF(dstP) > N_BYTES_IN_BITMAP) + goto stop; + srcP += cnt; + goto nextOp; +run: + wordCnt = (UBYTE) * srcP++; /* 8-bit unsigned count */ + pixel = *srcP++; + nBytes -= 3; /* length of run code & data */ + /* ASM: es:di=dstP, al=pixel, cx=wordCnt, then do "rep stosb". */ + /* Equivalent: "do { *dstP++ = pixel; } while (--wordCnt);" */ + far_setmem_ptr(dstP, wordCnt, pixel); + dstP += wordCnt; + if (FP_OFF(dstP) > N_BYTES_IN_BITMAP) + goto stop; + goto nextOp; +longOp: + wordCnt = *((UWORD far *)srcP)++; + if ((WORD)wordCnt <= 0) + goto notLongSkip; /* Do SIGNED test. */ + +/* longSkip. */ + nBytes -= 3; + dstP += wordCnt; + if (FP_OFF(dstP) > N_BYTES_IN_BITMAP) + goto stop; + goto nextOp; + +notLongSkip: + if (wordCnt == 0) + goto stop; + wordCnt -= 0x8000; /* Remove sign bit. */ + if (wordCnt >= 0x4000) + goto longRun; + +/* longDump. */ + nBytes -= 3 + wordCnt; + /* ASM: ds:si=srcP, es:di=dstP, cx=wordCnt, then do "rep movsb". */ + /* Equivalent: "do { *dstP++ = *srcP++; } while (--wordCnt);" */ + far_movmem_ptrs(srcP, dstP, wordCnt); + dstP += wordCnt; + if (FP_OFF(dstP) > N_BYTES_IN_BITMAP) + goto stop; + srcP += wordCnt; + goto nextOp; + +longRun: + wordCnt -= 0x4000; /* Clear "longRun" bit. */ + pixel = *srcP++; + nBytes -= 4; + /* ASM: es:di=dstP, al=pixel, cx=wordCnt, then do "rep stosb". */ + /* Equivalent: "do { *dstP++ = pixel; } while (--wordCnt);" */ + far_setmem_ptr(dstP, wordCnt, pixel); + dstP += wordCnt; + if (FP_OFF(dstP) > N_BYTES_IN_BITMAP) + goto stop; + goto nextOp; + +stop: +/* all done */ + if (FP_OFF(dstP) > N_BYTES_IN_BITMAP) +#endif /* RunSkipDump in C. */ + BugExit("LPC"); + /* "Wrong amount of screen data generated from RunSkipDump + * body"); + */ + } + else { /* TBD: Should be Info Msg, not Exit. */ + UnrecognizedDeltaTypeExit(); + } +} + + +/* --------------- PlayDeltaFrame --------------- + * Play the current delta info onto the specified frame bitmap. + */ +PlayDeltaFrame(BITMAP * bm) +{ + if (BODY_BYTES == 0) + return; /* "0 bytes" means "no change". */ + PlayDeltaFrame0(BSEG(bm)); +} + + +/* ----------------------------------------------------------------------- */ +BOOL permitScreenSwap = TRUE; + +/* --------------- CreateFile --------------- + */ +WORD CreateFile(char *baseName, char *suffix) +{ + WORD file; + char name[80]; + + AppendSuffix(name, baseName, suffix); + file = creatdos(name, O_RDWR); + if (file == -1) + file = NULL; /* No file open. */ + return file; +} + + +/* --------------- CloseFile --------------- + * Once i/o is buffered, this will flush & release buffer. + */ +void CloseFile(WORD file) +{ + if (file && file != -1) + closedos(file); + /* NOTE: we use "NULL" to indicate non-open file. */ +} + + +/* --------------- WriteN --------------- + * Write near data, and return FALSE on error. + */ +BOOL WriteN(UWORD file, BYTE *data, UWORD cnt) +{ + return (cnt == writedos(file, dataseg(), data, cnt)); +} + + +/* --------------- WriteFar --------------- + * Write far data, and return FALSE on error. + */ +BOOL WriteFar(UWORD file, WORD far * data, UWORD cnt) +{ + return (cnt == writedos(file, FP_SEG(data), FP_OFF(data), cnt)); +} + + +/* --------------- ReadN --------------- + * Read near data, and return FALSE on error. + */ +BOOL ReadN(UWORD file, BYTE * data, UWORD cnt) +{ + return (cnt == read(file, data, cnt)); +} + + +/* --------------- ReadFar --------------- + * Read far data, and return FALSE on error. + */ +BOOL ReadFar(UWORD file, WORD far * data, UWORD cnt) +{ + return (cnt == readdos(file, FP_SEG(data), FP_OFF(data), cnt)); +} + + +/* --------------- CreateLpFile0 --------------- + * Create file with one frame. + * If "blank", the first frame is blank, otherwise it is the + * contents of "hidbm". + */ +BOOL animOptimized; /* TRUE when anim is packed for optimal playback. */ +BOOL cleanGap = FALSE; /* TRUE to put nulls in gap when write lp. */ + +void CreateLpFile0(BOOL blank) +{ + lpFile = CreateFile(animName, lpfSuffix); + if (!lpFile) + CantCreateAnimFileExit(); + + setmem(&lpfHdr, sizeof(lpfHdr), 0); /* BEFORE set any fields. */ +#if 0 /* ...done by setmem... */ + lpfHdr.variant = lpfHdr.hasLastDelta = + lpfHdr.lastDeltaValid = lpfHdr.pixelType = + lpfHdr.otherRecordsPerFrame = 0; +#endif + lpfHdr.version = LPF_VERSION; + + /* TBD: Whenever create new anim, starts at a specified rate. + * Should this instead be done when program boots, then use whatever + * gets loaded? + * Hard to say, since can either be set by user, + * or by loading an anim (in which case user may not realize it + * changed). + */ + /* TBD: Boot, or NewAnim, now creates at 10 fps. Good choice? */ + DeclareFramesPerSecond(10 /* FASTEST_RATE */ ); + + lpfHdr.id = LARGE_PAGE_FILE_ID; + lpfHdr.maxLps = MAX_LARGE_PAGE; + lpfHdr.maxRecsPerLp = MAX_RECORDS_PER_LP; +/* lpfHdr.nLps & .nRecords are over-ridden by independent variables. */ + lpfHdr.lpfTableOffset = LPF_TABLE_OFFSET; + lpfHdr.contentType = ANIM_CONTENTS_ID; + lpfHdr.width = 320; + lpfHdr.height = 200; + lpfHdr.bitmapRecordsPerFrame = 1; + lpfHdr.highestBBComp = BBC_RUN_SKIP_DUMP; + + AnimFramesX(totalNRecords = 1); /* # records in whole lpFile */ + lpfHdr.nFrames = animFrames + lpfHdr.hasLastDelta; + nLps = 1; + CUR_LP = 0; + + CUR_REC = LP_BASE_REC = 0; + LP_N_RECS = 1; /* # records in current large page */ + LP_N_BYTES = 0; + lpTable[0] = 0; /* A zero-byte page description. */ + /* (Since it is first frame, zero-bytes means all-white). */ + + LP_REC_ADDR0 = 0; /* No header info before frame data in + * buffer seg. */ +#if 1 + /* --- Hack: Force zero-size first frame to be re-computed as + * a series of all-white runs, since the player no longer sets bitmap + * to white before first frame. + * THEN, say the anim is not dirty, so won't save it unless some + * change is made. This avoids asking user to save the empty + * untitled anim, when he boots DP-A, then does LoadAnim. + * !!! Is ugly to be calling these routines from inside here. !!! + */ + ReadLpfFrame(FIRST_FRAME_N); + if (blank) { + SetBitMap(&hidbm, white_color); /* Clear what will be frame 0. */ + FirstAnimFrame0(); + WriteAnimFrameAndReadNext(); + } else { /* Use "hidbm" as first frame's contents. */ + FirstAnimFrame00(); + WriteAnimFrameAndReadNext(); + } + animOptimized = TRUE; +#endif + + WriteCurLp(); /* Make sure disk is up-to-date. */ + ReadCurLp(); /* Overkill. Makes sure buffer & tables + * consistent. */ + ReadLpfFrame(FIRST_FRAME_N); + /* Adjust BODY_ADDR, etc., for correct header size. */ +} + + +/* --------------- CreateLpFile --------------- + * Create file, with first frame blank. + */ +void CreateLpFile() +{ + CreateLpFile0(TRUE); +} + + +/* --------------- WriteHdrAndCloseLpFile --------------- + * IMPLICIT PARAMETERS: lpFile, lpfHdr, nLps, lpfTable, totalNRecords. + */ +WriteHdrAndCloseLpFile() +{ + register UWORD i; + BOOL tryAgain = TRUE; + +again: + if (!lpFile) + return; + + MaybeWriteCurLp(); + +/* lpfHdr.version = LPF_VERSION; --redundant */ + lpfHdr.nLps = nLps; + lpfHdr.nRecords = totalNRecords; + lpfHdr.nFrames = animFrames + lpfHdr.hasLastDelta; + + /* --- Clear unused elements of lpfTable. */ + setmem(&lpfTable[nLps], + sizeof(LP_DESCRIPTOR) * (MAX_LARGE_PAGE - nLps), + 0); + + /* --- Write lpfHdr. */ + CHECK_DOS(lseekdos(lpFile, (LONG) 0, SEEK_SET)); + CHECK_DOS(writefull(lpFile, (char *) &lpfHdr, sizeof(lpfHdr))); + + /* --- Write cycle info as part of header */ + /* TBD: byte flipping for 68000 */ + CHECK_DOS(writefull(lpFile, (char *) cycles, sizeof(cycles))); + + /* --- Write palette, immediately after future-expansion of lpfHdr. + * ASSUME PALETTE_SIZE == 3*256. + * NOTE: Palette byte-order not changed between 8086 & 68000. + */ + CHECK_DOS(writefull(lpFile, (char *)curpal, PALETTE_SIZE)); + + /* --- Write lpfTable, immediately after palette. */ + CHECK_DOS(writefull(lpFile, (char *)lpfTable, SIZEOF_LPF_TABLE_IN_FILE)); + goto ok; + +doserr: + if (tryAgain) { /* Attempt to overcome spurious disk error. */ + tryAgain = FALSE; + goto again; + } + TroubleWritingFileMsg(); +ok: + closedos(lpFile); + lpFile = NULL; + + if ((animFrames + lpfHdr.hasLastDelta) != totalNRecords) + BugExit("LPH"); /* "inconsistent #frames vs #records in + * file"); */ + /* NOTE: when hasLastDelta is TRUE, + * nRecords includes that delta. + * In that case, number of frames in anim is + * "nRecords-1". + * ASSUME TRUE == 1. + * WARNING: Calling "BugExit" would be + * recursive, if done before + * set lpFile = NULL. + */ +} + + +/* --------------- WriteLargePage0 --------------- + * IMPLICIT PARAMETERS: "lpfTable" describes output lpFile. + * TBD: should be descriptor containing both lpFile & lpfTable. + * ASSUME lpFile is open for writing. + * Q: Can this change to do in one disk i/o operation? + * That requires lpTable to be moved to head of lpSeg, yet lpTable is + * variable-size. So will have to MOVE the 64KB of data. + * ANS: CANNOT have "lpTable" part of lpSeg (requiring this routine to + * shift data in lpSeg), as this routine is used to + * WriteNewLp, while lpSeg still holding other useful data! + */ +#define LP_SIZE_IN_FILE(nLp) \ + (lpfTable[nLp].nBytes + LP_HEADER_SIZE(lpfTable[nLp].nRecords)) + /* Size of an lp in file -- contents PLUS header. */ + +WORD WriteLargePage0( + UWORD lpFile, UWORD seg, LP_TABLE_ELEMENT lpTable[], + register LpX * lpX) +{ + LPageHeaderFixed lphf; + UWORD gapSize, writeSize; + UBYTE zeroes[512]; /* 512 bytes on stack. TBD: can be larger? */ + UWORD zeroSeg, zeroAddr; + BOOL tryAgain = TRUE; + +again: + lpfTable[lpX->nLp] = lpX->x; + + CHECK_DOS(SeekLargePage(lpX->nLp)); + + /* --- Write header for lp. + * Note: if header changes, so must LP_HEADER_SIZE. + */ + lphf.x = lpX->x; + lphf.nByteContinuation = 0; + + CHECK_DOS(writefull(lpFile, (char *) &lphf, sizeof(lphf))); + + if (lpX->x.nRecords) + CHECK_DOS(writefull(lpFile, + (char *) lpTable, lpX->x.nRecords * sizeof(LP_TABLE_ELEMENT))); + /* --- Table describing the records. */ + + if (lpX->x.nBytes) + CHECK_DOS(writedosfull(lpFile, seg, lpX->recAddr0, lpX->x.nBytes)); + + if (cleanGap) { /* Fill gap with nulls. */ + zeroSeg = DAllocBiggest(32768, &writeSize); + if (writeSize <= sizeof(zeroes)) + zeroSeg = SFree(zeroSeg); + if (zeroSeg) + zeroAddr = 0; /* Allocated a large far buffer */ + else { + zeroSeg = dataseg();/* Use stack buffer */ + zeroAddr = (UWORD) zeroes; + writeSize = sizeof(zeroes); + } + far_setmem(zeroSeg, zeroAddr, writeSize, 0); + gapSize = (65535 - LP_SIZE_IN_FILE(lpX->nLp)) + 1; + while (gapSize) { + if (writeSize > gapSize) + writeSize = gapSize; + gapSize -= writeSize; + CHECK_DOS(writedosfull( + lpFile, zeroSeg, zeroAddr, writeSize)); + } + if (zeroSeg != dataseg()) + zeroSeg = SFree(zeroSeg); + } + return (SUCCESS); +doserr: + if (tryAgain) { /* Attempt to overcome spurious disk error. */ + tryAgain = FALSE; + goto again; + } + TroubleWritingFileMsg(); + return (FAIL); +} + + +/* --------------- WriteCurLp --------------- + * Write current large page back into buffer. + */ +local WORD WriteCurLp(void) +{ + WORD result; + + result = WriteLargePage0(lpFile, lpSeg, &lpTable[lpTableOffset], &curLpX); + curLpIsDirty = FALSE; + return result; +} + + +/* --------------- ReadCurLp --------------- + * Read current large page back into buffer. + * TBD: If no lp specified yet, does nothing. Should it load first frame + * instead? + */ +local void ReadCurLp(void) +{ + if (CUR_LP < nLps) + ReadLargePage(CUR_LP); +} + + +/* --------------- RecordFits --------------- + */ +BOOL RecordFits(UWORD srcBytes) +{ + if (LP_N_RECS == MAX_RECORDS_PER_LP) + return FALSE; + + /* --- If added this record, check whether header + body still + * fit. + */ + if (LP_HEADER_SIZE(LP_N_RECS + 1) + (ULONG)LP_N_BYTES + (ULONG)srcBytes > + (ULONG)MAX_LARGE_PAGE_SIZE) + return FALSE; + return TRUE; +} + + +/* --------------- LpfFrameLimitAddr --------------- + * For current lpf frame, RETURN limitAddr. + * == current size of frame. + */ +UWORD LpfFrameLimitAddr() +{ + return BODY_ADDR + BODY_BYTES; +} + + +/* ------------------------------------------------------------ */ +/* --------------- Other routines --------------- */ + +/* --------------- IsLpfId --------------- + * RETURN TRUE if id matches Large-Page-File's id. + */ +BOOL IsLpfId(ULONG id) +{ + return (id == LARGE_PAGE_FILE_ID); +} + + +/* ------------------------------------------------------------------------ + * Delta management. + * ------------------------------------------------------------------------ + */ + + +/* --------------- delta buffer --------------- + * Buffer to hold one delta (difference between two bitmaps). + * (seg:addr) is start of buffer, (seg:limit) is just past end of buffer, + * "nBytes" is length of delta. + */ +typedef struct { + UWORD seg, addr, limit, nBytes; +} DeltaX; +DeltaX deltaX = {0}; + +extern UWORD allocSeg; + +/* --------------- ComputeDeltaX --------------- + * Given prevFrame & current frame in hidbm, compute delta in save_bitmap. + * IMPLICIT INPUT: deltaX, hidbmSeg, prevFrameSeg. + * RETURN TRUE if succeeded in creating delta, FALSE if delta didn't fit. + * SIDE_EFFECT: set deltaX.nBytes, store that many bytes at deltaX.(seg:addr). + * Note: if algorithm is changed, must be careful that can't exceed + * MAX_LARGE_PAGE_SIZE. + */ +#define MRSD_ASM 1 /* Make RunSkipDump in assembly. */ + +#define CLIP_X(stopLabel) { \ + if (x == w) { \ + x = 0; \ + if (inFinalRow) { \ + mustStop = TRUE; \ + goto stopLabel; } \ + if (src2 == finalRow2) {\ + w = finalRowWidth; \ + inFinalRow = TRUE; }\ + } \ + } + +#define CROSSED_W(n) (xWas + (n) > width) + /* Test avoids using SHORT ops when line-wrap. + * This is specified, so can write algorithm to play onto wider screen, + * without having to test shortDump & shortRun for line-wrap on any pixel. + * "width" rather than "w", since is from previous line, not current line. + * This only matters on last line. + */ + +#define PUT_DUMP(body, cnt) if (cnt) { \ + if ((cnt) <= MAX_SHORT_DUMP && !CROSSED_W(cnt)) \ + *dst++ = OP_DUMP | (cnt); \ + else{ \ + *dst++ = LONG_OP; \ + *((UWORD far *)dst)++ = \ + (LONG_DUMP<<8) | (cnt); } \ + if (dst - dst0 > finalDst-(cnt)) \ + goto incompressible; \ + far_movmem_ptrs( body, dst, cnt ); \ + dst += cnt; } + /* NOTE the check for zero cnt. + * NOTE that cnt must already have been limited to MAX_DUMP. + */ + +#define PUT_RUN(wordCnt,runPix) if (wordCnt) { \ + if ((wordCnt) <= MAX_SHORT_RUN && !CROSSED_W(wordCnt)) { \ + *dst++ = OP_RUN; \ + *dst++ = wordCnt; } \ + else{ \ + *dst++ = LONG_OP; \ + *((UWORD far *)dst)++ = \ + (LONG_RUN<<8) | (wordCnt); } \ + *dst++ = runPix; \ + } + + +local BOOL ComputeDeltaX(BOOL skipPermitted) +{ + /* Inputs: */ + UBYTE far *src1, far * src2, far * final2, far * dst; + UWORD width, finalDst; + + /* src1 points to previous frame, src2 to screen, limit2 to final + * screen + * byte, dst points to "finalDst+1" byte buffer for Body, + * width is # pixels in a row. For 64 KB buffer, finalDst==0xFFFF. + */ + /* Local variables: */ + UBYTE far *finalRow2, far * dst0; + UBYTE pixel, runPix, skipInDump, runInDump; + UWORD x, w, finalRowWidth, wordCnt, xWas; + BOOL inFinalRow, mustStop; + +#if 0 + UWORD deltaSize; + +#endif + if (!deltaX.limit) + BugExit("LPJ"); /* "ComputeDelta -- deltaX.limit"); */ + + src1 = BYTE_FAR_PTR(prevFrameSeg, 0); + src2 = BYTE_FAR_PTR(hidbmSeg, 0); + final2 = BYTE_FAR_PTR(hidbmSeg, NBYTES_IN_BITMAP(&hidbm) - 1); + dst = BYTE_FAR_PTR(deltaX.seg, deltaX.addr); + width = hidbm.box.w; + finalDst = deltaX.limit; + + w = width; + finalRowWidth = (UWORD)(final2 - src2 + 1) % width; + if (!finalRowWidth) + finalRowWidth = width; /* # pixels in final row. */ + finalRow2 = final2 - (finalRowWidth - 1); /* Ptr to start of final + * row. */ + inFinalRow = (finalRow2 == src2); + /* FALSE unless src2 is a single row. */ + if (inFinalRow) + w = finalRowWidth; /* In case single-row src is shorter than + * width. */ + + +#if MRSD_ASM /* RunSkipDump in assembly. */ + return MakeRunSkipDump(prevFrameSeg, hidbmSeg, NBYTES_IN_BITMAP(&hidbm) - 1, + deltaX.seg, deltaX.addr, deltaX.limit, &deltaX.nBytes, + w, FP_OFF(finalRow2), finalRowWidth, inFinalRow, skipPermitted); + +#else /* ---- RunSkipDump in C. --- most likely out of date ------ */ + dst0 = dst; /* Remember, so can calculate Body size. */ + *(UWORD far *) dst = BMBODY_RUNSKIPDUMP; /* 2-byte header with type. */ + dst += 2; + + x = 0; /* Keep track of pixel-position, so break + * at row end. */ + mustStop = FALSE; + +notInASequence: + wordCnt = 0; + +/*--- "pixel" must be set when jump to beDump with "wordCnt != 0".*/ +beDump: + xWas = x + width - wordCnt; /* Where in line dump started. */ + if (xWas >= width) + xWas -= width; + /* "width" logic in case x < wordCnt, because already + * line-wrapped. + */ + if (FP_OFF(dst) > finalDst - 3) + goto incompressible; + /* "3" is longDump overhead. Dump DATA is checked inside + * PUT_DUMP. + */ + skipInDump = 0; + runInDump = (wordCnt ? 1 : 0); /* Any pixel is run==1. */ +inDump: + CLIP_X(stopDump); /* If mustStop, goto to "stopDump" to get + * final dump. */ + runPix = pixel; + pixel = *src2++; + x++; + wordCnt++; /* Get&count byte. */ + if (pixel == *src1++) + skipInDump++; /* # skippable bytes. */ + else + skipInDump = 0; + if (pixel == runPix) + runInDump++; /* # runnable bytes. */ + else + runInDump = 1; /* Any pixel is run==1. */ + + if (skipInDump == MIN_SKIP && skipPermitted) { /* Minimum worthwhile + * skip. */ + PUT_DUMP(src2 - wordCnt, wordCnt - MIN_SKIP); + wordCnt = MIN_SKIP; + goto beSkip; /* "Skip 2" so far. */ + } + if (runInDump == MIN_RUN) { /* Minimum worthwhile run. */ + PUT_DUMP(src2 - wordCnt, wordCnt - MIN_RUN); + wordCnt = MIN_RUN; + goto beRun; /* "Run 4" so far. */ + } + /* --- Byte still in Dump. */ + if (wordCnt == MAX_LONG_DUMP) { +stopDump: + PUT_DUMP(src2 - wordCnt, wordCnt); + if (mustStop) + goto stop; + goto notInASequence; + } + goto inDump; + +beRun: + xWas = x + width - wordCnt; /* Where in line run started. */ + if (xWas >= width) + xWas -= width; + if (FP_OFF(dst) > finalDst - 4) + goto incompressible; /* "4" is length of longRun. */ + skipInDump = 0; /* ACTUALLY skip is in run, not in dump... */ + runPix = pixel; /* Only need do once per run. */ +inRun: + CLIP_X(stopRun); /* If mustStop, goto to "stopRun" to get + * final run. */ + pixel = *src2++; + x++; + wordCnt++; /* Get byte & count it. */ + if (pixel == *src1++) + skipInDump++; /* # skippable bytes. */ + else + skipInDump = 0; + /* Note: check for byte runnable comes later. */ + + if (skipInDump == MIN_RUN_SKIP && skipPermitted) { + wordCnt -= MIN_RUN_SKIP; + PUT_RUN(wordCnt, runPix); + wordCnt = MIN_RUN_SKIP; + goto beSkip; /* "Skip 4" so far. */ + } + if (pixel != runPix) { /* Byte not runnable -- requires Dump. */ + wordCnt--; /* Retract pixel from Run. */ + PUT_RUN(wordCnt, runPix); + wordCnt = 1; + goto beDump; /* "Dump 1" so far. */ + } + /* --- Byte runnable. */ + if (wordCnt == MAX_LONG_RUN) { +stopRun: + PUT_RUN(wordCnt, runPix); + if (mustStop) + goto stop; + goto notInASequence; + } + goto inRun; + +beSkip: + xWas = x + width - wordCnt; /* Where in line skip started. */ + if (xWas >= width) + xWas -= width; + if (FP_OFF(dst) > finalDst - 3) + goto incompressible; /* "3" is length of LongSkip. */ +inSkip: + runPix = pixel; + pixel = *src2++; + x++; + wordCnt++; /* Get byte & count it. */ + if (pixel != *src1++) { /* Byte not skippable. */ + wordCnt--; /* Retract pixel from Skip. */ + if (wordCnt <= MAX_SHORT_SKIP) { + *dst++ = OP_SKIP | wordCnt; + } else if (wordCnt <= 2 * MAX_SHORT_SKIP) { + *dst++ = OP_SKIP | MAX_SHORT_SKIP; + wordCnt -= MAX_SHORT_SKIP; + *dst++ = OP_SKIP | wordCnt; + } else { + UWORD wordCnt0 = wordCnt; + + while (wordCnt0) { + wordCnt = MIN(wordCnt0, MAX_LONG_SKIP); + wordCnt0 -= wordCnt; + *dst++ = LONG_OP; + *dst++ = (UBYTE)wordCnt; /* Low byte of UWORD. */ + *dst++ = wordCnt >> 8; /* High byte of UWORD. */ + } + } + wordCnt = 1; + goto beDump; /* "Dump 1" so far. */ + } + /* --- Byte skippable. */ + /* --- Final Skip is NOT output prior to Stop. */ + CLIP_X(stop); + goto inSkip; /* Skip may be any length up to 64KB-1. */ + +stop: + if (FP_OFF(dst) > finalDst - 3) + goto incompressible; /* "3" is length of Stop. */ + *dst++ = LONG_OP; /* Stop represented as "LongOp #0". */ + /* 68000 note: Don't use word op to put cnt, as may not be + * word-aligned. + */ + *dst++ = 0; /* High byte of cnt==0. */ + *dst++ = 0; /* Low byte of cnt==0. */ + deltaX.nBytes = dst - dst0; + /* "body size": # bytes in Body, excluding any header. + * NOTE: incompressible tests guarantee that deltaX.nBytes won't quite + * reach 64 KB, which would overflow UWORD. + */ + return TRUE; /* deltaX.nBytes is set as a side-effect. */ + /* NOTE: if deltaX.nBytes == 3, all there is is a Stop. + * Client may wish to set deltaX.nBytes == 0 & have no data in this + * case. + */ + +incompressible: + return FALSE; +#endif /* RunSkipDump in C. */ +} + + +/* --------------- AbandonChangesMaybeExit --------------- + */ +local void AbandonChangesMaybeExit(BOOL closeAndExit) +{ + CUR_LP = (UWORD)-1; /* None loaded -- abandon lpBuffer. */ + curLpIsDirty = FALSE; + /* --- Drastic solution -- don't try to continue. */ + if (closeAndExit) + DiskFullChangesLostExit(); /* closes lp. */ +} + + +/* --------------- FindFreeLp --------------- + */ +local UWORD FindFreeLp(void) +{ + register UWORD nLp; + + for (nLp = 0; nLp < nLps; nLp++) { + if (lpfTable[nLp].nRecords == 0) + return nLp; /* Found empty lp in middle of file. */ + } + if (nLps == MAX_LARGE_PAGE) { + BugExit("LPK"); /* "Too many pages in anim"); */ + } + return nLps++; /* Page # of next lp to use (lps #d from 0). */ +} + + +/* --------------- LpTableToLpBufferHeader --------------- + * Assuming space made available, put correct contents in header, + * based on lpTable & variables. + * ASSUMES LP_N_RECS & LP_N_BYTES has already been changed to reflect # recs + * & new contents in lp. + * Copy these changes to lpfTable, so FindLargePageForRecord will see truth. + */ +local void LpTableToLpBufferHeader(void) +{ + far_movmem(dataseg(), (UWORD)&curLpX.x, lpSeg, 0, sizeof(LP_DESCRIPTOR)); + *WORD_FAR_PTR(lpSeg, sizeof(LPageHeaderFixed) - 2) = 0; /* no cont'. */ + /* ASSUMES nByteContinuation is last field. */ + far_movmem(dataseg(), (UWORD)lpTable, lpSeg, sizeof(LPageHeaderFixed), + sizeof(LP_TABLE_ELEMENT) * LP_N_RECS); + + lpfTable[CUR_LP] = curLpX.x; /* IMPORTANT! */ +} + + +/* --------------- UpdateLpBufferHeader --------------- + * Shift the data in the lp buffer, and re-write the header, so that it + * matches lpTable. + */ +local void UpdateLpBufferHeader(void) +{ + UWORD newRecAddr0 = LP_HEADER_SIZE(LP_N_RECS); + + far_movmem_same_seg(lpSeg, LP_REC_ADDR0, newRecAddr0, LP_N_BYTES); + + /* --- "current record" info has changed location. */ + REC_ADDR = REC_ADDR - LP_REC_ADDR0 + newRecAddr0; + BODY_ADDR = BODY_ADDR - LP_REC_ADDR0 + newRecAddr0; + + LP_REC_ADDR0 = newRecAddr0; + LpTableToLpBufferHeader(); + curLpIsDirty = TRUE; +} + + +/* --------------- WriteNewLp --------------- + * Extract a portion of lp buffer as a new lp. + * Return FAIL if trouble writing (presumably, disk is full). + */ +#define SV_BASE_REC svLpX.x.baseRecord +local WORD WriteNewLp(UWORD startRecord, UWORD endRecord) +{ + register UWORD nRecord; + WORD result; + LpX svLpX; + + svLpX = curLpX; + CUR_LP = FindFreeLp(); + + lpTableOffset = startRecord - SV_BASE_REC; + /* Fake out WriteCurLp. */ + + /* NOTE: need unmodified startRecord & endRecord for this. */ + LP_BASE_REC = startRecord; + LP_N_RECS = endRecord - startRecord + 1; + + startRecord -= SV_BASE_REC; + endRecord -= SV_BASE_REC; + + /* NOTE: use startRecord/endRecord RELATIVE to SV_BASE_REC. */ + /* --- Get from real LP_REC_ADDR0 to fake LP_REC_ADDR0 (at + * startRecord). + */ + for (nRecord = 0; nRecord < startRecord; nRecord++) { + LP_REC_ADDR0 += lpTable[nRecord]; + } + + /* --- Sum of bytes for desired records. */ + LP_N_BYTES = 0; /* So far */ + for (nRecord = startRecord; nRecord <= endRecord; nRecord++) { + LP_N_BYTES += lpTable[nRecord]; + } + result = WriteCurLp(); /* New lp. */ + + lpTableOffset = 0; /* Done faking out WriteCurLp. */ + curLpX = svLpX; /* Restore access to "current lp". */ + /* Including LP_REC_ADDR0! */ + return result; +} + + +/* --------------- CurRec_NewBody --------------- + * Place a new body into CurRec. If necessary, records before and/or after + * current are moved into new lps. + * IMPLICIT INPUT: curRecX, deltaX, lpSeg, curLpX. + */ +local void CurRec_NewBody(void) +{ + WORD result = SUCCESS; + + /* 1. Determine how much room for new body. */ +#define AVAIL_BODY_SIZE (GAP_SIZE + BODY_BYTES) + UWORD availBodySize = AVAIL_BODY_SIZE; + BOOL newExtraBytes = (EXTRA_BYTES == 0); + + /* If there was no record at all, create an ID+FLAGS UWORD. */ + if (newExtraBytes) + availBodySize -= 2; /* For ID+FLAGS. */ + + /* 2A. If won't fit, move other records to new lps. */ + if (deltaX.nBytes > availBodySize) { + /* --- Dumbest possible approach: split into 3 buffers. */ + UWORD newRecAddr0 = LP_HEADER_SIZE(1); + + /* --- Following records. */ + if (CUR_REC != LAST_RECORD_IN_BUF && result == SUCCESS) { + result = WriteNewLp(CUR_REC + 1, LAST_RECORD_IN_BUF); +/* if (result != SUCCESS) goto fail; TBD... */ + /* Cur lp now has just base-rec thru cur-rec. */ + LP_N_RECS = (CUR_REC + 1) - LP_BASE_REC; + LP_N_BYTES = (REC_ADDR + REC_BYTES) - LP_REC_ADDR0; + UpdateLpBufferHeader(); + availBodySize = AVAIL_BODY_SIZE; + if (newExtraBytes) + availBodySize -= 2; /* For ID+FLAGS. */ + if (deltaX.nBytes <= availBodySize) + goto nowFits; + } + if (CUR_REC > LP_BASE_REC && result == SUCCESS) + result = WriteNewLp(LP_BASE_REC, CUR_REC - 1); /* Previous records */ + + if (result != SUCCESS) { + /* TBD: Don't use new lps. */ + BugExit("NewLp"); + } + /* --- Prepare lp with just CUR_REC. */ + LP_BASE_REC = CUR_REC; + LP_N_RECS = 1; + if (newExtraBytes) + EXTRA_BYTES = 2; + else + far_movmem(lpSeg, REC_ADDR, lpSeg, newRecAddr0, EXTRA_BYTES); + BODY_BYTES = deltaX.nBytes; + LP_REC_ADDR0 = REC_ADDR = newRecAddr0; + BODY_ADDR = REC_ADDR + EXTRA_BYTES; + REC_BYTES = EXTRA_BYTES + BODY_BYTES; + LP_N_BYTES = lpTable[0] = REC_BYTES; + LpTableToLpBufferHeader(); /* Buffer now has single frame in + * it! */ + /* NOTE: should NOT do i/o, + * just preparing variables. + */ + } else { /* 2B. Make room for new body, & set + * variables. */ + UWORD curRecLimit; + UWORD sizeChange; + +nowFits: + curRecLimit = REC_ADDR + REC_BYTES; + sizeChange = deltaX.nBytes - BODY_BYTES; + /* NOTE: May be NEGATIVE number. Relying on 16-bit wrapping! */ +#define BYTES_AFTER_BODY (LP_TOTAL_BYTES - curRecLimit) + + if (newExtraBytes) { + EXTRA_BYTES = 2; + sizeChange += EXTRA_BYTES; + BODY_ADDR = REC_ADDR + EXTRA_BYTES; + /* No longer access old body. */ + } +#define NEW_REC_LIM (curRecLimit + sizeChange) + /* ASSUMES body is last field in record. */ + /* ASSUMES lp starts at addr 0 w/i lpSeg. */ + + far_movmem_same_seg(lpSeg, curRecLimit, NEW_REC_LIM, BYTES_AFTER_BODY); + BODY_BYTES = deltaX.nBytes; /* When newExtra, not same as + * sizeChange */ + REC_BYTES += sizeChange; + LP_N_BYTES += sizeChange; + lpTable[CUR_REC - LP_BASE_REC] = REC_BYTES; + } + + /* 3. Get new body into lp buffer. */ + if (newExtraBytes) + *WORD_FAR_PTR(lpSeg, REC_ADDR) = DEFAULT_BITMAP_ID_FLAGS; + far_movmem(deltaX.seg, deltaX.addr, lpSeg, BODY_ADDR, BODY_BYTES); + curLpIsDirty = TRUE; +} + +/* --------------- DAllocBiggest --------------- + * Allocate the requested block. If can't, find and allocate + * the biggest possible. + * TBD: Is there a DOS or BIOS call to find biggest available block? + * RETURNS seg # of allocation, NULL if failed. + * SIDE_EFFECT: sets "*allocSizeP" to # bytes actually allocated. + */ +local UWORD DAllocBiggest(UWORD nBytes, UWORD * allocSizeP) +{ + UWORD seg, allocParas; + + /* --- First, try to allocate full request, kicking out other stuff + * if necessary. + */ + seg = DAlloc(nBytes); + if (seg) { + *allocSizeP = nBytes; + return seg; + } + + /* --- Couldn't get all, get what we can. */ + +#define N_PARAGRAPHS(nBytes) ( (nBytes >> 4) + (nBytes & 0x0f ? 1 : 0) ) + /* NOTE: Don't do as "(nBytes+15) >> 4", since may overflow UWORD. */ + + seg = allocsome(N_PARAGRAPHS(nBytes), &allocParas); + *allocSizeP = allocParas << 4; + if (!seg) /* Only happens if memory completely full. */ + *allocSizeP = 0; + return seg; +} + + +/* --------------- ComputeDelta --------------- + * Compute delta into a large temporary buffer. + * IMPLICIT INPUT: curRecX, lpSeg. + * SIDE_EFFECT: sets deltaX. + */ +local void ComputeDelta(void) +{ + BOOL skipPermitted = (curFrame != FIRST_FRAME_N); + + /* Disallow skip code on first frame, so don't need to blank + * frame before drawing delta -- will overwrite every pixel + * via Dumps and Runs. + */ + + deltaX.seg = allocSeg; + deltaX.addr = 0; + deltaX.limit = MAX_LARGE_PAGE_SIZE; + +bigEnough: + if (!ComputeDeltaX(skipPermitted)) { + /* Handle incompressible frame. */ + UWORD rawSize = N_BYTES_IN_BITMAP; + + deltaX.nBytes = rawSize + sizeof(UWORD); + /* UWORD for header, then raw dump of screen data. */ + if (deltaX.limit - deltaX.addr < deltaX.nBytes) + BugExit("LPM"); + /* "Buffer too small for incompressible frame"); */ + *WORD_FAR_PTR(deltaX.seg, deltaX.addr) = BMBODY_UNCOMPRESSED; + /* header contains type "uncompressed". */ + far_movmem(hidbmSeg, 0, deltaX.seg, deltaX.addr + 2, rawSize); + } +} + + +/* --------------- WriteFinalAnimFrame --------------- + * Compute and transfer to file the current delta-frame, + * which must be the last frame in the file. + * (If not last frame, must use WriteAnimFrameAndReadNext). + */ +void WriteFinalAnimFrame(void) +{ + ComputeDelta(); + CurRec_NewBody(); /* Implicit: deltaX. */ +} + +/* --------------- WriteAnimFrameAndReadNext --------------- + * Transfer to file the specified delta-frame. + * Also compute & transfer the next delta-frame, as it is affected by the + * changes in the current anim-frame. + * TBD: Some caller's may wish to MaybeWriteCurLp, so that lp buffer is + * free for immediate use by menus/pop-ups. + */ +void WriteAnimFrameAndReadNext(void) +{ + ComputeDelta(); + + /* ---2. Exchange prevFrame with new-frame in hidbm. + * Because new-frame is next-frame's prevFrame. + */ + far_swapmem(BSEG(&hidbm), 0, prevFrameSeg, 0, N_BYTES_IN_BITMAP); + + /* ---3. Apply old-delta to hidbm. (Convert prev- to old- frame.) */ + PlayDeltaFrame(&hidbm); /* Implicit: curRecX, lpSeg. */ + CurRec_NewBody(); /* Implicit: deltaX. */ + + /* ---4. If at anim end, simply set up first frame. */ + /* FUTURE: may compute delta between last & first frame. + * Could store in special frame before the normal first frame. + */ + curFrame++; + if (curFrame > LAST_FRAME_N) { + FirstAnimFrame0(); + goto done; + } + + /* ---5. Read & apply next delta. */ + ReadLpfFrame(curFrame); + PlayDeltaFrame(&hidbm); /* Convert old-frame to next-frame. */ + + /* ---6. Recompute next-frame's delta (since prevFrame is new.) */ + ComputeDelta(); + CurRec_NewBody(); + +done: ; +} + +/* --------------- AddFrame --------------- + * ASSUMES current frame is last frame in lpfile. + * Add an identical frame after it, and make it current. + * NOTE: Be careful to leave valid cur rec & cur lp variables. + */ +void AddFrame() +{ + UWORD afterRecord = CUR_REC; /* Hold, in case lp changes affect CUR_REC.*/ + WORD afterFrame = curFrame; + + if ( MAX_RECORDS_PER_LP - LP_N_RECS < 1 || /* lpTable overflow*/ + MAX_LARGE_PAGE_SIZE - LP_N_BYTES < + LP_HEADER_SIZE(LP_N_RECS+1) /* lp overflow */ + ) { + /* --- Create new lp, with only an empty frame. */ + MaybeWriteCurLp(); + + LP_BASE_REC = afterRecord + 1; + LP_N_BYTES = 0; + setmem( &lpTable[0], sizeof(LP_TABLE_ELEMENT), 0 ); + /* Zero the new frame. */ + + /* --- SWITCH ACCESS from current lp to new lp. */ + CUR_LP = FindFreeLp(); + LP_N_RECS = 1; + + WriteCurLp(); + } else { + /* Add frame to current lp. + * Zero the new frame. record # relative to CUR_LP's base rec. + */ + lpTable[afterRecord+1 - LP_BASE_REC] = 0; + LP_N_RECS += 1; + } + totalNRecords += 1; + AnimFramesX(animFrames + 1); + + UpdateLpBufferHeader(); + ReadLpfFrame(curFrame = afterFrame+1); /* Make this frame current. */ +} + +/* --------------- ConvertFinalFrameToLastDelta --------------- + */ +ConvertFinalFrameToLastDelta() +{ + animFrames--; + lpfHdr.hasLastDelta = lpfHdr.lastDeltaValid = TRUE; + curFrame--; +} diff --git a/tools/old/anm/MAIN.H b/tools/old/anm/MAIN.H new file mode 100644 index 000000000..a6ab47051 --- /dev/null +++ b/tools/old/anm/MAIN.H @@ -0,0 +1,162 @@ +/*--main.h---------------------------------------------------------- + * Main include file for ANIM2PCX. + * Note: all files editted with tab stops every 4 spaces. + */ + +/* ------------------------------------------------------------------------ + * Typedefs for portability. + */ + +typedef char BOOL; /* 0==FALSE, 1==TRUE */ +typedef char BYTE; /* signed 8-bit number */ +typedef unsigned char UBYTE; /* unsigned 8-bit number */ +typedef int WORD; /* signed 16-bit number */ +typedef unsigned int UWORD; /* unsigned 16-bit number */ +typedef long LONG; /* signed 32-bit number */ +typedef unsigned long ULONG; /* unsigned 32-bit number */ +typedef void (*ProcHandle)(); + +/* --- enable argument checking in Microsoft's include files */ +#define LINT_ARGS + +/*-----------------------------------------------------------------*/ + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef FALSE +#define FALSE 0 +#define TRUE 1 +#endif + +#define FAIL 1 +#define SUCCESS 0 + +#define MAX_INTEGER 32767 + +#define HIWORD(longValue) ((UWORD)((longValue) >> 16)) +#define LOWORD(longValue) ((UWORD)(longValue)) + +/* --- this depends on the memory model we're using */ +/* Within the 64 KB data segment. */ +#define NULL_DATAPTR 0 +/* #define NULL_PROCPTR ((BYTE far *) NULL) */ +#define NULL_PROCPTR ((ProcHandle) NULL) + +/* --- separate Microsoft "far" ptrs into their segment & offset parts */ +#define FP_SEG(fp) (*((UWORD *)&(fp) + 1)) +#define FP_OFF(fp) (*((UWORD *)&(fp))) + +/* --- combine segment & offset into a "far" ptr */ +#define BYTE_FAR_PTR(seg,off) ((BYTE far *)(((LONG)(seg)<<16)+(off))) +#define WORD_FAR_PTR(seg,off) ((WORD far *)(((LONG)(seg)<<16)+(UWORD)(off))) + +/*----------------------------------------------------------------------*/ + +#define SWAP(a,b) { (a) ^= (b); (b) ^= (a); (a) ^= (b); } +#define ORDER(a,b) if ((a)>(b)) SWAP((a),(b)) +#define MAX(a,b) ((a)>(b)?(a):(b)) +#define MIN(a,b) ((a)<(b)?(a):(b)) +#define ABS(a) ((a)>0?(a):-(a)) +#define DIV_ROUND(x, d) (((x) + ((d) >> 1)) / (d)) /* ASSUME d > 0. */ +#define EVEN_UP(a) ( ((a)+1) & ~1 ) + /* Even number >= a. */ + +#define CHECK_DOS(fn) if ((fn) == -1) goto doserr + +/* ------------------------------------------------------------------------ + * Graphics data structures. + */ + +typedef struct { + WORD x, y; +} POINT; +typedef struct { + WORD w, h; +} Dims; +typedef struct { + WORD x, y, w, h; +} Box; + +/* + * kludge for easy access to individual red/green/blue values within a LONG. + * NOTE: this depends on 808x byte order being low-high. + */ +typedef struct { + UBYTE blue, green, red, unused1; +} LONG_RGB; + +/* --- Max # colors visible on screen. */ +#define MAX_COLORS 256 + +/* --- Max # planes that a bitmap can have. */ +#define MAX_PLANES 4 + +/* --- BITMAP structure */ +typedef struct { + WORD width; /* Width in bytes of each row. Must be even. */ + Box box; /* Pixel bounds of bitmap. (x,y == 0.) */ + WORD planes; /* Number of planes. */ + UWORD seg[MAX_PLANES]; /* SEG where each plane is allocated. */ +} BITMAP; + +typedef struct { + BITMAP *bitmap; + WORD nPlanes; /* used only in FMT_ONLY mode */ + UBYTE xpcolor; +} MaskBM; + +typedef struct { + UWORD w, h; /* raster width & height in pixels */ + UBYTE nPlanes; /* # source bitplanes */ +} BitMapHeader; + +/* -------------------------------------------------------------------------- + * Description of screen format "f" (320 x 200, 256-colors). + */ +#define ppb 1 /* pixels per byte */ +#define ppb_minus1 0 /* ppb - 1 */ +#define ppb_shift 0 /* 1 << ppb_shift == ppb */ +#define bpp 8 /* bits per pixel */ +#define bpp_minus1 7 /* bpp - 1 */ +#define bpp_shift 3 /* 1 << bpp_shift == bpp */ +#define curDepth 1 /* Single plane in byte-per-pixel format. */ +#define white_color 0xff /* register # for default white. */ + +/* ----------------------------------------------------------------------- + * Number of chars in an MS-DOS filename or directory (path) name. + */ +#define FILENAME_ROOT_LENGTH 8 +#define FILENAME_SUFFIX_LENGTH 3 +#define SEQUENCE_ROOT_LENGTH 4 /* XXXX in XXXX0001.PCX, XXXX0002.PCX...*/ +#define SEQUENCE_DIGITS_LENGTH (FILENAME_ROOT_LENGTH - SEQUENCE_ROOT_LENGTH) +#define FILENAME_LENGTH 12 /* ROOT + '.' + SUFFIX */ +#define PATHNAME_LENGTH 66 /* drive + path (no filename) */ + +/* ----------------------------------------------------------------------- + * Screen Format "f". + */ +#define N_COLUMNS 320 +#define N_LINES 200 +#define N_BYTES_IN_BITMAP (N_COLUMNS * N_LINES) + +/* ----------------------------------------------------------------------- + * Buffered i/o. + */ +void OpenIOBuffer(BOOL forWriting); +void CloseIOBuffer(WORD file); +WORD GFlush(WORD file); +LONG GSeek(WORD file, LONG count, WORD seekType); +WORD GRead(WORD file, UBYTE *buffer, UWORD nBytes); +WORD GWrite(WORD file, UBYTE *buffer, UWORD nBytes); + +/* ----------------------------------------------------------------------- + * Procedures that need to be declared so parameters or return values of + * correct type. + */ +WORD far *BMLineStart(BITMAP*, WORD, WORD); + +/* --- mnemonic names for Microsoft library functions */ +#define movmem(source,dest,length) memmove(dest,source,length) +#define setmem(ptr,length,value) memset(ptr,value,length) diff --git a/tools/old/anm/MAIN.INC b/tools/old/anm/MAIN.INC new file mode 100644 index 000000000..bdad78264 --- /dev/null +++ b/tools/old/anm/MAIN.INC @@ -0,0 +1,100 @@ +;----------------------------------------------------------------- +; prism.inc +; --------- +; Assembly-language equivalent of prism.h. +; Changed for use with file conversion program. +; - changed MAX_PLANES from 4 to 8. Altered BITMAP_OFFS, SIZEOF_BITMAP +; accordingly. +;----------------------------------------------------------------- + +; comment these two out to eliminate debugging code! +; DEBUGGING equ 1 +; extrn _crash:far + +; --- miscellaneous constants +POSITIVE equ 1 +NEGATIVE equ 0 + +; --- display types. also in test.h. +EGA_640x200_16 equ 0 +EGA_640x350_16 equ 1 +CGA_320x200_4 equ 2 +CGA_640x200_2 equ 3 +EGA_320x200_16 equ 4 +HERC_720x348_2 equ 5 +MCGA_640x480_2 equ 6 +VGA_640x480_16 equ 7 +MCGA_320x200_256 equ 8 +TANDY_320x200_16 equ 9 +VGA_320x200_16 equ 10 ; same as EGA mode, but with VGA color control +VGA_640x200_16 equ 11 ; same as EGA mode, but with VGA color control +VGA_640x350_16 equ 12 ; same as EGA mode, but with VGA color control + +MAX_LINE_SIZE equ 320 +MAX_COLORS equ 256 +MAX_PLANES equ 8 +MAX_PLANES_SHIFT equ 3 ; MAX_PLANES expressed as left shift + +; --- drawing modes. +MODE_COPY equ 0 +MODE_XOR equ 1 +MODE_COLOR equ 2 +MODE_SWAP equ 3 +MODE_SHADE_UP equ 4 +MODE_SHADE_DOWN equ 5 +MODE_BMCOPY equ 6 +MODE_INV_COLOR equ 7 +; these two are only used by smear_copy +MODE_SMEAR equ 8 +MODE_BLEND equ 9 +MODE_SHADE_COPY equ 10 + +; --- offsets to parts of the BITMAP structure +; NOTE: drawchar.asm contains hard-coded inits for a BITMAP +BITMAP_FLAGS equ 0 +BITMAP_WIDTH equ 2 +BITMAP_BOX equ 4 +BITMAP_BOX_X equ 4 +BITMAP_BOX_Y equ 6 +BITMAP_BOX_W equ 8 +BITMAP_BOX_H equ 10 +BITMAP_PLANES equ 12 +BITMAP_YTABLE equ 14 +BITMAP_SEG equ 16 +BITMAP_OFFS equ 32 +; --- size of the BITMAP structure +SIZEOF_BITMAP equ 34 + +; --- offsets to parts of the Box structure +BOX_X equ 0 +BOX_Y equ 2 +BOX_W equ 4 +BOX_H equ 6 +; --- size of the Box structure +SIZEOF_BOX equ 8 + +; --- offsets to parts of the TMPRAS structure +TMPRAS_SEG equ 0 +TMPRAS_SIZE equ 2 + +; --- offsets to parts of the RASTPORT structure +RASTPORT_BITMAP equ 0 +RASTPORT_MODE equ 2 +RASTPORT_COLOR equ 4 + +; bitmap.flags values +EGA_BANK_SWITCH equ 1 +LINEAR_BITMAP equ 2 +NEED_BYTE_ALIGNMENT equ 4 + +; properties of screen formats +COLOR_CYCLE equ 1h ; can color cycle +MONO_MODE equ 2h ; mode is on mono screen +CGA_MODE equ 4h ; mode needs CGA adapter +EGA_MODE equ 8h ; mode needs EGA adapter +MCGA_MODE equ 10h ; mode needs MCGA adapter +VGA_MODE equ 20h ; mode needs VGA adapter +TANDY_MODE equ 40h ; mode needs TGA (Tandy) adapter + +; from event.c +MAX_CURSOR_H equ 11 diff --git a/tools/old/anm/MISC.C b/tools/old/anm/MISC.C new file mode 100644 index 000000000..90062c10f --- /dev/null +++ b/tools/old/anm/MISC.C @@ -0,0 +1,255 @@ +/*--misc.c---------------------------------------------------------- + * Miscellaneous routines. + */ + +#include "main.h" +#include "anim.h" + +#define local static + +extern BOOL EscFlag; +extern WORD curFrame; +extern BITMAP hidbm, prevFrame; + +/* --------------- BugExit, EmergencyExit --------------- + */ +BugExit(char *s) +{ + printf("Program Bug: %s.\n", s); + exit(1); +} + +EmergencyExit(char *s) +{ + printf("%s.\n", s); + exit(1); +} + +NotEnoughMemExit() +{ + EmergencyExit("Not enough memory to run this program"); +} + +/* --------------- AbortKeyHit, CheckAbort --------------- + */ +#define ESC 0x1b + +local BOOL AbortKeyHit() +{ + register WORD i; + + while (char_avail()) { /* Consume keys, looking for ESC. */ + i = get_char(); + if (i == ESC) { + EscFlag = TRUE; /* Remember ESC was hit. */ + return TRUE; + } + } + return FALSE; /* Abort key not seen. */ +} + +/* Once abort key has been hit, further checks see EscFlag. */ +BOOL CheckAbort() +{ + return (EscFlag || AbortKeyHit()); +} + +/* --------------- --------------- */ +#define bitmap_offs(bm, x, y) (x + (bm)->width * (y)) +#define BytesNeeded(pix) EVEN_UP(pix) /* one byte-per-pixel */ + /* Must be whole # words. */ + +/* --------------- BMLineStart --------------- + * Returns a far pointer to the start of line y + * of the given plane in the bitmap. + */ + +WORD far *BMLineStart(BITMAP *bm, WORD y, WORD plane) +{ + return (WORD_FAR_PTR(bm->seg[plane], bitmap_offs(bm, 0, y))); +} + +/* --------------- init_bitmap --------------- + */ +init_bitmap(bm, width, height) +register BITMAP *bm; +WORD width, height; +{ + bm->width = BytesNeeded(width); + bm->box.x = 0; + bm->box.y = 0; + bm->box.w = width; + bm->box.h = height; + bm->planes = curDepth; +} + +/* --------------- NewBitMap --------------- + * CAUTION: only call when have NOT allocated bm->seg[]'s. + */ +NewBitMap(BITMAP *bm, WORD width, WORD height) +{ + init_bitmap(bm, width, height); + bm->seg[0] = DAlloc(N_BYTES_IN_BITMAP); + if (!bm->seg[0]) + NotEnoughMemExit(); +} + +/* --------------- SetBitMap --------------- + */ +void SetBitMap(BITMAP *bm, WORD color) +{ + far_setmem(bm->seg[0], 0, N_BYTES_IN_BITMAP, color); +} + +/* --------------- FirstAnimFrame --------------- + * Switch to first frame for editing. + */ + +/* Read into lpBuffer, but don't transfer to hidbm. + * This gets all the pointers correctly set-up, so that hidbm can + * become the new first frame (by calling AnimSetDirtyBox). + */ +FirstAnimFrame00() { + curFrame = FIRST_FRAME_N; + ReadLpfFrame(curFrame); + } + + +FirstAnimFrame0() { + /* --- Clear junk from prevFrame. */ + far_setmem(BSEG(&prevFrame), 0, N_BYTES_IN_BITMAP, white_color); + + FirstAnimFrame00(); + PlayDeltaFrame(&hidbm); + } + +/* --------------- CopyHidbmToPrevFrame --------------- + */ +local void CopyHidbmToPrevFrame(void) { + far_movmem( BSEG(&hidbm), 0, + BSEG(&prevFrame), 0, N_BYTES_IN_BITMAP ); + } + +/* --------------- NextAnimFrame0 --------------- + * Switch to next frame for editing. + */ +NextAnimFrame0() { + curFrame++; + + if (curFrame > LAST_FRAME_N) + FirstAnimFrame0(); + else { + /* (old) current frame is (next) prevFrame. + * Don't use PlayDeltaFrame, because didn't keep Delta in RAM. */ + CopyHidbmToPrevFrame(); + ReadLpfFrame(curFrame); + PlayDeltaFrame(&hidbm); + /* Convert old current frame to new current frame. */ + } +} + +/* ------------------------------------------------------------------------- + * Disk i/o with critical error detection. + * ------------------------------------------------------------------------- + */ +/* returns -1 if it can't read the full number of bytes */ +int readfull(int file, char *buffer, unsigned int count) { + return (readdos(file,dataseg(),buffer,count) == count) ? 0: -1; + } + +/* returns -1 if it can't read the full number of bytes */ +int readdosfull(UWORD file, UWORD seg, UWORD buffer, UWORD count) { + return (readdos(file,seg,buffer,count) == count) ? 0: -1; + } + +/* returns -1 if it can't write the full number of bytes */ +int writefull(int file, char *buffer, unsigned int count) { + return (writedos(file,dataseg(),buffer,count) == count) ? 0: -1; + } + +/* returns -1 if it can't write the full number of bytes */ +int writedosfull(UWORD file, UWORD seg, UWORD buffer, UWORD count) { + return (writedos(file,seg,buffer,count) == count) ? 0: -1; + } + +long lseekdos(int file, long offset, int origin) { + long result = lseek(file,offset,origin); + return result; + } + +/*----------------------------------------------------------------- + * --------------- do_num_to_string ------------------------------- + * Convert a number to a string. Parameters: + * UWORD num = # to convert to string. + * char *string = Ptr to string where you want the #. + * UWORD length = # of chars you want in the resulting string. Set to -1 + * if you don't require any specific string length. If the string + * is too short, it will be padded with blanks on the left. If it + * is too long, it will be chopped off on the right. + * BOOL negative = Set to TRUE if you want numbers > 32767 to be printed + * as negative (with a leading "-"), or FALSE otherwise. + */ + +/* TRUE before calling do_num_to_string, if want padding with 0's + * instead of blanks. Must set back to FALSE when done, so + * other clients will get ' 's. + */ +local BOOL padWithZeroes = FALSE; + +void do_num_to_string(UWORD num, char *string, UWORD length, BOOL negative) +{ + UWORD temp; + register UWORD index, i; + BOOL start; + + index = 0; + + /* --- does caller want negative # printed with leading '-'? */ + if (negative && num >= 0x8000) { + if (index >= length) goto terminate; + num = -num; + string[index++] = '-'; + } + + /* --- convert the # to a string */ + if (num == 0) { + if (index >= length) goto terminate; + string[index++] = '0'; + } else { + start = FALSE; + for (i = 10000; i > 0; i /= 10) { + temp = (num / i); + if (temp || start) { + /* --- if string has reached max length, stop */ + if (index >= length) goto terminate; + string[index++] = temp + '0'; + start = TRUE; + } + num %= i; + } + } + + /* --- terminate the string */ +terminate: + string[index] = 0; + + /* --- if caller wants string to be at least a certain length, do it */ + i = strlen(string); + if ((WORD)i < (WORD)length) { + /* --- string is too short, so add spaces to left */ + while ((WORD)i < (WORD)length) { + movmem(string, string + 1, i + 1); + string[0] = (padWithZeroes ? '0' : ' '); + ++i; + } + } +} + +/* --------------- num_to_string_zeroes --------------- + * Specified length, no negative, padding with zeroes. + */ +void num_to_string_zeroes(UWORD num, char *string, UWORD length) { + padWithZeroes = TRUE; + do_num_to_string(num, string, length, FALSE); + padWithZeroes = FALSE; +} diff --git a/tools/old/anm/MISCA.ASM b/tools/old/anm/MISCA.ASM new file mode 100644 index 000000000..5fb49a6b4 --- /dev/null +++ b/tools/old/anm/MISCA.ASM @@ -0,0 +1,848 @@ +;----------------------------------------------------------------- +; misca.asm +; --------- +; Miscellaneous minor assembly-language routines. +;----------------------------------------------------------------- + + include asm.inc + include main.inc + include ega.inc + + HEADER misca + +;----------------------------------------------------------------- + +; --- seg & offs of BIOS equipment flag word (we only use its lower byte) +EQUIP_SEG equ 40h +EQUIP_OFFS equ 10h + + DSEG + +; --- Most recent i/o error code. NOTE: if there was not an error, +; this is undefined. + public _ioError +_ioError dw 0 + +; --- used by shift_right + public right_shift_masks +right_shift_masks equ this word + db 11111111b, 11111111b + db 01111111b, 11111111b + db 00111111b, 11111111b + db 00011111b, 11111111b + db 00001111b, 11111111b + db 00000111b, 11111111b + db 00000011b, 11111111b + db 00000001b, 11111111b + db 00000000b, 11111111b + db 00000000b, 01111111b + db 00000000b, 00111111b + db 00000000b, 00011111b + db 00000000b, 00001111b + db 00000000b, 00000111b + db 00000000b, 00000011b + db 00000000b, 00000001b + +; --- used by shift_left +left_shift_masks equ this word + db 11111111b, 11111111b + db 11111111b, 11111110b + db 11111111b, 11111100b + db 11111111b, 11111000b + db 11111111b, 11110000b + db 11111111b, 11100000b + db 11111111b, 11000000b + db 11111111b, 10000000b + db 11111111b, 00000000b + db 11111110b, 00000000b + db 11111100b, 00000000b + db 11111000b, 00000000b + db 11110000b, 00000000b + db 11100000b, 00000000b + db 11000000b, 00000000b + db 10000000b, 00000000b + + ENDDS + +;----------------------------------------------------------------- + + PSEG misca + +;----------------------------------------------------------------- +; WORD dataseg (); +; Returns the current value of the DS register. +;----------------------------------------------------------------- + + public _dataseg + STARTPROC _dataseg + + mov ax,ds + ret + + ENDPROC _dataseg + +;----------------------------------------------------------------- +; WORD codeseg (); +; Returns the current value of the CS register. +;----------------------------------------------------------------- + + public _codeseg + STARTPROC _codeseg + + mov ax,cs + ret + + ENDPROC _codeseg + +;----------------------------------------------------------------- +; void far_setmem (seg, offs, length, value); +; WORD seg, offs; +; UWORD length; +; WORD value; +; Set length bytes starting at seg:offs to value. +; NOTE: This could be optimized by using stosw if possible. +;----------------------------------------------------------------- + + public _far_setmem + STARTPROC _far_setmem + + push bp + mov bp,sp + push es + push si + push di + + mov es,ARGB[bp] ; segment + mov di,ARGB+2[bp] ; offset + mov cx,ARGB+4[bp] ; count + mov al,ARGB+6[bp] ; value + jcxz far_setmem_done + cld + rep stosb +far_setmem_done: + pop di + pop si + pop es + pop bp + ret + + ENDPROC _far_setmem + +;----------------------------------------------------------------- +; void far_movmem (sseg, soffs, dseg, doffs, length); +; WORD sseg, soffs, dseg, doffs; +; UWORD length; +; Move length bytes starting at sseg:soffs to dseg:doffs. +; This proc doesn't handle overlapping source & dest. +; NOTE: Could speed this up by using WORD move! +;----------------------------------------------------------------- + + public _far_movmem + STARTPROC _far_movmem + + push bp + mov bp,sp + push ds + push es + push si + push di + + mov ds,ARGB[bp] ; source seg + mov si,ARGB+2[bp] ; source offs + mov es,ARGB+4[bp] ; dest seg + mov di,ARGB+6[bp] ; dest offs +mov0: + mov cx,ARGB+8[bp] ; # bytes + jcxz far_movmem_done +move_left_to_right: + cld + rep movsb +far_movmem_done: + pop di + pop si + pop es + pop ds + pop bp + ret + + ENDPROC _far_movmem + +;----------------------------------------------------------------- +; void far_movmem_same_seg(UWORD seg, UWORD soffs, UWORD doffs, UWORD length); +; Move length bytes starting at seg:soffs to seg:doffs, +; dealing with possible OVERLAP -- +; when destination starts AFTER source, move RIGHT-TO-LEFT. +; NOTE: Could speed this up by using WORD move! +; NOTE: must have same register push/pop sequence as "_far_movmem". +;----------------------------------------------------------------- + + public _far_movmem_same_seg + STARTPROC _far_movmem_same_seg + + push bp + mov bp,sp + push ds + push es + push si + push di + + mov ds,ARGB[bp] ; source seg + mov si,ARGB+2[bp] ; source offs + mov es,ARGB[bp] ; dest seg + mov di,ARGB+4[bp] ; dest offs + mov cx,ARGB+6[bp] ; # bytes + jcxz far_movmem_same_seg_done + + cmp di,si + jbe move_left_to_right + + std ; Backwards through memory. + add si,cx + dec si ; Address of last byte. + add di,cx + dec di ; Address of last byte. + rep movsb +far_movmem_same_seg_done: + cld + pop di + pop si + pop es + pop ds + pop bp + ret + + ENDPROC _far_movmem_same_seg + +;----------------------------------------------------------------- +; void far_swapmem (sseg, soffs, dseg, doffs, length); +; WORD sseg, soffs, dseg, doffs; +; UWORD length; +; Swap length bytes starting at sseg:soffs with dseg:doffs. +; This proc doesn't handle overlapping source & dest. +; NOTE: Could speed this up by using WORD operations! (and by using xchg) +;----------------------------------------------------------------- + + public _far_swapmem + STARTPROC _far_swapmem + + push bp + mov bp,sp + push ds + push es + push si + push di + + mov ds,ARGB[bp] ; source seg + mov si,ARGB+2[bp] ; source offs + mov es,ARGB+4[bp] ; dest seg + mov di,ARGB+6[bp] ; dest offs + mov cx,ARGB+8[bp] ; # bytes + jcxz far_swapmem_done + cld +swap_loop: + mov al,[si] + mov bl,es:[di] + mov [si],bl + mov es:[di],al + inc si + inc di + loop swap_loop +far_swapmem_done: + pop di + pop si + pop es + pop ds + pop bp + ret + + ENDPROC _far_swapmem + +;----------------------------------------------------------------- +; LongFrac LFMULT (a, b); +; LongFrac a, b; +; Multiply two long fractions (ie, 32-bit fixed point numbers with 16 bits +; of binary fraction). +; +; register usage: +; [bp+ARGB] a.low +; [bp+ARGB+2] a.hi +; [bp+ARGB+4] b.lo +; [bp+ARGB+6] b.hi +; ax,dx = result (lo,hi) +;----------------------------------------------------------------- + + public _LFMULT + STARTPROC _LFMULT + + push bp + mov bp,sp + push di + push si + xor si,si + mov ax,[bp+ARGB+2] + test ax,ax ; a>0 ? + jns aplus + not word ptr [bp+ARGB+2] ; a = -a + neg word ptr [bp+ARGB] + sbb word ptr [bp+ARGB+2],0ffffh + not si +aplus: mov ax,[bp+ARGB+6] + test ax,ax ; b>0? + jns bplus + not word ptr [bp+ARGB+6] ; b = -b + neg word ptr [bp+ARGB+4] + sbb word ptr [bp+ARGB+6],0ffffh + not si +bplus: mov ax,[bp+ARGB] ; get a.lo + mul word ptr [bp+ARGB+4] ; a.lo*b.lo + mov bx,dx ; res.lo = highhalf(a.lo*b.lo) + mov ax,[bp+ARGB+2] + mul word ptr [bp+ARGB+6]; a.hi*b.hi + mov cx,ax ; res.hi = lowhalf(a.hi*b.hi) + mov ax,[bp+ARGB] + mul word ptr [bp+ARGB+6] ; a.lo*b.hi + add bx,ax + adc cx,dx + mov ax,[bp+ARGB+2] + mul word ptr [bp+ARGB+4] ; a.hi*b.lo + add ax,bx ; ax = lo + adc dx,cx ; dx = hi + test si,si + jns leave ; if (neg) + not dx ; res = -res + neg ax + sbb dx,0ffffh +leave: + pop si + pop di + pop bp + ret + + ENDPROC _LFMULT + +;----------------------------------------------------------------- +; Return TRUE if there is a char in the keyboard buffer, or FALSE otherwise. +;----------------------------------------------------------------- + + public _char_avail + STARTPROC _char_avail + + mov ah,1 + int 16h + jz no_char_avail + mov ax,-1 + ret +no_char_avail: + xor ax,ax + ret + + ENDPROC _char_avail + +;----------------------------------------------------------------- +; Get an "extended" char, where normal chars are in the range 0-255, and +; non-ascii chars (for example, the function keys) are >= 256. +;----------------------------------------------------------------- + + public _get_char + STARTPROC _get_char + + mov ah,0 + int 16h + or al,al + jz gc_done + xor ah,ah +gc_done: + ret + + ENDPROC _get_char + +;----------------------------------------------------------------- +; set_ioError: if an io or critical error occurred, squirrels +; away the error code and clears did_crit_error and returns -1 +; +; Assumes that the carry flag and ax are the results of the last +; io operation (int 21h). +; +; If no error occurred, ax is unchanged. +;----------------------------------------------------------------- +did_crit_error dw 0 ;NOTE: didn't include crit error handler in program. + + STARTPROC set_ioError + pushf ; hold carry flag + + test cs:did_crit_error, 0ffffh + jz noCritError + push cs:did_crit_error + pop _ioError + + popflags + jmp short ioerr + +noCritError: + popflags + jnc iodone ; okay; leave ax unchanged + mov _ioError,ax +ioerr: + mov cs:did_crit_error,0 + mov ax,0ffffh ; return -1 for any error +iodone: ret + ENDPROC set_ioError + +;----------------------------------------------------------------- +; Open Dos File: fileHandle = opendos (name, access); +;----------------------------------------------------------------- + + public _opendos + STARTPROC _opendos + + push bp + mov bp,sp + mov al,[bp+ARGB+2] ; get access code + mov dx,[bp+ARGB] ; pointer to name + mov ah,03dh + int 021h + call set_ioError + pop bp + ret + + ENDPROC _opendos + +;----------------------------------------------------------------- +; Create Dos File: fileHandle = creatdos (name); +;----------------------------------------------------------------- + + public _creatdos + STARTPROC _creatdos + + push bp + mov bp,sp + xor cx,cx ; attribute= normal files + mov dx,[bp+ARGB] ; pointer to name + mov ah,03ch + int 021h ; do open or create + + jnb cdx ; if carry flag is set + mov ax,0FFFFh ; return -1 +cdx: + pop bp + ret + + ENDPROC _creatdos + +;----------------------------------------------------------------- +; Close Dos File: closedos (filehandle); +;----------------------------------------------------------------- + + public _closedos + STARTPROC _closedos + + push bp + mov bp,sp + mov bx,[bp+ARGB] ; get file handle + mov ah,03eh + int 021h ; do read or write + pop bp + ret + + ENDPROC _closedos + +;---------------------------------------------------------------------- +; Delete Dos File: deletedos (name); +;--------------------------------------------------------------------- + + public _deletedos + STARTPROC _deletedos + + push bp + mov bp,sp + mov dx,ARGB[bp] ; pointer to name + mov ah,41h + int 21h ; delete file + call set_ioError + pop bp + ret + + ENDPROC _deletedos + +;----------------------------------------------------------------- +; Read from Dos File: nBytes = readdos (file, seg, offset, length); +;----------------------------------------------------------------- + +O_FILE = ARGB +O_SEG = ARGB+2 +O_OFFSET = ARGB+4 +O_LENGTH = ARGB+6 + + public _readdos + STARTPROC _readdos + + push bp + mov bp,sp + push ds + mov ah,3fh + mov bx,O_FILE[bp] + mov cx,O_LENGTH[bp] + mov ds,O_SEG[bp] + mov dx,O_OFFSET[bp] + int 021h + call set_ioError + pop ds + pop bp + ret + + ENDPROC _readdos + +;----------------------------------------------------------------- +; Write to Dos File: nBytes = writedos (file, seg, offset, length); +; RETURN -1 on error. +;----------------------------------------------------------------- + +O_FILE = ARGB +O_SEG = ARGB+2 +O_OFFSET = ARGB+4 +O_LENGTH = ARGB+6 + + public _writedos + STARTPROC _writedos + + push bp + mov bp,sp + push ds + mov ah,40h + mov bx,O_FILE[bp] + mov cx,O_LENGTH[bp] + mov ds,O_SEG[bp] + mov dx,O_OFFSET[bp] + int 021h + call set_ioError + pop ds + pop bp + ret + + ENDPROC _writedos + +;----------------------------------------------------------------- +; LFDIV (num, denom); +;----------------------------------------------------------------- + +NUM = ARGB +DENOM = ARGB+4 + + public _LFDIV + STARTPROC _LFDIV + + push bp + mov bp,sp + +; neg = FALSE + xor cx,cx + +; if (num < 0) { num = -num; neg = !neg; } + cmp word ptr NUM+2[bp],0 + jge lfdiv1 + mov ax,NUM[bp] ; num = -num + mov dx,NUM+2[bp] + neg ax + adc dx,0 + neg dx + mov NUM[bp],ax + mov NUM+2[bp],dx + not cx ; neg = !neg +lfdiv1: + +; if (denom < 0) { denom = -denom; neg = !neg; } + cmp word ptr DENOM+2[bp],0 + jge lfdiv2 + mov ax,DENOM[bp] ; denom = -denom + mov dx,DENOM+2[bp] + neg ax + adc dx,0 + neg dx + mov DENOM[bp],ax + mov DENOM+2[bp],dx + not cx ; neg = !neg +lfdiv2: + +; while (denom >= 0x10000) { num >>= 1; denom >>= 1; } + mov bx,cx ; save neg in bx +lfdiv5: + mov cx,DENOM+2[bp] + jcxz lfdiv3 + sar word ptr NUM+2[bp],1 ; num >>= 1 + rcr word ptr NUM[bp],1 + sar word ptr DENOM+2[bp],1 ; denom >>= 1 + rcr word ptr DENOM[bp],1 + jmp lfdiv5 +lfdiv3: + mov cx,bx ; restore neg to cx + +; high word of result = num / denom + mov ax,NUM[bp] + mov dx,NUM+2[bp] + cmp dx,DENOM[bp] ; test for overflow + jb no_overflow + mov ax,7fffh ; overflow, so use a large # + xor dx,dx + jmp lfdiv6 +no_overflow: + div word ptr DENOM[bp] + mov bx,ax + +; low word of result = ((num % denom) << 16) / denom +lfdiv6: + xor ax,ax + div word ptr DENOM[bp] + mov dx,bx ; dx = high word of result + +; if (neg) result = -result; + jcxz lfdiv4 + neg ax + adc dx,0 + neg dx +lfdiv4: + + pop bp + ret + + ENDPROC _LFDIV + +;----------------------------------------------------------------- +; WORD get_first_mcb (); +; Returns address of first MCB in DOS free memory list. +;----------------------------------------------------------------- + + public _get_first_mcb + STARTPROC _get_first_mcb + + mov ah,52h + int 21h + mov ax,es:[bx-2] + ret + + ENDPROC _get_first_mcb + +;----------------------------------------------------------------- +; WORD cdist (a, b); +; LONG a, b; +; Calculate the distance between RGB color values a and b. This is +; done using the sum of the absolute R,G,B deltas. It would be more +; accurate (but much slower) to calculate the actual distance between them. +; +; Improved: absdR + absdG + absdB + MAX(absdR, absdG, absdB). +; This approximates the sum of squares, by forcing large component to +; have double contribution to error term. +;----------------------------------------------------------------- + +A = ARGB +B = ARGB+4 + + public _cdist + STARTPROC _cdist + + push bp + mov bp,sp + +; --- clear top half of ax so we can use it as a word + sub ah,ah + +; --- get absolute distance between BLUE coords, put result in bx + mov bl,A[bp] + mov cl,B[bp] + cmp bl,cl + jae cdist_p1 + xchg bl,cl +cdist_p1: + sub bl,cl + sub bh,bh ; BX: abs(delta R). + + mov dx,bx ; dx will be MAX. + +; --- get absolute distance between GREEN coords, add to bx + mov al,A+1[bp] + mov cl,B+1[bp] + cmp al,cl + jae cdist_p2 + xchg al,cl +cdist_p2: + sub al,cl + add bx,ax ; BX: absdR + absdG. + + cmp dx,ax + jge cdist_R_ge_G + mov dx,ax +cdist_R_ge_G: ; DX: MAX(absdR, absdG). + +; --- get absolute distance between RED coords, add bx to this value + mov al,A+2[bp] + mov cl,B+2[bp] + cmp al,cl + jae cdist_p3 + xchg al,cl +cdist_p3: + sub al,cl + add ax,bx ; AX: absdR + absdG + absdB. + + cmp dx,ax + jge cdist_RG_ge_B + mov dx,ax +cdist_RG_ge_B: ; DX: MAX(absdR, absdG, absdB). + + add ax,dx ; AX: absdR + absdG + absdB + MAX(...). + + pop bp + ret + + ENDPROC _cdist + +;----------------------------------------------------------------- +; void dos_print_string (string); +; char *string; +; Call DOS to print the given string, in text mode. The string should +; not contain a '$', since DOS will treat that as the end of the string, +; and not print any chars after that! +;----------------------------------------------------------------- + + public _dos_print_string + STARTPROC _dos_print_string + + push bp + mov bp,sp + push si + +; --- replace the NULL terminator with a '$', like DOS wants + mov si,ARGB[bp] + dec si +find_dollar: + inc si + mov al,[si] + or al,al + jnz find_dollar + mov byte ptr [si],'$' + +; --- call DOS to print the string + push si + mov ah,9 + mov dx,ARGB[bp] + int 21h + pop si + +; --- restore NULL string terminator + mov byte ptr [si],0 + + pop si + pop bp + ret + + ENDPROC _dos_print_string + +;----------------------------------------------------------------- +; Allocate Memory: segment = allocsome (paragraphs, &size) +; Will allocate request or largest remaining, whichever is bigger. +; Returns segment = 0 if failed. Puts number of paragraphs actually +; allocated into *size. +; Right now, this is only used by FixTandyMemory. +;----------------------------------------------------------------- + + public _allocsome + STARTPROC _allocsome + + push bp + mov bp,sp + mov bx,[bp+ARGB] +allocscont: + mov di,[bp+ARGB+2] + mov [di],bx ; return number of words allocated + mov ax,0 + cmp ax,bx + je allocsret ; fail nothing requested + mov ax,04800h + int 021h ; execute DOS function + jnc allocsret + mov cx,ax + mov ax,0 ; error: return NIL + cmp cx,7 ; arena trashed + jne allocscont ; keep trying until we alloc max left or fail +allocsret: + pop bp + ret + + ENDPROC _allocsome + +;----------------------------------------------------------------- +; LONG FreeDiskSpace (drive); +; WORD drive; /* 0 = drive A, 1 = drive B, etc... */ +; Returns free disk space in bytes on the specified drive. If there +; is an error accessing that drive, it returns 0. +;----------------------------------------------------------------- + + public _FreeDiskSpace + STARTPROC _FreeDiskSpace + + push bp + mov bp,sp + + mov ah,36h + mov dl,ARGB[bp] + inc dl ; this func uses 1 = drive A, 2 = drive B... + int 21h + cmp ax,0ffffh + jne fds_no_error +; --- error getting info, so return 0 + xor ax,ax + xor dx,dx + jmp fds_done +; --- no error, so return (sectorsPerCluster * bytesPerSector * freeClusters) +; NOTE: we assume that sectorsPerCluster * bytesPerSector < 64k. +fds_no_error: + mul cx + mul bx +fds_done: + pop bp + ret + + ENDPROC _FreeDiskSpace + +;----------------------------------------------------------------- +; LONG GetSystemTime (); +; Returns the number of timer ticks (18.2 per second) since midnight. +;----------------------------------------------------------------- + + public _GetSystemTime + STARTPROC _GetSystemTime + + mov ah,0 + int 1ah + mov ax,dx ; move low word to ax + mov dx,cx ; move high word to dx + ret + + ENDPROC _GetSystemTime + +;----------------------------------------------------------------- +; name WordMulDiv -- +; +; c = (a*num)/denom; +; +; UWORD muldiv(a,num,denom) UWORD a,num,denom; +; +; register usage +; [bp+ARGB] a +; [bp+ARGB+2] num +; [bp+ARGB+4] denom +;----------------------------------------------------------------- + + public _WordMulDiv + STARTPROC _WordMulDiv + push bp + mov bp,sp + mov ax,[bp+ARGB] + mul word ptr[bp+ARGB+2] + div word ptr[bp+ARGB+4] + pop bp + ret + ENDPROC _WordMulDiv + +;----------------------------------------------------------------- + + ENDPS misca + END diff --git a/tools/old/anm/PBIO.C b/tools/old/anm/PBIO.C new file mode 100644 index 000000000..8fe5d1c4b --- /dev/null +++ b/tools/old/anm/PBIO.C @@ -0,0 +1,387 @@ +/*--pbio.c----------------------------------------------------------* + * * + * Routines to read & write PC Paintbrush files. * + * * + * Date Who Changes * + * --------- --- -------------------------------------------------- * + * 31-Mar-89 mjc band read & write to allow large files. * + * 19-Apr-89 mjc 256 color palette added at end of paintbrush file. * + * * + * TBD: haven't added scroll-offset logic to "to planar" case, since + * ANIMDISK is only 8 bpp. + *------------------------------------------------------------------*/ + +#include "main.h" +#include +#include +#include +#include +#include +#include + +#define local static + +/* RowBytes computes the number of bytes in a row, from the width in pixels.*/ +#define RowBytes(w) (((w) + 15) >> 4 << 1) + +/*------------------------------------------------------------------ + * 256 Color Palette + * + * When reading the paintbrush file, the 256 color palette is + * sought only if the version number in the header is 5 and the + * bits per pixel * planes == 8. The last 769 bytes of the file + * must start with 0x0C, and be followed by the 768 byte palette. + * + * When writing the paintbrush file, we write + * version 5 in the header, and append the palette to the end of + * the file in the same format as above (0x0C followed by 768 + * bytes of palette). + *------------------------------------------------------------------ + */ + +/* Return SUCCESS, FAIL, or specific errors ... */ +#define PB_NOT_ENUF_MEM 2 +#define PB_NO_256_PALETTE 3 + +local WORD readCount; /* For compression. */ +local UBYTE readChar; + +/* --- Forward declarations. */ +void GetByte(WORD file); +BOOL PutBytes(BYTE far * ptr, WORD bytes, WORD file); + +/*-----------------------------------------------------------------*/ + +typedef struct { + BYTE manufacturer; + BYTE version; + BYTE encoding; + BYTE bitsperpixel; + WORD xmin, ymin, xmax, ymax; + WORD hres, vres; + BYTE colormap[16][3]; + BYTE reserved; + BYTE nplanes; + WORD bytesperline; +} PCPAINTBRUSH_HEADER; + +local PCPAINTBRUSH_HEADER *pbh = NULL; /* paintbrush header pointer */ + /* Global pointer so can allocate in header, use fields in body. */ + +/*--------------------- Bad Paintbrush Header ----------------------*/ +#define BadPbHeader(s) (FAIL) + +/*-------------------- Invalid Paintbrush File ---------------------*/ +#define InvalidPbFile() (FAIL) + +#define WrongPbFileType() (FAIL) /* Expected different data format.*/ +#define PCXNo256PaletteMsg() + +/*-----------------------------------------------------------------* + * Read the header of a pc paintbrush file. + * Sets bmHdr fields. Calls reSize if necessary. + * Returns SUCCESS or FAIL. + *-----------------------------------------------------------------*/ + +BOOL ReadPCX_Header(WORD file, BITMAP *bitmap, LONG *palette, + BitMapHeader *bmHdr) +{ + register WORD i; + UBYTE c, palet[256][3]; + + if (!pbh) /* Test in case we come through twice w/o freeing. */ + pbh = malloc(sizeof(PCPAINTBRUSH_HEADER) + 4); + if (!pbh) + return (FAIL); + + if (read(file, (char *)pbh, sizeof(PCPAINTBRUSH_HEADER)) != + sizeof(PCPAINTBRUSH_HEADER)) + return (InvalidPbFile()); + + /* --- To start of pixel data. */ + if (0 > lseek(file, (LONG) 128, SEEK_SET)) + return (InvalidPbFile()); + + /* --- Check that the header info is valid. */ + if (pbh->manufacturer != 10) + return (InvalidPbFile()); + + /* --- Expecting version with palette at end. */ + if (pbh->version != 5) + return (BadPbHeader(s_wrongPBVersion)); + + if (pbh->encoding != 1) + return (BadPbHeader(s_unknownEncoding)); + + if (pbh->bitsperpixel != 1 && pbh->nplanes != 1) + return (BadPbHeader(s_wrongLayout)); + + if (pbh->bitsperpixel != 8) + return (WrongPbFileType()); + + /* --- Compute dimensions and # colors. */ + setmem(bmHdr, sizeof(BitMapHeader), 0); + bmHdr->w = 1 + pbh->xmax - pbh->xmin; + bmHdr->h = 1 + pbh->ymax - pbh->ymin; + bmHdr->nPlanes = pbh->bitsperpixel * pbh->nplanes; + /* MAY BE PACKED. */ + + /* --- Get the color map. */ + if (palette != NULL) { + /* If a 256 color palette should be present at the end of the + * file, try to fetch it from disk and copy it to the palette. + */ + c = 0; + if (lseek(file, (LONG)-769, SEEK_END) >= 0) + if (read(file, &c, 1) == 1) + if (read(file, (UBYTE *)&palet[0][0], 768) == 768) + if (c == 0x0C) + for (i = 0; i < 256; ++i) + palette[i] = ((LONG)palet[i][0] << 16) + + ((LONG)palet[i][1] << 8) + + ((LONG)palet[i][2]); + /* --- To start of pixel data (again). */ + lseek(file, (LONG)128, SEEK_SET); + if (c != 0x0C) { + /* ---- We couldn't read a 256 color palette at the end + * of the file. + */ + PCXNo256PaletteMsg(); + return (PB_NO_256_PALETTE); + } + } + return (SUCCESS); /* Header done; BODY yet to do. */ +} + +/*-----------------------------------------------------------------* + * Read the pixel data into the bitmap. Return SUCCESS or FAIL. + *-----------------------------------------------------------------*/ +#define MaxPCXPlanes 8 /* 256-color, no mask. */ + +BOOL ReadPCX_BODY(WORD file, BITMAP *bitmap, BitMapHeader *bmHdr) +{ + register WORD i, iPlane; + BOOL result = SUCCESS; + BYTE far *dest; + WORD bodyNRows, srcPlanesToUse; + WORD bodyIRow; /* Increment from 0..bodyNRows-1. */ + BYTE far *dests[MaxPCXPlanes]; /* Ptrs to dest scan lines. */ + WORD useBytes; + + /* --------- Initialization. ---------- */ + readCount = 0; /* For compression. */ + + bodyNRows = MIN(bmHdr->h, bitmap->box.h); + srcPlanesToUse = MIN(bitmap->planes + bpp_minus1, bmHdr->nPlanes); + + /* ---------- Read all scan lines. ---------- */ + OpenIOBuffer(FALSE); + + for (bodyIRow = 0; bodyIRow < bodyNRows; ++bodyIRow) { + readCount = 0; /* Just in case, supposed to start anew each line. */ + + useBytes = MIN(bitmap->width, pbh->bytesperline); + + /* ----- Read a scan line. */ + dest = (BYTE far *)BMLineStart(bitmap, bodyIRow, 0); + for (i = 0; i < pbh->bytesperline; i++) { + GetByte(file); + if (i < useBytes) + *dest++ = readChar; + } + } + CloseIOBuffer(file); + +done: + return (result); +} + +/*--------------------- Close Paintbrush File ---------------------*/ +/* --- NOTE: if change, must change WritePCX_Done, since it calls this. */ + +void ReadPCX_Done() +{ + /* --- Free pbh, which is shared by header & body routines. */ + if (pbh) + free(pbh); + pbh = NULL; +} + +void WritePCX_Done() +{ + ReadPCX_Done(); +} + +/*---------------------------- Get Byte ---------------------------*/ +/* Set readCount & readChar. At EOF or file error, returns 0's forever. */ + +void GetByte(WORD file) +{ + UBYTE c; + + /* --- if in the middle of a run of encoded bytes, don't read any + * more + */ + if (readCount > 0) { + --readCount; + return; + } + readCount = 0; + if (GReadOne(file, &c) != 1) { +sawEOF: + readCount = 32767; /* Huge count of 0's to pad the end. */ + readChar = 0; + return; + } + if ((c & 0xc0) == 0xc0) { + readCount = (0x3f & c) - 1; /* "-1": consuming one of count. */ + if (GReadOne(file, &c) != 1) + goto sawEOF; + } + readChar = c; +} + +/*----------------------------------------------------------------------* + Output File Routines & Variables + *----------------------------------------------------------------------*/ + +/*---------------------------------------------------------------* + Output header for a PC Paintbrush file with the given number + of bitsperpixel and planes. One of these two parms must be 1. + ASSUMES OKAY TO TRASH buffer[]. + Returns SUCCESS or FAIL. + *---------------------------------------------------------------*/ + +BOOL WritePCX_Header(WORD file, BITMAP *bitmap, LONG *palette) +{ + register PCPAINTBRUSH_HEADER *ppbh; + WORD i; +#define GAP_SIZE (128 - sizeof(PCPAINTBRUSH_HEADER)) + UBYTE buffer1[GAP_SIZE]; + + /* --- init the header that we'll write. + * Note: since DPaint never reads & writes at the same time, + * it is okay to share the same read & write structure, + * unlike in CONVERT.EXE. + */ + if (!pbh) /* Test in case we come through twice w/o + * freeing. */ + pbh = malloc(sizeof(PCPAINTBRUSH_HEADER) + 4); + if (!pbh) + return (FAIL); + ppbh = pbh; /* Register variable for smaller, faster code. */ + + setmem(ppbh, sizeof(PCPAINTBRUSH_HEADER) + 4, 0); + ppbh->manufacturer = 10; + ppbh->version = 5; + ppbh->encoding = 1; + + ppbh->bitsperpixel = bpp; + ppbh->xmin = ppbh->ymin = 0; + ppbh->xmax = bitmap->box.w - 1; + ppbh->ymax = bitmap->box.h - 1; + ppbh->hres = N_COLUMNS; + ppbh->vres = N_LINES; + + /* --- bytesperline doesn't take into account multiple planes. + * Output in same format as bitmap (planar vs packed). + */ + ppbh->bytesperline = bitmap->width; + + ppbh->nplanes = bitmap->planes; + ppbh->reserved = 0; + + /* --- First 16 colors of our palette info. */ + for (i = 0; i < 16; ++i) { + ppbh->colormap[i][0] = (BYTE)(palette[i] >> 16); + ppbh->colormap[i][1] = (BYTE)(palette[i] >> 8); + ppbh->colormap[i][2] = (BYTE) palette[i]; + } + + /* --- write the 128-byte header */ + if (GWrite(file, (char *)ppbh, sizeof(PCPAINTBRUSH_HEADER)) + != sizeof(PCPAINTBRUSH_HEADER)) + goto error; + + setmem(buffer1, GAP_SIZE, 0); + if (GWrite(file, buffer1, GAP_SIZE) != GAP_SIZE) +error: + return (FAIL); + + return (SUCCESS); +} + +/* --------------- WritePCX_BODY --------------- + * Write the pixel data. + * Returns SUCCESS or an error condition. + * ------------------------------------------------------------------- + */ +WORD WritePCX_BODY(WORD file, BITMAP *bitmap) +{ + register WORD y; + + /* --- Write to a bit-packed file. */ + for (y = 0; y < bitmap->box.h; ++y) { /* for each line in band */ + if (PutBytes((BYTE far *)BMLineStart(bitmap, y, 0), + pbh->bytesperline, file)) + return FAIL; + } + return SUCCESS; +} + +/*-------------------- Output any 256-color palette ------------------------*/ +BOOL WritePCX_256Palette(WORD file, LONG *palette) +{ + register WORD i; + UBYTE c, palet[256][3]; + + if (pbh->version == 5 && pbh->bitsperpixel == 8) { + for (i = 0; i < 256; ++i) { + palet[i][0] = (BYTE)(palette[i] >> 16); + palet[i][1] = (BYTE)(palette[i] >> 8); + palet[i][2] = (BYTE) palette[i]; + } + c = 0x0C; + if (GWrite(file, &c, 1) != 1 || + GWrite(file, (char *)&palet[0][0], 768) != 768) + return FAIL; + } + return SUCCESS; +} + +/*------------------------------------------------------------------- + * Write bytes to a file, handling packing as it goes. + * Returns SUCCESS or FAIL. + *------------------------------------------------------------------- + */ +BOOL PutBytes(BYTE far *ptr, WORD bytes, WORD file) +{ + register WORD startbyte, count; + char b; + + while (bytes > 0) { + /* --- check for a repeating byte value */ + startbyte = *ptr++; + --bytes; + count = 1; + while (*ptr == startbyte && bytes > 0 && count < 63) { + ++ptr; + --bytes; + ++count; + } + /* --- If we can pack the sequence, or if we have to add a + * byte before it because the top 2 bits of the value + * are 1's, write a packed sequence of 2 bytes. + * Otherwise, just write the byte value. + */ + if (count > 1 || (startbyte & 0xc0) == 0xc0) { + b = 0xc0 | count; + if (GWrite(file, &b, 1) != 1) + return FAIL; + } + b = startbyte; + if (GWrite(file, &b, 1) != 1) + return FAIL; + } + return SUCCESS; +} diff --git a/tools/old/anm/READFRST.TXT b/tools/old/anm/READFRST.TXT new file mode 100644 index 000000000..a4d86a81d --- /dev/null +++ b/tools/old/anm/READFRST.TXT @@ -0,0 +1,27 @@ + +Dear DeluxePaint Animation user: + +Thank you for contacting us regarding the use of animation files created with +DeluxePaint Animation. + +The enclosed files be useful for reading and writing animations from you own +application code or for converting animations to and from your own file +format. The files contain both an executable program as well as C source +code. For further details, please see the README.TXT file provided with these +files. For information on the ANM (animation) file format, please see the +comments in the LPFILE.C file. + +The PCX and PCC format is available from a company called Z-Soft, they can be +contacted by calling 404-428-0008. + +Please understand that these files and information are presented as is and +that we cannot provide technical support for the Programmer's Kit. However, +if you should have any questions concerning the operation of DeluxePaint +Animation, please do not hesitate to contact us. + +Electronic Arts Multimedia Support +P.O. Box 7578 +San Mateo, CA 94403-7578 +(415) 572-2787 +(415) 571-6552 FAX + diff --git a/tools/old/anm/README.TXT b/tools/old/anm/README.TXT new file mode 100644 index 000000000..e4c952eeb --- /dev/null +++ b/tools/old/anm/README.TXT @@ -0,0 +1,50 @@ + + Programmer's Kit for Version 1.0 + DeluxePaint Animation 10/24/90 + by Electronic Arts + + ---------------------- + This kit has two uses: + + 1. It contains a program, ANIM2PCX.EXE, which is readily used to + (1) break an animation file into individual picture files for + each frame, or + (2) to join a group of picture files into an animation file for + editting in DPaint Animation or for playback with PLAY.EXE. + + (PLAY.EXE is included in the DeluxePaint Animation package and may be + copied and distributed by anyone who has purchased DPaint Animation.) + + The picture files are in the PCX format, which can be read by + DeluxePaint Animation, DeluxePaint II Enhanced and other paint programs, + and by desktop publishing programs and graphics-importing word processors. + + For instructions on using the program as provided, type: + anim2pcx + + + 2. Since the source code for ANIM2PCX is included on this disk, + a C programmer can access animations from his/her own application, + or write a converter between the ANM format and some other format, + by including the subroutines required to read and write ".ANM" files. + You will need all the enclosed .C, .H, .ASM, .INC files, + except for PBIO.C and GIO.C (which are used to read/write PCX files), + and ANIM2PCX.C (which is the main program that you will replace with + your own code). + For example, to read the frames of an anim, you might write code + similar to "AnimFileToPCXFiles()" routine in ANIM2PCX.C + + The only existing documentation on the ANM format + is in comments in LPFILE.C. + + + --------------------- + The source code for ANIM2PCX may be freely incorporated into + commercial programs. + + Disclaimer: + THIS PROGRAM IS PROVIDED WITHOUT SEPARATE CHARGE AND IS + PROVIDED AS IS. ELECTRONIC ARTS DISCLAIMS ALL WARRANTIES, + INCLUDING IMPLIED WARRANTIES AND WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + diff --git a/tools/old/anm/anmformt/ANIMFILE.TXT b/tools/old/anm/anmformt/ANIMFILE.TXT new file mode 100644 index 000000000..a8d2b9308 --- /dev/null +++ b/tools/old/anm/anmformt/ANIMFILE.TXT @@ -0,0 +1,138 @@ +DeluxePaint Animation ".ANM" files consist of a large header and a series of +structures that can be up to 64 KB long each. The programmer refers to these +structures as "Large Pages". Large Pages are a format for dividing a file +into 64 KB chunks that can be stored out-of-sequence in the file. That is, +a large page can be logically inserted into the file, without having to move +all the following data out of the way. + +Each large page holds one or more "records". A record represents one frame +of the original animation. A record is of any length from 0 to almost 64 KB. +The records in a large page are sequential. However, the first large page +may not contain the first frames of the anim file. Each large page contains +a sequential set of records but the large pages themselves are not in +sequential order. It is possible for the first large page in a file to +contain the last few frames of the animation. When you process the anim file +you must scan the large page structures to find which large page conatins the +frame you wish to display or process next. + +A DeluxePaint Animation "ANM" ("Anim") file is built on this mechanism, +so that as frames change in size, they can be maintained with a minimum +of extra file i/o, yet without loss of playback performance. +In addition, there is an optional special record which is the delta from +the last frame to the first frame, for smooth playback of looping anims. + +The following is the structure of a DeluxeAnimate anim file header. +Header size is exactly 2816 bytes. The first large page structure can be +reached by simply seeking to this location in the file. + + ULONG id; 4 character ID == "LPF " + + UWORD maxLps; max # largePages allowed. 256 FOR NOW. + + UWORD nLps; # largePages in this file. + + ULONG nRecords; # records in this file. 65534 is current limit plus + one for last-to-first delta for looping the animation + + UWORD maxRecsPerLp; # records permitted in an lp. 256 FOR NOW. + + UWORD lpfTableOffset; Absolute Seek position of lpfTable. 1280 FOR NOW. + The lpf Table is an array of 256 large page structures + that is used to facilitate finding records in an anim + file without having to seek through all of the Large + Pages to find which one a specific record lives in. + + ULONG contentType; 4 character ID == "ANIM" + + UWORD width; Width of screen in pixels. + UWORD height; Height of screen in pixels. + UBYTE variant; 0==ANIM. + UBYTE version; 0==frame rate is multiple of 18 cycles/sec. + 1==frame rate is multiple of 70 cycles/sec. + + UBYTE hasLastDelta; 1==Last record is a delta from last-to-first frame. + + UBYTE lastDeltaValid; 0==The last-to-first delta (if present) hasn't been + updated to match the current first&last frames, so it + should be ignored. + + UBYTE pixelType; 0==256 color. + + UBYTE CompressionType; 1==(RunSkipDump) Only one used FOR NOW. + + UBYTE otherRecsPerFrm; 0 FOR NOW. + + UBYTE bitmaptype; 1==320x200, 256-color. Only one implemented so far. + + UBYTE recordTypes[32]; Not yet implemented. + + ULONG nFrames; In case future version adds other records at end of + file, we still know how many actual frames. + NOTE: DOES include last-to-first delta when present. + + UWORD framesPerSecond; Number of frames to play per second. + + UWORD pad2[29]; 58 bytes of filler to round up to 128 bytes total. + + Range cycles[16]; Color cycling info (128 bytes long). + This is the format of a cycle structure. + typedef struct { + WORD count; + WORD rate; + WORD flags; + UBYTE low, high; /* bounds of range */ + } Range; + + + total is = 256 bytes. + + Following the anim file header is the color palette + + ULONG palette[256] Color palette arranged as 3 bytes each of Red Green + & Blue and one unused byte. + + Following the palette is an array of structures that are copies of the + large page headers. This array is loaded and used to find which large page + a given frame can be found in. + + Large_page LParay[256] Copies of all the Large Page structures in the anim + file. Each Large Page structure is 6 bytes long so + the total length of this table is 1536 bytes. Even if + the file only contains 1 large page there are still + 256 entries of 6 bytes each. + + The Large Pages follow the LParray and are in the sequence dictated by + their order of occurence in the LParray in the anim file header. + + The following is the structure of a single Large Page in an anim file. Each + Large Page is exactly 64k long in the anim file. The only exception is the + last large page wich is truncated to be only as long as necessary. + + UWORD baseRecord; Number of first record in this large page. + + UWORD nRecords; Number of records in lp. + bit 15 of "nRecords" == "has continuation from previous lp". + bit 14 of "nRecords" == "final record continues on next lp". + + UWORD nBytes; Total number of bytes of contents, excluding header. + + UWORD BytesContinued; The number of bytes of the last record of the + previous large page that extend into this large page. + This was never implemented and is always 0. + + UWORD RecordSizes[nRecords] Array of lengths of each record in the large page. + + The actual records start here. Each record has a variable length header that + is like the following structure. + + typedef struct{ + UBYTE IDnum; always 66 + UBYTE Flags; 0==no extra bytes field next + + UWORD extrabytes; if Flags is non zero this is # of bytes + to skip before compressed data starts + extrabytes does not include the size + of the 2 previous bytes. Also make + sure you round the final address up to + an even byte boundry. + } record_header; diff --git a/tools/old/anm/anmformt/CGRAPH.ASM b/tools/old/anm/anmformt/CGRAPH.ASM new file mode 100644 index 000000000..ee389fb60 --- /dev/null +++ b/tools/old/anm/anmformt/CGRAPH.ASM @@ -0,0 +1,351 @@ +; my generic graphics routines for C programs + + + .8086 + + .model large,c + +;***************************************************************************** +; Program code starts here +;***************************************************************************** + + +EQUIP_FLAG EQU byte ptr ds:[10h] ; (in Video Display Data Area) + +CGAbits EQU 00100000b ; bits for EQUIP_FLAG +MDAbits EQU 00110000b + + + .code + + public SetVideoMode +SetVideoMode proc far + + push bp ; preserve caller registers + mov bp,sp + push ds + + mov ax,40h + mov ds,ax ; DS -> Video Display Data Area + + mov bl,CGAbits ; BL := bits indicating presence of CGA + mov al,6[bp] ; AL := desired video mode number + + mov ah,al ; test if desired mode is monochrome + and ah,7 + cmp ah,7 + jne L01 ; jump if desired mode not 7 or 0Fh + + mov bl,MDAbits ; BL := bits indicating presence of MDA + +L01: and EQUIP_FLAG,11001111b + or EQUIP_FLAG,bl ; set bits in EQUIP_FLAG + + xor ah,ah ; AH := 0 (INT 10h function number) + + push bp + int 10h ; call ROM BIOS to set the video mode + pop bp + + pop ds ; restore caller registers and return + pop bp + + ret + +SetVideoMode endp + + public GetVideoMode +GetVideoMode proc far + + push bp + mov ah,0Fh ; Get video mode sub-function + int 10h ; call ROM BIOS to get video mode number + pop bp + + xor ah,ah ; AX := video mode number + + ret + +GetVideoMode endp + + +; LoadPalette(numcolors, startcolor, paletteaddr) + public LoadPalette +LoadPalette proc far + + push bp + mov bp,sp + + push bx + push cx + push dx + push es + + mov bx,8[bp] + mov cx,6[bp] + mov es,12[bp] + mov dx,10[bp] + + mov ax,1012h + int 10H + + pop es + pop dx + pop cx + pop bx + pop bp + + ret + +LoadPalette endp + + +; initialize the mouse to its default values and display it + public InitMouse +InitMouse proc far + + push ax + + mov ax,0 + int 33h + mov ax,1 + int 33h + + pop ax + + ret + +InitMouse endp + +; display the mouse cursor + public ShowMouse +ShowMouse proc far + + push ax + + mov ax,1 + int 33h + + pop ax + + ret +ShowMouse endp + + +; hide the mouse cursor + public HideMouse +HideMouse proc far + push ax + + mov ax,2 + int 33h + + pop ax + + ret +HideMouse endp + +; read the mouse buttons and cursor position +; on exit: +; BX = button state bit 0 = left button bit 1 = right button +; CX = cursor x position +; DX = cursor y position + public ReadMouse +ReadMouse proc far + push bp + mov bp,sp + push ds + push si + push bx + push cx + push dx + + mov ax,3 + int 33h + + lds si,6[bp] + mov [si],bx + + lds si,10[bp] + mov [si],cx + + lds si,14[bp] + mov [si],dx + + + pop dx + pop cx + pop bx + pop si + pop ds + + pop bp + + ret +ReadMouse endp + +; PlayRunSkipDump(sourcebuf, destbuf); + public PlayRunSkipDump +PlayRunSkipDump proc far + +ARGB = 6 +PR_SRC_SEG = ARGB+2 +PR_SRC_ADDR = ARGB +PR_DST_SEG = ARGB+6 +PR_DST_ADDR = ARGB+4 + + push bp + mov bp,sp + push si + push di + push es + + mov si,PR_SRC_ADDR[bp] + mov di,PR_DST_ADDR[bp] + mov es,PR_DST_SEG[bp] + + push ds ; Save DS:DGROUP. + mov ds,PR_SRC_SEG[bp] ; SET DS:dstSeg. NOT DGROUP. + + sub ch,ch ; SET CH = 0. + jmp short nextOp + +skip: + sub cl,80h ; Strip off sign bit, leaving skip cnt. + jz longOp ; cnt==0 indicates a long op. +; --- shortSkip --- + add di,cx ; skip # pixels. (CH=0) +; --- variation on NEXTOP inline to minimize jmp's --- +nextOp: ; Get and decode next op. + mov cl,[si] + inc si + jcxz run + or cl,cl ; Test CL's sign bit. + jl skip +dump: + rep movsb ; copy # pixels. (CH=0) +; --- variation on NEXTOP inline to minimize jmp's --- + mov cl,[si] + inc si + or cl,cl ; Test CL's sign bit. + jl skip + jg dump +run: + mov cl,[si] ; 8-bit unsigned count. + inc si + lodsb ; pixel value. + rep stosb ; set # pixels to value. (CH=0) +; --- variation on NEXTOP inline to minimize jmp's --- + mov cl,[si] + inc si + jcxz run + or cl,cl ; Test CL's sign bit. + jl skip + jmp short dump + +longOp: ; NOTE: if load into CX, must clear CH afterwards. + lodsw ; 16-bit unsigned count. + or ax,ax ; set flags. + jle notLongSkip +;longSkip: + add di,ax ; skip # pixels. + jmp short nextOp + ; longSkip only used for > 2*127, so can't be very many, + ; so don't bother saving one jmp with inline NEXTOP. + +notLongSkip: + jz stop ; long count of zero means "stop code". + mov cx,ax ; may SET CH non-zero. + sub ch,80h ; Clear sign bit. + cmp ch,40h + jge longRun +; --- For maximum speed on longDump, caller should insure src & dst are +; aligned. To do so, caller must calculate whether +; src DATA will begin on same (odd or even) alignment as dst data. +; If not, first put a 1-byte Dump, which occupies 2 src bytes, thereby +; shifting relative alignment (src moves 2, dst moves 1). +;longDump + test si,1 ; Insure src word-aligned. + ; In case caller didn't sync src & dst, we chose + ; to align src because we know it is of benefit -- + ; aligning dst on 8-bit video cards might not be of + ; any benefit. + jz dumpWordAligned + movsb ; get to word boundary. + dec cx +dumpWordAligned: + shr cx,1 ; Convert byte count to word count. + jc dumpOddByte + rep movsw ; Word-aligned. +longOpDone: + sub ch,ch ; SET CH = 0. + jmp short nextOp + +dumpOddByte: + rep movsw ; Word-aligned. + movsb + jmp short longOpDone + +longRun: + sub ch,40h ; Clear "longRun" bit. + lodsb + mov ah,al ; Replicate byte to word value. + test di,1 ; Insure dst word-aligned. + jz runWordAligned + stosb + dec cx +runWordAligned: + shr cx,1 ; Convert byte count to word count. + jc runOddByte + rep stosw ; Word-aligned. + jmp short longOpDone + +runOddByte: + rep stosw ; Word-aligned. + stosb + jmp short longOpDone + +stop: + pop ds ; Restore DS:DGROUP. + + mov ax,di ; RETURN final dstAddr. + pop es + pop di + pop si + pop bp + ret + +PlayRunSkipDump endp + +; clear the screen to a color +; cls(color); + public cls +cls proc far + + push bp + mov bp,sp + + push di + push es + push cx + + mov ax,0A000h + mov es,ax + xor di,di + + mov al,6[bp] + mov ah,al + mov cx,32000 + rep stosw + + pop cx + pop es + pop di + + pop bp + + ret + +cls endp + + end diff --git a/tools/old/anm/anmformt/MAKESHOW.M b/tools/old/anm/anmformt/MAKESHOW.M new file mode 100644 index 000000000..ccf542e36 --- /dev/null +++ b/tools/old/anm/anmformt/MAKESHOW.M @@ -0,0 +1,8 @@ +showanim.obj: showanim.c showanim.h +cl /c /Zi /AL showanim.c + +cgraph.obj: cgraph.asm + masm $*; + +showanim.exe: showanim.obj cgraph.obj + link /co showanim+cgraph; diff --git a/tools/old/anm/anmformt/SHOWANIM.C b/tools/old/anm/anmformt/SHOWANIM.C new file mode 100644 index 000000000..3f7755fb0 --- /dev/null +++ b/tools/old/anm/anmformt/SHOWANIM.C @@ -0,0 +1,323 @@ +/* + This is a small program to play a deluxe animate file. No attempt has + been made to time the animation speed correctly. The playback speed will + be dictated by the speed of your machine. +*/ + +#include +#include +#include + +#define EXIT_FAILURE 1 +#define EXIT_SUCCESS 0 + +#define TRUE 1 +#define FALSE 0 + +/* Typedefs for portability. */ + +typedef char BOOL; /* 0==FALSE, 1==TRUE */ +typedef char BYTE; /* signed 8-bit number */ +typedef unsigned char UBYTE; /* unsigned 8-bit number */ +typedef int WORD; /* signed 16-bit number */ +typedef unsigned int UWORD; /* unsigned 16-bit number */ +typedef long LONG; /* signed 32-bit number */ +typedef unsigned long ULONG; /* unsigned 32-bit number */ + +/* function prototypes */ +void SetVideoMode(UWORD mode); +WORD GetVideoMode(void); +void LoadPalette(UWORD numcolors, UWORD startcolor, UBYTE *paletteaddr); +void InitMouse(void); +void ShowMouse(void); +void HideMouse(void); +void ReadMouse(UWORD *buttonstate, UWORD *mousex, UWORD *mousey); +void PlayRunSkipDump(UBYTE *srcbuf, UBYTE *dstbuf); +void cls(UWORD color); + +#include "showanim.h" /* contains structures for large page files */ + +lpfileheader lpheader; /* file header will be loaded into this structure */ + +lp_descriptor LpArray[256]; /* arrays of large page structs used to find frames */ + +UBYTE lppalette[768]; /* anim file palette is loaded here */ +UBYTE *screen = (char *)0xA0000000l; /* pointer to the screen */ + +UWORD curlpnum=0xFFFF; /* initialize to an invalid Large page number */ + +lp_descriptor curlp; /* header of large page currently in memory */ + +UWORD *thepage; /* pointer to the buffer where current large page is loaded */ + +FILE *infile; /* input file pointer */ + +ULONG inputsize; /* input file size. I allways get this out of habbit */ + + +/* support routines for the rest of the program start here */ + +/* given a frame number return the large page number it resides in */ +UWORD findpage(framenumber) +UWORD framenumber; +{ + UWORD i; + + for(i=0; i framenumber) + return(i); + } + return(i); +} + +/* seek out and load in the large page specified */ +loadpage(pagenumber, pagepointer) +UWORD pagenumber; +UWORD *pagepointer; +{ + if(curlpnum!=pagenumber) + { + curlpnum=pagenumber; + fseek(infile, 0x0B00l+(LONG)pagenumber * 0x10000l,SEEK_SET); + fread(&curlp, sizeof(lp_descriptor), 1, infile); + getw(infile); /* skip empty word */ + fread(pagepointer, curlp.nBytes+(curlp.nRecords*2), 1, infile); + } +} + +/* This version of the decompressor is here for portability to non PC's */ +void CPlayRunSkipDump(srcP,dstP) +BYTE *srcP; /* srcP points at first sequence in Body */ +BYTE *dstP; /* dstP points at pixel #0 on screen. */ +{ + BYTE cnt; + UWORD wordCnt; + UBYTE pixel; + + +nextOp: + cnt = (signed char) *srcP++; + if (cnt > 0) + goto dump; + if (cnt == 0) + goto run; + cnt -= 0x80; + if (cnt == 0) + goto longOp; +/* shortSkip */ + dstP += cnt; /* adding 7-bit count to 32-bit pointer */ + goto nextOp; +dump: + do + { + *dstP++ = *srcP++; + } while (--cnt); + + dstP += cnt; + srcP += cnt; + goto nextOp; +run: + wordCnt = (UBYTE)*srcP++; /* 8-bit unsigned count */ + pixel = *srcP++; + do + { + *dstP++ = pixel; + } while (--wordCnt); + + dstP += wordCnt; + goto nextOp; +longOp: + wordCnt = *((UWORD far *)srcP)++; + if ((WORD)wordCnt <= 0) + goto notLongSkip; /* Do SIGNED test. */ + +/* longSkip. */ + dstP += wordCnt; + goto nextOp; + +notLongSkip: + if (wordCnt == 0) + goto stop; + wordCnt -= 0x8000; /* Remove sign bit. */ + if (wordCnt >= 0x4000) + goto longRun; + +/* longDump. */ + do + { + *dstP++ = *srcP++; + } while (--wordCnt); + + dstP += wordCnt; + srcP += wordCnt; + goto nextOp; + +longRun: + wordCnt -= 0x4000; /* Clear "longRun" bit. */ + pixel = *srcP++; + do + { + *dstP++ = pixel; + } while (--wordCnt); + + dstP += wordCnt; + goto nextOp; + +stop: /* all done */ + ; +} + + + +/* draw the frame sepcified from the large page in the buffer pointed to */ +renderframe(framenumber, pagepointer) +UWORD framenumber; +UWORD *pagepointer; +{ + UWORD offset=0; + UWORD i; + UWORD destframe; + UBYTE *ppointer; + + destframe = framenumber - curlp.baseRecord; + + for(i = 0; i < destframe; i++) + { + offset += pagepointer[i]; + } + ppointer = (UBYTE *)pagepointer; + + ppointer+=curlp.nRecords*2+offset; + + if(ppointer[1]) + { + ppointer += (4 + (((UWORD *)ppointer)[1] + (((UWORD *)ppointer)[1] & 1))); + } + else + { + ppointer+=4; + } + +/* + this is the C version of the decompressor, uncomment it if you are not + running on a PC +*/ +/* CPlayRunSkipDump(ppointer, screen); */ + + PlayRunSkipDump(ppointer, screen); +} + +/* high level frame draw routine */ +void drawframe(framenumber) +UWORD framenumber; +{ + loadpage(findpage(framenumber), thepage); + renderframe(framenumber, thepage); +} + +/* main program code */ +main(argc,argv) +int argc; +char *argv[]; +{ + UWORD i; + UWORD framecount; + WORD oldvideomode; + UWORD mousebutton=0, mousex=0, mousey=0; + +/* had to use "halloc" because I had to allocate a buffer exactly 64k long */ + thepage =(UWORD *)halloc(0x10000l,1); /* allocate page buffer */ + + if(argc < 2) + { + printf("'Showanim file.ANM' display Deluxe animate file on VGA screen.\n\n"); + return EXIT_FAILURE; + } + + if((infile = fopen(argv[1],"rb")) == NULL) + { + printf("Input file not found!\n"); + return EXIT_FAILURE; + } + + /* get the size of the anim file */ + fseek(infile, 0L, SEEK_END); + inputsize = ftell(infile); + rewind(infile); + + /* read the anim file header */ + if(fread(&lpheader,sizeof(lpfileheader),1,infile) == NULL) + { + printf("Error reading file header!\n"); + return EXIT_FAILURE; + } + + fseek(infile, 128L, SEEK_CUR); /* skip color cycling structures */ + + /* read in the color palette */ + for(i=0; i<768; i+=3) + { + lppalette[i+2] = (UBYTE)((getc(infile) >> 2) & 63); /* read red */ + lppalette[i+1] = (UBYTE)((getc(infile) >> 2) & 63); /* read green */ + lppalette[i] = (UBYTE)((getc(infile) >> 2) & 63); /* read blue */ + + getc(infile); /* skip over the extra pad byte */ + } + + /* read in large page descriptors */ + fread(LpArray,sizeof(lp_descriptor),256,infile); + + /* the file pointer now points to the first large page structure */ + + oldvideomode = GetVideoMode(); /* save the current video mode */ + + SetVideoMode(0x13); /* set the video mode to 13h MCGA 256 color */ + + cls(0); /* clear the screen to black */ + + LoadPalette(256,0,lppalette); /* init the color palette */ + + InitMouse(); + + HideMouse(); + + drawframe(0); /* draw the first frame of the file */ + + ShowMouse(); + + mousebutton=0; +/* + Remember, the last frame in the file is a delta back to the first frame. + You should only draw the first frame once and then use the last frame to + redraw the first frame. +*/ + while(!(mousebutton&1)) + { + + for(framecount = 1; framecount < (UWORD)lpheader.nRecords; framecount++) + { + ReadMouse(&mousebutton, &mousex, &mousey); + + while(!(mousebutton&3)) + ReadMouse(&mousebutton, &mousex, &mousey); + + if(mousebutton&1) + break; + + HideMouse(); + drawframe(framecount); + ShowMouse(); + } + } + + HideMouse(); + SetVideoMode(oldvideomode); + fclose(infile); + + hfree(thepage); + + return EXIT_SUCCESS; +} + + diff --git a/tools/old/anm/anmformt/SHOWANIM.H b/tools/old/anm/anmformt/SHOWANIM.H new file mode 100644 index 000000000..7dd9b6ad0 --- /dev/null +++ b/tools/old/anm/anmformt/SHOWANIM.H @@ -0,0 +1,69 @@ +/* structure declarations for deluxe animate large page files */ + + +typedef struct { + + ULONG id; /* 4 character ID == "LPF " */ + + UWORD maxLps; /* max # largePages allowed. 256 FOR NOW. */ + + UWORD nLps; /* # largePages in this file. */ + + ULONG nRecords; /* # records in this file. 65534 is current limit plus */ + /* one for last-to-first delta for looping the animation */ + + UWORD maxRecsPerLp; /* # records permitted in an lp. 256 FOR NOW. */ + + UWORD lpfTableOffset; /* Absolute Seek position of lpfTable. 1280 FOR NOW. + The lpf Table is an array of 256 large page structures + that is used to facilitate finding records in an anim + file without having to seek through all of the Large + Pages to find which one a specific record lives in. */ + + ULONG contentType; /* 4 character ID == "ANIM" */ + + UWORD width; /* Width of screen in pixels. */ + UWORD height; /* Height of screen in pixels. */ + UBYTE variant; /* 0==ANIM. */ + UBYTE version; /* 0==frame rate is multiple of 18 cycles/sec. + 1==frame rate is multiple of 70 cycles/sec. */ + + UBYTE hasLastDelta; /* 1==Last record is a delta from last-to-first frame. */ + + UBYTE lastDeltaValid; /* 0==The last-to-first delta (if present) hasn't been + updated to match the current first&last frames, so it + should be ignored. */ + + UBYTE pixelType; /* 0==256 color. */ + + UBYTE CompressionType; /* 1==(RunSkipDump) Only one used FOR NOW. */ + + UBYTE otherRecsPerFrm; /* 0 FOR NOW. */ + + UBYTE bitmaptype; /* 1==320x200, 256-color. Only one implemented so far. */ + + UBYTE recordTypes[32]; /* Not yet implemented. */ + + ULONG nFrames; /* In case future version adds other records at end of + file, we still know how many actual frames. + NOTE: DOES include last-to-first delta when present. */ + + UWORD framesPerSecond; /* Number of frames to play per second. */ + + UWORD pad2[29]; /* 58 bytes of filler to round up to 128 bytes total. */ +} lpfileheader; + + +/* this is the format of an large page structure */ +typedef struct { + UWORD baseRecord; /* Number of first record in this large page. */ + + UWORD nRecords; /* Number of records in lp. + bit 15 of "nRecords" == "has continuation from previous lp". + bit 14 of "nRecords" == "final record continues on next lp". */ + + UWORD nBytes; /* Total number of bytes of contents, excluding header. */ + +} lp_descriptor; + + diff --git a/tools/old/anm/anmformu/ANIMFILE.TXT b/tools/old/anm/anmformu/ANIMFILE.TXT new file mode 100644 index 000000000..a8d2b9308 --- /dev/null +++ b/tools/old/anm/anmformu/ANIMFILE.TXT @@ -0,0 +1,138 @@ +DeluxePaint Animation ".ANM" files consist of a large header and a series of +structures that can be up to 64 KB long each. The programmer refers to these +structures as "Large Pages". Large Pages are a format for dividing a file +into 64 KB chunks that can be stored out-of-sequence in the file. That is, +a large page can be logically inserted into the file, without having to move +all the following data out of the way. + +Each large page holds one or more "records". A record represents one frame +of the original animation. A record is of any length from 0 to almost 64 KB. +The records in a large page are sequential. However, the first large page +may not contain the first frames of the anim file. Each large page contains +a sequential set of records but the large pages themselves are not in +sequential order. It is possible for the first large page in a file to +contain the last few frames of the animation. When you process the anim file +you must scan the large page structures to find which large page conatins the +frame you wish to display or process next. + +A DeluxePaint Animation "ANM" ("Anim") file is built on this mechanism, +so that as frames change in size, they can be maintained with a minimum +of extra file i/o, yet without loss of playback performance. +In addition, there is an optional special record which is the delta from +the last frame to the first frame, for smooth playback of looping anims. + +The following is the structure of a DeluxeAnimate anim file header. +Header size is exactly 2816 bytes. The first large page structure can be +reached by simply seeking to this location in the file. + + ULONG id; 4 character ID == "LPF " + + UWORD maxLps; max # largePages allowed. 256 FOR NOW. + + UWORD nLps; # largePages in this file. + + ULONG nRecords; # records in this file. 65534 is current limit plus + one for last-to-first delta for looping the animation + + UWORD maxRecsPerLp; # records permitted in an lp. 256 FOR NOW. + + UWORD lpfTableOffset; Absolute Seek position of lpfTable. 1280 FOR NOW. + The lpf Table is an array of 256 large page structures + that is used to facilitate finding records in an anim + file without having to seek through all of the Large + Pages to find which one a specific record lives in. + + ULONG contentType; 4 character ID == "ANIM" + + UWORD width; Width of screen in pixels. + UWORD height; Height of screen in pixels. + UBYTE variant; 0==ANIM. + UBYTE version; 0==frame rate is multiple of 18 cycles/sec. + 1==frame rate is multiple of 70 cycles/sec. + + UBYTE hasLastDelta; 1==Last record is a delta from last-to-first frame. + + UBYTE lastDeltaValid; 0==The last-to-first delta (if present) hasn't been + updated to match the current first&last frames, so it + should be ignored. + + UBYTE pixelType; 0==256 color. + + UBYTE CompressionType; 1==(RunSkipDump) Only one used FOR NOW. + + UBYTE otherRecsPerFrm; 0 FOR NOW. + + UBYTE bitmaptype; 1==320x200, 256-color. Only one implemented so far. + + UBYTE recordTypes[32]; Not yet implemented. + + ULONG nFrames; In case future version adds other records at end of + file, we still know how many actual frames. + NOTE: DOES include last-to-first delta when present. + + UWORD framesPerSecond; Number of frames to play per second. + + UWORD pad2[29]; 58 bytes of filler to round up to 128 bytes total. + + Range cycles[16]; Color cycling info (128 bytes long). + This is the format of a cycle structure. + typedef struct { + WORD count; + WORD rate; + WORD flags; + UBYTE low, high; /* bounds of range */ + } Range; + + + total is = 256 bytes. + + Following the anim file header is the color palette + + ULONG palette[256] Color palette arranged as 3 bytes each of Red Green + & Blue and one unused byte. + + Following the palette is an array of structures that are copies of the + large page headers. This array is loaded and used to find which large page + a given frame can be found in. + + Large_page LParay[256] Copies of all the Large Page structures in the anim + file. Each Large Page structure is 6 bytes long so + the total length of this table is 1536 bytes. Even if + the file only contains 1 large page there are still + 256 entries of 6 bytes each. + + The Large Pages follow the LParray and are in the sequence dictated by + their order of occurence in the LParray in the anim file header. + + The following is the structure of a single Large Page in an anim file. Each + Large Page is exactly 64k long in the anim file. The only exception is the + last large page wich is truncated to be only as long as necessary. + + UWORD baseRecord; Number of first record in this large page. + + UWORD nRecords; Number of records in lp. + bit 15 of "nRecords" == "has continuation from previous lp". + bit 14 of "nRecords" == "final record continues on next lp". + + UWORD nBytes; Total number of bytes of contents, excluding header. + + UWORD BytesContinued; The number of bytes of the last record of the + previous large page that extend into this large page. + This was never implemented and is always 0. + + UWORD RecordSizes[nRecords] Array of lengths of each record in the large page. + + The actual records start here. Each record has a variable length header that + is like the following structure. + + typedef struct{ + UBYTE IDnum; always 66 + UBYTE Flags; 0==no extra bytes field next + + UWORD extrabytes; if Flags is non zero this is # of bytes + to skip before compressed data starts + extrabytes does not include the size + of the 2 previous bytes. Also make + sure you round the final address up to + an even byte boundry. + } record_header; diff --git a/tools/old/anm/anmformu/CGRAPH.ASM b/tools/old/anm/anmformu/CGRAPH.ASM new file mode 100644 index 000000000..ee389fb60 --- /dev/null +++ b/tools/old/anm/anmformu/CGRAPH.ASM @@ -0,0 +1,351 @@ +; my generic graphics routines for C programs + + + .8086 + + .model large,c + +;***************************************************************************** +; Program code starts here +;***************************************************************************** + + +EQUIP_FLAG EQU byte ptr ds:[10h] ; (in Video Display Data Area) + +CGAbits EQU 00100000b ; bits for EQUIP_FLAG +MDAbits EQU 00110000b + + + .code + + public SetVideoMode +SetVideoMode proc far + + push bp ; preserve caller registers + mov bp,sp + push ds + + mov ax,40h + mov ds,ax ; DS -> Video Display Data Area + + mov bl,CGAbits ; BL := bits indicating presence of CGA + mov al,6[bp] ; AL := desired video mode number + + mov ah,al ; test if desired mode is monochrome + and ah,7 + cmp ah,7 + jne L01 ; jump if desired mode not 7 or 0Fh + + mov bl,MDAbits ; BL := bits indicating presence of MDA + +L01: and EQUIP_FLAG,11001111b + or EQUIP_FLAG,bl ; set bits in EQUIP_FLAG + + xor ah,ah ; AH := 0 (INT 10h function number) + + push bp + int 10h ; call ROM BIOS to set the video mode + pop bp + + pop ds ; restore caller registers and return + pop bp + + ret + +SetVideoMode endp + + public GetVideoMode +GetVideoMode proc far + + push bp + mov ah,0Fh ; Get video mode sub-function + int 10h ; call ROM BIOS to get video mode number + pop bp + + xor ah,ah ; AX := video mode number + + ret + +GetVideoMode endp + + +; LoadPalette(numcolors, startcolor, paletteaddr) + public LoadPalette +LoadPalette proc far + + push bp + mov bp,sp + + push bx + push cx + push dx + push es + + mov bx,8[bp] + mov cx,6[bp] + mov es,12[bp] + mov dx,10[bp] + + mov ax,1012h + int 10H + + pop es + pop dx + pop cx + pop bx + pop bp + + ret + +LoadPalette endp + + +; initialize the mouse to its default values and display it + public InitMouse +InitMouse proc far + + push ax + + mov ax,0 + int 33h + mov ax,1 + int 33h + + pop ax + + ret + +InitMouse endp + +; display the mouse cursor + public ShowMouse +ShowMouse proc far + + push ax + + mov ax,1 + int 33h + + pop ax + + ret +ShowMouse endp + + +; hide the mouse cursor + public HideMouse +HideMouse proc far + push ax + + mov ax,2 + int 33h + + pop ax + + ret +HideMouse endp + +; read the mouse buttons and cursor position +; on exit: +; BX = button state bit 0 = left button bit 1 = right button +; CX = cursor x position +; DX = cursor y position + public ReadMouse +ReadMouse proc far + push bp + mov bp,sp + push ds + push si + push bx + push cx + push dx + + mov ax,3 + int 33h + + lds si,6[bp] + mov [si],bx + + lds si,10[bp] + mov [si],cx + + lds si,14[bp] + mov [si],dx + + + pop dx + pop cx + pop bx + pop si + pop ds + + pop bp + + ret +ReadMouse endp + +; PlayRunSkipDump(sourcebuf, destbuf); + public PlayRunSkipDump +PlayRunSkipDump proc far + +ARGB = 6 +PR_SRC_SEG = ARGB+2 +PR_SRC_ADDR = ARGB +PR_DST_SEG = ARGB+6 +PR_DST_ADDR = ARGB+4 + + push bp + mov bp,sp + push si + push di + push es + + mov si,PR_SRC_ADDR[bp] + mov di,PR_DST_ADDR[bp] + mov es,PR_DST_SEG[bp] + + push ds ; Save DS:DGROUP. + mov ds,PR_SRC_SEG[bp] ; SET DS:dstSeg. NOT DGROUP. + + sub ch,ch ; SET CH = 0. + jmp short nextOp + +skip: + sub cl,80h ; Strip off sign bit, leaving skip cnt. + jz longOp ; cnt==0 indicates a long op. +; --- shortSkip --- + add di,cx ; skip # pixels. (CH=0) +; --- variation on NEXTOP inline to minimize jmp's --- +nextOp: ; Get and decode next op. + mov cl,[si] + inc si + jcxz run + or cl,cl ; Test CL's sign bit. + jl skip +dump: + rep movsb ; copy # pixels. (CH=0) +; --- variation on NEXTOP inline to minimize jmp's --- + mov cl,[si] + inc si + or cl,cl ; Test CL's sign bit. + jl skip + jg dump +run: + mov cl,[si] ; 8-bit unsigned count. + inc si + lodsb ; pixel value. + rep stosb ; set # pixels to value. (CH=0) +; --- variation on NEXTOP inline to minimize jmp's --- + mov cl,[si] + inc si + jcxz run + or cl,cl ; Test CL's sign bit. + jl skip + jmp short dump + +longOp: ; NOTE: if load into CX, must clear CH afterwards. + lodsw ; 16-bit unsigned count. + or ax,ax ; set flags. + jle notLongSkip +;longSkip: + add di,ax ; skip # pixels. + jmp short nextOp + ; longSkip only used for > 2*127, so can't be very many, + ; so don't bother saving one jmp with inline NEXTOP. + +notLongSkip: + jz stop ; long count of zero means "stop code". + mov cx,ax ; may SET CH non-zero. + sub ch,80h ; Clear sign bit. + cmp ch,40h + jge longRun +; --- For maximum speed on longDump, caller should insure src & dst are +; aligned. To do so, caller must calculate whether +; src DATA will begin on same (odd or even) alignment as dst data. +; If not, first put a 1-byte Dump, which occupies 2 src bytes, thereby +; shifting relative alignment (src moves 2, dst moves 1). +;longDump + test si,1 ; Insure src word-aligned. + ; In case caller didn't sync src & dst, we chose + ; to align src because we know it is of benefit -- + ; aligning dst on 8-bit video cards might not be of + ; any benefit. + jz dumpWordAligned + movsb ; get to word boundary. + dec cx +dumpWordAligned: + shr cx,1 ; Convert byte count to word count. + jc dumpOddByte + rep movsw ; Word-aligned. +longOpDone: + sub ch,ch ; SET CH = 0. + jmp short nextOp + +dumpOddByte: + rep movsw ; Word-aligned. + movsb + jmp short longOpDone + +longRun: + sub ch,40h ; Clear "longRun" bit. + lodsb + mov ah,al ; Replicate byte to word value. + test di,1 ; Insure dst word-aligned. + jz runWordAligned + stosb + dec cx +runWordAligned: + shr cx,1 ; Convert byte count to word count. + jc runOddByte + rep stosw ; Word-aligned. + jmp short longOpDone + +runOddByte: + rep stosw ; Word-aligned. + stosb + jmp short longOpDone + +stop: + pop ds ; Restore DS:DGROUP. + + mov ax,di ; RETURN final dstAddr. + pop es + pop di + pop si + pop bp + ret + +PlayRunSkipDump endp + +; clear the screen to a color +; cls(color); + public cls +cls proc far + + push bp + mov bp,sp + + push di + push es + push cx + + mov ax,0A000h + mov es,ax + xor di,di + + mov al,6[bp] + mov ah,al + mov cx,32000 + rep stosw + + pop cx + pop es + pop di + + pop bp + + ret + +cls endp + + end diff --git a/tools/old/anm/anmformu/MAKESHOW.M b/tools/old/anm/anmformu/MAKESHOW.M new file mode 100644 index 000000000..ccf542e36 --- /dev/null +++ b/tools/old/anm/anmformu/MAKESHOW.M @@ -0,0 +1,8 @@ +showanim.obj: showanim.c showanim.h +cl /c /Zi /AL showanim.c + +cgraph.obj: cgraph.asm + masm $*; + +showanim.exe: showanim.obj cgraph.obj + link /co showanim+cgraph; diff --git a/tools/old/anm/anmformu/SHOWANIM.C b/tools/old/anm/anmformu/SHOWANIM.C new file mode 100644 index 000000000..3f7755fb0 --- /dev/null +++ b/tools/old/anm/anmformu/SHOWANIM.C @@ -0,0 +1,323 @@ +/* + This is a small program to play a deluxe animate file. No attempt has + been made to time the animation speed correctly. The playback speed will + be dictated by the speed of your machine. +*/ + +#include +#include +#include + +#define EXIT_FAILURE 1 +#define EXIT_SUCCESS 0 + +#define TRUE 1 +#define FALSE 0 + +/* Typedefs for portability. */ + +typedef char BOOL; /* 0==FALSE, 1==TRUE */ +typedef char BYTE; /* signed 8-bit number */ +typedef unsigned char UBYTE; /* unsigned 8-bit number */ +typedef int WORD; /* signed 16-bit number */ +typedef unsigned int UWORD; /* unsigned 16-bit number */ +typedef long LONG; /* signed 32-bit number */ +typedef unsigned long ULONG; /* unsigned 32-bit number */ + +/* function prototypes */ +void SetVideoMode(UWORD mode); +WORD GetVideoMode(void); +void LoadPalette(UWORD numcolors, UWORD startcolor, UBYTE *paletteaddr); +void InitMouse(void); +void ShowMouse(void); +void HideMouse(void); +void ReadMouse(UWORD *buttonstate, UWORD *mousex, UWORD *mousey); +void PlayRunSkipDump(UBYTE *srcbuf, UBYTE *dstbuf); +void cls(UWORD color); + +#include "showanim.h" /* contains structures for large page files */ + +lpfileheader lpheader; /* file header will be loaded into this structure */ + +lp_descriptor LpArray[256]; /* arrays of large page structs used to find frames */ + +UBYTE lppalette[768]; /* anim file palette is loaded here */ +UBYTE *screen = (char *)0xA0000000l; /* pointer to the screen */ + +UWORD curlpnum=0xFFFF; /* initialize to an invalid Large page number */ + +lp_descriptor curlp; /* header of large page currently in memory */ + +UWORD *thepage; /* pointer to the buffer where current large page is loaded */ + +FILE *infile; /* input file pointer */ + +ULONG inputsize; /* input file size. I allways get this out of habbit */ + + +/* support routines for the rest of the program start here */ + +/* given a frame number return the large page number it resides in */ +UWORD findpage(framenumber) +UWORD framenumber; +{ + UWORD i; + + for(i=0; i framenumber) + return(i); + } + return(i); +} + +/* seek out and load in the large page specified */ +loadpage(pagenumber, pagepointer) +UWORD pagenumber; +UWORD *pagepointer; +{ + if(curlpnum!=pagenumber) + { + curlpnum=pagenumber; + fseek(infile, 0x0B00l+(LONG)pagenumber * 0x10000l,SEEK_SET); + fread(&curlp, sizeof(lp_descriptor), 1, infile); + getw(infile); /* skip empty word */ + fread(pagepointer, curlp.nBytes+(curlp.nRecords*2), 1, infile); + } +} + +/* This version of the decompressor is here for portability to non PC's */ +void CPlayRunSkipDump(srcP,dstP) +BYTE *srcP; /* srcP points at first sequence in Body */ +BYTE *dstP; /* dstP points at pixel #0 on screen. */ +{ + BYTE cnt; + UWORD wordCnt; + UBYTE pixel; + + +nextOp: + cnt = (signed char) *srcP++; + if (cnt > 0) + goto dump; + if (cnt == 0) + goto run; + cnt -= 0x80; + if (cnt == 0) + goto longOp; +/* shortSkip */ + dstP += cnt; /* adding 7-bit count to 32-bit pointer */ + goto nextOp; +dump: + do + { + *dstP++ = *srcP++; + } while (--cnt); + + dstP += cnt; + srcP += cnt; + goto nextOp; +run: + wordCnt = (UBYTE)*srcP++; /* 8-bit unsigned count */ + pixel = *srcP++; + do + { + *dstP++ = pixel; + } while (--wordCnt); + + dstP += wordCnt; + goto nextOp; +longOp: + wordCnt = *((UWORD far *)srcP)++; + if ((WORD)wordCnt <= 0) + goto notLongSkip; /* Do SIGNED test. */ + +/* longSkip. */ + dstP += wordCnt; + goto nextOp; + +notLongSkip: + if (wordCnt == 0) + goto stop; + wordCnt -= 0x8000; /* Remove sign bit. */ + if (wordCnt >= 0x4000) + goto longRun; + +/* longDump. */ + do + { + *dstP++ = *srcP++; + } while (--wordCnt); + + dstP += wordCnt; + srcP += wordCnt; + goto nextOp; + +longRun: + wordCnt -= 0x4000; /* Clear "longRun" bit. */ + pixel = *srcP++; + do + { + *dstP++ = pixel; + } while (--wordCnt); + + dstP += wordCnt; + goto nextOp; + +stop: /* all done */ + ; +} + + + +/* draw the frame sepcified from the large page in the buffer pointed to */ +renderframe(framenumber, pagepointer) +UWORD framenumber; +UWORD *pagepointer; +{ + UWORD offset=0; + UWORD i; + UWORD destframe; + UBYTE *ppointer; + + destframe = framenumber - curlp.baseRecord; + + for(i = 0; i < destframe; i++) + { + offset += pagepointer[i]; + } + ppointer = (UBYTE *)pagepointer; + + ppointer+=curlp.nRecords*2+offset; + + if(ppointer[1]) + { + ppointer += (4 + (((UWORD *)ppointer)[1] + (((UWORD *)ppointer)[1] & 1))); + } + else + { + ppointer+=4; + } + +/* + this is the C version of the decompressor, uncomment it if you are not + running on a PC +*/ +/* CPlayRunSkipDump(ppointer, screen); */ + + PlayRunSkipDump(ppointer, screen); +} + +/* high level frame draw routine */ +void drawframe(framenumber) +UWORD framenumber; +{ + loadpage(findpage(framenumber), thepage); + renderframe(framenumber, thepage); +} + +/* main program code */ +main(argc,argv) +int argc; +char *argv[]; +{ + UWORD i; + UWORD framecount; + WORD oldvideomode; + UWORD mousebutton=0, mousex=0, mousey=0; + +/* had to use "halloc" because I had to allocate a buffer exactly 64k long */ + thepage =(UWORD *)halloc(0x10000l,1); /* allocate page buffer */ + + if(argc < 2) + { + printf("'Showanim file.ANM' display Deluxe animate file on VGA screen.\n\n"); + return EXIT_FAILURE; + } + + if((infile = fopen(argv[1],"rb")) == NULL) + { + printf("Input file not found!\n"); + return EXIT_FAILURE; + } + + /* get the size of the anim file */ + fseek(infile, 0L, SEEK_END); + inputsize = ftell(infile); + rewind(infile); + + /* read the anim file header */ + if(fread(&lpheader,sizeof(lpfileheader),1,infile) == NULL) + { + printf("Error reading file header!\n"); + return EXIT_FAILURE; + } + + fseek(infile, 128L, SEEK_CUR); /* skip color cycling structures */ + + /* read in the color palette */ + for(i=0; i<768; i+=3) + { + lppalette[i+2] = (UBYTE)((getc(infile) >> 2) & 63); /* read red */ + lppalette[i+1] = (UBYTE)((getc(infile) >> 2) & 63); /* read green */ + lppalette[i] = (UBYTE)((getc(infile) >> 2) & 63); /* read blue */ + + getc(infile); /* skip over the extra pad byte */ + } + + /* read in large page descriptors */ + fread(LpArray,sizeof(lp_descriptor),256,infile); + + /* the file pointer now points to the first large page structure */ + + oldvideomode = GetVideoMode(); /* save the current video mode */ + + SetVideoMode(0x13); /* set the video mode to 13h MCGA 256 color */ + + cls(0); /* clear the screen to black */ + + LoadPalette(256,0,lppalette); /* init the color palette */ + + InitMouse(); + + HideMouse(); + + drawframe(0); /* draw the first frame of the file */ + + ShowMouse(); + + mousebutton=0; +/* + Remember, the last frame in the file is a delta back to the first frame. + You should only draw the first frame once and then use the last frame to + redraw the first frame. +*/ + while(!(mousebutton&1)) + { + + for(framecount = 1; framecount < (UWORD)lpheader.nRecords; framecount++) + { + ReadMouse(&mousebutton, &mousex, &mousey); + + while(!(mousebutton&3)) + ReadMouse(&mousebutton, &mousex, &mousey); + + if(mousebutton&1) + break; + + HideMouse(); + drawframe(framecount); + ShowMouse(); + } + } + + HideMouse(); + SetVideoMode(oldvideomode); + fclose(infile); + + hfree(thepage); + + return EXIT_SUCCESS; +} + + diff --git a/tools/old/anm/anmformu/SHOWANIM.H b/tools/old/anm/anmformu/SHOWANIM.H new file mode 100644 index 000000000..7dd9b6ad0 --- /dev/null +++ b/tools/old/anm/anmformu/SHOWANIM.H @@ -0,0 +1,69 @@ +/* structure declarations for deluxe animate large page files */ + + +typedef struct { + + ULONG id; /* 4 character ID == "LPF " */ + + UWORD maxLps; /* max # largePages allowed. 256 FOR NOW. */ + + UWORD nLps; /* # largePages in this file. */ + + ULONG nRecords; /* # records in this file. 65534 is current limit plus */ + /* one for last-to-first delta for looping the animation */ + + UWORD maxRecsPerLp; /* # records permitted in an lp. 256 FOR NOW. */ + + UWORD lpfTableOffset; /* Absolute Seek position of lpfTable. 1280 FOR NOW. + The lpf Table is an array of 256 large page structures + that is used to facilitate finding records in an anim + file without having to seek through all of the Large + Pages to find which one a specific record lives in. */ + + ULONG contentType; /* 4 character ID == "ANIM" */ + + UWORD width; /* Width of screen in pixels. */ + UWORD height; /* Height of screen in pixels. */ + UBYTE variant; /* 0==ANIM. */ + UBYTE version; /* 0==frame rate is multiple of 18 cycles/sec. + 1==frame rate is multiple of 70 cycles/sec. */ + + UBYTE hasLastDelta; /* 1==Last record is a delta from last-to-first frame. */ + + UBYTE lastDeltaValid; /* 0==The last-to-first delta (if present) hasn't been + updated to match the current first&last frames, so it + should be ignored. */ + + UBYTE pixelType; /* 0==256 color. */ + + UBYTE CompressionType; /* 1==(RunSkipDump) Only one used FOR NOW. */ + + UBYTE otherRecsPerFrm; /* 0 FOR NOW. */ + + UBYTE bitmaptype; /* 1==320x200, 256-color. Only one implemented so far. */ + + UBYTE recordTypes[32]; /* Not yet implemented. */ + + ULONG nFrames; /* In case future version adds other records at end of + file, we still know how many actual frames. + NOTE: DOES include last-to-first delta when present. */ + + UWORD framesPerSecond; /* Number of frames to play per second. */ + + UWORD pad2[29]; /* 58 bytes of filler to round up to 128 bytes total. */ +} lpfileheader; + + +/* this is the format of an large page structure */ +typedef struct { + UWORD baseRecord; /* Number of first record in this large page. */ + + UWORD nRecords; /* Number of records in lp. + bit 15 of "nRecords" == "has continuation from previous lp". + bit 14 of "nRecords" == "final record continues on next lp". */ + + UWORD nBytes; /* Total number of bytes of contents, excluding header. */ + +} lp_descriptor; + + diff --git a/tools/old/anm/anmformu/anmformt.txt b/tools/old/anm/anmformu/anmformt.txt new file mode 100644 index 000000000..2a0c43f9c --- /dev/null +++ b/tools/old/anm/anmformu/anmformt.txt @@ -0,0 +1,5 @@ +Long Description: Info and code on the DeluxePaint Animation .ANM file format + Tutorial: No + Sample Code: Yes + Utility/Tool: No + Notes: Nicely documented, and works. diff --git a/tools/old/anm/cnv1.bat b/tools/old/anm/cnv1.bat new file mode 100755 index 000000000..e978085c1 --- /dev/null +++ b/tools/old/anm/cnv1.bat @@ -0,0 +1,2 @@ +anim2pcx %1 +ren ????0???.pcx %1.pcx diff --git a/tools/old/anm/cnvrtanm.bat b/tools/old/anm/cnvrtanm.bat new file mode 100755 index 000000000..dcfe6618a --- /dev/null +++ b/tools/old/anm/cnvrtanm.bat @@ -0,0 +1,2 @@ +\sc2\utils\anm\anim2pcx %1 +ren *????.pcx %1*????.pcx diff --git a/tools/old/anm/msvc++/anm2pcx.dsp b/tools/old/anm/msvc++/anm2pcx.dsp new file mode 100644 index 000000000..dad2b9266 --- /dev/null +++ b/tools/old/anm/msvc++/anm2pcx.dsp @@ -0,0 +1,96 @@ +# Microsoft Developer Studio Project File - Name="anm2pcx" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=anm2pcx - 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 "anm2pcx.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 "anm2pcx.mak" CFG="anm2pcx - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "anm2pcx - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "anm2pcx - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "anm2pcx - 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 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 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /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=link.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 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 winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 + +!ELSEIF "$(CFG)" == "anm2pcx - 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 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 /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /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=link.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 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 winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 + +!ENDIF + +# Begin Target + +# Name "anm2pcx - Win32 Release" +# Name "anm2pcx - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# 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/old/anm/msvc++/anm2pcx.dsw b/tools/old/anm/msvc++/anm2pcx.dsw new file mode 100644 index 000000000..89bba224c --- /dev/null +++ b/tools/old/anm/msvc++/anm2pcx.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "anm2pcx"=".\anm2pcx.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/tools/old/font test/fonts.c b/tools/old/font test/fonts.c new file mode 100644 index 000000000..79536467b --- /dev/null +++ b/tools/old/font test/fonts.c @@ -0,0 +1,158 @@ +#include +#include +#include + +#include +#include + +#include + +void process_input(void); +void init_sdl(void); +SDL_Surface *init_video(void); +void showLastError(char *c); + +static char* font_names[] = { "SC2 Arilou", "SC2 Chmmr", "SC2 Earthling", + "SC2 Ilwrath", "SC2 Kohr-Ah", "SC2 Melnorme/Druuge", "SC2 Mycon", + "SC2 Orz", "SC2 Pkunk", "SC2 Shofixti", "SC2 Slylandro", + "SC2 Slylandro Probe", "SC2 Spathi", "SC2 Supox", "SC2 Syreen", + "SC2 Talking Pet", "SC2 Thraddash", "SC2 Umgah", "SC2 Ur-Quan", + "SC2 Utwig", "SC2 VUX", "SC2 Yehat", "SC2 ZoqFotPik" }; +#define NUM_FONTS 23 +int currentFont = 0; + +void init(void) { + HDC hdc; + + glClearColor(0.0, 0.0, 0.0, 0.0); + glShadeModel(GL_FLAT); +// glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +} + +void display(void) { + HDC hdc; + HGDIOBJ hgdiobj; + + glClear(GL_COLOR_BUFFER_BIT); + + if ((hdc = wglGetCurrentDC()) == NULL) { + showLastError("wglGetCurrentDC failed"); + } + if ((hgdiobj = SelectObject(hdc, CreateFont(0, 0, 0, 0, FW_DONTCARE, + FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, + font_names[currentFont]))) == NULL) { + showLastError("SelectObject failed"); + } + if (!wglUseFontBitmaps(hdc, 0, 255, 1000)) { + showLastError("wglUseFontBitmaps failed"); + } + + glListBase(1000); + glRasterPos2d(-.9, .15); + glCallLists(strlen(font_names[currentFont]), GL_UNSIGNED_BYTE, + font_names[currentFont]); + glRasterPos2d(-.9, 0); + glCallLists(28, GL_UNSIGNED_BYTE, "Press UP/DOWN to change font"); + glRasterPos2d(-.9, -.15); + glCallLists(23, GL_UNSIGNED_BYTE, "0123 ABC abc !@#$%^&*()"); + + if (DeleteObject(hgdiobj) == 0) { + showLastError("DeleteObject failed"); + } + glFlush(); + SDL_GL_SwapBuffers(); +} + +int main(int argc, char*argv[]) { + SDL_Surface *screen; + + init_sdl(); + init_video(); + init(); + while (1) { + display(); + process_input(); + } + return 0; +} + +// The following functions are mostly unimportant -- they just set up opengl and sdl + +// Shows last Windows error in a message box using GetLastError() +void showLastError(char *c) { + LPVOID lpMsgBuf; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + + // Display the string. + MessageBox( NULL, lpMsgBuf, c, MB_OK|MB_ICONINFORMATION ); + + // Free the buffer. + LocalFree( lpMsgBuf ); +} + +//the following functions merely deal with OpenGL and SDL + +void process_input(void) { + SDL_Event e; + + while (SDL_PollEvent(&e)) { + switch (e.type) { + case SDL_KEYDOWN: + if (e.key.keysym.sym == SDLK_ESCAPE) { + exit(0); + } + if (e.key.keysym.sym == SDLK_UP) { + currentFont --; + if (currentFont < 0) { + currentFont = NUM_FONTS - 1; + } + } + if (e.key.keysym.sym == SDLK_DOWN) { + currentFont ++; + if (currentFont == NUM_FONTS) { + currentFont = 0; + } + } + + break; + case SDL_QUIT: + exit(0); + break; + } + } +} + +void init_sdl(void) { + if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) { + fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError()); + exit(1); + } + atexit(SDL_Quit); + + SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 ); + SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 ); + SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 ); + SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 ); + SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); +} + +SDL_Surface *init_video(void) { + SDL_Surface *screen; + + screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE | SDL_OPENGL); + if ( screen == NULL ) { + fprintf(stderr, "Unable to set video: %s\n", SDL_GetError()); + exit(1); + } + + return screen; +} diff --git a/tools/old/ndxscripts/ndxcomms.bat b/tools/old/ndxscripts/ndxcomms.bat new file mode 100755 index 000000000..d4b057b6d --- /dev/null +++ b/tools/old/ndxscripts/ndxcomms.bat @@ -0,0 +1,74 @@ +cd \sc2\src\3do_code\comm +cd arilou +\sc2\Utils\ndx arilou.res \sc2\Content\arilou.con +cd .. +cd blackur +\sc2\Utils\ndx blackur.res \sc2\Content\blackur.con +cd .. +cd chmmr +\sc2\Utils\ndx chmmr.res \sc2\Content\chmmr.con +cd .. +cd druuge +\sc2\Utils\ndx druuge.res \sc2\Content\druuge.con +cd .. +cd comandr +\sc2\Utils\ndx comandr.res \sc2\Content\comandr.con +cd .. +cd ilwrath +\sc2\Utils\ndx ilwrath.res \sc2\Content\ilwrath.con +cd .. +cd slyhome +\sc2\Utils\ndx slyhome.res \sc2\Content\slyhome.con +cd .. +cd melnorm +\sc2\Utils\ndx melnorm.res \sc2\Content\melnorm.con +cd .. +cd talkpet +\sc2\Utils\ndx talkpet.res \sc2\Content\talkpet.con +cd .. +cd mycon +\sc2\Utils\ndx mycon.res \sc2\Content\mycon.con +cd .. +cd orz +\sc2\Utils\ndx orz.res \sc2\Content\orz.con +cd .. +cd pkunk +\sc2\Utils\ndx pkunk.res \sc2\Content\pkunk.con +cd .. +cd shofixt +\sc2\Utils\ndx shofixt.res \sc2\Content\shofixt.con +cd .. +cd slyland +\sc2\Utils\ndx slyland.res \sc2\Content\slyland.con +cd .. +cd spathi +\sc2\Utils\ndx spathi.res \sc2\Content\spathi.con +cd .. +cd supox +\sc2\Utils\ndx supox.res \sc2\Content\supox.con +cd .. +cd syreen +\sc2\Utils\ndx syreen.res \sc2\Content\syreen.con +cd .. +cd thradd +\sc2\Utils\ndx thradd.res \sc2\Content\thradd.con +cd .. +cd umgah +\sc2\Utils\ndx umgah.res \sc2\Content\umgah.con +cd .. +cd urquan +\sc2\Utils\ndx urquan.res \sc2\Content\urquan.con +cd .. +cd utwig +\sc2\Utils\ndx utwig.res \sc2\Content\utwig.con +cd .. +cd vux +\sc2\Utils\ndx vux.res \sc2\Content\vux.con +cd .. +cd yehat +\sc2\Utils\ndx yehat.res \sc2\Content\yehat.con +cd .. +cd zoqfot +\sc2\Utils\ndx zoqfot.res \sc2\Content\zoqfot.con +cd .. +cd \sc2 diff --git a/tools/old/ndxscripts/ndxships.bat b/tools/old/ndxscripts/ndxships.bat new file mode 100755 index 000000000..50e2cdf2e --- /dev/null +++ b/tools/old/ndxscripts/ndxships.bat @@ -0,0 +1,86 @@ +cd \sc2\src\3do_code +\sc2\Utils\ndx star3do.res \sc2\Content\starcon.ndx +cd sis_ship +\sc2\Utils\ndx sis.res \sc2\Content\sis.dat +cd .. +cd androsyn +\sc2\Utils\ndx androsyn.res \sc2\Content\androsyn.shp +cd .. +cd arilou +\sc2\Utils\ndx arilou.res \sc2\Content\arilou.shp +cd .. +cd blackurq +\sc2\Utils\ndx blackurq.res \sc2\Content\blackurq.shp +cd .. +cd chenjesu +\sc2\Utils\ndx chenjesu.res \sc2\Content\chenjesu.shp +cd .. +cd chmmr +\sc2\Utils\ndx chmmr.res \sc2\Content\chmmr.shp +cd .. +cd druuge +\sc2\Utils\ndx druuge.res \sc2\Content\druuge.shp +cd .. +cd human +\sc2\Utils\ndx human.res \sc2\Content\human.shp +cd .. +cd ilwrath +\sc2\Utils\ndx ilwrath.res \sc2\Content\ilwrath.shp +cd .. +cd lastbat +\sc2\Utils\ndx lastbat.res \sc2\Content\lastbat.shp +cd .. +cd melnorme +\sc2\Utils\ndx melnorme.res \sc2\Content\melnorme.shp +cd .. +cd mmrnmhrm +\sc2\Utils\ndx mmrnmhrm.res \sc2\Content\mmrnmhrm.shp +cd .. +cd mycon +\sc2\Utils\ndx mycon.res \sc2\Content\mycon.shp +cd .. +cd orz +\sc2\Utils\ndx orz.res \sc2\Content\orz.shp +cd .. +cd pkunk +\sc2\Utils\ndx pkunk.res \sc2\Content\pkunk.shp +cd .. +cd probe +\sc2\Utils\ndx probe.res \sc2\Content\probe.sc2 +cd .. +cd shofixti +\sc2\Utils\ndx shofixti.res \sc2\Content\shofixti.shp +cd .. +cd slylandr +\sc2\Utils\ndx slylandr.res \sc2\Content\slylandr.shp +cd .. +cd spathi +\sc2\Utils\ndx spathi.res \sc2\Content\spathi.shp +cd .. +cd supox +\sc2\Utils\ndx supox.res \sc2\Content\supox.shp +cd .. +cd syreen +\sc2\Utils\ndx syreen.res \sc2\Content\syreen.shp +cd .. +cd thradd +\sc2\Utils\ndx thradd.res \sc2\Content\thradd.shp +cd .. +cd umgah +\sc2\Utils\ndx umgah.res \sc2\Content\umgah.shp +cd .. +cd urquan +\sc2\Utils\ndx urquan.res \sc2\Content\urquan.shp +cd .. +cd utwig +\sc2\Utils\ndx utwig.res \sc2\Content\utwig.shp +cd .. +cd vux +\sc2\Utils\ndx vux.res \sc2\Content\vux.shp +cd .. +cd yehat +\sc2\Utils\ndx yehat.res \sc2\Content\yehat.shp +cd .. +cd zoqfot +\sc2\Utils\ndx zoqfot.res \sc2\Content\zoqfot.shp +cd .. diff --git a/tools/old/palette test/Palette Shifting Test.dsp b/tools/old/palette test/Palette Shifting Test.dsp new file mode 100644 index 000000000..23d603822 --- /dev/null +++ b/tools/old/palette test/Palette Shifting Test.dsp @@ -0,0 +1,111 @@ +# Microsoft Developer Studio Project File - Name="Palette Shifting Test" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=Palette Shifting Test - 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 "Palette Shifting Test.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 "Palette Shifting Test.mak" CFG="Palette Shifting Test - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Palette Shifting Test - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "Palette Shifting Test - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Palette Shifting Test - 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 "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x1c09 /d "NDEBUG" +# ADD RSC /l 0x1c09 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.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:windows /machine:I386 +# ADD 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:windows /machine:I386 + +!ELSEIF "$(CFG)" == "Palette Shifting Test - 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 "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MD /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x1c09 /d "_DEBUG" +# ADD RSC /l 0x1c09 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.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:windows /debug /machine:I386 /pdbtype:sept +# ADD 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 sdl.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "Palette Shifting Test - Win32 Release" +# Name "Palette Shifting Test - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\main.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE="..\..\SDL-1.2.4\lib\SDL.lib" +# End Source File +# End Group +# End Target +# End Project diff --git a/tools/old/palette test/Palette Shifting Test.dsw b/tools/old/palette test/Palette Shifting Test.dsw new file mode 100644 index 000000000..535a673be --- /dev/null +++ b/tools/old/palette test/Palette Shifting Test.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "Palette Shifting Test"=".\Palette Shifting Test.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/tools/old/palette test/main.cpp b/tools/old/palette test/main.cpp new file mode 100644 index 000000000..5296d4789 --- /dev/null +++ b/tools/old/palette test/main.cpp @@ -0,0 +1,506 @@ +/****************************************************************************** + + Palette Shifting Test + Copyright (C) 2002 Stuart Binge (datura@mighty.co.za) + + 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. You can also view the GNU + General Public License, online, at the GNU Homepage: http://www.gnu.org + + ******************************************************************************/ + +/* + * NOTE: If you are building with MSVC, make sure that the "Use runtime library" + * setting is "Multithreaded DLL", in "Project->Settings->C++->Code Generation". + * Use this setting for both debug and runtime builds. Also use "Win32 + * Application" as the project template, NOT "Win32 Console Application", when + * creating a project for this. + */ + +/* + * NOTE: You'll need to add the OpenGL, GLU, and SDL libs to your project if your + * compiler does not understand these lib pragma's. + */ +#pragma comment(lib, "opengl32") +#pragma comment(lib, "glu32") +#pragma comment(lib, "sdl") +#pragma comment(lib, "sdlmain") + +#include + +#ifdef _WIN32 +// Win32 GL headers require that windows.h be included before them +#include +#endif + +#include +#include + +#include +#include + +#include +#include +#include + +const double pi = 3.14159265358979323846; + +bool g_bRunning = true; +bool g_bRotate = false; +bool g_bCycle1 = false; +bool g_bCycle2 = false; + +const int g_iWidth = 640; +const int g_iHeight = 480; +const bool g_bFullscreen = false; + +GLuint g_uiTexName = 0; +char* g_pcData; +int g_iTexWid; +int g_iTexHei; +GLfloat g_rpal[256]; +GLfloat g_gpal[256]; +GLfloat g_bpal[256]; +GLfloat g_apal[256]; +SDL_Surface* g_ssAppWindow; + +/* + * NOTE: The following structures are assumed to be in little-endian format + * (i.e. as used on Intel-32 architecture). + */ + +/* + * NOTE: if not building with MSVC, or if your compiler does not understand + * pack pragma's, then change this next structure to somehow use 1-byte + * alignment. + */ +#pragma pack(push, 1) + +struct sRGBTriple { + Uint8 rgbt_Blue; + Uint8 rgbt_Green; + Uint8 rgbt_Red; +}; + +#pragma pack(pop) + +struct sRGBQuad { + Uint8 rgbq_Blue; + Uint8 rgbq_Green; + Uint8 rgbq_Red; + Uint8 rgbq_Reserved; +}; + +/* + * NOTE: if not building with MSVC, or if your compiler does not understand + * pack pragma's, then change this next structure to somehow use 2-byte + * alignment. + */ +#pragma pack(push, 2) + +struct sBitmapFileHeader { + Uint16 bfh_Type; + Uint32 bfh_Size; + Uint16 bfh_Reserved1; + Uint16 bfh_Reserved2; + Uint32 bfh_OffBits; +}; + +#pragma pack(pop) + +// Currently defined valid bitmap headers + +// This first header uses sRGBTriple's for its colour map +struct sBitmapHeader_1 { + Uint16 bh1_Width; + Uint16 bh1_Height; + Uint16 bh1_Planes; + Uint16 bh1_BitCount; +}; + +// Headers 2, 3 and 4 have this structure in common +struct sStandardBH { + Uint32 Width; + Uint32 Height; + Uint16 Planes; + Uint16 BitCount; + Uint32 Compression; + Uint32 SizeImage; + Uint32 XPelsPerMeter; + Uint32 YPelsPerMeter; + Uint32 ClrUsed; +}; + +// The next three headers use sRGBQuad's for their colour map +struct sBitmapHeader_2 { + sStandardBH std; + Uint32 _unused[1]; +}; + +struct sBitmapHeader_3 { + sStandardBH std; + Uint32 _unused[18]; +}; + +struct sBitmapHeader_4 { + sStandardBH std; + Uint32 _unused[22]; +}; + +// End of structures + +bool img_Load8bppBMP(std::string filename) { + if (filename.empty()) return false; + + std::ifstream file(filename.c_str(), std::ios_base::binary | std::ios_base::in); + if (!file) return false; + + sBitmapFileHeader bfh; + + file.read(reinterpret_cast(&bfh), sizeof(sBitmapFileHeader)); + if (file.bad() || file.eof()) return false; + + if (bfh.bfh_Type != (('M' << 8) | 'B')) return false; + + Uint32 hdrsz; + + file.read(reinterpret_cast(&hdrsz), sizeof(Uint32)); + if (file.bad() || file.eof()) return false; + + hdrsz -= sizeof(Uint32); + + bool trip = false; + + if (hdrsz == sizeof(sBitmapHeader_1)) { + sBitmapHeader_1 bh; + file.read(reinterpret_cast(&bh), sizeof(sBitmapHeader_1)); + if (file.bad() || file.eof() || bh.bh1_BitCount != 8) return false; + + g_iTexWid = bh.bh1_Width; + g_iTexHei = bh.bh1_Height; + trip = true; + } else if (hdrsz == sizeof(sBitmapHeader_2)) { + sBitmapHeader_2 bh; + file.read(reinterpret_cast(&bh), sizeof(sBitmapHeader_2)); + if (file.bad() || file.eof() || bh.std.BitCount != 8) return false; + + g_iTexWid = bh.std.Width; + g_iTexHei = bh.std.Height; + } else if (hdrsz == sizeof(sBitmapHeader_3)) { + sBitmapHeader_3 bh; + file.read(reinterpret_cast(&bh), sizeof(sBitmapHeader_3)); + if (file.bad() || file.eof() || bh.std.BitCount != 8) return false; + + g_iTexWid = bh.std.Width; + g_iTexHei = bh.std.Height; + } else if (hdrsz == sizeof(sBitmapHeader_4)) { + sBitmapHeader_4 bh; + file.read(reinterpret_cast(&bh), sizeof(sBitmapHeader_4)); + if (file.bad() || file.eof() || bh.std.BitCount != 8) return false; + + g_iTexWid = bh.std.Width; + g_iTexHei = bh.std.Height; + } + + bool invert = true; + if (g_iTexHei < 0) { + invert = false; + g_iTexHei = -g_iTexHei; + } + + if (trip) { + sRGBTriple tmppal[256]; + file.read(reinterpret_cast(tmppal), sizeof(sRGBTriple) * 256); + + for (int i = 0; i < 256; i++) { + g_rpal[i] = (float)tmppal[i].rgbt_Red / 255.0f; + g_gpal[i] = (float)tmppal[i].rgbt_Green / 255.0f; + g_bpal[i] = (float)tmppal[i].rgbt_Blue / 255.0f; + } + } else { + sRGBQuad tmppal[256]; + file.read(reinterpret_cast(tmppal), sizeof(sRGBQuad) * 256); + + for (int i = 0; i < 256; i++) { + g_rpal[i] = (float)tmppal[i].rgbq_Red / 255.0f; + g_gpal[i] = (float)tmppal[i].rgbq_Green / 255.0f; + g_bpal[i] = (float)tmppal[i].rgbq_Blue / 255.0f; + } + } + + g_pcData = new char[g_iTexWid * g_iTexHei]; + file.read(g_pcData, g_iTexWid * g_iTexHei); + + if (invert) { + char* tmpbuf = new char[g_iTexWid]; + for (int i = 0; i < g_iTexHei / 2; i++) { + memcpy(tmpbuf, g_pcData + (g_iTexHei - 1 - i) * g_iTexWid, g_iTexWid); + memcpy(g_pcData + (g_iTexHei - 1 - i) * g_iTexWid, g_pcData + i * g_iTexWid, g_iTexWid); + memcpy(g_pcData + i * g_iTexWid, tmpbuf, g_iTexWid); + } + delete[] tmpbuf; + } + + return true; +} + +static void inp_KeyHandler(SDL_keysym* keysym) { + switch (keysym->sym) { + case SDLK_q: + g_bCycle1 = !g_bCycle1; + break; + + case SDLK_w: + g_bCycle2 = !g_bCycle2; + break; + + case SDLK_ESCAPE: + g_bRunning = false; + break; + +/* case SDLK_RETURN: + if ((keysym->mod | KMOD_ALT) > 0) + SDL_WM_ToggleFullScreen(g_ssAppWindow); + break;*/ + + case SDLK_SPACE: + g_bRotate = !g_bRotate; + break; + } +} + +void app_ProcessEvents() { + SDL_Event event; + + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_KEYDOWN: + inp_KeyHandler(&event.key.keysym); + break; + + case SDL_QUIT: + g_bRunning = false; + break; + } + + } + +} + +void app_DrawFrame() { + static float rot = 0.0f; + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glTranslatef(0.0f, 0.0f, -3.0f); + + if (g_bRotate) rot += 1.0f; + + glRotatef(rot, 0.0, 1.0, 0.0); + + if (g_bCycle1) { + GLfloat tmp[4]; + tmp[0] = g_rpal[256 - 16 - 1]; + tmp[1] = g_gpal[256 - 16 - 1]; + tmp[2] = g_bpal[256 - 16 - 1]; + tmp[3] = g_apal[256 - 16 - 1]; + for (int i = 256 - 16 - 1; i > 0; i--) { + g_rpal[i] = g_rpal[i-1]; + g_gpal[i] = g_gpal[i-1]; + g_bpal[i] = g_bpal[i-1]; + g_apal[i] = g_apal[i-1]; + } + + g_rpal[0] = tmp[0]; + g_gpal[0] = tmp[1]; + g_bpal[0] = tmp[2]; + g_apal[0] = tmp[3]; + } + + if (g_bCycle2) { + GLfloat tmp[4]; + tmp[0] = g_rpal[256 - 1]; + tmp[1] = g_gpal[256 - 1]; + tmp[2] = g_bpal[256 - 1]; + tmp[3] = g_apal[256 - 1]; + for (int i = 256 - 1; i > 256 - 16; i--) { + g_rpal[i] = g_rpal[i-1]; + g_gpal[i] = g_gpal[i-1]; + g_bpal[i] = g_bpal[i-1]; + g_apal[i] = g_apal[i-1]; + } + + g_rpal[256 - 16] = tmp[0]; + g_gpal[256 - 16] = tmp[1]; + g_bpal[256 - 16] = tmp[2]; + g_apal[256 - 16] = tmp[3]; + } + + if (g_bCycle1 || g_bCycle2) { + glPixelMapfv(GL_PIXEL_MAP_I_TO_R, 256, g_rpal); + glPixelMapfv(GL_PIXEL_MAP_I_TO_G, 256, g_gpal); + glPixelMapfv(GL_PIXEL_MAP_I_TO_B, 256, g_bpal); + glPixelMapfv(GL_PIXEL_MAP_I_TO_A, 256, g_apal); + + glBindTexture(GL_TEXTURE_2D, g_uiTexName); + glTexSubImage2D + ( + GL_TEXTURE_2D, + 0, 0, 0, + g_iTexWid, g_iTexHei, + GL_COLOR_INDEX, GL_UNSIGNED_BYTE, + g_pcData + ); + } + + glBegin(GL_QUADS); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glBindTexture(GL_TEXTURE_2D, g_uiTexName); + + // Front face + glTexCoord2f(1.0f, 0.0f); + glVertex3f(1.0f, 1.0f, 0.0f); + glTexCoord2f(0.0f, 0.0f); + glVertex3f(-1.0f, 1.0f, 0.0f); + glTexCoord2f(0.0f, 1.0f); + glVertex3f(-1.0f, -1.0f, 0.0f); + glTexCoord2f(1.0f, 1.0f); + glVertex3f(1.0f, -1.0f, 0.0f); + + // Back face + glTexCoord2f(1.0f, 0.0f); + glVertex3f(-1.0f, 1.0f, 0.0f); + glTexCoord2f(0.0f, 0.0f); + glVertex3f(1.0f, 1.0f, 0.0f); + glTexCoord2f(0.0f, 1.0f); + glVertex3f(1.0f, -1.0f, 0.0f); + glTexCoord2f(1.0f, 1.0f); + glVertex3f(-1.0f, -1.0f, 0.0f); + glEnd(); + + glFlush(); +} + +void ogl_Setup() { + glViewport(0, 0, g_iWidth, g_iHeight); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + gluPerspective(45.0, static_cast(g_iWidth) / static_cast(g_iHeight), 0.1, 100); + + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + glClearDepth(1.0f); + glDepthFunc(GL_LESS); + glEnable(GL_DEPTH_TEST); + + glShadeModel(GL_SMOOTH); + glDisable(GL_LIGHTING); + + glCullFace(GL_BACK); + glFrontFace(GL_CCW); + glEnable(GL_CULL_FACE); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_ALPHA_TEST); + + glEnable(GL_TEXTURE_2D); + + glGenTextures(1, &g_uiTexName); + + img_Load8bppBMP(std::string("test.bmp")); + + for (int i = 0; i < 256; i++) g_apal[i] = 1.0f; + +/* std::ofstream tf("maps.txt"); + for (i = 0; i < 256; i++) { + tf << i << " R: " << g_rpal[i] << ", G: " << g_gpal[i] << ", B: " << g_bpal[i] << ", A: " << g_apal[i] << std::endl; + } */ + + /*std::ofstream bin("index.bin", std::ios_base::binary | std::ios_base::out); + bin.write(g_data, 512*512);*/ + + glPixelTransferi(GL_MAP_COLOR, GL_TRUE); + + glPixelMapfv(GL_PIXEL_MAP_I_TO_R, 256, g_rpal); + glPixelMapfv(GL_PIXEL_MAP_I_TO_G, 256, g_gpal); + glPixelMapfv(GL_PIXEL_MAP_I_TO_B, 256, g_bpal); + glPixelMapfv(GL_PIXEL_MAP_I_TO_A, 256, g_apal); + + glBindTexture(GL_TEXTURE_2D, g_uiTexName); + glTexImage2D(GL_TEXTURE_2D, 0, 4, g_iTexWid, g_iTexHei, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, g_pcData); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +} + +int main(int argc, char** argv){ +/* std::ofstream f("test.txt"); + + f << "sizeof(sRGBTriple) = " << sizeof(sRGBTriple) << ", sizeof(RGBTRIPLE) = " << sizeof(RGBTRIPLE) << std::endl; + f << "sizeof(sRGBQuad) = " << sizeof(sRGBQuad) << ", sizeof(RGBQUAD) = " << sizeof(RGBQUAD) << std::endl; + f << "sizeof(sBitmapFileHeader) = " << sizeof(sBitmapFileHeader) << ", sizeof(BITMAPFILEHEADER) = " << sizeof(BITMAPFILEHEADER) << std::endl; + f << "sizeof(sBitmapHeader_1) = " << sizeof(sBitmapHeader_1) << ", sizeof(BITMAPCOREHEADER) = " << sizeof(BITMAPCOREHEADER) << std::endl; + f << "sizeof(sBitmapHeader_2) = " << sizeof(sBitmapHeader_2) << ", sizeof(BITMAPINFOHEADER) = " << sizeof(BITMAPINFOHEADER) << std::endl; + f << "sizeof(sBitmapHeader_3) = " << sizeof(sBitmapHeader_3) << ", sizeof(BITMAPV4HEADER) = " << sizeof(BITMAPV4HEADER) << std::endl; + f << "sizeof(sBitmapHeader_4) = " << sizeof(sBitmapHeader_4) << ", sizeof(BITMAPV5HEADER) = " << sizeof(BITMAPV5HEADER) << std::endl;*/ + + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + std::cerr << "Video initialisation failed: " << SDL_GetError() << std::endl; + return 1; + } + + const SDL_VideoInfo* info = SDL_GetVideoInfo(); + if (!info) { + std::cerr << "Video information query failed: " << SDL_GetError() << std::endl; + return 1; + } + + int bpp = info->vfmt->BitsPerPixel; + + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + int flags = SDL_OPENGL | (g_bFullscreen ? SDL_FULLSCREEN : 0); + + if ((g_ssAppWindow = SDL_SetVideoMode(g_iWidth, g_iHeight, bpp, flags)) == 0) { + std::cerr << "Video mode set failed: " << SDL_GetError() << std::endl; + return 1; + } + + SDL_WM_SetCaption("Palette Shifting Test", 0); + + ogl_Setup(); + + for (;;) { + app_ProcessEvents(); + if (!g_bRunning) break; + app_DrawFrame(); + SDL_GL_SwapBuffers(); + } + + delete[] g_pcData; + + glDeleteTextures(1, &g_uiTexName); + + return 0; +} diff --git a/tools/old/pcx2png/msvc++/pcx2png.dsp b/tools/old/pcx2png/msvc++/pcx2png.dsp new file mode 100644 index 000000000..15f945065 --- /dev/null +++ b/tools/old/pcx2png/msvc++/pcx2png.dsp @@ -0,0 +1,118 @@ +# Microsoft Developer Studio Project File - Name="pcx2png" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=pcx2png - 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 "pcx2png.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 "pcx2png.mak" CFG="pcx2png - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "pcx2png - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "pcx2png - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "pcx2png - 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 "C:\devil\include" /I "C:\mssdk\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /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=link.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 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 winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /out:"../pcx2png.exe" + +!ELSEIF "$(CFG)" == "pcx2png - 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 "C:\devil\include" /I "C:\mssdk\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /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=link.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 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 winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib 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 /out:"../pcx2png.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "pcx2png - Win32 Release" +# Name "pcx2png - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\src\main.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=..\..\..\..\DevIL\lib\ILUT.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\DevIL\lib\il_wrap.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\DevIL\lib\ILU.lib +# End Source File +# Begin Source File + +SOURCE=..\..\..\..\DevIL\lib\DevIL.lib +# End Source File +# End Group +# End Target +# End Project diff --git a/tools/old/pcx2png/msvc++/pcx2png.dsw b/tools/old/pcx2png/msvc++/pcx2png.dsw new file mode 100644 index 000000000..ff74880e4 --- /dev/null +++ b/tools/old/pcx2png/msvc++/pcx2png.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "pcx2png"=".\pcx2png.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/tools/old/pcx2png/pcx2png.exe b/tools/old/pcx2png/pcx2png.exe new file mode 100755 index 0000000000000000000000000000000000000000..66a2b7c2bc1740a50365d4aa22e0b04e9b40e947 GIT binary patch literal 155710 zcmeFa4}4VRnKpcqOkjiwGhm{rqK*O;1t}HVf-!9fjG|>U6B%_|tD*#lfWRg*fG)Ab z!?c+kMrqf)ulv5fU0Cd{yR}>PE8i~L7B@jkz{PIBv`uZc4VG=sIN3H`(-PgO^Ig~d zoHKJ0V%zt7`+dLn{ryg0&Y$Q1b3ONS-}iGre@^&Qd$lr6(>(a)^O|-TcmCDM^|xR8 z;63B2Z_LmRUG&=3hf7w!cJ-RrhSuQLmMxFAtbHu_$lA@Dx5R@FHw9Y~n}ZuR2Up&8 zckr<->zWo-R7{&|B^|&1z`n(weC=)f_w{>UdAkPh18aKUo+9^?Z!Z!5Q*W2!-niyR zZ{H~H$K~F*;gJ~Q+9hoWY1-`dDcx5uBBwV`EL8PDPF3_Tg0+{oZ}gz3C%||1+Qe z$5|Lj9;WZxUy1F&2+e%1T+{Sp9=*+58n2AqN2jE6YSzpwM#)CVXRPu>Vr$@)?izb9 zpKmn(6k|R8m@l>xZptG$_M3dZ!F0trqGQK*SN#gETa6GN%YTi>%|;lH73cBzs4<$adOlLG)r^`El-U?fM{|wM zCHbo7l;bVpXoPYN`Ko7?({(Cbn)Qg}tM)3_i?w8@3RwandC*YNE(2scm4#G9YX48#E3%EV_z^B`f zu?cI2&Bt&v{_QibsK)*O`I?`{(&y)~X8CzUGe3_o=jX8nRAG$Ob3NyKXjzF@c9tyP z-5sw}uZdp*U=+UO8~OL%d$O!gAIUE{s`q&QS}Q4OkDJEw9KznX`&@kPU&C^x#V^K9 z%g0Nzucepgnd*X`SJKPhD?I(C@RYNjqyV6IeRwg6Jv5XG4W`3^RJb3MttGCEJqJ*m zwdT*n_VA(93|>lnEA_FGM9HZoXOd?U-_zTC47pQK(&q}}Y#ynTUMGL~^G38PuD8vUu=<(hLb1RB~0vA1j zu<}R2;otB+{v}Moym1m=6~CkzA79 zaF{(0I5bINys?GX!Daq@xZJH=^x7OU(GtPtyct+bJUsePFxegV_mdnuBqu!0;db2|l@z#fZLeHR_ zQHzo-`uu3@MMcT?RI+3?C7(>5OnfhP@OrlIGAS})h>n5`y$#AeAq0dJ$K)LtMa=y- zGprYU)GiQgyp@=5!17qg8!7B<8aNq=9j0!qgJ)+_mU8;EP zdDB}~#Q>?QZd|R1fq680OHv@Rf4yDmj}AMndA9j4lBcIPlw!;jRYS}K-m15a z#GdVDzl) z_k~Fo#)_+O3=;2F{{74iw%(^2Ik657A# zBwqY4hX?d`f;+EbQ2pH-C1Oq5Z73i!>F#FWtp53cF4ve- z0rJ=`K9`zL&6r3tr_*Vsi?;AKvYrj*j|j*yU*<4opn5}NQZn?s^f3f8x_C`>eT&aY zUeS52uF#u2g?Ij0^~r2Q3M^|X9b@<|UiG(vDfMuKuYv8W4Dnsk-PxW47Wui!bGT8e zz6$tq+4-Or9~vu{y%N-_pDaygGzw6aq^ap9=d?feGR4Y6Eo$C`z($PSpIY%J! zq@<+!5tdhLyMz%$h^Ogr{s$?!gCj__HlCSA9MY>x`;E1L>7B`&8J>8cB-?t%JYO#jF0-?J4ze zgs+RXZ!*M}2wi=xAXI^yAQT`1t3l8Hm%aKsA58>74gQzwOZ2gu66i;u2*3pr$?f`% zfaU8|y&;oA%0LlF1PSd$fOgkwUO=1a@v7>jx*lSYlDz8Xij;ad!q<=ZKi`efpdlfa zob2q}BgINLuvnqoyv0ZYOs<$H3ef&$fUala%LKBMXe+S3^{LSCdLuj>Np}q(;YM@0 za04{wpx!p95kwLknMU@560yOKm^=)R&NQzbX+}oRXE>D-WMpPG$|!MWt2n9TAq3Np z@T$dqMp|B>BquI2s+NLHi(nmUF!#KTU>qtAX72(p=z}c!$@m zpUwIVA)=JH7-_nv(l6pFHqBjp?->Vj`~Jf^n|X-Kx>7S<>{WR(osL8|K|mOjb& zhNPlrN>p+XmO(?jmvpZ;O7S|=NHa7ENFK7i%6~z0==8g&aQ0J@k9WTS2ROn*sq{gn z+$HHtF1lHgk_WW=m4Kq}$E%)=hE96RvC0G>5WzQB~B zeT$kr%SiKmy&)`deQIWQhM__TFH3ogRFk}<<1ak1*`k0z`h&7_P_K<@^XLaGMz40JMMxhK{2JmRL3`&iWQSj6aJ zT8gPsS4)dO2Jx%F-JuS#&2}LzfPIObR|Ny+tJX*ekDc)cia`@rh}9|tTGjt@sXlf? zVwUt^@P8=fLy-A4Eq9ODw4CwL>OvM;hfuxA6DS=zhL)kyRea5EQy>6&xb`6sXYDEO z_v0#qne}0xUKpoZcPjNcP~pH#7pltYw2L2c|0IFR@O>75SHf z{8>j0u7KkTjIbl-=g8{Rm5-wO(&XQO*w-5>`L0LEt2xgTXm29`Q%i@xFD#0*s+f&*TD~UFe74d^ zv#8T0yW~m#?shhSkj|eqHW*z@tWl-hV0PUG+`1R1l6xgB(ia0sT=WJe)M#o5WEEOs z>qi)R*^{#jiB=}mVg=L#2L|m!ELLbJ(+IwZGAl;mAaxKA=nS-Q9l8*hjQ;N8 z#1zVqM0FuDe2$kahPgxf$Dn?MvPJVJzXPZWG+=RjI8mKdM12Fm5;$)ZI7`shmd^s) z2f2V4$vJ1JI6=$D5ba_?cyK{@B$eKc93>6to{8CM(Ndv$Ll^F%S7UR~{1NJ*9}77B zpiifzcQu$?U<622pU|Lzyidc?&4^nYVJhK5qfT`Umn zK;Nd6{95Q zexz-U7#_O3PJ0)>TV~g3U%{{JiaKo;eh=XHOZ+ zX?aX)VPeO04 zM1le73g-QYFC&{u{pNh4G+UbOvrP?B5xe}31kf=H3842YdBW6WOyo5$x**Ayi$#+1 zcnyU0(AGK)HG`dHdCtzX==^pE1h@iO8=fwD0d3Tb4Of}wJ6KP#GFJOK(w}-5 zlM?ytBgo-hJBJ455Me5nX+8rmc;^z8&A-Z54Wp>=N_oU9do6ta6F!&~5g$P0>5>Fs zr-6amm+~d~S||qVw}0eLyP&BGJ{Nq2{tho(3`5u}5C-=iPmcWy_`^Tu%V4DLP9J#( zZ*PBP{a5}59zP!Efj7%T1KAa0kO;*i9h#j==6(U{DWdD8Wv2>h!>!bx+^1nQT!+%; zt2~YM5E%Za({R#jeXx&diTc>OGWu!oOC?896#WRVT09uL4?aekZ&1;4wD2*G9aHl8 zYAN-T07%)_5Sxqe=``zr@DdbUy^HTq0>=>FD#s`u%>l3~mUJUh(A%oD_{R*X323-F z68m>Q2R5vAqxp15SX{EZtui)-VSPGD_XhKGis`bNi5n#esIvno?KuRZ{>JA%JR4~~ zK_4aVjpm&yo|Oy=Oiy!_Bei8k(o^=f%GfDpYz4hS1(kU}JJE~m=sqo8pOzLzO#(18 z_!?u~h#cc0Pj*7cv$Ub{_($& zHF+AWk`y}-nskKS1|7mD{Z~I*imqE>MN|#$^!31Zvl#fVXr7kt8bmI_0nP7xoR#*a zlKpUEyYY^aq9|-=KnPAJjzH9hS8t;UD?8#;rlel)Q{C*v7kDh`evpg<{q^wDndpy8 z*lHlY#Jt!cj~E=^fIN-8$mdcM6C9|!ObC>l^D(6;rrdvtc@PFIz?sixbRDmBt3+jN zFQTFPGP9dmE-eYz@GATZlLK?l37Gm=-L~r>*Bi}?l>?NU^qP`x@TBIl*dC+;-qB$G z{VKu52v?@kBR@yXBfM(y+l?+hG@9T2Ng=t97)iP{m_5qPkQkDv1h&()LVa2#E%>0* z3?phavL*O@=G+9jp&GhQH$v5^qzPww^FGddmYv8s_;{^E_$;A9NQ7D&G8uxK$MWYh z{e>K+gMp;F2I0gEcrSRdL*qRM#zH?nD?juyl#4WDMdQ8Tg=l?vAGM}&Ap3hoB6=Y@L$b!R>WrQQk14m{JM`i#=CIp(# zfsQGM?nftVj6I87EaouE(B|Jtf4IfL9Oxb~|H~(Yq++vzC0cANVx_z2(P+LV3=&|B zg4V#kaV<;CY`(;NR@jE8xy9&O^`U7Vhn@jdT^fAuJKs`6_ zQ$0*n0{9!DO1LY2<_M+cCo65mL9`WneiP|YEJ$h`ccUv=;V3UbRq(1rcc%1!W_7Ow z!Q==vD~)3r%p!A^F?)$5@%>wwga<=8&ysGaNaOVxRenhbCSL>$ILd_l^x**JYkEVY z@YMFl$o__qR(!E}75Fj|y*hTVTsXjTa)1~3Txzb6IVtCqV4qR736WEnLkNx4lyAi| z=Dmv*8AGKMk0PG=s;!I3m1iS^2ZY!c*g(cMNp@0h&3xlLyYg(uEc*AeAB?R+5Lx1( zLSZWI|B`UkR=92?`^J*)%zR4WFy>>(H}!Y00L7@1Dw4x<-bie2u^1)h-Q$wyWd0A4{7J+{ONu2yAM?cP&@?6So5$t25N>7h55`8&!<|Jg zG4sD>)$AfO%{NpTWEu=}Ff&xc+6_MyIo``01!#_3)kE7TSzjpE%N9g+bA<`8TyH(i zEaaNKb-r(XWAHurQgMw0#HkX>kcv>vV3~bXU{EIHFz6$g2dVd&kn8_X%9V))>5va^Cd6ov3iuMPww zrYU_Lrf+ZKlJ0%m;0;R5={@jz&GKS8!O13+3jP26`zz+p;pzVx)@X1fQ>~=33}Ac_ z^M??Q=yI3|*W1Rl_Jfs%MV3T*QmPy8luaZKfr`@CB^DHnL>Kb%}Z7?*JM zvob+Pu8uih$v?K%0p(GNW;0+ikCS8`CMIz>U#ve~Sw{XgtoYlo26Z+%*8YSr0n7=2 z9(Q19adm8yN}7WWyOkatmoyvC5^z zkxR+ATv&k~A+>qvP2j_5_pyk{6;L!EacRn^mLLaQfi$vn&@B4Vx!?epJimAO1%a+a zAftlvh@*b>&^D|k?mKZ+R7tS0fy6+cXJz zfZPw=82m&m?wGsw)zk;J&4n8ZxgZj7a2>eh%HU$I5sif$t9u_A7C91fiI_FYLuX+z z4R#i37tJjgFIKVuuBE?75&bqb?KDKn0Eut*?#%YO3lnh=v8Qpx{=Bl#uck|)jl z3lpgK91!-8G#~e9aV(Ld8&jQ`3S?_USg16QsWgu|(){r+oJB6AS$cqi#1=R+lw3i= zsfdSDz@v7KMwJL0Sd2%pUXI)j`6?NLx=zOJe?R?<%hx91xBK6fetZGHC3}Vvr`Dr+ z9l94)Lh5_q#^V_1iaxAsPuDQ&~E*He& z-ih3Ar=&NI`(?sNNtpbDYO>VHf!=nMrEXkV$hb~|ap@V=4{}Cp zEefU*^P&rLu|P;{0y+*BowHc=G1h ztcMq9gh@Dpbl$%J7g2-4 zg8GnjMAOGb8`pW&LOEO1OXsCJA)VK$1F-Xoo>A<)h9ifo$K@cMSG11G3rNmN1%`Vj zKaTdk=t!_HGqI+iJ;dO^7?j~a*&1wH{B=KvqM~b~mHA9ED(b`JzrvxnicZU+@5Vm> zAA8+V@=L~*+=2qSKL%=(08=Miz9@A-H07zWDZuxUh1{pb{|k<;7E zGXLklN{^6<6=0E2ofbQH(L}j*>}M?Hc)9f@M2dA^5cJQ+1ts`zWVgkhzaZQnj|;~h z@kaK}*p3Ur-99cH0eS-ii`5r|yLwzW$rsvdIl8iFJy6r3tzcayW~gLr=->TQaAkX{ zm}@01VWq$0!FnSEdIEj$G7b!jKBZhXL7y^CZWnzl0cS7HT#3>(du&Z}Oz)W;G5?O! z3?e8Yl*h=gBmoY*hQ|p;&AjKQPMRPzuc4fP+bMq86Hy-}AJ;e%$52D0FqWWF3J*8L z9P&^z-w`{yli=*cRn4?SgA^8zquV=i@cwvMrcBGN|I_(60`|wNPS7crCB>aH#6#M{+ULMVj*|-Y2IJiPFQX#y|&S1jS zl7|?YfZ9YxGNGIn$M^(lQKdaL^>8}`EeB#4$w$4MZ26AOCJPxbeJY#)%`#x-s{+c( zf3;ZgW>NbjJH}#wh%k6W zvghcVW6r20ucU^0LU#XzETz}OuQTxx>l<|)N%orY_x#e^QtVgAdO zCwyk4qWn|(hKwQ>#1>AQ$Z0qsHy7xF!phsYNEgl1 zyRuV^i_A5Qw{{3djNo6lVn@ja(etq4)MA5wPOyvChGh3ntP4dCEzoLtTU7e0t<1yL zx3beCOA?B~*iTk|0eWFUWr2&ark!lEtbv@$SgzWNA>p2#hp>$?FAylOkk7zwJihWj z%-jXaU{YcPNJSQcT$B+ZwQBKrVU9Kc{t91f`Ly&MAB|}ob_cY?qS%@XAphCW#9Uz) z9?P5pE=8!>QMtyCQ2W!n1T&~Xs94Ux)c%^i)eF`3vIPN>)OgjrmLYiR-#TDV?p$#`lU=+d&DGV_>#0-J%)SiW#U{X!cZE^eqxqS^NgVVT)F<4J@;8j#aU)QuwZZHUODlo;k)& zz(EMO;Z{%#)OvQ#h&dpJ0LrE7B?Zj?FGVd1MCBb<0V)s!*$-JErA*$&*g|K7@BfH3 zcA7FzOStOB*j#70uSqyt;IXS>D}b|(p2QzZA!$%$)q2L%b|#zc$3~pQ|BxhS3uel& zqk1j*hXz*1x=J!s9I(F%&XgExi1brXBgP(?{iI4^f+dMs$&$-@M8d>QIJ5fIzdCEk ztWG0`2J?TYgtDI=Uystn9mN7nR*z?$i9aWakE@3yUT2l^d(c&4J1^*kYbBbErs#PW zbZ^za?-%{|5R%g{O2C&erv^+8)r4R2r)B9~)LRxk z)L9?w2p!aGcR<}Qd2)74rg_2#l^P#0KVq+ie=!THJUGeT5JpIaU)0-P)Z#M=K~m8d znCS~aW*R!w8GfN-b@}0fcVlcT=m#DfyUWt6%TGnj+23YE_%a`5e~unHzOw2t7S5k) zNQVzcVh=fqt$uJ~lYRd}coaT20Ust}KK%~kV8aoXrGG$g>(>$&JNi_-R&N`?YM0m! zdsZ#SLNyMHNU?SK_%*`BD?=!!7nQa!JUc;eSdt2_{^_Z)Lo;HS8 zE&Bnu^w};TD=o{QXYgQDETrX?7Ii)-o;6Rlx=dglr}vOnu3smpB%?c}rm1&@c%B!z7uR z4Rh!RY%3?suW>X_X$)y_y9EsMg^*l|Vn@s`-Y&o^uU+SU4o7TZw2I2QjhnxfS=%fo z0Klew^Q?q0yNHBtR|!olxe}o)zg{~;CXL-AAY04cBRdp z{S4b+E|66+l?V3K(8SKGmiUAt&gYzQj0#4In73}R%Kop3g)_|(|! z&7*Z?m-qoXaC5GWB65N0xIqGVuv08mL71>o($S=(e^5^VQ9(O~w9C~l9Ate&uB@9MjNPcW41J6ZbPPE*Rfr=#}+D> zQ57r@@$HS6OGRedOEiG2*Zgj`)Y(o5HHFAZdpe=LVmBA}G|y2<5+}3d0Qc#`D^kyk!+y{j4C}C_56a=@l9-UiGS$#PEHM!LA*+D*53_c3u0(gtl{V* z*e_>gpucmGKY5R+zE)UhnphWxqdsKYF{a7@%~aNRc^>_K7?oo4sHV6YB}dO^@{A)G zT!iR02H77gR~bG22vlG-KN~!NF2_B(=uXfHDy`iTm8lYIfNdErRbKko{gf`20RZGE zxQ}Gd+PPknh(Jm#IrERDDBt;Cq7utwjz1{zxhMD+lBLt=S*$+$3Fu4EOqauz* zPMc~$8gqIJggAo1@mztzkCGqP?spJWwN>8X-{miy=09Op3hJ_2`s30lc z2rcjNE1TEFmMShx?tHkP%ohAt3J*Ip<{$D^K}5iag7p(V9^y(clZJ~4sbY*%1^EL% z^KZps;k9rprh}=Z%s;T&f&sREyeJr$f`J1#!2oI!FaXJqf-fjZPHrItP;g@X?X`LX z2)7_?O6^Bt(04Sub`%tEyl&M_tzepgq+xlUEwzKm5ddKB3so9zFrT>%MZ_@N=X3b za8N%A*?Z6ky@0`^RKG{6A7=GgT~t4Guvdl)z~T6ERR3h=VMvAE5a~wautiFau=`*j2h+n7+20+W%nnC^P%EoIu>X|#)2C5NBlMzC!RpBwEr@pzz6;6CHLbhsq=36c28mjH4mbo9C`A+vW>Qo> z+J}49Fj5lur$Vx7aH#k(hW;FXFX`sk-v4Yjicp6l9N-+1UdyW{vsYJ{SIw4X8Z(Uw zx&oPKCiLWr@xnvFRF>pog1H@zG<7``+92iTyF}8Jnj5CPT-goqlRp({JPhyL+t#T zuY0qvtb3-MNr5|}Ft04>UT0MBz5Q_yGXlY3X=I~sS;U)AV83#AWx?zW3a1 z{zzWDh=#d>mCtz1wV-Ol^Gs@m4{^PS059XFXR`Ybvu@ehf^xQsi8tr(Hov6ee@0Q0 z)hJQ4ir2W#SU$VKSYF*=K5hk)8Y+E4&ig8f&r%0}Y1k21dlSqdC5h`|>^SCpTxgZ8 zy@hH9&-LSj9PVZMl%H)5p?=and=TvexNNNv{SNv86lBid&1$`v)QBY~m9HH}1IV7; zACZE?-WuPx>EustMgr|^UgjRZnw0GM?zi9}sshNb#QZlg99i}?Rc=QG>g@_F!=^lp zZyhO^Km4j7&Viay`5IGgw0Enbvv6NtW(3(jQU zeZ1)|zN#hs4d!DiH`HDqyJg!#>=2Z&_b6wKIMORizYR^o-eeXYjhOGi0tq^fX@2fg zYCr_+SCf^N5RRh_=`@`p<{9M_*ge0^x*X|(mMss>dh*4SD@-$c35fCi<1iB)c2ty?_ z`Y5!-HDGj#@UY`NU)3P5IjR>T6FBk50XA$dEz2cgrgGCHh3rHbcb)wW${=T)d3nZJ zrKk`ctB*p7lHC~6pW26mu+IFiSNX0|nvO_}sQE~$Yv?~gxfoiA5_%&%kwwo~Im)V^ zMOj2u@xQ$CRqKFAb-Wt)qwPRLQ*Cq>T^-Nne|b%h$3B+DzniDZVLSp}X6^QZ{96$A z)r13n{VfzD-8GCds101{G@lpr)M}_~+k0-PL8qUvQ- z_Mq+AnV~q%!BDp>$=EVV9aFVf@ai&2v8^;aD_fw9(QJ8UDz%+3a+Ek=6ou_26VWz2 zuUb5VRstI{NfuV7>_s-cL9@qtqQ|*IA&%W%qveUJBH4mYQ&l8&&W%FJe@iXFB^@H~ z_vd zQ{3Q)nHRi5Gm&7N=P6F^z{$XQg)mUrTi7Pfa)93ydR_~yvzJeb;Yu)^p*lz{;ZI(f zEaUtX2NQa2T!zz_?pGW4YPnSMNsH55&k$&vhmdY()Yman31KizF_AzCApfc0JS`~` zXF;dA!9U3UTCp1mLrqg-T~2byDi3V?nvi(WqZUkcVqS5>baFvo|c?B|4U;4 zPd?mV&n`Dk827^mS{B_-XHNg{^joI~rk_lVo`2gIIlpdhHA1YMTY3JcWv5$a)F9k; zZ_Csggxywh=aMtV@drMAG*DPpb~l4s*-3(u9n?5vc67-ZkR-DUAUhvIdM9Le0@+o5 z0hfT4mk)W(KwjQ$-UTT8?d3&};_#ZIKCLfqKiS$@?pWz_f&40Ge#=9N;Q&tOoNxh4~W! zTfR@g?u|kKVh6miey?&`;!>KYK08y+9no6fCm(wcvbCeok7hu-I7@BgPX$>PrExXf z1^CmnDW_dwkEEPIC^DvU$;n6qC(qCn4d%lznTgG%a>$oNh!|{a zZp=jvI4>Ofz=h|9A0HR8Tg~zh{+9E?(E!+wYef5jHT&Bj^vk~yt%1jd<5=)|4@}%V z{AoEt4RT`zjtdVB8eSOomz+^!_f)h`oMfJ0Ff|Rwh2umftizc4B9p=;v3?``PVtaCZA;e~s}V*0b)L0Bi<;nPKn1viG5D| zS%kl7_pjsEoP=lrhWOws>(#^Y+e)><%Y(0USiaI97GiLe4h_l4mCly_ zRBXPIyHoy=fY~k0r9~53`qOsE!NbmwLK6TTd%5cgr#cWm0wFpGam5*=L9#+_u(P}F zV1sE&^MFIbP&xQ}9t_{lq|_--&V%8v_)Dv$`!8r|)gL0Yl=x|kNn0x0Gkm^*mt={! zw+=5jVH``A7-tQyQRiu}<5Zk;}am-$MFNtGP%Io(h zIWQJK_Ufv{$Mo6;k>!h;OJXCfbr`$dhYalKrJl80UtW4GVkgc z9EwWAY~}U`pq*iYY43NK%-pVT;AT|RAqhF0+Lx;0b9U+em2~28)|aZ_GqjtkRdnOr zuI~UJvsfv(nob-DBPO4-8&G0zd;u~2X=dkNeL1V`a8 z{?fe)?f_NU#UScOOE8~^bGg|X2$yTjL#iHA3%4LmEL#P0l>SpK?PJ0YF73l>;?PCJbszOA8s3BRx5_wV>=a{OJ1 zIt8y(4#F$*jH4E%Uw{Bej|JNO?F%plCRu<1`!NOr9<0Dn$D9-oWD)wn1dkfs*RDZZ zYKhM{PwE1OJZRyH*nQx&Kolc5IiQO{bt?h~4x3`D7y$G6R)G5uAa)boungRCyI&&F z2Pe3Lx!}R-rr=Js^u>u6s3~8h(m2ZUItQt zlnf-M_GC&ETe4SoPPw&X>TS2j=i!Sb*D3!**7yN^Bl=Iu;uR_Yd_VNb#M_Wcfloj1 z;49~QnNWNdqxyGu;#s*Qey*Z!g2yKl?|%9LCB{S!-X8y&5`|N2QFw`d-1=n7k01&c zLKI$Ui9(+eg^A;-OS9Eb2ry{E(+o>BxHOAXIV8;`-M7c5E$L28g`B-TF@^#sl6Dyt zee7RnL*-3X@R^ii8T8S<;%)2sc#qiOWjr+lf-a(#0730xLn?!>m4FOfV5i2k{N5f~Zpv<_?4r zfsd=F@If4w?;#W!IutA~Gk`Msnq64MzqmhUXd6ow;?s6$NlJ8E61B%8zK)?Rx z2(|*UG#tTNQxx}erof&}k@ivMWvj->59{$EnN^K;NL{$q97R-iH!TjPD%}wxv8F=G zb)~J@H626LkfZ#?^gZK?MMd4=nST zh3%i9Ix@l+t4(~ST?fct$d)lINyo^=oDEZ^1BzRLkFhEzJ2E->iOoH&G;u(zWT#MN zfZV~PFi{j}{>OEaEQ=%A{6>ldyvMY}6XOx$>JYzv7OT5p>Ei}}8y>cx-4wT?a7H92 zt2DS=h#!KX!a!jN@UaFC=96I|UUE6}3M+pp4{XzID*x<~@p*G$k|H0Nb=1HNBveHb z0;gpASOrL2q}Q^0$njKTSxhIRiI!prSET6j%w~>`iv3;olR@jbS!k<9HJr_5u{MW0 z^01BlP4V#Zr226LEK^+t0%rdJIU$<9$C#-tms9g)wvx;Q){g-UIZvI~Bsm>QIwn zQP_M3I6bG=@~U*E4;d9QMObkQoO;Xa=piNJ)S!Brk0)r>g_M;bM*7g#_A}VV?n;$P z*$HTCY6?)msq>oAZpVI8zL&qo^U3XwmHJ#e>i+Ij_=3tw78R zu&>M?ksUe=TGtHq5Q&TtjD5jvLM6Icm2m8Pw~h1GNCjL1NuNlOl$e-ATVhw&m zigm&WpD-FcH4(2r*#{SR2U{Ps>N@zkdA<)-HloLj)txKnoS@zkI+j|!7fY3om4yd8 zBc5Gv!Nzs0EHv1`FLBY)|8j(fG*^#L1bdg}VEl~r?pbUl-#~V|UVrQS8B!mx z*xh~%E_05m3{$&1`Kr?9bUM%PJysSS#EiOfmnj~=wLp>vOiXVtT%b~U$zSA+)K=%~L*}|9;aQ!t=U=tuV9M6x* z>W(4Oe0WHm)T5r|R5iMbHQ<~yDxT4A&#@C&h@KFN9tgH#gB9w5PusBZL9GKs4(mbX zxdU``CUJ>{*TCy> zWuaQ4kc-_Cs97IBk9V#NmZ)%FY8A?ZF{xO##xSdZUG6t){^VMKr`HNk_3vJRm;Fn@ zE_;Uj81Lf&GZkgv8K$-VVi%F-k}WQ@P!Low{OfP+m(Z&SL=_*=Uo58pJ|Y5#-rZjy ziSW<%=!~oYL$KdEA}dr>qdowtT!G$-^9d!{de7YVRC#EU6E{q=U;z&n&f9B1tYqw! zA$CleA+_~85s$K>WaF7iS$9%)RHch4m<2rzR?uw2n;pa>5xlka%zyzK2Qqf5VK*~0^7{cbTU|XgB zDi#_Ky{^8eatZ=BpRKaK=LC1q3g&2D#~Qs;__zt7mlGsvqW!IN(O6)3bHLI}^qx8O zp6Mqba7wdS?}{aQFu$5uuoyKF)}Q<#TSf#eBbhal7Ls7p!8u%0i2gVy;+cLF$}5w= z62)#*-OOSGrWM?u>_RFk#a4V!$i(IkeyPuq-9cXE|G1EPqRQlf zNcP%D8X?}mJ7P7OBObOCI*5tIKU}hJLTKvC@?xquq(Y^t2#@kgfwzOt!w}M^w_(@J z9P|-7psHk;>Lqb%&LQD*)A8+s1XOzpJtTk*h1i30*0h7Q$_qn^M4J9Ra0e`N?vojp zzAWTb--d1x(BTv5XG=stV@pc5mO0vQwes`u5b}0 zx&+ChU}uH}!Opa80d}G+IwS&&jzz&fAvF+y2zFBh`-lkk5yKMfBO(Ln2u7urThE{v z;gA3uA+XYLlqfA)4xSh8i9vPCd~IG+wpM*snJX4n7Dlp#chi&9&9g-4}M zDN8R4cPj^ldLa{~PKoWPQffCwd-_Njjj&^>dT3xHW!T|CQX2rFBM5dTLN;;J1VRm@ z?%;sSKpgBH!deI1Q#b;P8n9U-8a&TT?5h#s!JSWJ^Zb)8*vI~heO;ah?2%DHpN|Oh ztSP6$kA2S-yz4!IjVEE^pSZ414aH>US-1e@J7i``MiWMrL_Hcv$-{*_ITt&&977Xt zVPq%90YqOOKyCCVFc(F$#gO>0Pg^W4~2as&|69mrpG~^$diSlAz*w!A!1;`09R5D5KA^6 zm_>N(^jR4au%%Mb0UoD1V6&wD0!xCadWf-TOC6HsDU?2+XbV!8!rCp*tKhpNq^Oyq zj>cymYkL|b(DNo%t$MNGq3l)A1QEetOx9+C955&*CSagqL;f(kS!kqO+e%J;4wQsZ zOcu&q4lAz_O_@Y$Lg%)BMnDlL;M@CD4#Op@`g%78K`cRU$p~CgCKZ|8hXih_=@ypt z4wkii7@;r)1!1USWS>Eu+K-N*Flt)|QbfOy8NXpN39GKdQrB~~F9;gGz*r#xUoZk_ zp8dV(qC^j17@_{&-J%X7akLv%-xYA|T(v@!$o>xKHfON#m(~f7{wjJ8v|EqW>7h_^ zi~}$&4V>j4Q2jvKdod<0_3le)9s+nsA|N9YuRR6@e;QR|P>_k;%zcGsMhEuEw|a+B zT}<|IE*?c5hL)QO^`o?$3IMY^$6?3Q2RX0|kEr!(kZJ>E(UE1*b5BzAMzIJL4e8WX zWMng>Mm8YFep|Dq*rX~`7^^^;u|{%zMscjtmy)qcpM%w7#HCn09Vd)ctVG6-RVV~3 z{n#3f_8H^GDt#$iL&n&vAi9{mh%P!7$0`$28$VX*m$6E}Eg||rHpI^ws|=K3AreL$ zU}RVj<$s#fDuBE!d``M5z8v*0-9oXDJE%A9i|bB4>J=OA-3-y*##+D$9k zwfy<<8uVh!>PrhOM zlsx%qdw@St0h*|D6-M6+UX4f`3@;nh@H}EZ^Z|$vjKpR1PN^ji4#g1)5%6jsju9uz zwIcM{uR|#^xJ&rurifSiTFd8X5Kb(_d#q ziDKZK&E!6KiIQlf`B=dN{(@y0(jrBp-Tr zCrvx(cR8!*-}7N4ue7%`3+=2J?f;pt!r$nk7fk5A$!_4?D>MfTxT zLSHJ~2PdP8*Y=~--BMjA=#r$1zC*s1mZl5F?(u1dv5q&Nsg?XBVreQ#aE&yt_yQ}R zyLeS!Df*}(-Zah1L;DeifOJ1&a8WiNvh_w6gIN;U0n#U)#Mfj9 zlBhKDWb6^RD0L)YYEKv8(VVfdIjAnv5fBFUl>Pv>&-_g>Zp2$7xWEhFLda*Hp_kOjZaZQj)W(O* zxA=C1j~YL81w+A&jsd^)>gh*Qa(B8j8r^x%ew3|M9K#C(pyxq&PVjosipRSmBM2+i zTsXuHr$jiL3U&Ao*5RKEZI01SjgTO`eo3!`^h%Q)xNBA(GTm6NieZN#ED;|(f@cl1 zM6Ba3I39hK0s^2Nx|=<(36 z=!6`xpNmtk)-DN?Bwd}!~Vx^U%xQo3;j&Aa&|0|-R{QKp+r(5=78N@ES zaKe~QhNn}iufq}5e-w>Tl7N9+MKE}L${&&Xu*htThtt~2?z1?{4bAp3niDG|p~`ln z-lsl`3q*>^H<;Ch1h^iAA^|)R7s(4#(m5W%Q`~=r^(e*qf&Gj5#$GrV9#a)-`x9VU zs8l>gBqyuTHFhwm%9n&FCsYMCrOKVxV*fD8U{|HlT=6B=8ioqXvDed%qG*{vmX>p_ zXVQn~3&H*p-2*tuUIcGV#j{u@AvU_#=}xd_ntzMxnAbsc!`8rYomEe?oQ*5Am2$sc z3t|K=8@m@99ec6501HI@Ny;H>ii8mc#q>4U-ZseXwAi&88a%!$h!bM8?3+c3a41=x zR$!LfcxEx$EWPLGKBUWaE=UT8L*ujDq!^*H7m=Zf=Ch)$SL21#Lq zRE21DqGP0FS#)qaJ}-p#(aya*$Ya_UI*>42I^;F`TK3N~+lU!f)d(iN<+GQnb-Oqc z3K%t-)e5)+bD`H3OK#IL)Wa#QJZg61$;IToq0#lmp5@OXll3WIG=Q|SubbaR62O#- za)w+v9UVfCb5Naqvg;&bzfJp^aOXc0gt)Jt9in~$41S96( zz`&008E__o(AWV@)UiP&kY*_&*c=I_TE$3>WdFdj6|eKz3f7`yZ;<@zkCfMvli*|_NlZQ<`w<13I_Jw5R53f+ z$rhB4)qZ=*S-Fl*Nvp!b`YFC?a;|IU+oVA!NxXm6{u_eoLL$psYShE0w%=$KS`Opd z^=d%ns~EcS(tCm`U#k=m6?Lth#uG?G5u2Ruv9rIfIHqeq+k1k}M}5*dysxtPH|A%cZGa*6mh(J6vZM*>A@!?!@8Nmc;edg|YkG{+ zWyfpY+vcqq^FOr%5v(=Vl~_AWjqx3C%XM#m8QVve{$-tJ^nQctiJtMaK=COnJAuzx zG<=!ND7^~advQO7*S!znvIoC|_{}-piN(jAx0ZC=R?>NEDU$8DtyDi=ruRzXrwWOu zZ!d}748&#LB@3(7bS4M1UsO~*f+OYdBkv+$o=#J}PQG zFMhyzHgKMedo}LWxL4wi-NR1@aL2aZr+v6%1Mkx~0v`v9tbE#oyJvj6D13&Ho{8TW ze!dqS?Q&}wYVT+Vc}Hy>ZGgHVjB*>-Zgyu>@`>_Uwq6xQoV~pka{7i=eA)yv=iVC6 zcXxdlDlu04;vnYNcH=o!#j_u>_1W)06S%mA-&3Bu9UHso%Hv)p)DBzhD902RCOmVgN;%p{PDR4!P!90?tKVKUo|21mpD^6Z z6(-e>*Wq-lSCJwL$D)*H#L{LDx5)q4e(H1&zuqp$TySUs58+M3>{D6lsmqHJ2E7nX zT*94vxzhNR+4-_^{nz=bxafCW9p3ya>kTZ{7vWJY^uxS<@fZ&4%m=Jquk3-&d8ukv zEWC#zvaK$+AqR!|jvEq>_D0c@AO|dKps4vdF_;s@s zN!d&OU&;6CzXh+HM7}Tns>qZ1@TPo!39ozWaM{EM{C+R_&cq=H3SljoF+sjF)a3Hr zitk5&9P%8+Zy3LG_zmLMkKZZ$AQ%1s@?DU~v%-t*bYdmSpUOy+PeMdtXhM0;+uZ# z9CpH|noPZR4~M>qyV9X^7|6xqly3M0{4Veda2$wq`a^=^(C~ElTm(V3N)WCt+c_=} z25IU{)9VpjrCXZ7W-@#P_adVzj$~5N*%J?BFv7DjqsN3Y{N$X92Aj`0zTi_zj7r-= zDq2lbwK^k#yT5{R9O9c;sayhkQ8ifH4q@-p9?XVqu2xS>W z2?AhykdjzjSdBGisw~_+p#oyn9S@=yumY1K6JZX4(oH8YZL}^`fvhygp*rK_0+N@EZ{6JB5OFO>bDP5Sr!fwV~s)7>TA>nOXxMfildByKz zS|A}0hsnMUrifYK^f(`Z_2kSq2@-lEPtmYWKiVGKEy|U-YdfXDxKkKl*MyaN9@Q|= zB{VI_m>>L1gaz##+%oq!9wf+PRbj-(^ukv##KSB0nehx2X;7HQ@kPGbTKsZlG+s43 zVpevDpn^|t{cM)4SW2jf#Rj2#%E$J;Uw<03`_o?OPxq2qt^OpsBKyl8!I_MbKxdyV9in*9gxVIEuVS*9 z4>E>?MK8NlQVcqJ8LTnvW%j8lbI0|vV4;_(wc%WN_dQet@G9W25?uANXO6I!^+_-5 zLoc%%;J5ZDCii(Hhb2|0!65pJIx2%l5!qQ|;U`D@2wG&Elfsaap z)RsUUAi@>$CG(}Q{nmtL%hJJ0h5#F4&&9edWIKpw`%`(U%_LJEIFR`6l)zlm5L5cR_h@mWqA}>)fbp(s2^FAo!GTkn_O+Okp;dRg`F-E zqLGGDanvDKQGV`euA}~(zgw1FteO<3P=@&hNggyaWF3nY4ubhkjDb=AfMQJDlQJf2 z45|7%bW`c&YRtun2-%4?2Bfj38sjY|fiUPg}kf@N3? z@DTZ)*1S0OqGEub#d-ck2G|X%=f{F%u2MMQ8BFxZ8fTp+7RT#&hA!7zH<%$^u`?_5 zd8qgZDM!0`?NdIySkuia!NZ!o1e^QJEBSf-5qyhf-hf;O-W_ zQn}tD*E+ebl@>%|ZKlUDKwfc++D|H!j-x$PW0~?;p0_=e25Dv~}&HO*aP- z;Kr?+9}TYGu&HVD+Q*tCEvCnZ^;=pVTN@8vT^qbJx_Y&ywQg$tQ|JAmK(Yc^~~F0C6{1XY16vaYZeB9ThrRd zZut0vTjMRk8;Y+FuWfA#e!Mog_&QB{aQ&v%hZ6;y3m{L?v?*GNrUkUJDcY3MfF~3R zmGkc-i?s$8A~=6(!+le|+Q$|zzPDj2-h*B`dmoBDgg;H&x^)Nsya=I9)x2KZy!gjg zZN9cyOK6+$4+Y@+=ESB=c-)eRZ%xEiGd>byQ65|~|JwT(UkktGt*uQh0_3f0K|kvl zFVxbqr3LqU*S2g%lW6l==g(VrU66FDRlvO%XT8L^dJ?yrgTP=#OMKUo zzgv-8e9M;LrY&gcEiHgGXk~VH6VP54ToGHl`H`kzF$Yzun}fHaaL9jQaPXv^BiSiQ;qO`A5q0c6@5Y;20RJRXd10ckO*IC{g{ty?#3cw{Z{1D4am zTh=8up+}-T(^z0UO=Ed^M}b2-wlX0EmLPDu6&P&TtokVX3I4~nY!5!ZCDFo8#bSY6 z*?&;KARgA*%{7hCCt8|7jZIBb7DrvzZFwZ|7|2!%#za-L)*L)~LdYZb2}-L8l= zJ+d(@HJH!d^x)Q8H?*|I>!sASwZW}-ZCWQU;;V8=Is`!JRvU^RF(veei?9 zt#>wUzc4w;tA6!eD?a()nm=j?%`fD0!^byEXf(@pwY3jAf)w3R7H4?rDk$six7~SH zW9Y%vx8E5GGGn{wH++0kW78ienp)$*VyMPY1j$I>y}k7ww#h2s(xABN{H>&lm22Z` zS-Xmz%3vGY9lh@hPB?>tFi)-5JD0lY9L#8NMe$1l1_|>$R@)mXapBVQDhTE)C__! zih>BjLsSq@M3m?R2YskGqNC%&``zkp5)ANs-{*f;^>;XRZ{78G&vGl=Qy4WfW(A=W z*Cv`xLhPmurVN4OK%!pk`Kd6BR6jL-sY%0<2B+!1qEhCJn79?YqBEc$Go=tiuAx7t z=DETbD_b0ZC5Xu8DGRq*_=5DDf>B8s>8S%^gFP-FCt_U+z4Wz0OrnZe!bIE`V8*_6 zKt8xHj7-RbVJQpNRr-C!foP69R#$PDJ~KZbn+5afF+Fu{dqk&L+2|riO2<@>xf2wL z%^L$tk2{UE32WH1L zKd#d0?#2z93_$LSZf?+4v|MU*S5pFIV;j77<%Snm1WLj_e_d6`R}!oWv0Wt_Z%Iw~ z*Fa;%>x!8{_VsVL=49&$iw`^BzS^&szQpwr?aQ66`P=$e`fv9U0-1?!HVEnGI(>J8 z&@YymiixmoV$hvet?yd9Gx0Hlr2EYNwKjZsXVQP5kcXz=&wW0!K;{XYwED=h1ZU# zEg@aeS#HMgoSaAwOOl-Q%)xDvBz5?(r1Z?zoNUSoYS+%!!u1yw!x>^r!#XI3v7Zp| zF$Hs*A*`Ij%CS9upgLGLuFO{(D#HE@b_#laOL?1$?p~v{9zA6}%Bj~FJQhfo8s|t@fxewI&ZwUV0VRmeh@hL1NG%4 zZOTS53N(ZwV#JVXMUgOkco&~K^cXEuh1VIpt>6X04}@a&wYC3K;}Wgphb*Ib*Um-7 zQGJW;*5F90%BxSrnRDlJ()EGtl-C5S***~MVXT}xpOcn_$hjNFT6dtVtiW(8tqh_& zXq#(yTroh7Kj4qd=cN1W?5Kbq-)RGq&i^m(#(4Fmv2Vcz>)9 zWCcTYAwrNBNslhC_6Khv(cNisupx;AYfITiI`Wc(cG<<==W_p+NNxm`mQ)67nX*Om zpIDVhR)AQU`KuGjB2WQylu@OPyyLam__B)LL9odP0r0IHd^$_q7I1K`Y35o28 zAZdtCCS@S@e^l(;Xoo1VbnIG-=S`sbAXbMFd-n5(Z<0eDl1VdYKWH~-JBVG)b}Nr# z6=K)9v71)T`fXdJ^-1K8J!j-y9s<7=fino%aCWrt#kgm3&8`RA+|S0nd+-(c_q4gc zx6OTHoBR9P+|OxqKex^Of1xd$sCCap&jM$9!V*mEeP_(Q2<(K5$#qk=WE`(0WIFg+ z;CbNejD-Zw>U9D?4}5ReWO6?ED)0-yXM*54exyq>=?%UXybpLII6L1x z863w_NeFxbcp>;t;Q8Rkz%#%%tVld5RSZlfj4+FKzX3QE9Qn0>);?zl=5)H>bkhEJ zV)-eg^%qBe+pld4Q%UPD9+u^|{9^TeK)}0T-)~JM-$U4$-Nun$mor@A;ybu1wFJ)! zr`|fXFU!RB#DNH3xHQ72ENEt;M-nGZcKMSi|LWp>i+z#D?f#weOC&2X%2)r!@=4M1 zFQEL}i&_@-A_o^8T6EK?+n==1tuX=yWW>I)`+THeU&TJ5efeE`KWhGg5Pni*WDJKM zAg0fZ(4EVf-C;V4=G=4bIGgY4II|I5KnyI#ncg$b^qxIqwk!6Gwad=LGky+;wa@GV z%VTzd*#t%`pW)5&}Y;Yl#d2y?cV@meOH25J5?YbC4QXv+*tgvHq5USh+PIHomt&?D=~j z_Pi%RVfc8Lhk%EGhk%EGhk%EGhk%EGhk%EGhrk~l0W*ueEk&+B<;0W55%FYlo4kpm z;>m90o$UHoHu6!Y8>kPcg{A+W7l(Q_C>vA?Y5>gu-49vD9;EyPVaGd^3Rcn~7+AlwKQ`UW-UkcQ{$$8nQZ)MjW}HCCRcl z#2$y-$ZUkT5%Ns@$ZC8w0kiO@HIxKG>|+FI4ig|`r5lr<)*1;G8Fg(EdHxhnMw55q zN0<8p_z*))Zg3cjW=lp~Bsr6fwS7aR)5-JkC#$OXoIp4NZwlgEfnRr4md!L5L8c^& zrEi)?+k&9Wm=HCnXZ_mlCe2j0~`b{MBvWjc6x}-23c6B=u6P zw@8w#cjYXL4VnC%-6y5s4|hE4d3f3|c0ZBz(MGmf;*R5(8;pTVaw79*pI~8lVC6@h zm;(%#lR=erwPkDu$#tdpehH*&eOyM$u%gg$`P~s9+CG%g#*8h7dmaKF0v-Y$0v-Y$0v-Y$0w+b_TtfEa!F60RH-;O})pK`o_j1d*qug11A70>x z@MHNfe;5Ba|2)5iA1nBU3Lzxa3w^}?;vjLjc!tzXx|x{q$z~Abo_cr7zQs^liF_eoX&KkI?Vv zkF=8_D2kG#j8gKIVx>$8Dw~xST3_MTkIDcOv;Dz24EL+!};<2Tz(VXO1IM;bT{2g_tR$DLJ!fy=<_K3o_1Bv zQ@Se`DHkhQO0JTJo(mN}`mR($N?2)7CMuJa>B>wcO&hPx(&lTsv;*1^?LS&)JwflM z%X*T&Q-4oCsDGh2*X;|-&ud4YL_nPpa)51XsaE#{l% zC+0V%&$`0mtu$-6^@6p|dfVD#9kqx(&{pi*?LGEUn>d#`nv>?--~^n>PNOs5S>tSR zb~#5K!r}k=bdJMiw?B*~KQkp3bqmNrTk(rc(nb7>)+Mjxdc=w|wFnxqU; zZc(Nw?*M8E@)X&#N zJxjk)FV$!0v-Ah_rTVk_YkHnhW!!44G+x1~{a~D7-eit5r}Ty4?GNlP?7mKgbBA-c^MbR{A&G>n!#elmF6YX* zI&L-hD%X#{jt^kf_wap%@sQWsgoVNr!hZ{I3117}2^Wc%Kzg4R*NCr(pNR?5Ak2P& zbV%wgkB~>oH^^h;I{DA?QhAk}05qPYTj*P~Kv}K4sx&JHm2=c#>L+R!t*4fwh23obWdF&@#47&PdDl6_ zWEAgYEntK@i@TB&xeRU;Hy7GR_$T=1_?P%i{5$*y{Ac`E{P+Bs!ns)0%Y|HF4A%4s zVXg3i&`Zo0$B7ffd&K+2rDBt~N&HCsR_uZ`)uj>AO;V+FkF-o$FKv-_OCL&|W4Q-$k=@fbookw4z7b-sGQDur6*0<{Q#vR5zkl&|_b;jF< zW~Q4J=Dp@hbA!3dyuun{RamoJx!q|Uv&!v>_QUoHd!_x7y~EDI3O(n1&E{B0$X2ip z+(d2~w-T$fn>&*~n?H}gf*;5a#yU;n=fJ`&+rJhiSU{5mGGkwFLo1qh<(K? zMHy@I5M=B{jDMr}y0}d|CSE8_g_bo+3#FCPYtm)%)v^Kmm@Ajb)$$$keEAJ|pWGrJ zk`K#A0#KUS;kzWtC?W-Gw(L%VCA-$JI(#(r)GjBSwpRCYqT{6>lm`? zt;yD1)-tQfddXr3bY^0%+k|(81DMyDVpp-J=)=4;aj=*p`o*BwfEmsc9}}00e}g8i z$13d-_ly4{9u+Oo*x&OxnM>n_!+(y0^_j#y&%MYsb1mE8Q#JZSEn^3(EWdAqzr z-YxHy_sh+$vTbrXjtUU)^IA6a+AFPkmOJLz<=#BbQ`bPa@__zeaXIx`AMwW4- z(O}FrR=@+lYFuJo3m<$dQ0-(fuXY{eOSMcZVBKvkwN^l`R#|J|<2G2EtgY7hc2B#H z?Xxep@3J2N&TH&-_6B>C{jq(vV>zkL5GTXQa&nzKC*LV_mIL`!zg+bB){rZXLIU+sDQ6v-u|eef~?H2z>-YNCWO=uH2N0H;XgH2gSwW zGtkU8#69qYmr2aFjFUc*I?AJ=gB__xx6uRiYwSiw0Kpl`%gXCYs(QVerH)eb)nc_w ztyaV81a-1H1NLN&I!}E}U7{{mo75N7b?QcStNNC@TivHNtDn05@q6_b=w)Z^T&;)J zN4rcLpbgX{P1h2&L0X2E4L>qgV<*?xnZFen`9%2o`<;2tZ|kJ|67b@4h;E=$^Qaw=Bk7M literal 0 HcmV?d00001 diff --git a/tools/old/pcx2png/src/main.cpp b/tools/old/pcx2png/src/main.cpp new file mode 100644 index 000000000..c65cb6397 --- /dev/null +++ b/tools/old/pcx2png/src/main.cpp @@ -0,0 +1,47 @@ +/* + + Brainless pcx2png converter. + +*/ + +#include "il/ilut.h" + +int main(int argc, char** argv) +{ + unsigned int ILid; + int size; + char filein[256]; + char filetemp1[256]; + char filetemp2[256]; + char fileout[256]; + + printf("\n"); + + if(argc!=2) + { + printf("Usage: pcx2png filename\n"); + exit(0); + } + + sprintf(filein,"%s",argv[1]); + sprintf(filetemp1,"%s","deleteme1.pcx"); + sprintf(filetemp2,"%s","deleteme2.pcx"); + sprintf(fileout,"%s",filein); + size=strlen(fileout); + fileout[size-3]='p'; + fileout[size-2]='n'; + fileout[size-1]='g'; + + ilInit(); + ilGenImages(1,&ILid); + ilBindImage(ILid); + ilLoadImage(filein); + ilSaveImage(filetemp1); + ilLoadImage(filetemp1); + ilSaveImage(filetemp2); + ilLoadImage(filetemp2); + ilSaveImage(fileout); + + printf("In: %s\n",filein); + printf("Out: %s\n",fileout); +} \ No newline at end of file