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.
MoofWars/TTileCollection.cp
/* |
File: TTileCollection.cp |
Contains: A TileCollection is a set of tiles that can be used to draw a grid. |
Essentially, this class performs the same function that the TGraphicCollection |
class does, but it is designed just to draw 32x32x8 tiles. By making this |
code as specific as possible, this code is more than twice as fast as using |
TGraphics to draw the tiles. |
Written by: Timothy Carroll |
Copyright: Copyright © 1996-1999 by Apple Computer, Inc., All Rights Reserved. |
You may incorporate this Apple sample source code into your program(s) without |
restriction. This Apple sample source code has been provided "AS IS" and the |
responsibility for its operation is yours. You are not permitted to redistribute |
this Apple sample source code as "Apple sample source code" after having made |
changes. If you're going to re-distribute the source, we require that you make |
it clear in the source that the code was descended from Apple sample source |
code, but that you've made changes. |
Change History (most recent first): |
7/2/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1 |
1/23/97 Timothy Carroll Added include for Moofwars.h so that MrC will |
compile |
8/15/96 Timothy Carroll Initial Release |
*/ |
#include <Memory.h> |
#include <Resources.h> |
#include "Moofwars.h" |
#include "TTileCollection.h" |
#include "Scaling.h" |
#include "GridTilesFormat.h" |
const int kTileSize = 1024; |
const int kTileGroupSize = (kTileSize+1)*8; |
/************************************************************************************* |
Internal Declarations |
We will hold the list of created TTileCollection objects in a handle. This handle is |
automatically created the first time we load a TTileCollection and is deallocated when |
the list is empty. |
All of the allocation and deallocation is handled by the static NewCollection call. |
NewCollection has a few utility routines it calls on to manage the handle. Mainly they do |
the searching, insertion and deletion from the list. |
*************************************************************************************/ |
static Handle gTileCollectionList = NULL; |
static unsigned long gNumberItemsInList = 0; |
static OSErr InsertCollectionIntoList (TTileCollection *theCollection, UInt32 index); |
static OSErr DeleteCollectionFromList (UInt32 index); |
static OSErr SearchCollectionList (SInt16 resID, Boolean *found, UInt32 *index); |
/************************************************************************************* |
InsertCollectionIntoList |
This routine creates the handle if necessary, and otherwise inserts the TTileCollection |
into the list at the index location given. |
Assumptions: |
theCollection must be a legitimate TTileCollection -- no NULL parameters. |
index must be no more than 1 larger than gNumberItemsInList. ????? |
*************************************************************************************/ |
OSErr InsertCollectionIntoList (TTileCollection *theCollection, UInt32 index) |
{ |
OSErr theErr = noErr; |
#if qDebugging |
if (index > gNumberItemsInList) |
SIGNAL_ERROR ("\pAttempting to insert collection at invalid index") |
if (theCollection == NULL) |
SIGNAL_ERROR ("\pAttempting to insert a null collection into the list") |
#endif |
if (gTileCollectionList == NULL) |
{ |
gNumberItemsInList = 1; |
gTileCollectionList = NewHandleClear (sizeof (TTileCollection *)); |
theErr = MemError(); |
FAIL_OSERR (theErr, "\pCouldn't allocate a new handle of information") |
FAIL_NIL (gTileCollectionList, "\pCouldn't allocate a new handle of information") |
} |
else |
{ |
gNumberItemsInList++; |
SetHandleSize(gTileCollectionList,gNumberItemsInList*sizeof(TTileCollection *)); |
theErr = MemError(); |
FAIL_OSERR (theErr, "\pCouldn't resize the list handle") |
FAIL_NIL (gTileCollectionList, "\pCouldn't resize the list handle") |
// Shift the data to make room |
BlockMoveData( (*(TTileCollection ***)gTileCollectionList)+index, |
(*(TTileCollection ***)gTileCollectionList)+index+1, |
(gNumberItemsInList - index-1) * sizeof(TTileCollection *)); |
} |
// finally, set the new object in place |
*((*(TTileCollection ***) gTileCollectionList)+index) = theCollection; |
return noErr; |
error: |
if (theErr == noErr) |
theErr = paramErr; |
return theErr; |
} |
/************************************************************************************* |
DeleteCollectionFromList |
This routine removes the collection from the list and destroys it. If there are no more items |
in the list then we dispose of the handle. |
Assumptions: |
index must be within the list. |
*************************************************************************************/ |
OSErr DeleteCollectionFromList (UInt32 index) |
{ |
OSErr theErr; |
gNumberItemsInList--; |
// slide remaining elements up |
BlockMoveData( (*(TTileCollection ***)gTileCollectionList)+index+1, |
(*(TTileCollection ***)gTileCollectionList)+index, |
(gNumberItemsInList - index) * sizeof(TTileCollection *)); |
// cut back the storage and dispose of the handle if we have no items left |
if (gNumberItemsInList> 0) |
{ |
SetHandleSize((Handle) gTileCollectionList,gNumberItemsInList*sizeof(TTileCollection *)); |
theErr = MemError(); |
FAIL_OSERR (theErr, "\pCouldn't resize the list handle") |
FAIL_NIL (gTileCollectionList, "\pCouldn't resize the list handle") |
} |
else |
{ |
DisposeHandle (gTileCollectionList); |
gTileCollectionList = NULL; |
} |
return noErr; |
error: |
if (theErr == noErr) |
theErr = paramErr; |
return theErr; |
} |
/************************************************************************************* |
SearchCollectionList |
This routine searches through the list and attempts to find an existing TTileCollection with |
that resID. If it finds one with that resID, then it returns the index to that collection and |
sets found to true. If it doesn't find that resource, then it sets found to false AND sets the |
index to where it should be inserted into the list. |
*************************************************************************************/ |
OSErr SearchCollectionList (SInt16 resID, Boolean *found, UInt32 *index) |
{ |
UInt32 low = 0; |
UInt32 high = gNumberItemsInList; |
UInt32 tempIndex; |
TTileCollection *theItem; |
OSErr theErr = noErr; |
*found = false; |
while (low < high) |
{ |
tempIndex = (low+high) >> 1; |
theItem = (*(TTileCollection ***)gTileCollectionList)[tempIndex]; |
FAIL_NIL (theItem, "\pBad TTile object") |
if (resID < theItem->GetResID()) |
high = tempIndex; // element is below "high" |
else if (resID == theItem->GetResID()) |
{ |
*found = true; |
*index = tempIndex; |
return noErr; |
} |
else |
low = tempIndex+1; // element is above "low" |
} |
// use final calculations to put insert in the right place in the list |
*index = (low+high) >> 1; |
return noErr; |
error: |
if (theErr == noErr) |
theErr = paramErr; |
return theErr; |
} |
/************************************************************************************* |
TTileCollection::NewCollection |
This routine merely uses the routines we created above to properly create and load |
the TTileCollections. |
*************************************************************************************/ |
TTileCollection |
*TTileCollection::NewCollection (SInt16 resID) |
{ |
unsigned long listIndex; |
Boolean tableAlreadyExists; |
TTileCollection *newCollection = NULL; |
OSErr theErr; |
theErr = SearchCollectionList (resID, &tableAlreadyExists, &listIndex); |
FAIL_OSERR(theErr,"\pCouldn't search the collection list in TTileCollection::NewCollection") |
if (tableAlreadyExists) |
{ |
// find the existing collection and add 1 to the ref count. |
newCollection = (*(TTileCollection ***)gTileCollectionList)[listIndex]; |
newCollection->AddReference(); |
} |
else |
{ |
// create a new collection |
newCollection = new TTileCollection(resID); |
theErr = newCollection->CreateCollection (); |
FAIL_OSERR(theErr,"\pCouldn't create new TTileCollection") |
theErr = InsertCollectionIntoList(newCollection, listIndex); |
FAIL_OSERR(theErr, "\pCouldn't add new TTileCollection to list") |
newCollection->AddReference(); |
} |
return newCollection; |
error: |
if (newCollection != NULL) |
delete newCollection; |
return NULL; |
} |
/************************************************************************************* |
TTileCollection::AddReference |
*************************************************************************************/ |
void |
TTileCollection::AddReference (void) |
{ |
fReferenceCount++; |
} |
/************************************************************************************* |
TTileCollection::DisposeReference |
*************************************************************************************/ |
void |
TTileCollection::DisposeReference (void) |
{ |
fReferenceCount--; |
if (fReferenceCount == 0) |
{ |
UInt32 listIndex; |
Boolean tableEntry; |
OSErr theErr; |
theErr = SearchCollectionList (fResID, &tableEntry, &listIndex); |
FAIL_OSERR (theErr, "\pFailed to search the CollectionList") |
FAIL_FALSE (tableEntry, "\pFailed to find an existing TTileCollection in list") |
theErr = DeleteCollectionFromList(listIndex); |
FAIL_OSERR (theErr, "\pFailed to delete Collection from the list") |
delete this; |
} |
error: |
return; |
} |
/************************************************************************************* |
TTileCollection::TTileCollection |
All of the actual work is done in CreateCollection |
*************************************************************************************/ |
TTileCollection::TTileCollection (SInt16 resID) |
{ |
fResID = resID; |
fReferenceCount = 0; |
fNumberOfTiles = 0; |
fTiles = NULL; |
} |
/************************************************************************************* |
TTileCollection::~TTileCollection |
All of the actual work is done in DeleteCollection |
*************************************************************************************/ |
TTileCollection::~TTileCollection (void) |
{ |
if (fTiles != NULL) |
{ |
OSErr theErr = DestroyCollection(); |
FAIL_OSERR (theErr, "\pFailed to destroy the TTileCollection data") |
} |
error: |
return; |
} |
/************************************************************************************* |
TTileCollection::CreateCollection |
This routine uses the resource number we passed into the contructor to load the TTileCollection |
from the 'SptA' resource we created for it. Note that we don't make any assumptions about |
the resource file being used, so the correct resource file already needs to be opened for this |
call to work. |
*************************************************************************************/ |
OSErr TTileCollection::CreateCollection(void) |
{ |
OSErr theErr = noErr; |
TileCollectionResHeader **tiles; |
int loop; |
Ptr srcPtr, destPtr; |
// Load the 'TILE' resource and check to make sure we can read the header information. |
tiles = (TileCollectionResHeader **) Get1Resource (TileCollectionResType, fResID); |
theErr = ResError(); |
FAIL_OSERR (theErr, "\pFailed to load the TILE resource.") |
FAIL_NIL (tiles, "\pFailed to load the TILE resource.") |
if ( (**tiles).version != 0) SIGNAL_ERROR ("\pInvalid version number in TILE resource") |
if ( (**tiles).depth != 8) SIGNAL_ERROR ("\pInvalid Pixel Depth in TILE resource") |
fNumberOfTiles = (**tiles).numTiles; |
fTiles = NewHandle (fNumberOfTiles * kTileGroupSize); |
theErr = MemError(); |
FAIL_OSERR (theErr, "\pFailed to allocate memory for the tiles") |
FAIL_NIL (fTiles, "\pFailed to allocate memory for the tiles") |
srcPtr = (Ptr)(*tiles) + sizeof (TileCollectionResHeader); |
destPtr = (*fTiles); |
fTileOffset = (fNumberOfTiles * kTileSize) +1; |
for (loop = 0; loop < 8; loop++) |
{ |
BlockMoveData (srcPtr, destPtr, kTileSize*fNumberOfTiles); |
destPtr += fTileOffset; |
} |
// Completed successfully, cleanup and exit with no error; |
goto cleanup; |
error: |
if (theErr == noErr) |
theErr = paramErr; |
if (fTiles != NULL) |
DisposeHandle (fTiles); |
fTiles = NULL; |
cleanup: |
if (tiles != NULL) |
ReleaseResource ((Handle) tiles); |
return theErr; |
} |
/************************************************************************************* |
TTileCollection::DestroyCollection |
Throw away all of the objects that we're created. We do check for null TTile objects here, |
and properly skip null objects that might not have been finished from the create calls. |
*************************************************************************************/ |
OSErr |
TTileCollection::DestroyCollection (void) |
{ |
if (fTiles != NULL) |
DisposeHandle (fTiles); |
fTiles = NULL; |
return noErr; |
} |
/************************************************************************************* |
TTileCollection::LockCollection |
*************************************************************************************/ |
OSErr |
TTileCollection::LockCollection (void) |
{ |
OSErr theErr = noErr; |
MoveHHi (fTiles); |
theErr = MemError(); |
FAIL_OSERR (theErr, "\pCouldn't move fTiles handle high") |
HLock (fTiles); |
theErr = MemError(); |
FAIL_OSERR (theErr, "\pCouldn't lock fTiles handle") |
error: |
return theErr; |
} |
/************************************************************************************* |
TTileCollection::UnlockCollection |
*************************************************************************************/ |
OSErr |
TTileCollection::UnlockCollection (void) |
{ |
OSErr theErr = noErr; |
HUnlock (fTiles); |
theErr = MemError(); |
FAIL_OSERR (theErr, "\pCouldn't unlock fTiles handle") |
error: |
return theErr; |
} |
/************************************************************************************* |
TTileCollection::CopyImageUnclipped |
This is a set of optimized image copying routines that take advantage of alignment for some serious |
speed improvements. These routines take the destination pointer and assume that the image being |
copied is completely on the screen. If your routine can't determine which of these routines to |
call, call CopyImageClip instead. |
Now for a more detailed discussion of these routines and why we actually go about this. The main |
advantage to these routines is that their specialization allows them to be much faster than the |
generic copying loop in the TGraphic class. |
The fastest way to move memory on PPC is usually to load and store float doubles, which are 64 bits |
wide. The problem is that if you decide to move doubles, you need to guarantee alignment to an |
8 byte boundary, or your code will run slow on a 603 and 604 processor. For the generic sprite |
blitter, it was faster to just move longs and let the hardware deal with address misalignment. But |
for tiles, we can make copies of the same data at different alignments and use the correct data |
when drawing to the screen. In fact, we could do this for sprites too. The main advantage is that |
because we know the width of the tile, we can write a blitter loop that has no logic in it other |
than loads and stores. At one point, I did attempt to write a variable length blitter that did the |
same thing, but for small sprites, the overhead of checking for the correct sprite was always more |
than just drawing with longs. |
In any case, each of these blitters performs every load and every store on an exact boundary, with |
no misalignments. This results in much faster code in general, and also lets us load data into |
the floats and stores. |
Future possibilities: |
* The cache touch instructions might be useful to make sure that the source data is loaded well ahead |
of each time through the loop. This can help performance, and is also possible to do for the |
destination if the destination is cacheable. I haven't experimented with this yet, but probably |
will in the future. |
* Currently the largest number of loads for a single line is 7 (CopyImageUnclipped1). Because the |
next line starts immediately after the previous line in memory, we can probably replace 3 of the |
loads (load char, load char, load short) with a single load long, and use shifts to get the correct |
data. This won't do much to reduce the number of stores, but might improve performance slightly. |
*************************************************************************************/ |
/*************************************** |
TTileCollection::CopyImageUnclipped0 |
****************************************/ |
void |
TTileCollection::CopyImageUnclipped0 (UInt32 index, unsigned char *destPtr) |
{ |
register double double1, double2, double3, double4; |
unsigned char *srcPtr; // the current position in the sprite data |
int loop; |
int rowBytesLocal; // used to hold the rowbytes value to eliminate a load. |
#if qDebugging |
if (gDestPixMap == NULL) |
SIGNAL_ERROR ("\pAttempting to draw to a NULL destination pixmap") |
if (index >= fNumberOfTiles) |
// We're outside of the bounds of the Tiles table here. Debugger time! :-) |
SIGNAL_ERROR("\ptried to index a TTile that was out of bounds"); |
#endif |
srcPtr = (unsigned char *) ((*fTiles) + kTileSize*index); |
rowBytesLocal = gRowBytes; |
for (loop = 0; loop < 32; loop++) |
{ |
// load all the data into the registers |
double1 = *((double *) srcPtr); |
double2 = *((double *) srcPtr+1); |
double3 = *((double *) srcPtr+2); |
double4 = *((double *) srcPtr+3); |
// dump all the data out to the destination. |
*((double *) destPtr) = double1; |
*((double *) destPtr+1) = double2; |
*((double *) destPtr+2) = double3; |
*((double *) destPtr+3) = double4; |
srcPtr += 32; |
destPtr += rowBytesLocal; |
} |
error: |
return; |
} |
/*************************************** |
TTileCollection::CopyImageUnclipped1 |
****************************************/ |
void |
TTileCollection::CopyImageUnclipped1 (UInt32 index, unsigned char *destPtr) |
{ |
register double double1, double2, double3; |
register unsigned char char1,char2; |
register unsigned short short1; |
register unsigned long long1; |
unsigned char *srcPtr; // the current position in the sprite data |
int loop; |
int rowBytesLocal; // used to hold the rowbytes value to eliminate a load. |
#if qDebugging |
if (gDestPixMap == NULL) |
SIGNAL_ERROR ("\pAttempting to draw to a NULL destination pixmap") |
if (index >= fNumberOfTiles) |
// We're outside of the bounds of the Tiles table here. Debugger time! :-) |
SIGNAL_ERROR("\ptried to index a TTile that was out of bounds"); |
#endif |
srcPtr = (unsigned char *) ((*fTiles) + kTileSize*index + fTileOffset); |
rowBytesLocal = gRowBytes; |
for (loop = 0; loop < 32; loop++) |
{ |
// load all the data into the registers. We're one byte misaligned, so we need to load 7 bytes before |
// we hit the next 8-byte boundary. |
char1 = *((unsigned char *) srcPtr); |
short1 = *((unsigned short *) ((unsigned char *) srcPtr+1)); |
long1 = *((unsigned long *) ((unsigned char *) srcPtr+3)); |
double1 = *((double *) ((unsigned char *) srcPtr+7)); |
double2 = *((double *) ((unsigned char *) srcPtr+15)); |
double3 = *((double *) ((unsigned char *) srcPtr+23)); |
char2 = *((unsigned char *) ((unsigned char *) srcPtr+31)); |
srcPtr += 32; |
// dump all the data out to the destination. |
*((unsigned char *) ((unsigned char *) destPtr)) = char1; |
*((unsigned short *) ((unsigned char *) destPtr+1)) = short1; |
*((unsigned long *) ((unsigned char *) destPtr+3)) = long1; |
*((double *) ((unsigned char *) destPtr+7)) = double1; |
*((double *) ((unsigned char *) destPtr+15)) = double2; |
*((double *) ((unsigned char *) destPtr+23)) = double3; |
*((unsigned char *) ((unsigned char *) destPtr+31)) = char2; |
destPtr += rowBytesLocal; |
} |
error: |
return; |
} |
/*************************************** |
TTileCollection::CopyImageUnclipped2 |
****************************************/ |
void |
TTileCollection::CopyImageUnclipped2 (UInt32 index, unsigned char *destPtr) |
{ |
register double double1, double2, double3; |
register unsigned short short1, short2; |
register unsigned long long1; |
unsigned char *srcPtr; // the current position in the sprite data |
int loop; |
int rowBytesLocal; // used to hold the rowbytes value to eliminate a load. |
#if qDebugging |
if (gDestPixMap == NULL) |
SIGNAL_ERROR ("\pAttempting to draw to a NULL destination pixmap") |
if (index >= fNumberOfTiles) |
// We're outside of the bounds of the Tiles table here. Debugger time! :-) |
SIGNAL_ERROR("\ptried to index a TTile that was out of bounds"); |
#endif |
srcPtr = (unsigned char *) ((*fTiles) + kTileSize*index + fTileOffset*2); |
rowBytesLocal = gRowBytes; |
for (loop = 0; loop < 32; loop++) |
{ |
// load all the data into the registers |
short1 = *((unsigned short *) srcPtr); |
long1 = *((unsigned long *) ((unsigned char *) srcPtr+2)); |
double1 = *((double *) ((unsigned char *) srcPtr+6)); |
double2 = *((double *) ((unsigned char *) srcPtr+14)); |
double3 = *((double *) ((unsigned char *) srcPtr+22)); |
short2 = *((unsigned short *) ((unsigned char *) srcPtr+30)); |
// dump all the data out to the destination. |
*((unsigned short *) ((unsigned char *) destPtr)) = short1; |
*((unsigned long *) ((unsigned char *) destPtr+2)) = long1; |
*((double *) ((unsigned char *) destPtr+6)) = double1; |
*((double *) ((unsigned char *) destPtr+14)) = double2; |
*((double *) ((unsigned char *) destPtr+22)) = double3; |
*((unsigned short *) ((unsigned char *) destPtr+30)) = short2; |
srcPtr += 32; |
destPtr += rowBytesLocal; |
} |
error: |
return; |
} |
/*************************************** |
TTileCollection::CopyImageUnclipped3 |
****************************************/ |
void |
TTileCollection::CopyImageUnclipped3 (UInt32 index, unsigned char *destPtr) |
{ |
register double double1, double2, double3; |
register unsigned char char1,char2; |
register unsigned short short1; |
register unsigned long long1; |
unsigned char *srcPtr; // the current position in the sprite data |
int loop; |
int rowBytesLocal; // used to hold the rowbytes value to eliminate a load. |
#if qDebugging |
if (gDestPixMap == NULL) |
SIGNAL_ERROR ("\pAttempting to draw to a NULL destination pixmap") |
if (index >= fNumberOfTiles) |
// We're outside of the bounds of the Tiles table here. Debugger time! :-) |
SIGNAL_ERROR("\ptried to index a TTile that was out of bounds"); |
#endif |
srcPtr = (unsigned char *) ((*fTiles) + kTileSize*index + fTileOffset*3); |
rowBytesLocal = gRowBytes; |
for (loop = 0; loop < 32; loop++) |
{ |
// load all the data into the registers |
char1 = *((unsigned char *) srcPtr); |
long1 = *((unsigned long *) ((unsigned char *)srcPtr+1)); |
double1 = *((double *) ((unsigned char *)srcPtr+5)); |
double2 = *((double *) ((unsigned char *)srcPtr+13)); |
double3 = *((double *) ((unsigned char *)srcPtr+21)); |
char2 = *((unsigned char *) ((unsigned char *)srcPtr+29)); |
short1 = *((unsigned short *) ((unsigned char *)srcPtr+30)); |
// dump all the data out to the destination. |
*((unsigned char *) ((unsigned char *) destPtr)) = char1; |
*((unsigned long *) ((unsigned char *) destPtr+1)) = long1; |
*((double *) ((unsigned char *) destPtr+5)) = double1; |
*((double *) ((unsigned char *) destPtr+13)) = double2; |
*((double *) ((unsigned char *) destPtr+21)) = double3; |
*((unsigned char *) ((unsigned char *) destPtr+29)) = char2; |
*((unsigned short *)((unsigned char *) destPtr+30)) = short1; |
srcPtr += 32; |
destPtr += rowBytesLocal; |
} |
error: |
return; |
} |
/*************************************** |
TTileCollection::CopyImageUnclipped4 |
****************************************/ |
void |
TTileCollection::CopyImageUnclipped4 (UInt32 index, unsigned char *destPtr) |
{ |
register double double1, double2, double3; |
register unsigned long long1, long2; |
unsigned char *srcPtr; // the current position in the sprite data |
int loop; |
int rowBytesLocal; // used to hold the rowbytes value to eliminate a load. |
#if qDebugging |
if (gDestPixMap == NULL) |
SIGNAL_ERROR ("\pAttempting to draw to a NULL destination pixmap") |
if (index >= fNumberOfTiles) |
// We're outside of the bounds of the Tiles table here. Debugger time! :-) |
SIGNAL_ERROR("\ptried to index a TTile that was out of bounds"); |
#endif |
//srcPtr = (unsigned char *) ((*fTiles) + alignment * fTileOffset + kTileSize*index); |
srcPtr = (unsigned char *) ((*fTiles) + kTileSize*index + 4*fTileOffset); |
rowBytesLocal = gRowBytes; |
for (loop = 0; loop < 32; loop++) |
{ |
long1 = *((unsigned long *) ((unsigned char *)srcPtr)); |
double1 = *((double *) ((unsigned char *)srcPtr+4)); |
double2 = *((double *) ((unsigned char *)srcPtr+12)); |
double3 = *((double *) ((unsigned char *)srcPtr+20)); |
long2 = *((unsigned long *) ((unsigned char *)srcPtr+28)); |
// dump all the data out to the destination. |
*((unsigned long *) ((unsigned char *) destPtr)) = long1; |
*((double *) ((unsigned char *) destPtr+4)) = double1; |
*((double *) ((unsigned char *) destPtr+12)) = double2; |
*((double *) ((unsigned char *) destPtr+20)) = double3; |
*((unsigned long *) ((unsigned char *) destPtr+28)) = long2; |
srcPtr += 32; |
destPtr += rowBytesLocal; |
} |
error: |
return; |
} |
/*************************************** |
TTileCollection::CopyImageUnclipped5 |
****************************************/ |
void |
TTileCollection::CopyImageUnclipped5 (UInt32 index, unsigned char *destPtr) |
{ |
register double double1, double2, double3; |
register unsigned char char1,char2; |
register unsigned short short1; |
register unsigned long long1; |
unsigned char *srcPtr; // the current position in the sprite data |
int loop; |
int rowBytesLocal; // used to hold the rowbytes value to eliminate a load. |
#if qDebugging |
if (gDestPixMap == NULL) |
SIGNAL_ERROR ("\pAttempting to draw to a NULL destination pixmap") |
if (index >= fNumberOfTiles) |
// We're outside of the bounds of the Tiles table here. Debugger time! :-) |
SIGNAL_ERROR("\ptried to index a TTile that was out of bounds"); |
#endif |
srcPtr = (unsigned char *) ((*fTiles) + kTileSize*index + 5*fTileOffset); |
rowBytesLocal = gRowBytes; |
for (loop = 0; loop < 32; loop++) |
{ |
// load all the data into the registers |
char1 = *((unsigned char *) ((unsigned char *) srcPtr+0)); |
short1 = *((unsigned short *) ((unsigned char *) srcPtr+1)); |
double1 = *((double *) ((unsigned char *) srcPtr+3)); |
double2 = *((double *) ((unsigned char *) srcPtr+11)); |
double3 = *((double *) ((unsigned char *) srcPtr+19)); |
long1 = *((unsigned long *) ((unsigned char *) srcPtr+27)); |
char2 = *((unsigned char *) ((unsigned char *) srcPtr+31)); |
*((unsigned char *) ((unsigned char *) destPtr+0)) = char1; |
*((unsigned short *)((unsigned char *) destPtr+1)) = short1; |
*((double *) ((unsigned char *) destPtr+3)) = double1; |
*((double *) ((unsigned char *) destPtr+11)) = double2; |
*((double *) ((unsigned char *) destPtr+19)) = double3; |
*((unsigned long *) ((unsigned char *) destPtr+27)) = long1; |
*((unsigned char *) ((unsigned char *) destPtr+31)) = char2; |
srcPtr += 32; |
destPtr += rowBytesLocal; |
} |
error: |
return; |
} |
/*************************************** |
TTileCollection::CopyImageUnclipped6 |
****************************************/ |
void |
TTileCollection::CopyImageUnclipped6 (UInt32 index, unsigned char *destPtr) |
{ |
register double double1, double2, double3; |
register unsigned short short1, short2; |
register unsigned long long1; |
unsigned char *srcPtr; // the current position in the sprite data |
int loop; |
int rowBytesLocal; // used to hold the rowbytes value to eliminate a load. |
#if qDebugging |
if (gDestPixMap == NULL) |
SIGNAL_ERROR ("\pAttempting to draw to a NULL destination pixmap") |
if (index >= fNumberOfTiles) |
// We're outside of the bounds of the Tiles table here. Debugger time! :-) |
SIGNAL_ERROR("\ptried to index a TTile that was out of bounds"); |
#endif |
//srcPtr = (unsigned char *) ((*fTiles) + alignment * fTileOffset + kTileSize*index); |
srcPtr = (unsigned char *) ((*fTiles) + kTileSize*index + 6*fTileOffset); |
rowBytesLocal = gRowBytes; |
for (loop = 0; loop < 32; loop++) |
{ |
short1 = *((unsigned short *) ((unsigned char *) srcPtr+0)); |
double1 = *((double *) ((unsigned char *) srcPtr+2)); |
double2 = *((double *) ((unsigned char *) srcPtr+10)); |
double3 = *((double *) ((unsigned char *) srcPtr+18)); |
long1 = *((unsigned long *) ((unsigned char *) srcPtr+26)); |
short2 = *((unsigned short *) ((unsigned char *) srcPtr+30)); |
*((unsigned short *)((unsigned char *) destPtr+0)) = short1; |
*((double *) ((unsigned char *) destPtr+2)) = double1; |
*((double *) ((unsigned char *) destPtr+10)) = double2; |
*((double *) ((unsigned char *) destPtr+18)) = double3; |
*((unsigned long *) ((unsigned char *) destPtr+26)) = long1; |
*((unsigned short *)((unsigned char *) destPtr+30)) = short2; |
srcPtr += 32; |
destPtr += rowBytesLocal; |
} |
error: |
return; |
} |
/*************************************** |
TTileCollection::CopyImageUnclipped7 |
****************************************/ |
void |
TTileCollection::CopyImageUnclipped7 (UInt32 index, unsigned char *destPtr) |
{ |
register double double1, double2, double3; |
register unsigned char char1,char2; |
register unsigned short short1; |
register unsigned long long1; |
unsigned char *srcPtr; // the current position in the sprite data |
int loop; |
int rowBytesLocal; // used to hold the rowbytes value to eliminate a load. |
#if qDebugging |
if (gDestPixMap == NULL) |
SIGNAL_ERROR ("\pAttempting to draw to a NULL destination pixmap") |
if (index >= fNumberOfTiles) |
// We're outside of the bounds of the Tiles table here. Debugger time! :-) |
SIGNAL_ERROR("\ptried to index a TTile that was out of bounds"); |
#endif |
//srcPtr = (unsigned char *) ((*fTiles) + alignment * fTileOffset + kTileSize*index); |
srcPtr = (unsigned char *) ((*fTiles) + kTileSize*index+ 7*fTileOffset); |
rowBytesLocal = gRowBytes; |
for (loop = 0; loop < 32; loop++) |
{ |
char1 = *((unsigned char *) ((unsigned char *) srcPtr+0)); |
double1 = *((double *) ((unsigned char *) srcPtr+1)); |
double2 = *((double *) ((unsigned char *) srcPtr+9)); |
double3 = *((double *) ((unsigned char *) srcPtr+17)); |
long1 = *((unsigned long *) ((unsigned char *) srcPtr+25)); |
short1 = *((unsigned short *) ((unsigned char *) srcPtr+29)); |
char2 = *((unsigned char *) ((unsigned char *) srcPtr+31)); |
*((unsigned char *) ((unsigned char *) destPtr+0)) = char1; |
*((double *) ((unsigned char *) destPtr+1)) = double1; |
*((double *) ((unsigned char *) destPtr+9)) = double2; |
*((double *) ((unsigned char *) destPtr+17)) = double3; |
*((unsigned long *) ((unsigned char *) destPtr+25)) = long1; |
*((unsigned short *)((unsigned char *) destPtr+29)) = short1; |
*((unsigned char *) ((unsigned char *) destPtr+31)) = char2; |
srcPtr += 32; |
destPtr += rowBytesLocal; |
} |
error: |
return; |
} |
/************************************************************************************* |
TTileCollection::CopyImageClipped |
CopyImageClipped also draws the image, but always checks to make sure that it is inside the |
designated drawing area set in the clipping rectangle for our drawing code. For the moment, this |
version of the code always does the drawing using simple long moves without regard to alignment. |
*************************************************************************************/ |
void |
TTileCollection::CopyImageClipped (UInt32 index, SInt32 top, SInt32 left) |
{ |
#if qDebugging |
if (gDestPixMap == NULL) |
SIGNAL_ERROR ("\pAttempting to draw to a NULL destination pixmap") |
if (EmptyRect (&gClipRect)) |
SIGNAL_ERROR ("\pEmpty Clipping Region") |
if (index >= fNumberOfTiles) |
// We're outside of the bounds of the Tiles table here. Debugger time! :-) |
SIGNAL_ERROR("\ptried to index a TTile that was out of bounds"); |
#endif |
// We'll do all our calculations in variables rather than use a structure. |
// hopefully this should speed things up |
SInt32 destTop, destBottom, destLeft, destRight; |
destTop = top; |
destBottom = top+32; |
destLeft = left; |
destRight = left+32; |
// determine if the spite needs to be drawn at all |
if (destTop >= gClipRect.bottom || destBottom <= gClipRect.top || |
destLeft >= gClipRect.right || destRight <= gClipRect.left ) |
// no need to draw, goodbye |
return; |
// determine if the sprite will be clipped |
if (destTop < gClipRect.top || destBottom > gClipRect.bottom || |
destLeft < gClipRect.left || destRight > gClipRect.right) |
{ |
UInt32 clipTop, clipBottom, clipLeft, clipRight; |
unsigned char *srcPtr; // the current position in the tile data |
unsigned char *destPtr; // the current position in the destination pixmap |
unsigned long blitwidth, blitheight; |
unsigned long yLoop; |
unsigned long sourceOffset, destOffset; |
// Calculate clipping rectangle. |
clipTop = destTop < gClipRect.top ? gClipRect.top - destTop : 0; |
clipBottom = destBottom > gClipRect.bottom ? gClipRect.bottom-destTop : destBottom-destTop; |
clipLeft = destLeft < gClipRect.left ? gClipRect.left-destLeft : 0; |
clipRight = destRight > gClipRect.right ? gClipRect.right-destLeft : destRight-destLeft; |
// calculate source and destination pointers |
srcPtr = ( unsigned char * )( *fTiles ) + kTileSize*index; |
srcPtr += 32*clipTop+clipLeft; |
destPtr = gDestBaseAddr + (top + clipTop) * gRowBytes + left + clipLeft; |
// how much do we actually need to draw? |
blitwidth = clipRight - clipLeft; |
blitheight = clipBottom - clipTop; |
sourceOffset = 32-blitwidth; |
destOffset = gRowBytes-blitwidth; |
for (yLoop = 0; yLoop < blitheight; yLoop++) |
{ |
register unsigned long sixteenblits, blitloop; |
sixteenblits = blitwidth >> 4; |
for ( blitloop = 0; blitloop < sixteenblits; blitloop++) |
{ |
register unsigned long temp1, temp2, temp3, temp4; |
temp1 = ((unsigned long *) srcPtr)[0]; |
temp2 = ((unsigned long *) srcPtr)[1]; |
temp3 = ((unsigned long *) srcPtr)[2]; |
temp4 = ((unsigned long *) srcPtr)[3]; |
((unsigned long *) destPtr)[0] = temp1; |
((unsigned long *) destPtr)[1] = temp2; |
((unsigned long *) destPtr)[2] = temp3; |
((unsigned long *) destPtr)[3] = temp4; |
srcPtr += 16; |
destPtr += 16; |
} |
// move any remaining data, up to 15 bytes total |
if (blitwidth & 0x8) |
{ |
register unsigned long temp1, temp2; |
temp1 = ((unsigned long *) srcPtr)[0]; |
temp2 = ((unsigned long *) srcPtr)[1]; |
((unsigned long *) destPtr)[0] = temp1; |
((unsigned long *) destPtr)[1] = temp2; |
srcPtr += 8; |
destPtr += 8; |
} |
if (blitwidth & 0x4) |
{ |
register unsigned long temp1; |
temp1 = *((unsigned long *) srcPtr); |
srcPtr +=4; |
*((unsigned long *) destPtr) = temp1; |
destPtr +=4; |
} |
if (blitwidth & 0x2) |
{ |
register unsigned short temp1; |
temp1 = *((unsigned short *) srcPtr); |
srcPtr +=2; |
*((unsigned short *) destPtr) = temp1; |
destPtr +=2; |
} |
if (blitwidth & 0x1) |
*destPtr++ = *srcPtr++; |
srcPtr += sourceOffset; |
destPtr += destOffset; |
} |
} |
else |
{ |
// Unclipped, so calculate the destination pointer and alignment and call the appropriate unclipped case. |
unsigned char *destPtr; // the current position in the destination pixmap |
long alignment; |
destPtr = gDestBaseAddr + top * gRowBytes + left; |
alignment = ((long) destPtr) & 0x07; |
switch (alignment) |
{ |
case 0: CopyImageUnclipped0 (index, destPtr); break; |
case 1: CopyImageUnclipped1 (index, destPtr); break; |
case 2: CopyImageUnclipped2 (index, destPtr); break; |
case 3: CopyImageUnclipped3 (index, destPtr); break; |
case 4: CopyImageUnclipped4 (index, destPtr); break; |
case 5: CopyImageUnclipped5 (index, destPtr); break; |
case 6: CopyImageUnclipped6 (index, destPtr); break; |
case 7: CopyImageUnclipped7 (index, destPtr); break; |
} |
} |
error: |
return; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-10-14