Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Darkstalkers Chronicle: Add specializations and speedhacks to get it kinda playable #12443

Merged
merged 18 commits into from
Oct 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ build.ios
versionname.txt
versioncode.txt
build*/
android/.cxx

# Temp file used by jenkins windows build (TODO: remove)
desc.txt
Expand Down
2 changes: 2 additions & 0 deletions Core/Compatibility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) {
CheckSetting(iniFile, gameID, "JitInvalidationHack", &flags_.JitInvalidationHack);
CheckSetting(iniFile, gameID, "HideISOFiles", &flags_.HideISOFiles);
CheckSetting(iniFile, gameID, "MoreAccurateVMMUL", &flags_.MoreAccurateVMMUL);
CheckSetting(iniFile, gameID, "ForceSoftwareRenderer", &flags_.ForceSoftwareRenderer);
CheckSetting(iniFile, gameID, "DarkStalkersPresentHack", &flags_.DarkStalkersPresentHack);
}

void Compatibility::CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag) {
Expand Down
2 changes: 2 additions & 0 deletions Core/Compatibility.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ struct CompatFlags {
bool JitInvalidationHack;
bool HideISOFiles;
bool MoreAccurateVMMUL;
bool ForceSoftwareRenderer;
bool DarkStalkersPresentHack;
};

class IniFile;
Expand Down
2 changes: 1 addition & 1 deletion Core/HLE/sceUtility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ enum UtilityDialogType {

// Only a single dialog is allowed at a time.
static UtilityDialogType currentDialogType;
static bool currentDialogActive;
bool currentDialogActive;
static PSPSaveDialog saveDialog;
static PSPMsgDialog msgDialog;
static PSPOskDialog oskDialog;
Expand Down
5 changes: 5 additions & 0 deletions Core/System.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,11 @@ bool PSP_InitStart(const CoreParameter &coreParam, std::string *error_string) {

CPU_Init();

// Compat flags get loaded in CPU_Init (which is a bit of a misnomer) so we check for SW renderer here.
if (g_Config.bSoftwareRendering || PSP_CoreParameter().compat.flags().ForceSoftwareRenderer) {
coreParameter.gpuCore = GPUCORE_SOFTWARE;
}

*error_string = coreParameter.errorString;
bool success = coreParameter.fileToStart != "";
if (!success) {
Expand Down
1 change: 1 addition & 0 deletions GPU/GPU.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<ForcedIncludeFiles>Common/DbgNew.h</ForcedIncludeFiles>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
Expand Down
4 changes: 4 additions & 0 deletions GPU/Math3D.h
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,10 @@ class Vec4
*this = *this / f;
}

bool operator ==(const Vec4 &other) const {
return x == other.x && y == other.y && z == other.z && w == other.w;
}

T Length2() const
{
return x*x + y*y + z*z + w*w;
Expand Down
89 changes: 66 additions & 23 deletions GPU/Software/Clipper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,20 @@

#include <algorithm>

#include "Core/System.h"

#include "GPU/GPUState.h"

#include "GPU/Software/Clipper.h"
#include "GPU/Software/Rasterizer.h"

#include "profiler/profiler.h"


extern bool g_DarkStalkerStretch;
// For Darkstalkers hack. Ugh.
extern bool currentDialogActive;

namespace Clipper {

enum {
Expand All @@ -49,39 +56,36 @@ static inline int CalcClipMask(const ClipCoords& v)
return mask;
}

#define AddInterpolatedVertex(t, out, in, numVertices) \
{ \
Vertices[numVertices]->Lerp(t, *Vertices[out], *Vertices[in]); \
numVertices++; \
inline bool different_signs(float x, float y) {
return ((x <= 0 && y > 0) || (x > 0 && y <= 0));
}

#define DIFFERENT_SIGNS(x,y) ((x <= 0 && y > 0) || (x > 0 && y <= 0))

#define CLIP_DOTPROD(I, A, B, C, D) \
(Vertices[I]->clippos.x * A + Vertices[I]->clippos.y * B + Vertices[I]->clippos.z * C + Vertices[I]->clippos.w * D)
inline float clip_dotprod(const VertexData &vert, float A, float B, float C, float D) {
return (vert.clippos.x * A + vert.clippos.y * B + vert.clippos.z * C + vert.clippos.w * D);
}

#define POLY_CLIP( PLANE_BIT, A, B, C, D ) \
{ \
if (mask & PLANE_BIT) { \
int idxPrev = inlist[0]; \
float dpPrev = CLIP_DOTPROD(idxPrev, A, B, C, D ); \
float dpPrev = clip_dotprod(*Vertices[idxPrev], A, B, C, D );\
int outcount = 0; \
\
inlist[n] = inlist[0]; \
for (int j = 1; j <= n; j++) { \
int idx = inlist[j]; \
float dp = CLIP_DOTPROD(idx, A, B, C, D ); \
float dp = clip_dotprod(*Vertices[idx], A, B, C, D ); \
if (dpPrev >= 0) { \
outlist[outcount++] = idxPrev; \
} \
\
if (DIFFERENT_SIGNS(dp, dpPrev)) { \
if (different_signs(dp, dpPrev)) { \
if (dp < 0) { \
float t = dp / (dp - dpPrev); \
AddInterpolatedVertex(t, idx, idxPrev, numVertices); \
Vertices[numVertices++]->Lerp(t, *Vertices[idx], *Vertices[idxPrev]); \
} else { \
float t = dpPrev / (dpPrev - dp); \
AddInterpolatedVertex(t, idxPrev, idx, numVertices); \
Vertices[numVertices++]->Lerp(t, *Vertices[idxPrev], *Vertices[idx]); \
} \
outlist[outcount++] = numVertices - 1; \
} \
Expand All @@ -104,25 +108,23 @@ static inline int CalcClipMask(const ClipCoords& v)

#define CLIP_LINE(PLANE_BIT, A, B, C, D) \
{ \
if (mask & PLANE_BIT) { \
float dp0 = CLIP_DOTPROD(0, A, B, C, D ); \
float dp1 = CLIP_DOTPROD(1, A, B, C, D ); \
int i = 0; \
if (mask & PLANE_BIT) { \
float dp0 = clip_dotprod(*Vertices[0], A, B, C, D ); \
float dp1 = clip_dotprod(*Vertices[1], A, B, C, D ); \
int numVertices = 0; \
\
if (mask0 & PLANE_BIT) { \
if (dp0 < 0) { \
float t = dp1 / (dp1 - dp0); \
i = 0; \
AddInterpolatedVertex(t, 1, 0, i); \
Vertices[0]->Lerp(t, *Vertices[1], *Vertices[0]); \
} \
} \
dp0 = CLIP_DOTPROD(0, A, B, C, D ); \
dp0 = clip_dotprod(*Vertices[0], A, B, C, D ); \
\
if (mask1 & PLANE_BIT) { \
if (dp1 < 0) { \
float t = dp1 / (dp1- dp0); \
i = 1; \
AddInterpolatedVertex(t, 1, 0, i); \
Vertices[1]->Lerp(t, *Vertices[1], *Vertices[0]); \
} \
} \
} \
Expand All @@ -139,8 +141,11 @@ static void RotateUVThrough(const VertexData &tl, const VertexData &br, VertexDa
}
}

bool needsClear = false;

void ProcessRect(const VertexData& v0, const VertexData& v1)
{
g_DarkStalkerStretch = false;
if (!gstate.isModeThrough()) {
VertexData buf[4];
buf[0].clippos = ClipCoords(v0.clippos.x, v0.clippos.y, v1.clippos.z, v1.clippos.w);
Expand Down Expand Up @@ -182,6 +187,44 @@ void ProcessRect(const VertexData& v0, const VertexData& v1)
ProcessTriangle(*topleft, *bottomleft, *bottomright, buf[3]);
} else {
// through mode handling

// Check for 1:1 texture mapping. In that case we can call DrawSprite.
int xdiff = v1.screenpos.x - v0.screenpos.x;
int ydiff = v1.screenpos.y - v0.screenpos.y;
int udiff = (v1.texturecoords.x - v0.texturecoords.x) * 16.0f;
int vdiff = (v1.texturecoords.y - v0.texturecoords.y) * 16.0f;
bool coord_check =
(xdiff == udiff || xdiff == -udiff) &&
(ydiff == vdiff || ydiff == -vdiff);
bool state_check = !gstate.isModeClear(); // TODO: Add support for clear modes in Rasterizer::DrawSprite.
if ((coord_check || !gstate.isTextureMapEnabled()) && state_check) {
Rasterizer::DrawSprite(v0, v1);
return;
}

// Eliminate the stretch blit in DarkStalkers.
// We compensate for that when blitting the framebuffer in SoftGpu.cpp.
if (PSP_CoreParameter().compat.flags().DarkStalkersPresentHack && v0.texturecoords.x == 64.0f && v0.texturecoords.y == 16.0f && v1.texturecoords.x == 448.0f && v1.texturecoords.y == 240.0f) {
if (v0.screenpos.x == 0x7100 && v0.screenpos.y == 0x7780 && v1.screenpos.x == 0x8f00 && v1.screenpos.y == 0x8880) {
// Also check for save/load dialog.
if (!currentDialogActive) {
g_DarkStalkerStretch = true;
if (needsClear) {
needsClear = false;
// Afterwards, we also need to clear the actual destination. Can do a fast rectfill.
gstate.textureMapEnable &= ~1;
VertexData newV0 = v0;
newV0.color0 = Vec4<int>(0, 0, 0, 255);
Rasterizer::DrawSprite(newV0, v1);
gstate.textureMapEnable |= 1;
}
return;
} else {
needsClear = true;
}
} // else, handle the Capcom screen stretch, or the non-wide stretch? Or let's just not bother.
}

VertexData buf[4];
buf[0].screenpos = ScreenCoords(v0.screenpos.x, v0.screenpos.y, v1.screenpos.z);
buf[0].texturecoords = v0.texturecoords;
Expand All @@ -196,7 +239,7 @@ void ProcessRect(const VertexData& v0, const VertexData& v1)

// Color and depth values of second vertex are used for the whole rectangle
buf[0].color0 = buf[1].color0 = buf[2].color0 = buf[3].color0;
buf[0].color1 = buf[1].color1 = buf[2].color1 = buf[3].color1;
buf[0].color1 = buf[1].color1 = buf[2].color1 = buf[3].color1; // is color1 ever used in through mode?
buf[0].clippos.w = buf[1].clippos.w = buf[2].clippos.w = buf[3].clippos.w = 1.0f;
buf[0].fogdepth = buf[1].fogdepth = buf[2].fogdepth = buf[3].fogdepth = 1.0f;

Expand Down
Loading