-
Notifications
You must be signed in to change notification settings - Fork 0
/
animation.cp
314 lines (271 loc) · 15.8 KB
/
animation.cp
1
/****************************************************************************************//* ANIMATION.CP *//****************************************************************************************//* (c) 1995 by Magnet Interactive Studios, inc. All rights reserved. *//****************************************************************************************//* Revision History: *//* 7/7/94 File first created. By Andrew Looney. *//* v1.0 8/3/94 First polished version. By Andrew Looney. *//* v2.0 8/24/94 Seven level version burned onto CD-ROM. By Andrew Looney. *//* v2.1 8/29/94 Comments brought back up to date. By Andrew Looney. *//* v2.2 9/7/94 Sixteen level version. By Andrew Looney. *//* v2.3 9/23/94 Thirty level version burned onto CD-ROM. By Andrew Looney. *//* v2.4 10/19/94 Fifty level version. By Andrew Looney. *//* v2.5 10/31/94 Sixty level version burned onto CD-ROM. By Andrew Looney. *//* v3.0 10/31/94 Began switching over to real artwork. By Andrew Looney. *//* v3.1 11/11/94 COMDEX version. By Andrew Looney. *//* v3.2 12/2/94 Seventy-five level version. By Andrew Looney. *//* v3.3 12/14/94 Ack! Zombies! By Andrew Looney. *//* v3.4 12/23/94 Orange Meanies! By Andrew Looney. *//* v3.5 1/3/95 100 Levels! By Andrew Looney. *//* v3.6 1/5/95 101 Levels. By Andrew Looney. *//* v3.7 1/16/95 New, improved Brainy Seeker logic! By Andrew Looney. *//* v3.8 1/27/95 114 level version burned onto CD-ROM. By Andrew Looney. *//* v3.9 2/3/95 New CD-ROM burned for shipment to 3DO. By Andrew Looney. *//* v4.0 2/9/95 New CD-ROM featuring the big level grid. By Andrew Looney. *//* v4.1 2/22/95 New CD-ROM with rough draft of full interface. By Andrew Looney. *//* v4.2 3/17/95 The St. Patrick's Day Version. By Andrew Looney. *//* v4.3 3/20/95 The last version before the movies get added. By Andrew Looney. *//* v4.4 3/21/95 First version with movies integrated. By Andrew Looney. *//* v4.5 3/22/95 Second version with movies integrated. By Andrew Looney. *//* v4.6 3/27/95 Third version with movies integrated. By Andrew Looney. *//* v5.0 3/28/95 Newest version sent to QA. By Andrew Looney. *//* v5.1 3/28/95 Now, with Easter Eggs! By Andrew Looney. *//* v5.2 3/29/95 Could this be the final version? By Andrew Looney. *//* v5.3 3/30/95 OK, now maybe THIS is the final version! By Andrew Looney. *//* v5.4 4/3/95 Made a couple more minor changes. By Andrew Looney. *//****************************************************************************************//***************************** WHAT THIS SOFTWARE DOES ********************************** The purpose of the following functions is to improve upon the animation handling functions provided by 3DO. The 3DO functions allow you to easily load an anim file and step through it, but if you want to put two copies of the same anim on the screen at the same time, you run into troubles. Either you can load an entirely separate copy of the animation, which chews up valuable memory space, or you can exactly duplicate what the anim is displaying, which only works if you're willing to have your two anims synchronized. You can't have two users access a single anim structure because the anim structure maintains its own index into the list of frames, and if two users call GetAnimCel on their own, the anim sequence will get all smurfed up. Or rather, that's how it used to be. The functions defined below solve all of these problems. Contained herein are two class definitions, anim_source and anim_user. An application will create a single anim_source entity for each anim it wishes to access, which serves only to provide an original of the anim from which copies can be made.After this, any number of anim_user entities can be created, which will link to the anim_source and provide access to the anim. Each anim_user entity maintains its ownlocal copy of the anim's frame index, so that no matter how many users are playing ananim at the same time, each copy plays at its own point in the sequence. Also, whenever you create an anim_user entity, the memory it needs is allocated dynamically (and must therefore be deallocated when no longer needed) thus causing an application to gobble up only as much memory as it really requires.*****************************************************************************************//***** includes (make sure CPlusSwiHack.h is the last one) *****/#include "graphics.h"#include "stdio.h"#include "stdlib.h"#include "mem.h"#include "types.h"#include "hardware.h"#include "event.h"#include "strings.h"#include "access.h"#include "UMemory.h"#include "Form3DO.h"#include "Init3DO.h"#include "Parse3DO.h"#include "Utils3DO.h"#include "audio.h"#include "music.h"/***** Magnet includes *****/#include "animation.h"/***** special c++ include (this must be last) *****/#include "CPlusSwiHack.h"/***** global variables *****/extern ScreenContext g_screen;extern Item vbl;/*************************** anim_source::LoadArtwork ********************************* This function should be called only once during initialization. It will load the anim file and store the artwork in memory where it can be accessed whenever needed byanim_user entities. It will return TRUE if the animation loaded successfully, FALSE otherwise.*****************************************************************************************/bool anim_source::LoadArtwork(char *filename){ anim_pointer = LoadAnim(filename,MEMTYPE_CEL); if (anim_pointer == NULL) { WaitVBL (vbl, 1); ScavengeMem(); WaitVBL (vbl, 1); anim_pointer = LoadAnim(filename,MEMTYPE_CEL); if (anim_pointer != NULL) printf("Note: anim_source::LoadArtwork didn't succeed until 2nd try.\n"); } if (anim_pointer == NULL) { printf("anim_source::LoadArtwork: Cannot load anim file %s\n",filename); return (FALSE); } return(TRUE);}/************************** anim_source::ShutdownForExit ****************************** This function deallocates memory that was reserved for storage of the master copy ofan animation. It should be called when (but only when) the animation is no longer needed.*****************************************************************************************/void anim_source::ShutdownForExit(void){ if (anim_pointer != (ANIM *) NULL) UnloadAnim (anim_pointer); anim_pointer = (ANIM *) NULL;}/*************************** anim_user::InitializeAnim ******************************** This function initializes an anim_user entity. It takes as input the pointer to the anim_source structure it wishes to access, along with a frame rate value (specified as a 16.16 number) which it will use when fetching the next frame of the animation. Note that this function allocates memory to store its own local copy of the current cel of the animation, so a call to ShutdownForRestart is always required when an anim_user is no longer needed. (Otherwise, memory will gradually be lost.)*****************************************************************************************/void anim_user::InitializeAnim (anim_source *original, int32 frame_rate){ anim_source_pointer = original; anim_source_pointer->anim_pointer->cur_Frame = 0; next_frame_ccb = GetAnimCel(anim_source_pointer->anim_pointer, 0); current_frame_number = anim_source_pointer->anim_pointer->cur_Frame; current_frame_ccb = new(CCB); memcpy(current_frame_ccb,next_frame_ccb,sizeof(CCB)); anim_frame_rate = frame_rate; dormant = TRUE;}/***************************** anim_user::ChangeArt ************************************ If an anim_user is dealing with several very similar animations, it may wish to popfrom one anim source to another rather than have a user for each different source. Thischange is very easily managed by this routine.*****************************************************************************************/void anim_user::ChangeArt (anim_source *original){ anim_source_pointer = original;}/**************************** anim_user::PositionAnim ********************************* This function sets up the anim_user object so that it will display the anim at thegiven x,y coordinates.*****************************************************************************************/void anim_user::PositionAnim (int32 x_position, int32 y_position){ current_frame_ccb->ccb_XPos = x_position; current_frame_ccb->ccb_YPos = y_position;}/**************************** anim_user::AdvanceFrame ********************************* This function advances an animation's frame from the point of view of this particular anim_user object. Note that this is done by setting the anim_source's frame index to the anim_user's own local copy of the frame index, fetching the next frame, and then reading the frame index value and storing it back in the local copy. The upshot of this is that everyone using the anim_source must be doing it via an anim_user object; the frame sequencing from the perspective of the anim_source object will be totally haywire if several anim_users are playing the animation at once.*****************************************************************************************/void anim_user::AdvanceFrame(void){ anim_source_pointer->anim_pointer->cur_Frame = current_frame_number; next_frame_ccb = GetAnimCel(anim_source_pointer->anim_pointer, anim_frame_rate); current_frame_number = anim_source_pointer->anim_pointer->cur_Frame; current_frame_ccb->ccb_SourcePtr = next_frame_ccb->ccb_SourcePtr; current_frame_ccb->ccb_PLUTPtr = next_frame_ccb->ccb_PLUTPtr;}/**************************** anim_user::RefetchFrame ********************************* This function is similar to AdvanceFrame; however, it does everything except advancethe frame. It can be used in cases where the animation source has changed and the userwishes to switch over to the new animation without actually advancing the frame.*****************************************************************************************/void anim_user::RefetchFrame(void){ anim_source_pointer->anim_pointer->cur_Frame = current_frame_number; next_frame_ccb = GetAnimCel(anim_source_pointer->anim_pointer, anim_frame_rate); current_frame_ccb->ccb_SourcePtr = next_frame_ccb->ccb_SourcePtr; current_frame_ccb->ccb_PLUTPtr = next_frame_ccb->ccb_PLUTPtr;}/**************************** anim_user::DisplayFrame ********************************* This function draws the current frame of the animation into the screen bufferindicated by the external global variable g_screen.*****************************************************************************************/void anim_user::DisplayFrame(void){ DrawScreenCels(g_screen.sc_Screens[g_screen.sc_curScreen],current_frame_ccb);}/****************************** anim_user::Restart ************************************ This function resets the values in an anim_user object so that it will replay the animation from the beginning.*****************************************************************************************/void anim_user::Restart(void){ anim_source_pointer->anim_pointer->cur_Frame = 0; next_frame_ccb = GetAnimCel(anim_source_pointer->anim_pointer, 0); current_frame_number = anim_source_pointer->anim_pointer->cur_Frame; current_frame_ccb->ccb_SourcePtr = next_frame_ccb->ccb_SourcePtr; current_frame_ccb->ccb_PLUTPtr = next_frame_ccb->ccb_PLUTPtr; dormant = TRUE;}/**************************** anim_user::AnimComplete ********************************* This is a simple boolean function which can be used to determine if an anim_userobject has reached the final frame of an animation. You would think this statement would be all that this function needs: return ((current_frame_number>>16)+1 == anim_source_pointer->anim_pointer->num_Frames);... however, this doesn't work. current_frame_number, in actuallity, stores the NEXTframe number to be shown. This means that the statement above causes this function toreturn a frame early, i.e. on the next to last frame instead of the last frame. Of course, we also cannot simply return when the current frame equals zero, becausethis will cause this routine to return immediately, before the anim ever starts playing,since on initialization, the current frame is set to 0. Thus, we need a way of preventingtwo types of early returns: immediate, and on the next to last frame. We use a specialvariable just for this stupid situation, because I can't figure out a better way. Thedormant variable is set to TRUE on initialization and it keeps us from bailing out ofthis routine before the animation ever gets started. After this, we can return TRUEwhen the anim wraps around and gets to frame 0.*****************************************************************************************/bool anim_user::AnimComplete(void){ if (dormant == TRUE) { dormant = FALSE; return(FALSE); } return (current_frame_number == 0);}/******************************* anim_user::AnimCued *********************************** This is a simple boolean function which can be used to determine if an anim_userobject has wrapped around and is set back at the beginning of the sequence. This routine terminates when the frame number equals 1. This is because "current frame"isn't really an accurate description. It's really the next frame to be shown, which meansthat if the current frame value is 1, the frame currently being shown is frame 0.*****************************************************************************************/bool anim_user::AnimCued(void){ return ((current_frame_number >> 16) == 1);}/**************************** anim_user::AnimOnGivenFrame ****************************** This function exists to cue anims up to a frame other than the first or last frame,which is occassionally required. Like AnimComplete and AnimCued, it returns TRUE whenthe specified frame number is reached.*****************************************************************************************/bool anim_user::AnimOnGivenFrame(int32 frame){ return ((current_frame_number >> 16) == frame);}/***************************** anim_user::MoveAnim ************************************ This function shifts the anim_user object a given distance in either or both directions as specified by the values of x_change and y_change. These parameters can have either positive or negative values depending on which direction you wish to move the anim.*****************************************************************************************/void anim_user::MoveAnim(int32 x_change, int32 y_change){ current_frame_ccb->ccb_XPos += x_change; current_frame_ccb->ccb_YPos += y_change;}/************************** anim_user::ShutdownForRestart ***************************** When an anim_user object is no longer needed, this function should be called to surrender the memory that was allocated for use by the anim_object in InitializeAnim.*****************************************************************************************/void anim_user::ShutdownForRestart (void){ if (current_frame_ccb != (CCB *) NULL) delete (current_frame_ccb);}/************************************** EOF *********************************************/