mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 09:35:09 +02:00
Merge pull request #18653 from hrydgard/simplify-bof-rendering
Use the Tokimeki / old Juiced 2 method for Breath of Fire III
This commit is contained in:
@@ -482,73 +482,6 @@ void SoftwareTransform::Transform(int prim, u32 vertType, const DecVtxFormat &de
|
||||
}
|
||||
}
|
||||
|
||||
// Also, this assumes SetTexture() has already figured out the actual texture height.
|
||||
void SoftwareTransform::DetectOffsetTexture(int maxIndex) {
|
||||
TransformedVertex *transformed = params_.transformed;
|
||||
|
||||
const int w = gstate.getTextureWidth(0);
|
||||
const int h = gstate.getTextureHeight(0);
|
||||
float widthFactor = (float)w / (float)gstate_c.curTextureWidth;
|
||||
float heightFactor = (float)h / (float)gstate_c.curTextureHeight;
|
||||
|
||||
// Breath of Fire 3 does some interesting rendering here, probably from being a port.
|
||||
// It draws at 384x240 to two buffers in VRAM, one right after the other.
|
||||
// We end up creating separate framebuffers, and rendering to each.
|
||||
// But the game then stretches this to the screen - and reads from a single 512 tall texture.
|
||||
// We initially use the first framebuffer. This code detects the read from the second.
|
||||
//
|
||||
// First Vs: 12, 228 - second Vs: 252, 468 - estimated fb height: 272
|
||||
|
||||
// If curTextureHeight is < h, it must be a framebuffer that wasn't full height.
|
||||
if (gstate_c.curTextureHeight < (u32)h && maxIndex >= 2) {
|
||||
// This is the max V that will still land within the framebuffer (since it's shorter.)
|
||||
// We already adjusted V to the framebuffer above.
|
||||
const float maxAvailableV = 1.0f;
|
||||
// This is the max V that would've been inside the original texture size.
|
||||
const float maxValidV = heightFactor;
|
||||
|
||||
// Apparently, Assassin's Creed: Bloodlines accesses just outside.
|
||||
const float invTexH = 1.0f / gstate_c.curTextureHeight; // size of one texel.
|
||||
|
||||
// Are either TL or BR inside the texture but outside the framebuffer?
|
||||
const bool tlOutside = transformed[0].v > maxAvailableV + invTexH && transformed[0].v <= maxValidV;
|
||||
const bool brOutside = transformed[1].v > maxAvailableV + invTexH && transformed[1].v <= maxValidV;
|
||||
|
||||
// If TL isn't outside, is it at least near the end?
|
||||
// We check this because some games do 0-512 from a 272 tall framebuf.
|
||||
const bool tlAlmostOutside = transformed[0].v > maxAvailableV * 0.5f && transformed[0].v <= maxValidV;
|
||||
|
||||
if (tlOutside || (brOutside && tlAlmostOutside)) {
|
||||
const u32 prevXOffset = gstate_c.curTextureXOffset;
|
||||
const u32 prevYOffset = gstate_c.curTextureYOffset;
|
||||
|
||||
// This is how far the nearest coord is, so that's where we'll look for the next framebuf.
|
||||
const u32 yOffset = (int)(gstate_c.curTextureHeight * std::min(transformed[0].v, transformed[1].v));
|
||||
if (params_.texCache->SetOffsetTexture(yOffset)) {
|
||||
const float oldWidthFactor = widthFactor;
|
||||
const float oldHeightFactor = heightFactor;
|
||||
widthFactor = (float)w / (float)gstate_c.curTextureWidth;
|
||||
heightFactor = (float)h / (float)gstate_c.curTextureHeight;
|
||||
|
||||
// We need to subtract this offset from the UVs to address the new framebuf.
|
||||
const float adjustedYOffset = yOffset + prevYOffset - gstate_c.curTextureYOffset;
|
||||
const float yDiff = (float)adjustedYOffset / (float)h;
|
||||
const float adjustedXOffset = prevXOffset - gstate_c.curTextureXOffset;
|
||||
const float xDiff = (float)adjustedXOffset / (float)w;
|
||||
|
||||
for (int index = 0; index < maxIndex; ++index) {
|
||||
transformed[index].u = (transformed[index].u / oldWidthFactor - xDiff) * widthFactor;
|
||||
transformed[index].v = (transformed[index].v / oldHeightFactor - yDiff) * heightFactor;
|
||||
}
|
||||
|
||||
// We undid the offset, so reset. This avoids a different shader.
|
||||
gstate_c.curTextureXOffset = prevXOffset;
|
||||
gstate_c.curTextureYOffset = prevYOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: The viewport must be up to date!
|
||||
void SoftwareTransform::BuildDrawingParams(int prim, int vertexCount, u32 vertType, u16 *&inds, int &maxIndex, SoftwareTransformResult *result) {
|
||||
TransformedVertex *transformed = params_.transformed;
|
||||
|
||||
@@ -66,7 +66,6 @@ public:
|
||||
|
||||
void SetProjMatrix(const float mtx[14], bool invertedX, bool invertedY, const Lin::Vec3 &trans, const Lin::Vec3 &scale);
|
||||
void Transform(int prim, u32 vertexType, const DecVtxFormat &decVtxFormat, int maxIndex, SoftwareTransformResult *result);
|
||||
void DetectOffsetTexture(int maxIndex);
|
||||
void BuildDrawingParams(int prim, int vertexCount, u32 vertType, u16 *&inds, int &maxIndex, SoftwareTransformResult *result);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -407,9 +407,6 @@ void DrawEngineD3D11::DoFlush() {
|
||||
// Games sometimes expect exact matches (see #12626, for example) for equal comparisons.
|
||||
if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f)
|
||||
result.action = SW_NOT_READY;
|
||||
if (result.action == SW_NOT_READY) {
|
||||
swTransform.DetectOffsetTexture(numDecodedVerts_);
|
||||
}
|
||||
|
||||
if (textureNeedsApply)
|
||||
textureCache_->ApplyTexture();
|
||||
|
||||
@@ -364,9 +364,6 @@ void DrawEngineDX9::DoFlush() {
|
||||
// Games sometimes expect exact matches (see #12626, for example) for equal comparisons.
|
||||
if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f)
|
||||
result.action = SW_NOT_READY;
|
||||
if (result.action == SW_NOT_READY) {
|
||||
swTransform.DetectOffsetTexture(numDecodedVerts_);
|
||||
}
|
||||
|
||||
if (textureNeedsApply)
|
||||
textureCache_->ApplyTexture();
|
||||
|
||||
@@ -392,8 +392,6 @@ void DrawEngineGLES::DoFlush() {
|
||||
// Games sometimes expect exact matches (see #12626, for example) for equal comparisons.
|
||||
if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f)
|
||||
result.action = SW_NOT_READY;
|
||||
if (result.action == SW_NOT_READY)
|
||||
swTransform.DetectOffsetTexture(numDecodedVerts_);
|
||||
|
||||
if (textureNeedsApply)
|
||||
textureCache_->ApplyTexture();
|
||||
|
||||
@@ -428,8 +428,8 @@ void DrawEngineVulkan::DoFlush() {
|
||||
// Games sometimes expect exact matches (see #12626, for example) for equal comparisons.
|
||||
if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f)
|
||||
result.action = SW_NOT_READY;
|
||||
|
||||
if (result.action == SW_NOT_READY) {
|
||||
swTransform.DetectOffsetTexture(numDecodedVerts_);
|
||||
swTransform.BuildDrawingParams(prim, vertexCount, dec_->VertexType(), inds, numDecodedVerts_, &result);
|
||||
}
|
||||
|
||||
|
||||
@@ -1280,6 +1280,12 @@ ULKS46226 = true
|
||||
ULAS42206 = true
|
||||
ULJM05541 = true
|
||||
|
||||
# Breath of Fire III
|
||||
ULES00193 = true
|
||||
ULJM05029 = true
|
||||
ULJM05224 = true
|
||||
NPJH50214 = true
|
||||
|
||||
[AtracLoopHack]
|
||||
#Atrac looped incorrectly see #7601 #13773 #11586 #10139 #12083
|
||||
|
||||
|
||||
Reference in New Issue
Block a user