mirror of
https://github.com/dborth/snes9xgx.git
synced 2024-11-24 11:39:21 +01:00
388 lines
14 KiB
C++
388 lines
14 KiB
C++
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#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) {
|
|
uint8_t r = (((rgba >> 24) & 0xff) * 31) / 255;
|
|
uint8_t g = (((rgba >> 16) & 0xff) * 63) / 255;
|
|
uint8_t b = (((rgba >> 8) & 0xff) * 31) / 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;
|
|
}
|