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 000000000..66a2b7c2b Binary files /dev/null and b/tools/old/pcx2png/pcx2png.exe differ 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