mupen64plus-oldsvn/rice_video/RDP_Texture.h
Scott Knauert edcef05047 Changes: Fixed nearly all warnings in Rice (Issue 24) except
one pointer arithmetic one in TextureFilters.cpp (see tracker).
Once that is fixed Issue 24 in current form can be closed.

Testing done: Code compiles for normal and debug use without 
any -Wall warnings and seems to yield the same results and previous 
svn on my r300.
2008-04-04 19:18:54 +00:00

2383 lines
66 KiB
C

/*
Copyright (C) 2002 Rice1964
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.
*/
// Texture related ucode
uint32 g_TmemFlag[16];
void SetTmemFlag(uint32 tmemAddr, uint32 size);
bool IsTmemFlagValid(uint32 tmemAddr);
uint32 GetValidTmemInfoIndex(uint32 tmemAddr);
void EnhanceTexture(TxtrCacheEntry *pEntry);
void MirrorTexture(uint32 tileno, TxtrCacheEntry *pEntry);
void LoadHiresTexture( TxtrCacheEntry &entry );
extern TMEMLoadMapInfo g_tmemInfo0; // Info for Tmem=0
extern TMEMLoadMapInfo g_tmemInfo1; // Info for Tmem=0x100
TmemType g_Tmem;
/************************************************************************/
/* */
/************************************************************************/
uint32 sizeShift[4] = {2,1,0,0};
uint32 sizeIncr[4] = {3,1,0,0};
uint32 sizeBytes[4] = {0,1,2,4};
inline uint32 Txl2Words(uint32 width, uint32 size)
{
if( size == TXT_SIZE_4b )
return max(1, width/16);
else
return max(1, width*sizeBytes[size]/8);
}
inline uint32 CalculateImgSize(uint32 width, uint32 height, uint32 size)
{
//(((width)*(height) + siz##_INCR) >> siz##_SHIFT) -1
return (((width)*(height) + sizeIncr[size]) >> sizeShift[size]) -1;
}
inline uint32 CalculateDXT(uint32 txl2words)
{
//#define CALC_DXT(width, b_txl) ((2048 + TXL2WORDS(width, b_txl) - 1) / TXL2WORDS(width, b_txl))
if( txl2words == 0 ) return 1;
else return (2048+txl2words-1)/txl2words;
}
inline uint32 ReverseDXT(uint32 val, uint32 lrs, uint32 width, uint32 size)
{
//#define TXL2WORDS(txls, b_txl) MAX(1, ((txls)*(b_txl)/8))
if( val == 0x800 ) return 1;
unsigned int low = 2047/val;
if( CalculateDXT(low) > val ) low++;
unsigned int high = 2047/(val-1);
if( low == high ) return low;
for( unsigned int i=low; i<=high; i++ )
{
if( Txl2Words(width, size) == i )
return i;
}
return (low+high)/2; //dxt = 2047 / (dxt-1);
}
// The following inline assemble routines are borrowed from glN64, I am too tired to
// rewrite these routine by myself.
// Rice, 02/24/2004
static uint32 g_value;
static uint16 g_value16;
inline void UnswapCopy( void *src, void *dest, uint32 numBytes )
{
#if defined(__INTEL_COMPILER)
__asm
{
mov ecx, 0
mov esi, dword ptr [src]
mov edi, dword ptr [dest]
mov ebx, esi
and ebx, 3 // ebx = number of leading bytes
cmp ebx, 0
jz StartDWordLoop
neg ebx
add ebx, 4
cmp ebx, [numBytes]
jle NotGreater
mov ebx, [numBytes]
NotGreater:
mov ecx, ebx
xor esi, 3
LeadingLoop: // Copies leading bytes, in reverse order (un-swaps)
mov al, byte ptr [esi]
mov byte ptr [edi], al
sub esi, 1
add edi, 1
loop LeadingLoop
add esi, 5
StartDWordLoop:
mov ecx, dword ptr [numBytes]
sub ecx, ebx // Don't copy what's already been copied
mov ebx, ecx
and ebx, 3
// add ecx, 3 // Round up to nearest dword
shr ecx, 2
cmp ecx, 0 // If there's nothing to do, don't do it
jle StartTrailingLoop
// Copies from source to destination, bswap-ing first
DWordLoop:
mov eax, dword ptr [esi]
bswap eax
mov dword ptr [edi], eax
add esi, 4
add edi, 4
loop DWordLoop
StartTrailingLoop:
cmp ebx, 0
jz Done
mov ecx, ebx
xor esi, 3
TrailingLoop:
mov al, byte ptr [esi]
mov byte ptr [edi], al
sub esi, 1
add edi, 1
loop TrailingLoop
Done:
}
#elif defined(__GNUC__) && defined(__x86_64__)
asm volatile(" movl %k1, %%ebx \n"
" andl $3, %%ebx \n"
" cmpl $0, %%ebx \n"
" jz 2f \n"
" negl %%ebx \n"
" addl $4, %%ebx \n"
" cmpl %k2, %%ebx \n"
" jle 0f \n"
" movl %k2, %%ebx \n"
"0: \n"
" movl %%ebx, %%ecx \n"
" xor $3, %1 \n"
"1: \n"
" movb (%1), %%al \n"
" movb %%al, (%0) \n"
" sub $1, %1 \n"
" add $1, %0 \n"
" decl %%ecx \n"
" jne 1b \n"
" add $5, %1 \n"
"2: \n"
" movl %k2, %%ecx \n"
" subl %%ebx, %%ecx \n"
" movl %%ecx, %%ebx \n"
" andl $3, %%ebx \n"
" shrl $2, %%ecx \n"
" cmpl $0, %%ecx \n"
" jle 4f \n"
"3: \n"
" movl (%1), %%eax \n"
" bswapl %%eax \n"
" movl %%eax, (%0) \n"
" add $4, %1 \n"
" add $4, %0 \n"
" decl %%ecx \n"
" jne 3b \n"
"4: \n"
" cmpl $0, %%ebx \n"
" jz 6f \n"
" xor $3, %1 \n"
"5: \n"
" movb (%1), %%al \n"
" movb %%al, (%0) \n"
" sub $1, %1 \n"
" add $1, %0 \n"
" decl %%ebx \n"
" jne 5b \n"
"6: \n"
:"+r"(dest), "+r"(src)
:"r"(numBytes)
: "memory", "cc", "%rax", "%rbx", "%rcx"
);
#else // GCC assumed
# ifndef PIC
g_src = src;
g_dest = dest;
g_numBytes = numBytes;
asm volatile ("pusha \n"
"mov $0, %%ecx \n"
"mov g_src, %%esi \n"
"mov g_dest, %%edi \n"
"mov %%esi, %%ebx \n"
"and $3, %%ebx \n" // ebx = number of leading bytes
"cmp $0, %%ebx \n"
"jz 2f \n" //jz StartDWordLoop
"neg %%ebx \n"
"add $4, %%ebx \n"
"cmp g_numBytes, %%ebx \n"
"jle 0f \n" //jle NotGreater
"mov g_numBytes, %%ebx \n"
"0: \n" //NotGreater:
"mov %%ebx, %%ecx \n"
"xor $3, %%esi \n"
"1: \n" //LeadingLoop: // Copies leading bytes, in reverse order (un-swaps)
"mov (%%esi), %%al \n"
"mov %%al, (%%edi) \n"
"sub $1, %%esi \n"
"add $1, %%edi \n"
"loop 1b \n" //loop LeadingLoop
"add $5, %%esi \n"
"2: \n" //StartDWordLoop:
"mov g_numBytes, %%ecx \n"
"sub %%ebx, %%ecx \n" // Don't copy what's already been copied
"mov %%ecx, %%ebx \n"
"and $3, %%ebx \n"
// add ecx, 3 // Round up to nearest dword
"shr $2, %%ecx \n"
"cmp $0, %%ecx \n" // If there's nothing to do, don't do it
"jle 4f \n" //jle StartTrailingLoop
// Copies from source to destination, bswap-ing first
"3: \n" //DWordLoop:
"mov (%%esi), %%eax \n"
"bswap %%eax \n"
"mov %%eax, (%%edi) \n"
"add $4, %%esi \n"
"add $4, %%edi \n"
"loop 3b \n" //loop DWordLoop
"4: \n" //StartTrailingLoop:
"cmp $0, %%ebx \n"
"jz 6f \n" //jz Done
"mov %%ebx, %%ecx \n"
"xor $3, %%esi \n"
"5: \n" //TrailingLoop:
"mov (%%esi), %%al \n"
"mov %%al, (%%edi) \n"
"sub $1, %%esi \n"
"add $1, %%edi \n"
"loop 5b \n" //loop TrailingLoop
"6: \n" //Done:
"popa \n"
:
:
: "memory", "cc"
);
# else // PIC
unsigned int saveEBX;
asm volatile ("mov %%ebx, %2 \n"
"mov $0, %%ecx \n"
"mov %0, %%esi \n"
"mov %1, %%edi \n"
"mov %%esi, %%ebx \n"
"and $3, %%ebx \n" // ebx = number of leading bytes
"cmp $0, %%ebx \n"
"jz 2f \n" //jz StartDWordLoop
"neg %%ebx \n"
"add $4, %%ebx \n"
"cmp %3, %%ebx \n"
"jle 0f \n" //jle NotGreater
"mov %3, %%ebx \n"
"0: \n" //NotGreater:
"mov %%ebx, %%ecx \n"
"xor $3, %%esi \n"
"1: \n" //LeadingLoop: // Copies leading bytes, in reverse order (un-swaps)
"mov (%%esi), %%al \n"
"mov %%al, (%%edi) \n"
"sub $1, %%esi \n"
"add $1, %%edi \n"
"loop 1b \n" //loop LeadingLoop
"add $5, %%esi \n"
"2: \n" //StartDWordLoop:
"mov %3, %%ecx \n"
"sub %%ebx, %%ecx \n" // Don't copy what's already been copied
"mov %%ecx, %%ebx \n"
"and $3, %%ebx \n"
// add ecx, 3 // Round up to nearest dword
"shr $2, %%ecx \n"
"cmp $0, %%ecx \n" // If there's nothing to do, don't do it
"jle 4f \n" //jle StartTrailingLoop
// Copies from source to destination, bswap-ing first
"3: \n" //DWordLoop:
"mov (%%esi), %%eax \n"
"bswap %%eax \n"
"mov %%eax, (%%edi) \n"
"add $4, %%esi \n"
"add $4, %%edi \n"
"loop 3b \n" //loop DWordLoop
"4: \n" //StartTrailingLoop:
"cmp $0, %%ebx \n"
"jz 6f \n" //jz Done
"mov %%ebx, %%ecx \n"
"xor $3, %%esi \n"
"5: \n" //TrailingLoop:
"mov (%%esi), %%al \n"
"mov %%al, (%%edi) \n"
"sub $1, %%esi \n"
"add $1, %%edi \n"
"loop 5b \n" //loop TrailingLoop
"6: \n" //Done:
"mov %2, %%ebx \n"
:
: "m"(src), "m"(dest), "m"(saveEBX), "m"(numBytes)
: "memory", "cc", "%ecx", "%esi", "%edi", "%eax"
);
# endif // PIC
#endif
}
inline void DWordInterleave( void *mem, uint32 numDWords )
{
#ifdef __INTEL_COMPILER
__asm {
mov esi, dword ptr [mem]
mov edi, dword ptr [mem]
add edi, 4
mov ecx, dword ptr [numDWords]
DWordInterleaveLoop:
mov eax, dword ptr [esi]
mov ebx, dword ptr [edi]
mov dword ptr [esi], ebx
mov dword ptr [edi], eax
add esi, 8
add edi, 8
loop DWordInterleaveLoop
}
#elif defined(__GNUC__) && defined(__x86_64__)
asm volatile("0: \n"
" movl (%0), %%eax \n"
" movl 8(%0), %%ebx \n"
" movl %%eax, 8(%0) \n"
" movl %%ebx, (%0) \n"
" add $8, %0 \n"
" decl %k1 \n"
" jne 0b \n"
: "+r"(mem), "+r"(numDWords)
:
: "memory", "cc", "%rax", "%rbx"
);
#else // GCC assumed
# ifndef PIC
g_mem = mem;
g_numDWords = numDWords;
asm volatile ("pusha \n"
"mov g_mem, %%esi \n"
"mov g_mem, %%edi \n"
"add $4, %%edi \n"
"mov g_numDWords, %%ecx \n"
"0: \n" //DWordInterleaveLoop:
"mov (%%esi), %%eax \n"
"mov (%%edi), %%ebx \n"
"mov %%ebx, (%%esi) \n"
"mov %%eax, (%%edi) \n"
"add $8, %%esi \n"
"add $8, %%edi \n"
"loop 0b \n" //loop DWordInterleaveLoop
"popa \n"
:
:
: "memory", "cc"
);
# else // PIC
unsigned int saveEBX;
asm volatile ("mov %%ebx, %2 \n"
"mov %0, %%esi \n"
"mov %0, %%edi \n"
"add $4, %%edi \n"
"mov %1, %%ecx \n"
"0: \n" //DWordInterleaveLoop:
"mov (%%esi), %%eax \n"
"mov (%%edi), %%ebx \n"
"mov %%ebx, (%%esi) \n"
"mov %%eax, (%%edi) \n"
"add $8, %%esi \n"
"add $8, %%edi \n"
"loop 0b \n" //loop DWordInterleaveLoop
"mov %2, %%ebx \n"
:
: "m"(mem), "m"(numDWords), "m"(saveEBX)
: "memory", "cc", "%esi", "%edi", "%ecx", "%eax"
);
# endif // PIC
#endif
}
inline void QWordInterleave( void *mem, uint32 numDWords )
{
#ifdef __INTEL_COMPILER
__asm
{
// Interleave the line on the qword
mov esi, dword ptr [mem]
mov edi, dword ptr [mem]
add edi, 8
mov ecx, dword ptr [numDWords]
shr ecx, 1
QWordInterleaveLoop:
mov eax, dword ptr [esi]
mov ebx, dword ptr [edi]
mov dword ptr [esi], ebx
mov dword ptr [edi], eax
add esi, 4
add edi, 4
mov eax, dword ptr [esi]
mov ebx, dword ptr [edi]
mov dword ptr [esi], ebx
mov dword ptr [edi], eax
add esi, 12
add edi, 12
loop QWordInterleaveLoop
}
#elif defined(__GNUC__) && defined(__x86_64__)
asm volatile(" shr $1, %k1 \n"
"0: \n"
" mov (%0), %%rax \n"
" mov 8(%0), %%rbx \n"
" mov %%rax, 8(%0) \n"
" mov %%rbx, (%0) \n"
" add $16, %0 \n"
" decl %k1 \n"
" jne 0b \n"
: "+r"(mem), "+r"(numDWords)
:
: "memory", "cc", "%rax", "%rbx"
);
#else // GCC assumed
# ifndef PIC
g_mem = mem;
g_numDWords = numDWords;
asm volatile("pusha \n"
// Interleave the line on the qword
"mov g_mem, %%esi \n"
"mov g_mem, %%edi \n"
"add $8, %%edi \n"
"mov g_numDWords, %%ecx \n"
"shr $1, %%ecx \n"
"0: \n" //QWordInterleaveLoop:
"mov (%%esi), %%eax \n"
"mov (%%edi), %%ebx \n"
"mov %%ebx, (%%esi) \n"
"mov %%eax, (%%edi) \n"
"add $4, %%esi \n"
"add $4, %%edi \n"
"mov (%%esi), %%eax \n"
"mov (%%edi), %%ebx \n"
"mov %%ebx, (%%esi) \n"
"mov %%eax, (%%edi) \n"
"add $12, %%esi \n"
"add $12, %%edi \n"
"loop 0b \n" //loop QWordInterleaveLoop
"popa \n"
:
:
: "memory", "cc"
);
# else // PIC
unsigned int saveEBX;
asm volatile("mov %%ebx, %2 \n"
// Interleave the line on the qword
"mov %0, %%esi \n"
"mov %0, %%edi \n"
"add $8, %%edi \n"
"mov %1, %%ecx \n"
"shr $1, %%ecx \n"
"0: \n" //QWordInterleaveLoop:
"mov (%%esi), %%eax \n"
"mov (%%edi), %%ebx \n"
"mov %%ebx, (%%esi) \n"
"mov %%eax, (%%edi) \n"
"add $4, %%esi \n"
"add $4, %%edi \n"
"mov (%%esi), %%eax \n"
"mov (%%edi), %%ebx \n"
"mov %%ebx, (%%esi) \n"
"mov %%eax, (%%edi) \n"
"add $12, %%esi \n"
"add $12, %%edi \n"
"loop 0b \n" //loop QWordInterleaveLoop
"mov %2, %%ebx \n"
:
: "m"(mem), "m"(numDWords), "m"(saveEBX)
: "memory", "cc", "%esi", "%edi", "%ecx", "%eax"
);
# endif // PIC
#endif
}
inline uint32 swapdword( uint32 value )
{
#ifdef __INTEL_COMPILER
__asm
{
mov eax, dword ptr [value]
bswap eax
}
#elif defined(__GNUC__) && defined(__x86_64__)
asm volatile(" bswapl %k0 \n"
: "+r"(value)
:
:
);
return value;
#else // GCC assumed
g_value = value;
asm volatile("pusha \n"
"mov g_value, %%eax \n"
"bswap %%eax \n"
"mov %%eax, g_value \n"
"popa \n"
:
:
: "memory", "cc"
);
return g_value;
#endif
}
inline uint16 swapword( uint16 value )
{
#ifdef __INTEL_COMPILER
__asm
{
mov ax, word ptr [value]
xchg ah, al
}
#elif defined(__GNUC__) && defined(__x86_64__)
asm volatile("xchg %%al, %%ah \n"
: "+a"(value)
:
:
);
return value;
#else // GCC assumed
g_value16 = value;
asm volatile("pusha \n"
"mov g_value16, %%ax \n"
"xchg %%al, %%ah \n"
"mov %%ax, g_value16 \n"
"popa \n"
:
:
: "memory", "cc"
);
return g_value16;
#endif
}
void ComputeTileDimension(int mask, int clamp, int mirror, int width, uint32 &widthToCreate, uint32 &widthToLoad)
{
int maskwidth = mask > 0 ? (1<<mask) : 0;
widthToCreate = widthToLoad = width;
if( mask > 0 )
{
if( width > maskwidth )
{
if( clamp == 0 )
{
// clamp is not used, so just use the dwTileMaskWidth as the real width
widthToCreate = widthToLoad = maskwidth;
}
else
{
widthToLoad = maskwidth;
//gti.WidthToCreate = dwTileWidth;
// keep the current WidthToCreate, we will do mirror/wrap
// during texture loading, not during rendering
}
}
else if( width < maskwidth )
{
// dwTileWidth < dwTileMaskWidth
if( clamp == 0 )
{
if( maskwidth%width == 0 )
{
if( (maskwidth/width)%2 == 0 || mirror == 0 )
{
// Do nothing
// gti.WidthToLoad = gti.WidthToCreate = gRDP.tiles[tileno].dwWidth = dwTileWidth
}
else
{
widthToCreate = maskwidth;
}
}
else
{
widthToCreate = maskwidth;
//widthToLoad = maskwidth;
}
}
else
{
widthToCreate = maskwidth;
//widthToLoad = maskwidth;
}
}
else // dwTileWidth == dwTileMaskWidth
{
}
// Some hacks, to limit the image size
if( mask >= 8 )
{
if( maskwidth / width >= 2 )
{
widthToCreate = width;
}
}
}
}
bool conkerSwapHack=false;
bool CalculateTileSizes_method_2(int tileno, TMEMLoadMapInfo *info, TxtrInfo &gti)
{
Tile &tile = gRDP.tiles[tileno];
Tile &loadtile = gRDP.tiles[RDP_TXT_LOADTILE];
uint32 dwPitch;
// Now Initialize the texture dimension
int dwTileWidth;
int dwTileHeight;
if( info->bSetBy == CMD_LOADTILE )
{
if( tile.sl >= tile.sh )
{
dwTileWidth = info->dwWidth; // From SetTImage
dwTileWidth = dwTileWidth << info->dwSize >> tile.dwSize;
}
else
{
dwTileWidth= tile.sh - tile.sl + 1;
}
if( tile.tl >= tile.th )
{
dwTileHeight= info->th - info->tl + 1;
}
else
{
dwTileHeight= tile.th - tile.tl + 1;
}
}
else
{
if( tile.dwMaskS == 0 || tile.bClampS )
{
dwTileWidth = tile.hilite_sh - tile.hilite_sl +1;
if( dwTileWidth < tile.sh - tile.sl +1 )
dwTileWidth = tile.sh - tile.sl +1;
if( dwTileWidth <= 0 )
{
DebuggerAppendMsg("Error");
}
}
else
{
if( tile.dwMaskS < 8 )
dwTileWidth = (1 << tile.dwMaskS );
else if( tile.dwLine )
{
dwTileWidth = (tile.dwLine<<5)>>tile.dwSize;
}
else
{
if( tile.sl <= tile.sh )
{
dwTileWidth = tile.sh - tile.sl +1;
}
else if( loadtile.sl <= loadtile.sh )
{
dwTileWidth = loadtile.sh - loadtile.sl +1;
}
else
{
dwTileWidth = tile.sh - tile.sl +1;
}
}
}
if( tile.dwMaskT == 0 || tile.bClampT )
{
dwTileHeight= tile.hilite_th - tile.hilite_tl +1;
if( dwTileHeight < tile.th - tile.tl +1 )
dwTileHeight = tile.th - tile.tl +1;
if( dwTileHeight <= 0 )
{
DebuggerAppendMsg("Error");
}
}
else
{
if( tile.dwMaskT < 8 )
dwTileHeight = (1 << tile.dwMaskT );
else if( tile.tl <= tile.th )
{
dwTileHeight = tile.th - tile.tl +1;
}
else if( loadtile.tl <= loadtile.th )
{
dwTileHeight = loadtile.th - loadtile.tl +1;
}
else
{
dwTileHeight = tile.th - tile.tl +1;
}
}
}
int dwTileMaskWidth = tile.dwMaskS > 0 ? (1 << tile.dwMaskS ) : 0;
int dwTileMaskHeight = tile.dwMaskT > 0 ? (1 << tile.dwMaskT ) : 0;
if( dwTileWidth < 0 || dwTileHeight < 0)
{
if( dwTileMaskWidth > 0 )
dwTileWidth = dwTileMaskWidth;
else if( dwTileWidth < 0 )
dwTileWidth = -dwTileWidth;
if( dwTileMaskHeight > 0 )
dwTileHeight = dwTileMaskHeight;
else if( dwTileHeight < 0 )
dwTileHeight = -dwTileHeight;
}
if( dwTileWidth-dwTileMaskWidth == 1 && dwTileMaskWidth && dwTileHeight-dwTileMaskHeight == 1 && dwTileMaskHeight )
{
// Hack for Mario Kart
dwTileWidth--;
dwTileHeight--;
}
ComputeTileDimension(tile.dwMaskS, tile.bClampS,
tile.bMirrorS, dwTileWidth, gti.WidthToCreate, gti.WidthToLoad);
tile.dwWidth = gti.WidthToCreate;
ComputeTileDimension(tile.dwMaskT, tile.bClampT,
tile.bMirrorT, dwTileHeight, gti.HeightToCreate, gti.HeightToLoad);
tile.dwHeight = gti.HeightToCreate;
#ifdef _DEBUG
if( gti.WidthToCreate < gti.WidthToLoad )
TRACE2("Check me, width to create = %d, width to load = %d", gti.WidthToCreate, gti.WidthToLoad);
if( gti.HeightToCreate < gti.HeightToLoad )
TRACE2("Check me, height to create = %d, height to load = %d", gti.HeightToCreate, gti.HeightToLoad);
#endif
gti.bSwapped = info->bSwapped;
if( info->bSetBy == CMD_LOADTILE )
{
// It was a tile - the pitch is set by LoadTile
dwPitch = info->dwWidth<<(info->dwSize-1);
if( dwPitch == 0 )
{
dwPitch = 1024; // Hack for Bust-A-Move
}
}
else //Set by LoadBlock
{
// It was a block load - the pitch is determined by the tile size
if (info->dxt == 0 || info->dwTmem != tile.dwTMem )
{
dwPitch = tile.dwLine << 3;
gti.bSwapped = TRUE;
if( info->dwTmem != tile.dwTMem && info->dxt != 0 && info->dwSize == TXT_SIZE_16b && tile.dwSize == TXT_SIZE_4b )
conkerSwapHack = true;
}
else
{
uint32 DXT = info->dxt;
if( info->dxt > 1 )
{
DXT = ReverseDXT(info->dxt, info->sh, dwTileWidth, tile.dwSize);
}
dwPitch = DXT << 3;
}
if (tile.dwSize == TXT_SIZE_32b)
dwPitch = tile.dwLine << 4;
}
gti.Pitch = tile.dwPitch = dwPitch;
if( (gti.WidthToLoad < gti.WidthToCreate || tile.bSizeIsValid == false) && tile.dwMaskS > 0 && gti.WidthToLoad != (unsigned int)dwTileMaskWidth &&
info->bSetBy == CMD_LOADBLOCK )
//if( (gti.WidthToLoad < gti.WidthToCreate ) && tile.dwMaskS > 0 && gti.WidthToLoad != dwTileMaskWidth &&
// info->bSetBy == CMD_LOADBLOCK )
{
// We have got the pitch now, recheck the width_to_load
uint32 pitchwidth = dwPitch<<1>>tile.dwSize;
if( pitchwidth == (unsigned int)dwTileMaskWidth )
{
gti.WidthToLoad = pitchwidth;
}
}
if( (gti.HeightToLoad < gti.HeightToCreate || tile.bSizeIsValid == false) && tile.dwMaskT > 0 && gti.HeightToLoad != (unsigned int)dwTileMaskHeight &&
info->bSetBy == CMD_LOADBLOCK )
//if( (gti.HeightToLoad < gti.HeightToCreate ) && tile.dwMaskT > 0 && gti.HeightToLoad != dwTileMaskHeight &&
// info->bSetBy == CMD_LOADBLOCK )
{
//uint32 pitchwidth = dwPitch<<1>>tile.dwSize;
uint32 pitchHeight = (info->dwTotalWords<<1)/dwPitch;
if( pitchHeight == (unsigned int)dwTileMaskHeight || gti.HeightToLoad == 1 )
{
gti.HeightToLoad = pitchHeight;
}
}
if( gti.WidthToCreate < gti.WidthToLoad ) gti.WidthToCreate = gti.WidthToLoad;
if( gti.HeightToCreate < gti.HeightToLoad ) gti.HeightToCreate = gti.HeightToLoad;
if( info->bSetBy == CMD_LOADTILE )
{
gti.LeftToLoad = (info->sl<<info->dwSize)>>tile.dwSize;
gti.TopToLoad = info->tl;
}
else
{
gti.LeftToLoad = (info->sl<<info->dwSize)>>tile.dwSize;
gti.TopToLoad = (info->tl<<info->dwSize)>>tile.dwSize;
}
uint32 total64BitWordsToLoad = (gti.HeightToLoad*gti.WidthToLoad)>>(4-tile.dwSize);
if( total64BitWordsToLoad + tile.dwTMem > 0x200 )
{
//TRACE0("Warning: texture loading tmem is over range");
if( gti.WidthToLoad > gti.HeightToLoad )
{
uint32 newheight = (dwPitch << 1 )>> tile.dwSize;
tile.dwWidth = gti.WidthToLoad = gti.WidthToCreate = min(newheight, (gti.WidthToLoad&0xFFFFFFFE));
tile.dwHeight = gti.HeightToCreate = gti.HeightToLoad = ((0x200 - tile.dwTMem) << (4-tile.dwSize)) / gti.WidthToLoad;
}
else
{
tile.dwHeight = gti.HeightToCreate = gti.HeightToLoad = info->dwTotalWords / ((gti.WidthToLoad << tile.dwSize) >> 1);
}
}
// Check the info
if( (info->dwTotalWords>>2) < total64BitWordsToLoad+tile.dwTMem-info->dwTmem - 4 )
{
// Hack here
if( (options.enableHackForGames == HACK_FOR_ZELDA||options.enableHackForGames == HACK_FOR_ZELDA_MM) && (unsigned int)tileno != gRSP.curTile )
{
return false;
}
if( total64BitWordsToLoad+tile.dwTMem-info->dwTmem <= 0x200 )
{
LOG_TEXTURE(TRACE4("Fix me, info is not covering this Tmem address,Info start: 0x%x, total=0x%x, Tmem start: 0x%x, total=0x%x",
info->dwTmem,info->dwTotalWords>>2, tile.dwTMem, total64BitWordsToLoad));
}
}
//Check memory boundary
if( gti.Address + gti.HeightToLoad*gti.Pitch >= g_dwRamSize )
{
WARNING(TRACE0("Warning: texture loading tmem is over range 3"));
gti.HeightToCreate = gti.HeightToLoad = tile.dwHeight = (g_dwRamSize-gti.Address)/gti.Pitch;
}
return true;
}
bool CalculateTileSizes_method_1(int tileno, TMEMLoadMapInfo *info, TxtrInfo &gti)
{
Tile &tile = gRDP.tiles[tileno];
//Tile &loadtile = gRDP.tiles[RDP_TXT_LOADTILE];
// Now Initialize the texture dimension
int loadwidth, loadheight;
int maskwidth = tile.dwMaskS ? (1 << tile.dwMaskS ) : 0;
int maskheight = tile.dwMaskT ? (1 << tile.dwMaskT ) : 0;
int clampwidth = abs(tile.hilite_sh - tile.hilite_sl) +1;
int clampheight = abs(tile.hilite_th - tile.hilite_tl) +1;
int linewidth = tile.dwLine << (5 - tile.dwSize);
gti.bSwapped = info->bSwapped;
if( info->bSetBy == CMD_LOADTILE )
{
loadwidth = (abs(info->sh - info->sl) + 1) << info->dwSize >> tile.dwSize;
loadheight = (abs(info->th - info->tl) + 1) << info->dwSize >> tile.dwSize;
tile.dwPitch = info->dwWidth << info->dwSize >> 1;
if( tile.dwPitch == 0 ) tile.dwPitch = 1024; // Hack for Bust-A-Move
gti.LeftToLoad = (info->sl<<info->dwSize)>>tile.dwSize;
gti.TopToLoad = info->tl;
}
else
{
loadwidth = abs(tile.sh - tile.sl) +1;
if( tile.dwMaskS )
{
loadwidth = maskwidth;
}
loadheight = abs(tile.th - tile.tl) +1;
if( tile.dwMaskT )
{
loadheight = maskheight;
}
// It was a block load - the pitch is determined by the tile size
if (tile.dwSize == TXT_SIZE_32b)
tile.dwPitch = tile.dwLine << 4;
else if (info->dxt == 0 )
{
tile.dwPitch = tile.dwLine << 3;
gti.bSwapped = TRUE;
if( info->dwTmem != tile.dwTMem && info->dxt != 0 && info->dwSize == TXT_SIZE_16b && tile.dwSize == TXT_SIZE_4b )
conkerSwapHack = true;
}
else
{
uint32 DXT = info->dxt;
if( info->dxt > 1 )
{
DXT = ReverseDXT(info->dxt, info->sh, loadwidth, tile.dwSize);
}
tile.dwPitch = DXT << 3;
}
gti.LeftToLoad = (info->sl<<info->dwSize)>>tile.dwSize;
gti.TopToLoad = (info->tl<<info->dwSize)>>tile.dwSize;
}
if( options.enableHackForGames == HACK_FOR_MARIO_KART )
{
if( loadwidth-maskwidth == 1 && tile.dwMaskS )
{
loadwidth--;
if( loadheight%2 ) loadheight--;
}
if( loadheight-maskheight == 1 && tile.dwMaskT )
{
loadheight--;
if(loadwidth%2) loadwidth--;
}
if( loadwidth - ((g_TI.dwWidth<<g_TI.dwSize)>>tile.dwSize) == 1 )
{
loadwidth--;
if( loadheight%2 ) loadheight--;
}
}
// Limit the texture size
if( g_curRomInfo.bUseSmallerTexture )
{
if( tile.dwMaskS && tile.bClampS )
{
if( !tile.bMirrorS )
{
if( clampwidth/maskwidth >= 2 )
{
clampwidth = maskwidth;
tile.bForceWrapS = true;
}
else if( clampwidth && maskwidth/clampwidth >= 2 )
{
maskwidth = clampwidth;
tile.bForceClampS = true;
}
}
else
{
if( clampwidth/maskwidth == 2 )
{
clampwidth = maskwidth*2;
tile.bForceWrapS = false;
}
else if( clampwidth/maskwidth > 2 )
{
clampwidth = maskwidth*2;
tile.bForceWrapS = true;
}
}
}
if( tile.dwMaskT && tile.bClampT )
{
if( !tile.bMirrorT )
{
if( clampheight/maskheight >= 2 )
{
clampheight = maskheight;
tile.bForceWrapT = true;
}
else if( clampheight && maskheight/clampheight >= 2 )
{
maskwidth = clampwidth;
tile.bForceClampT = true;
}
}
else
{
if( clampheight/maskheight == 2 )
{
clampheight = maskheight*2;
tile.bForceWrapT = false;
}
else if( clampheight/maskheight >= 2 )
{
clampheight = maskheight*2;
tile.bForceWrapT = true;
}
}
}
}
else
{
//if( clampwidth > linewidth ) clampwidth = linewidth;
if( clampwidth > 512 && clampheight > 512 )
{
if( clampwidth > maskwidth && maskwidth && clampheight > 256 ) clampwidth = maskwidth;
if( clampheight > maskheight && maskheight && clampheight > 256 ) clampheight = maskheight;
}
if( tile.dwMaskS > 8 && tile.dwMaskT > 8 )
{
maskwidth = loadwidth;
maskheight = loadheight;
}
else
{
if( tile.dwMaskS > 10 )
maskwidth = loadwidth;
if( tile.dwMaskT > 10 )
maskheight = loadheight;
}
}
gti.Pitch = tile.dwPitch;
if( tile.dwMaskS == 0 || tile.bClampS )
{
gti.WidthToLoad = linewidth ? min( linewidth, maskwidth ? min(clampwidth,maskwidth) : clampwidth ) : clampwidth;
if( tile.dwMaskS && clampwidth < maskwidth )
tile.dwWidth = gti.WidthToCreate = clampwidth;
else
tile.dwWidth = gti.WidthToCreate = max(clampwidth,maskwidth);
}
else
{
gti.WidthToLoad = loadwidth > 2 ? min(loadwidth,maskwidth) : maskwidth;
if( linewidth ) gti.WidthToLoad = min( linewidth, (int)gti.WidthToLoad );
tile.dwWidth = gti.WidthToCreate = maskwidth;
}
if( tile.dwMaskT == 0 || tile.bClampT )
{
gti.HeightToLoad = maskheight ? min(clampheight,maskheight) : clampheight;
if( tile.dwMaskT && clampheight < maskheight )
tile.dwHeight = gti.HeightToCreate = clampheight;
else
tile.dwHeight = gti.HeightToCreate = max(clampheight,maskheight);
}
else
{
gti.HeightToLoad = loadheight > 2 ? min(loadheight,maskheight) : maskheight;
tile.dwHeight = gti.HeightToCreate = maskheight;
}
if( options.enableHackForGames == HACK_FOR_MARIO_KART )
{
if( gti.WidthToLoad - ((g_TI.dwWidth<<g_TI.dwSize)>>tile.dwSize) == 1 )
{
gti.WidthToLoad--;
if( gti.HeightToLoad%2 ) gti.HeightToLoad--;
}
}
// Double check
uint32 total64BitWordsToLoad = (gti.HeightToLoad*gti.WidthToLoad)>>(4-tile.dwSize);
if( total64BitWordsToLoad + tile.dwTMem > 0x200 )
{
//TRACE0("Warning: texture loading tmem is over range");
if( gti.WidthToLoad > gti.HeightToLoad )
{
uint32 newheight = (tile.dwPitch << 1 )>> tile.dwSize;
tile.dwWidth = gti.WidthToLoad = gti.WidthToCreate = min(newheight, (gti.WidthToLoad&0xFFFFFFFE));
tile.dwHeight = gti.HeightToCreate = gti.HeightToLoad = ((0x200 - tile.dwTMem) << (4-tile.dwSize)) / gti.WidthToLoad;
}
else
{
tile.dwHeight = gti.HeightToCreate = gti.HeightToLoad = info->dwTotalWords / ((gti.WidthToLoad << tile.dwSize) >> 1);
}
}
// Check the info
if( (info->dwTotalWords>>2) < total64BitWordsToLoad+tile.dwTMem-info->dwTmem - 4 )
{
// Hack here
if( (options.enableHackForGames == HACK_FOR_ZELDA||options.enableHackForGames == HACK_FOR_ZELDA_MM) && (unsigned int)tileno != gRSP.curTile )
{
return false;
}
if( total64BitWordsToLoad+tile.dwTMem-info->dwTmem <= 0x200 )
{
LOG_TEXTURE(TRACE4("Fix me, info is not covering this Tmem address,Info start: 0x%x, total=0x%x, Tmem start: 0x%x, total=0x%x",
info->dwTmem,info->dwTotalWords>>2, tile.dwTMem, total64BitWordsToLoad));
}
}
//Check memory boundary
if( gti.Address + gti.HeightToLoad*gti.Pitch >= g_dwRamSize )
{
WARNING(TRACE0("Warning: texture loading tmem is over range 3"));
gti.HeightToCreate = gti.HeightToLoad = tile.dwHeight = (g_dwRamSize-gti.Address)/gti.Pitch;
}
return true;
}
TxtrCacheEntry* LoadTexture(uint32 tileno)
{
//TxtrCacheEntry *pEntry = NULL;
TxtrInfo gti;
Tile &tile = gRDP.tiles[tileno];
// Retrieve the tile loading info
uint32 infoTmemAddr = tile.dwTMem;
TMEMLoadMapInfo *info = &g_tmemLoadAddrMap[infoTmemAddr];
if( !IsTmemFlagValid(infoTmemAddr) )
{
infoTmemAddr = GetValidTmemInfoIndex(infoTmemAddr);
info = &g_tmemLoadAddrMap[infoTmemAddr];
}
if( info->dwFormat != tile.dwFormat )
{
// Check the tile format, hack for Zelda's road
if( tileno != gRSP.curTile && tile.dwTMem == gRDP.tiles[gRSP.curTile].dwTMem &&
tile.dwFormat != gRDP.tiles[gRSP.curTile].dwFormat )
{
//TRACE1("Tile %d format is not matching the loaded texture format", tileno);
return NULL;
}
}
gti = tile; // Copy tile info to textureInfo entry
gti.TLutFmt = gRDP.otherMode.text_tlut <<RSP_SETOTHERMODE_SHIFT_TEXTLUT;
if (gti.Format == TXT_FMT_CI && gti.TLutFmt == TLUT_FMT_NONE )
gti.TLutFmt = TLUT_FMT_RGBA16; // Force RGBA
gti.PalAddress = (uchar *) (&g_wRDPTlut[0]);
if( !options.bUseFullTMEM && tile.dwSize == TXT_SIZE_4b )
gti.PalAddress += 16 * 2 * tile.dwPalette;
gti.Address = (info->dwLoadAddress+(tile.dwTMem-infoTmemAddr)*8) & (g_dwRamSize-1) ;
gti.pPhysicalAddress = ((uint8*)g_pRDRAMu32)+gti.Address;
gti.tileNo = tileno;
if( g_curRomInfo.bTxtSizeMethod2 )
{
if( !CalculateTileSizes_method_2(tileno, info, gti) )
return NULL;
}
else
{
if( !CalculateTileSizes_method_1(tileno, info, gti) )
return NULL;
}
LOG_TEXTURE(
{
TRACE0("Loading texture:\n");
DebuggerAppendMsg("Left: %d, Top: %d, Width: %d, Height: %d, Size to Load (%d, %d)",
gti.LeftToLoad, gti.TopToLoad, gti.WidthToCreate, gti.HeightToCreate, gti.WidthToLoad, gti.HeightToLoad);
DebuggerAppendMsg("Pitch: %d, Addr: 0x%08x", gti.Pitch, gti.Address);
});
// Option for faster loading tiles
if( g_curRomInfo.bFastLoadTile && info->bSetBy == CMD_LOADTILE && ((gti.Pitch<<1)>>gti.Size) <= 0x400
//&& ((gti.Pitch<<1)>>gti.Size) > 128 && status.primitiveType == PRIM_TEXTRECT
)
{
uint32 idx = tileno-gRSP.curTile;
status.LargerTileRealLeft[idx] = gti.LeftToLoad;
gti.LeftToLoad=0;
gti.WidthToLoad = gti.WidthToCreate = ((gti.Pitch<<1)>>gti.Size);
status.UseLargerTile[idx]=true;
}
// Loading the textures by using texture cache manager
return gTextureManager.GetTexture(&gti, true, true, true); // Load the texture by using texture cache
}
void PrepareTextures()
{
if( gRDP.textureIsChanged || !currentRomOptions.bFastTexCRC ||
CRender::g_pRender->m_pColorCombiner->m_pDecodedMux->m_ColorTextureFlag[0] ||
CRender::g_pRender->m_pColorCombiner->m_pDecodedMux->m_ColorTextureFlag[1] )
{
status.UseLargerTile[0]=false;
status.UseLargerTile[1]=false;
int tilenos[2];
if( CRender::g_pRender->IsTexel0Enable() || gRDP.otherMode.cycle_type == CYCLE_TYPE_COPY )
tilenos[0] = gRSP.curTile;
else
tilenos[0] = -1;
if( gRSP.curTile<7 && CRender::g_pRender->IsTexel1Enable() )
tilenos[1] = gRSP.curTile+1;
else
tilenos[1] = -1;
for( int i=0; i<2; i++ )
{
if( tilenos[i] < 0 ) continue;
if( CRender::g_pRender->m_pColorCombiner->m_pDecodedMux->m_ColorTextureFlag[i] )
{
TxtrCacheEntry *pEntry = gTextureManager.GetConstantColorTexture(CRender::g_pRender->m_pColorCombiner->m_pDecodedMux->m_ColorTextureFlag[i]);
CRender::g_pRender->SetCurrentTexture( tilenos[i], pEntry->pTexture, 4, 4, pEntry);
}
else
{
TxtrCacheEntry *pEntry = LoadTexture(tilenos[i]);
if (pEntry && pEntry->pTexture )
{
if( pEntry->txtrBufIdx <= 0 )
{
if( pEntry->pEnhancedTexture && pEntry->dwEnhancementFlag == TEXTURE_EXTERNAL && !options.bLoadHiResTextures )
{
SAFE_DELETE(pEntry->pEnhancedTexture);
}
if( pEntry->pEnhancedTexture == NULL )
{
MirrorTexture(tilenos[i], pEntry);;
}
if( options.bLoadHiResTextures && (pEntry->pEnhancedTexture == NULL || pEntry->dwEnhancementFlag < TEXTURE_EXTERNAL ) )
{
LoadHiresTexture(*pEntry);
}
if( pEntry->pEnhancedTexture == NULL || (pEntry->dwEnhancementFlag != options.textureEnhancement && pEntry->dwEnhancementFlag < TEXTURE_EXTERNAL ) )
{
EnhanceTexture(pEntry);
}
}
CRender::g_pRender->SetCurrentTexture( tilenos[i],
(pEntry->pEnhancedTexture)?pEntry->pEnhancedTexture:pEntry->pTexture,
pEntry->ti.WidthToLoad, pEntry->ti.HeightToLoad, pEntry);
}
else
{
pEntry = gTextureManager.GetBlackTexture();
CRender::g_pRender->SetCurrentTexture( tilenos[i], pEntry->pTexture, 4, 4, pEntry);
_VIDEO_DisplayTemporaryMessage("Fail to load texture, use black to replace");
}
}
}
gRDP.textureIsChanged = false;
}
}
extern uint32 g_TxtLoadBy;;
void DLParser_LoadTLut(Gfx *gfx)
{
gRDP.textureIsChanged = true;
uint32 tileno = gfx->loadtile.tile;
uint32 uls = gfx->loadtile.sl/4;
uint32 ult = gfx->loadtile.tl/4;
uint32 lrs = gfx->loadtile.sh/4;
uint32 lrt = gfx->loadtile.th/4;
#ifdef _DEBUG
uint32 dwTLutFmt = (gRDP.otherModeH >> RSP_SETOTHERMODE_SHIFT_TEXTLUT)&0x3;
#endif
uint32 dwCount;
// starting location in the palettes
uint32 dwTMEMOffset = gRDP.tiles[tileno].dwTMem - 256;
// number to copy
dwCount = ((uint16)((gfx->words.w1) >> 14) & 0x03FF) + 1;
uint32 dwRDRAMOffset = 0;
Tile &tile = gRDP.tiles[tileno];
tile.bForceWrapS = tile.bForceWrapT = tile.bForceClampS = tile.bForceClampT = false;
tile.hilite_sl = tile.sl = uls;
tile.hilite_tl = tile.tl = ult;
tile.sh = lrs;
tile.th = lrt;
tile.bSizeIsValid = true;
tile.lastTileCmd = CMD_LOADTLUT;
#ifdef _DEBUG
/*
if((((gfx->words.w0)>>12)&0x3) != 0 || (((gfx->words.w0))&0x3) != 0 || (((gfx->words.w1)>>12)&0x3) != 0 || (((gfx->words.w1))&0x3) != 0)
{ TRACE0("Load tlut, sl,tl,sh,th are not integers"); }
*/
#endif
dwCount = (lrs - uls)+1;
dwRDRAMOffset = (uls + ult*g_TI.dwWidth )*2;
uint32 dwPalAddress = g_TI.dwAddr + dwRDRAMOffset;
//Copy PAL to the PAL memory
uint16 *srcPal = (uint16*)(g_pRDRAMu8 + (dwPalAddress& (g_dwRamSize-1)) );
for (uint32 i=0; i<dwCount && i<0x100; i++)
{ g_wRDPTlut[(i+dwTMEMOffset)^1] = srcPal[i^1]; }
if( options.bUseFullTMEM )
{
for (uint32 i=0; i<dwCount && i+tile.dwTMem<0x200; i++)
{ *(uint16*)(&g_Tmem.g_Tmem64bit[tile.dwTMem+i]) = srcPal[i^1]; }
}
LOG_TEXTURE(
{
DebuggerAppendMsg("LoadTLut Tile: %d Start: 0x%X+0x%X, Count: 0x%X\nFmt is %s, TMEM=0x%X\n",
tileno, g_TI.dwAddr, dwRDRAMOffset, dwCount,textluttype[dwTLutFmt],
dwTMEMOffset);
DebuggerAppendMsg(" :ULS: 0x%X, ULT:0x%X, LRS: 0x%X, LRT:0x%X\n", uls, ult, lrs,lrt);
if( pauseAtNext && eventToPause == NEXT_LOADTLUT && dwCount == 16 )
{
char buf[2000];
strcpy(buf, "Data:\n");
for(uint32 i=0; i<16; i++ )
{
sprintf(buf+strlen(buf), "%04X ", g_wRDPTlut[dwTMEMOffset+i]);
if(i%4 == 3)
{ sprintf(buf+strlen(buf), "\n"); }
}
sprintf(buf+strlen(buf), "\n");
TRACE0(buf);
}
});
DEBUGGER_PAUSE_COUNT_N(NEXT_LOADTLUT);
extern bool RevTlutTableNeedUpdate;
RevTlutTableNeedUpdate = true;
g_TxtLoadBy = CMD_LOADTLUT;
}
void DLParser_LoadBlock(Gfx *gfx)
{
gRDP.textureIsChanged = true;
uint32 tileno = gfx->loadtile.tile;
uint32 uls = gfx->loadtile.sl;
uint32 ult = gfx->loadtile.tl;
uint32 lrs = gfx->loadtile.sh;
uint32 dxt = gfx->loadtile.th; // 1.11 fixed point
Tile &tile = gRDP.tiles[tileno];
tile.bForceWrapS = tile.bForceWrapT = tile.bForceClampS = tile.bForceClampT = false;
uint32 size = lrs+1;
if( tile.dwSize == TXT_SIZE_32b ) size<<=1;
SetTmemFlag(tile.dwTMem, size>>2);
TMEMLoadMapInfo &info = g_tmemLoadAddrMap[tile.dwTMem];
info.bSwapped = (dxt == 0? TRUE : FALSE);
info.sl = tile.hilite_sl = tile.sl = uls;
info.sh = tile.hilite_sh = tile.sh = lrs;
info.tl = tile.tl = ult;
info.th = tile.th = dxt;
tile.bSizeIsValid = false;
for( int i=0; i<8; i++ )
{
if( tile.dwTMem == tile.dwTMem )
tile.lastTileCmd = CMD_LOADBLOCK;
}
info.dwLoadAddress = g_TI.dwAddr;
info.bSetBy = CMD_LOADBLOCK;
info.dxt = dxt;
info.dwLine = tile.dwLine;
info.dwFormat = g_TI.dwFormat;
info.dwSize = g_TI.dwSize;
info.dwWidth = g_TI.dwWidth;
info.dwTotalWords = size;
info.dwTmem = tile.dwTMem;
if( gRDP.tiles[tileno].dwTMem == 0 )
{
if( size >= 1024 )
{
memcpy(&g_tmemInfo0, &info, sizeof(TMEMLoadMapInfo) );
g_tmemInfo0.dwTotalWords = size>>2;
}
if( size == 2048 )
{
memcpy(&g_tmemInfo1, &info, sizeof(TMEMLoadMapInfo) );
g_tmemInfo1.dwTotalWords = size>>2;
}
}
else if( tile.dwTMem == 0x100 )
{
if( size == 1024 )
{
memcpy(&g_tmemInfo1, &info, sizeof(TMEMLoadMapInfo) );
g_tmemInfo1.dwTotalWords = size>>2;
}
}
g_TxtLoadBy = CMD_LOADBLOCK;
if( options.bUseFullTMEM )
{
uint32 bytes = (lrs + 1) << tile.dwSize >> 1;
uint32 address = g_TI.dwAddr + ult * g_TI.bpl + (uls << g_TI.dwSize >> 1);
if ((bytes == 0) || ((address + bytes) > g_dwRamSize) || (((tile.dwTMem << 3) + bytes) > 4096))
{
return;
}
uint64* src = (uint64*)(g_pRDRAMu8+address);
uint64* dest = &g_Tmem.g_Tmem64bit[tile.dwTMem];
if( dxt > 0)
{
void (*Interleave)( void *mem, uint32 numDWords );
uint32 line = (2047 + dxt) / dxt;
uint32 bpl = line << 3;
uint32 height = bytes / bpl;
if (tile.dwSize == TXT_SIZE_32b)
Interleave = QWordInterleave;
else
Interleave = DWordInterleave;
for (uint32 y = 0; y < height; y++)
{
UnswapCopy( src, dest, bpl );
if (y & 1) Interleave( dest, line );
src += line;
dest += line;
}
}
else
UnswapCopy( src, dest, bytes );
}
LOG_UCODE(" Tile:%d (%d,%d - %d) DXT:0x%04x\n", tileno, uls, ult, lrs, dxt);
LOG_TEXTURE(
{
DebuggerAppendMsg("LoadBlock:%d (%d,%d,%d) DXT:0x%04x(%X)\n",
tileno, uls, ult, (((gfx->words.w1)>>12)&0x0FFF), dxt, ((gfx->words.w1)&0x0FFF));
});
DEBUGGER_PAUSE_COUNT_N(NEXT_TEXTURE_CMD);
}
void swap(uint32 &a, uint32 &b)
{
uint32 temp = a;
a = b;
b = temp;
}
void DLParser_LoadTile(Gfx *gfx)
{
gRDP.textureIsChanged = true;
uint32 tileno = gfx->loadtile.tile;
uint32 uls = gfx->loadtile.sl/4;
uint32 ult = gfx->loadtile.tl/4;
uint32 lrs = gfx->loadtile.sh/4;
uint32 lrt = gfx->loadtile.th/4;
Tile &tile = gRDP.tiles[tileno];
tile.bForceWrapS = tile.bForceWrapT = tile.bForceClampS = tile.bForceClampT = false;
if (lrt < ult) swap(lrt, ult);
if (lrs < uls) swap(lrs, uls);
tile.hilite_sl = tile.sl = uls;
tile.hilite_tl = tile.tl = ult;
tile.hilite_sh = tile.sh = lrs;
tile.hilite_th = tile.th = lrt;
tile.bSizeIsValid = true;
// compute block height, and bpl of source and destination
uint32 bpl = (lrs - uls + 1) << tile.dwSize >> 1;
uint32 height = lrt - ult + 1;
uint32 line = tile.dwLine;
if (tile.dwSize == TXT_SIZE_32b) line <<= 1;
if (((tile.dwTMem << 3) + line * height) > 4096) // check destination ending point (TMEM is 4k bytes)
return;
if( options.bUseFullTMEM )
{
void (*Interleave)( void *mem, uint32 numDWords );
uint32 address, line, y;
uint64 *dest;
uint8 *src;
if( g_TI.bpl == 0 )
{
if( options.enableHackForGames == HACK_FOR_BUST_A_MOVE )
{
g_TI.bpl = 1024; // Hack for Bust-A-Move
}
else
{
TRACE0("Warning: g_TI.bpl = 0" );
}
}
address = g_TI.dwAddr + tile.tl * g_TI.bpl + (tile.sl << g_TI.dwSize >> 1);
src = &g_pRDRAMu8[address];
dest = &g_Tmem.g_Tmem64bit[tile.dwTMem];
if ((address + height * bpl) > g_dwRamSize) // check source ending point
{
return;
}
// Line given for 32-bit is half what it seems it should since they split the
// high and low words. I'm cheating by putting them together.
if (tile.dwSize == TXT_SIZE_32b)
{
Interleave = QWordInterleave;
}
else
{
Interleave = DWordInterleave;
}
if( tile.dwLine == 0 )
{
//tile.dwLine = 1;
return;
}
for (y = 0; y < height; y++)
{
UnswapCopy( src, dest, bpl );
if (y & 1) Interleave( dest, line );
src += g_TI.bpl;
dest += line;
}
}
for( int i=0; i<8; i++ )
{
if( gRDP.tiles[i].dwTMem == tile.dwTMem )
gRDP.tiles[i].lastTileCmd = CMD_LOADTILE;
}
uint32 size = line * height;
SetTmemFlag(tile.dwTMem,size );
uint32 dwPitch = g_TI.dwWidth;
if( tile.dwSize != TXT_SIZE_4b )
{
dwPitch = g_TI.dwWidth<<(tile.dwSize-1);
}
LOG_TEXTURE(
{
DebuggerAppendMsg("LoadTile:%d (%d,%d) -> (%d,%d) [%d x %d]\n",
tileno, uls, ult, lrs, lrt,
(lrs - uls)+1, (lrt - ult)+1);
});
DEBUGGER_PAUSE_COUNT_N(NEXT_TEXTURE_CMD);
LOG_UCODE(" Tile:%d (%d,%d) -> (%d,%d) [%d x %d]",
tileno, uls, ult, lrs, lrt,
(lrs - uls)+1, (lrt - ult)+1);
TMEMLoadMapInfo &info = g_tmemLoadAddrMap[tile.dwTMem];
info.dwLoadAddress = g_TI.dwAddr;
info.dwFormat = g_TI.dwFormat;
info.dwSize = g_TI.dwSize;
info.dwWidth = g_TI.dwWidth;
info.sl = uls;
info.sh = lrs;
info.tl = ult;
info.th = lrt;
info.dxt = 0;
info.dwLine = tile.dwLine;
info.dwTmem = tile.dwTMem;
info.dwTotalWords = size<<2;
info.bSetBy = CMD_LOADTILE;
info.bSwapped =FALSE;
g_TxtLoadBy = CMD_LOADTILE;
if( tile.dwTMem == 0 )
{
if( size >= 256 )
{
memcpy(&g_tmemInfo0, &info, sizeof(TMEMLoadMapInfo) );
g_tmemInfo0.dwTotalWords = size;
}
if( size == 512 )
{
memcpy(&g_tmemInfo1, &info, sizeof(TMEMLoadMapInfo) );
g_tmemInfo1.dwTotalWords = size;
}
}
else if( tile.dwTMem == 0x100 )
{
if( size == 256 )
{
memcpy(&g_tmemInfo1, &info, sizeof(TMEMLoadMapInfo) );
g_tmemInfo1.dwTotalWords = size;
}
}
}
const char *pszOnOff[2] = {"Off", "On"};
uint32 lastSetTile;
void DLParser_SetTile(Gfx *gfx)
{
gRDP.textureIsChanged = true;
uint32 tileno = gfx->settile.tile;
Tile &tile = gRDP.tiles[tileno];
tile.bForceWrapS = tile.bForceWrapT = tile.bForceClampS = tile.bForceClampT = false;
lastSetTile = tileno;
tile.dwFormat = gfx->settile.fmt;
tile.dwSize = gfx->settile.siz;
tile.dwLine = gfx->settile.line;
tile.dwTMem = gfx->settile.tmem;
tile.dwPalette = gfx->settile.palette;
tile.bClampT = gfx->settile.ct;
tile.bMirrorT = gfx->settile.mt;
tile.dwMaskT = gfx->settile.maskt;
tile.dwShiftT = gfx->settile.shiftt;
tile.bClampS = gfx->settile.cs;
tile.bMirrorS = gfx->settile.ms;
tile.dwMaskS = gfx->settile.masks;
tile.dwShiftS = gfx->settile.shifts;
tile.fShiftScaleS = 1.0f;
if( tile.dwShiftS )
{
if( tile.dwShiftS > 10 )
{
tile.fShiftScaleS = (float)(1 << (16 - tile.dwShiftS));
}
else
{
tile.fShiftScaleS = (float)1.0f/(1 << tile.dwShiftS);
}
}
tile.fShiftScaleT = 1.0f;
if( tile.dwShiftT )
{
if( tile.dwShiftT > 10 )
{
tile.fShiftScaleT = (float)(1 << (16 - tile.dwShiftT));
}
else
{
tile.fShiftScaleT = (float)1.0f/(1 << tile.dwShiftT);
}
}
// Hack for DK64
/*
if( tile.dwMaskS > 0 && tile.dwMaskT > 0 && tile.dwMaskS < 8 && tile.dwMaskT < 8 )
{
tile.sh = tile.sl + (1<<tile.dwMaskS);
tile.th = tile.tl + (1<<tile.dwMaskT);
tile.hilite_sl = tile.sl;
tile.hilite_tl = tile.tl;
}
*/
tile.lastTileCmd = CMD_SETTILE;
LOG_TEXTURE(
{
DebuggerAppendMsg("SetTile:%d Fmt: %s/%s Line:%d TMem:0x%04x Palette:%d\n",
tileno, pszImgFormat[tile.dwFormat], pszImgSize[tile.dwSize],
tile.dwLine, tile.dwTMem, tile.dwPalette);
DebuggerAppendMsg(" S: Clamp: %s Mirror:%s Mask:0x%x Shift:0x%x\n",
pszOnOff[tile.bClampS],pszOnOff[tile.bMirrorS],
tile.dwMaskS, tile.dwShiftS);
DebuggerAppendMsg(" T: Clamp: %s Mirror:%s Mask:0x%x Shift:0x%x\n",
pszOnOff[tile.bClampT],pszOnOff[tile.bMirrorT],
tile.dwMaskT, tile.dwShiftT);
});
DEBUGGER_PAUSE_COUNT_N(NEXT_TEXTURE_CMD);
LOG_UCODE(" Tile:%d Fmt: %s/%s Line:%d TMem:0x%04x Palette:%d",
tileno, pszImgFormat[tile.dwFormat], pszImgSize[tile.dwSize],
tile.dwLine, tile.dwTMem, tile.dwPalette);
LOG_UCODE(" S: Clamp: %s Mirror:%s Mask:0x%x Shift:0x%x",
pszOnOff[tile.bClampS],pszOnOff[tile.bMirrorS],
tile.dwMaskS, tile.dwShiftS);
LOG_UCODE(" T: Clamp: %s Mirror:%s Mask:0x%x Shift:0x%x",
pszOnOff[tile.bClampT],pszOnOff[tile.bMirrorT],
tile.dwMaskT, tile.dwShiftT);
}
void DLParser_SetTileSize(Gfx *gfx)
{
gRDP.textureIsChanged = true;
uint32 tileno = gfx->loadtile.tile;
int sl = gfx->loadtile.sl;
int tl = gfx->loadtile.tl;
int sh = gfx->loadtile.sh;
int th = gfx->loadtile.th;
Tile &tile = gRDP.tiles[tileno];
tile.bForceWrapS = tile.bForceWrapT = tile.bForceClampS = tile.bForceClampT = false;
if( options.bUseFullTMEM )
{
tile.bSizeIsValid = true;
tile.hilite_sl = tile.sl = sl / 4;
tile.hilite_tl = tile.tl = tl / 4;
tile.hilite_sh = tile.sh = sh / 4;
tile.hilite_th = tile.th = th / 4;
tile.fhilite_sl = tile.fsl = sl / 4.0f;
tile.fhilite_tl = tile.ftl = tl / 4.0f;
tile.fhilite_sh = tile.fsh = sh / 4.0f;
tile.fhilite_th = tile.fth = th / 4.0f;
tile.lastTileCmd = CMD_SETTILE_SIZE;
}
else
{
if( tile.lastTileCmd != CMD_SETTILE_SIZE )
{
tile.bSizeIsValid = true;
if( sl/4 > sh/4 || tl/4 > th/4 || (sh == 0 && tile.dwShiftS==0 && th == 0 && tile.dwShiftT ==0 ) )
{
#ifdef _DEBUG
if( sl != 0 || tl != 0 || sh != 0 || th != 0 )
{
if( tile.dwMaskS==0 || tile.dwMaskT==0 )
TRACE0("Check me, setTileSize is not correct");
}
#endif
tile.bSizeIsValid = false;
}
tile.hilite_sl = tile.sl = sl / 4;
tile.hilite_tl = tile.tl = tl / 4;
tile.hilite_sh = tile.sh = sh / 4;
tile.hilite_th = tile.th = th / 4;
tile.fhilite_sl = tile.fsl = sl / 4.0f;
tile.fhilite_tl = tile.ftl = tl / 4.0f;
tile.fhilite_sh = tile.fsh = sh / 4.0f;
tile.fhilite_th = tile.fth = th / 4.0f;
tile.lastTileCmd = CMD_SETTILE_SIZE;
}
else
{
tile.fhilite_sh = tile.fsh;
tile.fhilite_th = tile.fth;
tile.fhilite_sl = tile.fsl = (sl>0x7ff ? (sl-0xfff) : sl)/4.0f;
tile.fhilite_tl = tile.ftl = (tl>0x7ff ? (tl-0xfff) : tl)/4.0f;
tile.hilite_sl = sl>0x7ff ? (sl-0xfff) : sl;
tile.hilite_tl = tl>0x7ff ? (tl-0xfff) : tl;
tile.hilite_sl /= 4;
tile.hilite_tl /= 4;
tile.hilite_sh = sh/4;
tile.hilite_th = th/4;
tile.lastTileCmd = CMD_SETTILE_SIZE;
}
}
LOG_TEXTURE(
{
DebuggerAppendMsg("SetTileSize:%d (%d/4,%d/4) -> (%d/4,%d/4) [%d x %d]\n",
tileno, sl, tl, sh, th,
((sh/4) - (sl/4)) + 1, ((th/4) - (tl/4)) + 1);
});
DEBUGGER_PAUSE_COUNT_N(NEXT_TEXTURE_CMD);
LOG_UCODE(" Tile:%d (%d,%d) -> (%d,%d) [%d x %d]",
tileno, sl/4, tl/4, sh/4, th/4,
((sh/4) - (sl/4)) + 1, ((th/4) - (tl/4)) + 1);
}
extern const char *pszImgFormat[8];// = {"RGBA", "YUV", "CI", "IA", "I", "?1", "?2", "?3"};
extern const char *pszImgSize[4];// = {"4", "8", "16", "32"};
void DLParser_SetTImg(Gfx *gfx)
{
gRDP.textureIsChanged = true;
g_TI.dwFormat = gfx->setimg.fmt;
g_TI.dwSize = gfx->setimg.siz;
g_TI.dwWidth = gfx->setimg.width + 1;
g_TI.dwAddr = RSPSegmentAddr((gfx->setimg.addr));
g_TI.bpl = g_TI.dwWidth << g_TI.dwSize >> 1;
#ifdef _DEBUG
if( g_TI.dwAddr == 0x00ffffff)
{
TRACE0("Check me here in setTimg");
}
LOG_TEXTURE(TRACE4("SetTImage: 0x%08x Fmt: %s/%s Width in Pixel: %d\n", g_TI.dwAddr,
pszImgFormat[g_TI.dwFormat], pszImgSize[g_TI.dwSize], g_TI.dwWidth));
DEBUGGER_PAUSE_COUNT_N(NEXT_TEXTURE_CMD);
LOG_UCODE("Image: 0x%08x Fmt: %s/%s Width in Pixel: %d", g_TI.dwAddr,
pszImgFormat[g_TI.dwFormat], pszImgSize[g_TI.dwSize], g_TI.dwWidth);
#endif
}
void DLParser_TexRect(Gfx *gfx)
{
//Gtexrect *gtextrect = (Gtexrect *)gfx;
if( !status.bCIBufferIsRendered ) g_pFrameBufferManager->ActiveTextureBuffer();
status.primitiveType = PRIM_TEXTRECT;
// This command used 128bits, and not 64 bits. This means that we have to look one
// Command ahead in the buffer, and update the PC.
uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction
uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwPC+4);
uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwPC+4+8);
uint32 dwHalf1 = *(uint32 *)(g_pRDRAMu8 + dwPC);
uint32 dwHalf2 = *(uint32 *)(g_pRDRAMu8 + dwPC+8);
if( options.enableHackForGames == HACK_FOR_ALL_STAR_BASEBALL || options.enableHackForGames == HACK_FOR_MLB )
{
if( ((dwHalf1>>24) == 0xb4 || (dwHalf1>>24) == 0xb3 || (dwHalf1>>24) == 0xb2 || (dwHalf1>>24) == 0xe1) &&
((dwHalf2>>24) == 0xb4 || (dwHalf2>>24) == 0xb3 || (dwHalf2>>24) == 0xb2 || (dwHalf2>>24) == 0xf1) )
{
// Increment PC so that it points to the right place
gDlistStack[gDlistStackPointer].pc += 16;
}
else
{
// Hack for some games, All_Star_Baseball_2000
gDlistStack[gDlistStackPointer].pc += 8;
dwCmd3 = dwCmd2;
//dwCmd2 = dwHalf1;
//dwCmd2 = 0;
// fix me here
dwCmd2 = (((dwHalf1>>12)&0x03FF)<<17) | (((dwHalf1)&0x03FF)<<1);
}
}
else
{
gDlistStack[gDlistStackPointer].pc += 16;
}
// Hack for Mario Tennis
if( !status.bHandleN64RenderTexture && g_CI.dwAddr == g_ZI.dwAddr )
{
return;
}
LOG_UCODE("0x%08x: %08x %08x", dwPC, *(uint32 *)(g_pRDRAMu8 + dwPC+0), *(uint32 *)(g_pRDRAMu8 + dwPC+4));
LOG_UCODE("0x%08x: %08x %08x", dwPC+8, *(uint32 *)(g_pRDRAMu8 + dwPC+8), *(uint32 *)(g_pRDRAMu8 + dwPC+8+4));
uint32 dwXH = (((gfx->words.w0)>>12)&0x0FFF)/4;
uint32 dwYH = (((gfx->words.w0) )&0x0FFF)/4;
uint32 tileno = ((gfx->words.w1)>>24)&0x07;
uint32 dwXL = (((gfx->words.w1)>>12)&0x0FFF)/4;
uint32 dwYL = (((gfx->words.w1) )&0x0FFF)/4;
uint16 uS = (uint16)( dwCmd2>>16)&0xFFFF;
uint16 uT = (uint16)( dwCmd2 )&0xFFFF;
uint16 uDSDX = (uint16)(( dwCmd3>>16)&0xFFFF);
uint16 uDTDY = (uint16)(( dwCmd3 )&0xFFFF);
if( (int)dwXL >= gRDP.scissor.right || (int)dwYL >= gRDP.scissor.bottom || (int)dwXH < gRDP.scissor.left || (int)dwYH < gRDP.scissor.top )
{
// Clipping
return;
}
short s16S = *(short*)(&uS);
short s16T = *(short*)(&uT);
short s16DSDX = *(short*)(&uDSDX);
short s16DTDY = *(short*)(&uDTDY);
uint32 curTile = gRSP.curTile;
ForceMainTextureIndex(tileno);
float fS0 = s16S / 32.0f;
float fT0 = s16T / 32.0f;
float fDSDX = s16DSDX / 1024.0f;
float fDTDY = s16DTDY / 1024.0f;
uint32 cycletype = gRDP.otherMode.cycle_type;
if (cycletype == CYCLE_TYPE_COPY)
{
fDSDX /= 4.0f; // In copy mode 4 pixels are copied at once.
dwXH++;
dwYH++;
}
else if (cycletype == CYCLE_TYPE_FILL)
{
dwXH++;
dwYH++;
}
if( fDSDX == 0 ) fDSDX = 1;
if( fDTDY == 0 ) fDTDY = 1;
float fS1 = fS0 + (fDSDX * (dwXH - dwXL));
float fT1 = fT0 + (fDTDY * (dwYH - dwYL));
LOG_UCODE(" Tile:%d Screen(%d,%d) -> (%d,%d)", tileno, dwXL, dwYL, dwXH, dwYH);
LOG_UCODE(" Tex:(%#5f,%#5f) -> (%#5f,%#5f) (DSDX:%#5f DTDY:%#5f)",
fS0, fT0, fS1, fT1, fDSDX, fDTDY);
LOG_UCODE("");
float t0u0 = (fS0-gRDP.tiles[tileno].hilite_sl) * gRDP.tiles[tileno].fShiftScaleS;
float t0v0 = (fT0-gRDP.tiles[tileno].hilite_tl) * gRDP.tiles[tileno].fShiftScaleT;
float t0u1 = t0u0 + (fDSDX * (dwXH - dwXL))*gRDP.tiles[tileno].fShiftScaleS;
float t0v1 = t0v0 + (fDTDY * (dwYH - dwYL))*gRDP.tiles[tileno].fShiftScaleT;
if( dwXL==0 && dwYL==0 && dwXH==windowSetting.fViWidth-1 && dwYH==windowSetting.fViHeight-1 &&
t0u0 == 0 && t0v0==0 && t0u1==0 && t0v1==0 )
{
//Using TextRect to clear the screen
}
else
{
if( status.bHandleN64RenderTexture && //status.bDirectWriteIntoRDRAM &&
g_pRenderTextureInfo->CI_Info.dwFormat == gRDP.tiles[tileno].dwFormat &&
g_pRenderTextureInfo->CI_Info.dwSize == gRDP.tiles[tileno].dwSize &&
gRDP.tiles[tileno].dwFormat == TXT_FMT_CI && gRDP.tiles[tileno].dwSize == TXT_SIZE_8b )
{
if( options.enableHackForGames == HACK_FOR_YOSHI )
{
// Hack for Yoshi background image
PrepareTextures();
TexRectToFrameBuffer_8b(dwXL, dwYL, dwXH, dwYH, t0u0, t0v0, t0u1, t0v1, tileno);
DEBUGGER_PAUSE_AT_COND_AND_DUMP_COUNT_N((eventToPause == NEXT_FLUSH_TRI || eventToPause == NEXT_TEXTRECT), {
DebuggerAppendMsg("TexRect: tile=%d, X0=%d, Y0=%d, X1=%d, Y1=%d,\nfS0=%f, fT0=%f, ScaleS=%f, ScaleT=%f\n",
gRSP.curTile, dwXL, dwYL, dwXH, dwYH, fS0, fT0, fDSDX, fDTDY);
DebuggerAppendMsg("Pause after TexRect for Yoshi\n");
});
}
else
{
if( frameBufferOptions.bUpdateCIInfo )
{
PrepareTextures();
TexRectToFrameBuffer_8b(dwXL, dwYL, dwXH, dwYH, t0u0, t0v0, t0u1, t0v1, tileno);
}
if( !status.bDirectWriteIntoRDRAM )
{
CRender::g_pRender->TexRect(dwXL, dwYL, dwXH, dwYH, fS0, fT0, fDSDX, fDTDY);
status.dwNumTrisRendered += 2;
}
}
}
else
{
CRender::g_pRender->TexRect(dwXL, dwYL, dwXH, dwYH, fS0, fT0, fDSDX, fDTDY);
status.bFrameBufferDrawnByTriangles = true;
status.dwNumTrisRendered += 2;
}
}
if( status.bHandleN64RenderTexture ) g_pRenderTextureInfo->maxUsedHeight = max(g_pRenderTextureInfo->maxUsedHeight,(int)dwYH);
ForceMainTextureIndex(curTile);
}
void DLParser_TexRectFlip(Gfx *gfx)
{
status.bCIBufferIsRendered = true;
status.primitiveType = PRIM_TEXTRECTFLIP;
// This command used 128bits, and not 64 bits. This means that we have to look one
// Command ahead in the buffer, and update the PC.
uint32 dwPC = gDlistStack[gDlistStackPointer].pc; // This points to the next instruction
uint32 dwCmd2 = *(uint32 *)(g_pRDRAMu8 + dwPC+4);
uint32 dwCmd3 = *(uint32 *)(g_pRDRAMu8 + dwPC+4+8);
// Increment PC so that it points to the right place
gDlistStack[gDlistStackPointer].pc += 16;
uint32 dwXH = (((gfx->words.w0)>>12)&0x0FFF)/4;
uint32 dwYH = (((gfx->words.w0) )&0x0FFF)/4;
uint32 tileno = ((gfx->words.w1)>>24)&0x07;
uint32 dwXL = (((gfx->words.w1)>>12)&0x0FFF)/4;
uint32 dwYL = (((gfx->words.w1) )&0x0FFF)/4;
uint32 dwS = ( dwCmd2>>16)&0xFFFF;
uint32 dwT = ( dwCmd2 )&0xFFFF;
LONG nDSDX = (LONG)(short)(( dwCmd3>>16)&0xFFFF);
LONG nDTDY = (LONG)(short)(( dwCmd3 )&0xFFFF);
uint32 curTile = gRSP.curTile;
ForceMainTextureIndex(tileno);
float fS0 = (float)dwS / 32.0f;
float fT0 = (float)dwT / 32.0f;
float fDSDX = (float)nDSDX / 1024.0f;
float fDTDY = (float)nDTDY / 1024.0f;
uint32 cycletype = gRDP.otherMode.cycle_type;
if (cycletype == CYCLE_TYPE_COPY)
{
fDSDX /= 4.0f; // In copy mode 4 pixels are copied at once.
dwXH++;
dwYH++;
}
else if (cycletype == CYCLE_TYPE_FILL)
{
dwXH++;
dwYH++;
}
float fS1 = fS0 + (fDSDX * (dwYH - dwYL));
float fT1 = fT0 + (fDTDY * (dwXH - dwXL));
LOG_UCODE(" Tile:%d (%d,%d) -> (%d,%d)",
tileno, dwXL, dwYL, dwXH, dwYH);
LOG_UCODE(" Tex:(%#5f,%#5f) -> (%#5f,%#5f) (DSDX:%#5f DTDY:%#5f)",
fS0, fT0, fS1, fT1, fDSDX, fDTDY);
LOG_UCODE("");
float t0u0 = (fS0) * gRDP.tiles[tileno].fShiftScaleS-gRDP.tiles[tileno].sl;
float t0v0 = (fT0) * gRDP.tiles[tileno].fShiftScaleT-gRDP.tiles[tileno].tl;
float t0u1 = t0u0 + (fDSDX * (dwYH - dwYL))*gRDP.tiles[tileno].fShiftScaleS;
float t0v1 = t0v0 + (fDTDY * (dwXH - dwXL))*gRDP.tiles[tileno].fShiftScaleT;
CRender::g_pRender->TexRectFlip(dwXL, dwYL, dwXH, dwYH, t0u0, t0v0, t0u1, t0v1);
status.dwNumTrisRendered += 2;
if( status.bHandleN64RenderTexture ) g_pRenderTextureInfo->maxUsedHeight = max(g_pRenderTextureInfo->maxUsedHeight,int(dwYL+(dwXH-dwXL)));
ForceMainTextureIndex(curTile);
}
/************************************************************************/
/* */
/************************************************************************/
/*
* TMEM emulation
* There are 0x200's 64bits entry in TMEM
* Usually, textures are loaded into TMEM at 0x0, and TLUT is loaded at 0x100
* of course, the whole TMEM can be used by textures if TLUT is not used, and TLUT
* can be at other address of TMEM.
*
* We don't want to emulate TMEM by creating a block of memory for TMEM and load
* everything into the block of memory, this will be slow.
*/
typedef struct TmemInfoEntry{
uint32 start;
uint32 length;
uint32 rdramAddr;
TmemInfoEntry* next;
} TmemInfoEntry;
const int tmenMaxEntry=20;
TmemInfoEntry tmenEntryBuffer[20]={{0}};
TmemInfoEntry *g_pTMEMInfo=NULL;
TmemInfoEntry *g_pTMEMFreeList=tmenEntryBuffer;
void TMEM_Init()
{
g_pTMEMInfo=NULL;
g_pTMEMFreeList=tmenEntryBuffer;
int i;
for( i=0; i<tmenMaxEntry; i++ )
{
tmenEntryBuffer[i].start=0;
tmenEntryBuffer[i].length=0;
tmenEntryBuffer[i].rdramAddr=0;
tmenEntryBuffer[i].next = &(tmenEntryBuffer[i+1]);
}
tmenEntryBuffer[i].next = NULL;
}
void TMEM_SetBlock(uint32 tmemstart, uint32 length, uint32 rdramaddr)
{
TmemInfoEntry *p=g_pTMEMInfo;
if( p == NULL )
{
// Move an entry from freelist and link it to the header
p = g_pTMEMFreeList;
g_pTMEMFreeList = g_pTMEMFreeList->next;
p->start = tmemstart;
p->length = length;
p->rdramAddr = rdramaddr;
p->next = NULL;
}
else
{
while ( tmemstart > (p->start+p->length) )
{
if( p->next != NULL ) {
p = p->next;
continue;
}
else {
break;
}
}
if ( p->start == tmemstart )
{
// need to replace the block of 'p'
// or append a new block depend the block lengths
if( length == p->length )
{
p->rdramAddr = rdramaddr;
return;
}
else if( length < p->length )
{
TmemInfoEntry *newentry = g_pTMEMFreeList;
g_pTMEMFreeList = g_pTMEMFreeList->next;
newentry->length = p->length - length;
newentry->next = p->next;
newentry->rdramAddr = p->rdramAddr + p->length;
newentry->start = p->start + p->length;
p->length = length;
p->next = newentry;
p->rdramAddr = rdramaddr;
}
}
else if( p->start > tmemstart )
{
// p->start > tmemstart, need to insert the new block before 'p'
TmemInfoEntry *newentry = g_pTMEMFreeList;
g_pTMEMFreeList = g_pTMEMFreeList->next;
if( length+tmemstart < p->start+p->length )
{
newentry->length = p->length - length;
newentry->next = p->next;
newentry->rdramAddr = p->rdramAddr + p->length;
newentry->start = p->start + p->length;
p->length = length;
p->next = newentry;
p->rdramAddr = rdramaddr;
p->start = tmemstart;
}
else if( length+tmemstart == p->start+p->length )
{
}
}
else
{
}
}
}
uint32 TMEM_GetRdramAddr(uint32 tmemstart, uint32 length)
{
return 0;
}
/*
* New implementation of texture loading
*/
bool IsTmemFlagValid(uint32 tmemAddr)
{
uint32 index = tmemAddr>>5;
uint32 bitIndex = (tmemAddr&0x1F);
return ((g_TmemFlag[index] & (1<<bitIndex))!=0);
}
uint32 GetValidTmemInfoIndex(uint32 tmemAddr)
{
return 0;
uint32 index = tmemAddr>>5;
uint32 bitIndex = (tmemAddr&0x1F);
if ((g_TmemFlag[index] & (1<<bitIndex))!=0 ) //This address is valid
return tmemAddr;
else
{
for( uint32 i=index; i>=0; i-- )
{
if( g_TmemFlag[i] != 0 )
{
for( uint32 j=0x1F; j>=0; j-- )
{
if( (g_TmemFlag[i] & (1<<j)) != 0 )
{
return ((i<<5)+j);
}
}
}
}
TRACE0("Error, check me");
return 0;
}
}
void SetTmemFlag(uint32 tmemAddr, uint32 size)
{
uint32 index = tmemAddr>>5;
uint32 bitIndex = (tmemAddr&0x1F);
#ifdef _DEBUG
if( size > 0x200 )
{
DebuggerAppendMsg("Check me: tmemaddr=%X, size=%x", tmemAddr, size);
size = 0x200-tmemAddr;
}
#endif
if( bitIndex == 0 )
{
uint32 i;
for( i=0; i< (size>>5); i++ )
{
g_TmemFlag[index+i] = 0;
}
if( (size&0x1F) != 0 )
{
//ErrorMsg("Check me: tmemaddr=%X, size=%x", tmemAddr, size);
g_TmemFlag[index+i] &= ~((1<<(size&0x1F))-1);
}
g_TmemFlag[index] |= 1;
}
else
{
if( bitIndex + size <= 0x1F )
{
uint32 val = g_TmemFlag[index];
uint32 mask = (1<<(bitIndex))-1;
mask |= ~((1<<(bitIndex + size))-1);
val &= mask;
val |= (1<<bitIndex);
g_TmemFlag[index] = val;
}
else
{
//ErrorMsg("Check me: tmemaddr=%X, size=%x", tmemAddr, size);
uint32 val = g_TmemFlag[index];
uint32 mask = (1<<bitIndex)-1;
val &= mask;
val |= (1<<bitIndex);
g_TmemFlag[index] = val;
index++;
size -= (0x20-bitIndex);
uint32 i;
for( i=0; i< (size>>5); i++ )
{
g_TmemFlag[index+i] = 0;
}
if( (size&0x1F) != 0 )
{
//ErrorMsg("Check me: tmemaddr=%X, size=%x", tmemAddr, size);
g_TmemFlag[index+i] &= ~((1<<(size&0x1F))-1);
}
}
}
}