home *** CD-ROM | disk | FTP | other *** search
- /* -----------------------------------------------------------------------------------
- -----------------------------------------------------------------------------------
- BlitPixieRotated.c
-
- by Brian Roddy
-
- 6/3/97
-
- These are blitters for rendering rotated versions of a sprite. The API is simple.
- Use SWSetSpriteRotation to set the sprite's rotation. The amount of rotation must be
- between 0 to the constant kNumberOfRotationSteps. Calling SWSetSpriteRotation with
- 0 as the rotation will reset the sprite to use the standard blitting routines.
-
- Example Use:
-
- SWSetSpriteRotation(mySpritePtr, 3); // Rotate it
-
- SWSetSpriteRotation(mySpritePtr, 0); // Reset it back to normal
-
-
- Note that all rotation is clipped to frameRect of the sprite. In other words, the sprite
- is rotated within its bounding rectangle. Thus if you have a long skinny sprite, part
- of it will be lost while rotating it. The fix to this problem is to make sure that you
- store the sprite in the resource with enough white space around it that it can rotate
- fully and have nothing lost.
-
- Also note that rotation is done on-the-fly. As a result, it can
- be fairly slow and the pixels in the frames don't match what shows up on the screen.
- This means that functions which rely on the sprite's mask, such as SWPixelCollision,
- won't work as expected. Thus using the pixel or mask collisions routines with
- rotated sprites won't work accurately.
-
- Because blitting rotated sprites is slow and there are collision issues, there is
- a function called CreateRotatedFrameFromFrame that can be called to create a new
- frame object which contains a rotated version of a frame. In this way the frame is
- precomputed and blits quickly. Example Use:
-
- for (currentRotation = 1; currentRotation < 8; currentRotation++)
- CreateRotatedFrameFromFrame(gSpriteWorld,
- myFrames[0],
- &myFrames[currentRotation],
- currentRotation);
-
- Imagine an asteroids like game with a single ship image. This would fill up a frame
- array with rotated versions of the ship stored in frame zero.
-
- One additional note. We need the sin and cos function to do this rotation. For speed
- we precompute the values of sin and cos corresponding to each amount of rotation.
- Since we often want to use 8, 16, 32, or 64 degrees of rotations, arrays of these
- are predefined in our code.
-
- If we wish to use a different number for kNumberOfRotationSteps, then we need to
- uncomment the #define DYNAMICALLY_GENERATE_TABLE in the header file for this code.
- When DYNAMICALLY_GENERATE_TABLE is defined, we have to call InitializeRotationTables()
- to fill up the tables with values. This requires including MathLib. If this
- sounds confusing, just leave kNumberOfRotationSteps with the value 8, 16, 32, or 64.
-
- -------------------------------------------------------------------------------------
- Implementation Notes:
-
- A little about how this works. The equations for rotation are:
- x' = cos(rotation) * x + sin(rotation) * y
- y' = cos(rotation) * y - sin(rotation) * x
-
- While rendering we precalculate as much of this equation as possible. But we still
- need to compute the corresponding source x and y for each pixel we blit.
-
- Note that all of this is done with floating point, which on the PPC is fairly quick
- but on the 68K is slow. Versions of these which fake floating point math using
- integers would make the 68K version faster. 68K users should just make use of
- the functionality to premake rotated frames of all they need and use these to blit.
-
- Also, there's probably a faster method for doing this, but I haven't learned it
- yet, so don't hesitate to let me know a better way.
-
- This source code is available for free use.
-
- -----------------------------------------------------------------------------------
- ----------------------------------------------------------------------------------- */
-
- #ifndef __SWCOMMON__
- #include "SWCommonHeaders.h"
- #endif
-
- #ifndef __SPRITEWORLDUTILS__
- #include "SpriteWorldUtils.h"
- #endif
-
- #ifndef __TOOLUTILS__
- #include <ToolUtils.h>
- #endif
-
- #ifndef __OSUTILS__
- #include <OSUtils.h>
- #endif
-
- #ifndef __QUICKDRAW__
- #include <Quickdraw.h>
- #endif
-
- #ifndef __QDOFFSCREEN__
- #include <QDOffscreen.h>
- #endif
-
- #ifndef __SPRITEWORLD__
- #include "SpriteWorld.h"
- #endif
-
-
- #include "BlitPixieRotated.h"
-
- // See section on sin/cosin caching below for more detail about this
- #ifdef DYNAMICALLY_GENERATE_TABLE
- #include <math.h>
- #endif
-
- ///--------------------------------------------------------------------------------------
- ///--------------------------------------------------------------------------------------
- /// Public API:
- ///--------------------------------------------------------------------------------------
- ///--------------------------------------------------------------------------------------
-
- #pragma mark ------------- Public API ---------------
-
- SW_FUNC OSErr CreateRotatedFrameFromFrame(
- SpriteWorldPtr destSpriteWorld,
- FramePtr originalFrameP,
- FramePtr* newFramePPtr,
- int amountOfRotation) {
- FramePtr newFrameP;
- OSErr err;
-
- if (! ((destSpriteWorld->pixelDepth == 8) ||
- (destSpriteWorld->pixelDepth == 16))) {
- // Only works in 8 or 16 bit modes
- SWSetStickyIfError( kWrongDepthErr );
- return kWrongDepthErr;
- }
-
- // Copy the frame
- SWCopyFrame(destSpriteWorld, originalFrameP, newFramePPtr, true);
- newFrameP = *newFramePPtr;
-
- // Lock everything so we can rotate it
- SWLockFrame(originalFrameP);
- SWLockFrame(newFrameP);
-
- // Clear the old image by painting white, our mask color
- SetGWorld(newFrameP->framePort, nil);
- ForeColor(whiteColor);
- PaintRect(&newFrameP->maskPort->portRect);
- ForeColor(blackColor); // Change back when done!
-
-
- // Rotate the image, saving it in the new frame
- if (destSpriteWorld->pixelDepth == 8) {
- BlitPixieRotateFrame8Bit(originalFrameP, newFrameP,
- &originalFrameP->frameRect, &newFrameP->frameRect, amountOfRotation);
- } else if (destSpriteWorld->pixelDepth == 16) {
- BlitPixieRotateFrame16Bit(originalFrameP, newFrameP,
- &originalFrameP->frameRect, &newFrameP->frameRect, amountOfRotation);
- }
-
- // Make a mask for the new rotated tile image
- err = SWUpdateFrameMasks(destSpriteWorld, newFrameP);
-
- // Return success
- SWSetStickyIfError( err );
- return err;
- }
-
-
- SW_FUNC OSErr SWSetSpriteRotation(
- SpritePtr srcSpriteP,
- unsigned char rotation)
- {
- short currentPixelDepth;
- OSErr err;
-
-
- currentPixelDepth = (*srcSpriteP->frameArray[0]->framePort->portPixMap)->pixelSize;
- err = kWrongDepthErr;
-
- srcSpriteP->rotation = rotation;
-
- if (currentPixelDepth == 8)
- {
- if (rotation == 0)
- srcSpriteP->frameDrawProc = BlitPixie8BitMaskDrawProc;
- else
- srcSpriteP->frameDrawProc = BlitPixie8BitRotatedMaskDrawProc;
- err = noErr;
- }
- else if (currentPixelDepth == 16)
- {
- if (rotation == 0)
- srcSpriteP->frameDrawProc = BlitPixieAllBitMaskDrawProc;
- else
- srcSpriteP->frameDrawProc = BlitPixie16BitRotatedMaskDrawProc;
- err = noErr;
- }
- SWSetStickyIfError( err );
- return err;
- }
-
-
- SW_FUNC unsigned char SWGetSpriteRotation(SpritePtr srcSpriteP) {
- if ((srcSpriteP->frameDrawProc == BlitPixie8BitRotatedMaskDrawProc) ||
- (srcSpriteP->frameDrawProc == BlitPixie16BitRotatedMaskDrawProc))
- return srcSpriteP->rotation;
- else
- return 0;
- }
-
-
- ///--------------------------------------------------------------------------------------
- ///--------------------------------------------------------------------------------------
- /// Internal Functions
- ///--------------------------------------------------------------------------------------
- ///--------------------------------------------------------------------------------------
-
-
- #pragma mark ---------- Sin/Cos Caching ------------
- ///--------------------------------------------------------------------------------------
- /// Sine/Cosine caching:
- ///--------------------------------------------------------------------------------------
- Boolean gRotationInitialized = false;
-
- // if this is defined, we can use whatever value for kNumberOfRotationSteps that
- // we want. We just have to call InitializeRotationTables to fill up the
- // tables with values...
- #ifdef DYNAMICALLY_GENERATE_TABLE
- double sineArray[kNumberOfRotationSteps];
- double cosineArray[kNumberOfRotationSteps];
-
- void InitializeRotationTables(void) {
- int i;
- double curRotation;
- for(i = 0; i < kNumberOfRotationSteps; i++) {
- curRotation = ((double)i / (double)kNumberOfRotationSteps) * 2.0 * 3.1415926535;
- sineArray[i] = sin(curRotation);
- cosineArray[i] = cos(curRotation);
- }
- gRotationInitialized = true;
- }
- #else
- // ...Normally though we just want to use 8, 16, 32, or 64 rotations. For these
- // we have precomputed them and automatically can put them in our array. This means
- // we don't have to include any Math Library and it means we don't have to call
- // InitializeRotationTables.
-
- // The tables for 8 steps of rotation
- #if (kNumberOfRotationSteps == 8)
- double sineArray[8] = {0.0, 0.7071067811706742, 1.0, 0.7071067812341675, 8.979306187484326E-11, -0.707106781107181, -1.0, -0.7071067812976605};
- double cosineArray[8] = {1.0, 0.7071067812024209, 4.489653093742163E-11, -0.7071067811389276, -1.0, -0.7071067812659142, -1.346895928122649E-10, 0.7071067810754346};
- #endif
-
- // The tables for 16 steps of rotation
- #if (kNumberOfRotationSteps == 16)
- double sineArray[16] = {0.0, 0.38268343235472, 0.7071067811706742, 0.9238795324984009, 1.0, 0.9238795325327632, 0.7071067812341675, 0.3826834324376778, 8.979306187484326E-11, -0.3826834322717618, -0.707106781107181, -0.9238795324640386, -1.0, -0.9238795325671256, -0.7071067812976605, -0.38268343252063575};
- double cosineArray[16] = {1.0, 0.9238795325155821, 0.7071067812024209, 0.382683432396199, 4.489653093742163E-11, -0.38268343231324103, -0.7071067811389276, -0.9238795324812198, -1.0, -0.9238795325499445, -0.7071067812659142, -0.38268343247915676, -1.346895928122649E-10, 0.38268343223028284, 0.7071067810754346, 0.9238795324468575};
- #endif
-
- // The tables for 32 steps of rotation
- #if (kNumberOfRotationSteps == 32)
- double sineArray[32] = {0.0, 0.19509032201062404, 0.38268343235472, 0.5555702330056034, 0.7071067811706742, 0.8314696122869558, 0.9238795324984009, 0.9807852803955665, 1.0, 0.9807852804130842, 0.9238795325327632, 0.831469612336842, 0.7071067812341675, 0.5555702330802637, 0.3826834324376778, 0.19509032209869162, 8.979306187484326E-11, -0.1950903219225562, -0.3826834322717618, -0.5555702329309433, -0.707106781107181, -0.8314696122370696, -0.9238795324640386, -0.9807852803780487, -1.0, -0.980785280430602, -0.9238795325671256, -0.8314696123867287, -0.7071067812976605, -0.5555702331549235, -0.38268343252063575, -0.19509032218675934};
- double cosineArray[32] = {1.0, 0.9807852804043253, 0.9238795325155821, 0.831469612311899, 0.7071067812024209, 0.5555702330429335, 0.382683432396199, 0.1950903220546578, 4.489653093742163E-11, -0.19509032196659007, -0.38268343231324103, -0.5555702329682733, -0.7071067811389276, -0.8314696122620125, -0.9238795324812198, -0.9807852803868076, -1.0, -0.9807852804218431, -0.9238795325499445, -0.8314696123617852, -0.7071067812659142, -0.5555702331175935, -0.38268343247915676, -0.19509032214272548, -1.346895928122649E-10, 0.19509032187852235, 0.38268343223028284, 0.5555702328936128, 0.7071067810754346, 0.8314696122121265, 0.9238795324468575, 0.9807852803692898};
- #endif
-
- // The tables for 64 steps of rotation
- #if (kNumberOfRotationSteps == 64)
- double sineArray[64] = {0.0, 0.09801714032676807, 0.19509032201062404, 0.2902846772464067, 0.38268343235472, 0.47139673681362415, 0.5555702330056034, 0.6343932841484619, 0.7071067811706742, 0.7730104533467158, 0.8314696122869558, 0.8819212643338048, 0.9238795324984009, 0.9569403357216197, 0.9807852803955665, 0.9951847266680713, 1.0, 0.9951847266768725, 0.9807852804130842, 0.9569403357476852, 0.9238795325327632, 0.8819212643761328, 0.831469612336842, 0.7730104534036799, 0.7071067812341675, 0.6343932842178729, 0.5555702330802637, 0.4713967368928147, 0.3826834324376778, 0.29028467733233315, 0.19509032209869162, 0.0980171404161287, 8.979306187484326E-11, -0.09801714023740733, -0.1950903219225562, -0.29028467716047995, -0.3826834322717618, -0.4713967367344339, -0.5555702329309433, -0.6343932840790509, -0.707106781107181, -0.7730104532897519, -0.8314696122370696, -0.8819212642914767, -0.9238795324640386, -0.9569403356955543, -0.9807852803780487, -0.99518472665927, -1.0, -0.9951847266856738, -0.980785280430602, -0.9569403357737509, -0.9238795325671256, -0.8819212644184612, -0.8314696123867287, -0.7730104534606443, -0.7071067812976605, -0.6343932842872835, -0.5555702331549235, -0.4713967369720047, -0.38268343252063575, -0.2902846774182598, -0.19509032218675934, -0.09801714050548939};
- double cosineArray[64] = {1.0, 0.9951847266724719, 0.9807852804043253, 0.9569403357346525, 0.9238795325155821, 0.8819212643549688, 0.831469612311899, 0.7730104533751978, 0.7071067812024209, 0.6343932841831673, 0.5555702330429335, 0.4713967368532193, 0.382683432396199, 0.2902846772893701, 0.1950903220546578, 0.09801714037144836, 4.489653093742163E-11, -0.09801714028208768, -0.19509032196659007, -0.2902846772034435, -0.38268343231324103, -0.4713967367740291, -0.5555702329682733, -0.6343932841137564, -0.7071067811389276, -0.7730104533182337, -0.8314696122620125, -0.8819212643126406, -0.9238795324812198, -0.956940335708587, -0.9807852803868076, -0.9951847266636706, -1.0, -0.9951847266812732, -0.9807852804218431, -0.9569403357607181, -0.9238795325499445, -0.8819212643972969, -0.8314696123617852, -0.7730104534321619, -0.7071067812659142, -0.634393284252578, -0.5555702331175935, -0.4713967369324095, -0.38268343247915676, -0.2902846773752965, -0.19509032214272548, -0.09801714046080905, -1.346895928122649E-10, 0.09801714019272699, 0.19509032187852235, 0.29028467711751665, 0.38268343223028284, 0.4713967366948383, 0.5555702328936128, 0.634393284044345, 0.7071067810754346, 0.7730104532612699, 0.8314696122121265, 0.8819212642703126, 0.9238795324468575, 0.9569403356825215, 0.9807852803692898, 0.9951847266548695};
- #endif
-
- // In these cases, our Rotation Tables are already initialized so this function
- // does nothing. We leave it here for consistency.
- void InitializeRotationTables(void) {}
-
- #endif
-
-
- ///--------------------------------------------------------------------------------------
- /// The Blitting Functions:
- ///--------------------------------------------------------------------------------------
- extern SInt8 gSWmmuMode;
- extern SpritePtr gCurrentSpriteBeingDrawn;
-
-
- #pragma mark ------------ 8 Bit Blitters -------------
-
- ///--------------------------------------------------------------------------------------
- // BlitPixieRotateFrame8Bit
- ///--------------------------------------------------------------------------------------
- /// This version allows it to be called directly with a specified rotation.
- /// No need for any globals to be set.
-
- SW_FUNC void BlitPixieRotateFrame8Bit(
- FramePtr srcFrameP,
- FramePtr dstFrameP,
- Rect *srcRect,
- Rect *dstRect,
- short rotation)
- {
- Rect dstBlitRect = *dstRect;
- Rect srcBlitRect = *srcRect;
- unsigned long numBytesPerRow;
- unsigned long srcBaseOffset;
-
- SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
- SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 8);
- SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 8);
- SW_ASSERT(srcFrameP->maskPort != NULL);
-
- BP_CLIP_RECT(dstFrameP->frameRect, srcBlitRect, dstBlitRect);
- START_32_BIT_MODE
-
- // calculate the offset to the first byte of the source
- srcBaseOffset = srcFrameP->scanLinePtrArray[srcBlitRect.top - srcFrameP->frameRect.top] +
- srcBlitRect.left;
-
- // calculate the number of bytes in a row
- numBytesPerRow = (dstBlitRect.right - dstBlitRect.left);
-
- BlitPixieMask8BitRotated(
- // calculate the address of the first byte of the source
- (unsigned char *)(srcFrameP->frameBaseAddr + srcBaseOffset),
-
- // calculate the address of the first byte of the destination
- (unsigned char *)(dstFrameP->frameBaseAddr +
- (dstFrameP->scanLinePtrArray[dstBlitRect.top]) + dstBlitRect.left),
-
- // calculate the address of the first byte of the mask
- (unsigned char *)(srcFrameP->maskBaseAddr + srcBaseOffset),
-
- // calculate the number of rows to blit
- dstBlitRect.bottom - dstBlitRect.top,
-
- // number of bytes in a row (duh!)
- numBytesPerRow,
-
- srcFrameP->frameRowBytes,
- dstFrameP->frameRowBytes,
-
- rotation
- );
-
- END_32_BIT_MODE
- }
-
-
- /// This version of the drawproc is used by the system, and should be used as a sprite
- /// draw proc. It requires that the global "gCurrentSpriteBeingDrawn" be set before being called.
- SW_FUNC void BlitPixie8BitRotatedMaskDrawProc(
- FramePtr srcFrameP,
- FramePtr dstFrameP,
- Rect *srcRect,
- Rect *dstRect)
- {
- Rect dstBlitRect = *dstRect;
- Rect srcBlitRect = *srcRect;
- unsigned long numBytesPerRow;
- unsigned long srcBaseOffset;
- unsigned long rotation = 0;
-
- SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
- SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 8);
- SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 8);
- SW_ASSERT(srcFrameP->maskPort != NULL);
-
- if (gCurrentSpriteBeingDrawn != NULL)
- rotation = gCurrentSpriteBeingDrawn->rotation;
-
- BP_CLIP_RECT(dstFrameP->frameRect, srcBlitRect, dstBlitRect);
- START_32_BIT_MODE
-
- // calculate the offset to the first byte of the source
- srcBaseOffset = srcFrameP->scanLinePtrArray[srcBlitRect.top - srcFrameP->frameRect.top] +
- srcBlitRect.left;
-
- // calculate the number of bytes in a row
- numBytesPerRow = (dstBlitRect.right - dstBlitRect.left);
-
- BlitPixieMask8BitRotated(
- // calculate the address of the first byte of the source
- (unsigned char *)(srcFrameP->frameBaseAddr + srcBaseOffset),
-
- // calculate the address of the first byte of the destination
- (unsigned char *)(dstFrameP->frameBaseAddr +
- (dstFrameP->scanLinePtrArray[dstBlitRect.top]) + dstBlitRect.left),
-
- // calculate the address of the first byte of the mask
- (unsigned char *)(srcFrameP->maskBaseAddr + srcBaseOffset),
-
- // calculate the number of rows to blit
- dstBlitRect.bottom - dstBlitRect.top,
-
- // number of bytes in a row (duh!)
- numBytesPerRow,
-
- srcFrameP->frameRowBytes,
- dstFrameP->frameRowBytes,
-
- rotation
- );
-
- END_32_BIT_MODE
- }
-
-
- ///--------------------------------------------------------------------------------------
- // BlitPixieMask8BitRotated
- ///--------------------------------------------------------------------------------------
- void BlitPixieMask8BitRotated(
- register unsigned char *srcPixelP,
- register unsigned char *dstPixelP,
- register unsigned char *maskPixelP,
- register unsigned long rowsToCopy,
- register unsigned long numBytesPerRow,
- register unsigned long srcOffset,
- register unsigned long dstOffset,
- register unsigned long curRotation)
- {
- register unsigned char *rotatedPixelLocationP;
- register unsigned char *rotatedMaskLocationP;
- register int x, y, curOff;
- int roundedNewX, roundedNewY;
-
- // We pull all of these out to here so in our loop
- // all we do is the minimal number of additions
- register double cosineOfRotation = cosineArray[curRotation];
- register double sineOfRotation = sineArray[curRotation];
- double midx = numBytesPerRow / 2;
- double midy = rowsToCopy / 2;
- register double curX = midx + ((0 - midx) * cosineOfRotation) +
- ((0 - midy) * sineOfRotation);
- register double curY = midy + ((0 - midy) * cosineOfRotation) -
- ((0 - midx) * sineOfRotation);
- double xInc = sineOfRotation - (cosineOfRotation * numBytesPerRow);
- double yInc = cosineOfRotation + (sineOfRotation * numBytesPerRow);
-
-
- // Now we go through each pixel in the destination and compute the corresponding
- // source pixel. We could do this in reverse (go through source, and compute the
- // destination) and it would be faster, but round off error leaves holes in the
- // image. This is the correct way.
- for (y = 0; y < rowsToCopy; y++) {
- for (x = 0; x < numBytesPerRow; x++) {
- curX += cosineOfRotation;
- curY -= sineOfRotation;
-
- // round it to an integer for the array lookup
- roundedNewX = curX;
- roundedNewY = curY;
-
- // Super safe bounds checking (for now)
- // We only rotate inside our bounds
- // we could potentially speed this up to figure out where to start
- if ((roundedNewX >= 0) && (roundedNewY >= 0) &&
- (roundedNewX < numBytesPerRow) && (roundedNewY < rowsToCopy)) {
- // Compute the memory location corresponding to the new x and y.
- // potential place to speed it up is here
- curOff = roundedNewX + (srcOffset * roundedNewY);
- rotatedMaskLocationP = maskPixelP + curOff;
- if (*rotatedMaskLocationP == 0) {
- rotatedPixelLocationP = srcPixelP + curOff;
- dstPixelP[x] = *rotatedPixelLocationP;
- }
- }
- }
- // bump down one row and reset x back to 0
- curX += xInc;
- curY += yInc;
-
- // Go to next row.
- dstPixelP += dstOffset;
- }
- }
-
- #pragma mark ----------- 16 Bit Blitters -------------
- ///--------------------------------------------------------------------------------------
- // BlitPixieRotateFrame16Bit
- ///--------------------------------------------------------------------------------------
- /// This version allows it to be called directly with a specified rotation.
- /// No need for any globals to be set.
-
- SW_FUNC void BlitPixieRotateFrame16Bit(
- FramePtr srcFrameP,
- FramePtr dstFrameP,
- Rect *srcRect,
- Rect *dstRect,
- short rotation)
- {
- Rect dstBlitRect = *dstRect;
- Rect srcBlitRect = *srcRect;
- unsigned long numBytesPerRow;
- unsigned long srcBaseOffset;
-
- SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
- SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 16);
- SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 16);
- SW_ASSERT(srcFrameP->maskPort != NULL);
-
- BP_CLIP_RECT(dstFrameP->frameRect, srcBlitRect, dstBlitRect);
- START_32_BIT_MODE
-
- // calculate the offset to the first byte of the source
- srcBaseOffset = srcFrameP->scanLinePtrArray[srcBlitRect.top - srcFrameP->frameRect.top] +
- srcBlitRect.left;
-
- // calculate the number of bytes in a row
- numBytesPerRow = (dstBlitRect.right - dstBlitRect.left) << 1;
-
- BlitPixieMask16BitRotated(
- // calculate the address of the first byte of the source
- (unsigned short *)(srcFrameP->frameBaseAddr + srcBaseOffset),
-
- // calculate the address of the first byte of the destination
- (unsigned short *)(dstFrameP->frameBaseAddr +
- (dstFrameP->scanLinePtrArray[dstBlitRect.top]) +
- (dstBlitRect.left << 1)),
-
- // calculate the address of the first byte of the mask
- (unsigned short *)(srcFrameP->maskBaseAddr + srcBaseOffset),
-
- // calculate the number of rows to blit
- dstBlitRect.bottom - dstBlitRect.top,
-
- // number of bytes in a row (duh!)
- numBytesPerRow,
-
- srcFrameP->frameRowBytes,
- dstFrameP->frameRowBytes,
-
- rotation
- );
-
- END_32_BIT_MODE
- }
-
-
- ///--------------------------------------------------------------------------------------
- // BlitPixie16BitRotatedMaskDrawProc
- ///--------------------------------------------------------------------------------------
- /// This version of the drawproc is used by the system, and should be used as a sprite
- /// draw proc. It requires that the global "gCurrentSpriteBeingDrawn" be set before being called.
-
- SW_FUNC void BlitPixie16BitRotatedMaskDrawProc(
- FramePtr srcFrameP,
- FramePtr dstFrameP,
- Rect *srcRect,
- Rect *dstRect)
- {
- Rect dstBlitRect = *dstRect;
- Rect srcBlitRect = *srcRect;
- unsigned long numBytesPerRow;
- unsigned long srcBaseOffset;
- unsigned long rotation = 0;
-
- SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
- SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 16);
- SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 16);
- SW_ASSERT(srcFrameP->maskPort != NULL);
-
- if (gCurrentSpriteBeingDrawn != NULL)
- rotation = gCurrentSpriteBeingDrawn->rotation;
-
- BP_CLIP_RECT(dstFrameP->frameRect, srcBlitRect, dstBlitRect);
- START_32_BIT_MODE
-
- // calculate the offset to the first byte of the source
- srcBaseOffset = srcFrameP->scanLinePtrArray[srcBlitRect.top - srcFrameP->frameRect.top] +
- srcBlitRect.left;
-
- // calculate the number of bytes in a row
- numBytesPerRow = (dstBlitRect.right - dstBlitRect.left) << 1;
-
- BlitPixieMask16BitRotated(
- // calculate the address of the first byte of the source
- (unsigned short *)(srcFrameP->frameBaseAddr + srcBaseOffset),
-
- // calculate the address of the first byte of the destination
- (unsigned short *)(dstFrameP->frameBaseAddr +
- (dstFrameP->scanLinePtrArray[dstBlitRect.top]) +
- (dstBlitRect.left << 1)),
-
- // calculate the address of the first byte of the mask
- (unsigned short *)(srcFrameP->maskBaseAddr + srcBaseOffset),
-
- // calculate the number of rows to blit
- dstBlitRect.bottom - dstBlitRect.top,
-
- // number of bytes in a row (duh!)
- numBytesPerRow,
-
- srcFrameP->frameRowBytes,
- dstFrameP->frameRowBytes,
-
- rotation
- );
-
- END_32_BIT_MODE
- }
-
-
- ///--------------------------------------------------------------------------------------
- // BlitPixieMask16BitRotated
- ///--------------------------------------------------------------------------------------
- void BlitPixieMask16BitRotated(
- register unsigned short *srcPixelP,
- register unsigned short *dstPixelP,
- register unsigned short *maskPixelP,
- register unsigned long rowsToCopy,
- register unsigned long numBytesPerRow,
- register unsigned long srcOffset,
- register unsigned long dstOffset,
- register unsigned long curRotation)
- {
- register unsigned short *rotatedPixelLocationP;
- register unsigned short *rotatedMaskLocationP;
- register int x, y, curOff;
- register int roundedNewX, roundedNewY;
-
- // We pull all of these out to here so in our loop
- // all we do is the minimal number of additions
- register unsigned long pixelWidth = numBytesPerRow / 2;
- register double cosineOfRotation = cosineArray[curRotation];
- register double sineOfRotation = sineArray[curRotation];
- double midx = pixelWidth / 2;
- double midy = rowsToCopy / 2;
- register double curX = midx + ((0 - midx) * cosineOfRotation) +
- ((0 - midy) * sineOfRotation);
- register double curY = midy + ((0 - midy) * cosineOfRotation) -
- ((0 - midx) * sineOfRotation);
- double xInc = sineOfRotation - (cosineOfRotation * pixelWidth);
- double yInc = cosineOfRotation + (sineOfRotation * pixelWidth);
-
- // divide the offsets by 2 to get number of shorts from bytes
- srcOffset >>= 1;
- dstOffset >>= 1;
-
- // Now we go through each pixel in the destination and compute the corresponding
- // source pixel. We could do this in reverse (go through source, and compute the
- // destination) and it would be faster, but round off error leaves holes in the
- // image. This is the correct way.
- for (y = 0; y < rowsToCopy; y++) {
- for (x = 0; x < pixelWidth; x++) {
- curX += cosineOfRotation;
- curY -= sineOfRotation;
-
- // round it to an integer for the array lookup
- roundedNewX = curX;
- roundedNewY = curY;
-
- // Super safe bounds checking (for now)
- // We only rotate inside our bounds
- // we could potentially speed this up to figure out where to start
- if ((roundedNewX >= 0) && (roundedNewY >= 0) &&
- (roundedNewX < pixelWidth) && (roundedNewY < rowsToCopy)) {
- // Compute the memory location corresponding to the new x and y.
- // potential place to speed it up is here
- curOff = roundedNewX + (srcOffset * roundedNewY);
- rotatedMaskLocationP = maskPixelP + curOff;
- if (*rotatedMaskLocationP == 0) {
- rotatedPixelLocationP = srcPixelP + curOff;
- dstPixelP[x] = *rotatedPixelLocationP;
- }
- }
- }
- // bump down one row and reset x back to 0
- curX += xInc;
- curY += yInc;
-
- // Go to next row.
- dstPixelP += dstOffset;
- }
- }
-
-
-