Fix fog and stencil buffer clearing. The latter fixes the sky in MotoGP.

This commit is contained in:
Henrik Rydgard 2013-01-14 20:43:18 +01:00
parent 7d1ddced9f
commit 7271e3fcd5
10 changed files with 120 additions and 46 deletions

View File

@ -249,7 +249,6 @@ void PSPSaveDialog::DisplaySaveDataInfo1()
char time[512];
char saveTitle[512];
char saveDetail[512];
_dbg_assert_msg_(HLE, sizeof(txt) > sizeof(SaveFileInfo), "Local buffer is too small.");
snprintf(title,512,"%s", param.GetFileInfo(currentSelectedSave).title);
snprintf(time,512,"%02d/%02d/%d %02d:%02d %lld KB"

View File

@ -61,6 +61,12 @@ const int flushBeforeCommandList[] = {
GE_CMD_TEXTUREMAPENABLE,
GE_CMD_LIGHTINGENABLE,
GE_CMD_FOGENABLE,
GE_CMD_ALPHABLENDENABLE,
GE_CMD_ALPHATESTENABLE,
GE_CMD_ALPHATEST,
GE_CMD_COLORTESTENABLE,
GE_CMD_COLORTESTMASK,
GE_CMD_COLORREF,
GE_CMD_TEXSCALEU,GE_CMD_TEXSCALEV,
GE_CMD_TEXOFFSETU,GE_CMD_TEXOFFSETV,
GE_CMD_MINZ,GE_CMD_MAXZ,
@ -79,14 +85,24 @@ const int flushBeforeCommandList[] = {
GE_CMD_TEXSIZE4,GE_CMD_TEXSIZE5,GE_CMD_TEXSIZE6,GE_CMD_TEXSIZE7,
GE_CMD_ZBUFPTR,
GE_CMD_ZBUFWIDTH,
GE_CMD_AMBIENTCOLOR,
GE_CMD_AMBIENTALPHA,
GE_CMD_TEXOFFSETU,
GE_CMD_TEXOFFSETV,
GE_CMD_TEXSCALEU,
GE_CMD_TEXSCALEV,
GE_CMD_OFFSETY,
GE_CMD_OFFSETX,
GE_CMD_OFFSETY,
GE_CMD_LMODE,
GE_CMD_REVERSENORMAL,
GE_CMD_MATERIALUPDATE,
GE_CMD_MATERIALEMISSIVE,
GE_CMD_MATERIALAMBIENT,
GE_CMD_MATERIALDIFFUSE,
GE_CMD_MATERIALEMISSIVE,
GE_CMD_MATERIALSPECULAR,
GE_CMD_MATERIALALPHA,
GE_CMD_MATERIALSPECULARCOEF,
GE_CMD_AMBIENTCOLOR,
GE_CMD_AMBIENTALPHA,
GE_CMD_COLORMODEL,
GE_CMD_LIGHTTYPE0, GE_CMD_LIGHTTYPE1, GE_CMD_LIGHTTYPE2, GE_CMD_LIGHTTYPE3,
GE_CMD_LX0,GE_CMD_LY0,GE_CMD_LZ0,
@ -112,14 +128,10 @@ const int flushBeforeCommandList[] = {
GE_CMD_VIEWPORTZ1,GE_CMD_VIEWPORTZ2,
GE_CMD_LIGHTENABLE0,GE_CMD_LIGHTENABLE1,GE_CMD_LIGHTENABLE2,GE_CMD_LIGHTENABLE3,
GE_CMD_CULL,
GE_CMD_LMODE,
GE_CMD_REVERSENORMAL,
GE_CMD_PATCHDIVISION,
GE_CMD_MATERIALUPDATE,
GE_CMD_CLEARMODE,
GE_CMD_ALPHABLENDENABLE,
GE_CMD_ALPHATESTENABLE,
GE_CMD_ALPHATEST,
GE_CMD_TEXFUNC,
GE_CMD_TEXFILTER,
GE_CMD_TEXENVCOLOR,
@ -130,6 +142,7 @@ const int flushBeforeCommandList[] = {
GE_CMD_ZTESTENABLE,
GE_CMD_STENCILTESTENABLE,
GE_CMD_STENCILOP,
GE_CMD_STENCILTEST,
GE_CMD_ZTEST,
GE_CMD_FOG1,
GE_CMD_FOG2,
@ -680,6 +693,18 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
case GE_CMD_LIGHTINGENABLE:
break;
case GE_CMD_FOGCOLOR:
shaderManager_->DirtyUniform(DIRTY_FOGCOLOR);
break;
case GE_CMD_FOG1:
shaderManager_->DirtyUniform(DIRTY_FOGCOEF);
break;
case GE_CMD_FOG2:
shaderManager_->DirtyUniform(DIRTY_FOGCOEF);
break;
case GE_CMD_FOGENABLE:
break;
@ -973,9 +998,11 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
break;
case GE_CMD_ALPHATESTENABLE:
case GE_CMD_COLORTESTENABLE:
// This is done in the shader.
break;
case GE_CMD_COLORREF:
case GE_CMD_ALPHATEST:
shaderManager_->DirtyUniform(DIRTY_ALPHACOLORREF);
break;

View File

@ -73,23 +73,23 @@ void GenerateFragmentShader(char *buffer)
int lmode = gstate.lmode & 1;
int doTexture = (gstate.textureMapEnable & 1) && !(gstate.clearmode & 1);
bool enableFog = gstate.isFogEnabled() && !gstate.isModeThrough() && !gstate.isModeClear();
if (doTexture)
WRITE(p, "uniform sampler2D tex;\n");
if ((gstate.alphaTestEnable & 1) || (gstate.colorTestEnable & 1))
if ((gstate.alphaTestEnable & 1) || (gstate.colorTestEnable & 1)) {
WRITE(p, "uniform vec4 u_alphacolorref;\n");
if (gstate.fogEnable & 1) {
WRITE(p, "uniform vec3 u_fogcolor;\n");
WRITE(p, "uniform vec2 u_fogcoef;\n");
}
WRITE(p, "uniform vec3 u_texenv;\n");
WRITE(p, "varying vec4 v_color0;\n");
if (lmode)
WRITE(p, "varying vec3 v_color1;\n");
if (enableFog) {
WRITE(p, "uniform vec3 u_fogcolor;\n");
WRITE(p, "varying float v_fogdepth;\n");
}
if (doTexture)
WRITE(p, "varying vec2 v_texcoord;\n");
if (gstate.isFogEnabled())
WRITE(p, "varying float v_depth;\n");
WRITE(p, "void main() {\n");
WRITE(p, " vec4 v;\n");
@ -107,17 +107,17 @@ void GenerateFragmentShader(char *buffer)
WRITE(p, " vec4 s = vec4(v_color1, 0.0);");
secondary = " + s";
} else {
WRITE(p, " vec4 s = vec4(0.0, 0.0, 0.0, 0.0);\n");
WRITE(p, " vec4 s = vec4(0.0, 0.0, 0.0, 0.0);\n");
secondary = "";
}
if (gstate.textureMapEnable & 1) {
WRITE(p, " vec4 t = texture2D(tex, v_texcoord);\n");
WRITE(p, " vec4 p = clamp(v_color0, 0.0, 1.0);\n");
WRITE(p, " vec4 t = texture2D(tex, v_texcoord);\n");
WRITE(p, " vec4 p = clamp(v_color0, 0.0, 1.0);\n");
} else {
// No texture mapping
WRITE(p, " vec4 t = vec4(1.0, 1.0, 1.0, 1.0);\n");
WRITE(p, " vec4 p = clamp(v_color0, 0.0, 1.0);\n");
WRITE(p, " vec4 t = vec4(1.0, 1.0, 1.0, 1.0);\n");
WRITE(p, " vec4 p = clamp(v_color0, 0.0, 1.0);\n");
}
if (gstate.texfunc & 0x100) { // texfmt == RGBA
@ -174,9 +174,9 @@ void GenerateFragmentShader(char *buffer)
WRITE(p, "if (!(v.rgb %s u_alphacolorref.rgb)) discard;", colorTestFuncs[colorTestFunc]);
}*/
if (gstate.isFogEnabled()) {
// Haven't figured out how to adjust the depth range yet.
// WRITE(p, " v = mix(v, u_fogcolor, u_fogcoef.x + u_fogcoef.y * v_depth;\n");
if (enableFog) {
WRITE(p, " float fogCoef = clamp(v_fogdepth, 0.0, 1.0);\n");
WRITE(p, " v = mix(vec4(u_fogcolor, v.a), v, fogCoef);\n");
// WRITE(p, " v.x = v_depth;\n");
}
}

View File

@ -138,19 +138,33 @@ LinkedShader::~LinkedShader() {
// Utility
static void SetColorUniform3(int uniform, u32 color)
{
const float col[3] = { ((color & 0xFF0000) >> 16) / 255.0f, ((color & 0xFF00) >> 8) / 255.0f, ((color & 0xFF)) / 255.0f};
const float col[3] = {
((color & 0xFF)) / 255.0f,
((color & 0xFF00) >> 8) / 255.0f,
((color & 0xFF0000) >> 16) / 255.0f
};
glUniform3fv(uniform, 1, col);
}
static void SetColorUniform3Alpha(int uniform, u32 color, u8 alpha)
{
const float col[4] = { ((color & 0xFF0000) >> 16) / 255.0f, ((color & 0xFF00) >> 8) / 255.0f, ((color & 0xFF)) / 255.0f, alpha/255.0f};
const float col[4] = {
((color & 0xFF)) / 255.0f,
((color & 0xFF00) >> 8) / 255.0f,
((color & 0xFF0000) >> 16) / 255.0f,
alpha/255.0f
};
glUniform4fv(uniform, 1, col);
}
static void SetColorUniform3ExtraFloat(int uniform, u32 color, float extra)
{
const float col[4] = { ((color & 0xFF0000) >> 16) / 255.0f, ((color & 0xFF00) >> 8) / 255.0f, ((color & 0xFF)) / 255.0f, extra};
const float col[4] = {
((color & 0xFF)) / 255.0f,
((color & 0xFF00) >> 8) / 255.0f,
((color & 0xFF0000) >> 16) / 255.0f,
extra
};
glUniform4fv(uniform, 1, col);
}
@ -226,13 +240,16 @@ void LinkedShader::updateUniforms() {
SetColorUniform3(u_texenv, gstate.texenvcolor);
}
if (u_alphacolorref != -1 && (dirtyUniforms & DIRTY_ALPHACOLORREF)) {
glUniform4f(u_alphacolorref, 0.0f, 0.0f, 0.0f, ((float)((gstate.alphatest >> 8) & 0xFF)) / 255.0f);
SetColorUniform3Alpha(u_alphacolorref, gstate.colortest, (gstate.alphatest >> 8) & 0xFF);
}
if (u_fogcolor != -1 && (dirtyUniforms & DIRTY_FOGCOLOR)) {
SetColorUniform3(u_fogcolor, gstate.fogcolor);
}
if (u_fogcoef != -1 && (dirtyUniforms & DIRTY_FOGCOEF)) {
const float fogcoef[2] = { getFloat24(gstate.fog1), getFloat24(gstate.fog2) };
const float fogcoef[2] = {
getFloat24(gstate.fog1),
getFloat24(gstate.fog2),
};
glUniform2fv(u_fogcoef, 1, fogcoef);
}

View File

@ -183,6 +183,10 @@ void ApplyDrawState(int prim) {
glstate.stencilOp.set(stencilOps[gstate.stencilop & 0x7], // stencil fail
stencilOps[(gstate.stencilop >> 8) & 0x7], // depth fail
stencilOps[(gstate.stencilop >> 16) & 0x7]);
} else if (gstate.isModeClear()) {
glstate.stencilTest.enable();
glstate.stencilOp.set(GL_REPLACE, GL_REPLACE, GL_REPLACE);
glstate.stencilFunc.set(GL_ALWAYS, 0, 0xFF);
} else {
glstate.stencilTest.disable();
}

View File

@ -332,7 +332,7 @@ static void SwapUVs(TransformedVertex &a, TransformedVertex &b) {
// Used by Star Soldier and Ys vs Sora.
static void RotateUVs(TransformedVertex v[4]) {
if ((v[0].x > v[2].x && v[0].y < v[2].y) || (v[0].x < v[2].x && v[0].y > v[2].y)) {
if ((v[0].x > v[2].x && v[0].y < v[2].y) /*|| (v[0].x < v[2].x && v[0].y > v[2].y)*/) {
SwapUVs(v[1], v[3]);
}
}
@ -365,6 +365,8 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
#endif
Lighter lighter;
float fog_end = getFloat24(gstate.fog1);
float fog_slope = getFloat24(gstate.fog2);
VertexReader reader(decoded, decVtxFormat);
for (int index = 0; index < maxIndex; index++) {
@ -374,6 +376,7 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
float c0[4] = {1, 1, 1, 1};
float c1[4] = {0, 0, 0, 0};
float uv[2] = {0, 0};
float fogCoef = 1.0f;
if (throughmode) {
// Do not touch the coordinates or the colors. No lighting.
@ -393,6 +396,7 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
if (reader.hasUV()) {
reader.ReadUV(uv);
}
fogCoef = 1.0f;
// Scale UV?
} else {
// We do software T&L for now
@ -533,10 +537,12 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
// Transform the coord by the view matrix.
Vec3ByMatrix43(v, out, gstate.viewMatrix);
fogCoef = (v[2] + fog_end) * fog_slope;
}
// TODO: Write to a flexible buffer, we don't always need all four components.
memcpy(&transformed[index].x, v, 3 * sizeof(float));
transformed[index].fog = fogCoef;
memcpy(&transformed[index].u, uv, 2 * sizeof(float));
memcpy(&transformed[index].color0, c0, 4 * sizeof(float));
memcpy(&transformed[index].color1, c1, 3 * sizeof(float));
@ -622,10 +628,10 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
glBufferData(GL_ARRAY_BUFFER, vertexSize * numTrans, drawBuffer, GL_DYNAMIC_DRAW);
drawBuffer = 0; // so that the calls use offsets instead.
}
glVertexAttribPointer(program->a_position, 3, GL_FLOAT, GL_FALSE, vertexSize, drawBuffer);
if (program->a_texcoord != -1) glVertexAttribPointer(program->a_texcoord, 2, GL_FLOAT, GL_FALSE, vertexSize, ((uint8_t*)drawBuffer) + 3 * 4);
if (program->a_color0 != -1) glVertexAttribPointer(program->a_color0, 4, GL_FLOAT, GL_FALSE, vertexSize, ((uint8_t*)drawBuffer) + 5 * 4);
if (program->a_color1 != -1) glVertexAttribPointer(program->a_color1, 3, GL_FLOAT, GL_FALSE, vertexSize, ((uint8_t*)drawBuffer) + 9 * 4);
glVertexAttribPointer(program->a_position, 4, GL_FLOAT, GL_FALSE, vertexSize, drawBuffer);
if (program->a_texcoord != -1) glVertexAttribPointer(program->a_texcoord, 2, GL_FLOAT, GL_FALSE, vertexSize, ((uint8_t*)drawBuffer) + 4 * 4);
if (program->a_color0 != -1) glVertexAttribPointer(program->a_color0, 4, GL_FLOAT, GL_FALSE, vertexSize, ((uint8_t*)drawBuffer) + 6 * 4);
if (program->a_color1 != -1) glVertexAttribPointer(program->a_color1, 3, GL_FLOAT, GL_FALSE, vertexSize, ((uint8_t*)drawBuffer) + 10 * 4);
if (drawIndexed) {
if (useVBO) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_[curVbo_]);

View File

@ -98,9 +98,9 @@ struct Color4 {
a+=c.a;
}
void GetFromRGB(u32 col) {
r = ((col>>16) & 0xff)/255.0f;
b = ((col>>16) & 0xff)/255.0f;
g = ((col>>8) & 0xff)/255.0f;
b = ((col>>0) & 0xff)/255.0f;
r = ((col>>0) & 0xff)/255.0f;
}
void GetFromA(u32 col) {
a = (col&0xff)/255.0f;

View File

@ -53,7 +53,7 @@ struct DecVtxFormat {
// This struct too.
struct TransformedVertex
{
float x, y, z; // in case of morph, preblend during decode
float x, y, z, fog; // in case of morph, preblend during decode
float u; float v; // scaled by uscale, vscale, if there
float color0[4]; // prelit
float color1[3]; // prelit

View File

@ -135,6 +135,7 @@ void GenerateVertexShader(int prim, char *buffer) {
bool hwXForm = CanUseHardwareTransform(prim);
bool hasColor = (gstate.vertType & GE_VTYPE_COL_MASK) != 0 || !hwXForm;
bool hasNormal = (gstate.vertType & GE_VTYPE_NRM_MASK) != 0 && hwXForm;
bool enableFog = gstate.isFogEnabled() && !gstate.isModeThrough() && !gstate.isModeClear();
DoLightComputation doLight[4] = {LIGHT_OFF, LIGHT_OFF, LIGHT_OFF, LIGHT_OFF};
if (hwXForm) {
@ -154,7 +155,11 @@ void GenerateVertexShader(int prim, char *buffer) {
WRITE(p, "%s", boneWeightAttrDecl[gstate.getNumBoneWeights() - 1]);
}
WRITE(p, "attribute vec3 a_position;\n");
if (hwXForm)
WRITE(p, "attribute vec3 a_position;\n");
else
WRITE(p, "attribute vec4 a_position;\n"); // need to pass the fog coord in w
if (doTexture) WRITE(p, "attribute vec2 a_texcoord;\n");
if (hasColor) {
WRITE(p, "attribute vec4 a_color0;\n");
@ -175,6 +180,10 @@ void GenerateVertexShader(int prim, char *buffer) {
if (hwXForm || !hasColor)
WRITE(p, "uniform vec4 u_matambientalpha;\n"); // matambient + matalpha
if (enableFog) {
WRITE(p, "uniform vec2 u_fogcoef;\n");
}
if (hwXForm) {
// When transforming by hardware, we need a great deal more uniforms...
WRITE(p, "uniform mat4 u_world;\n");
@ -216,7 +225,8 @@ void GenerateVertexShader(int prim, char *buffer) {
WRITE(p, "varying vec4 v_color0;\n");
if (lmode) WRITE(p, "varying vec3 v_color1;\n");
if (doTexture) WRITE(p, "varying vec2 v_texcoord;\n");
if (gstate.isFogEnabled()) WRITE(p, "varying float v_depth;\n");
if (enableFog) WRITE(p, "varying float v_fogdepth;\n");
WRITE(p, "void main() {\n");
if (!hwXForm) {
@ -232,16 +242,19 @@ void GenerateVertexShader(int prim, char *buffer) {
if (lmode)
WRITE(p, " v_color1 = vec3(0.0, 0.0, 0.0);\n");
}
if (enableFog) {
WRITE(p, " v_fogdepth = a_position.w;\n");
}
if (gstate.isModeThrough()) {
WRITE(p, " gl_Position = u_proj_through * vec4(a_position, 1.0);\n");
WRITE(p, " gl_Position = u_proj_through * vec4(a_position.xyz, 1.0);\n");
} else {
WRITE(p, " gl_Position = u_proj * vec4(a_position, 1.0);\n");
WRITE(p, " gl_Position = u_proj * vec4(a_position.xyz, 1.0);\n");
}
} else {
// Step 1: World Transform / Skinning
if ((gstate.vertType & GE_VTYPE_WEIGHT_MASK) == GE_VTYPE_WEIGHT_NONE) {
// No skinning, just standard T&L.
WRITE(p, " vec3 worldpos = (u_world * vec4(a_position, 1.0)).xyz;\n");
WRITE(p, " vec3 worldpos = (u_world * vec4(a_position.xyz, 1.0)).xyz;\n");
if (hasNormal)
WRITE(p, " vec3 worldnormal = (u_world * vec4(a_normal, 0.0)).xyz;\n");
} else {
@ -254,7 +267,7 @@ void GenerateVertexShader(int prim, char *buffer) {
// workaround for "cant do .x of scalar" issue
if (numWeights == 1 && i == 0) weightAttr = "a_weight0123";
if (numWeights == 5 && i == 4) weightAttr = "a_weight4567";
WRITE(p, " worldpos += %s * (u_bone%i * vec4(a_position, 1.0)).xyz;\n", weightAttr, i);
WRITE(p, " worldpos += %s * (u_bone%i * vec4(a_position.xyz, 1.0)).xyz;\n", weightAttr, i);
if (hasNormal)
WRITE(p, " worldnormal += %s * (u_bone%i * vec4(a_normal, 0.0)).xyz;\n", weightAttr, i);
}
@ -266,6 +279,8 @@ void GenerateVertexShader(int prim, char *buffer) {
if (hasNormal)
WRITE(p, " worldnormal = normalize(worldnormal);\n");
WRITE(p, " vec4 viewPos = u_view * vec4(worldpos, 1.0);\n");
// Step 2: Color/Lighting
if (hasColor) {
WRITE(p, " vec3 unlitColor = a_color0.rgb;\n");
@ -331,7 +346,7 @@ void GenerateVertexShader(int prim, char *buffer) {
if (lmode) {
WRITE(p, " v_color1 = clamp(lightSum1, 0.0, 1.0);\n");
} else {
WRITE(p, " v_color0 += vec4(lightSum1, 0.0);\n");
WRITE(p, " v_color0 = clamp(v_color0 + vec4(lightSum1, 0.0), 0.0, 1.0);\n");
}
} else {
// Lighting doesn't affect color.
@ -354,7 +369,7 @@ void GenerateVertexShader(int prim, char *buffer) {
case 1: // Projection mapping.
switch (gstate.getUVProjMode()) {
case 0: // Use model space XYZ as source
WRITE(p, " vec3 temp_tc = a_position;\n");
WRITE(p, " vec3 temp_tc = a_position.xyz;\n");
break;
case 1: // Use unscaled UV as source
WRITE(p, " vec3 temp_tc = vec3(a_texcoord.xy, 0.0);\n");
@ -379,11 +394,14 @@ void GenerateVertexShader(int prim, char *buffer) {
break;
}
}
// Compute fogdepth
if (enableFog)
WRITE(p, " v_fogdepth = (viewPos.z + u_fogcoef.x) * u_fogcoef.y;\n");
// Step 4: Final view and projection transforms.
WRITE(p, " gl_Position = u_proj * (u_view * vec4(worldpos, 1.0));\n");
WRITE(p, " gl_Position = u_proj * viewPos;\n");
}
if (gstate.isFogEnabled())
WRITE(p, " v_depth = gl_Position.z;\n");
WRITE(p, "}\n");
}

View File

@ -220,6 +220,9 @@ enum GECommand
GE_CMD_SCISSOR2=0xD5,
GE_CMD_MINZ=0xD6,
GE_CMD_MAXZ=0xD7,
GE_CMD_COLORTEST=0xD8,
GE_CMD_COLORREF=0xD9,
GE_CMD_COLORTESTMASK=0xDA,
GE_CMD_ALPHATEST=0xDB,
GE_CMD_STENCILTEST=0xDC,
GE_CMD_STENCILOP=0xDD,