Added proper Bounding Box support.

Should fix most graphical issues with Paper Mario: TTYD and Super Paper Mario. Fixes issue 360.

Since only those two games seem to require BBox support, and as per ector's suggestion, BBox is only enabled for those two games.

BBoxes and Display List Caches don't get along too well, causing Paper Mario: TTYD to hang during certain effects where BBoxes are used. For now, I disabled DList Cache for the Paper Mario games, hopefully both will be compatible in the future.
This commit is contained in:
crudelios 2011-10-26 01:19:10 +01:00
parent 78832cb4ea
commit 852fe9c4be
12 changed files with 93 additions and 61 deletions

View File

@ -41,5 +41,7 @@ $Max Gold
$Max Shop Points $Max Shop Points
026EE7F0 000003E7 026EE7F0 000003E7
[Video] [Video]
UseBBox = True
ProjectionHack = 0 ProjectionHack = 0
[Video_Hacks]
DlistCachingEnable = False

View File

@ -4,3 +4,7 @@
EmulationStateId = 4 EmulationStateId = 4
[OnFrame] Add memory patches to be applied every frame here. [OnFrame] Add memory patches to be applied every frame here.
[ActionReplay] Add action replay cheats here. [ActionReplay] Add action replay cheats here.
[Video]
UseBBox = True
[Video_Hacks]
DlistCachingEnable = False

View File

@ -5,3 +5,7 @@ EmulationIssues = Sound requires LLE. No graphical issues.
EmulationStateId = 4 EmulationStateId = 4
[OnFrame] Add memory patches to be applied every frame here. [OnFrame] Add memory patches to be applied every frame here.
[ActionReplay] Add action replay cheats here. [ActionReplay] Add action replay cheats here.
[Video]
UseBBox = True
[Video_Hacks]
DlistCachingEnable = False

View File

@ -7,5 +7,8 @@ EmulationIssues =
[OnFrame] Add memory patches to be applied every frame here. [OnFrame] Add memory patches to be applied every frame here.
[ActionReplay] Add action replay cheats here. [ActionReplay] Add action replay cheats here.
[Video] [Video]
UseBBox = True
ProjectionHack = 0 ProjectionHack = 0
[Video_Hacks]
DlistCachingEnable = False
[Gecko] [Gecko]

View File

@ -6,4 +6,7 @@ EmulationIssues =
[OnFrame] Add memory patches to be applied every frame here. [OnFrame] Add memory patches to be applied every frame here.
[ActionReplay] Add action replay cheats here. [ActionReplay] Add action replay cheats here.
[Video] [Video]
UseBBox = True
ProjectionHack = 0 ProjectionHack = 0
[Video_Hacks]
DlistCachingEnable = False

View File

@ -325,6 +325,9 @@ void CISOProperties::CreateGUIControls(bool IsWad)
DisableWiimoteSpeaker->SetToolTip(_("Mutes the Wiimote speaker. Fixes random disconnections on real wiimotes. No effect on emulated wiimotes.")); DisableWiimoteSpeaker->SetToolTip(_("Mutes the Wiimote speaker. Fixes random disconnections on real wiimotes. No effect on emulated wiimotes."));
// Video // Video
UseBBox = new wxCheckBox(m_GameConfig, ID_ZTP_SPEEDUP, _("Enable Bounding Box Calculation"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER);
UseBBox->SetToolTip(_("If checked, the bounding box registers will be updated. Used by the Paper Mario games."));
UseZTPSpeedupHack = new wxCheckBox(m_GameConfig, ID_ZTP_SPEEDUP, _("ZTP hack"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER); UseZTPSpeedupHack = new wxCheckBox(m_GameConfig, ID_ZTP_SPEEDUP, _("ZTP hack"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER);
UseZTPSpeedupHack->SetToolTip(_("Enable this to speed up The Legend of Zelda: Twilight Princess. Disable for ANY other game.")); UseZTPSpeedupHack->SetToolTip(_("Enable this to speed up The Legend of Zelda: Twilight Princess. Disable for ANY other game."));
@ -383,6 +386,7 @@ void CISOProperties::CreateGUIControls(bool IsWad)
wxStaticBoxSizer * const sbVideoOverrides = wxStaticBoxSizer * const sbVideoOverrides =
new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Video")); new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Video"));
sbVideoOverrides->Add(UseBBox, 0, wxLEFT, 5);
sbVideoOverrides->Add(UseZTPSpeedupHack, 0, wxLEFT, 5); sbVideoOverrides->Add(UseZTPSpeedupHack, 0, wxLEFT, 5);
szrPHackSettings->Add(PHackEnable, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5); szrPHackSettings->Add(PHackEnable, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5);
szrPHackSettings->Add(PHSettings, 0, wxLEFT, 5); szrPHackSettings->Add(PHSettings, 0, wxLEFT, 5);
@ -899,6 +903,12 @@ void CISOProperties::LoadGameConfig()
else else
DisableWiimoteSpeaker->Set3StateValue(wxCHK_UNDETERMINED); DisableWiimoteSpeaker->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Video", "UseBBox", &bTemp))
UseBBox->Set3StateValue((wxCheckBoxState)bTemp);
else
UseBBox->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Video", "ZTPSpeedupHack", &bTemp)) if (GameIni.Get("Video", "ZTPSpeedupHack", &bTemp))
UseZTPSpeedupHack->Set3StateValue((wxCheckBoxState)bTemp); UseZTPSpeedupHack->Set3StateValue((wxCheckBoxState)bTemp);
else else
@ -992,6 +1002,11 @@ bool CISOProperties::SaveGameConfig()
else else
GameIni.Set("Wii", "DisableWiimoteSpeaker", DisableWiimoteSpeaker->Get3StateValue()); GameIni.Set("Wii", "DisableWiimoteSpeaker", DisableWiimoteSpeaker->Get3StateValue());
if (UseBBox->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Video", "UseBBox");
else
GameIni.Set("Video", "UseBBox", UseBBox->Get3StateValue());
if (UseZTPSpeedupHack->Get3StateValue() == wxCHK_UNDETERMINED) if (UseZTPSpeedupHack->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Video", "ZTPSpeedupHack"); GameIni.DeleteKey("Video", "ZTPSpeedupHack");
else else

View File

@ -74,7 +74,7 @@ private:
// Wii // Wii
wxCheckBox *EnableProgressiveScan, *EnableWideScreen, *DisableWiimoteSpeaker; wxCheckBox *EnableProgressiveScan, *EnableWideScreen, *DisableWiimoteSpeaker;
// Video // Video
wxCheckBox *UseZTPSpeedupHack, *PHackEnable; wxCheckBox *UseZTPSpeedupHack, *PHackEnable, *UseBBox;
wxButton *PHSettings; wxButton *PHSettings;
wxArrayString arrayStringFor_EmuState; wxArrayString arrayStringFor_EmuState;

View File

@ -257,9 +257,8 @@ void BPWritten(const BPCmd& bp)
// We should be able to get away with deactivating the current bbox tracking // We should be able to get away with deactivating the current bbox tracking
// here. Not sure if there's a better spot to put this. // here. Not sure if there's a better spot to put this.
// the number of lines copied is determined by the y scale * source efb height // the number of lines copied is determined by the y scale * source efb height
#ifdef BBOX_SUPPORT
PixelEngine::bbox_active = false; PixelEngine::bbox_active = false;
#endif
float yScale; float yScale;
if (PE_copy.scale_invert) if (PE_copy.scale_invert)
@ -400,28 +399,29 @@ void BPWritten(const BPCmd& bp)
case BPMEM_CLEARBBOX1: case BPMEM_CLEARBBOX1:
case BPMEM_CLEARBBOX2: case BPMEM_CLEARBBOX2:
{ {
#ifdef BBOX_SUPPORT if(g_ActiveConfig.bUseBBox)
// which is which? these are GUESSES! {
if (bp.address == BPMEM_CLEARBBOX1) { // which is which? these are GUESSES!
int right = bp.newvalue >> 10; if (bp.address == BPMEM_CLEARBBOX1) {
int left = bp.newvalue & 0x3ff; int right = bp.newvalue >> 10;
int left = bp.newvalue & 0x3ff;
// We should only set these if bbox is calculated properly. // We should only set these if bbox is calculated properly.
PixelEngine::bbox[0] = left; PixelEngine::bbox[0] = left;
PixelEngine::bbox[1] = right; PixelEngine::bbox[1] = right;
PixelEngine::bbox_active = true; PixelEngine::bbox_active = true;
// WARN_LOG(VIDEO, "ClearBBox LR: %i, %08x - %i, %i", bp.address, bp.newvalue, left, right); // WARN_LOG(VIDEO, "ClearBBox LR: %i, %08x - %i, %i", bp.address, bp.newvalue, left, right);
} else { } else {
int bottom = bp.newvalue >> 10; int bottom = bp.newvalue >> 10;
int top = bp.newvalue & 0x3ff; int top = bp.newvalue & 0x3ff;
// We should only set these if bbox is calculated properly. // We should only set these if bbox is calculated properly.
PixelEngine::bbox[2] = top; PixelEngine::bbox[2] = top;
PixelEngine::bbox[3] = bottom; PixelEngine::bbox[3] = bottom;
PixelEngine::bbox_active = true; PixelEngine::bbox_active = true;
// WARN_LOG(VIDEO, "ClearBBox TB: %i, %08x - %i, %i", bp.address, bp.newvalue, top, bottom); // WARN_LOG(VIDEO, "ClearBBox TB: %i, %08x - %i, %i", bp.address, bp.newvalue, top, bottom);
}
} }
#endif
} }
break; break;
case BPMEM_TEXINVALIDATE: // Used, if game has manual control the Texture Cache, which we don't allow case BPMEM_TEXINVALIDATE: // Used, if game has manual control the Texture Cache, which we don't allow

View File

@ -101,7 +101,7 @@ void LOADERDECL PosMtx_Write()
void LOADERDECL UpdateBoundingBox() void LOADERDECL UpdateBoundingBox()
{ {
if (!PixelEngine::bbox_active) if (!PixelEngine::bbox_active)
return; return;
// Truly evil hack, reading backwards from the write pointer. If we were writing to write-only // Truly evil hack, reading backwards from the write pointer. If we were writing to write-only
@ -119,40 +119,46 @@ void LOADERDECL UpdateBoundingBox()
t[1] = p[0] * world_matrix[4] + p[1] * world_matrix[5] + p[2] * world_matrix[6] + world_matrix[7]; t[1] = p[0] * world_matrix[4] + p[1] * world_matrix[5] + p[2] * world_matrix[6] + world_matrix[7];
t[2] = p[0] * world_matrix[8] + p[1] * world_matrix[9] + p[2] * world_matrix[10] + world_matrix[11]; t[2] = p[0] * world_matrix[8] + p[1] * world_matrix[9] + p[2] * world_matrix[10] + world_matrix[11];
float o[4]; float o[3];
o[2] = t[0] * proj_matrix[8] + t[1] * proj_matrix[9] + t[2] * proj_matrix[10] + proj_matrix[11];
// Depth culling
if (o[2] < 0.0) {
// No pixels are likely to be drawn - don't update bounding box.
return;
}
o[0] = t[0] * proj_matrix[0] + t[1] * proj_matrix[1] + t[2] * proj_matrix[2] + proj_matrix[3]; o[0] = t[0] * proj_matrix[0] + t[1] * proj_matrix[1] + t[2] * proj_matrix[2] + proj_matrix[3];
o[1] = t[0] * proj_matrix[4] + t[1] * proj_matrix[5] + t[2] * proj_matrix[6] + proj_matrix[7]; o[1] = t[0] * proj_matrix[4] + t[1] * proj_matrix[5] + t[2] * proj_matrix[6] + proj_matrix[7];
o[3] = t[0] * proj_matrix[12] + t[1] * proj_matrix[13] + t[2] * proj_matrix[14] + proj_matrix[15]; o[2] = t[0] * proj_matrix[12] + t[1] * proj_matrix[13] + t[2] * proj_matrix[14] + proj_matrix[15];
o[0] /= o[3];
o[1] /= o[3]; o[0] /= o[2];
o[1] /= o[2];
// should possibly adjust for viewport? // should possibly adjust for viewport?
o[0] = (o[0] + 1.0f) * 320.0f; o[0] = (o[0] + 1.0f) * 304.0f;
o[1] = (o[1] + 1.0f) * 240.0f; o[1] = (1.0f - o[1]) * 240.0f;
if (o[0] < PixelEngine::bbox[0]) PixelEngine::bbox[0] = (u16)std::max(0.0f, o[0]); if (o[0] < PixelEngine::bbox[0])
if (o[0] > PixelEngine::bbox[1]) PixelEngine::bbox[1] = (u16)std::min(640.0f, o[0]); {
if (o[1] < PixelEngine::bbox[2]) PixelEngine::bbox[2] = (u16)std::max(0.0f, o[1]); PixelEngine::bbox[0] = (u16) std::max(0.0f, o[0]);
if (o[1] > PixelEngine::bbox[3]) PixelEngine::bbox[3] = (u16)std::min(480.0f, o[1]);
// Hardware tests bounding boxes in 2x2 blocks => left and top are even, right and bottom are odd // Hardware tests bounding boxes in 2x2 blocks => left and top are even, right and bottom are odd
PixelEngine::bbox[0] &= ~1; PixelEngine::bbox[0] &= ~1;
PixelEngine::bbox[1] |= 1; }
PixelEngine::bbox[2] &= ~1;
PixelEngine::bbox[3] |= 1;
/* if (o[0] > PixelEngine::bbox[1])
if (GetAsyncKeyState(VK_LSHIFT)) { {
ERROR_LOG(VIDEO, "XForm: %f %f %f to %f %f", p[0], p[1], p[2], o[0], o[1]); PixelEngine::bbox[1] = (u16) std::min(608.0f, o[0]);
ERROR_LOG(VIDEO, "%i %i %i %i", g_VideoInitialize.pBBox[0], g_VideoInitialize.pBBox[1], g_VideoInitialize.pBBox[2], g_VideoInitialize.pBBox[3]); if(!(PixelEngine::bbox[1] & 1) && PixelEngine::bbox[1] != 0)
}*/ PixelEngine::bbox[1]--;
}
if (o[1] < PixelEngine::bbox[2])
{
PixelEngine::bbox[2] = (u16) std::max(0.0f, o[1]);
PixelEngine::bbox[2] &= ~1;
}
if (o[1] > PixelEngine::bbox[3])
{
PixelEngine::bbox[3] = (u16) std::min(480.0f, o[1]);
if(!(PixelEngine::bbox[3] & 1) && PixelEngine::bbox[3] != 0)
PixelEngine::bbox[3]--;
}
} }
void LOADERDECL TexMtx_ReadDirect_UByte() void LOADERDECL TexMtx_ReadDirect_UByte()
@ -290,9 +296,8 @@ void VertexLoader::CompileVertexTranslator()
// OK, so we just got a point. Let's go back and read it for the bounding box. // OK, so we just got a point. Let's go back and read it for the bounding box.
#ifdef BBOX_SUPPORT if(g_ActiveConfig.bUseBBox)
WriteCall(UpdateBoundingBox); WriteCall(UpdateBoundingBox);
#endif
// Normals // Normals
vtx_decl.num_normals = 0; vtx_decl.num_normals = 0;

View File

@ -56,12 +56,6 @@ enum
MAX_XFB_HEIGHT = 574 MAX_XFB_HEIGHT = 574
}; };
// If this is enabled, bounding boxes will be computed for everything drawn.
// This can theoretically have a big speed hit in some geom heavy games. Needs more work.
// Helps some effects in Paper Mario (but they aren't quite right yet).
// Do testing to figure out if the speed hit is bad?
// #define BBOX_SUPPORT
// Logging // Logging
// ---------- // ----------
void HandleGLError(); void HandleGLError();

View File

@ -172,6 +172,7 @@ void VideoConfig::GameIniLoad(const char *ini_file)
iniFile.GetIfExists("Video", "PH_ZNear", &sPhackvalue[0]); iniFile.GetIfExists("Video", "PH_ZNear", &sPhackvalue[0]);
iniFile.GetIfExists("Video", "PH_ZFar", &sPhackvalue[1]); iniFile.GetIfExists("Video", "PH_ZFar", &sPhackvalue[1]);
iniFile.GetIfExists("Video", "ZTPSpeedupHack", &bZTPSpeedHack); iniFile.GetIfExists("Video", "ZTPSpeedupHack", &bZTPSpeedHack);
iniFile.GetIfExists("Video", "UseBBox", &bUseBBox);
} }
void VideoConfig::VerifyValidity() void VideoConfig::VerifyValidity()

View File

@ -135,6 +135,7 @@ struct VideoConfig
std::string sPhackvalue[2]; std::string sPhackvalue[2];
float fAspectRatioHackW, fAspectRatioHackH; float fAspectRatioHackW, fAspectRatioHackH;
bool bZTPSpeedHack; // The Legend of Zelda: Twilight Princess bool bZTPSpeedHack; // The Legend of Zelda: Twilight Princess
bool bUseBBox;
bool bEnablePixelLighting; bool bEnablePixelLighting;
bool bEnablePerPixelDepth; bool bEnablePerPixelDepth;