*            the top-left y-coord of the alpha blit region
	 * @param destData
	 *            the destination byte array containing image data
	 * @param destDepth
	 *            the destination depth: one of 8, 16, 24, 32
	 * @param destStride
	 *            the destination number of bytes per line
	 * @param destOrder
	 *            the destination byte ordering: one of MSB_FIRST or LSB_FIRST;
	 *            ignored if destDepth is not 16 or 32
	 * @param destX
	 *            the top-left x-coord of the destination blit region
	 * @param destY
	 *            the top-left y-coord of the destination blit region
	 * @param destWidth
	 *            the width of the destination blit region
	 * @param destHeight
	 *            the height of the destination blit region
	 * @param destRedMask
	 *            the destination red channel mask
	 * @param destGreenMask
	 *            the destination green channel mask
	 * @param destBlueMask
	 *            the destination blue channel mask
	 * @param flipX
	 *            if true the resulting image is flipped along the vertical axis
	 * @param flipY
	 *            if true the resulting image is flipped along the horizontal
	 *            axis
	 */
	static void blit(int op, byte[] srcData, int srcDepth, int srcStride,
			int srcOrder, int srcX, int srcY, int srcWidth, int srcHeight,
			byte[] srcReds, byte[] srcGreens, byte[] srcBlues, int alphaMode,
			byte[] alphaData, int alphaStride, int alphaX, int alphaY,
			byte[] destData, int destDepth, int destStride, int destOrder,
			int destX, int destY, int destWidth, int destHeight,
			int destRedMask, int destGreenMask, int destBlueMask,
			boolean flipX, boolean flipY) {
		if ((destWidth <= 0) || (destHeight <= 0)
				|| (alphaMode == ALPHA_TRANSPARENT))
			return;

		/*** Fast blit (straight copy) ***/
		if (srcX == 0 && srcY == 0 && destX == 0 && destY == 0
				&& destWidth == srcWidth && destHeight == srcHeight) {
			if (destDepth == 24 && srcDepth == 8 && (op & BLIT_ALPHA) == 0
					&& destRedMask == 0xFF0000 && destGreenMask == 0xFF00
					&& destBlueMask == 0xFF) {
				for (int y = 0, sp = 0, dp = 0, spad = srcStride - srcWidth, dpad = destStride
						- (destWidth * 3); y < destHeight; y++, sp += spad, dp += dpad) {
					for (int x = 0; x < destWidth; x++) {
						int index = srcData[sp++] & 0xff;
						destData[dp++] = srcReds[index];
						destData[dp++] = srcGreens[index];
						destData[dp++] = srcBlues[index];
					}
				}
				return;
			}
			if (destDepth == 32 && destOrder == MSB_FIRST && srcDepth == 8
					&& (op & BLIT_ALPHA) == 0 && destRedMask == 0xFF0000
					&& destGreenMask == 0xFF00 && destBlueMask == 0xFF) {
				for (int y = 0, sp = 0, dp = 0, spad = srcStride - srcWidth, dpad = destStride
						- (destWidth * 4); y < destHeight; y++, sp += spad, dp += dpad) {
					for (int x = 0; x < destWidth; x++) {
						int index = srcData[sp++] & 0xff;
						dp++;
						destData[dp++] = srcReds[index];
						destData[dp++] = srcGreens[index];
						destData[dp++] = srcBlues[index];
					}
				}
				return;
			}
		}
		// these should be supplied as params later
		final int destAlphaMask = 0;

		/*** Prepare scaling data ***/
		final int dwm1 = destWidth - 1;
		final int sfxi = (dwm1 != 0) ? (int) ((((long) srcWidth << 16) - 1) / dwm1)
				: 0;
		final int dhm1 = destHeight - 1;
		final int sfyi = (dhm1 != 0) ? (int) ((((long) srcHeight << 16) - 1) / dhm1)
				: 0;

		/*** Prepare source-related data ***/
		final int stype;
		switch (srcDepth) {
		case 8:
			stype = TYPE_INDEX_8;
			break;
		case 4:
			srcStride <<= 1;
			stype = TYPE_INDEX_4;
			break;
		case 2:
			srcStride <<= 2;
			stype = TYPE_INDEX_2;
			break;
		case 1:
			srcStride <<= 3;
			stype = (srcOrder == MSB_FIRST) ? TYPE_INDEX_1_MSB
					: TYPE_INDEX_1_LSB;
			break;
		default:
			// throw new IllegalArgumentException("Invalid source type");
			return;
		}
		int spr = srcY * srcStride + srcX;

		/*** Prepare destination-related data ***/
		final int dbpp, dtype;
		switch (destDepth) {
		case 8:
			dbpp = 1;
			dtype = TYPE_GENERIC_8;
			break;
		case 16:
			dbpp = 2;
			dtype = (destOrder == MSB_FIRST) ? TYPE_GENERIC_16_MSB
					: TYPE_GENERIC_16_LSB;
			break;
		case 24:
			dbpp = 3;
			dtype = TYPE_GENERIC_24;
			break;
		case 32:
			dbpp = 4;
			dtype = (destOrder == MSB_FIRST) ? TYPE_GENERIC_32_MSB
					: TYPE_GENERIC_32_LSB;
			break;
		default:
			// throw new IllegalArgumentException("Invalid destination type");
			return;
		}
		int dpr = ((flipY) ? destY + dhm1 : destY) * destStride
				+ ((flipX) ? destX + dwm1 : destX) * dbpp;
		final int dprxi = (flipX) ? -dbpp : dbpp;
		final int dpryi = (flipY) ? -destStride : destStride;

		/*** Prepare special processing data ***/
		int apr;
		if ((op & BLIT_ALPHA) != 0) {
			switch (alphaMode) {
			case ALPHA_MASK_UNPACKED:
			case ALPHA_CHANNEL_SEPARATE:
				if (alphaData == null)
					alphaMode = 0x10000;
				apr = alphaY * alphaStride + alphaX;
				break;
			case ALPHA_MASK_PACKED:
				if (alphaData == null)
					alphaMode = 0x10000;
				alphaStride <<= 3;
				apr = alphaY * alphaStride + alphaX;
				break;
			case ALPHA_MASK_INDEX:
			case ALPHA_MASK_RGB:
				if (alphaData == null)
					alphaMode = 0x10000;
				apr = 0;
				break;
			default:
				alphaMode = (alphaMode << 16) / 255; // prescale
			case ALPHA_CHANNEL_SOURCE:
				apr = 0;
				break;
			}
		} else {
			alphaMode = 0x10000;
			apr = 0;
		}

		/*** Comprehensive blit (apply transformations) ***/
		final int destRedShift = getChannelShift(destRedMask);
		final int destRedWidth = getChannelWidth(destRedMask, destRedShift);
		final byte[] destReds = ANY_TO_EIGHT[destRedWidth];
		final int destRedPreShift = 8 - destRedWidth;
		final int destGreenShift = getChannelShift(destGreenMask);
		final int destGreenWidth = getChannelWidth(destGreenMask,
				destGreenShift);
		final byte[] destGreens = ANY_TO_EIGHT[destGreenWidth];
		final int destGreenPreShift = 8 - destGreenWidth;
		final int destBlueShift = getChannelShift(destBlueMask);
		final int destBlueWidth = getChannelWidth(destBlueMask, destBlueShift);
		final byte[] destBlues = ANY_TO_EIGHT[destBlueWidth];
		final int destBluePreShift = 8 - destBlueWidth;
		final int destAlphaShift = getChannelShift(destAlphaMask);
		final int destAlphaWidth = getChannelWidth(destAlphaMask,
				destAlphaShift);
		final byte[] destAlphas = ANY_TO_EIGHT[destAlphaWidth];
		final int destAlphaPreShift = 8 - destAlphaWidth;

		int dp = dpr;
		int sp = spr;
		int ap = apr, alpha = alphaMode;
		int r = 0, g = 0, b = 0, a = 0, index = 0;
		int rq = 0, gq = 0, bq = 0, aq = 0;
		for (int dy = destHeight, sfy = sfyi; dy > 0; --dy, sp = spr += (sfy >>> 16)
				* srcStride, ap = apr += (sfy >>> 16) * alphaStride, sfy = (sfy & 0xffff)
				+ sfyi, dp = dpr += dpryi) {
			for (int dx = destWidth, sfx = sfxi; dx > 0; --dx, dp += dprxi, sfx = (sfx & 0xffff)
					+ sfxi) {
				/*** READ NEXT PIXEL ***/
				switch (stype) {
				case TYPE_INDEX_8:
					index = srcData[sp] & 0xff;
					sp += (sfx >>> 16);
					break;
				case TYPE_INDEX_4:
					if ((sp & 1) != 0)
						index = srcData[sp >> 1] & 0x0f;
					else
						index = (srcData[sp >> 1] >>> 4) & 0x0f;
					sp += (sfx >>> 16);
					break;
				case TYPE_INDEX_2:
					index = (srcData[sp >> 2] >>> (6 - (sp & 3) * 2)) & 0x03;
					sp += (sfx >>> 16);
					break;
				case TYPE_INDEX_1_MSB:
					index = (srcData[sp >> 3] >>> (7 - (sp & 7))) & 0x01;
					sp += (sfx >>> 16);
					break;
				case TYPE_INDEX_1_LSB:
					index = (srcData[sp >> 3] >>> (sp & 7)) & 0x01;
					sp += (sfx >>> 16);
					break;
				}

				/*** DO SPECIAL PROCESSING IF REQUIRED ***/
				r = srcReds[index] & 0xff;
				g = srcGreens[index] & 0xff;
				b = srcBlues[index] & 0xff;
				switch (alphaMode) {
				case ALPHA_CHANNEL_SEPARATE:
					alpha = ((alphaData[ap] & 0xff) << 16) / 255;
					ap += (sfx >> 16);
					break;
				case ALPHA_MASK_UNPACKED:
					alpha = (alphaData[ap] != 0) ? 0x10000 : 0;
					ap += (sfx >> 16);
					break;
				case ALPHA_MASK_PACKED:
					alpha = (alphaData[ap >> 3] << ((ap & 7) + 9)) & 0x10000;
					ap += (sfx >> 16);
					break;
				case ALPHA_MASK_INDEX: { // could speed up using binary search
											// if we sorted the indices
					int i = 0;
					while (i < alphaData.length) {
						if (index == (alphaData[i] & 0xff))
							break;
					}
					if (i < alphaData.length)
						continue;
				}
					break;
				case ALPHA_MASK_RGB: {
					int i = 0;
					while (i < alphaData.length) {
						if ((r == (alphaData[i] & 0xff))
								&& (g == (alphaData[i + 1] & 0xff))
								&& (b == (alphaData[i + 2] & 0xff)))
							break;
						i += 3;
					}
					if (i < alphaData.length)
						continue;
				}
					break;
				}
				if (alpha != 0x10000) {
					if (alpha == 0x0000)
						continue;
					switch (dtype) {
					case TYPE_GENERIC_8: {
						final int data = destData[dp] & 0xff;
						rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
						gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
						bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
						aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
					}
						break;
					case TYPE_GENERIC_16_MSB: {
						final int data = ((destData[dp] & 0xff) << 8)
								| (destData[dp + 1] & 0xff);
						rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
						gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
						bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
						aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
					}
						break;
					case TYPE_GENERIC_16_LSB: {
						final int data = ((destData[dp + 1] & 0xff) << 8)
								| (destData[dp] & 0xff);
						rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
						gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
						bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
						aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
					}
						break;
					case TYPE_GENERIC_24: {
						final int data = ((((destData[dp] & 0xff) << 8) | (destData[dp + 1] & 0xff)) << 8)
								| (destData[dp + 2] & 0xff);
						rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
						gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
						bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
						aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
					}
						break;
					case TYPE_GENERIC_32_MSB: {
						final int data = ((((((destData[dp] & 0xff) << 8) | (destData[dp + 1] & 0xff)) << 8) | (destData[dp + 2] & 0xff)) << 8)
								| (destData[dp + 3] & 0xff);
						rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
						gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
						bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
						aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
					}
						break;
					case TYPE_GENERIC_32_LSB: {
						final int data = ((((((destData[dp + 3] & 0xff) << 8) | (destData[dp + 2] & 0xff)) << 8) | (destData[dp + 1] & 0xff)) << 8)
								| (destData[dp] & 0xff);
						rq = destReds[(data & destRedMask) >>> destRedShift] & 0xff;
						gq = destGreens[(data & destGreenMask) >>> destGreenShift] & 0xff;
						bq = destBlues[(data & destBlueMask) >>> destBlueShift] & 0xff;
						aq = destAlphas[(data & destAlphaMask) >>> destAlphaShift] & 0xff;
					}
						break;
					}
					// Perform alpha blending
					a = aq + ((a - aq) * alpha >> 16);
					r = rq + ((r - rq) * alpha >> 16);
					g = gq + ((g - gq) * alpha >> 16);
					b = bq + ((b - bq) * alpha >> 16);
				}

				/*** WRITE NEXT PIXEL ***/
				final int data = (r >>> destRedPreShift << destRedShift)
						| (g >>> destGreenPreShift << destGreenShift)
						| (b >>> destBluePreShift << destBlueShift)
						| (a >>> destAlphaPreShift << destAlphaShift);
				switch (dtype) {
				case TYPE_GENERIC_8: {
					destData[dp] = (byte) data;
				}
					break;
				case TYPE_GENERIC_16_MSB: {
					destData[dp] = (byte) (data >>> 8);
					destData[dp + 1] = (byte) (data & 0xff);
				}
					break;
				case TYPE_GENERIC_16_LSB: {
					destData[dp] = (byte) (data & 0xff);
					destData[dp + 1] = (byte) (data >>> 8);
				}
					break;
				case TYPE_GENERIC_24: {
					destData[dp] = (byte) (data >>> 16);
					destData[dp + 1] = (byte) (data >>> 8);
					destData[dp + 2] = (byte) (data & 0xff);
				}
					break;
				case TYPE_GENERIC_32_MSB: {
					destData[dp] = (byte) (data >>> 24);
					destData[dp + 1] = (byte) (data >>> 16);
					destData[dp + 2] = (byte) (data >>> 8);
					destData[dp + 3] = (byte) (data & 0xff);
				}
					break;
				case TYPE_GENERIC_32_LSB: {
					destData[dp] = (byte) (data & 0xff);
					destData[dp + 1] = (byte) (data >>> 8);
					destData[dp + 2] = (byte) (data >>> 16);
					destData[dp + 3] = (byte) (data >>> 24);
				}
					break;
				}
			}
		}
	}