home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1999 Spring / macformat-077.iso / Shareware Plus / Development / SpriteWorld 2.2 / SpriteWorld files / Utils / Brian's Extensions / BlitPixieRotated.c next >
Encoding:
C/C++ Source or Header  |  1999-01-14  |  27.1 KB  |  680 lines  |  [TEXT/CWIE]

  1. /*  -----------------------------------------------------------------------------------
  2.     -----------------------------------------------------------------------------------
  3.     BlitPixieRotated.c
  4.     
  5.     by Brian Roddy
  6.     
  7.     6/3/97
  8.  
  9.     These are blitters for rendering rotated versions of a sprite.  The API is simple.
  10.     Use SWSetSpriteRotation to set the sprite's rotation.  The amount of rotation must be 
  11.     between 0 to the constant kNumberOfRotationSteps.  Calling SWSetSpriteRotation with
  12.     0 as the rotation will reset the sprite to use the standard blitting routines.
  13.     
  14.     Example Use:
  15.     
  16.     SWSetSpriteRotation(mySpritePtr, 3);  // Rotate it
  17.         
  18.     SWSetSpriteRotation(mySpritePtr, 0);  // Reset it back to normal
  19.     
  20.     
  21.     Note that all rotation is clipped to frameRect of the sprite.  In other words, the sprite
  22.     is rotated within its bounding rectangle.  Thus if you have a long skinny sprite, part
  23.     of it will be lost while rotating it.  The fix to this problem is to make sure that you 
  24.     store the sprite in the resource with enough white space around it that it can rotate 
  25.     fully and have nothing lost.
  26.     
  27.     Also note that rotation is done on-the-fly.  As a result, it can 
  28.     be fairly slow and the pixels in the frames don't match what shows up on the screen.  
  29.     This means that functions which rely on the sprite's mask, such as SWPixelCollision, 
  30.     won't work as expected.  Thus using the pixel or mask collisions routines with 
  31.     rotated sprites won't work accurately.
  32.     
  33.     Because blitting rotated sprites is slow and there are collision issues, there is 
  34.     a function called CreateRotatedFrameFromFrame that can be called to create a new 
  35.     frame object which contains a rotated version of a frame. In this way the frame is 
  36.     precomputed and blits quickly.  Example Use:
  37.     
  38.     for (currentRotation = 1; currentRotation < 8; currentRotation++) 
  39.         CreateRotatedFrameFromFrame(gSpriteWorld, 
  40.                                     myFrames[0], 
  41.                                     &myFrames[currentRotation], 
  42.                                     currentRotation);
  43.     
  44.     Imagine an asteroids like game with a single ship image.  This would fill up a frame
  45.     array with rotated versions of the ship stored in frame zero. 
  46.     
  47.     One additional note.  We need the sin and cos function to do this rotation.  For speed
  48.     we precompute the values of sin and cos corresponding to each amount of rotation.
  49.     Since we often want to use 8, 16, 32, or 64 degrees of rotations, arrays of these
  50.     are predefined in our code.  
  51.     
  52.     If we wish to use a different number for kNumberOfRotationSteps, then we need to 
  53.     uncomment the #define DYNAMICALLY_GENERATE_TABLE in the header file for this code.
  54.     When DYNAMICALLY_GENERATE_TABLE is defined, we have to call InitializeRotationTables() 
  55.     to fill up the tables with values.  This requires including MathLib.  If this
  56.     sounds confusing, just leave kNumberOfRotationSteps with the value 8, 16, 32, or 64.
  57.     
  58.     -------------------------------------------------------------------------------------
  59.     Implementation Notes:
  60.  
  61.     A little about how this works.  The equations for rotation are:
  62.         x' = cos(rotation) * x + sin(rotation) * y
  63.         y' = cos(rotation) * y - sin(rotation) * x
  64.         
  65.     While rendering we precalculate as much of this equation as possible.  But we still
  66.     need to compute the corresponding source x and y for each pixel we blit.
  67.     
  68.     Note that all of this is done with floating point, which on the PPC is fairly quick
  69.     but on the 68K is slow.  Versions of these which fake floating point math using
  70.     integers would make the 68K version faster.  68K users should just make use of
  71.     the functionality to premake rotated frames of all they need and use these to blit.
  72.  
  73.     Also, there's probably a faster method for doing this, but I haven't learned it
  74.     yet, so don't hesitate to let me know a better way.
  75.  
  76.     This source code is available for free use.
  77.  
  78.     ----------------------------------------------------------------------------------- 
  79.     ----------------------------------------------------------------------------------- */
  80.  
  81. #ifndef __SWCOMMON__
  82. #include "SWCommonHeaders.h"
  83. #endif
  84.  
  85. #ifndef __SPRITEWORLDUTILS__
  86. #include "SpriteWorldUtils.h"
  87. #endif
  88.  
  89. #ifndef __TOOLUTILS__
  90. #include <ToolUtils.h>
  91. #endif
  92.  
  93. #ifndef __OSUTILS__
  94. #include <OSUtils.h>
  95. #endif
  96.  
  97. #ifndef __QUICKDRAW__
  98. #include <Quickdraw.h>
  99. #endif
  100.  
  101. #ifndef __QDOFFSCREEN__
  102. #include <QDOffscreen.h>
  103. #endif
  104.  
  105. #ifndef __SPRITEWORLD__
  106. #include "SpriteWorld.h"
  107. #endif
  108.  
  109.  
  110. #include "BlitPixieRotated.h"
  111.  
  112. // See section on sin/cosin caching below for more detail about this
  113. #ifdef DYNAMICALLY_GENERATE_TABLE
  114. #include <math.h>
  115. #endif
  116.  
  117. ///--------------------------------------------------------------------------------------
  118. ///--------------------------------------------------------------------------------------
  119. /// Public API:
  120. ///--------------------------------------------------------------------------------------
  121. ///--------------------------------------------------------------------------------------
  122.  
  123. #pragma mark ------------- Public API ---------------
  124.  
  125. SW_FUNC OSErr CreateRotatedFrameFromFrame(
  126.     SpriteWorldPtr     destSpriteWorld,
  127.     FramePtr         originalFrameP, 
  128.     FramePtr*         newFramePPtr, 
  129.     int             amountOfRotation) {
  130.     FramePtr newFrameP;
  131.     OSErr err;
  132.     
  133.     if (! ((destSpriteWorld->pixelDepth == 8) ||
  134.             (destSpriteWorld->pixelDepth == 16))) {
  135.         // Only works in 8 or 16 bit modes
  136.         SWSetStickyIfError( kWrongDepthErr );
  137.         return kWrongDepthErr;
  138.     }
  139.  
  140.         // Copy the frame
  141.     SWCopyFrame(destSpriteWorld, originalFrameP, newFramePPtr, true);
  142.     newFrameP = *newFramePPtr;
  143.     
  144.         // Lock everything so we can rotate it
  145.     SWLockFrame(originalFrameP);
  146.     SWLockFrame(newFrameP);
  147.  
  148.         // Clear the old image by painting white, our mask color
  149.     SetGWorld(newFrameP->framePort, nil);
  150.     ForeColor(whiteColor);
  151.     PaintRect(&newFrameP->maskPort->portRect);
  152.     ForeColor(blackColor);    // Change back when done!
  153.     
  154.     
  155.         // Rotate the image, saving it in the new frame
  156.     if (destSpriteWorld->pixelDepth == 8) {
  157.         BlitPixieRotateFrame8Bit(originalFrameP, newFrameP,
  158.             &originalFrameP->frameRect, &newFrameP->frameRect, amountOfRotation);
  159.     } else if (destSpriteWorld->pixelDepth == 16) {
  160.         BlitPixieRotateFrame16Bit(originalFrameP, newFrameP,
  161.             &originalFrameP->frameRect, &newFrameP->frameRect, amountOfRotation);
  162.     } 
  163.     
  164.         // Make a mask for the new rotated tile image
  165.     err = SWUpdateFrameMasks(destSpriteWorld, newFrameP);
  166.  
  167.         // Return success
  168.     SWSetStickyIfError( err );
  169.     return err;
  170. }
  171.  
  172.  
  173. SW_FUNC OSErr SWSetSpriteRotation(
  174.     SpritePtr srcSpriteP,
  175.     unsigned char rotation) 
  176. {
  177.     short         currentPixelDepth;
  178.     OSErr        err;
  179.     
  180.     
  181.     currentPixelDepth = (*srcSpriteP->frameArray[0]->framePort->portPixMap)->pixelSize;
  182.     err = kWrongDepthErr;
  183.     
  184.     srcSpriteP->rotation = rotation;
  185.     
  186.     if (currentPixelDepth == 8)
  187.     {
  188.         if (rotation == 0)
  189.             srcSpriteP->frameDrawProc = BlitPixie8BitMaskDrawProc;
  190.         else
  191.             srcSpriteP->frameDrawProc = BlitPixie8BitRotatedMaskDrawProc;
  192.         err = noErr;
  193.     }
  194.     else if (currentPixelDepth == 16)
  195.     {
  196.         if (rotation == 0)
  197.             srcSpriteP->frameDrawProc = BlitPixieAllBitMaskDrawProc;
  198.         else
  199.             srcSpriteP->frameDrawProc = BlitPixie16BitRotatedMaskDrawProc;
  200.         err = noErr;
  201.     }
  202.     SWSetStickyIfError( err );
  203.     return err;
  204. }
  205.  
  206.  
  207. SW_FUNC unsigned char SWGetSpriteRotation(SpritePtr srcSpriteP) {
  208.     if ((srcSpriteP->frameDrawProc == BlitPixie8BitRotatedMaskDrawProc) ||
  209.         (srcSpriteP->frameDrawProc == BlitPixie16BitRotatedMaskDrawProc))
  210.         return srcSpriteP->rotation;
  211.     else 
  212.         return 0;
  213. }
  214.  
  215.  
  216. ///--------------------------------------------------------------------------------------
  217. ///--------------------------------------------------------------------------------------
  218. /// Internal Functions
  219. ///--------------------------------------------------------------------------------------
  220. ///--------------------------------------------------------------------------------------
  221.  
  222.  
  223. #pragma mark ---------- Sin/Cos Caching ------------
  224. ///--------------------------------------------------------------------------------------
  225. /// Sine/Cosine caching:
  226. ///--------------------------------------------------------------------------------------
  227. Boolean gRotationInitialized = false;
  228.  
  229. // if this is defined, we can use whatever value for kNumberOfRotationSteps that
  230. // we want.  We just have to call InitializeRotationTables to fill up the
  231. // tables with values...
  232. #ifdef DYNAMICALLY_GENERATE_TABLE
  233. double sineArray[kNumberOfRotationSteps];
  234. double cosineArray[kNumberOfRotationSteps];
  235.  
  236. void InitializeRotationTables(void) {
  237.     int i;
  238.     double curRotation;
  239.     for(i = 0; i < kNumberOfRotationSteps; i++) {
  240.         curRotation = ((double)i / (double)kNumberOfRotationSteps) * 2.0 * 3.1415926535;
  241.         sineArray[i] = sin(curRotation);
  242.         cosineArray[i] = cos(curRotation);
  243.     }
  244.     gRotationInitialized = true;
  245. }
  246. #else
  247. // ...Normally though we just want to use 8, 16, 32, or 64 rotations.  For these
  248. // we have precomputed them and automatically can put them in our array.  This means
  249. // we don't have to include any Math Library and it means we don't have to call 
  250. // InitializeRotationTables.
  251.  
  252. // The tables for 8 steps of rotation
  253. #if (kNumberOfRotationSteps == 8)
  254. double sineArray[8] = {0.0, 0.7071067811706742, 1.0, 0.7071067812341675, 8.979306187484326E-11, -0.707106781107181, -1.0, -0.7071067812976605};
  255. double cosineArray[8] = {1.0, 0.7071067812024209, 4.489653093742163E-11, -0.7071067811389276, -1.0, -0.7071067812659142, -1.346895928122649E-10, 0.7071067810754346};
  256. #endif
  257.  
  258. // The tables for 16 steps of rotation
  259. #if (kNumberOfRotationSteps == 16)
  260. 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};
  261. 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};
  262. #endif
  263.  
  264. // The tables for 32 steps of rotation
  265. #if (kNumberOfRotationSteps == 32)
  266. 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};
  267. 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};
  268. #endif
  269.  
  270. // The tables for 64 steps of rotation
  271. #if (kNumberOfRotationSteps == 64)
  272. 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};
  273. 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};
  274. #endif
  275.  
  276. // In these cases, our Rotation Tables are already initialized so this function
  277. // does nothing.  We leave it here for consistency.
  278. void InitializeRotationTables(void) {}  
  279.  
  280. #endif
  281.  
  282.  
  283. ///--------------------------------------------------------------------------------------
  284. /// The Blitting Functions:
  285. ///--------------------------------------------------------------------------------------
  286. extern SInt8                 gSWmmuMode;
  287. extern SpritePtr            gCurrentSpriteBeingDrawn;
  288.  
  289.  
  290. #pragma mark ------------ 8 Bit Blitters -------------
  291.  
  292. ///--------------------------------------------------------------------------------------
  293. //        BlitPixieRotateFrame8Bit
  294. ///--------------------------------------------------------------------------------------
  295. /// This version allows it to be called directly with a specified rotation.
  296. /// No need for any globals to be set.
  297.  
  298. SW_FUNC void BlitPixieRotateFrame8Bit(
  299.     FramePtr srcFrameP,
  300.     FramePtr dstFrameP,
  301.     Rect *srcRect,
  302.     Rect *dstRect,
  303.     short rotation)
  304. {
  305.     Rect dstBlitRect = *dstRect;
  306.     Rect srcBlitRect = *srcRect;
  307.     unsigned long         numBytesPerRow;
  308.     unsigned long         srcBaseOffset;
  309.     
  310.     SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
  311.     SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 8);
  312.     SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 8);
  313.     SW_ASSERT(srcFrameP->maskPort != NULL);
  314.  
  315.     BP_CLIP_RECT(dstFrameP->frameRect, srcBlitRect, dstBlitRect);    
  316.     START_32_BIT_MODE
  317.  
  318.         // calculate the offset to the first byte of the source
  319.     srcBaseOffset = srcFrameP->scanLinePtrArray[srcBlitRect.top - srcFrameP->frameRect.top] + 
  320.         srcBlitRect.left;
  321.  
  322.         // calculate the number of bytes in a row
  323.     numBytesPerRow = (dstBlitRect.right - dstBlitRect.left);
  324.  
  325.     BlitPixieMask8BitRotated(
  326.             // calculate the address of the first byte of the source
  327.         (unsigned char *)(srcFrameP->frameBaseAddr + srcBaseOffset),
  328.  
  329.             // calculate the address of the first byte of the destination
  330.         (unsigned char *)(dstFrameP->frameBaseAddr + 
  331.             (dstFrameP->scanLinePtrArray[dstBlitRect.top]) + dstBlitRect.left),
  332.  
  333.             // calculate the address of the first byte of the mask
  334.         (unsigned char *)(srcFrameP->maskBaseAddr + srcBaseOffset),
  335.  
  336.             // calculate the number of rows to blit
  337.         dstBlitRect.bottom - dstBlitRect.top,
  338.  
  339.             // number of bytes in a row (duh!)
  340.         numBytesPerRow,
  341.  
  342.         srcFrameP->frameRowBytes,
  343.         dstFrameP->frameRowBytes,
  344.  
  345.         rotation
  346.         );
  347.  
  348.     END_32_BIT_MODE
  349. }
  350.  
  351.  
  352. /// This version of the drawproc is used by the system, and should be used as a sprite
  353. /// draw proc.  It requires that the global "gCurrentSpriteBeingDrawn" be set before being called.
  354. SW_FUNC void BlitPixie8BitRotatedMaskDrawProc(
  355.     FramePtr srcFrameP,
  356.     FramePtr dstFrameP,
  357.     Rect *srcRect,
  358.     Rect *dstRect)
  359. {
  360.     Rect dstBlitRect = *dstRect;
  361.     Rect srcBlitRect = *srcRect;
  362.     unsigned long         numBytesPerRow;
  363.     unsigned long         srcBaseOffset;
  364.     unsigned long         rotation = 0;
  365.     
  366.     SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
  367.     SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 8);
  368.     SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 8);
  369.     SW_ASSERT(srcFrameP->maskPort != NULL);
  370.     
  371.     if (gCurrentSpriteBeingDrawn != NULL)
  372.         rotation = gCurrentSpriteBeingDrawn->rotation;
  373.  
  374.     BP_CLIP_RECT(dstFrameP->frameRect, srcBlitRect, dstBlitRect);    
  375.     START_32_BIT_MODE
  376.  
  377.         // calculate the offset to the first byte of the source
  378.     srcBaseOffset = srcFrameP->scanLinePtrArray[srcBlitRect.top - srcFrameP->frameRect.top] + 
  379.         srcBlitRect.left;
  380.  
  381.         // calculate the number of bytes in a row
  382.     numBytesPerRow = (dstBlitRect.right - dstBlitRect.left);
  383.  
  384.     BlitPixieMask8BitRotated(
  385.             // calculate the address of the first byte of the source
  386.         (unsigned char *)(srcFrameP->frameBaseAddr + srcBaseOffset),
  387.  
  388.             // calculate the address of the first byte of the destination
  389.         (unsigned char *)(dstFrameP->frameBaseAddr + 
  390.             (dstFrameP->scanLinePtrArray[dstBlitRect.top]) + dstBlitRect.left),
  391.  
  392.             // calculate the address of the first byte of the mask
  393.         (unsigned char *)(srcFrameP->maskBaseAddr + srcBaseOffset),
  394.  
  395.             // calculate the number of rows to blit
  396.         dstBlitRect.bottom - dstBlitRect.top,
  397.  
  398.             // number of bytes in a row (duh!)
  399.         numBytesPerRow,
  400.  
  401.         srcFrameP->frameRowBytes,
  402.         dstFrameP->frameRowBytes,
  403.  
  404.         rotation
  405.         );
  406.  
  407.     END_32_BIT_MODE
  408. }
  409.  
  410.  
  411. ///--------------------------------------------------------------------------------------
  412. //        BlitPixieMask8BitRotated
  413. ///--------------------------------------------------------------------------------------
  414. void BlitPixieMask8BitRotated(
  415.     register unsigned char *srcPixelP,
  416.     register unsigned char *dstPixelP,
  417.     register unsigned char *maskPixelP,
  418.     register unsigned long rowsToCopy,
  419.     register unsigned long numBytesPerRow,
  420.     register unsigned long srcOffset,
  421.     register unsigned long dstOffset,
  422.     register unsigned long curRotation)
  423. {
  424.     register unsigned char *rotatedPixelLocationP;
  425.     register unsigned char *rotatedMaskLocationP;
  426.     register int x, y, curOff;
  427.     int roundedNewX, roundedNewY;
  428.  
  429.     // We pull all of these out to here so in our loop
  430.     // all we do is the minimal number of additions
  431.     register double cosineOfRotation = cosineArray[curRotation];
  432.     register double sineOfRotation = sineArray[curRotation];
  433.     double midx = numBytesPerRow / 2;
  434.     double midy = rowsToCopy / 2;    
  435.     register double curX = midx + ((0 - midx) * cosineOfRotation) +
  436.                               ((0 - midy) * sineOfRotation);
  437.     register double curY = midy + ((0 - midy) * cosineOfRotation) -
  438.                                       ((0 - midx) * sineOfRotation);
  439.     double xInc = sineOfRotation - (cosineOfRotation * numBytesPerRow);
  440.     double yInc = cosineOfRotation + (sineOfRotation * numBytesPerRow);
  441.     
  442.     
  443.     // Now we go through each pixel in the destination and compute the corresponding
  444.     // source pixel.  We could do this in reverse (go through source, and compute the
  445.     // destination) and it would be faster, but round off error leaves holes in the
  446.     // image.  This is the correct way.
  447.     for (y = 0; y < rowsToCopy; y++) {
  448.         for (x = 0; x < numBytesPerRow; x++) {
  449.             curX += cosineOfRotation;
  450.             curY -= sineOfRotation;
  451.         
  452.             // round it to an integer for the array lookup
  453.             roundedNewX = curX;
  454.             roundedNewY = curY;
  455.             
  456.             // Super safe bounds checking (for now)
  457.             // We only rotate inside our bounds
  458.             // we could potentially speed this up to figure out where to start
  459.             if ((roundedNewX >= 0) && (roundedNewY >= 0) && 
  460.                 (roundedNewX < numBytesPerRow) && (roundedNewY < rowsToCopy)) {
  461.                 // Compute the memory location corresponding to the new x and y.
  462.                 // potential place to speed it up is here
  463.                 curOff = roundedNewX + (srcOffset * roundedNewY);
  464.                 rotatedMaskLocationP = maskPixelP + curOff;
  465.                 if (*rotatedMaskLocationP == 0) {
  466.                     rotatedPixelLocationP = srcPixelP + curOff;
  467.                     dstPixelP[x] = *rotatedPixelLocationP;
  468.                 }
  469.             }
  470.         }
  471.         // bump down one row and reset x back to 0
  472.         curX += xInc;
  473.         curY += yInc;
  474.                 
  475.         // Go to next row.
  476.         dstPixelP += dstOffset;
  477.     }
  478. }
  479.  
  480. #pragma mark ----------- 16 Bit Blitters -------------
  481. ///--------------------------------------------------------------------------------------
  482. //        BlitPixieRotateFrame16Bit
  483. ///--------------------------------------------------------------------------------------
  484. /// This version allows it to be called directly with a specified rotation.
  485. /// No need for any globals to be set.
  486.  
  487. SW_FUNC void BlitPixieRotateFrame16Bit(
  488.     FramePtr srcFrameP,
  489.     FramePtr dstFrameP,
  490.     Rect *srcRect,
  491.     Rect *dstRect,
  492.     short rotation)
  493. {
  494.     Rect dstBlitRect = *dstRect;
  495.     Rect srcBlitRect = *srcRect;
  496.     unsigned long         numBytesPerRow;
  497.     unsigned long         srcBaseOffset;
  498.     
  499.     SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
  500.     SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 16);
  501.     SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 16);
  502.     SW_ASSERT(srcFrameP->maskPort != NULL);
  503.     
  504.     BP_CLIP_RECT(dstFrameP->frameRect, srcBlitRect, dstBlitRect);    
  505.     START_32_BIT_MODE
  506.  
  507.         // calculate the offset to the first byte of the source
  508.     srcBaseOffset = srcFrameP->scanLinePtrArray[srcBlitRect.top - srcFrameP->frameRect.top] + 
  509.         srcBlitRect.left;
  510.  
  511.         // calculate the number of bytes in a row
  512.     numBytesPerRow = (dstBlitRect.right - dstBlitRect.left) << 1;
  513.  
  514.     BlitPixieMask16BitRotated(
  515.             // calculate the address of the first byte of the source
  516.         (unsigned short *)(srcFrameP->frameBaseAddr + srcBaseOffset),
  517.  
  518.             // calculate the address of the first byte of the destination
  519.         (unsigned short *)(dstFrameP->frameBaseAddr + 
  520.             (dstFrameP->scanLinePtrArray[dstBlitRect.top]) + 
  521.             (dstBlitRect.left << 1)),
  522.  
  523.             // calculate the address of the first byte of the mask
  524.         (unsigned short *)(srcFrameP->maskBaseAddr + srcBaseOffset),
  525.  
  526.             // calculate the number of rows to blit
  527.         dstBlitRect.bottom - dstBlitRect.top,
  528.  
  529.             // number of bytes in a row (duh!)
  530.         numBytesPerRow,
  531.  
  532.         srcFrameP->frameRowBytes,
  533.         dstFrameP->frameRowBytes,
  534.  
  535.         rotation
  536.         );
  537.         
  538.     END_32_BIT_MODE
  539. }
  540.  
  541.  
  542. ///--------------------------------------------------------------------------------------
  543. //        BlitPixie16BitRotatedMaskDrawProc
  544. ///--------------------------------------------------------------------------------------
  545. /// This version of the drawproc is used by the system, and should be used as a sprite
  546. /// draw proc.  It requires that the global "gCurrentSpriteBeingDrawn" be set before being called.
  547.  
  548. SW_FUNC void BlitPixie16BitRotatedMaskDrawProc(
  549.     FramePtr srcFrameP,
  550.     FramePtr dstFrameP,
  551.     Rect *srcRect,
  552.     Rect *dstRect)
  553. {
  554.     Rect dstBlitRect = *dstRect;
  555.     Rect srcBlitRect = *srcRect;
  556.     unsigned long         numBytesPerRow;
  557.     unsigned long         srcBaseOffset;
  558.     unsigned long         rotation = 0;
  559.  
  560.     SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
  561.     SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 16);
  562.     SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 16);
  563.     SW_ASSERT(srcFrameP->maskPort != NULL);
  564.     
  565.     if (gCurrentSpriteBeingDrawn != NULL)
  566.         rotation = gCurrentSpriteBeingDrawn->rotation;
  567.  
  568.     BP_CLIP_RECT(dstFrameP->frameRect, srcBlitRect, dstBlitRect);    
  569.     START_32_BIT_MODE
  570.  
  571.         // calculate the offset to the first byte of the source
  572.     srcBaseOffset = srcFrameP->scanLinePtrArray[srcBlitRect.top - srcFrameP->frameRect.top] + 
  573.         srcBlitRect.left;
  574.  
  575.         // calculate the number of bytes in a row
  576.     numBytesPerRow = (dstBlitRect.right - dstBlitRect.left) << 1;
  577.  
  578.     BlitPixieMask16BitRotated(
  579.             // calculate the address of the first byte of the source
  580.         (unsigned short *)(srcFrameP->frameBaseAddr + srcBaseOffset),
  581.  
  582.             // calculate the address of the first byte of the destination
  583.         (unsigned short *)(dstFrameP->frameBaseAddr + 
  584.             (dstFrameP->scanLinePtrArray[dstBlitRect.top]) + 
  585.             (dstBlitRect.left << 1)),
  586.  
  587.             // calculate the address of the first byte of the mask
  588.         (unsigned short *)(srcFrameP->maskBaseAddr + srcBaseOffset),
  589.  
  590.             // calculate the number of rows to blit
  591.         dstBlitRect.bottom - dstBlitRect.top,
  592.  
  593.             // number of bytes in a row (duh!)
  594.         numBytesPerRow,
  595.  
  596.         srcFrameP->frameRowBytes,
  597.         dstFrameP->frameRowBytes,
  598.  
  599.         rotation
  600.         );
  601.  
  602.     END_32_BIT_MODE
  603. }
  604.  
  605.  
  606. ///--------------------------------------------------------------------------------------
  607. //        BlitPixieMask16BitRotated
  608. ///--------------------------------------------------------------------------------------
  609. void BlitPixieMask16BitRotated(
  610.     register unsigned short *srcPixelP,
  611.     register unsigned short *dstPixelP,
  612.     register unsigned short *maskPixelP,
  613.     register unsigned long rowsToCopy,
  614.     register unsigned long numBytesPerRow,
  615.     register unsigned long srcOffset,
  616.     register unsigned long dstOffset,
  617.     register unsigned long curRotation)
  618. {
  619.     register unsigned short *rotatedPixelLocationP;
  620.     register unsigned short *rotatedMaskLocationP;
  621.     register int x, y, curOff;
  622.     register int roundedNewX, roundedNewY;
  623.     
  624.     // We pull all of these out to here so in our loop
  625.     // all we do is the minimal number of additions
  626.     register unsigned long pixelWidth = numBytesPerRow / 2;
  627.     register double cosineOfRotation = cosineArray[curRotation];
  628.     register double sineOfRotation = sineArray[curRotation];
  629.     double midx = pixelWidth / 2;
  630.     double midy = rowsToCopy / 2;    
  631.     register double curX = midx + ((0 - midx) * cosineOfRotation) +
  632.                               ((0 - midy) * sineOfRotation);
  633.     register double curY = midy + ((0 - midy) * cosineOfRotation) -
  634.                                       ((0 - midx) * sineOfRotation);
  635.     double xInc = sineOfRotation - (cosineOfRotation * pixelWidth);
  636.     double yInc = cosineOfRotation + (sineOfRotation * pixelWidth);
  637.     
  638.     // divide the offsets by 2 to get number of shorts from bytes
  639.     srcOffset >>= 1;
  640.     dstOffset >>= 1;
  641.     
  642.     // Now we go through each pixel in the destination and compute the corresponding
  643.     // source pixel.  We could do this in reverse (go through source, and compute the
  644.     // destination) and it would be faster, but round off error leaves holes in the
  645.     // image.  This is the correct way.
  646.     for (y = 0; y < rowsToCopy; y++) {
  647.         for (x = 0; x < pixelWidth; x++) {
  648.             curX += cosineOfRotation;
  649.             curY -= sineOfRotation;
  650.         
  651.             // round it to an integer for the array lookup
  652.             roundedNewX = curX;
  653.             roundedNewY = curY;
  654.             
  655.             // Super safe bounds checking (for now)
  656.             // We only rotate inside our bounds
  657.             // we could potentially speed this up to figure out where to start
  658.             if ((roundedNewX >= 0) && (roundedNewY >= 0) && 
  659.                 (roundedNewX < pixelWidth) && (roundedNewY < rowsToCopy)) {
  660.                 // Compute the memory location corresponding to the new x and y.
  661.                 // potential place to speed it up is here
  662.                 curOff = roundedNewX + (srcOffset * roundedNewY);
  663.                 rotatedMaskLocationP = maskPixelP + curOff;
  664.                 if (*rotatedMaskLocationP == 0) {
  665.                     rotatedPixelLocationP = srcPixelP + curOff;
  666.                     dstPixelP[x] = *rotatedPixelLocationP;
  667.                 }
  668.             }
  669.         }
  670.         // bump down one row and reset x back to 0
  671.         curX += xInc;
  672.         curY += yInc;
  673.  
  674.         // Go to next row.
  675.         dstPixelP += dstOffset;
  676.     }
  677. }
  678.  
  679.  
  680.