Old tools that got removed a long time ago.
git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1545 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
@@ -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;
|
||||
@@ -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. */
|
||||
|
||||
@@ -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 <fcntl.h>
|
||||
#include <sys\types.h>
|
||||
#include <sys\stat.h>
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
anim2pcx anima dalloc gio misc misca lpfile pbio
|
||||
anim2pcx.exe
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
@@ -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 <sys\types.h>
|
||||
#include <sys\stat.h>
|
||||
|
||||
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 <name> 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 <num> 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 */
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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 <reg> of chip with
|
||||
; index register at <index> 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
|
||||
@@ -0,0 +1,197 @@
|
||||
/*--gio.c-----------------------------------------------------------------
|
||||
* Buffered i/o.
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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));
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 <fcntl.h>
|
||||
#include <malloc.h>
|
||||
#include <sys\types.h>
|
||||
#include <sys\stat.h>
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#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<lpheader.nLps; i++)
|
||||
{
|
||||
if(LpArray[i].baseRecord <= framenumber && LpArray[i].baseRecord + LpArray[i].nRecords > 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#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<lpheader.nLps; i++)
|
||||
{
|
||||
if(LpArray[i].baseRecord <= framenumber && LpArray[i].baseRecord + LpArray[i].nRecords > 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
anim2pcx %1
|
||||
ren ????0???.pcx %1.pcx
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
\sc2\utils\anm\anim2pcx %1
|
||||
ren *????.pcx %1*????.pcx
|
||||
@@ -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
|
||||
@@ -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>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Reference in New Issue
Block a user