CnC_Remastered_Collection/TIBERIANDAWN/WIN32LIB/WSA.CPP
PG-SteveT 03416d24e1 Initial Source Code commit
Initial commit of original Tiberian Dawn and Red Alert source code converted to build as DLLs, and compatible with the release version of Command & Conquer Remastered.
2020-05-27 12:16:20 -07:00

1154 lines
45 KiB
C++

//
// Copyright 2020 Electronic Arts Inc.
//
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
// software: you can redistribute it and/or modify it under the terms of
// the GNU General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
// in the hope that it will be useful, but with permitted additional restrictions
// under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
// distributed with this program. You should have received a copy of the
// GNU General Public License along with permitted additional restrictions
// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
/* $Header: g:/library/source/rcs/./wsa.c 1.16 1994/05/20 15:35:27 joe_bostic Exp $ */
/***************************************************************************
** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S **
***************************************************************************
* *
* Project Name : Library Animation System *
* *
* File Name : WSA.C *
* *
* Programmer : Michael Legg *
* *
* Start Date : November 20, 1991 *
* *
*-------------------------------------------------------------------------*
* There are many different ways that the user can use the WSA library *
* module. The options are as follows : *
* *
* System Allocation vs User Buffer - The user may request that the *
* system allocate the needed buffer from the heap or the user may *
* pass his own buffer in for the animator to use. *
* *
* Resident vs File based - If there is enough RAM, the user may put the *
* entire animation into RAM for fastest animations. If there is *
* not enouph RAM, the system will automatically make it so each *
* frame will be read off disk when needed. *
* *
* Direct to Page vs Use of a user buffer -- Noramally Direct to page *
* is the best method both in speed and in RAM need to hold anim. *
* One may want to use the write to user buffer method if they *
* are using the animation in a non sequencial order. *
* *
*-------------------------------------------------------------------------*
* Functions: *
* Animate_Frame -- Displays a frame of a given animation *
* Get_Animation_Frame_Count -- Return Number of frames in an animation. *
* Get_Animation_X -- Gets the x from an animation *
* Get_Animation_Y -- Gets the y from an animation *
* Get_Animation_Width -- Gets the width from an animation *
* Get_Animation_Height -- The height of the animation we are processing *
* Apply_Delta -- Copies frame into delta buffer, then applies to target *
* Close_Animation -- Close the animation, freeing the space if necessary*
* Get_File_Frame_Offset -- Get offset of a delta frame from animate file*
* Get_Resident_Frame_Offset -- Gets frame offset of animate file in RAM *
* Open_Animation -- Opens an animation file and reads into buffer *
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include <wwstd.h>
#include "wsa.h"
#include <wwmem.h>
#include <file.h>
#include <misc.h>
#include <iff.h>
//#include <mem.h>
#include <string.h>
//
// WSA animation header allocation type.
// If we need more then 8 flags for the flags variable, we can combine
// USER_ALLOCATED with SYS_ALLOCATED and combine FILE with RESIDENT.
//
#define WSA_USER_ALLOCATED 0x01
#define WSA_SYS_ALLOCATED 0x02
#define WSA_FILE 0x04
#define WSA_RESIDENT 0x08
#define WSA_TARGET_IN_BUFFER 0x10
#define WSA_LINEAR_ONLY 0x20
#define WSA_FRAME_0_ON_PAGE 0x40
#define WSA_AMIGA_ANIMATION 0x80
#define WSA_PALETTE_PRESENT 0x100
#define WSA_FRAME_0_IS_DELTA 0x200
// These are used to call Apply_XOR_Delta_To_Page_Or_Viewport() to setup flags parameter. If
// These change, make sure and change their values in lp_asm.asm.
#define DO_XOR 0x0
#define DO_COPY 0x01
#define TO_VIEWPORT 0x0
#define TO_PAGE 0x02
typedef struct {
unsigned short current_frame;
unsigned short total_frames;
unsigned short pixel_x;
unsigned short pixel_y;
unsigned short pixel_width;
unsigned short pixel_height;
unsigned short largest_frame_size;
char *delta_buffer;
char *file_buffer;
char file_name[ 13 ];
short flags;
// New fields that animate does not know about below this point. SEE EXTRA_charS_ANIMATE_NOT_KNOW_ABOUT
short file_handle;
unsigned long anim_mem_size;
} SysAnimHeaderType;
// NOTE:"THIS IS A BAD THING. SINCE sizeof(SysAnimHeaderType) CHANGED, THE ANIMATE.EXE
// UTILITY DID NOT KNOW I UPDATED IT, IT ADDS IT TO largest_frame_size BEFORE SAVING
// IT TO THE FILE. THIS MEANS I HAVE TO ADD THESE charS ON NOW FOR IT TO WORK.
#define EXTRA_charS_ANIMATE_NOT_KNOW_ABOUT (sizeof(short) + sizeof(unsigned long))
//
// Header structure for the file.
// NOTE: The 'total_frames' field is used to differentiate between Amiga and IBM
// animations. Amiga animations have the HIGH bit set.
//
typedef struct {
unsigned short total_frames;
unsigned short pixel_x;
unsigned short pixel_y;
unsigned short pixel_width;
unsigned short pixel_height;
unsigned short largest_frame_size;
short flags;
unsigned long frame0_offset;
unsigned long frame0_end;
/* unsigned long data_seek_offset, unsigned short frame_size ... */
} WSA_FileHeaderType;
#define WSA_FILE_HEADER_SIZE ( sizeof(WSA_FileHeaderType) - (2 * sizeof(unsigned long)) )
/*=========================================================================*/
/* The following PRIVATE functions are in this file: */
/*=========================================================================*/
PRIVATE unsigned long Get_Resident_Frame_Offset( char *file_buffer, int frame );
PRIVATE unsigned long Get_File_Frame_Offset( int file_handle, int frame, int palette_adjust);
PRIVATE BOOL Apply_Delta(SysAnimHeaderType *sys_header, int curr_frame, char *dest_ptr, int dest_w);
/*= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
/***************************************************************************
* OPEN_ANIMATION -- Opens an animation file and reads into buffer *
* *
* INPUT: char *file_name of animation sequence file. *
* char *user_buffer pointer if one exists (NULL ok) *
* unsigned long user_buffer_size if known (NULL ok) *
* WSAOpenType user_flags - flags on how to open. *
* unsigned char *palette - pointer to palette space for return (NULL ok) *
* *
* OUTPUT: void *pointer to animation data. Must be used for all *
* other WSA calls. *
* *
* WARNINGS: May return NULL, please check. *
* *
* HISTORY: *
* 11/26/1991 SB : Created. *
*=========================================================================*/
void * __cdecl Open_Animation(char const *file_name, char *user_buffer, long user_buffer_size, WSAOpenType user_flags, unsigned char *palette)
{
int fh, anim_flags;
int palette_adjust;
unsigned int offsets_size;
unsigned int frame0_size;
long target_buffer_size, delta_buffer_size, file_buffer_size;
long max_buffer_size, min_buffer_size;
char *sys_anim_header_buffer;
char *target_buffer;
char *delta_buffer, *delta_back;
SysAnimHeaderType *sys_header;
WSA_FileHeaderType file_header;
/*======================================================================*/
/* Open the file to get the header information */
/*======================================================================*/
anim_flags = 0;
fh = Open_File(file_name, READ);
Read_File(fh, (char *) &file_header, sizeof(WSA_FileHeaderType));
/*======================================================================*/
/* If the file has an attached palette then if we have a valid palette */
/* pointer we need to read it in. */
/*======================================================================*/
if (file_header.flags & 1) {
anim_flags |= WSA_PALETTE_PRESENT;
palette_adjust = 768;
if (palette != NULL) {
Seek_File(fh, sizeof(unsigned long) * (file_header.total_frames), SEEK_CUR);
Read_File(fh, palette, 768L);
}
} else {
palette_adjust = 0;
}
// Check for flag from ANIMATE indicating that this animation was
// created from a .LBM and a .ANM. These means that the first
// frame is a XOR Delta from a picture, not black.
if (file_header.flags & 2) {
anim_flags |= WSA_FRAME_0_IS_DELTA;
}
// Get the total file size minus the size of the first frame and the size
// of the file header. These will not be read in to save even more space.
file_buffer_size = Seek_File(fh, 0L, SEEK_END);
if (file_header.frame0_offset) {
long tlong;
tlong = file_header.frame0_end - file_header.frame0_offset;
frame0_size = (unsigned short) tlong;
}
else {
anim_flags |= WSA_FRAME_0_ON_PAGE;
frame0_size = 0;
}
file_buffer_size -= palette_adjust + frame0_size + WSA_FILE_HEADER_SIZE;
// We need to determine the buffer sizes required for the animation. At a
// minimum, we need a target buffer for the uncompressed frame and a delta
// buffer for the delta data. We may be able to make the file resident,
// so we will determine the file size.
//
// If the target buffer is in the user buffer
// Then figure its size
// and set the allocation flag
// Else size is zero.
//
if (user_flags & WSA_OPEN_DIRECT) {
target_buffer_size = 0L;
}
else {
anim_flags |= WSA_TARGET_IN_BUFFER;
target_buffer_size = (unsigned long) file_header.pixel_width * file_header.pixel_height;
}
// NOTE:"THIS IS A BAD THING. SINCE sizeof(SysAnimHeaderType) CHANGED, THE ANIMATE.EXE
// UTILITY DID NOT KNOW I UPDATED IT, IT ADDS IT TO largest_frame_size BEFORE SAVING
// IT TO THE FILE. THIS MEANS I HAVE TO ADD THESE charS ON NOW FOR IT TO WORK.
delta_buffer_size = (unsigned long) file_header.largest_frame_size + EXTRA_charS_ANIMATE_NOT_KNOW_ABOUT;
min_buffer_size = target_buffer_size + delta_buffer_size;
max_buffer_size = min_buffer_size + file_buffer_size;
// check to see if buffer size is big enough for at least min required
if (user_buffer && (user_buffer_size < min_buffer_size)) {
Close_File(fh);
return(NULL);
}
// A buffer was not passed in, so do allocations
if (user_buffer == NULL) {
// If the user wants it from the disk, then let us give it to him,
// otherwise, try to give a max allocation he can have.
if (user_flags & WSA_OPEN_FROM_DISK) {
user_buffer_size = min_buffer_size;
}
// else no buffer size, then try max configuration.
else if (!user_buffer_size) {
user_buffer_size = max_buffer_size;
}
// else if buffer specified is less then max needed, give min.
else if (user_buffer_size < max_buffer_size) {
user_buffer_size = min_buffer_size;
}
// otherwise we only want to alloc what we need.
else {
user_buffer_size = max_buffer_size;
}
// Check to see if enough RAM available for buffer_size.
if (user_buffer_size > Ram_Free(MEM_NORMAL)) {
// If not enough room for even the min, return no buffer.
if (min_buffer_size > Ram_Free(MEM_NORMAL)) {
Close_File(fh);
return(NULL);
}
// Else make buffer size the min and allocate it.
user_buffer_size = min_buffer_size;
}
// allocate buffer needed
user_buffer = (char *) Alloc(user_buffer_size, MEM_CLEAR);
anim_flags |= WSA_SYS_ALLOCATED;
}
else {
// Check to see if the user_buffer_size should be min or max.
if ((user_flags & WSA_OPEN_FROM_DISK) || (user_buffer_size < max_buffer_size)) {
user_buffer_size = min_buffer_size;
}
else {
user_buffer_size = max_buffer_size;
}
anim_flags |= WSA_USER_ALLOCATED;
}
// Set the pointers to the RAM buffers
sys_anim_header_buffer = user_buffer;
target_buffer = (char *) Add_Long_To_Pointer(sys_anim_header_buffer, sizeof(SysAnimHeaderType));
delta_buffer = (char *) Add_Long_To_Pointer(target_buffer, target_buffer_size);
// Clear target buffer if it is in the user buffer.
if (target_buffer_size) {
memset( target_buffer, 0, (unsigned short) target_buffer_size );
}
// Poke data into the system animation header (start of user_buffer)
// current_frame is set to total_frames so that Animate_Frame() knows that
// it needs to clear the target buffer.
sys_header = ( SysAnimHeaderType * ) sys_anim_header_buffer;
sys_header -> current_frame =
sys_header -> total_frames = file_header.total_frames;
sys_header -> pixel_x = file_header.pixel_x;
sys_header -> pixel_y = file_header.pixel_y;
sys_header -> pixel_width = file_header.pixel_width;
sys_header -> pixel_height = file_header.pixel_height;
sys_header -> anim_mem_size = user_buffer_size;
sys_header -> delta_buffer = delta_buffer;
sys_header -> largest_frame_size =
(unsigned short) (delta_buffer_size - sizeof(SysAnimHeaderType));
strcpy(sys_header->file_name, file_name);
// Figure how much room the frame offsets take up in the file.
// Add 2 - one for the wrap around and one for the final end offset.
offsets_size = (file_header.total_frames + 2) << 2;
// Can the user_buffer_size handle the maximum case buffer?
if ( user_buffer_size == max_buffer_size) {
//
// set the file buffer pointer,
// Skip over the header information.
// Read in the offsets.
// Skip over the first frame.
// Read in remaining frames.
//
sys_header->file_buffer = (char *)Add_Long_To_Pointer(delta_buffer,sys_header->largest_frame_size);
Seek_File( fh, WSA_FILE_HEADER_SIZE, SEEK_SET);
Read_File( fh, sys_header->file_buffer, offsets_size);
Seek_File( fh, frame0_size + palette_adjust, SEEK_CUR);
Read_File( fh, sys_header->file_buffer + offsets_size,
file_buffer_size - offsets_size);
//
// Find out if there is an ending value for the last frame.
// If there is not, then this animation will not be able to
// loop back to the beginning.
//
if (Get_Resident_Frame_Offset( sys_header->file_buffer, sys_header->total_frames + 1))
anim_flags |= WSA_RESIDENT;
else
anim_flags |= WSA_LINEAR_ONLY | WSA_RESIDENT;
}
else { // buffer cannot handle max_size of buffer
if(Get_File_Frame_Offset( fh, sys_header->total_frames + 1, palette_adjust))
anim_flags |= WSA_FILE;
else
anim_flags |= WSA_LINEAR_ONLY | WSA_FILE;
////
sys_header->file_buffer = NULL;
}
// Figure where to back load frame 0 into the delta buffer.
delta_back = (char *)Add_Long_To_Pointer(delta_buffer,
sys_header->largest_frame_size - frame0_size);
// Read the first frame into the delta buffer and uncompress it.
// Then close it.
Seek_File( fh, WSA_FILE_HEADER_SIZE + offsets_size + palette_adjust, SEEK_SET);
Read_File( fh, delta_back, frame0_size);
// We do not use the file handle when it is in RAM.
if (anim_flags & WSA_RESIDENT) {
sys_header -> file_handle = (short) -1;
Close_File(fh);
}
else {
sys_header -> file_handle = (short)fh;
}
LCW_Uncompress(delta_back, delta_buffer, sys_header->largest_frame_size);
// Finally set the flags,
sys_header->flags = (short)anim_flags;
// return valid handle
return( user_buffer );
}
/***************************************************************************
* CLOSE_ANIMATION -- Close the animation, freeing the space if necessary. *
* *
* INPUT: void *handle to the animation data buffer *
* *
* OUTPUT: none *
* *
* WARNINGS: handle MUST have been returned by Open_Animation *
* *
* HISTORY: *
* 11/23/1991 ML : Created. *
*=========================================================================*/
void __cdecl Close_Animation( void *handle )
{
SysAnimHeaderType *sys_header;
// Assign our local system header pointer to the beginning of the handle space
sys_header = (SysAnimHeaderType *) handle;
// Close the WSA file in it was disk based.
if (sys_header->flags & WSA_FILE) {
Close_File(sys_header->file_handle);
}
// Check to see if the buffer was allocated OR the programmer provided the buffer
if (handle && sys_header->flags & WSA_SYS_ALLOCATED) {
Free(handle);
}
}
/***************************************************************************
* ANIMATE_FRAME -- Displays a frame of a given animation *
* *
* INPUT: void *handle to the animation. *
* int frame_number wanted to be displayed *
* int x_pixel position of left side of animation on page *
* int y_pixel position of top of animation on page *
* *
* OUTPUT: BOOL if successfull or not. *
* *
* WARNINGS: *
* *
* HISTORY: *
* 11/27/1991 SB : Created. *
*=========================================================================*/
//#pragma off (unreferenced)
BOOL __cdecl Animate_Frame(void *handle, GraphicViewPortClass& view,
int frame_number, int x_pixel, int y_pixel,
WSAType flags_and_prio, void *magic_cols, void *magic)
{
SysAnimHeaderType *sys_header; // fix up the void pointer past in.
int curr_frame; // current frame we are on.
int total_frames; // number of frames in anim.
int distance; // distance to desired frame.
int search_dir; // direcion to search for desired frame.
int search_frames; // How many frames to search.
int loop; // Just a loop varible.
char *frame_buffer; // our destination.
BOOL direct_to_dest; // are we going directly to the destination?
int dest_width; // the width of the destination buffer or page.
// Assign local pointer to the beginning of the buffer where the system information
// resides
sys_header = (SysAnimHeaderType *)handle;
// Get the total number of frames
total_frames = sys_header->total_frames;
// Are the animation handle and the frame number valid?
if (!handle || (total_frames <= frame_number)) {
return FALSE;
}
if (view.Lock()!=TRUE) return (FALSE);
// Decide if we are going to a page or a viewport (part of a buffer).
dest_width = view.Get_Width() + view.Get_XAdd() + view.Get_Pitch();
//
// adjust x_pixel and y_pixel by system pixel_x and pixel_y respectively.
//
x_pixel += (short)sys_header->pixel_x;
y_pixel += (short)sys_header->pixel_y;
//
// Check to see if we are using a buffer inside of the animation buffer or if
// it is being drawn directly to the destination page or buffer.
//
if (sys_header->flags & WSA_TARGET_IN_BUFFER) {
// Get a pointer to the frame in animation buffer.
frame_buffer = (char *)Add_Long_To_Pointer(sys_header, sizeof(SysAnimHeaderType));
direct_to_dest = FALSE;
}
else {
frame_buffer = (char *)view.Get_Offset();
frame_buffer += (y_pixel * dest_width) + x_pixel;
direct_to_dest = TRUE;
}
//
// If current_frame is equal to tatal_frames, then no animations have taken place
// so must uncompress frame 0 in delta buffer to the frame_buffer/page if it
// exists.
//
if (sys_header->current_frame == total_frames) {
// Call apply delta telling it wether to copy or to xor depending on if the
// target is a page or a buffer.
if (!(sys_header->flags & WSA_FRAME_0_ON_PAGE)) {
if (direct_to_dest) {
// The last parameter says weather to copy or to XOR. If the
// first frame is a DELTA, then it must be XOR'd. A TRUE is
// copy while FALSE is XOR.
Apply_XOR_Delta_To_Page_Or_Viewport(frame_buffer, sys_header->delta_buffer,
sys_header->pixel_width, dest_width, //dest_width - sys_header->pixel_width,
(sys_header->flags & WSA_FRAME_0_IS_DELTA)? DO_XOR : DO_COPY);
}
else {
Apply_XOR_Delta(frame_buffer, sys_header->delta_buffer);
}
}
sys_header->current_frame = 0;
}
//
// Get the current frame
// If no looping aloud, are the trying to do it anyways?
//
curr_frame = sys_header->current_frame;
#if (FALSE)
// This is commented out since we will let them loop even though they should
// not - it will be slower.
if ( (sys_header->flags & WSA_LINEAR_ONLY) && (frame_number < cur_frame) ) {
view.Unlock();
return FALSE;
}
#endif
// Get absoulte distance from our current frame to the target frame
distance = ABS(curr_frame - frame_number);
// Assume we are searching right
search_dir = 1;
// Calculate the number of frames to search if we go right and wrap
if (frame_number > curr_frame) {
search_frames = total_frames - frame_number + curr_frame;
// Is going right faster than going backwards?
// Or are they trying to loop when the should not?
if ((search_frames < distance) && !(sys_header->flags & WSA_LINEAR_ONLY)) {
search_dir = -1; // No, so go left
}
else {
search_frames = distance;
}
}
else {
search_frames = total_frames - curr_frame + frame_number;
// Is going right faster than going backwards?
// Or are they trying to loop when the should not?
if ((search_frames >= distance) || (sys_header->flags & WSA_LINEAR_ONLY)) {
search_dir = -1; // No, so go left
search_frames = distance;
}
}
// Take care of the case when we are searching right (possibly right)
if (search_dir > 0) {
for (loop = 0; loop < search_frames; loop++) {
// Move the logical frame number ordinally right
curr_frame += search_dir;
Apply_Delta(sys_header, curr_frame, frame_buffer, dest_width);
// Adjust the current frame number, taking into consideration that we could
// have wrapped
if (curr_frame == total_frames) {
curr_frame = 0;
}
}
}
else {
for (loop = 0; loop < search_frames; loop++) {
// If we are going backwards and we are on frame 0, the delta to get
// to the last frame is the n + 1 delta (wrap delta)
if (curr_frame == 0) {
curr_frame = total_frames;
}
Apply_Delta(sys_header, curr_frame, frame_buffer, dest_width);
curr_frame += search_dir;
}
}
sys_header->current_frame = (short)frame_number;
// If we did this all in a hidden buffer, then copy it to the desired page or viewport.
if (sys_header->flags & WSA_TARGET_IN_BUFFER) {
#if TRUE
Buffer_To_Page(x_pixel, y_pixel, sys_header->pixel_width, sys_header->pixel_height, frame_buffer, view);
#else
int flags = ((unsigned short)flags_and_prio & 0xFF00u) >> 12u;
int pri = flags_and_prio & 0x00FF;
Buffer_Bitblit_To_LogicPage(x_pixel, y_pixel, sys_header->pixel_width,
sys_header->pixel_height, 0, flags, frame_buffer, pri,
magic_cols, magic);
#endif
}
view.Unlock();
return TRUE;
}
/***************************************************************************
* ANIMATE_FRAME -- Displays a frame of a given animation *
* *
* INPUT: void *handle to the animation. *
* int frame_number wanted to be displayed *
* int x_pixel position of left side of animation on page *
* int y_pixel position of top of animation on page *
* *
* OUTPUT: BOOL if successfull or not. *
* *
* WARNINGS: *
* *
* HISTORY: *
* 11/27/1991 SB : Created. *
*=========================================================================*/
//#pragma argsused
#ifdef cuts
BOOL __cdecl Animate_Frame(void *handle, GraphicViewPortClass& view,
int frame_number, int x_pixel, int y_pixel,
WSAType flags_and_prio, void *magic_cols, void *magic)
{
SysAnimHeaderType *sys_header; // fix up the void pointer past in.
int curr_frame; // current frame we are on.
int total_frames; // number of frames in anim.
int distance; // distance to desired frame.
int search_dir; // direcion to search for desired frame.
int search_frames; // How many frames to search.
int loop; // Just a loop varible.
char *frame_buffer; // our destination.
BOOL direct_to_dest; // are we going directly to the destination?
int dest_width; // the width of the destination buffer or page.
// Assign local pointer to the beginning of the buffer where the system information
// resides
sys_header = (SysAnimHeaderType *)handle;
// Get the total number of frames
total_frames = sys_header->total_frames;
// Are the animation handle and the frame number valid?
if (!handle || (total_frames <= frame_number)) {
return FALSE;
}
// Decide if we are going to a page or a viewport (part of a buffer).
dest_width = view.Get_Width() + view.Get_XAdd();
//
// adjust x_pixel and y_pixel by system pixel_x and pixel_y respectively.
//
x_pixel += (short)sys_header->pixel_x;
y_pixel += (short)sys_header->pixel_y;
//
// Check to see if we are using a buffer inside of the animation buffer or if
// it is being drawn directly to the destination page or buffer.
//
if (sys_header->flags & WSA_TARGET_IN_BUFFER) {
// Get a pointer to the frame in animation buffer.
frame_buffer = (char *)Add_Long_To_Pointer(sys_header, sizeof(SysAnimHeaderType));
direct_to_dest = FALSE;
}
else {
frame_buffer = (char *)view.Get_Offset();
frame_buffer += (y_pixel * dest_width) + x_pixel;
direct_to_dest = TRUE;
}
//
// If current_frame is equal to tatal_frames, then no animations have taken place
// so must uncompress frame 0 in delta buffer to the frame_buffer/page if it
// exists.
//
if (sys_header->current_frame == total_frames) {
// Call apply delta telling it wether to copy or to xor depending on if the
// target is a page or a buffer.
if (!(sys_header->flags & WSA_FRAME_0_ON_PAGE)) {
if (direct_to_dest) {
// The last parameter says weather to copy or to XOR. If the
// first frame is a DELTA, then it must be XOR'd. A TRUE is
// copy while FALSE is XOR.
Apply_XOR_Delta_To_Page_Or_Viewport(frame_buffer, sys_header->delta_buffer,
sys_header->pixel_width, dest_width, //dest_width - sys_header->pixel_width,
(sys_header->flags & WSA_FRAME_0_IS_DELTA)? DO_XOR : DO_COPY);
}
else {
Apply_XOR_Delta(frame_buffer, sys_header->delta_buffer);
}
}
sys_header->current_frame = 0;
}
//
// Get the current frame
// If no looping aloud, are the trying to do it anyways?
//
curr_frame = sys_header->current_frame;
#if (FALSE)
// This is commented out since we will let them loop even though they should
// not - it will be slower.
if ( (sys_header->flags & WSA_LINEAR_ONLY) && (frame_number < cur_frame) ) {
return FALSE;
}
#endif
// Get absoulte distance from our current frame to the target frame
distance = ABS(curr_frame - frame_number);
// Assume we are searching right
search_dir = 1;
// Calculate the number of frames to search if we go right and wrap
if (frame_number > curr_frame) {
search_frames = total_frames - frame_number + curr_frame;
// Is going right faster than going backwards?
// Or are they trying to loop when the should not?
if ((search_frames < distance) && !(sys_header->flags & WSA_LINEAR_ONLY)) {
search_dir = -1; // No, so go left
}
else {
search_frames = distance;
}
}
else {
search_frames = total_frames - curr_frame + frame_number;
// Is going right faster than going backwards?
// Or are they trying to loop when the should not?
if ((search_frames >= distance) || (sys_header->flags & WSA_LINEAR_ONLY)) {
search_dir = -1; // No, so go left
search_frames = distance;
}
}
// Take care of the case when we are searching right (possibly right)
if (search_dir > 0) {
for (loop = 0; loop < search_frames; loop++) {
// Move the logical frame number ordinally right
curr_frame += search_dir;
Apply_Delta(sys_header, curr_frame, frame_buffer, dest_width);
// Adjust the current frame number, taking into consideration that we could
// have wrapped
if (curr_frame == total_frames) {
curr_frame = 0;
}
}
}
else {
for (loop = 0; loop < search_frames; loop++) {
// If we are going backwards and we are on frame 0, the delta to get
// to the last frame is the n + 1 delta (wrap delta)
if (curr_frame == 0) {
curr_frame = total_frames;
}
Apply_Delta(sys_header, curr_frame, frame_buffer, dest_width);
curr_frame += search_dir;
}
}
sys_header->current_frame = frame_number;
// If we did this all in a hidden buffer, then copy it to the desired page or viewport.
if (sys_header->flags & WSA_TARGET_IN_BUFFER) {
#if TRUE
Buffer_To_Page(x_pixel, y_pixel, sys_header->pixel_width, sys_header->pixel_height, frame_buffer, view);
#else
int flags = ((unsigned short)flags_and_prio & 0xFF00u) >> 12u;
int pri = flags_and_prio & 0x00FF;
Buffer_Bitblit_To_LogicPage(x_pixel, y_pixel, sys_header->pixel_width,
sys_header->pixel_height, 0, flags, frame_buffer, pri,
magic_cols, magic);
#endif
}
return TRUE;
}
#endif
/***************************************************************************
* ANIMATE_FRAME_COUNT -- Return Number of frames in an animation. *
* *
* INPUT: void *handle to the animation. *
* *
* OUTPUT: int number of frames in animation. *
* *
* WARNINGS: *
* *
* HISTORY: *
* 12/05/1991 SB : Created. *
*=========================================================================*/
int __cdecl Get_Animation_Frame_Count(void *handle)
{
SysAnimHeaderType *sys_header;
if (!handle) {
return FALSE;
}
sys_header = (SysAnimHeaderType *) handle;
return((short)sys_header->total_frames);
}
/***************************************************************************
* GET_ANIM_X -- Gets the x from an animation *
* *
* *
* INPUT: void * to the animation that we are processing *
* *
* OUTPUT: int the x of the animation we are processing *
* *
* WARNINGS: *
* *
* HISTORY: *
* 07/03/1992 DRD : Created. *
*=========================================================================*/
int __cdecl Get_Animation_X(void const *handle)
{
SysAnimHeaderType const *sys_header;
if (!handle) {
return FALSE;
}
sys_header = (SysAnimHeaderType *) handle;
return(sys_header->pixel_x);
}
/***************************************************************************
* GET_ANIM_Y -- Gets the y from an animation *
* *
* *
* INPUT: void * to the animation that we are processing *
* *
* OUTPUT: int the y of the animation we are processing *
* *
* WARNINGS: *
* *
* HISTORY: *
* 10/14/1992 PWG : Created. *
*=========================================================================*/
int __cdecl Get_Animation_Y(void const *handle)
{
SysAnimHeaderType const *sys_header;
if (!handle) {
return FALSE;
}
sys_header = (SysAnimHeaderType *) handle;
return(sys_header->pixel_y);
}
/***************************************************************************
* GET_ANIM_WIDTH -- Gets the width from an animation *
* *
* *
* INPUT: void * to the animation that we are processing *
* *
* OUTPUT: int the width of the animation we are processing *
* *
* WARNINGS: *
* *
* HISTORY: *
* 10/14/1992 PWG : Created. *
*=========================================================================*/
int __cdecl Get_Animation_Width(void const *handle)
{
SysAnimHeaderType const *sys_header;
if (!handle) {
return FALSE;
}
sys_header = (SysAnimHeaderType *) handle;
return(sys_header->pixel_width);
}
/***************************************************************************
* GET_ANIM_HEIGHT -- The height of the animation we are processing *
* *
* INPUT: void * to the animation that we are processing *
* *
* OUTPUT: int the height of the animation we are processing *
* *
* HISTORY: *
* 10/14/1992 PWG : Created. *
*=========================================================================*/
int __cdecl Get_Animation_Height(void const *handle)
{
SysAnimHeaderType const *sys_header;
if (!handle) {
return FALSE;
}
sys_header = (SysAnimHeaderType *) handle;
return(sys_header->pixel_height);
}
/***************************************************************************
* GET_ANIM_PALETTE -- Returns true if the anim had an attached palette *
* *
* INPUT: void * to the animation that we are processing *
* *
* OUTPUT: int True if the animation has a set palette. False if the *
* animation does not. *
* *
* HISTORY: *
* 10/14/1992 PWG : Created. *
*=========================================================================*/
int __cdecl Get_Animation_Palette(void const *handle)
{
SysAnimHeaderType const *sys_header;
if (!handle) {
return FALSE;
}
sys_header = (SysAnimHeaderType *) handle;
return(sys_header->flags & WSA_PALETTE_PRESENT);
}
/***************************************************************************
* GET_ANIMATION_SIZE -- Return the amount of memory the animation is using*
* *
* *
* INPUT: void * to the animation that we are processing *
* *
* OUTPUT: unsigned long number of byte used by animation. *
* *
* WARNINGS: *
* *
* HISTORY: *
* 05/23/1994 SKB : Created. *
*=========================================================================*/
unsigned long __cdecl Get_Animation_Size(void const *handle)
{
SysAnimHeaderType const *sys_header;
if (!handle) {
return FALSE;
}
sys_header = (SysAnimHeaderType *) handle;
return(sys_header->anim_mem_size);
}
/* :::::::::::::::::::::::::::: PRIVATE FUNCTIONS :::::::::::::::::::::::::::::: */
/***************************************************************************
* GET_RESIDENT_FRAME_OFFSET -- Gets frame offset of animate file in RAM *
* *
* INPUT: char *file_buffer in RAM of animation file. *
* int frame number that we need the offset of. *
* *
* OUTPUT: int offset of frame requested. *
* *
* WARNINGS: *
* *
* HISTORY: *
* 11/26/1991 SB : Created. *
*=========================================================================*/
PRIVATE unsigned long Get_Resident_Frame_Offset( char *file_buffer, int frame )
{
unsigned long frame0_size;
unsigned long *lptr;
// If there is a frame 0, the calculate its size.
lptr = (unsigned long *) file_buffer;
if (*lptr) {
frame0_size = lptr[1] - *lptr;
} else {
frame0_size = 0;
}
// Return the offset into RAM for the frame.
lptr += frame;
if (*lptr)
return (*lptr - (frame0_size + WSA_FILE_HEADER_SIZE));
else
return (0L);
}
/***************************************************************************
* GET_FILE_FRAME_OFFSET -- Get offset of a delta frame from animate file. *
* *
* INPUT: int file_handle of animation file. *
* int frame number that we need the offset of. *
* *
* OUTPUT: int offset of frame requested. *
* *
* WARNINGS: *
* *
* HISTORY: *
* 11/26/1991 SB : Created. *
*=========================================================================*/
PRIVATE unsigned long Get_File_Frame_Offset( int file_handle, int frame, int palette_adjust)
{
unsigned long offset;
Seek_File(file_handle, (frame << 2) + WSA_FILE_HEADER_SIZE, SEEK_SET);
if (Read_File(file_handle, (char *) &offset, sizeof(unsigned long)) != sizeof(unsigned long)) {
offset = 0L;
}
offset += palette_adjust;
return( offset );
}
/***************************************************************************
* APPLY_DELTA -- Copies frame into delta buffer, then applies to target *
* *
* INPUT: SysAnimHeaderType *sys_header - pointer to animation buffer.*
* int curr_frame - frame to put into target buffer. *
* *
* OUTPUT: BOOL - Return wether or not it worked. *
* *
* WARNINGS: *
* *
* HISTORY: *
* 11/26/1991 SB : Created. *
*=========================================================================*/
PRIVATE BOOL Apply_Delta(SysAnimHeaderType *sys_header, int curr_frame, char *dest_ptr, int dest_w)
{
char *data_ptr, *delta_back;
int file_handle, palette_adjust;
unsigned long frame_data_size, frame_offset;
palette_adjust = ((sys_header->flags & WSA_PALETTE_PRESENT) ? 768 : 0);
delta_back = sys_header->delta_buffer;
if (sys_header->flags & WSA_RESIDENT) {
// Get offset of the given frame in the resident file
// Get the size of the frame <- (frame+1 offset) - (offset)
// Point at the delta data
// figure offset to load data into end of delta buffer
// copy it into buffer
frame_offset = Get_Resident_Frame_Offset(sys_header->file_buffer, curr_frame);
frame_data_size = Get_Resident_Frame_Offset(sys_header->file_buffer, curr_frame + 1) - frame_offset;
data_ptr = (char *)Add_Long_To_Pointer(sys_header->file_buffer, frame_offset);
delta_back = (char *)Add_Long_To_Pointer(delta_back,
sys_header->largest_frame_size - frame_data_size);
Mem_Copy( data_ptr, delta_back, frame_data_size );
} else if (sys_header -> flags & WSA_FILE) {
// Open up file because not file not in RAM.
// Get offset of the given frame in the file on disk
// Get the size of the frame <- (frame+1 offset) - (offset)
// Return if Get_.._offset() failed. -- need error handling????
// Seek to delta data.
// figure offset to load data into end of delta buffer
// Read it into buffer -- Return if correct amount not read.-- errors??
file_handle = sys_header->file_handle;
Seek_File(file_handle, 0L, SEEK_SET);
frame_offset = Get_File_Frame_Offset(file_handle, curr_frame, palette_adjust);
frame_data_size = Get_File_Frame_Offset(file_handle, curr_frame + 1, palette_adjust) - frame_offset;
if (!frame_offset || !frame_data_size) {
return(FALSE);
}
Seek_File(file_handle, frame_offset, SEEK_SET);
delta_back = (char *)Add_Long_To_Pointer(delta_back, sys_header->largest_frame_size - frame_data_size);
if (Read_File(file_handle, delta_back, frame_data_size) != frame_data_size) {
return(FALSE);
}
}
// Uncompress data at end of delta buffer to the beginning of delta buffer.
// Find start of target buffer.
// Apply the XOR delta.
LCW_Uncompress(delta_back, sys_header->delta_buffer, sys_header->largest_frame_size);
if (sys_header->flags & WSA_TARGET_IN_BUFFER) {
Apply_XOR_Delta(dest_ptr, sys_header->delta_buffer);
}
else {
Apply_XOR_Delta_To_Page_Or_Viewport(dest_ptr, sys_header->delta_buffer,
sys_header->pixel_width, dest_w, DO_XOR);
}
return(TRUE);
}