mirror of
https://github.com/DaedalusX64/daedalus.git
synced 2025-04-02 10:21:48 -04:00
676 lines
18 KiB
C++
676 lines
18 KiB
C++
/*
|
|
Copyright (C) 2001 StrmnNrmn
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program 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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
#include "BuildOptions.h"
|
|
#include "Base/Types.h"
|
|
|
|
#include "DLDebug.h"
|
|
#include "Core/Memory.h"
|
|
#include "Debug/DBGConsole.h"
|
|
#include "Graphics/NativePixelFormat.h"
|
|
#include "HLEGraphics/ConvertFormats.h"
|
|
#include "HLEGraphics/ConvertImage.h"
|
|
#include "HLEGraphics/N64PixelFormat.h"
|
|
#include "HLEGraphics/RDP.h"
|
|
#include "HLEGraphics/TextureInfo.h"
|
|
#include "Base/MathUtil.h"
|
|
#include "Ultra/ultra_gbi.h"
|
|
|
|
namespace
|
|
{
|
|
|
|
struct TextureDestInfo
|
|
{
|
|
explicit TextureDestInfo( ETextureFormat tex_fmt )
|
|
: Format( tex_fmt )
|
|
, Width( 0 )
|
|
, Height( 0 )
|
|
, Pitch( 0 )
|
|
, Data( nullptr )
|
|
, Palette( nullptr )
|
|
{
|
|
}
|
|
|
|
ETextureFormat Format;
|
|
u32 Width; // Describes the width of the locked area. Use lPitch to move between successive lines
|
|
u32 Height; // Describes the height of the locked area
|
|
s32 Pitch; // Specifies the number of bytes on each row (not necessarily bitdepth*width/8)
|
|
void * Data; // Pointer to the top left pixel of the image
|
|
NativePf8888 * Palette;
|
|
};
|
|
|
|
template< u32 Size >
|
|
struct SByteswapInfo;
|
|
|
|
template<> struct SByteswapInfo< 1 >
|
|
{
|
|
enum { Fiddle = 3 };
|
|
};
|
|
template<> struct SByteswapInfo< 2 >
|
|
{
|
|
enum { Fiddle = 2 };
|
|
};
|
|
template<> struct SByteswapInfo< 4 >
|
|
{
|
|
enum { Fiddle = 0 };
|
|
};
|
|
|
|
template< u32 Size >
|
|
struct SSwizzleInfo;
|
|
|
|
template<> struct SSwizzleInfo< 1 >
|
|
{
|
|
enum { Swizzle = 4 };
|
|
};
|
|
template<> struct SSwizzleInfo< 2 >
|
|
{
|
|
enum { Swizzle = 2 };
|
|
};
|
|
template<> struct SSwizzleInfo< 4 >
|
|
{
|
|
enum { Swizzle = 2 };
|
|
};
|
|
|
|
template < typename OutT >
|
|
struct SConvertGeneric
|
|
{
|
|
using ConvertRowFunction = void (*) ( OutT * dst, const u8 * src, u32 src_offset, u32 width );
|
|
|
|
|
|
static void ConvertGeneric( const TextureDestInfo & dsti,
|
|
const TextureInfo & ti,
|
|
ConvertRowFunction swapped_fn,
|
|
ConvertRowFunction unswapped_fn )
|
|
{
|
|
OutT * dst = reinterpret_cast< OutT * >( dsti.Data );
|
|
const u8 * src = g_pu8RamBase;
|
|
u32 src_offset = ti.GetLoadAddress();
|
|
u32 src_pitch = ti.GetPitch();
|
|
|
|
if ( ti.IsSwapped())
|
|
{
|
|
for (u32 y = 0; y < ti.GetHeight(); y++)
|
|
{
|
|
if ((y&1) == 0)
|
|
{
|
|
unswapped_fn( dst, src, src_offset, ti.GetWidth() );
|
|
}
|
|
else
|
|
{
|
|
swapped_fn( dst, src, src_offset, ti.GetWidth() );
|
|
}
|
|
|
|
src_offset += src_pitch;
|
|
dst = reinterpret_cast< OutT * >( (u8*)dst + dsti.Pitch );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (u32 y = 0; y < ti.GetHeight(); y++)
|
|
{
|
|
unswapped_fn( dst, src, src_offset, ti.GetWidth() );
|
|
|
|
src_offset += src_pitch;
|
|
dst = reinterpret_cast< OutT * >( (u8*)dst + dsti.Pitch );
|
|
}
|
|
}
|
|
}
|
|
|
|
};
|
|
using ConvertPalettisedRowFunction = void (*)( NativePf8888 * dst, const u8 * src, u32 src_offset, u32 width, const NativePf8888 * palette );
|
|
|
|
|
|
static void ConvertPalettisedTo8888( const TextureDestInfo & dsti, const TextureInfo & ti,
|
|
const NativePf8888 * palette,
|
|
ConvertPalettisedRowFunction swapped_fn,
|
|
ConvertPalettisedRowFunction unswapped_fn )
|
|
{
|
|
NativePf8888 * dst = reinterpret_cast< NativePf8888 * >( dsti.Data );
|
|
const u8 * src = g_pu8RamBase;
|
|
u32 src_offset = ti.GetLoadAddress();
|
|
u32 src_pitch = ti.GetPitch();
|
|
|
|
if (ti.IsSwapped())
|
|
{
|
|
for (u32 y = 0; y < ti.GetHeight(); y++)
|
|
{
|
|
if ((y&1) == 0)
|
|
{
|
|
unswapped_fn( dst, src, src_offset, ti.GetWidth(), palette );
|
|
}
|
|
else
|
|
{
|
|
swapped_fn( dst, src, src_offset, ti.GetWidth(), palette );
|
|
}
|
|
|
|
src_offset += src_pitch;
|
|
dst = reinterpret_cast< NativePf8888 * >( (u8*)dst + dsti.Pitch );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (u32 y = 0; y < ti.GetHeight(); y++)
|
|
{
|
|
unswapped_fn( dst, src, src_offset, ti.GetWidth(), palette );
|
|
|
|
src_offset += src_pitch;
|
|
dst = reinterpret_cast< NativePf8888 * >( (u8*)dst + dsti.Pitch );
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename OutT>
|
|
static void ConvertPalettisedToCI( const TextureDestInfo & dsti, const TextureInfo & ti,
|
|
void (*swapped_fn)( OutT * dst, const u8 * src, u32 src_offset, u32 width ),
|
|
void (*unswapped_fn)( OutT * dst, const u8 * src, u32 src_offset, u32 width ) )
|
|
{
|
|
OutT * dst = reinterpret_cast< OutT * >( dsti.Data );
|
|
const u8 * src = g_pu8RamBase;
|
|
u32 src_offset = ti.GetLoadAddress();
|
|
u32 src_pitch = ti.GetPitch();
|
|
|
|
if (ti.IsSwapped())
|
|
{
|
|
for (u32 y = 0; y < ti.GetHeight(); y++)
|
|
{
|
|
if ((y&1) == 0)
|
|
{
|
|
unswapped_fn( dst, src, src_offset, ti.GetWidth() );
|
|
}
|
|
else
|
|
{
|
|
swapped_fn( dst, src, src_offset, ti.GetWidth() );
|
|
}
|
|
|
|
src_offset += src_pitch;
|
|
dst = reinterpret_cast< OutT * >( (u8*)dst + dsti.Pitch );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (u32 y = 0; y < ti.GetHeight(); y++)
|
|
{
|
|
unswapped_fn( dst, src, src_offset, ti.GetWidth() );
|
|
|
|
src_offset += src_pitch;
|
|
dst = reinterpret_cast< OutT * >( (u8*)dst + dsti.Pitch );
|
|
}
|
|
}
|
|
}
|
|
|
|
template < typename InT >
|
|
struct SConvert
|
|
{
|
|
enum { Fiddle = SByteswapInfo< sizeof( InT ) >::Fiddle };
|
|
enum { Swizzle = SSwizzleInfo< sizeof( InT ) >::Swizzle };
|
|
|
|
//
|
|
// This routine converts from any format which is > 1 byte to any Psp format.
|
|
//
|
|
template < typename OutT, u32 InFiddle, u32 OutFiddle >
|
|
static inline void ConvertRow( OutT * dst, const u8 * src, u32 src_offset, u32 width )
|
|
{
|
|
DAEDALUS_DL_ASSERT( IsAligned( src_offset, sizeof( InT ) ), "Offset should be correctly aligned" );
|
|
//
|
|
// Need to be careful of this - ensure that it's doing the right thing in all cases and not overflowing rows.
|
|
// This is to ensure that we correctly convert all the texels in a row, even when we're fiddling.
|
|
// If we have a fiddle of 2 for instance, and the row is not a multiple of the fiddle amount
|
|
// then we don't convert enough pixels (we actually poke some values in past the end of the row)
|
|
// and get some random noise at the end instead.
|
|
//
|
|
// There may well be an easier (and less gross) way of doing this if we move the OutFiddle calculation
|
|
// into the source pixel lookup, and just have dst[x] = ...
|
|
//
|
|
width = AlignPow2( width, 1<<OutFiddle );
|
|
|
|
for (u32 x = 0; x < width; x++)
|
|
{
|
|
InT colour( *reinterpret_cast< const InT * >( &src[src_offset ^ InFiddle] ) );
|
|
|
|
dst[x ^ OutFiddle] = ConvertPixelFormat< OutT, InT >( colour );
|
|
|
|
src_offset += sizeof( InT );
|
|
}
|
|
}
|
|
|
|
template < typename OutT >
|
|
static inline void ConvertTextureT( const TextureDestInfo & dsti, const TextureInfo & ti )
|
|
{
|
|
SConvertGeneric< OutT >::ConvertGeneric( dsti, ti,
|
|
ConvertRow< OutT, Fiddle, Swizzle >,
|
|
ConvertRow< OutT, Fiddle, 0 > );
|
|
}
|
|
|
|
static void ConvertTexture( const TextureDestInfo & dsti, const TextureInfo & ti )
|
|
{
|
|
switch( dsti.Format )
|
|
{
|
|
case TexFmt_5650: ConvertTextureT< NativePf5650 >( dsti, ti ); return;
|
|
case TexFmt_5551: ConvertTextureT< NativePf5551 >( dsti, ti ); return;
|
|
case TexFmt_4444: ConvertTextureT< NativePf4444 >( dsti, ti ); return;
|
|
case TexFmt_8888: ConvertTextureT< NativePf8888 >( dsti, ti ); return;
|
|
|
|
case TexFmt_CI4_8888: break;
|
|
case TexFmt_CI8_8888: break;
|
|
|
|
}
|
|
|
|
DAEDALUS_DL_ERROR( "Unhandled format" );
|
|
}
|
|
};
|
|
|
|
struct SConvertIA4
|
|
{
|
|
enum { Fiddle = 0x3 };
|
|
|
|
template < typename OutT, u32 F >
|
|
static inline void ConvertRow( OutT * dst, const u8 * src, u32 src_offset, u32 width )
|
|
{
|
|
// Do two pixels at a time
|
|
for (u32 x = 0; x < width; x+=2)
|
|
{
|
|
u8 b = src[src_offset ^ F];
|
|
|
|
// Even
|
|
dst[x + 0] = OutT( ThreeToEight[(b & 0xE0) >> 5],
|
|
ThreeToEight[(b & 0xE0) >> 5],
|
|
ThreeToEight[(b & 0xE0) >> 5],
|
|
OneToEight[(b & 0x10) >> 4]);
|
|
// Odd
|
|
dst[x + 1] = OutT( ThreeToEight[(b & 0x0E) >> 1],
|
|
ThreeToEight[(b & 0x0E) >> 1],
|
|
ThreeToEight[(b & 0x0E) >> 1],
|
|
OneToEight[(b & 0x01) ] );
|
|
src_offset++;
|
|
}
|
|
|
|
if(width & 1)
|
|
{
|
|
u8 b {src[src_offset ^ F]};
|
|
|
|
// Even
|
|
dst[width-1] = OutT( ThreeToEight[(b & 0xE0) >> 5],
|
|
ThreeToEight[(b & 0xE0) >> 5],
|
|
ThreeToEight[(b & 0xE0) >> 5],
|
|
OneToEight[(b & 0x10) >> 4]);
|
|
}
|
|
}
|
|
|
|
template < typename OutT >
|
|
static inline void ConvertTextureT( const TextureDestInfo & dsti, const TextureInfo & ti )
|
|
{
|
|
SConvertGeneric< OutT >::ConvertGeneric( dsti, ti, ConvertRow< OutT, 0x4 | Fiddle >, ConvertRow< OutT, Fiddle > );
|
|
}
|
|
|
|
static void ConvertTexture( const TextureDestInfo & dsti, const TextureInfo & ti )
|
|
{
|
|
switch( dsti.Format )
|
|
{
|
|
case TexFmt_5650: ConvertTextureT< NativePf5650 >( dsti, ti ); return;
|
|
case TexFmt_5551: ConvertTextureT< NativePf5551 >( dsti, ti ); return;
|
|
case TexFmt_4444: ConvertTextureT< NativePf4444 >( dsti, ti ); return;
|
|
case TexFmt_8888: ConvertTextureT< NativePf8888 >( dsti, ti ); return;
|
|
|
|
case TexFmt_CI4_8888: break;
|
|
case TexFmt_CI8_8888: break;
|
|
|
|
}
|
|
|
|
DAEDALUS_DL_ERROR( "Unhandled format" );
|
|
}
|
|
};
|
|
|
|
struct SConvertI4
|
|
{
|
|
enum { Fiddle = 0x3 };
|
|
|
|
template< typename OutT, u32 F >
|
|
static inline void ConvertRow( OutT * dst, const u8 * src, u32 src_offset, u32 width )
|
|
{
|
|
// Do two pixels at a time
|
|
for ( u32 x = 0; x+1 < width; x+=2 )
|
|
{
|
|
u8 b {src[src_offset ^ F]};
|
|
|
|
// Even
|
|
dst[x + 0] = OutT( FourToEight[(b & 0xF0)>>4],
|
|
FourToEight[(b & 0xF0)>>4],
|
|
FourToEight[(b & 0xF0)>>4],
|
|
FourToEight[(b & 0xF0)>>4] );
|
|
// Odd
|
|
dst[x + 1] = OutT( FourToEight[(b & 0x0F)],
|
|
FourToEight[(b & 0x0F)],
|
|
FourToEight[(b & 0x0F)],
|
|
FourToEight[(b & 0x0F)] );
|
|
|
|
src_offset++;
|
|
}
|
|
|
|
if(width & 1)
|
|
{
|
|
u8 b {src[src_offset ^ F]};
|
|
|
|
// Even
|
|
dst[width-1] = OutT( FourToEight[(b & 0xF0)>>4],
|
|
FourToEight[(b & 0xF0)>>4],
|
|
FourToEight[(b & 0xF0)>>4],
|
|
FourToEight[(b & 0xF0)>>4] );
|
|
|
|
}
|
|
}
|
|
|
|
template < typename OutT >
|
|
static inline void ConvertTextureT( const TextureDestInfo & dsti, const TextureInfo & ti )
|
|
{
|
|
SConvertGeneric< OutT >::ConvertGeneric( dsti, ti, ConvertRow< OutT, 0x4 | Fiddle >, ConvertRow< OutT, Fiddle > );
|
|
}
|
|
|
|
static void ConvertTexture( const TextureDestInfo & dsti, const TextureInfo & ti )
|
|
{
|
|
switch( dsti.Format )
|
|
{
|
|
case TexFmt_5650: ConvertTextureT< NativePf5650 >( dsti, ti ); return;
|
|
case TexFmt_5551: ConvertTextureT< NativePf5551 >( dsti, ti ); return;
|
|
case TexFmt_4444: ConvertTextureT< NativePf4444 >( dsti, ti ); return;
|
|
case TexFmt_8888: ConvertTextureT< NativePf8888 >( dsti, ti ); return;
|
|
|
|
case TexFmt_CI4_8888: break;
|
|
case TexFmt_CI8_8888: break;
|
|
|
|
}
|
|
|
|
DAEDALUS_DL_ERROR( "Unhandled format" );
|
|
}
|
|
};
|
|
|
|
static void ConvertPalette(ETLutFmt tlut_format, NativePf8888 * dst, const void * src, u32 count)
|
|
{
|
|
if( tlut_format == kTT_IA16 )
|
|
{
|
|
const N64PfIA16 * palette = static_cast< const N64PfIA16 * >( src );
|
|
|
|
for( u32 i = 0; i < count; ++i )
|
|
{
|
|
dst[ i ] = NativePf8888::Make( palette[ i ^ U16H_TWIDDLE ] );
|
|
}
|
|
}
|
|
else //if( tlut_format == kTT_RGBA16 )
|
|
{
|
|
// NB: assume RGBA for all other tlut_formats.
|
|
const N64Pf5551 * palette = static_cast< const N64Pf5551 * >( src );
|
|
|
|
for( u32 i = 0; i < count; ++i )
|
|
{
|
|
dst[ i ] = NativePf8888::Make( palette[ i ^ U16H_TWIDDLE ] );
|
|
}
|
|
}
|
|
}
|
|
|
|
template< u32 F >
|
|
static void ConvertCI4_Row( NativePfCI44 * dst, const u8 * src, u32 src_offset, u32 width )
|
|
{
|
|
for (u32 x = 0; x+1 < width; x+=2)
|
|
{
|
|
u8 b = src[src_offset ^ F];
|
|
|
|
dst[ x/2 ].Bits = (b >> 4) | (b << 4);
|
|
|
|
src_offset++;
|
|
}
|
|
|
|
// Handle any remaining odd pixels
|
|
if( width & 1 )
|
|
{
|
|
u8 b {src[src_offset ^ F]};
|
|
|
|
dst[ width/2 ].Bits = (b >> 4) | 0;
|
|
}
|
|
}
|
|
|
|
template< u32 F >
|
|
static void ConvertCI4_Row_To_8888( NativePf8888 * dst, const u8 * src, u32 src_offset, u32 width, const NativePf8888 * palette )
|
|
{
|
|
for (u32 x = 0; x+1 < width; x+=2)
|
|
{
|
|
u8 b = src[src_offset ^ F];
|
|
|
|
u32 bhi = (u32)(b&0xf0)>>4;
|
|
u32 blo = (u32)(b&0x0f);
|
|
|
|
dst[ x + 0 ] = palette[ bhi ]; // Remember palette has already been swapped
|
|
dst[ x + 1 ] = palette[ blo ];
|
|
|
|
src_offset++;
|
|
}
|
|
|
|
// Handle any remaining odd pixels
|
|
if(width & 1)
|
|
{
|
|
u8 b = src[src_offset ^ F];
|
|
|
|
u8 bhi = (u8)((b&0xf0)>>4);
|
|
|
|
dst[width-1] = palette[ bhi ]; // Remember palette has already been swapped
|
|
}
|
|
}
|
|
|
|
template< u32 F >
|
|
static void ConvertCI8_Row( NativePfCI8 * dst, const u8 * src, u32 src_offset, u32 width )
|
|
{
|
|
for (u32 x = 0; x < width; x++)
|
|
{
|
|
dst[ x ].Bits = src[src_offset ^ F];
|
|
src_offset++;
|
|
}
|
|
}
|
|
|
|
template< u32 F >
|
|
static void ConvertCI8_Row_To_8888( NativePf8888 * dst, const u8 * src, u32 src_offset, u32 width, const NativePf8888 * palette )
|
|
{
|
|
for (u32 x = 0; x < width; x++)
|
|
{
|
|
u8 b {src[src_offset ^ F]};
|
|
dst[ x ] = palette[ b ]; // Remember palette has already been swapped
|
|
src_offset++;
|
|
}
|
|
}
|
|
|
|
static void ConvertRGBA16(const TextureDestInfo & dsti, const TextureInfo & ti)
|
|
{
|
|
SConvert< N64Pf5551 >::ConvertTexture( dsti, ti );
|
|
}
|
|
|
|
static void ConvertRGBA32(const TextureDestInfo & dsti, const TextureInfo & ti)
|
|
{
|
|
// Did have Fiddle of 8 here, pretty sure this was wrong (should have been 4)
|
|
SConvert< N64Pf8888 >::ConvertTexture( dsti, ti );
|
|
}
|
|
|
|
static void ConvertIA4(const TextureDestInfo & dsti, const TextureInfo & ti)
|
|
{
|
|
SConvertIA4::ConvertTexture( dsti, ti );
|
|
}
|
|
|
|
static void ConvertIA8(const TextureDestInfo & dsti, const TextureInfo & ti)
|
|
{
|
|
SConvert< N64PfIA8 >::ConvertTexture( dsti, ti );
|
|
}
|
|
|
|
static void ConvertIA16(const TextureDestInfo & dsti, const TextureInfo & ti)
|
|
{
|
|
SConvert< N64PfIA16 >::ConvertTexture( dsti, ti );
|
|
}
|
|
|
|
static void ConvertI4(const TextureDestInfo & dsti, const TextureInfo & ti)
|
|
{
|
|
SConvertI4::ConvertTexture( dsti, ti );
|
|
}
|
|
|
|
static void ConvertI8(const TextureDestInfo & dsti, const TextureInfo & ti)
|
|
{
|
|
SConvert< N64PfI8 >::ConvertTexture( dsti, ti );
|
|
}
|
|
|
|
static void ConvertCI8(const TextureDestInfo & dsti, const TextureInfo & ti)
|
|
{
|
|
|
|
NativePf8888 temp_palette[256];
|
|
|
|
NativePf8888 * dst_palette = dsti.Palette ? reinterpret_cast< NativePf8888 * >( dsti.Palette ) : temp_palette;
|
|
const void * src_palette = g_pu8RamBase + ti.GetTlutAddress();
|
|
|
|
ConvertPalette(ti.GetTLutFormat(), dst_palette, src_palette, 256);
|
|
|
|
switch( dsti.Format )
|
|
{
|
|
case TexFmt_8888:
|
|
ConvertPalettisedTo8888( dsti, ti, dst_palette,
|
|
ConvertCI8_Row_To_8888< 0x4 | 0x3 >,
|
|
ConvertCI8_Row_To_8888< 0x3 > );
|
|
break;
|
|
|
|
case TexFmt_CI8_8888:
|
|
ConvertPalettisedToCI( dsti, ti,
|
|
ConvertCI8_Row< 0x4 | 0x3 >,
|
|
ConvertCI8_Row< 0x3 > );
|
|
break;
|
|
|
|
default:
|
|
DAEDALUS_ERROR( "Unhandled format for CI8 textures" );
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void ConvertYUV16(const TextureDestInfo & dsti, const TextureInfo & ti)
|
|
{
|
|
u32 * dst = static_cast<u32*>(dsti.Data);
|
|
u32 dst_row_stride = dsti.Pitch / sizeof(u32);
|
|
u32 dst_row_offset = 0;
|
|
|
|
const u8 * src = g_pu8RamBase;
|
|
u32 src_row_stride = ti.GetPitch();
|
|
u32 src_row_offset = ti.GetLoadAddress();
|
|
|
|
u32 width = ti.GetWidth();
|
|
u32 height = ti.GetHeight();
|
|
|
|
// NB! YUV/16 line needs to be doubled.
|
|
src_row_stride *= 2;
|
|
|
|
if (ti.IsSwapped())
|
|
{
|
|
//TODO: This should be easy to implement but I would like to find first a game that uses it
|
|
DAEDALUS_ERROR("Swapped YUV16 textures are not supported yet");
|
|
}
|
|
else
|
|
{
|
|
for (u32 y = 0; y < height; y++)
|
|
{
|
|
u32 src_offset = src_row_offset;
|
|
u32 dst_offset = dst_row_offset;
|
|
|
|
// Do two pixels at a time
|
|
for (u32 x = 0; x < width; x += 2)
|
|
{
|
|
s32 y0 = src[src_offset+2];
|
|
s32 y1 = src[src_offset+0];
|
|
s32 u0 = src[src_offset+3];
|
|
s32 v0 = src[src_offset+1];
|
|
|
|
dst[dst_offset+0] = YUV16(y0,u0,v0);
|
|
dst[dst_offset+1] = YUV16(y1,u0,v0);
|
|
|
|
src_offset += 4;
|
|
dst_offset += 2;
|
|
}
|
|
src_row_offset += src_row_stride;
|
|
dst_row_offset += dst_row_stride;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ConvertCI4(const TextureDestInfo & dsti, const TextureInfo & ti)
|
|
{
|
|
NativePf8888 temp_palette[16];
|
|
|
|
NativePf8888 * dst_palette = dsti.Palette ? reinterpret_cast< NativePf8888 * >( dsti.Palette ) : temp_palette;
|
|
const void * src_palette = g_pu8RamBase + ti.GetTlutAddress();
|
|
|
|
ConvertPalette(ti.GetTLutFormat(), dst_palette, src_palette, 16);
|
|
|
|
switch( dsti.Format )
|
|
{
|
|
case TexFmt_8888:
|
|
ConvertPalettisedTo8888( dsti, ti, dst_palette,
|
|
ConvertCI4_Row_To_8888< 0x4 | 0x3 >,
|
|
ConvertCI4_Row_To_8888< 0x3 > );
|
|
break;
|
|
|
|
case TexFmt_CI4_8888:
|
|
ConvertPalettisedToCI( dsti, ti,
|
|
ConvertCI4_Row< 0x4 | 0x3 >,
|
|
ConvertCI4_Row< 0x3 > );
|
|
break;
|
|
|
|
default:
|
|
DAEDALUS_ERROR( "Unhandled format for CI4 textures" );
|
|
break;
|
|
}
|
|
}
|
|
|
|
} // anonymous namespace
|
|
using ConvertFunction = void (*)( const TextureDestInfo & dsti, const TextureInfo & ti);
|
|
|
|
static const ConvertFunction gConvertFunctions[ 32 ] =
|
|
{
|
|
// 4bpp 8bpp 16bpp 32bpp
|
|
nullptr, nullptr, ConvertRGBA16, ConvertRGBA32,// RGBA
|
|
nullptr, nullptr, ConvertYUV16, nullptr, // YUV
|
|
ConvertCI4, ConvertCI8, nullptr, nullptr, // CI
|
|
ConvertIA4, ConvertIA8, ConvertIA16, nullptr, // IA
|
|
ConvertI4, ConvertI8, nullptr, nullptr, // I
|
|
nullptr, nullptr, nullptr, nullptr, // ?
|
|
nullptr, nullptr, nullptr, nullptr, // ?
|
|
nullptr, nullptr, nullptr, nullptr // ?
|
|
};
|
|
|
|
bool ConvertTexture(const TextureInfo & ti,
|
|
void * texels,
|
|
NativePf8888 * palette,
|
|
ETextureFormat texture_format,
|
|
u32 pitch)
|
|
{
|
|
//memset( texels, 0, buffer_size );
|
|
|
|
TextureDestInfo dsti( texture_format );
|
|
dsti.Data = texels;
|
|
dsti.Width = ti.GetWidth();
|
|
dsti.Height = ti.GetHeight();
|
|
dsti.Pitch = pitch;
|
|
dsti.Palette = palette;
|
|
|
|
const ConvertFunction fn = gConvertFunctions[ (ti.GetFormat() << 2) | ti.GetSize() ];
|
|
if( fn )
|
|
{
|
|
fn( dsti, ti );
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|