Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
SpriteMgr.c
/* |
© Copyright 1991 Ricardo Batista, All Rights Reserved. |
Sprite Manager |
04/20/91 |
HISTORY: (Most Recent first) |
04/20/91 rb New today |
*/ |
#include <Types.h> |
#include <QuickDraw.h> |
#include <QDOffscreen.h> |
#include <Memory.h> |
#include <Resources.h> |
#include <OSUtils.h> |
#include <Retrace.h> |
#include <Windows.h> |
#include <ToolUtils.h> |
#include "SpriteMgr.h" |
#define desiredPixSize 8 |
SpriteMgrRecPtr Sprite_Mgr_Globals; // global used to save our information |
pascal short SetDepth(GDHandle gd, short newDepth, short whichFlags, short newFlags) = |
{0x203C, 0x000A, 0x0013, 0xAAA2}; |
pascal short HasDepth(GDHandle gd, short newDepth, short whichFlags, short newFlags) = |
{0x203C, 0x000A, 0x0014, 0xAAA2}; |
/* |
This routine initializes the sprite manager, it must be called after dialogs, |
windows, resources, and quickdraw have been initialized. This routine creates |
a record to memory to keep the sprite manager globals, it also finds the best |
monitor in which to display the color animation and sets the monitor to 4 bit |
color after saving the previous color depth. This routine also installs a small |
vbl task used by the drawing routines. |
if cTable is not nil the given color table is made the current color table and the |
previous color table saved for later restoration. |
returns 0 if no error occured. 1 if no color monitor present or not enough memory |
to create memory record. |
*/ |
short InitSpriteMgr(CTabHandle cTable) |
{ |
short err; |
GDHandle device; |
PixMapHandle pixH; |
Boolean done = false; |
short oldPixelSize; |
CTabHandle colorTable = 0L; |
short mode; |
if (Sprite_Mgr_Globals) |
return(0); |
Sprite_Mgr_Globals = (SpriteMgrRecPtr) NewPtrClear(sizeof(SpriteMgrRec)); |
if (!Sprite_Mgr_Globals) |
return(1); |
device = GetDeviceList(); |
if (!device) { |
DisposPtr((Ptr) Sprite_Mgr_Globals); |
Sprite_Mgr_Globals = 0L; |
return(1); |
} |
while (device && !done) { |
pixH = (**device).gdPMap; |
oldPixelSize = (**pixH).pixelSize; |
if (oldPixelSize == desiredPixSize) { |
if (cTable) { |
colorTable = (**pixH).pmTable; |
(**pixH).pmTable = cTable; |
GDeviceChanged(device); |
} |
done = true; |
} |
else { |
mode = HasDepth(device, desiredPixSize, 1, 1); /* color device */ |
if (mode) { |
err = SetDepth(device, desiredPixSize, 1, 1); |
if (cTable) { |
colorTable = (**pixH).pmTable; |
(**pixH).pmTable = cTable; |
GDeviceChanged(device); |
} |
done = true; |
} |
} |
if (!done) |
device = (GDHandle) (**device).gdNextGD; |
} |
if (!done) |
return(1); |
Sprite_Mgr_Globals->originalCTable = colorTable; |
Sprite_Mgr_Globals->currCTable = cTable; |
Sprite_Mgr_Globals->originalDepth = oldPixelSize; |
Sprite_Mgr_Globals->task.qType = vType; |
Sprite_Mgr_Globals->task.vblAddr = (ProcPtr) VTASK; |
Sprite_Mgr_Globals->task.vblCount = 1; |
Sprite_Mgr_Globals->task.vblPhase = 0; |
Sprite_Mgr_Globals->deviceUsed = device; |
Sprite_Mgr_Globals->active = false; |
Sprite_Mgr_Globals->changed = true; |
Sprite_Mgr_Globals->updateRects = 0; |
err = VInstall((QElemPtr) &Sprite_Mgr_Globals->task.qLink); |
return(err); |
} |
/* |
This routine disposes of the window used by animation, destroys all of the graphic |
worlds created and deinstalls the vbl task. It also re-enables any applications |
hidden by ActivateAnimation. |
Restores the color table if it had been changed when InitSpriteMgr was called. |
This routine should be called when the application quits. |
*/ |
void CloseSpriteMgr(void) |
{ |
CTabHandle cTable; |
GDHandle device; |
short err; |
VRemove((QElemPtr) &Sprite_Mgr_Globals->task.qLink); |
device = Sprite_Mgr_Globals->deviceUsed; |
if (Sprite_Mgr_Globals->originalCTable) { |
cTable = (**(**device).gdPMap).pmTable; |
(**(**device).gdPMap).pmTable = Sprite_Mgr_Globals->originalCTable; |
GDeviceChanged(device); |
DisposHandle((Handle) cTable); |
} |
err = SetDepth(device, Sprite_Mgr_Globals->originalDepth, 1, 1); |
while (Sprite_Mgr_Globals->backSprites) |
KillSprite(Sprite_Mgr_Globals->backSprites->id); |
while (Sprite_Mgr_Globals->normSprites) |
KillSprite(Sprite_Mgr_Globals->normSprites->id); |
while (Sprite_Mgr_Globals->foreSprites) |
KillSprite(Sprite_Mgr_Globals->foreSprites->id); |
while (Sprite_Mgr_Globals->backgrounds) |
KillBackground(Sprite_Mgr_Globals->backgrounds->id); |
while (Sprite_Mgr_Globals->foregrounds) |
KillForeground(Sprite_Mgr_Globals->foregrounds->id); |
if (Sprite_Mgr_Globals->animationWindow) |
DisposeWindow((WindowPtr) Sprite_Mgr_Globals->animationWindow); |
if (Sprite_Mgr_Globals->animationGWorld) |
DisposeGWorld(Sprite_Mgr_Globals->animationGWorld); |
if (Sprite_Mgr_Globals->currCTable) |
DisposHandle((Handle) Sprite_Mgr_Globals->currCTable); |
DisposPtr((Ptr) Sprite_Mgr_Globals); |
Sprite_Mgr_Globals = 0L; |
} |
/* |
This routine creates a new background by creating a new graphics world and drawing |
in it the picture with id pictID. drawOrder is the background drawing priority |
with 1 being the highest priority. The highest priority gets drawn first. copyMode |
should be srcCopy for the highest priority element and transparent for the rest. |
animationRect is the area within the animation screen where the background will be |
drawn. The size of the picture must be at least as big as the animationRect and can |
be bigger if the area is to be scrolled later in the animation. If the given pictID |
is already in use by another graphic entity then graphics world will be shared instead |
of creating a new graphics world. |
id is returned if no errors occur. Otherwise 0 if there was not enough memory for the |
offscreen world or the picture could not be loaded. |
*/ |
short NewBackground(short pictID, short drawOrder, short copyMode, Rect *animationRect, short id) |
{ |
return (NewScenery(pictID, drawOrder, copyMode, animationRect, id, true)); |
} |
/* |
This routine creates a new foreground by creating a new graphics world and drawing |
in it the picture with id pictID. drawOrder is the foreground drawing priority |
with 1 being the highest priority. The highest priority gets drawn first. copyMode |
should be transparent in most cases. |
animationRect is the area within the animation screen where the foreground will be |
drawn. The size of the picture must be at least as big as the animationRect and can |
be bigger if the area is to be scrolled later in the animation. If the given pictID |
is already in use by another graphic entity then graphics world will be shared instead |
of creating a new graphics world. |
id is returned if no errors occur. Otherwise 0 if there was not enough memory for the |
offscreen world or the picture could not be loaded. |
*/ |
short NewForeground(short pictID, short drawOrder, short copyMode, Rect *animationRect, short id) |
{ |
return (NewScenery(pictID, drawOrder, copyMode, animationRect, id, true)); |
} |
/* |
This routine changes the offsets where the image is to be drawn in the animation |
world and marks the background as changed so that is it redrawn again. |
*/ |
void ScrollBackground(short id, short vOffset, short hOffset) |
{ |
SceneryInfoRecPtr sc; |
sc = Sprite_Mgr_Globals->backgrounds; |
while (sc) { |
if (sc->id == id) { |
sc->scrollOffset.v += vOffset; |
sc->scrollOffset.h += hOffset; |
sc->changed = true; |
return; |
} |
sc = (SceneryInfoRecPtr) sc->nextScenery; |
} |
} |
/* |
This routine changes the offsets where the image is to be drawn in the animation |
world and marks the foreground as changed so that is it redrawn again. |
*/ |
void ScrollForeground(short id, short vOffset, short hOffset) |
{ |
SceneryInfoRecPtr sc; |
sc = Sprite_Mgr_Globals->foregrounds; |
while (sc) { |
if (sc->id == id) { |
sc->scrollOffset.v += vOffset; |
sc->scrollOffset.h += hOffset; |
sc->changed = true; |
return; |
} |
sc = (SceneryInfoRecPtr) sc->nextScenery; |
} |
} |
/* |
This routine sets an auto scroll timer and amount for a background to |
be scrolled automatically. Autoscrolling has some limitations at the |
time. |
*/ |
void AutoScrollBackground(short id, short vOffset, short hOffset, long scrollTicks) |
{ |
SceneryInfoRecPtr sc; |
sc = Sprite_Mgr_Globals->backgrounds; |
while (sc) { |
if (sc->id == id) { |
sc->nextTickCount = TickCount() + scrollTicks; |
sc->scrollTicks = scrollTicks; |
sc->autoScrollAmount.v = vOffset; |
sc->autoScrollAmount.h = hOffset; |
return; |
} |
sc = (SceneryInfoRecPtr) sc->nextScenery; |
} |
} |
/* |
This routine sets an auto scroll timer and amount for a foreground to |
be scrolled automatically. Autoscrolling has some limitations at the |
time. |
*/ |
void AutoScrollForeground(short id, short vOffset, short hOffset, long scrollTicks) |
{ |
SceneryInfoRecPtr sc; |
sc = Sprite_Mgr_Globals->foregrounds; |
while (sc) { |
if (sc->id == id) { |
sc->nextTickCount = TickCount() + scrollTicks; |
sc->scrollTicks = scrollTicks; |
sc->autoScrollAmount.v = vOffset; |
sc->autoScrollAmount.h = hOffset; |
return; |
} |
sc = (SceneryInfoRecPtr) sc->nextScenery; |
} |
} |
/* |
This routine disposes of the graphics world used by the graphic entity with |
id number id if the graphics world is not being shared by other graphic entities. |
It also deletes any information about this entity from the Sprite Manager |
animation record. |
*/ |
void KillBackground(short id) |
{ |
SceneryInfoRecPtr sc, sc2; |
sc = Sprite_Mgr_Globals->backgrounds; |
if (sc && (sc->id == id)) { |
Sprite_Mgr_Globals->backgrounds = (SceneryInfoRecPtr) |
sc->nextScenery; |
if (sc->shared) { |
sc2 = FindTwinScenery(sc->pictID); |
if (sc2) |
sc->sceneryWorld = 0L; |
} |
if (sc->sceneryWorld) |
DisposeGWorld(sc->sceneryWorld); |
DisposPtr((Ptr) sc); |
return; |
} |
sc2 = sc; |
sc = (SceneryInfoRecPtr) sc2->nextScenery; |
while (sc) { |
if (sc->id == id) { |
sc2->nextScenery = sc->nextScenery; |
if (sc->shared) { |
sc2 = FindTwinScenery(sc->pictID); |
if (sc2) |
sc->sceneryWorld = 0L; |
} |
if (sc->sceneryWorld) |
DisposeGWorld(sc->sceneryWorld); |
DisposPtr((Ptr) sc); |
return; |
} |
sc2 = sc; |
if (sc) |
sc = (SceneryInfoRecPtr) sc->nextScenery; |
} |
} |
/* |
This routine disposes of the graphics world used by the graphic entity with |
id number id if the graphics world is not being shared by other graphic entities. |
It also deletes any information about this entity from the Sprite Manager |
animation record. |
*/ |
void KillForeground(short id) |
{ |
SceneryInfoRecPtr sc, sc2; |
sc = Sprite_Mgr_Globals->foregrounds; |
if (sc && (sc->id == id)) { |
Sprite_Mgr_Globals->foregrounds = (SceneryInfoRecPtr) |
sc->nextScenery; |
if (sc->shared) { |
sc2 = FindTwinScenery(sc->pictID); |
if (sc2) |
sc->sceneryWorld = 0L; |
} |
if (sc->sceneryWorld) |
DisposeGWorld(sc->sceneryWorld); |
DisposPtr((Ptr) sc); |
return; |
} |
sc2 = sc; |
sc = (SceneryInfoRecPtr) sc2->nextScenery; |
while (sc) { |
if (sc->id == id) { |
sc2->nextScenery = sc->nextScenery; |
if (sc->shared) { |
sc2 = FindTwinScenery(sc->pictID); |
if (sc2) |
sc->sceneryWorld = 0L; |
} |
if (sc->sceneryWorld) |
DisposeGWorld(sc->sceneryWorld); |
DisposPtr((Ptr) sc); |
return; |
} |
sc2 = sc; |
if (sc) |
sc = (SceneryInfoRecPtr) sc->nextScenery; |
} |
} |
/* |
This routine creates a graphics world for the new sprite. If the same pictID is |
shared by another sprite then the graphics world will be shared between all the |
sprites that share the same picture. Otherwise the picture range from pictID to |
pictID + totalPicts will be drawn in the new graphics world. copyMode should be |
transparent in most cases but could be blend in some cases. spriteProc is a |
procedure pointer that if given can be called every ProcTicks ticks |
(sixthieths of a second). If ProcTicks is not zero and spriteProc is nil then |
the Sprite Manager will automatically change the current face of the sprite |
every ProcTicks ticks to the next face. drawOrder is the priority in which the |
sprite will be drawn with 1 being the highest priority. collisionProc is a procedure |
pointer that will be called when a collision with another sprite is detected only if |
the parameter canColide is set to true and the collision occurs with another sprite. |
id is the id number that will be used to identify this sprite. |
Parameters to the collisionProc are the id of the sprite that collided with this |
sprite. |
pascal void CollisionProc(short spriteID); |
Parameters to the sprite procedure are the id of the sprite and the rectangle which |
encloses the sprite in the animation world. |
pascal void SpriteProc(short spriteID, Rect *locationRect); |
*/ |
short NewBackgroundSprite(short pictID, short totalPicts, short copyMode, |
ProcPtr spriteProc, long ProcTicks, short drawOrder, |
ProcPtr collisionProc, Boolean canColide, short id) |
{ |
return (SMgrNewSprite(pictID, totalPicts, copyMode, spriteProc, ProcTicks, drawOrder, |
collisionProc, canColide, id, 1)); |
} |
/* |
This routine creates a graphics world for the new sprite. If the same pictID is |
shared by another sprite then the graphics world will be shared between all the |
sprites that share the same picture. Otherwise the picture range from pictID to |
pictID + totalPicts will be drawn in the new graphics world. copyMode should be |
transparent in most cases but could be blend in some cases. spriteProc is a |
procedure pointer that if given can be called every ProcTicks ticks |
(sixthieths of a second). If ProcTicks is not zero and spriteProc is nil then |
the Sprite Manager will automatically change the current face of the sprite |
every ProcTicks ticks to the next face. drawOrder is the priority in which the |
sprite will be drawn with 1 being the highest priority. collisionProc is a procedure |
pointer that will be called when a collision with another sprite is detected only if |
the parameter canColide is set to true and the collision occurs with another sprite. |
id is the id number that will be used to identify this sprite. |
Parameters to the collisionProc are the id of the sprite that collided with this |
sprite. |
pascal void CollisionProc(short spriteID); |
Parameters to the sprite procedure are the id of the sprite and the rectangle which |
encloses the sprite in the animation world. |
pascal void SpriteProc(short spriteID, Rect *locationRect); |
*/ |
short NewSprite(short pictID, short totalPicts, short copyMode, |
ProcPtr spriteProc, long ProcTicks, short drawOrder, |
ProcPtr collisionProc, Boolean canColide, short id) |
{ |
return (SMgrNewSprite(pictID, totalPicts, copyMode, spriteProc, ProcTicks, drawOrder, |
collisionProc, canColide, id, 2)); |
} |
/* |
This routine creates a graphics world for the new sprite. If the same pictID is |
shared by another sprite then the graphics world will be shared between all the |
sprites that share the same picture. Otherwise the picture range from pictID to |
pictID + totalPicts will be drawn in the new graphics world. copyMode should be |
transparent in most cases but could be blend in some cases. spriteProc is a |
procedure pointer that if given can be called every ProcTicks ticks |
(sixthieths of a second). If ProcTicks is not zero and spriteProc is nil then |
the Sprite Manager will automatically change the current face of the sprite |
every ProcTicks ticks to the next face. drawOrder is the priority in which the |
sprite will be drawn with 1 being the highest priority. collisionProc is a procedure |
pointer that will be called when a collision with another sprite is detected only if |
the parameter canColide is set to true and the collision occurs with another sprite. |
id is the id number that will be used to identify this sprite. |
Parameters to the collisionProc are the id of the sprite that collided with this |
sprite. |
pascal void CollisionProc(short spriteID); |
Parameters to the sprite procedure are the id of the sprite and the rectangle which |
encloses the sprite in the animation world. |
pascal void SpriteProc(short spriteID, Rect *locationRect); |
*/ |
short NewForegroundSprite(short pictID, short totalPicts, short copyMode, |
ProcPtr spriteProc, long ProcTicks, short drawOrder, |
ProcPtr collisionProc, Boolean canColide, short id) |
{ |
return (SMgrNewSprite(pictID, totalPicts, copyMode, spriteProc, ProcTicks, drawOrder, |
collisionProc, canColide, id, 3)); |
} |
/* |
This procedure creates a new animation world and creates a graphics world |
for it. animationRect is the rectangle which will be used for the animation |
in a window to be created by this procedure. The window will be created in the |
graphics device which supports 4 bit color. windowH is the width of the window |
to be created and windowV is the height of the window. wTitle is the title that |
will be given to the window. The window created will be centered in the graphics |
device. A color window pointer is returned to the caller so that the application |
can use the areas outside the animationRect for purposes other than animation such |
as scores. |
*/ |
CWindowPtr NewAnimation(Rect *animationRect, short windowH, short windowV, Str255 wTitle) |
{ |
Rect box; |
short err; |
GWorldPtr world = 0L; |
CTabHandle cTable; |
short offsetV, offsetH; |
CGrafPtr savedGWorld; |
GDHandle savedGD; |
GetGWorld(&savedGWorld, &savedGD); |
box = (**(Sprite_Mgr_Globals->deviceUsed)).gdRect; |
offsetV = box.bottom - box.top - windowV; |
offsetH = box.right - box.left - windowH; |
if (offsetV > 0) |
offsetV /= 2; |
else |
offsetV = 0; |
if (offsetH > 0) |
offsetH /= 2; |
else |
offsetH = 0; |
box.right = box.left + windowH + offsetH; |
box.bottom = box.top + windowV + offsetV; |
box.top += offsetV; |
box.left += offsetH; |
Sprite_Mgr_Globals->animationWindow = (CWindowPtr) NewCWindow(0L, &box, wTitle, |
true, documentProc, (WindowPtr) -1L, false, 'Anim'); |
Sprite_Mgr_Globals->animationRect = *animationRect; |
cTable = Sprite_Mgr_Globals->currCTable; |
err = NewGWorld(&world, desiredPixSize, animationRect, cTable, 0L, (long) useTempMem); |
if (!err) { |
SetGWorld(world, 0L); |
EraseRect(animationRect); |
} |
Sprite_Mgr_Globals->animationGWorld = world; |
if (!world) { |
DisposeWindow((WindowPtr) Sprite_Mgr_Globals->animationWindow); |
Sprite_Mgr_Globals->animationWindow = 0L; |
} |
SetGWorld(savedGWorld, savedGD); |
return(Sprite_Mgr_Globals->animationWindow); |
} |
/* |
This procedure set the current face of the sprite with id number id to the |
given index. The changed flag is set to true so that drawing is performed in |
the next chance by the Sprite Manager. |
*/ |
void SetCurrentSpriteIndex(short id, short index) |
{ |
SpriteInfoRecPtr p; |
p = FindSprite(id); |
if (p) { |
p->changed = true; |
p->currentFace = index; |
} |
} |
/* |
This procedure puts the sprite in the animation world at the location given |
by top and left. The changed flag is set to true so that drawing is performed |
as soon as possible. A sprite should only be "put" in the animation world |
once unless it is first "removed" by calling RemoveSprite. |
*/ |
void PutSprite(short id, short top, short left) |
{ |
SpriteInfoRecPtr p; |
p = FindSprite(id); |
if (p) { |
p->changed = true; |
p->animationRect = p->spriteRect; |
p->animationRect.top += top; |
p->animationRect.bottom += top; |
p->animationRect.left += left; |
p->animationRect.right += left; |
} |
} |
/* |
This procedure removes a sprite from the animation world by setting its |
animation rectangle to an empty rectangle and setting the sprite's changed |
flag so that the animation world is updated correctly. |
*/ |
void RemoveSprite(short id) |
{ |
SpriteInfoRecPtr p; |
p = FindSprite(id); |
if (p) { |
p->changed = true; |
p->animationRect.top = p->animationRect.left = |
p->animationRect.bottom = p->animationRect.right = 0; |
} |
} |
/* |
This procedure moves the sprite in the animation world first remembering the |
sprite's old location for further updating. The sprite's location is offset by |
h and v. A new face for the sprite can be given by newIndex if newIndex is not |
zero. Once a sprite is "put" in the animation world it should |
*/ |
void MoveSprite(short id, short h, short v, short newIndex) |
{ |
SpriteInfoRecPtr p; |
p = FindSprite(id); |
if (p) { |
p->changed = true; |
p->oldAnimationRect = p->animationRect; |
p->animationRect.top += v; |
p->animationRect.left += h; |
p->animationRect.bottom += v; |
p->animationRect.right += h; |
if (newIndex) |
p->currentFace = newIndex; |
} |
} |
/* |
This procedure moves a sprite with the given id to the location specified by h |
and v. A new face for thr sprite may be given by specifying a newIndex other |
than zero. The old location of the sprite is recorded for further updating. |
*/ |
void MoveSpriteTo(short id, short h, short v, short newIndex) |
{ |
SpriteInfoRecPtr p; |
p = FindSprite(id); |
if (p) { |
p->changed = true; |
p->oldAnimationRect = p->animationRect; |
p->animationRect = p->spriteRect; |
p->animationRect.top += v; |
p->animationRect.left += h; |
p->animationRect.bottom += v; |
p->animationRect.right += h; |
if (newIndex) |
p->currentFace = newIndex; |
} |
} |
/* |
This procedure makes visible or invisible a sprite based on the show parameter. |
A "hiden" sprite is not drawn in the animation world but can still create |
collisions if its collision attribute is enabled. If the new visibility state |
of the sprite is changed the "changed" attribute gets set to true so that the |
animation world is updated correctly. |
*/ |
void ShowSprite(short id, Boolean show) |
{ |
SpriteInfoRecPtr p; |
p = FindSprite(id); |
if (p) { |
if (show != p->hidden) { |
p->changed = true; |
p->oldAnimationRect = p->animationRect; |
p->hidden = show; |
} |
} |
} |
/* |
This procedure returns the current location of the given sprite in the animation |
world or an empty rectangle if the sprite is not currently in the animation world. |
More detailed information can be obtained by calling GetSpriteInfo. |
*/ |
void GetSpriteLocation(short id, Rect *location) |
{ |
SpriteInfoRecPtr p; |
p = FindSprite(id); |
if (p) { |
*location = p->animationRect; |
} |
else { |
SetRect(location, 0, 0, 0, 0); |
} |
} |
/* |
This procedure enables or disables collisions for a sprite based on the enable value. |
Sprites with collisions enabled can only collide with other sprites which |
have the collision attribute set to true. |
*/ |
void EnableSpriteCollisions(short id, Boolean enable) |
{ |
SpriteInfoRecPtr p; |
p = FindSprite(id); |
if (p) { |
p->canCollide = enable; |
} |
} |
/* |
This is a special purpose call which "validates" the old rectangle which ussed to |
be occupied by a sprite. Its purpose is to prevent redundant drawing from occuring |
when an specific sprite and face moves into the position previously occupied by |
an identical sprite and face. |
*/ |
void ValidateOldSpriteLocation(short id) |
{ |
SpriteInfoRecPtr p; |
p = FindSprite(id); |
if (p) { |
p->oldAnimationRect.top = p->oldAnimationRect.left = p->oldAnimationRect.bottom = |
p->oldAnimationRect.right = 0; |
} |
} |
/* |
This call allows the programmer to specify a collision area for a sprite other than |
the sprite's own dimensions. The collision rectangle is given in the sprite's |
local coordinate system. By using this call collisions can be limited to a certain |
portion of th sprite's area. |
*/ |
void SetSpriteCollisionRect(short id, Rect *colRect) |
{ |
SpriteInfoRecPtr p; |
p = FindSprite(id); |
if (p) { |
p->collisionRect = *colRect; |
} |
} |
/* |
This function returns a pointer to a sprite information record. The pointer returned |
is valid for the life of the sprite. That is until is the sprite is "killed" with |
a call to "KillSprite". The data structure returned by this call should be used mostly |
for read-only purposes. Altering values in the data structure could result in |
animation errors. |
*/ |
SpriteInfoRecPtr GetSpriteInfo(short id) |
{ |
SpriteInfoRecPtr p; |
p = FindSprite(id); |
if (p) |
return(p); |
return(0L); |
} |
/* |
This procedure destroys the graphics world used by the sprite with the given id |
if such sprite is not currently sharing a graphics world with another sprite. |
If the sprite is currently in the animaton screen its area is recorded so it |
can be updated as soon as possible by the Sprite Manager. |
*/ |
void KillSprite(short id) |
{ |
SpriteInfoRecPtr p, p2, twin1, twin2; |
register short counter; |
for (counter = 0; counter < 3; counter++) { |
if (counter == 0) |
p = Sprite_Mgr_Globals->normSprites; |
if (counter == 1) |
p = Sprite_Mgr_Globals->backSprites; |
if (counter == 2) |
p = Sprite_Mgr_Globals->foreSprites; |
if (p) { |
if (p->id == id) { |
if (counter == 0) |
Sprite_Mgr_Globals->normSprites = (SpriteInfoRecPtr) p->nextSprite; |
if (counter == 1) |
Sprite_Mgr_Globals->backSprites = (SpriteInfoRecPtr) p->nextSprite; |
if (counter == 2) |
Sprite_Mgr_Globals->foreSprites = (SpriteInfoRecPtr) p->nextSprite; |
if (p->sharedWorld) { |
p->sharedWorld = false; // mark as unshared so FindTwin wont give us ourselves |
twin1 = FindTwinSprite(p->pictID); // find a twin |
if (!twin1) |
DisposeGWorld(p->spriteWorld); // no twins ! weird.. |
else { |
twin1->sharedWorld = false; // disable this one temporarily |
twin2 = FindTwinSprite(p->pictID); // are there any more ? |
if (twin2) |
twin1->sharedWorld = true; // restore shared status since there are more sharing |
} |
} |
else { |
DisposeGWorld(p->spriteWorld); |
} |
DisposPtr((Ptr) p); |
return; |
} |
p2 = p; |
p = (SpriteInfoRecPtr) p->nextSprite; |
while (p) { |
if (p->id == id) { |
if (p->sharedWorld) { |
p->sharedWorld = false; // mark as unshared so FindTwin wont give us ourselves |
twin1 = FindTwinSprite(p->pictID); // find a twin |
if (!twin1) |
DisposeGWorld(p->spriteWorld); // no twins ! weird.. |
else { |
twin1->sharedWorld = false; // disable this one temporarily |
twin2 = FindTwinSprite(p->pictID); // are there any more ? |
if (twin2) |
twin1->sharedWorld = true; // restore shared status since there are more sharing |
} |
} |
else { |
DisposeGWorld(p->spriteWorld); |
} |
p2->nextSprite = p->nextSprite; |
DisposPtr((Ptr) p); |
return; |
} |
p2 = p; |
p = (SpriteInfoRecPtr) p->nextSprite; |
} |
} |
} |
} |
/* |
This routine activates the animation world so that animation will occur the next |
time DoAnimation is called. The deafult state after calling NewAnimation is to have |
the animation world inactive. All applications other than the current one are hidden |
so that the processing time is dedicated to the animation application. |
*/ |
void ActivateAnimation(void) |
{ |
Sprite_Mgr_Globals->active = true; |
} |
/* |
This routine prevents any animation from ocurring by deactivating the animation |
world. This is the deafult state after calling NewAnimation. This procedure should |
be called when the animation is to be suspended. It also enabled all other applications |
so that the user can swith applications. |
*/ |
void DeactivateAnimation(void) |
{ |
Sprite_Mgr_Globals->active = true; |
} |
/* |
This is the main driver for the animation. If the parameter update is set to |
true then the animation world is simply redrawn. Call DoAnimation with update |
set to true when you receive an update event. When an update event occurs the |
application must bracket this call with BeginUpdate and EndUpdate and any |
application specific drawing ouside the animation area must be redrawn as well. |
When update is set to false this procedure animates the animation world by doing |
several things. |
1) Go trough the backgrounds updating the animation area as nessesary. |
2) Detect sprite collisions and calling collision procedures if nessesary. |
3) Check the tick counters and calling the tickle procedures if any. |
4) Updating automatic tickling sprites. |
5) Drawing any sprites that have changed their face. |
6) Updating foregounds. |
7) Updating foreground sprites that have changed. |
*/ |
void DoAnimation(Boolean update) |
{ |
GrafPtr g1, g2; |
Rect sRect; |
register short counter, total; |
register Rect *boxPtr; |
KeyMap keys; |
if (update) { |
g1 = (GrafPtr) Sprite_Mgr_Globals->animationGWorld; |
g2 = (GrafPtr) Sprite_Mgr_Globals->animationWindow; |
sRect = Sprite_Mgr_Globals->animationRect; |
Sprite_Mgr_Globals->task.inVBL = 0; |
while (Sprite_Mgr_Globals->task.inVBL == 0) |
; |
CopyBits(&(g1->portBits), &(g2->portBits), &sRect, &sRect, srcCopy, 0L); |
return; |
} |
if (Sprite_Mgr_Globals->active == false) |
return; |
Sprite_Mgr_Globals->changed = false; |
// next: update only changed rectangles on sceneries |
// Detect collisions |
do { |
Sprite_Mgr_Globals->redoCheck = false; |
CheckChangedScenery(Sprite_Mgr_Globals->backgrounds); // backgrounds |
CheckChangedSprite(Sprite_Mgr_Globals->backSprites); // back sprites |
CheckChangedSprite(Sprite_Mgr_Globals->normSprites); // sprites |
CheckChangedScenery(Sprite_Mgr_Globals->foregrounds); // foregrounds |
CheckChangedSprite(Sprite_Mgr_Globals->foreSprites); // fore sprites |
} while (Sprite_Mgr_Globals->redoCheck); |
Sprite_Mgr_Globals->updateRects = 0; // nothing to update |
UpdateScenery(Sprite_Mgr_Globals->backgrounds); // changed backgrounds |
UpdateSprite(Sprite_Mgr_Globals->backSprites); |
UpdateSprite(Sprite_Mgr_Globals->normSprites); // changed sprites |
UpdateScenery(Sprite_Mgr_Globals->foregrounds); // changed foregrounds |
UpdateSprite(Sprite_Mgr_Globals->foreSprites); |
if (Sprite_Mgr_Globals->changed == false) |
return; |
g1 = (GrafPtr) Sprite_Mgr_Globals->animationGWorld; |
g2 = (GrafPtr) Sprite_Mgr_Globals->animationWindow; |
GetKeys(&keys[0]); |
if ((keys[1] & 0x4) == 0) |
Sprite_Mgr_Globals->updateRects = kMaxUR; |
if (Sprite_Mgr_Globals->updateRects == kMaxUR) { // update full screen |
sRect = Sprite_Mgr_Globals->animationRect; |
Sprite_Mgr_Globals->task.inVBL = 0; |
while (Sprite_Mgr_Globals->task.inVBL == 0) |
; |
CopyBits(&(g1->portBits), &(g2->portBits), &sRect, &sRect, srcCopy, 0L); |
} |
else { |
total = Sprite_Mgr_Globals->updateRects; |
boxPtr = &(Sprite_Mgr_Globals->changedRect[0]); |
for (counter = 0; counter < total; counter++) { |
Sprite_Mgr_Globals->task.inVBL = 0; |
while (Sprite_Mgr_Globals->task.inVBL == 0) |
; |
CopyBits(&(g1->portBits), &(g2->portBits), boxPtr, boxPtr, srcCopy, 0L); |
boxPtr++; |
} |
Sprite_Mgr_Globals->updateRects = 0; |
} |
} |
/* |
This procedure changes the current animation pallete used in the animation world |
to the new color table. |
*/ |
void SetNewAnimationPallete(CTabHandle cTable) |
{ |
GDHandle dev; |
dev = Sprite_Mgr_Globals->deviceUsed; |
cTable = (**(**dev).gdPMap).pmTable; |
(**(**dev).gdPMap).pmTable = cTable; |
DisposHandle((Handle) cTable); |
GDeviceChanged(dev); |
} |
/************************************************************************************ |
P R I V A T E R O U T I N E S |
*************************************************************************************/ |
/* |
This is the common routine to create sceneries, we use this routine because we want |
to make things more readable for the programmer by providing "specialized" routines |
that allow them to distinguish between foregrounds and backgrounds. |
The basic process is to create the scenery data structure, fill in the default values, |
create the graphics world, load the picture and copy it into the g world, then |
the scenery data structure is inserted in the right place. |
I suppose that later on we could insert them in the linked list in their priority |
order. |
*/ |
short NewScenery(short pictID, short drawOrder, short copyMode, Rect *animationRect, |
short id, Boolean back) |
{ |
SceneryInfoRecPtr sc, sc2, sc3; |
short err; |
PicHandle picH; |
Rect box; |
GWorldPtr world; |
CGrafPtr CsavePort; |
GDHandle gd; |
PixMapHandle pixH; |
sc = (SceneryInfoRecPtr) NewPtrClear(sizeof(SceneryInfoRec)); |
if (!sc) |
return(0); |
sc->id = id; |
sc->pictID = pictID; |
sc->drawOrder = drawOrder; |
sc->copyMode = copyMode; |
sc->animationRect = *animationRect; |
sc->hidden = false; |
sc->changed = true; |
sc->shared = false; |
sc2 = FindTwinScenery(pictID); |
if (sc2) { |
sc->shared = true; |
sc2->shared = true; |
sc->sceneryWorld = sc2->sceneryWorld; |
sc->sceneryRect = sc2->sceneryRect; |
} |
else { |
picH = GetPicture(pictID); |
if (!picH) { |
DisposPtr((Ptr) sc); |
return(0); |
} |
LoadResource((Handle) picH); |
HLock((Handle) picH); |
box = (**picH).picFrame; |
box.right = box.right - box.left; |
box.bottom = box.bottom - box.top; |
box.top = box.left = 0; |
sc->sceneryRect = box; |
GetGWorld(&CsavePort, &gd); |
err = NewGWorld( &world, desiredPixSize, &box, 0L, 0L, 0L); // (long) useTempMem); |
if (err || (world->portPixMap == 0L)) { |
ReleaseResource((Handle) picH); |
DisposPtr((Ptr) sc); |
return(0); |
} |
pixH = world->portPixMap; |
HLock((Handle) pixH); |
LockPixels(pixH); |
NoPurgePixels(pixH); |
SetGWorld(world, 0L); |
sc->sceneryWorld = world; |
DrawPicture(picH, &box); |
ReleaseResource((Handle) picH); |
SetGWorld(CsavePort, gd); |
} |
if (back) |
sc2 = Sprite_Mgr_Globals->backgrounds; |
else |
sc2 = Sprite_Mgr_Globals->foregrounds; |
if (sc2->id > id) { |
if (back) |
Sprite_Mgr_Globals->backgrounds = sc; |
else |
Sprite_Mgr_Globals->foregrounds = sc; |
sc->nextScenery = (Ptr) sc2; |
return(id); |
} |
else { |
if (back) |
sc3 = sc2 = Sprite_Mgr_Globals->backgrounds; |
else |
sc3 = sc2 = Sprite_Mgr_Globals->foregrounds; |
while (sc2 && (sc2->id < id)) { |
sc3 = sc2; |
sc2 = (SceneryInfoRecPtr) sc2->nextScenery; |
} |
if (sc2) { |
sc3->nextScenery = (Ptr) sc; |
sc->nextScenery = (Ptr) sc2; |
} |
else { |
sc3->nextScenery = (Ptr) sc; |
} |
} |
return(id); |
} |
/* |
This is the common routine to create sprites, we use this routine because we want |
to make things more readable for the programmer by providing "specialized" routines |
that allow them to distinguish between foreground, normal and background sprites. |
The basic process is to create the sprite data structure, fill in the default values, |
create the graphics world, load the pictures and copy them into the g world, then |
the sprite data structure is inserted in the right place. |
I suppose that later on we could insert them in the linked list in their priority |
order. |
*/ |
short SMgrNewSprite(short pictID, short totalPicts, short copyMode, |
ProcPtr spriteProc, long ProcTicks, short drawOrder, |
ProcPtr collisionProc, Boolean canCollide, short id, short sType) |
{ |
SpriteInfoRecPtr p, p2, twin; |
short err, h, v; |
PicHandle picH; |
Rect box; |
GWorldPtr world; |
CGrafPtr CsavePort; |
GDHandle gd; |
PixMapHandle pixH; |
register short counter; |
p = (SpriteInfoRecPtr) NewPtrClear(sizeof(SpriteInfoRec)); |
if (!p) |
return(0); |
p->id = id; |
p->pictID = pictID; |
p->drawOrder = drawOrder; |
p->copyMode = copyMode; |
p->oldAnimationRect = p->animationRect; |
p->tickWait = ProcTicks; |
p->currentFace = 1; |
p->sharedWorld = false; |
p->faces = totalPicts; |
p->tickProc = spriteProc; |
p->canCollide = canCollide; |
p->collisionProc = collisionProc; |
p->hidden = false; |
p->changed = true; |
twin = FindTwinSprite(pictID); |
if (twin) { |
twin->sharedWorld = true; |
p->spriteRect = twin->spriteRect; |
p->collisionRect = twin->collisionRect; |
p->spriteWorld = twin->spriteWorld; |
p->nextSprite = 0L; |
} |
else { |
picH = GetPicture(pictID); |
if (!picH) { |
DisposPtr((Ptr) p); |
return(0); |
} |
LoadResource((Handle) picH); |
HLock((Handle) picH); |
box = (**picH).picFrame; |
h = box.right - box.left; |
v = box.bottom - box.top; |
box.right = h; // make zero offset based |
box.bottom = v; |
box.top = box.left = 0; |
p->spriteRect = box; |
p->collisionRect = box; |
box.right *= totalPicts; |
GetGWorld(&CsavePort, &gd); |
err = NewGWorld( &world, desiredPixSize, &box, 0L, 0L, 0L); // (long) useTempMem); |
if (err || (world->portPixMap == 0L)) { |
ReleaseResource((Handle) picH); |
DisposPtr((Ptr) p); |
return(0); |
} |
pixH = world->portPixMap; |
HLock((Handle) pixH); |
LockPixels(pixH); |
NoPurgePixels(pixH); |
SetGWorld(world, 0L); |
EraseRect(&world->portRect); |
p->spriteWorld = world; |
p->nextSprite = 0L; |
for (counter = 0; counter < totalPicts; counter++) { |
picH = GetPicture(pictID + counter); |
LoadResource((Handle) picH); |
HLock((Handle) picH); |
box = (**picH).picFrame; |
box.right = box.right - box.left; |
box.bottom = box.bottom - box.top; |
box.left = box.top = 0; |
box.right += h * counter; |
box.left += h * counter; |
DrawPicture(picH, &box); |
ReleaseResource((Handle) picH); |
} |
SetGWorld(CsavePort, gd); |
} |
if (sType == 1) { |
p2 = Sprite_Mgr_Globals->backSprites; |
Sprite_Mgr_Globals->backSprites = p; |
} |
if (sType == 2) { |
p2 = Sprite_Mgr_Globals->normSprites; |
Sprite_Mgr_Globals->normSprites = p; |
} |
if (sType == 3) { |
p2 = Sprite_Mgr_Globals->foreSprites; |
Sprite_Mgr_Globals->foreSprites = p; |
} |
p->nextSprite = (Ptr) p2; |
return(id); |
} |
/* |
This is a common routine which is used to find a sprite by a given id, this routine |
gets called by most of the sprite interface routines that allow the programmer to |
change attributes on a sprite. The lookup priority is by sprite, then foreground |
sprite and finally background sprites. If no sprite is found we return nil. |
*/ |
SpriteInfoRecPtr FindSprite(short id) |
{ |
SpriteInfoRecPtr p; |
p = Sprite_Mgr_Globals->normSprites; |
while (p) { |
if (p->id == id) |
return(p); |
p = (SpriteInfoRecPtr) p->nextSprite; |
} |
p = Sprite_Mgr_Globals->foreSprites; |
while (p) { |
if (p->id == id) |
return(p); |
p = (SpriteInfoRecPtr) p->nextSprite; |
} |
p = Sprite_Mgr_Globals->backSprites; |
while (p) { |
if (p->id == id) |
return(p); |
p = (SpriteInfoRecPtr) p->nextSprite; |
} |
return(0L); |
} |
/* |
This routine is used to find a sprite that needs to share its gworld, since it |
doesn't make sense to duplicate a gworld which is going to use the same as |
another one. This could happen in a "shotter" game for example. |
*/ |
SpriteInfoRecPtr FindTwinSprite(short pictID) |
{ |
SpriteInfoRecPtr p; |
p = Sprite_Mgr_Globals->normSprites; |
while (p) { |
if (p->pictID == pictID) |
return(p); |
p = (SpriteInfoRecPtr) p->nextSprite; |
} |
p = Sprite_Mgr_Globals->foreSprites; |
while (p) { |
if (p->pictID == pictID) |
return(p); |
p = (SpriteInfoRecPtr) p->nextSprite; |
} |
p = Sprite_Mgr_Globals->backSprites; |
while (p) { |
if (p->pictID == pictID) |
return(p); |
p = (SpriteInfoRecPtr) p->nextSprite; |
} |
return(0L); |
} |
SceneryInfoRecPtr FindTwinScenery(short pictID) |
{ |
SceneryInfoRecPtr sc; |
sc = Sprite_Mgr_Globals->backgrounds; |
while (sc) { |
if (sc->pictID == pictID) |
return(sc); |
sc = (SceneryInfoRecPtr) sc->nextScenery; |
} |
sc = Sprite_Mgr_Globals->foregrounds; |
while (sc) { |
if (sc->pictID == pictID) |
return(sc); |
sc = (SceneryInfoRecPtr) sc->nextScenery; |
} |
return(0L); |
} |
void CheckChangedScenery(SceneryInfoRecPtr scenery) |
{ |
SceneryInfoRecPtr sc = scenery; |
Rect box, dRect; |
while (sc) { |
box = sc->sceneryWorld->portRect; |
if (sc->scrollTicks) { |
if (sc->nextTickCount <= TickCount()) { |
sc->scrollOffset.v += sc->autoScrollAmount.v; |
sc->scrollOffset.h += sc->autoScrollAmount.h; |
sc->nextTickCount = TickCount() + sc->scrollTicks; |
sc->changed = true; |
Sprite_Mgr_Globals->redoCheck = true; |
if (sc->scrollOffset.v >= box.bottom) |
sc->scrollOffset.v = 0; |
if (sc->scrollOffset.h >= box.right) |
sc->scrollOffset.h = 0; // wrap around... |
} |
} |
if (sc->changed && (sc->hidden == false)) { |
dRect = sc->animationRect; |
MarkSpriteInRect(&dRect, Sprite_Mgr_Globals->backSprites); |
MarkSpriteInRect(&dRect, Sprite_Mgr_Globals->normSprites); |
MarkSpriteInRect(&dRect, Sprite_Mgr_Globals->foreSprites); |
MarkSceneryInRect(&dRect, Sprite_Mgr_Globals->foregrounds); |
MarkSceneryInRect(&dRect, Sprite_Mgr_Globals->backgrounds); |
} |
sc = (SceneryInfoRecPtr) sc->nextScenery; |
} |
} |
void CheckChangedSprite(SpriteInfoRecPtr sprite) |
{ |
SpriteInfoRecPtr p = sprite; |
Rect dRect; |
while (p) { |
if (p->tickWait) { |
if (p->lastTick <= TickCount()) { |
p->currentFace++; |
if (p->currentFace > p->faces) |
p->currentFace = 1; |
p->lastTick = TickCount() + p->tickWait; |
p->changed = true; |
Sprite_Mgr_Globals->redoCheck = true; |
} |
} |
if (p->changed && (p->hidden == false)) { |
dRect = p->animationRect; |
MarkSceneryInRect(&dRect, Sprite_Mgr_Globals->backgrounds); |
MarkSceneryInRect(&dRect, Sprite_Mgr_Globals->foregrounds); |
MarkSpriteInRect(&dRect, Sprite_Mgr_Globals->backSprites); |
MarkSpriteInRect(&dRect, Sprite_Mgr_Globals->normSprites); |
MarkSpriteInRect(&dRect, Sprite_Mgr_Globals->foreSprites); |
if (p->oldAnimationRect.right != 0) { |
dRect = p->oldAnimationRect; |
MarkSceneryInRect(&dRect, Sprite_Mgr_Globals->backgrounds); |
MarkSceneryInRect(&dRect, Sprite_Mgr_Globals->foregrounds); |
MarkSpriteInRect(&dRect, Sprite_Mgr_Globals->backSprites); |
MarkSpriteInRect(&dRect, Sprite_Mgr_Globals->normSprites); |
MarkSpriteInRect(&dRect, Sprite_Mgr_Globals->foreSprites); |
p->oldAnimationRect.right = 0; |
} |
} |
p = (SpriteInfoRecPtr) p->nextSprite; |
} |
} |
void UpdateScenery(SceneryInfoRecPtr scenery) |
{ |
SceneryInfoRecPtr sc = scenery; |
Rect sRect, dRect; |
WindowPtr g1, g2; |
short h, v; |
Boolean fits; |
while (sc) { |
if (sc->changed && (sc->hidden == false)) { |
sc->changed = false; |
fits = true; |
Sprite_Mgr_Globals->changed = true; |
sRect = sc->sceneryRect; |
dRect = sc->animationRect; |
if (Sprite_Mgr_Globals->updateRects < kMaxUR) { |
Sprite_Mgr_Globals->changedRect[Sprite_Mgr_Globals->updateRects] = dRect; |
Sprite_Mgr_Globals->updateRects++; |
} |
v = dRect.bottom - dRect.top; |
h = dRect.right - dRect.left; |
if (sRect.right > h) // is destination smaller ? |
sRect.right = sRect.left + h; // make source smaller |
if (sRect.bottom > v) |
sRect.bottom = sRect.top + v; |
sRect.top += sc->scrollOffset.v; |
sRect.bottom += sc->scrollOffset.v; // add scroll offsets |
sRect.left += sc->scrollOffset.h; |
sRect.right += sc->scrollOffset.h; |
g1 = (GrafPtr) sc->sceneryWorld; |
g2 = (GrafPtr) Sprite_Mgr_Globals->animationGWorld; |
if ((sRect.bottom - sRect.top) < v) |
fits = false; |
if ((sRect.right - sRect.left) < h) |
fits = false; |
if (fits) { |
CopyBits(&(g1->portBits), &(g2->portBits), &sRect, &dRect, sc->copyMode, 0L); |
} |
else { // source has scrolled too much, so compensate |
h -= sRect.right - sRect.left; |
v -= sRect.bottom - sRect.top; // get difference |
dRect.right -= h; // clip to area we already have |
dRect.bottom -= v; |
sRect.right -= h; |
sRect.bottom -= v; |
CopyBits(&(g1->portBits), &(g2->portBits), &sRect, &dRect, sc->copyMode, 0L); |
if (h) { |
dRect.right += h; // now get residue at right |
dRect.left = dRect.right - h; |
sRect.left = sc->sceneryRect.left; |
sRect.right = sRect.left + h; |
CopyBits(&(g1->portBits), &(g2->portBits), &sRect, &dRect, sc->copyMode, 0L); |
} |
if (v) { |
dRect.bottom += v; // now get residue at bottom |
dRect.top = dRect.bottom - v; |
sRect.top = sc->sceneryRect.top; |
sRect.bottom = sRect.top + v; |
CopyBits(&(g1->portBits), &(g2->portBits), &sRect, &dRect, sc->copyMode, 0L); |
} |
} |
} |
sc = (SceneryInfoRecPtr) sc->nextScenery; |
} |
} |
void UpdateSprite(SpriteInfoRecPtr sprite) |
{ |
SpriteInfoRecPtr p = sprite; |
Rect sRect, dRect; |
WindowPtr g1, g2; |
while (p) { |
if (p->changed && (p->hidden == false)) { |
p->changed = false; |
Sprite_Mgr_Globals->changed = true; |
sRect = p->spriteRect; |
sRect.left = sRect.right * (p->currentFace - 1); // get the right face... |
sRect.right *= p->currentFace; |
dRect = p->animationRect; |
if (Sprite_Mgr_Globals->updateRects < kMaxUR) { |
Sprite_Mgr_Globals->changedRect[Sprite_Mgr_Globals->updateRects] = dRect; |
Sprite_Mgr_Globals->updateRects++; |
} |
g1 = (GrafPtr) p->spriteWorld; |
g2 = (GrafPtr) Sprite_Mgr_Globals->animationGWorld; |
CopyBits(&(g1->portBits), &(g2->portBits), &sRect, &dRect, p->copyMode, 0L); |
} |
p = (SpriteInfoRecPtr) p->nextSprite; |
} |
} |
void MarkSceneryInRect(Rect *box, SceneryInfoRecPtr scenery) |
{ |
SceneryInfoRecPtr sc; |
Rect sRect; |
Boolean dirty; |
Point pixel; |
sc = scenery; |
while (sc) { |
if (sc->changed == false) { |
dirty = false; |
sRect = sc->animationRect; |
pixel.h = sRect.left; |
pixel.v = sRect.top; |
if (SMgrPtInRect(pixel, box)) |
dirty = true; |
if (!dirty) { |
pixel.h = sRect.left; |
pixel.v = sRect.bottom; |
if (SMgrPtInRect(pixel, box)) |
dirty = true; |
} |
if (!dirty) { |
pixel.h = sRect.right; |
pixel.v = sRect.bottom; |
if (SMgrPtInRect(pixel, box)) |
dirty = true; |
} |
if (!dirty) { |
pixel.h = sRect.right; |
pixel.v = sRect.top; |
if (SMgrPtInRect(pixel, box)) |
dirty = true; |
} |
if (!dirty) { |
if (RectIntersect(&sRect, box)) |
dirty = true; |
} |
if (dirty) { |
sc->changed = true; |
Sprite_Mgr_Globals->redoCheck = true; |
} |
} |
sc = (SceneryInfoRecPtr) sc->nextScenery; |
} |
} |
void MarkSpriteInRect(Rect *box, SpriteInfoRecPtr sprite) |
{ |
SpriteInfoRecPtr p = sprite; |
Rect sRect; |
Boolean dirty; |
Point pixel; |
while (p) { |
if (p->changed == false) { |
dirty = false; |
sRect = p->animationRect; |
pixel.h = sRect.left; |
pixel.v = sRect.top; |
if (SMgrPtInRect(pixel, box)) |
dirty = true; |
if (!dirty) { |
pixel.h = sRect.left; |
pixel.v = sRect.bottom; |
if (SMgrPtInRect(pixel, box)) |
dirty = true; |
} |
if (!dirty) { |
pixel.h = sRect.right; |
pixel.v = sRect.bottom; |
if (SMgrPtInRect(pixel, box)) |
dirty = true; |
} |
if (!dirty) { |
pixel.h = sRect.right; |
pixel.v = sRect.top; |
if (SMgrPtInRect(pixel, box)) |
dirty = true; |
} |
if (!dirty) { |
if (RectIntersect(&sRect, box)) |
dirty = true; |
} |
if (dirty) { |
p->changed = true; |
Sprite_Mgr_Globals->redoCheck = true; |
} |
} |
p = (SpriteInfoRecPtr) p->nextSprite; |
} |
} |
void CopyGToScreen(void) |
{ |
short id; |
SpriteInfoRecPtr p = 0L; |
SceneryInfoRecPtr sc = 0L; |
Boolean done = false; |
GrafPtr g1, g2; |
Rect sRect, dRect; |
short mode; |
DebugStr("\pSet ID?"); |
id = 0; |
p = FindSprite(id); |
if (!p) { |
sc = Sprite_Mgr_Globals->backgrounds; |
while (sc && !done) { |
if (sc->id == id) |
done = true; |
else |
sc = (SceneryInfoRecPtr) sc->nextScenery; |
} |
if (!sc) { |
sc = Sprite_Mgr_Globals->foregrounds; |
while (sc && !done) { |
if (sc->id == id) |
done = true; |
else |
sc = (SceneryInfoRecPtr) sc->nextScenery; |
} |
} |
if (!done) |
return; |
} |
if (p) { |
g1 = (GrafPtr) p->spriteWorld; |
dRect = sRect = p->spriteRect; |
mode = p->copyMode; |
} |
else { |
g1 = (GrafPtr) sc->sceneryWorld; |
dRect = sRect = sc->sceneryWorld->portRect; |
mode = sc->copyMode; |
} |
g2 = (GrafPtr) Sprite_Mgr_Globals->animationWindow; |
CopyBits(&(g1->portBits), &(g2->portBits), &sRect, &dRect, mode, 0L); |
} |
Boolean SMgrPtInRect(Point pixel, Rect *box) |
{ |
if (pixel.h < box->left) |
return(false); |
if (pixel.h > box->right) |
return(false); |
if (pixel.v < box->top) |
return(false); |
if (pixel.v > box->bottom) |
return(false); |
return(true); |
} |
Boolean RectIntersect(Rect *r, Rect *box) |
{ |
Rect inter; /* register short d; |
d = 0; |
if ((r->left > box->left) && (r->left < box->right)) |
d = r->left; |
if ((box->left > r->left) && (box->left < r->right)) |
d = box->left; |
if (d == 0) |
return(false); |
d = 0; |
if ((r->top > box->top) && (r->top < box->bottom)) |
d = r->top; |
if ((box->top > r->top) && (box->top < r->bottom)) |
d = box->top; |
if (d == 0) |
return(false); |
d = 0; |
if ((r->right < box->right) && (r->right > box->left)) |
d = r->right; |
if ((box->right < r->right) && (box->right > r->left)) |
d = box->right; |
if (d == 0) |
return(false); |
d = 0; |
if ((r->bottom < box->bottom) && (r->bottom > box->top)) |
d = r->bottom; |
if ((box->bottom < r->bottom) && (box->bottom > r->top)) |
d = box->bottom; |
if (d == 0) |
return(false); */ |
if (SectRect(r, box, &inter)) // make my own |
return(true); |
return(false); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-10-10