daedalus/Source/HLEGraphics/uCodes/Ucode_GBI2.h
Carlos R e0070b6861 Fix for blast corps and more bound checks
*Properly trigger DP interrupt, some games are very sensitive when we ignore it. Blast Corps no longer hangs after the Rare logo. Also ensure to trigger the interrupt when frameskip its enabled to avoid stalls
*Added bound checks for DLinMem and DLCount
*Disabled invalid address bound checks for the PSP. With the recent changes, now its safer to disable it
2020-07-12 15:10:16 -07:00

620 lines
18 KiB
C

/*
Copyright (C) 2009 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.
*/
#ifndef HLEGRAPHICS_UCODES_UCODE_GBI2_H_
#define HLEGRAPHICS_UCODES_UCODE_GBI2_H_
//*****************************************************************************
//
//*****************************************************************************
void DLParser_GBI2_Vtx( MicroCodeCommand command )
{
u32 address = RDPSegAddr(command.vtx2.addr);
u32 vend = command.vtx2.vend >> 1;
u32 n = command.vtx2.n;
u32 v0 = vend - n;
DL_PF( " Address[0x%08x] vEnd[%d] v0[%d] Num[%d]", address, vend, v0, n );
if (IsVertexInfoValid(address, 16, v0, n))
{
gRenderer->SetNewVertexInfo( address, v0, n );
#ifdef DAEDALUS_DEBUG_DISPLAYLIST
gNumVertices += n;
DLParser_DumpVtxInfo( address, v0, n );
#endif
}
}
//*****************************************************************************
//
//*****************************************************************************
void DLParser_GBI2_Mtx( MicroCodeCommand command )
{
u32 address = RDPSegAddr(command.mtx2.addr);
#ifdef DAEDALUS_DEBUG_DISPLAYLIST
DL_PF(" Command: %s %s %s Length %d Address 0x%08x",
command.mtx2.projection ? "Projection" : "ModelView",
command.mtx2.load ? "Load" : "Mul",
command.mtx2.nopush == 0 ? "Push" : "No Push",
command.mtx2.len, address);
#endif
// Load matrix from address
if (command.mtx2.projection)
{
gRenderer->SetProjection(address, command.mtx2.load);
}
else
{
gRenderer->SetWorldView(address, command.mtx2.nopush==0, command.mtx2.load);
}
}
//*****************************************************************************
//
//*****************************************************************************
void DLParser_GBI2_PopMtx( MicroCodeCommand command )
{
#ifdef DAEDALUS_DEBUG_DISPLAYLIST
DL_PF(" Command: (%s)", command.inst.cmd1 ? "Projection" : "ModelView");
#endif
// Banjo Tooie, pops more than one matrix
u32 num = command.inst.cmd1>>6;
// Just pop the worldview matrix
gRenderer->PopWorldView(num);
}
//*****************************************************************************
//
//*****************************************************************************
//0016A710: DB020000 00000018 CMD Zelda_MOVEWORD Mem[2][00]=00000018 Lightnum=0
//001889F0: DB020000 00000030 CMD Zelda_MOVEWORD Mem[2][00]=00000030 Lightnum=2
void DLParser_GBI2_MoveWord( MicroCodeCommand command )
{
switch (command.mw2.type)
{
case G_MW_MATRIX:
{
#ifdef DAEDALUS_DEBUG_DISPLAYLIST
DL_PF(" G_MW_MATRIX(2)");
#endif
gRenderer->InsertMatrix(command.inst.cmd0, command.inst.cmd1);
}
break;
case G_MW_NUMLIGHT:
{
// Lightnum
// command->cmd1:
// 0x18 = 24 = 0 lights
// 0x30 = 48 = 2 lights
u32 num_lights = command.mw2.value / 24;
#ifdef DAEDALUS_DEBUG_DISPLAYLIST
DL_PF(" G_MW_NUMLIGHT: %d", num_lights);
#endif
gRenderer->SetNumLights(num_lights);
}
break;
/*
case G_MW_CLIP: // Seems to be unused?
{
DL_PF(" G_MW_CLIP");
}
break;
*/
case G_MW_SEGMENT:
{
u32 segment = command.mw2.offset >> 2;
u32 address = command.mw2.value & 0x00FFFFFF;
DL_PF( " G_MW_SEGMENT Segment[%d] = 0x%08x", segment, address );
gSegments[segment] = address;
}
break;
case G_MW_FOG: // WIP, only works for the PSP
{
#ifdef DAEDALUS_PSP
f32 mul = (f32)(s16)(command.mw2.value >> 16); //Fog mult
f32 offs = (f32)(s16)(command.mw2.value & 0xFFFF); //Fog Offset
gRenderer->SetFogMultOffs(mul, offs);
// HW fog, only works for a few games
#if 0
f32 a = (f32)(command.mw2.value >> 16);
f32 b = (f32)(command.mw2.value & 0xFFFF);
f32 fog_near = a / 256.0f;
f32 fog_far = b / 6.0f;
gRenderer->SetFogMinMax(fog_near, fog_far);
#endif
//DL_PF(" G_MW_FOG. Mult = 0x%04x (%f), Off = 0x%04x (%f)", wMult, 255.0f * fMult, wOff, 255.0f * fOff );
//printf("1Fog %.0f | %.0f || %.0f | %.0f\n", min, max, a, b);
#endif
}
break;
case G_MW_LIGHTCOL:
{
u32 light_idx = command.mw2.offset / 0x18;
u32 field_offset = (command.mw2.offset & 0x7);
#ifdef DAEDALUS_DEBUG_DISPLAYLIST
DL_PF(" G_MW_LIGHTCOL/0x%08x: 0x%08x", command.mw2.offset, command.mw2.value);
#endif
if (field_offset == 0)
{
u8 r = ((command.mw2.value>>24)&0xFF);
u8 g = ((command.mw2.value>>16)&0xFF);
u8 b = ((command.mw2.value>>8)&0xFF);
gRenderer->SetLightCol(light_idx, r, g, b);
}
}
break;
/*
case G_MW_PERSPNORM:
DL_PF(" G_MW_PERSPNORM 0x%04x", (s16)command.inst.cmd1);
break;
case G_MW_POINTS:
DL_PF(" G_MW_POINTS : Ignored");
break;
*/
default:
{
#ifdef DAEDALUS_DEBUG_DISPLAYLIST
DL_PF(" Ignored!!");
#endif
}
break;
}
}
//*****************************************************************************
//
//*****************************************************************************
/*
001889F8: DC08060A 80188708 CMD Zelda_MOVEMEM Movemem[0806] <- 80188708
!light 0 color 0.12 0.16 0.35 dir 0.01 0.00 0.00 0.00 (2 lights) [ 1E285A00 1E285A00 01000000 00000000 ]
data(00188708): 1E285A00 1E285A00 01000000 00000000
00188A00: DC08090A 80188718 CMD Zelda_MOVEMEM Movemem[0809] <- 80188718
!light 1 color 0.23 0.25 0.30 dir 0.01 0.00 0.00 0.00 (2 lights) [ 3C404E00 3C404E00 01000000 00000000 ]
data(00188718): 3C404E00 3C404E00 01000000 00000000
00188A08: DC080C0A 80188700 CMD Zelda_MOVEMEM Movemem[080C] <- 80188700
!light 2 color 0.17 0.16 0.26 dir 0.23 0.31 0.70 0.00 (2 lights) [ 2C294300 2C294300 1E285A00 1E285A00 ]
*/
/*
ZeldaMoveMem: 0xdc080008 0x801984d8
SetScissor: x0=416 y0=72 x1=563 y1=312 mode=0
// Mtx
ZeldaMoveWord:0xdb0e0000 0x00000041 Ignored
ZeldaMoveMem: 0xdc08000a 0x80198538
ZeldaMoveMem: 0xdc08030a 0x80198548
ZeldeMoveMem: Unknown Type. 0xdc08000a 0x80198518
ZeldeMoveMem: Unknown Type. 0xdc08030a 0x80198528
ZeldeMoveMem: Unknown Type. 0xdc08000a 0x80198538
ZeldeMoveMem: Unknown Type. 0xdc08030a 0x80198548
ZeldeMoveMem: Unknown Type. 0xdc08000a 0x80198518
ZeldeMoveMem: Unknown Type. 0xdc08030a 0x80198528
ZeldeMoveMem: Unknown Type. 0xdc08000a 0x80198538
ZeldeMoveMem: Unknown Type. 0xdc08030a 0x80198548
0xa4001120: <0x0c000487> JAL 0x121c Seg2Addr(t8) dram
0xa4001124: <0x332100fe> ANDI at = t9 & 0x00fe
0xa4001128: <0x937309c1> LBU s3 <- 0x09c1(k1) len
0xa400112c: <0x943402f0> LHU s4 <- 0x02f0(at) dmem
0xa4001130: <0x00191142> SRL v0 = t9 >> 0x0005
0xa4001134: <0x959f0336> LHU ra <- 0x0336(t4)
0xa4001138: <0x080007f6> J 0x1fd8 SpMemXfer
0xa400113c: <0x0282a020> ADD s4 = s4 + v0 dmem
ZeldaMoveMem: 0xdc08000a 0x8010e830 Type: 0a Len: 08 Off: 4000
ZeldaMoveMem: 0xdc08030a 0x8010e840 Type: 0a Len: 08 Off: 4018
// Light
ZeldaMoveMem: 0xdc08060a 0x800ff368 Type: 0a Len: 08 Off: 4030
ZeldaMoveMem: 0xdc08090a 0x800ff360 Type: 0a Len: 08 Off: 4048
//VP
ZeldaMoveMem: 0xdc080008 0x8010e3c0 Type: 08 Len: 08 Off: 4000
*/
//*****************************************************************************
//
//*****************************************************************************
void DLParser_GBI2_MoveMem( MicroCodeCommand command )
{
u32 address = RDPSegAddr(command.inst.cmd1);
u32 type = (command.inst.cmd0 ) & 0xFE;
switch (type)
{
case G_GBI2_MV_VIEWPORT:
{
RDP_MoveMemViewport( address );
}
break;
case G_GBI2_MV_LIGHT:
{
u32 offset2 = (command.inst.cmd0 >> 5) & 0x7F8;
u32 light_idx = offset2 / 24;
if (light_idx < 2)
{
DL_PF(" G_MV_LOOKAT" );
return;
}
RDP_MoveMemLight< POINT_LIGHT_MM, 8 >(address, light_idx - 2);
}
break;
case G_GBI2_MV_MATRIX:
{
#ifdef DAEDALUS_DEBUG_DISPLAYLIST
DL_PF(" Force Matrix(2): addr=%08X", address);
#endif
// Rayman 2, Donald Duck, Tarzan, all wrestling games use this
gRenderer->ForceMatrix( address );
// ForceMatrix takes two cmds
gDlistStack.address[gDlistStackPointer] += 8;
}
break;
/*
case G_GBI2_MVO_L0:
case G_GBI2_MVO_L1:
case G_GBI2_MVO_L2:
case G_GBI2_MVO_L3:
case G_GBI2_MVO_L4:
case G_GBI2_MVO_L5:
case G_GBI2_MVO_L6:
case G_GBI2_MVO_L7:
DL_PF("MoveMem Light(2)");
break;
case G_GBI2_MV_POINT:
DL_PF("MoveMem Point(2)");
break;
case G_GBI2_MVO_LOOKATY:
DL_PF("MoveMem LOOKATY(2)");
break;
*/
case 0x00:
case 0x02:
{
// Ucode for Evangelion.v64
// 0 ObjMtx
// 2 SubMtx
DLParser_S2DEX_ObjMoveMem( command );
}
break;
default:
#ifdef DAEDALUS_DEBUG_DISPLAYLIST
DBGConsole_Msg(0, "GBI2 MoveMem: Unknown Type. 0x%08x 0x%08x", command.inst.cmd0, command.inst.cmd1);
#endif
break;
}
}
//*****************************************************************************
// Kirby 64, SSB and Cruisn' Exotica use this
//*****************************************************************************
void DLParser_GBI2_DL_Count( MicroCodeCommand command )
{
u32 address = RDPSegAddr(command.inst.cmd1);
if (address == 0 || !IsAddressValid(address, 8, "DL_Count"))
return;
gDlistStackPointer++;
gDlistStack.address[gDlistStackPointer] = address;
gDlistStack.limit = command.inst.cmd0 & 0xFFFF;
DL_PF(" DL Count: Push -> DisplayList 0x%08x", address);
DL_PF(" \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/ \\/");
DL_PF(" ############################################");
}
//*****************************************************************************
//
//*****************************************************************************
void DLParser_GBI2_GeometryMode( MicroCodeCommand command )
{
gGeometryMode._u32 &= command.inst.arg0;
gGeometryMode._u32 |= command.inst.arg1;
#ifdef DAEDALUS_DEBUG_DISPLAYLIST
DL_PF(" 0x%08x 0x%08x =(x & 0x%08x) | 0x%08x", command.inst.cmd0, command.inst.cmd1, command.inst.arg0, command.inst.arg1);
DL_PF(" ZBuffer %s", (gGeometryMode.GBI2_Zbuffer) ? "On" : "Off");
DL_PF(" Culling %s", (gGeometryMode.GBI2_CullBack) ? "Back face" : (gGeometryMode.GBI2_CullFront) ? "Front face" : "Off");
DL_PF(" Smooth Shading %s", (gGeometryMode.GBI2_ShadingSmooth) ? "On" : "Off");
DL_PF(" Lighting %s", (gGeometryMode.GBI2_Lighting) ? "On" : "Off");
DL_PF(" Texture Gen %s", (gGeometryMode.GBI2_TexGen) ? "On" : "Off");
DL_PF(" Texture Gen Linear %s", (gGeometryMode.GBI2_TexGenLin) ? "On" : "Off");
DL_PF(" Fog %s", (gGeometryMode.GBI2_Fog) ? "On" : "Off");
DL_PF(" PointLight %s", (gGeometryMode.GBI2_PointLight) ? "On" : "Off");
#endif
TnLMode TnL;
TnL._u32 = 0;
TnL.Light = gGeometryMode.GBI2_Lighting;
TnL.TexGen = gGeometryMode.GBI2_TexGen;
TnL.TexGenLin = gGeometryMode.GBI2_TexGenLin;
TnL.Fog = gGeometryMode.GBI2_Fog & gFogEnabled;// && (gRDPOtherMode.c1_m1a==3 || gRDPOtherMode.c1_m2a==3 || gRDPOtherMode.c2_m1a==3 || gRDPOtherMode.c2_m2a==3);
TnL.Shade = !(gGeometryMode.GBI2_TexGenLin/* & (g_ROM.GameHacks != TIGERS_HONEY_HUNT)*/);
TnL.Zbuffer = gGeometryMode.GBI2_Zbuffer;
TnL.TriCull = gGeometryMode.GBI2_CullFront | gGeometryMode.GBI2_CullBack;
TnL.CullBack = gGeometryMode.GBI2_CullBack;
TnL.PointLight = gGeometryMode.GBI2_PointLight;
gRenderer->SetTnLMode( TnL._u32 );
}
//*****************************************************************************
//
//*****************************************************************************
void DLParser_GBI2_SetOtherModeL( MicroCodeCommand command )
{
// Mask is constructed slightly differently
const u32 mask = (u32)((s32)(0x80000000) >> command.othermode.len) >> command.othermode.sft;
gRDPOtherMode.L = (gRDPOtherMode.L & ~mask) | command.othermode.data;
#ifdef DAEDALUS_DEBUG_DISPLAYLIST
DLDebug_DumpRDPOtherModeL(mask, command.othermode.data);
#endif
}
//*****************************************************************************
//
//*****************************************************************************
void DLParser_GBI2_SetOtherModeH( MicroCodeCommand command )
{
// Mask is constructed slightly differently
const u32 mask = (u32)((s32)(0x80000000) >> command.othermode.len) >> command.othermode.sft;
gRDPOtherMode.H = (gRDPOtherMode.H & ~mask) | command.othermode.data;
#ifdef DAEDALUS_DEBUG_DISPLAYLIST
DLDebug_DumpRDPOtherModeH(mask, command.othermode.data);
#endif
}
//*****************************************************************************
//
//*****************************************************************************
void DLParser_GBI2_Texture( MicroCodeCommand command )
{
bool enabled = command.texture.enable_gbi2;
if (!enabled)
{
DL_PF(" Texture its disabled -> Ignored");
gRenderer->SetTextureEnable( false );
return;
}
DL_PF(" Texture its enabled: Level[%d] Tile[%d]", command.texture.level, command.texture.tile);
gRenderer->SetTextureEnable( true );
gRenderer->SetTextureTile( command.texture.tile );
f32 scale_s = f32(command.texture.scaleS) / (65536.0f * 32.0f);
f32 scale_t = f32(command.texture.scaleT) / (65536.0f * 32.0f);
DL_PF(" ScaleS[%0.4f], ScaleT[%0.4f]", scale_s*32.0f, scale_t*32.0f);
gRenderer->SetTextureScale( scale_s, scale_t );
}
//*****************************************************************************
//
//*****************************************************************************
void DLParser_GBI2_DMA_IO( MicroCodeCommand command )
{
#ifdef DAEDALUS_DEBUG_CONSOLE
DL_UNIMPLEMENTED_ERROR( "G_DMA_IO" );
#endif
}
//*****************************************************************************
//
//*****************************************************************************
void DLParser_GBI2_Quad( MicroCodeCommand command )
{
// While the next command pair is Tri2, add vertices
u32 pc = gDlistStack.address[gDlistStackPointer];
u32 * pCmdBase = (u32 *)(g_pu8RamBase + pc);
bool tris_added = false;
do
{
//DL_PF(" 0x%08x: %08x %08x %-10s", pc-8, command.inst.cmd0, command.inst.cmd1, "G_GBI2_QUAD");
// Vertex indices are multiplied by 2
u32 v0_idx = command.gbi2line3d.v0 >> 1;
u32 v1_idx = command.gbi2line3d.v1 >> 1;
u32 v2_idx = command.gbi2line3d.v2 >> 1;
tris_added |= gRenderer->AddTri(v0_idx, v1_idx, v2_idx);
u32 v3_idx = command.gbi2line3d.v3 >> 1;
u32 v4_idx = command.gbi2line3d.v4 >> 1;
u32 v5_idx = command.gbi2line3d.v5 >> 1;
tris_added |= gRenderer->AddTri(v3_idx, v4_idx, v5_idx);
//printf("Q 0x%08x: %08x %08x %d\n", pc-8, command.inst.cmd0, command.inst.cmd1, tris_added);
command.inst.cmd0 = *pCmdBase++;
command.inst.cmd1 = *pCmdBase++;
pc += 8;
} while ( command.inst.cmd == G_GBI2_QUAD );
gDlistStack.address[gDlistStackPointer] = pc-8;
if (tris_added)
{
gRenderer->FlushTris();
}
}
//*****************************************************************************
//
//*****************************************************************************
// XXX SpiderMan uses this command.DLParser_GBI2_Tri2
void DLParser_GBI2_Line3D( MicroCodeCommand command )
{
// While the next command pair is Tri2, add vertices
u32 pc = gDlistStack.address[gDlistStackPointer];
u32 * pCmdBase = (u32 *)(g_pu8RamBase + pc);
bool tris_added = false;
do
{
//DL_PF(" 0x%08x: %08x %08x %-10s", pc-8, command.inst.cmd0, command.inst.cmd1, "G_GBI2_LINE3D");
u32 v0_idx = command.gbi2line3d.v0 >> 1;
u32 v1_idx = command.gbi2line3d.v1 >> 1;
u32 v2_idx = command.gbi2line3d.v2 >> 1;
tris_added |= gRenderer->AddTri(v0_idx, v1_idx, v2_idx);
u32 v3_idx = command.gbi2line3d.v3 >> 1;
u32 v4_idx = command.gbi2line3d.v4 >> 1;
u32 v5_idx = command.gbi2line3d.v5 >> 1;
tris_added |= gRenderer->AddTri(v3_idx, v4_idx, v5_idx);
command.inst.cmd0 = *pCmdBase++;
command.inst.cmd1 = *pCmdBase++;
pc += 8;
} while ( command.inst.cmd == G_GBI2_LINE3D );
gDlistStack.address[gDlistStackPointer] = pc-8;
if (tris_added)
{
gRenderer->FlushTris();
}
}
//*****************************************************************************
//
//*****************************************************************************
void DLParser_GBI2_Tri1( MicroCodeCommand command )
{
// While the next command pair is Tri1, add vertices
u32 pc = gDlistStack.address[gDlistStackPointer];
u32 * pCmdBase = (u32 *)(g_pu8RamBase + pc);
bool tris_added = false;
do
{
//DL_PF(" 0x%08x: %08x %08x %-10s", pc-8, command.inst.cmd0, command.inst.cmd1, "G_GBI2_TRI1");
u32 v0_idx = command.gbi2tri1.v0 >> 1;
u32 v1_idx = command.gbi2tri1.v1 >> 1;
u32 v2_idx = command.gbi2tri1.v2 >> 1;
tris_added |= gRenderer->AddTri(v0_idx, v1_idx, v2_idx);
command.inst.cmd0 = *pCmdBase++;
command.inst.cmd1 = *pCmdBase++;
pc += 8;
} while ( command.inst.cmd == G_GBI2_TRI1 );
gDlistStack.address[gDlistStackPointer] = pc-8;
if (tris_added)
{
gRenderer->FlushTris();
}
}
//*****************************************************************************
// While the next command pair is Tri2, add vertices
//*****************************************************************************
void DLParser_GBI2_Tri2( MicroCodeCommand command )
{
u32 pc = gDlistStack.address[gDlistStackPointer];
u32 * pCmdBase = (u32 *)(g_pu8RamBase + pc);
bool tris_added = false;
do
{
//DL_PF(" 0x%08x: %08x %08x %-10s", pc-8, command.inst.cmd0, command.inst.cmd1, "G_GBI2_TRI2");
// Vertex indices already divided in ucodedef
u32 v0_idx = command.gbi2tri2.v0;
u32 v1_idx = command.gbi2tri2.v1;
u32 v2_idx = command.gbi2tri2.v2;
tris_added |= gRenderer->AddTri(v0_idx, v1_idx, v2_idx);
u32 v3_idx = command.gbi2tri2.v3;
u32 v4_idx = command.gbi2tri2.v4;
u32 v5_idx = command.gbi2tri2.v5;
tris_added |= gRenderer->AddTri(v3_idx, v4_idx, v5_idx);
command.inst.cmd0 = *pCmdBase++;
command.inst.cmd1 = *pCmdBase++;
pc += 8;
} while ( command.inst.cmd == G_GBI2_TRI2 );
gDlistStack.address[gDlistStackPointer] = pc-8;
if (tris_added)
{
gRenderer->FlushTris();
}
}
//*****************************************************************************
//
//*****************************************************************************
/*
void DLParser_GBI2_0x8( MicroCodeCommand command )
{
if( (command.inst.arg0 == 0x2F && ((command.inst.cmd1)&0xFF000000) == 0x80000000 )
{
// V-Rally 64
DLParser_S2DEX_ObjLdtxRectR(command);
}
else
{
DLParser_Nothing(command);
}
}
*/
#endif // HLEGRAPHICS_UCODES_UCODE_GBI2_H_