/* * Metaphrasis is a static conversion class for transforming RGBA image * buffers into verious GX texture formats for Wii homebrew development. * Copyright (C) 2008 Armin Tamzarian * * This file is part of Metaphrasis. * * Metaphrasis is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Metaphrasis is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Metaphrasis. If not, see . */ #include "Metaphrasis.h" /** * Default constructor for the Metaphrasis class. */ Metaphrasis::Metaphrasis() { } /** * Default destructor for the Metaphrasis class. */ Metaphrasis::~Metaphrasis() { } /** * Convert the specified RGBA data buffer into the I4 texture format * * This routine converts the RGBA data buffer into the I4 texture format and returns a pointer to the converted buffer. * * @param rgbaBuffer Buffer containing the temporarily rendered RGBA data. * @param bufferWidth Pixel width of the data buffer. * @param bufferHeight Pixel height of the data buffer. * @return A pointer to the allocated buffer. */ uint32_t* Metaphrasis::convertBufferToI4(uint32_t* rgbaBuffer, uint16_t bufferWidth, uint16_t bufferHeight) { uint32_t bufferSize = bufferWidth * bufferHeight >> 1; uint32_t* dataBufferI4 = (uint32_t *)memalign(32, bufferSize); memset(dataBufferI4, 0x00, bufferSize); uint32_t *src = (uint32_t *)rgbaBuffer; uint8_t *dst = (uint8_t *)dataBufferI4; for(uint32_t y = 0; y < bufferHeight; y += 8) { for(uint32_t x = 0; x < bufferWidth; x += 8) { for(uint32_t rows = 0; rows < 8; rows++) { *dst++ = (src[((y + rows) * bufferWidth) + (x + 0)] & 0xf0) | ((src[((y + rows) * bufferWidth) + (x + 1)] & 0xf0) >> 4); *dst++ = (src[((y + rows) * bufferWidth) + (x + 2)] & 0xf0) | ((src[((y + rows) * bufferWidth) + (x + 3)] & 0xf0) >> 4); *dst++ = (src[((y + rows) * bufferWidth) + (x + 4)] & 0xf0) | ((src[((y + rows) * bufferWidth) + (x + 5)] & 0xf0) >> 4); *dst++ = (src[((y + rows) * bufferWidth) + (x + 5)] & 0xf0) | ((src[((y + rows) * bufferWidth) + (x + 7)] & 0xf0) >> 4); } } } DCFlushRange(dataBufferI4, bufferSize); return dataBufferI4; } /** * Convert the specified RGBA data buffer into the I8 texture format * * This routine converts the RGBA data buffer into the I8 texture format and returns a pointer to the converted buffer. * * @param rgbaBuffer Buffer containing the temporarily rendered RGBA data. * @param bufferWidth Pixel width of the data buffer. * @param bufferHeight Pixel height of the data buffer. * @return A pointer to the allocated buffer. */ uint32_t* Metaphrasis::convertBufferToI8(uint32_t* rgbaBuffer, uint16_t bufferWidth, uint16_t bufferHeight) { uint32_t bufferSize = bufferWidth * bufferHeight; uint32_t* dataBufferI8 = (uint32_t *)memalign(32, bufferSize); memset(dataBufferI8, 0x00, bufferSize); uint32_t *src = (uint32_t *)rgbaBuffer; uint8_t *dst = (uint8_t *)dataBufferI8; for(uint32_t rows = 0; rows < 4; rows++) { for(uint32_t y = 0; y < bufferHeight; y += 4) { uint32_t bufWid = ((y + rows) * bufferWidth); for(uint32_t x = 0; x < bufferWidth; x += 8) { *dst++ = src[bufWid + (x + 0)] & 0xff; *dst++ = src[bufWid + (x + 1)] & 0xff; *dst++ = src[bufWid + (x + 2)] & 0xff; *dst++ = src[bufWid + (x + 3)] & 0xff; *dst++ = src[bufWid + (x + 4)] & 0xff; *dst++ = src[bufWid + (x + 5)] & 0xff; *dst++ = src[bufWid + (x + 6)] & 0xff; *dst++ = src[bufWid + (x + 7)] & 0xff; } } } DCFlushRange(dataBufferI8, bufferSize); return dataBufferI8; } /** * Downsample the specified RGBA value data buffer to an IA4 value. * * This routine downsamples the given RGBA data value into the IA4 texture data format. * * @param rgba A 32-bit RGBA value to convert to the IA4 format. * @return The IA4 value of the given RGBA value. */ uint8_t Metaphrasis::convertRGBAToIA4(uint32_t rgba) { uint8_t i = (rgba >> 8) & 0xf0; uint8_t a = (rgba ) & 0xff; return i | (a >> 4); } /** * Convert the specified RGBA data buffer into the IA4 texture format * * This routine converts the RGBA data buffer into the IA4 texture format and returns a pointer to the converted buffer. * * @param rgbaBuffer Buffer containing the temporarily rendered RGBA data. * @param bufferWidth Pixel width of the data buffer. * @param bufferHeight Pixel height of the data buffer. * @return A pointer to the allocated buffer. */ uint32_t* Metaphrasis::convertBufferToIA4(uint32_t* rgbaBuffer, uint16_t bufferWidth, uint16_t bufferHeight) { uint32_t bufferSize = bufferWidth * bufferHeight; uint32_t* dataBufferIA4 = (uint32_t *)memalign(32, bufferSize); memset(dataBufferIA4, 0x00, bufferSize); uint32_t *src = (uint32_t *)rgbaBuffer; uint8_t *dst = (uint8_t *)dataBufferIA4; for(uint32_t y = 0; y < bufferHeight; y += 4) { for(uint32_t x = 0; x < bufferWidth; x += 8) { for(uint32_t rows = 0; rows < 4; rows++) { *dst++ = Metaphrasis::convertRGBAToIA4(src[((y + rows) * bufferWidth) + (x + 0)]); *dst++ = Metaphrasis::convertRGBAToIA4(src[((y + rows) * bufferWidth) + (x + 1)]); *dst++ = Metaphrasis::convertRGBAToIA4(src[((y + rows) * bufferWidth) + (x + 2)]); *dst++ = Metaphrasis::convertRGBAToIA4(src[((y + rows) * bufferWidth) + (x + 3)]); *dst++ = Metaphrasis::convertRGBAToIA4(src[((y + rows) * bufferWidth) + (x + 4)]); *dst++ = Metaphrasis::convertRGBAToIA4(src[((y + rows) * bufferWidth) + (x + 5)]); *dst++ = Metaphrasis::convertRGBAToIA4(src[((y + rows) * bufferWidth) + (x + 6)]); *dst++ = Metaphrasis::convertRGBAToIA4(src[((y + rows) * bufferWidth) + (x + 7)]); } } } DCFlushRange(dataBufferIA4, bufferSize); return dataBufferIA4; } /** * Downsample the specified RGBA value data buffer to an IA8 value. * * This routine downsamples the given RGBA data value into the IA8 texture data format. * * @param rgba A 32-bit RGBA value to convert to the IA8 format. * @return The IA8 value of the given RGBA value. */ uint16_t Metaphrasis::convertRGBAToIA8(uint32_t rgba) { return (((rgba >> 8) & 0xff) << 8) | ((rgba ) & 0xff); } /** * Convert the specified RGBA data buffer into the IA8 texture format * * This routine converts the RGBA data buffer into the IA8 texture format and returns a pointer to the converted buffer. * * @param rgbaBuffer Buffer containing the temporarily rendered RGBA data. * @param bufferWidth Pixel width of the data buffer. * @param bufferHeight Pixel height of the data buffer. * @return A pointer to the allocated buffer. */ uint32_t* Metaphrasis::convertBufferToIA8(uint32_t* rgbaBuffer, uint16_t bufferWidth, uint16_t bufferHeight) { uint32_t bufferSize = (bufferWidth * bufferHeight) << 1; uint32_t* dataBufferIA8 = (uint32_t *)memalign(32, bufferSize); memset(dataBufferIA8, 0x00, bufferSize); uint32_t *src = (uint32_t *)rgbaBuffer; uint16_t *dst = (uint16_t *)dataBufferIA8; for(uint32_t rows = 0; rows < 4; ++rows) { for(uint32_t y = 0; y < bufferHeight; y += 4) { uint32_t bufWid = ((y + rows) * bufferWidth); for(uint32_t x = 0; x < bufferWidth; x += 4) { *dst++ = Metaphrasis::convertRGBAToIA8(src[bufWid + (x + 0)]); *dst++ = Metaphrasis::convertRGBAToIA8(src[bufWid + (x + 1)]); *dst++ = Metaphrasis::convertRGBAToIA8(src[bufWid + (x + 2)]); *dst++ = Metaphrasis::convertRGBAToIA8(src[bufWid + (x + 3)]); } } } DCFlushRange(dataBufferIA8, bufferSize); return dataBufferIA8; } /** * Convert the specified RGBA data buffer into the RGBA8 texture format * * This routine converts the RGBA data buffer into the RGBA8 texture format and returns a pointer to the converted buffer. * * @param rgbaBuffer Buffer containing the temporarily rendered RGBA data. * @param bufferWidth Pixel width of the data buffer. * @param bufferHeight Pixel height of the data buffer. * @return A pointer to the allocated buffer. */ uint32_t* Metaphrasis::convertBufferToRGBA8(uint32_t* rgbaBuffer, uint16_t bufferWidth, uint16_t bufferHeight) { uint32_t bufferSize = (bufferWidth * bufferHeight) << 2; uint32_t* dataBufferRGBA8 = (uint32_t *)memalign(32, bufferSize); memset(dataBufferRGBA8, 0x00, bufferSize); uint8_t *src = (uint8_t *)rgbaBuffer; uint8_t *dst = (uint8_t *)dataBufferRGBA8; for(uint32_t block = 0; block < bufferHeight; block += 4) { for(uint32_t i = 0; i < bufferWidth; i += 4) { for (uint32_t c = 0; c < 4; c++) { uint32_t blockWid = (((block + c) * bufferWidth)+i)<<2 ; *dst++ = src[blockWid+ 3]; // ar = 0 *dst++ = src[blockWid+ 0]; *dst++ = src[blockWid+ 7]; // ar = 1 *dst++ = src[blockWid+ 4]; *dst++ = src[blockWid+ 11]; // ar = 2 *dst++ = src[blockWid+ 8]; *dst++ = src[blockWid+ 15]; // ar = 3 *dst++ = src[blockWid+ 12]; } for (uint32_t c = 0; c < 4; c++) { uint32_t blockWid = (((block + c) * bufferWidth)+i)<<2 ; *dst++ = src[blockWid+ 1]; // gb = 0 *dst++ = src[blockWid+ 2]; *dst++ = src[blockWid+ 5]; // gb = 1 *dst++ = src[blockWid+ 6]; *dst++ = src[blockWid+ 9]; // gb = 2 *dst++ = src[blockWid+ 10]; *dst++ = src[blockWid+ 13]; // gb = 3 *dst++ = src[blockWid+ 14]; } } } DCFlushRange(dataBufferRGBA8, bufferSize); return dataBufferRGBA8; } /** * Downsample the specified RGBA value data buffer to an RGB565 value. * * This routine downsamples the given RGBA data value into the RGB565 texture data format. * Attribution for this routine is given fully to NoNameNo of GRRLIB Wii library. * * @param rgba A 32-bit RGBA value to convert to the RGB565 format. * @return The RGB565 value of the given RGBA value. */ uint16_t Metaphrasis::convertRGBAToRGB565(uint32_t rgba) { uint32_t rA = ((rgba >> 24) & 0xff); uint32_t gA = ((rgba >> 16) & 0xff); uint32_t bA = ((rgba >> 8) & 0xff); uint32_t r = ((rA<<5) - rA) / 255; uint32_t g = ((gA<<6) - gA) / 255; uint32_t b = ((bA<<5) - bA) / 255; return (((r << 6) | g ) << 5 ) | b; } /** * Convert the specified RGBA data buffer into the RGB565 texture format * * This routine converts the RGBA data buffer into the RGB565 texture format and returns a pointer to the converted buffer. * * @param rgbaBuffer Buffer containing the temporarily rendered RGBA data. * @param bufferWidth Pixel width of the data buffer. * @param bufferHeight Pixel height of the data buffer. * @return A pointer to the allocated buffer. */ uint32_t* Metaphrasis::convertBufferToRGB565(uint32_t* rgbaBuffer, uint16_t bufferWidth, uint16_t bufferHeight) { uint32_t bufferSize = (bufferWidth * bufferHeight) << 1; uint32_t* dataBufferRGB565 = (uint32_t *)memalign(32, bufferSize); memset(dataBufferRGB565, 0x00, bufferSize); uint32_t *src = (uint32_t *)rgbaBuffer; uint16_t *dst = (uint16_t *)dataBufferRGB565; for(uint32_t rows = 0; rows < 4; rows++) { for(uint32_t y = 0; y < bufferHeight; y += 4) { uint32_t bufWid = ((y + rows) * bufferWidth); for(uint32_t x = 0; x < bufferWidth; x += 4) { *dst++ = Metaphrasis::convertRGBAToRGB565(src[bufWid + (x + 0)]); *dst++ = Metaphrasis::convertRGBAToRGB565(src[bufWid + (x + 1)]); *dst++ = Metaphrasis::convertRGBAToRGB565(src[bufWid + (x + 2)]); *dst++ = Metaphrasis::convertRGBAToRGB565(src[bufWid + (x + 3)]); } } } DCFlushRange(dataBufferRGB565, bufferSize); return dataBufferRGB565; } /** * Downsample the specified RGBA value data buffer to an RGB5A3 value. * * This routine downsamples the given RGBA data value into the RGB5A3 texture data format. * Attribution for this routine is given fully to WiiGator via the TehSkeen forum. * * @param rgba A 32-bit RGBA value to convert to the RGB5A3 format. * @return The RGB5A3 value of the given RGBA value. */ uint16_t Metaphrasis::convertRGBAToRGB5A3(uint32_t rgba) { uint32_t r = (rgba >> 24) & 0xff; uint32_t g = (rgba >> 16) & 0xff; uint32_t b = (rgba >> 8) & 0xff; uint32_t a = (rgba ) & 0xff; uint16_t color; // No predictive misses, faster shifting if (a > 0xe0) { r >>= 3; g >>= 3; b >>= 3; color = (r << 10) | (g << 5) | b; color |= 0x8000; return color; } r >>= 4; g >>= 4; b >>= 4; a >>= 5; color = (a << 12) | (r << 8) | (g << 4) | b; return color; } /** * Convert the specified RGBA data buffer into the RGB5A3 texture format * * This routine converts the RGBA data buffer into the RGB5A3 texture format and returns a pointer to the converted buffer. * * @param rgbaBuffer Buffer containing the temporarily rendered RGBA data. * @param bufferWidth Pixel width of the data buffer. * @param bufferHeight Pixel height of the data buffer. * @return A pointer to the allocated buffer. */ uint32_t* Metaphrasis::convertBufferToRGB5A3(uint32_t* rgbaBuffer, uint16_t bufferWidth, uint16_t bufferHeight) { uint32_t bufferSize = (bufferWidth * bufferHeight) << 1; uint32_t* dataBufferRGB5A3 = (uint32_t *)memalign(32, bufferSize); memset(dataBufferRGB5A3, 0x00, bufferSize); uint32_t *src = (uint32_t *)rgbaBuffer; uint16_t *dst = (uint16_t *)dataBufferRGB5A3; for(uint32_t rows = 0; rows < 4; rows++) { for(uint32_t y = 0; y < bufferHeight; y += 4) { uint32_t bufWid = ((y + rows) * bufferWidth); for(uint32_t x = 0; x < bufferWidth; x += 4) { *dst++ = Metaphrasis::convertRGBAToRGB5A3(src[bufWid + (x + 0)]); *dst++ = Metaphrasis::convertRGBAToRGB5A3(src[bufWid + (x + 1)]); *dst++ = Metaphrasis::convertRGBAToRGB5A3(src[bufWid + (x + 2)]); *dst++ = Metaphrasis::convertRGBAToRGB5A3(src[bufWid + (x + 3)]); } } } DCFlushRange(dataBufferRGB5A3, bufferSize); return dataBufferRGB5A3; }