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.
G4Graphics.c
/* |
File: G4Graphics.c |
Contains: xxx put contents here xxx |
Version: xxx put version here xxx |
Copyright: © 1998 by Apple Computer, Inc., all rights reserved. |
File Ownership: |
DRI: xxx put dri here xxx |
Other Contact: xxx put other contact here xxx |
Technology: xxx put technology here xxx |
Writers: |
(sjb) Steve Bollinger |
Change History (most recent first): |
<3> 7/1/98 sjb Update to CWPro 2 |
*/ |
//============================================================================ |
//---------------------------------------------------------------------------- |
// Graphics.c |
//---------------------------------------------------------------------------- |
//============================================================================ |
// I like to isolate all the graphic routines - put them in their own file. |
// This way all the thousands of Rect variables and Pixmaps have a place to go. |
// Anyway, this file contains all the drawing routines. |
#include "G4Externs.h" |
#include <Palettes.h> |
#include <QuickdrawText.h> |
#include <Fonts.h> |
#include <TextUtils.h> |
#include <Events.h> |
#define kUpperEyeHeight 100 |
#define kLowerEyeHeight 200 |
#define kNumLightningPts 8 |
void QuickUnionRect (Rect *, Rect *, Rect *); |
void CheckPlayerWrapAround (void); |
void DrawHand (void); |
void DrawEye (void); |
void DrawPlayer (void); |
void CheckEnemyWrapAround (short); |
void DrawEnemies (void); |
void DrawBanner (void); |
void DrawLava(void); |
void HandleLava(void); |
void HandlePixelShatter(void); |
Rect backSrcRect, workSrcRect, obSrcRect, playerSrcRect; |
Rect numberSrcRect, idleSrcRect, enemyWalkSrcRect, enemyFlySrcRect; |
Rect obeliskRects[4], playerRects[11], numbersSrc[11], numbersDest[11]; |
Rect flameSrcRect, flameDestRects[2], flameRects[4], eggSrcRect; |
Rect platformSrcRect, platformCopyRects[9], helpSrcRect, eyeSrcRect, bannerSrcRect; |
Rect helpSrc, helpDest, handSrcRect, handRects[2], eyeRects[4]; |
Point leftLightningPts[kNumLightningPts], rightLightningPts[kNumLightningPts]; |
CGrafPtr origBackSrcMap, backSrcMap, workSrcMap, obeliskSrcMap, playerSrcMap, eyeSrcMap; |
CGrafPtr numberSrcMap, idleSrcMap, enemyWalkSrcMap, enemyFlySrcMap; |
CGrafPtr flameSrcMap, eggSrcMap, bannerSrcMap, platformSrcMap, helpSrcMap, handSrcMap; |
GrafPtr playerMaskMap, enemyWalkMaskMap, enemyFlyMaskMap, eggMaskMap; |
GrafPtr handMaskMap, eyeMaskMap, obeliskMaskMap; |
Boolean whichList, helpOpen, scoresOpen; |
short numPixelShatter; |
pixelShatter thePixelShatter[kMaxPixelShatter]; |
extern handInfo theHand; |
extern eyeInfo theEye; |
extern prefsInfo thePrefs; |
extern playerType thePlayer; |
extern enemyType theEnemies[]; |
extern Rect enemyRects[24]; |
extern long theScore, wasTensOfThousands; |
extern short livesLeft, levelOn, numEnemies; |
extern Boolean evenFrame; |
extern short lightningCount; |
void HandleLightning(); |
extern short oldFrameRate; |
// in DR3 of DrawSprocket the underlay buffer will give the game the |
// ability to not worry about keeping track fo the update rects. As it |
// is right now, if you use update rects you have to save the update |
// rectangle for each frame, and the number of frames will vary depending |
// on the state of triple buffering and page flipping. |
// |
// Once the Underlay buffers are operational, enabiling this #define |
// will allow DS to optimize the screen updates instead of doing |
// a full screen copy (as happens in Glypha) |
//#define USE_INVALID_RECTS 1 |
//============================================================== Functions |
//-------------------------------------------------------------- DrawPlatforms |
// This function draws all the platforms on the background pixmap and theÉ |
// work pixmap. It needs to know merely how many of them to draw. |
void DrawPlatforms (short howMany) |
{ |
if (howMany > 3) // If there are more than 3 platformsÉ |
{ // Draw a platform to background pixmap. |
CopyBits(&((GrafPtr)platformSrcMap)->portBits, |
&((GrafPtr)backSrcMap)->portBits, |
&platformCopyRects[2], &platformCopyRects[7], srcCopy, 0L); |
// Draw a platform to work pixmap. |
CopyBits(&((GrafPtr)backSrcMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&platformCopyRects[7], &platformCopyRects[7], srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &platformCopyRects[7] ); |
#endif |
// Add rectangle to update list to be drawn to screen. |
// Ditto for a second platform. |
CopyBits(&((GrafPtr)platformSrcMap)->portBits, |
&((GrafPtr)backSrcMap)->portBits, |
&platformCopyRects[4], &platformCopyRects[8], srcCopy, 0L); |
CopyBits(&((GrafPtr)backSrcMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&platformCopyRects[8], &platformCopyRects[8], srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &platformCopyRects[8] ); |
#endif |
} |
else // If there are 3 or less platformsÉ |
{ |
CopyBits(&((GrafPtr)platformSrcMap)->portBits, |
&((GrafPtr)backSrcMap)->portBits, |
&platformCopyRects[3], &platformCopyRects[7], srcCopy, 0L); |
CopyBits(&((GrafPtr)backSrcMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&platformCopyRects[7], &platformCopyRects[7], srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &platformCopyRects[7] ); |
#endif |
CopyBits(&((GrafPtr)platformSrcMap)->portBits, |
&((GrafPtr)backSrcMap)->portBits, |
&platformCopyRects[5], &platformCopyRects[8], srcCopy, 0L); |
CopyBits(&((GrafPtr)backSrcMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&platformCopyRects[8], &platformCopyRects[8], srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &platformCopyRects[8] ); |
#endif |
} |
if (howMany > 5) // If there are more than 5 platformsÉ |
{ |
CopyBits(&((GrafPtr)platformSrcMap)->portBits, |
&((GrafPtr)backSrcMap)->portBits, |
&platformCopyRects[0], &platformCopyRects[6], srcCopy, 0L); |
CopyBits(&((GrafPtr)backSrcMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&platformCopyRects[6], &platformCopyRects[6], srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &platformCopyRects[6] ); |
#endif |
} |
else // If there are 5 or less platformsÉ |
{ |
CopyBits(&((GrafPtr)platformSrcMap)->portBits, |
&((GrafPtr)backSrcMap)->portBits, |
&platformCopyRects[1], &platformCopyRects[6], srcCopy, 0L); |
CopyBits(&((GrafPtr)backSrcMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&platformCopyRects[6], &platformCopyRects[6], srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &platformCopyRects[6] ); |
#endif |
} |
} |
//-------------------------------------------------------------- ScrollHelp |
// This function scrolls the help screen. You pass it a number of pixelsÉ |
// to scroll up or down (positive or negative number). |
void ScrollHelp (short scrollDown) |
{ |
// don't do any drawing, drawing is done by the idle animation automatically |
OffsetRect(&helpSrc, 0, scrollDown); // Move the source rectangle. |
if (helpSrc.bottom > 398) // Check to see we don't go too far. |
{ |
helpSrc.bottom = 398; |
helpSrc.top = helpSrc.bottom - 199; |
} |
else if (helpSrc.top < 0) |
{ |
helpSrc.top = 0; |
helpSrc.bottom = helpSrc.top + 199; |
} |
} |
//-------------------------------------------------------------- OpenHelp |
// Bring up the help screen. This is a kind of "wipe" or "barn door" effect. |
void OpenHelp (void) |
{ |
Rect wallSrc, wallDest; |
short i; |
SetRect(&helpSrc, 0, 0, 231, 0); // Initialize source and destination rects. |
helpDest = helpSrc; |
OffsetRect(&helpDest, 204, 171); |
SetRect(&wallSrc, 0, 0, 231, 199); |
OffsetRect(&wallSrc, 204, 171); |
wallDest = wallSrc; |
for (i = 0; i < 199; i ++) // Loop through 1 pixel at a time. |
{ |
DSpContext_GetBackBuffer( gTheContext, kDSpBufferKind_Normal, &workSrcMap ); |
DumpBackToWorkMap(); // clear the screen |
HandleLava(); |
HandlePixelShatter(); |
DrawTorches(); |
DrawBanner(); |
DrawLava(); |
DrawPixelShatter(); |
LogNextTick(1L); // Speed governor. |
helpSrc.bottom++; // Grow help source rect. |
helpDest.bottom++; // Grow help dest as well. |
wallSrc.bottom--; // Shrink wall source. |
wallDest.top++; // Shrink wall dest. |
// So, as the help graphic grows, the wall graphicÉ |
// shrinks. Thus it is as though the wall isÉ |
// lifting up to expose the help screen beneath. |
CopyBits( &((GrafPtr)helpSrcMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&helpSrc, &helpDest, srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &helpDest ); |
#endif |
CopyBits( &((GrafPtr)backSrcMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&wallSrc, &wallDest, srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &wallDest ); |
#endif |
// Copy slightly larger help screen. |
DSpContext_SwapBuffers( gTheContext, NULL, NULL ); |
} |
helpOpen = TRUE; // When done, set flag to indicate help is open. |
} |
//-------------------------------------------------------------- CloseWall |
// Close the wall over whatever screen is up (help screen or high scores). |
// Since the wall just comes down over the opening - covering whatever was beneath,É |
// it's simpler than the above function. |
void CloseWall (void) |
{ |
DSpContext_GetBackBuffer( gTheContext, kDSpBufferKind_Normal, &workSrcMap ); |
DumpBackToWorkMap(); // clear the screen |
DSpContext_SwapBuffers( gTheContext, NULL, NULL ); |
} |
//-------------------------------------------------------------- OpenHighScores |
// This function is practically identical to the OpenHelp(). The only realÉ |
// difference is that we must first draw all the high scores offscreen beforeÉ |
// lifting the wall to reveal them. |
void OpenHighScores (void) |
{ |
RGBColor theRGBColor, wasColor; |
Rect wallSrc, wallDest; |
Rect scoreSrc, scoreDest; |
Str255 scoreStr; |
short i, scoreWide; |
SetRect(&scoreSrc, 0, 0, 231, 0); // Initialize source and dest rects. |
OffsetRect(&scoreSrc, 204, 171); |
scoreDest = scoreSrc; |
SetRect(&wallSrc, 0, 0, 231, 199); |
OffsetRect(&wallSrc, 204, 171); |
wallDest = wallSrc; |
SetPort((GrafPtr)workSrcMap); // We'll draw scores to the work pixmap. |
PaintRect(&wallSrc); // Paint it black. |
GetForeColor(&wasColor); // Save the foreground color. |
TextFont(kFontIDGeneva); // Use Geneva 12 point Bold font. |
TextSize(12); |
TextFace(bold); |
Index2Color(132, &theRGBColor); // Get the 132nd color in RGB form. |
RGBForeColor(&theRGBColor); // Make this color the pen color. |
MoveTo(scoreSrc.left + 36, scoreSrc.top + 20); // Get pen in right position to draw. |
DrawString("\pGlypha IV High Scores"); // Draw the title. |
TextFont(kFontIDGeneva); // Use Geneva 9 point Bold font. |
TextSize(9); |
TextFace(bold); |
for (i = 0; i < 10; i++) // Walk through all 10 high scores. |
{ |
Index2Color(133, &theRGBColor); // Use color 133 (in palette). |
RGBForeColor(&theRGBColor); |
NumToString((long)i + 1L, scoreStr); // Draw "place" (1, 2, 3, É). |
MoveTo(scoreSrc.left + 8, scoreSrc.top + 40 + (i * 16)); |
DrawString(scoreStr); |
Index2Color(128, &theRGBColor); // Use color 128 (from palette). |
RGBForeColor(&theRGBColor); |
MoveTo(scoreSrc.left + 32, scoreSrc.top + 40 + (i * 16)); |
DrawString(thePrefs.highNames[i]); // Draw the high score name (Sue, É). |
Index2Color(164, &theRGBColor); // Use color 164 (from palette). |
RGBForeColor(&theRGBColor); |
NumToString(thePrefs.highScores[i], scoreStr); |
scoreWide = StringWidth(scoreStr); // Right justify. |
MoveTo(scoreSrc.left + 191 - scoreWide, scoreSrc.top + 40 + (i * 16)); |
DrawString(scoreStr); // Draw the high score (12,000, É). |
Index2Color(134, &theRGBColor); // Use color 134 (from palette). |
RGBForeColor(&theRGBColor); |
NumToString(thePrefs.highLevel[i], scoreStr); |
scoreWide = StringWidth(scoreStr); // Right justify. |
MoveTo(scoreSrc.left + 223 - scoreWide, scoreSrc.top + 40 + (i * 16)); |
DrawString(scoreStr); // Draw highest level (12, 10, É). |
} |
RGBForeColor(&wasColor); // Restore foreground color. |
for (i = 0; i < 199; i ++) // Now the standard scroll functions. |
{ |
WaitForNextTick(); |
DSpContext_GetBackBuffer( gTheContext, kDSpBufferKind_Normal, &workSrcMap ); |
DumpBackToWorkMap(); // clear the screen |
LogNextTick(1L); // Speed governor. |
scoreSrc.bottom++; |
scoreDest.bottom++; |
wallSrc.bottom--; |
wallDest.top++; |
// So, as the help graphic grows, the wall graphicÉ |
// shrinks. Thus it is as though the wall isÉ |
// lifting up to expose the help screen beneath. |
CopyBits( &((GrafPtr)workSrcMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&scoreSrc, &scoreDest, srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &scoreDest ); |
#endif |
CopyBits( &((GrafPtr)backSrcMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&wallSrc, &wallDest, srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &wallDest ); |
#endif |
// Copy slightly larger help screen. |
DSpContext_SwapBuffers( gTheContext, NULL, NULL ); |
} |
scoresOpen = TRUE; // Flag that the scores are up. |
} |
//-------------------------------------------------------------- UpdateLivesNumbers |
// During a game, this function is called to reflect the current number of lives. |
// This is "lives remaining", so 1 is subtracted before displaying it to the screen. |
// The lives is "wrapped around" after 99. So 112 lives will display as 12. It'sÉ |
// a lot easier to handle numbers this way (it beats a recursive function that mightÉ |
// potentially draw across the entire screen. |
void UpdateLivesNumbers (void) |
{ |
short digit; |
digit = (livesLeft - 1) / 10; // Get the "10's" digit. |
digit = digit % 10L; // Keep it less than 10 (0 -> 9). |
if ((digit == 0) && ((livesLeft - 1) < 10)) |
digit = 10; // Use a "blank" space if zero and less than 10. |
// Draw digit. |
CopyBits(&((GrafPtr)numberSrcMap)->portBits, |
&((GrafPtr)backSrcMap)->portBits, |
&numbersSrc[digit], &numbersDest[0], srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[0] ); |
#endif |
digit = (livesLeft - 1) % 10; // Get 1's digit. |
// Draw digit. |
CopyBits(&((GrafPtr)numberSrcMap)->portBits, |
&((GrafPtr)backSrcMap)->portBits, |
&numbersSrc[digit], &numbersDest[1], srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[1] ); |
#endif |
} |
//-------------------------------------------------------------- UpdateScoreNumbers |
// This function works just like the above function. However, we allow theÉ |
// score to go to 6 digits (999,999) before rolling over. Note however, thatÉ |
// in both the case of the score, number of lives, etc., the game does in factÉ |
// keep track of the "actual" number. It is just that only so many digits areÉ |
// being displayed. |
void UpdateScoreNumbers (void) |
{ |
long digit; |
digit = theScore / 100000L; // Get "hundreds of thousands" digit |
digit = digit % 10L; // Clip off anything greater than 9. |
if ((digit == 0) && (theScore < 1000000L)) |
digit = 10; // Use blank space if zero. |
// Draw digit. |
CopyBits(&((GrafPtr)numberSrcMap)->portBits, |
&((GrafPtr)backSrcMap)->portBits, |
&numbersSrc[digit], &numbersDest[2], srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[2] ); |
#endif |
digit = theScore / 10000L; // Get "tens of thousands" digit. |
if (digit > wasTensOfThousands) // Check for "extra life" here. |
{ |
livesLeft++; // Increment number of lives. |
UpdateLivesNumbers(); // Reflect new lives on screen. |
wasTensOfThousands = digit; // Note that life was given. |
} |
digit = digit % 10L; // Clip off anything greater than 9. |
if ((digit == 0) && (theScore < 100000L)) |
digit = 10; // Use blank space if zero. |
// Draw digit. |
CopyBits(&((GrafPtr)numberSrcMap)->portBits, |
&((GrafPtr)backSrcMap)->portBits, |
&numbersSrc[digit], &numbersDest[3], srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[3] ); |
#endif |
digit = theScore / 1000L; // Handle "thousands" digit. |
digit = digit % 10L; |
if ((digit == 0) && (theScore < 10000L)) |
digit = 10; |
CopyBits(&((GrafPtr)numberSrcMap)->portBits, |
&((GrafPtr)backSrcMap)->portBits, |
&numbersSrc[digit], &numbersDest[4], srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[4] ); |
#endif |
digit = theScore / 100L; // Handle 100's digit. |
digit = digit % 10L; |
if ((digit == 0) && (theScore < 1000L)) |
digit = 10; |
CopyBits(&((GrafPtr)numberSrcMap)->portBits, |
&((GrafPtr)backSrcMap)->portBits, |
&numbersSrc[digit], &numbersDest[5], srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[5] ); |
#endif |
digit = theScore / 10L; // Handle 10's digit. |
digit = digit % 10L; |
if ((digit == 0) && (theScore < 100L)) |
digit = 10; |
CopyBits(&((GrafPtr)numberSrcMap)->portBits, |
&((GrafPtr)backSrcMap)->portBits, |
&numbersSrc[digit], &numbersDest[6], srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[6] ); |
#endif |
digit = theScore % 10L; // Handle 1's digit. |
CopyBits(&((GrafPtr)numberSrcMap)->portBits, |
&((GrafPtr)backSrcMap)->portBits, |
&numbersSrc[digit], &numbersDest[7], srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[7] ); |
#endif |
} |
//-------------------------------------------------------------- UpdateLevelNumbers |
// Blah, blah, blah. Just like the above functions but handles displaying theÉ |
// level the player is on. We allow 3 digits here (up to 999) before wrapping. |
void UpdateLevelNumbers (void) |
{ |
short digit; |
short workNumber; |
// workNumber = levelOn; |
workNumber = oldFrameRate; |
digit = (workNumber + 1) / 100; // Do 100's digit. |
digit = digit % 10L; |
if ((digit == 0) && ((workNumber + 1) < 1000)) |
digit = 10; |
CopyBits(&((GrafPtr)numberSrcMap)->portBits, |
&((GrafPtr)backSrcMap)->portBits, |
&numbersSrc[digit], &numbersDest[8], srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[3] ); |
#endif |
digit = (workNumber + 1) / 10; // Do 10's digit. |
digit = digit % 10L; |
if ((digit == 0) && ((workNumber + 1) < 100)) |
digit = 10; |
CopyBits(&((GrafPtr)numberSrcMap)->portBits, |
&((GrafPtr)backSrcMap)->portBits, |
&numbersSrc[digit], &numbersDest[9], srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[9] ); |
#endif |
digit = (workNumber + 1) % 10; // Do 1's digit. |
CopyBits(&((GrafPtr)numberSrcMap)->portBits, |
&((GrafPtr)backSrcMap)->portBits, |
&numbersSrc[digit], &numbersDest[10], srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[10] ); |
#endif |
} |
//-------------------------------------------------------------- GenerateLightning |
// This function takes a point (h and v) and then generates two lightning boltsÉ |
// (one from the tip of each obelisk) to the point. It does this by generatingÉ |
// a list of segments (as the lightning is broken up into segements). The drawingÉ |
// counterpart to this function will draw a line connecting these segements (a sortÉ |
// of dot-to-dot). |
void GenerateLightning (short h, short v) |
{ |
#define kLeftObeliskH 172 |
#define kLeftObeliskV 250 |
#define kRightObeliskH 468 |
#define kRightObeliskV 250 |
#define kWander 16 |
short i, leftDeltaH, rightDeltaH, leftDeltaV, rightDeltaV, range; |
leftDeltaH = h - kLeftObeliskH; // Determine the h and v distances betweenÉ |
rightDeltaH = h - kRightObeliskH; // obelisks and the target point. |
leftDeltaV = v - kLeftObeliskV; |
rightDeltaV = v - kRightObeliskV; |
for (i = 0; i < kNumLightningPts; i++) // Calculate an even spread of points betweenÉ |
{ // obelisk tips and the target point. |
leftLightningPts[i].h = (leftDeltaH * i) / (kNumLightningPts - 1) + kLeftObeliskH; |
leftLightningPts[i].v = (leftDeltaV * i) / (kNumLightningPts - 1) + kLeftObeliskV; |
rightLightningPts[i].h = (rightDeltaH * i) / (kNumLightningPts - 1) + kRightObeliskH; |
rightLightningPts[i].v = (rightDeltaV * i) / (kNumLightningPts - 1) + kRightObeliskV; |
} |
range = kWander * 2 + 1; // Randomly scatter the points verticallyÉ |
for (i = 1; i < kNumLightningPts - 1; i++) // but NOT the 1st or last points. |
{ |
leftLightningPts[i].v += RandomInt(range) - kWander; |
rightLightningPts[i].v += RandomInt(range) - kWander; |
} |
} |
void DrawObelisks (void) |
{ |
if ((lightningCount > 0) && evenFrame) // Draw them "inverted" |
{ |
CopyMask( &((GrafPtr)obeliskSrcMap)->portBits, // src |
&((GrafPtr)obeliskMaskMap)->portBits, // mask |
&((GrafPtr) workSrcMap)->portBits, // dst |
&obeliskRects[0], // src rect |
&obeliskRects[0], // mask rect |
&obeliskRects[2]); // dst rect |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &obeliskRects[2] ); |
#endif |
CopyMask( &((GrafPtr)obeliskSrcMap)->portBits, // src |
&((GrafPtr)obeliskMaskMap)->portBits, // mask |
&((GrafPtr) workSrcMap)->portBits, // dst |
&obeliskRects[1], // src rect |
&obeliskRects[1], // mask rect |
&obeliskRects[3]); // dst rect |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &obeliskRects[3] ); |
#endif |
} |
else |
{ |
CopyMask( &((GrafPtr)backSrcMap)->portBits, // src |
&((GrafPtr)obeliskMaskMap)->portBits, // mask |
&((GrafPtr) workSrcMap)->portBits, // dst |
&obeliskRects[2], // src rect |
&obeliskRects[0], // mask rect |
&obeliskRects[2]); // dst rect |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &obeliskRects[2] ); |
#endif |
CopyMask( &((GrafPtr)backSrcMap)->portBits, // src |
&((GrafPtr)obeliskMaskMap)->portBits, // mask |
&((GrafPtr) workSrcMap)->portBits, // dst |
&obeliskRects[3], // src rect |
&obeliskRects[1], // mask rect |
&obeliskRects[3]); // dst rect |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &obeliskRects[3] ); |
#endif |
} |
} |
void StrikeLightningWork (void) |
{ |
short i; |
GrafPtr oldPort; |
RGBColor yellow = {65535, 65535, 0}; |
Rect theRect; |
GetPort(&oldPort); |
SetPort((GrafPtr)workSrcMap); |
PenSize(1, 2); // Use a tall pen. |
RGBForeColor(&yellow); |
// Draw lightning bolts with inverted pen. |
MoveTo(leftLightningPts[0].h, leftLightningPts[0].v); |
for (i = 0; i < kNumLightningPts - 1; i++) // Draw left lightning bolt. |
{ |
MoveTo(leftLightningPts[i].h, leftLightningPts[i].v); |
LineTo(leftLightningPts[i + 1].h - 1, leftLightningPts[i + 1].v); |
} |
SetRect( &theRect, leftLightningPts[0].h, leftLightningPts[0].v, |
leftLightningPts[kNumLightningPts].h - 1, leftLightningPts[kNumLightningPts].v ); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &theRect ); |
#endif |
MoveTo(rightLightningPts[0].h, rightLightningPts[0].v); |
for (i = 0; i < kNumLightningPts - 1; i++) // Draw right lightning bolt. |
{ |
MoveTo(rightLightningPts[i].h, rightLightningPts[i].v); |
LineTo(rightLightningPts[i + 1].h - 1, rightLightningPts[i + 1].v); |
} |
SetRect( &theRect, rightLightningPts[0].h, rightLightningPts[0].v, |
rightLightningPts[kNumLightningPts].h - 1, rightLightningPts[kNumLightningPts].v ); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &theRect ); |
#endif |
PenNormal(); // Return pen to normal. |
SetPort(oldPort); |
} |
//-------------------------------------------------------------- DumpBackToWorkMap |
// Simple handy function that copies the entire background pixmap to theÉ |
// work pixmap. |
//-- |
//-------------------------------------------------------------- DumpBackToWorkMap |
// Simple handy function that copies the entire background pixmap to theÉ |
// work pixmap. |
static inline void ClassicDumpBackToWork(void) |
{ |
// this is doing a full clean of the work map from the source map, don't inval |
// this rect. |
// |
// ¥ this will go away once DrawSprocket Underlays are used (in DR3 release) |
CopyBits(&((GrafPtr)backSrcMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&backSrcRect, &backSrcRect, srcCopy, 0L); |
} |
// faster on some machines, on others it is slow because of dcbz |
static inline void FastDumpBackToWorkMap (void) |
{ |
CGrafPtr srcGrafPtr = backSrcMap; |
PixMap *srcMap = *(srcGrafPtr->portPixMap); |
char *src = srcMap->baseAddr; |
UInt32 srcBump = srcMap->rowBytes & 0x3fff; |
CGrafPtr dstGrafPtr = workSrcMap; |
PixMap *dstMap = *(dstGrafPtr->portPixMap); |
char *dst = dstMap->baseAddr; |
UInt32 dstBump = dstMap->rowBytes & 0x3fff; |
int count; |
for(count = 0; count < 480; count++) |
{ |
BlockMoveData(src,dst,640); |
src += srcBump; |
dst += dstBump; |
} |
} |
void DumpBackToWorkMap(void) |
{ |
ClassicDumpBackToWork(); |
} |
//-------------------------------------------------------------- QuickUnionRect |
// The Mac Toolbox gives you a UnionRect() function, but, like any ToolboxÉ |
// routine, if we can do it faster, we ought to. Well, the function belowÉ |
// is quick because (among other reasons), it assumes that the two rectsÉ |
// being compared are the same size. |
// |
// Notes from Cary Farrier: Sorry John I don't agree with that advice. You |
// may be able to do something faster, but the speed gain you achieve may not |
// be worth the effort required to develop, test, and debug the code. John's |
// advice is good for some scenarios, but it is the exception and not the |
// rule. |
void QuickUnionRect (Rect *rect1, Rect *rect2, Rect *whole) |
{ |
if (rect1->left < rect2->left) // See if we're to use rect1's left. |
{ |
whole->left = rect1->left; |
whole->right = rect2->right; |
} |
else // Use rect2's left. |
{ |
whole->left = rect2->left; |
whole->right = rect1->right; |
} |
if (rect1->top < rect2->top) // See if we're to use rect1's top. |
{ |
whole->top = rect1->top; |
whole->bottom = rect2->bottom; |
} |
else // Use rect2's top. |
{ |
whole->top = rect2->top; |
whole->bottom = rect1->bottom; |
} |
} |
//-------------------------------------------------------------- CheckPlayerWrapAround |
// This handles drawing wrap-around. It is such that, when a player walks partlyÉ |
// off the right edge of the screen, you see the player peeking through on the leftÉ |
// side of the screen. Since we can't (shouldn't) assume that the physical screenÉ |
// memory wraps around, we'll draw the right player clipped against the right edgeÉ |
// of the screen and draw a SECOND PLAYER on the left edge (clipped to the left). |
void CheckPlayerWrapAround (void) |
{ |
Rect wrapRect, wasWrapRect, src; |
if (thePlayer.dest.right > 640) // Player off right edge of screen. |
{ |
thePlayer.wrapping = TRUE; // Set "wrapping" flag. |
wrapRect = thePlayer.dest; // Start out with copy of player bounds. |
wrapRect.left -= 640; // Offset it a screenwidth to left. |
wrapRect.right -= 640; |
// Ditto with old location. |
wasWrapRect = thePlayer.wasDest; |
wasWrapRect.left -= 640; |
wasWrapRect.right -= 640; |
if (thePlayer.mode == kBones) // Draw second bones. |
{ |
src = playerRects[thePlayer.srcNum]; |
src.bottom = src.top + thePlayer.frame; |
CopyMask(&((GrafPtr)playerSrcMap)->portBits, |
&((GrafPtr)playerMaskMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&src, &src, &wrapRect); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &wrapRect ); |
#endif |
} |
else // Draw second player (not bones). |
{ |
CopyMask(&((GrafPtr)playerSrcMap)->portBits, |
&((GrafPtr)playerMaskMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&playerRects[thePlayer.srcNum], |
&playerRects[thePlayer.srcNum], |
&wrapRect); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &wrapRect ); |
#endif |
} |
thePlayer.wrap = wrapRect; |
} |
else if (thePlayer.dest.left < 0) // Else if off the left edgeÉ |
{ |
thePlayer.wrapping = TRUE; // Set "wrapping" flag. |
wrapRect = thePlayer.dest; // Start out with copy of player bounds. |
wrapRect.left += 640; // Offset it a screenwidth to right. |
wrapRect.right += 640; |
// Ditto with old location. |
wasWrapRect = thePlayer.wasDest; |
wasWrapRect.left += 640; |
wasWrapRect.right += 640; |
if (thePlayer.mode == kBones) // Draw second bones. |
{ |
src = playerRects[thePlayer.srcNum]; |
src.bottom = src.top + thePlayer.frame; |
CopyMask(&((GrafPtr)playerSrcMap)->portBits, |
&((GrafPtr)playerMaskMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&src, &src, &wrapRect); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &wrapRect ); |
#endif |
} |
else // Draw second player (not bones). |
{ |
CopyMask(&((GrafPtr)playerSrcMap)->portBits, |
&((GrafPtr)playerMaskMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&playerRects[thePlayer.srcNum], |
&playerRects[thePlayer.srcNum], |
&wrapRect); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &wrapRect ); |
#endif |
} |
thePlayer.wrap = wrapRect; |
} |
else |
thePlayer.wrapping = FALSE; // Otherwise, we're not wrapping. |
} |
//-------------------------------------------------------------- DrawTorches |
// This handles drawing the two torch's flames. It chooses randomly fromÉ |
// 4 torch graphics and draws right over the old torches. |
void DrawTorches (void) |
{ |
short who; |
who = RandomInt(4); |
if (evenFrame) // Only draw 1 torch - left on even framesÉ |
{ |
CopyBits(&((GrafPtr)flameSrcMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&flameRects[who], &flameDestRects[0], srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &flameDestRects[0] ); |
#endif |
} |
else // and draw the right torch on odd frames. |
{ // We do this even/odd thing for speed. Why draw both? |
CopyBits(&((GrafPtr)flameSrcMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&flameRects[who], &flameDestRects[1], srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &flameDestRects[1] ); |
#endif |
} |
} |
//-------------------------------------------------------------- DrawHand |
// This function takes care of drawing the hand offscreen. There are onlyÉ |
// two (well really three) choices - hand open, hand clutching (or no handÉ |
// in which case both options are skipped). |
void DrawHand (void) |
{ |
theHand.dest.right = theHand.dest.left + 56; |
theHand.dest.bottom = theHand.dest.top + 57; |
if (theHand.mode == kOutGrabeth) // Fingers open. |
{ |
CopyMask(&((GrafPtr)handSrcMap)->portBits, |
&((GrafPtr)handMaskMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&handRects[0], |
&handRects[0], |
&theHand.dest); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &theHand.dest ); |
#endif |
} |
else if (theHand.mode == kClutching) // Fingers clenched. |
{ |
CopyMask(&((GrafPtr)handSrcMap)->portBits, |
&((GrafPtr)handMaskMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&handRects[1], |
&handRects[1], |
&theHand.dest); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &theHand.dest ); |
#endif |
} |
} |
//-------------------------------------------------------------- DrawEye |
// This function draws the eye (if it's floating about - stalking). |
void DrawEye (void) |
{ |
if (theEye.mode == kStalking) |
{ |
CopyMask(&((GrafPtr)eyeSrcMap)->portBits, |
&((GrafPtr)eyeMaskMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&eyeRects[theEye.srcNum], |
&eyeRects[theEye.srcNum], |
&theEye.dest); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &theEye.dest ); |
#endif |
} |
} |
//-------------------------------------------------------------- DrawPlayer |
// Although called "DrawPlayer()", this function actually does its drawingÉ |
// offscreen. It is the above routine that will finally copy our offscreenÉ |
// work to the main screen. Anyway, the below function draws the playerÉ |
// offscreen in the correct position and state. |
void DrawPlayer (void) |
{ |
Rect src; |
if ((evenFrame) && (thePlayer.mode == kIdle)) |
{ // On even frames, we'll draw the "flashed" graphic of the player. |
// If you've played Glypha, you notice that the player begins aÉ |
// game flashing alternately between bones and a normal player. |
CopyMask(&((GrafPtr)idleSrcMap)->portBits, |
&((GrafPtr)playerMaskMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&idleSrcRect, |
&playerRects[thePlayer.srcNum], |
&thePlayer.dest); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &thePlayer.dest ); |
#endif |
} |
else if (thePlayer.mode == kBones) |
{ // If the player is dead and a pile of bonesÉ |
src = playerRects[thePlayer.srcNum]; |
src.bottom = src.top + thePlayer.frame; |
CopyMask(&((GrafPtr)playerSrcMap)->portBits, |
&((GrafPtr)playerMaskMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&src, &src, &thePlayer.dest); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &thePlayer.dest ); |
#endif |
} |
else // Else, if the player is neither idle nor deadÉ |
{ |
CopyMask(&((GrafPtr)playerSrcMap)->portBits, |
&((GrafPtr)playerMaskMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&playerRects[thePlayer.srcNum], |
&playerRects[thePlayer.srcNum], |
&thePlayer.dest); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &thePlayer.dest ); |
#endif |
} |
// Now we add the player to the update rect list. |
// Record old locations. |
thePlayer.wasH = thePlayer.h; |
thePlayer.wasV = thePlayer.v; |
// Record old bounds rect. |
thePlayer.wasDest = thePlayer.dest; |
} |
//-------------------------------------------------------------- CheckEnemyWrapAround |
// This function both determines whether or not an enemy (sphinx) is wrapping around. |
// If it is, the "second" wrapped-around enemy is drawn. |
void CheckEnemyWrapAround (short who) |
{ |
Rect wrapRect, wasWrapRect, src; |
if (theEnemies[who].dest.right > 640) // Is enemy off the right edge of screen? |
{ |
wrapRect = theEnemies[who].dest; // Copy bounds. |
wrapRect.left -= 640; // Offset bounds copy to left (one screen width). |
wrapRect.right -= 640; |
// Ditto with old bounds. |
wasWrapRect = theEnemies[who].wasDest; |
wasWrapRect.left -= 640; |
wasWrapRect.right -= 640; |
// Handle "egg" enemies. |
if ((theEnemies[who].mode == kFalling) || (theEnemies[who].mode == kEggTimer)) |
{ // Handle "egg" enemy sinking into platform. |
if ((theEnemies[who].mode == kEggTimer) && (theEnemies[who].frame < 24)) |
{ |
src = eggSrcRect; |
src.bottom = src.top + theEnemies[who].frame; |
} |
else |
src = eggSrcRect; |
CopyMask(&((GrafPtr)eggSrcMap)->portBits, |
&((GrafPtr)eggMaskMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&src, &src, &wrapRect); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &wrapRect ); |
#endif |
} |
else // Otherwise, if enemy not an eggÉ |
{ |
CopyMask(&((GrafPtr)enemyFlySrcMap)->portBits, |
&((GrafPtr)enemyFlyMaskMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&enemyRects[theEnemies[who].srcNum], |
&enemyRects[theEnemies[who].srcNum], |
&wrapRect); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &wrapRect ); |
#endif |
} |
} |
else if (theEnemies[who].dest.left < 0) // Check to see if enemy off left edge instead. |
{ |
wrapRect = theEnemies[who].dest; // Make a copy of enemy bounds. |
wrapRect.left += 640; // Offset it right one screens width. |
wrapRect.right += 640; |
// Ditto with old bounds. |
wasWrapRect = theEnemies[who].wasDest; |
wasWrapRect.left += 640; |
wasWrapRect.right += 640; |
if ((theEnemies[who].mode == kFalling) || (theEnemies[who].mode == kEggTimer)) |
{ // Blah, blah, blah. This is just like the above. |
if ((theEnemies[who].mode == kEggTimer) && (theEnemies[who].frame < 24)) |
{ |
src = eggSrcRect; |
src.bottom = src.top + theEnemies[who].frame; |
} |
else |
src = eggSrcRect; |
CopyMask(&((GrafPtr)eggSrcMap)->portBits, |
&((GrafPtr)eggMaskMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&src, &src, &wrapRect); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &wrapRect ); |
#endif |
} |
else |
{ |
CopyMask(&((GrafPtr)enemyFlySrcMap)->portBits, |
&((GrafPtr)enemyFlyMaskMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&enemyRects[theEnemies[who].srcNum], |
&enemyRects[theEnemies[who].srcNum], |
&wrapRect); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &wrapRect ); |
#endif |
} |
} |
} |
//-------------------------------------------------------------- DrawEnemies |
// This function draws all the sphinx enemies (or eggs if they're in that state). |
// It doesn't handle wrap-around (the above function does) but it does call it. |
void DrawEnemies (void) |
{ |
Rect src; |
short i; |
for (i = 0; i < numEnemies; i++) // Go through all enemies. |
{ |
switch (theEnemies[i].mode) // Handle the different modes as seperate cases. |
{ |
case kSpawning: // Spawning enemies are "growing" out of the platform. |
src = enemyRects[theEnemies[i].srcNum]; |
src.bottom = src.top + theEnemies[i].frame; |
CopyMask(&((GrafPtr)enemyWalkSrcMap)->portBits, |
&((GrafPtr)enemyWalkMaskMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&src, &src, &theEnemies[i].dest); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &theEnemies[i].dest ); |
#endif |
// Don't need to check wrap-around, when enemiesÉ |
// spawn, they're never on the edge of screen. |
theEnemies[i].wasDest = theEnemies[i].dest; |
theEnemies[i].wasH = theEnemies[i].h; |
theEnemies[i].wasV = theEnemies[i].v; |
break; |
case kFlying: // Flying enemies are air borne (gee). |
CopyMask(&((GrafPtr)enemyFlySrcMap)->portBits, |
&((GrafPtr)enemyFlyMaskMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&enemyRects[theEnemies[i].srcNum], &enemyRects[theEnemies[i].srcNum], |
&theEnemies[i].dest); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &theEnemies[i].dest ); |
#endif |
CheckEnemyWrapAround(i); // I like the word "air bourne". |
theEnemies[i].wasDest = theEnemies[i].dest; |
theEnemies[i].wasH = theEnemies[i].h; |
theEnemies[i].wasV = theEnemies[i].v; |
break; |
case kWalking: // Walking enemies are walking. Enemies. |
CopyMask(&((GrafPtr)enemyWalkSrcMap)->portBits, |
&((GrafPtr)enemyWalkMaskMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&enemyRects[theEnemies[i].srcNum], &enemyRects[theEnemies[i].srcNum], |
&theEnemies[i].dest); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &theEnemies[i].dest ); |
#endif |
// Don't need to check wrap-around, enemies walkÉ |
// only briefly, and never off edge of screen. |
theEnemies[i].wasDest = theEnemies[i].dest; |
theEnemies[i].wasH = theEnemies[i].h; |
theEnemies[i].wasV = theEnemies[i].v; |
break; |
case kFalling: // Falling enemies are in fact eggs! |
CopyMask(&((GrafPtr)eggSrcMap)->portBits, |
&((GrafPtr)eggMaskMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&eggSrcRect, &eggSrcRect, &theEnemies[i].dest); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &theEnemies[i].dest ); |
#endif |
CheckEnemyWrapAround(i); // Check for wrap around. |
theEnemies[i].wasDest = theEnemies[i].dest; |
theEnemies[i].wasH = theEnemies[i].h; |
theEnemies[i].wasV = theEnemies[i].v; |
break; |
case kEggTimer: // These are idle, perhaps hatching, eggs. |
if (theEnemies[i].frame < 24) |
{ // Below countdown = 24, the egss are sinkingÉ |
src = eggSrcRect; // into the platform (hatch time!). |
src.bottom = src.top + theEnemies[i].frame; |
} |
else |
src = eggSrcRect; |
CopyMask(&((GrafPtr)eggSrcMap)->portBits, |
&((GrafPtr)eggMaskMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&src, &src, &theEnemies[i].dest); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &theEnemies[i].dest ); |
#endif |
CheckEnemyWrapAround(i); // Check for wrap around. |
theEnemies[i].wasDest = theEnemies[i].dest; |
theEnemies[i].wasH = theEnemies[i].h; |
theEnemies[i].wasV = theEnemies[i].v; |
break; |
} |
} |
} |
//------------- DrawBanner |
void DrawBanner (void) |
{ |
Rect destRect; |
Rect srcRect; |
long start = (TickCount() / 2) % 1280; |
long seg1Len; |
long seg2Len; |
if (start <= 640) |
{ |
seg1Len = 640; |
seg2Len = 0; |
} |
else |
{ |
seg1Len = 1280 - start; |
seg2Len = 640 - seg1Len; |
} |
SetRect(&destRect, |
0, // left |
460, // top |
seg1Len, // right |
480); // bottom |
SetRect(&srcRect, |
start, |
0, |
start + seg1Len, |
20); |
CopyBits( &((GrafPtr)bannerSrcMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&srcRect, &destRect, srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &destRect ); |
#endif |
if (seg2Len > 0) |
{ |
destRect.left = seg1Len; |
destRect.right = 640; |
srcRect.left = 0; |
srcRect.right = seg2Len; |
CopyBits( &((GrafPtr)bannerSrcMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&srcRect, &destRect, srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &destRect ); |
#endif |
} |
} |
//-------------------------------------------------------------- DrawPixelShatter |
void DrawPixelShatter (void) |
{ |
int i; |
CGrafPtr theGrafPtr = workSrcMap; |
PixMap *theMap = *(theGrafPtr->portPixMap); |
short h,v; |
short rowBytes = theMap->rowBytes & 0x3fff; |
short minH = 1000, minV = 1000, maxH = 0, maxV = 0; |
Rect theRect; |
for(i = 0; i < numPixelShatter; i++) |
{ |
char *addr = theMap->baseAddr; |
int offset = 0; |
h = thePixelShatter[i].h; |
v = thePixelShatter[i].v; |
if( h < minH ) |
minH = h; |
if( h > maxH ) |
maxH = h; |
if( v < minV ) |
minV = v; |
if( v > maxV ) |
maxV = v; |
h >>= 4; |
v >>= 4; |
offset = rowBytes * v; |
offset += h; |
addr += offset; |
*addr = thePixelShatter[i].color; |
} |
SetRect( &theRect, minH, minV, maxH, maxV ); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &theRect ); |
#endif |
} |
//-------------------------------------------------------------- DrawLava |
void DrawLava(void); |
#if 0 |
void DrawLava(void) |
{ |
short where = RandomInt(640); |
short velocity = -(RandomInt(15) + 15); |
StartPixelShatter( where, 460, 0, velocity, kShatterLavaBubble); |
} |
#endif |
void DrawScoreFloaters(void); |
void DrawScoreFloaters(void) |
{ |
#if 0 |
int i,j,count; |
Rect r; |
CGrafPtr theGrafPtr = workSrcMap; |
PixMap *theMap = *(theGrafPtr->portPixMap); |
short rowBytes = theMap->rowBytes & 0x3fff; |
char *addr = theMap->baseAddr; |
for(count = 0; count < numScoreFloater; count++) |
{ |
r.top = theScoreFloater[count].location.v; |
r.left = theScoreFloater[count].location.h; |
r.bottom = theScoreFloater[count].location.v + 20; |
r.right = theScoreFloater[count].location.h + 60; |
addr = theMap->baseAddr + (r.top * rowBytes); |
for(j = r.top; j < r.bottom; j++) |
{ |
for(i = r.left; i < r.right; i++) |
{ |
addr[i] = 0; |
} |
addr += rowBytes; |
} |
} |
#else |
int count; |
Rect baseRect = {0,0,8,11}; |
for(count = 0; count < numScoreFloater; count++) |
{ |
short digit; |
short workNumber; |
Rect r = baseRect; |
r.top += theScoreFloater[count].location.v; |
r.bottom += theScoreFloater[count].location.v; |
r.left += theScoreFloater[count].location.h; |
r.right += theScoreFloater[count].location.h; |
workNumber = theScoreFloater[count].score; |
digit = (workNumber + 1) / 1000; // Do 1000's digit. |
digit = digit % 10L; |
if (digit != 0) |
{ |
CopyBits(&((GrafPtr)numberSrcMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&numbersSrc[digit], &r, srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &r ); |
#endif |
} |
r.left += 11; |
r.right += 11; |
digit = (workNumber + 1) / 100; // Do 100's digit. |
digit = digit % 10L; |
if ((digit != 0) || (workNumber >= 1000)) |
{ |
CopyBits(&((GrafPtr)numberSrcMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&numbersSrc[digit], &r, srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &r ); |
#endif |
} |
r.left += 11; |
r.right += 11; |
digit = (workNumber + 1) / 10; // Do 10's digit. |
digit = digit % 10L; |
if ((digit != 0) || (workNumber >= 100)) |
{ |
CopyBits(&((GrafPtr)numberSrcMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&numbersSrc[digit], &r, srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &r ); |
#endif |
} |
r.left += 11; |
r.right += 11; |
digit = (workNumber) % 10; // Do 1's digit. |
CopyBits(&((GrafPtr)numberSrcMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&numbersSrc[digit], &r, srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &r ); |
#endif |
} |
#endif |
} |
//-------------------------------------------------------------- DrawFrame |
// This function is the "master" drawing function that calls all the aboveÉ |
// routines. It is called once per frame. |
void DrawFrame (void) |
{ |
Boolean bannerInFront = false; |
{ |
KeyMap theKeys; |
GetKeys(theKeys); |
if ((theKeys[1] & 0x004)) |
{ |
bannerInFront = true; |
} |
} |
if (!bannerInFront) |
{ |
DrawBanner(); |
} |
DrawTorches(); // Gee, draws the torches? |
DrawScoreFloaters(); |
DrawHand(); // Draws the hand? |
DrawEye(); // A clue to easing your documentation demandsÉ |
DrawPlayer(); // is to use "smart" names for your functions. |
CheckPlayerWrapAround(); // Check for player wrap-around. |
DrawEnemies(); // Handle all sphinx-type enemy drawing. |
DrawObelisks(); // draw the obelisks |
DrawPixelShatter(); // draw exploding pixels |
DrawLava(); // add sparkling lava |
if (bannerInFront) |
{ |
DrawBanner(); |
} |
} |
//-------------------------------------------------------------- GameQuitGraphics |
void GameQuitGraphics(void) |
{ |
short h,v; |
for(v = 0; v < 480; v += 24) |
{ |
for(h = 0; h < 640; h += 32) |
{ |
StartPixelShatter(h, v, 0, 0, kShatterLightningDust); |
} |
} |
CopyBits( &((GrafPtr)origBackSrcMap)->portBits, |
&((GrafPtr)backSrcMap)->portBits, |
&backSrcRect, &backSrcRect, srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &backSrcRect ); |
#endif |
} |
//-------------------------------------------------------------- GameIdleAnimation |
void GameIdleAnimation(void) |
{ |
// do our idle animation |
DSpContext_GetBackBuffer( gTheContext, kDSpBufferKind_Normal, &workSrcMap ); |
DumpBackToWorkMap(); // clear the screen |
DrawBanner(); |
DrawTorches(); |
HandlePixelShatter(); |
HandleLava(); |
DrawLava(); |
if (helpOpen) |
{ |
CopyBits(&((GrafPtr)helpSrcMap)->portBits, |
&((GrafPtr)workSrcMap)->portBits, |
&helpSrc, &helpDest, srcCopy, 0L); |
#ifdef USE_INVALID_RECTS |
DSpContext_InvalBackBufferRect( gTheContext, &helpDest ); |
#endif |
} |
DrawPixelShatter(); |
HandleLightning(); |
DSpContext_SwapBuffers( gTheContext, NULL, NULL ); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-10-14