diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c index 74ee67c4ad..f1a2956ca0 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c @@ -270,6 +270,12 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz mstring_append(body, "oD1 = vec4(0.0, 0.0, 0.0, specular.a);\n"); + if (state->local_eye) { + mstring_append(body, + "vec3 VPeye = normalize(eyePosition.xyz / eyePosition.w - tPosition.xyz / tPosition.w);\n" + ); + } + for (i = 0; i < NV2A_MAX_LIGHTS; i++) { if (state->light[i] == LIGHT_OFF) { continue; @@ -285,18 +291,20 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz "%svec3 lightLocalAttenuation%d;\n", u, i, u, i); mstring_append_fmt(body, - " vec3 VP = lightLocalPosition%d - tPosition.xyz/tPosition.w;\n" + " vec3 tPos = tPosition.xyz/tPosition.w;\n" + " vec3 VP = lightLocalPosition%d - tPos;\n" " float d = length(VP);\n" " if (d <= lightLocalRange(%d)) {\n" /* FIXME: Double check that range is inclusive */ " VP = normalize(VP);\n" " float attenuation = 1.0 / (lightLocalAttenuation%d.x\n" " + lightLocalAttenuation%d.y * d\n" " + lightLocalAttenuation%d.z * d * d);\n" - " vec3 halfVector = normalize(VP + eyePosition.xyz / eyePosition.w);\n" /* FIXME: Not sure if eyePosition is correct */ + " vec3 halfVector = normalize(VP + %s);\n" " float nDotVP = max(0.0, dot(tNormal, VP));\n" " float nDotHV = max(0.0, dot(tNormal, halfVector));\n", - i, i, i, i, i); - + i, i, i, i, i, + state->local_eye ? "VPeye" : "vec3(0.0, 0.0, 0.0)" + ); } switch(state->light[i]) { @@ -311,10 +319,19 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz mstring_append_fmt(body, " {\n" " float attenuation = 1.0;\n" - " float nDotVP = max(0.0, dot(tNormal, normalize(lightInfiniteDirection%d)));\n" - " float nDotHV = max(0.0, dot(tNormal, lightInfiniteHalfVector%d));\n", - i, i); - + " vec3 lightDirection = normalize(lightInfiniteDirection%d);\n" + " float nDotVP = max(0.0, dot(tNormal, lightDirection));\n", + i); + if (state->local_eye) { + mstring_append(body, + " float nDotHV = max(0.0, dot(tNormal, normalize(lightDirection + VPeye)));\n" + ); + } else { + mstring_append_fmt(body, + " float nDotHV = max(0.0, dot(tNormal, lightInfiniteHalfVector%d));\n", + i + ); + } break; case LIGHT_LOCAL: /* Everything done already */ @@ -413,7 +430,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz } if (state->ignore_specular_alpha) { mstring_append(body, - " oD1.w = 1.0;\n" + " oD1.a = 1.0;\n" " oB1.a = 1.0;\n" ); } diff --git a/hw/xbox/nv2a/pgraph/shaders.c b/hw/xbox/nv2a/pgraph/shaders.c index 79f66026d9..cddbf450f0 100644 --- a/hw/xbox/nv2a/pgraph/shaders.c +++ b/hw/xbox/nv2a/pgraph/shaders.c @@ -96,6 +96,8 @@ ShaderState pgraph_get_shader_state(PGRAPHState *pg) pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), NV_PGRAPH_CSV0_C_SEPARATE_SPECULAR); state.ignore_specular_alpha = !GET_MASK( pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), NV_PGRAPH_CSV0_C_ALPHA_FROM_MATERIAL_SPECULAR); + state.local_eye = GET_MASK( + pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), NV_PGRAPH_CSV0_C_LOCALEYE); state.specular_power = pg->specular_power; state.specular_power_back = pg->specular_power_back; diff --git a/hw/xbox/nv2a/pgraph/shaders.h b/hw/xbox/nv2a/pgraph/shaders.h index b384b679bf..4cc07e3a9d 100644 --- a/hw/xbox/nv2a/pgraph/shaders.h +++ b/hw/xbox/nv2a/pgraph/shaders.h @@ -81,6 +81,7 @@ typedef struct ShaderState { bool separate_specular; bool ignore_specular_alpha; + bool local_eye; float specular_power; float specular_power_back;