+
+ return b;
+}
+
+static void rleDistributeStreaks(RLEBitmap *bitmap) {
+ int scanline, halfW = bitmap->w >> 1;
+ unsigned char *ptr, tmp;
+
+ ptr = bitmap->scans;
+ for (scanline = 0; scanline < bitmap->h; scanline++) {
+ if (ptr[0] >= halfW) {
+ tmp = ptr[0];
+ ptr[0] = ptr[6];
+ ptr[6] = tmp;
+ tmp = ptr[1];
+ ptr[1] = ptr[7];
+ ptr[7] = tmp;
+ }
+
+ ptr += 8;
+ }
+}
+
+static void rleBlit(unsigned short *dst, int dstW, int dstH, int dstStride,
+ RLEBitmap *bitmap, int blitX, int blitY)
+{
+ int scanline = 0;
+ int streakPos = 0;
+ int streakLength = 0;
+ int streak = 0;
+ unsigned char *input = bitmap->scans;
+ unsigned short *output;
+ unsigned int *output32;
+
+ dst += blitX + blitY * dstStride;
+
+ for (scanline = blitY; scanline < blitY + bitmap->h; scanline++) {
+ if (scanline < 0 || scanline >= dstH) continue;
+ for (streak = 0; streak < RLE_STREAKS_PER_SCANLINE; streak++) {
+ streakPos = *input++;
+ streakLength = *input++;
+
+ if ((streakPos + blitX) <= 0) continue;
+
+ output = dst + streakPos;
+
+ /* Check if we need to write the first pixel as 16bit */
+ if (streakLength % 2) {
+ *output++ = RLE_FILL_COLOR;
+ }
+
+ /* Then, write 2 pixels at a time */
+ streakLength >>= 1;
+ output32 = (unsigned int*) output;
+ while (streakLength--) {
+ *output32++ = RLE_FILL_COLOR_32;
+ }
+ }
+
+ dst += dstStride;
+ }
+}
+
+static void interpolateScan(unsigned char *output, unsigned char *a, unsigned char *b, float t) {
+ static int div = 1 << 23;
+ int ti, i;
+
+ t += 1.0f;
+ ti = (*((unsigned int*)&t)) & 0x7FFFFF;
+
+ for (i = 0; i < RLE_BYTES_PER_SCANLINE; i++) {
+ if (*a == 0) {
+ *output++ = *b++;
+ a++;
+ } else {
+ if (*b == 0) {
+ *output++ = *a++;
+ b++;
+ } else {
+ *output++ = ((*b++ * ti) + (*a++ * (div - ti))) >> 23;
+ }
+ }
+ }
+}
+
+static void rleBlitScale(unsigned short *dst, int dstW, int dstH, int dstStride,
+ RLEBitmap *bitmap, int blitX, int blitY, float scaleX, float scaleY)
+{
+ int scanline = 0;
+ int streakPos = 0;
+ int streakLength = 0;
+ int streak = 0;
+ unsigned short *output;
+ unsigned int *output32;
+ unsigned char *input;
+ int scanlineCounter = 0;
+ int scaleXFixed;
+ static unsigned char scan[512];
+
+ /*int blitW = (int)(bitmap->w * scaleX + 0.5f);*/
+ int blitH = (int)(bitmap->h * scaleY + 0.5f);
+
+ /* From this point on, scaleY will be inverted */
+ scaleY = 1.0f / scaleY;
+
+ scaleXFixed = (int)(scaleX * (float)(1 << RLE_FIXED_BITS) + 0.5f);
+
+ dst += blitX + blitY * dstStride;
+
+ for (scanline = blitY; scanline < blitY + blitH; scanline++) {
+ float normalScan = scanlineCounter * scaleY; /* ScaleY is inverted */
+ unsigned char *scan0 = bitmap->scans + RLE_BYTES_PER_SCANLINE * (int)normalScan;
+ unsigned char *scan1 = scan0 + RLE_BYTES_PER_SCANLINE;
+ normalScan -= (int)normalScan;
+ interpolateScan(scan, scan0, scan1, normalScan);
+ input = scan;
+ scanlineCounter++;
+
+ if (scanline < 0 || scanline >= dstH) continue;
+ for (streak = 0; streak < RLE_STREAKS_PER_SCANLINE; streak++) {
+ streakPos = (*input++ * scaleXFixed) >> RLE_FIXED_BITS;
+ streakLength = (*input++ * scaleXFixed) >> RLE_FIXED_BITS;
+
+ if ((streakPos + blitX) <= 0) continue;
+
+ output = dst + streakPos;
+
+ /* Check if we need to write the first pixel as 16bit */
+ if (streakLength % 2) {
+ *output++ = RLE_FILL_COLOR;
+ }
+
+ /* Then, write 2 pixels at a time */
+ streakLength >>= 1;
+ output32 = (unsigned int*)output;
+ while (streakLength--) {
+ *output32++ = RLE_FILL_COLOR_32;
+ }
+ }
+
+ dst += dstStride;
+ }
+}
+
+
+
+static void rleBlitScaleInv(unsigned short *dst, int dstW, int dstH, int dstStride,
+ RLEBitmap *bitmap, int blitX, int blitY, float scaleX, float scaleY)
+{
+ int scanline = 0;
+ int streakPos = 0;
+ int streakLength = 0;
+ int streak = 0;
+ unsigned short *output;
+ unsigned int *output32;
+ unsigned char *input;
+ int scanlineCounter = 0;
+ int scaleXFixed;
+ static unsigned char scan[512];
+
+ /*int blitW = (int)(bitmap->w * scaleX + 0.5f);*/
+ int blitH = (int)(bitmap->h * scaleY + 0.5f);
+
+ /* From this point on, scaleY will be inverted */
+ scaleY = 1.0f / scaleY;
+
+ scaleXFixed = (int)(scaleX * (float)(1 << RLE_FIXED_BITS) + 0.5f);
+
+ dst += blitX + blitY * dstStride;
+
+ for (scanline = blitY; scanline > blitY - blitH; scanline--) {
+ float normalScan = scanlineCounter * scaleY; /* ScaleY is inverted */
+ unsigned char *scan0 = bitmap->scans + RLE_BYTES_PER_SCANLINE * (int)normalScan;
+ unsigned char *scan1 = scan0 + RLE_BYTES_PER_SCANLINE;
+ normalScan -= (int)normalScan;
+ interpolateScan(scan, scan0, scan1, normalScan);
+ input = scan;
+ scanlineCounter++;
+
+ if (scanline < 0 || scanline >= dstH) continue;
+ for (streak = 0; streak < RLE_STREAKS_PER_SCANLINE; streak++) {
+ streakPos = (*input++ * scaleXFixed) >> RLE_FIXED_BITS;
+ streakLength = (*input++ * scaleXFixed) >> RLE_FIXED_BITS;
+
+ if ((streakPos + blitX) <= 0) continue;
+
+ output = dst + streakPos;
+
+ /* Check if we need to write the first pixel as 16bit */
+ if (streakLength % 2) {
+ *output++ = RLE_FILL_COLOR;
+ }
+
+ /* Then, write 2 pixels at a time */
+ streakLength >>= 1;
+ output32 = (unsigned int*)output;
+ while (streakLength--) {
+ *output32++ = RLE_FILL_COLOR_32;
+ }
+ }
+
+ dst -= dstStride;
+ }
+}
+
+/* -------------------------------------------------------------------------------------------------
+* PROPELLER STUFF
+* -------------------------------------------------------------------------------------------------
+*/
+
+#define PROPELLER_CIRCLE_RADIUS 18
+#define PROPELLER_CIRCLE_RADIUS_SQ (PROPELLER_CIRCLE_RADIUS * PROPELLER_CIRCLE_RADIUS)
+
+static struct {
+ int circleX[3];
+ int circleY[3];
+} propellerState;
+
+static void updatePropeller(float t) {
+ int i, j;
+ int cx, cy, count = 0;
+ unsigned char *dst;
+ float x = 0.0f;
+ float y = 18.0f;
+ float nx, ny;
+ float cost, sint;
+ static float sin120 = 0.86602540378f;
+ static float cos120 = -0.5f;
+
+ /* Rotate */
+ sint = sin(t);
+ cost = cos(t);
+ nx = x * cost - y * sint;
+ ny = y * cost + x * sint;
+ x = nx;
+ y = ny;
+ propellerState.circleX[0] = (int)(x + 0.5f) + 16;
+ propellerState.circleY[0] = (int)(y + 0.5f) + 16;
+
+ /* Rotate by 120 degrees, for the second circle */
+ nx = x * cos120 - y * sin120;
+ ny = y * cos120 + x * sin120;
+ x = nx;
+ y = ny;
+ propellerState.circleX[1] = (int)(x + 0.5f) + 16;
+ propellerState.circleY[1] = (int)(y + 0.5f) + 16;
+
+ /* 3rd circle */
+ nx = x * cos120 - y * sin120;
+ ny = y * cos120 + x * sin120;
+ x = nx;
+ y = ny;
+ propellerState.circleX[2] = (int)(x + 0.5f) + 16;
+ propellerState.circleY[2] = (int)(y + 0.5f) + 16;
+
+ /* Write effect to the mini fx buffer*/
+ dst = miniFXBuffer;
+ for (j = 0; j < 32; j++) {
+ for (i = 0; i < 32; i++) {
+ count = 0;
+
+ /* First circle */
+ cx = propellerState.circleX[0] - i;
+ cy = propellerState.circleY[0] - j;
+ if (cx*cx + cy*cy < PROPELLER_CIRCLE_RADIUS_SQ) count++;
+
+ /* 2nd circle */
+ cx = propellerState.circleX[1] - i;
+ cy = propellerState.circleY[1] - j;
+ if (cx*cx + cy*cy < PROPELLER_CIRCLE_RADIUS_SQ) count++;
+
+ /* 3rd circle */
+ cx = propellerState.circleX[2] - i;
+ cy = propellerState.circleY[2] - j;
+ if (cx*cx + cy*cy < PROPELLER_CIRCLE_RADIUS_SQ) count++;
+
+ *dst++ = count >= 2;
+ }
+ }
+
+ /* Then, encode to rle */
+ rlePropeller = rleEncode(rlePropeller, miniFXBuffer, 32, 32);
+
+ /* Distribute the produced streaks so that they don't produce garbage when interpolated */
+ rleDistributeStreaks(rlePropeller);