mirror of https://github.com/xemu-project/xemu.git
Merge branch 'feat_spec_params' into work
This commit is contained in:
commit
49699eb69b
|
@ -1056,6 +1056,7 @@
|
|||
# define NV097_SET_TEXGEN_VIEW_MODEL_LOCAL_VIEWER 0
|
||||
# define NV097_SET_TEXGEN_VIEW_MODEL_INFINITE_VIEWER 1
|
||||
# define NV097_SET_FOG_PLANE 0x000009D0
|
||||
# define NV097_SET_SPECULAR_PARAMS 0x000009E0
|
||||
# define NV097_SET_SCENE_AMBIENT_COLOR 0x00000A10
|
||||
# define NV097_SET_VIEWPORT_OFFSET 0x00000A20
|
||||
# define NV097_SET_POINT_PARAMS 0x00000A30
|
||||
|
@ -1259,6 +1260,7 @@
|
|||
# define NV097_SET_CLEAR_RECT_HORIZONTAL 0x00001D98
|
||||
# define NV097_SET_CLEAR_RECT_VERTICAL 0x00001D9C
|
||||
# define NV097_SET_SPECULAR_FOG_FACTOR 0x00001E20
|
||||
# define NV097_SET_SPECULAR_PARAMS_BACK 0x00001E28
|
||||
# define NV097_SET_COMBINER_COLOR_OCW 0x00001E40
|
||||
# define NV097_SET_COMBINER_CONTROL 0x00001E60
|
||||
# define NV097_SET_SHADOW_ZSLOPE_THRESHOLD 0x00001E68
|
||||
|
|
|
@ -230,8 +230,12 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
|
|||
}
|
||||
|
||||
/* Lighting */
|
||||
if (state->lighting) {
|
||||
|
||||
if (!state->lighting) {
|
||||
mstring_append(body, " oD0 = diffuse;\n");
|
||||
mstring_append(body, " oD1 = specular;\n");
|
||||
mstring_append(body, " oB0 = backDiffuse;\n");
|
||||
mstring_append(body, " oB1 = backSpecular;\n");
|
||||
} else {
|
||||
//FIXME: Do 2 passes if we want 2 sided-lighting?
|
||||
|
||||
static char alpha_source_diffuse[] = "diffuse.a";
|
||||
|
@ -264,17 +268,17 @@ 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;
|
||||
}
|
||||
|
||||
/* FIXME: It seems that we only have to handle the surface colors if
|
||||
* they are not part of the material [= vertex colors].
|
||||
* If they are material the cpu will premultiply light
|
||||
* colors
|
||||
*/
|
||||
|
||||
mstring_append_fmt(body, "/* Light %d */ {\n", i);
|
||||
|
||||
if (state->light[i] == LIGHT_LOCAL
|
||||
|
@ -285,18 +289,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"
|
||||
//FIXME: if (d > lightLocalRange) { .. don't process this light .. } /* inclusive?! */ - what about directional lights?
|
||||
" 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 */
|
||||
" float nDotVP = max(0.0, dot(tNormal, VP));\n"
|
||||
" float nDotHV = max(0.0, dot(tNormal, halfVector));\n",
|
||||
i, i, i, i);
|
||||
|
||||
" 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 + %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,
|
||||
state->local_eye ? "VPeye" : "vec3(0.0, 0.0, -1.0)"
|
||||
);
|
||||
}
|
||||
|
||||
switch(state->light[i]) {
|
||||
|
@ -309,15 +315,21 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
|
|||
"%svec3 lightInfiniteDirection%d;\n",
|
||||
u, i, u, i);
|
||||
mstring_append_fmt(body,
|
||||
" float attenuation = 1.0;\n"
|
||||
" float nDotVP = max(0.0, dot(tNormal, normalize(vec3(lightInfiniteDirection%d))));\n"
|
||||
" float nDotHV = max(0.0, dot(tNormal, vec3(lightInfiniteHalfVector%d)));\n",
|
||||
i, i);
|
||||
|
||||
/* FIXME: Do specular */
|
||||
|
||||
/* FIXME: tBackDiffuse */
|
||||
|
||||
" {\n"
|
||||
" float attenuation = 1.0;\n"
|
||||
" 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 */
|
||||
|
@ -325,18 +337,18 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
|
|||
case LIGHT_SPOT:
|
||||
/* https://docs.microsoft.com/en-us/windows/win32/direct3d9/attenuation-and-spotlight-factor#spotlight-factor */
|
||||
mstring_append_fmt(body,
|
||||
" vec4 spotDir = lightSpotDirection(%d);\n"
|
||||
" float invScale = 1/length(spotDir.xyz);\n"
|
||||
" float cosHalfPhi = -invScale*spotDir.w;\n"
|
||||
" float cosHalfTheta = invScale + cosHalfPhi;\n"
|
||||
" float spotDirDotVP = dot(spotDir.xyz, VP);\n"
|
||||
" float rho = invScale*spotDirDotVP;\n"
|
||||
" if (rho > cosHalfTheta) {\n"
|
||||
" } else if (rho <= cosHalfPhi) {\n"
|
||||
" attenuation = 0.0;\n"
|
||||
" } else {\n"
|
||||
" attenuation *= spotDirDotVP + spotDir.w;\n" /* FIXME: lightSpotFalloff */
|
||||
" }\n",
|
||||
" vec4 spotDir = lightSpotDirection(%d);\n"
|
||||
" float invScale = 1/length(spotDir.xyz);\n"
|
||||
" float cosHalfPhi = -invScale*spotDir.w;\n"
|
||||
" float cosHalfTheta = invScale + cosHalfPhi;\n"
|
||||
" float spotDirDotVP = dot(spotDir.xyz, VP);\n"
|
||||
" float rho = invScale*spotDirDotVP;\n"
|
||||
" if (rho > cosHalfTheta) {\n"
|
||||
" } else if (rho <= cosHalfPhi) {\n"
|
||||
" attenuation = 0.0;\n"
|
||||
" } else {\n"
|
||||
" attenuation *= spotDirDotVP + spotDir.w;\n" /* FIXME: lightSpotFalloff */
|
||||
" }\n",
|
||||
i);
|
||||
break;
|
||||
default:
|
||||
|
@ -345,59 +357,75 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
|
|||
}
|
||||
|
||||
mstring_append_fmt(body,
|
||||
" float pf;\n"
|
||||
" if (nDotVP == 0.0) {\n"
|
||||
" pf = 0.0;\n"
|
||||
" } else {\n"
|
||||
" pf = pow(nDotHV, /* specular(l, m, n, l1, m1, n1) */ 0.001);\n"
|
||||
" }\n"
|
||||
" vec3 lightAmbient = lightAmbientColor(%d) * attenuation;\n"
|
||||
" vec3 lightDiffuse = lightDiffuseColor(%d) * attenuation * nDotVP;\n"
|
||||
" vec3 lightSpecular = lightSpecularColor(%d) * pf;\n",
|
||||
i, i, i);
|
||||
" float pf;\n"
|
||||
" if (nDotVP == 0.0) {\n"
|
||||
" pf = 0.0;\n"
|
||||
" } else {\n"
|
||||
" pf = pow(nDotHV, %f);\n"
|
||||
" }\n"
|
||||
" vec3 lightAmbient = lightAmbientColor(%d) * attenuation;\n"
|
||||
" vec3 lightDiffuse = lightDiffuseColor(%d) * attenuation * nDotVP;\n"
|
||||
" vec3 lightSpecular = lightSpecularColor(%d) * attenuation * pf;\n"
|
||||
" lightSpecular *= vec3(lessThanEqual(lightSpecular.rgb, vec3(1.0)));\n",
|
||||
state->specular_power, i, i, i);
|
||||
|
||||
mstring_append(body,
|
||||
" oD0.xyz += lightAmbient;\n");
|
||||
" oD0.xyz += lightAmbient;\n");
|
||||
|
||||
switch (state->diffuse_src) {
|
||||
case MATERIAL_COLOR_SRC_MATERIAL:
|
||||
mstring_append(body,
|
||||
" oD0.xyz += lightDiffuse;\n");
|
||||
" oD0.xyz += lightDiffuse;\n");
|
||||
break;
|
||||
case MATERIAL_COLOR_SRC_DIFFUSE:
|
||||
mstring_append(body,
|
||||
" oD0.xyz += diffuse.xyz * lightDiffuse;\n");
|
||||
" oD0.xyz += diffuse.xyz * lightDiffuse;\n");
|
||||
break;
|
||||
case MATERIAL_COLOR_SRC_SPECULAR:
|
||||
mstring_append(body,
|
||||
" oD0.xyz += specular.xyz * lightDiffuse;\n");
|
||||
" oD0.xyz += specular.xyz * lightDiffuse;\n");
|
||||
break;
|
||||
}
|
||||
|
||||
mstring_append(body,
|
||||
" oD1.xyz += specular.xyz * lightSpecular;\n");
|
||||
switch (state->specular_src) {
|
||||
case MATERIAL_COLOR_SRC_MATERIAL:
|
||||
mstring_append(body,
|
||||
" oD1.xyz += lightSpecular;\n");
|
||||
break;
|
||||
case MATERIAL_COLOR_SRC_DIFFUSE:
|
||||
mstring_append(body,
|
||||
" oD1.xyz += diffuse.xyz * lightSpecular;\n");
|
||||
break;
|
||||
case MATERIAL_COLOR_SRC_SPECULAR:
|
||||
mstring_append(body,
|
||||
" oD1.xyz += specular.xyz * lightSpecular;\n");
|
||||
break;
|
||||
}
|
||||
|
||||
mstring_append(body, "}\n");
|
||||
mstring_append(body, " }\n"
|
||||
"}\n");
|
||||
}
|
||||
} else {
|
||||
mstring_append(body, " oD0 = diffuse;\n");
|
||||
mstring_append(body, " oD1 = specular;\n");
|
||||
}
|
||||
|
||||
mstring_append(body, " oB0 = backDiffuse;\n");
|
||||
mstring_append(body, " oB1 = backSpecular;\n");
|
||||
/* TODO: Implement two-sided lighting */
|
||||
mstring_append(body, " oB0 = backDiffuse;\n");
|
||||
mstring_append(body, " oB1 = backSpecular;\n");
|
||||
}
|
||||
|
||||
if (!state->specular_enable) {
|
||||
mstring_append(body, " oD1 = vec4(0.0, 0.0, 0.0, 1.0);\n");
|
||||
mstring_append(body, " oB1 = vec4(0.0, 0.0, 0.0, 1.0);\n");
|
||||
} else {
|
||||
if (!state->separate_specular) {
|
||||
mstring_append(body, " oD1 = specular;\n");
|
||||
mstring_append(body, " oB1 = backSpecular;\n");
|
||||
mstring_append(body,
|
||||
" oD0.xyz += oD1.xyz;\n"
|
||||
" oD1 = specular;\n"
|
||||
" oB0.xyz += oB1.xyz;\n"
|
||||
" oB1 = backSpecular;\n"
|
||||
);
|
||||
}
|
||||
if (state->ignore_specular_alpha) {
|
||||
mstring_append(body,
|
||||
" oD1.w = 1.0;\n"
|
||||
" oD1.a = 1.0;\n"
|
||||
" oB1.a = 1.0;\n"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -96,6 +96,7 @@ DEF_METHOD_RANGE(NV097, SET_FOG_PARAMS, 3)
|
|||
DEF_METHOD_RANGE(NV097, SET_TEXGEN_PLANE_S, 4*4*4)
|
||||
DEF_METHOD(NV097, SET_TEXGEN_VIEW_MODEL)
|
||||
DEF_METHOD_RANGE(NV097, SET_FOG_PLANE, 4)
|
||||
DEF_METHOD_RANGE(NV097, SET_SPECULAR_PARAMS, 6)
|
||||
DEF_METHOD_RANGE(NV097, SET_SCENE_AMBIENT_COLOR, 3)
|
||||
DEF_METHOD_RANGE(NV097, SET_VIEWPORT_OFFSET, 4)
|
||||
DEF_METHOD_RANGE(NV097, SET_POINT_PARAMS, 8)
|
||||
|
@ -178,6 +179,7 @@ DEF_METHOD(NV097, CLEAR_SURFACE)
|
|||
DEF_METHOD(NV097, SET_CLEAR_RECT_HORIZONTAL)
|
||||
DEF_METHOD(NV097, SET_CLEAR_RECT_VERTICAL)
|
||||
DEF_METHOD_RANGE(NV097, SET_SPECULAR_FOG_FACTOR, 2)
|
||||
DEF_METHOD_RANGE(NV097, SET_SPECULAR_PARAMS_BACK, 6)
|
||||
DEF_METHOD(NV097, SET_SHADER_CLIP_PLANE_MODE)
|
||||
DEF_METHOD_RANGE(NV097, SET_COMBINER_COLOR_OCW, 8)
|
||||
DEF_METHOD(NV097, SET_COMBINER_CONTROL)
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "hw/xbox/nv2a/nv2a_int.h"
|
||||
#include "ui/xemu-notifications.h"
|
||||
#include "ui/xemu-settings.h"
|
||||
|
@ -1812,6 +1814,42 @@ DEF_METHOD_INC(NV097, SET_FOG_PLANE)
|
|||
pg->vsh_constants_dirty[NV_IGRAPH_XF_XFCTX_FOG] = true;
|
||||
}
|
||||
|
||||
// Based on curve fitting to observed values from DirectX uses.
|
||||
// x = -log2(30.80722523) / power
|
||||
// c3_param = -1.01441946 * pow(exp2( x ), 2) + 0.01451685
|
||||
#define SPECULAR_POWER_NUMERATOR_CONSTANT 30.80722523f
|
||||
#define SPECULAR_POWER_COEFFICIENT_A -1.0141946f
|
||||
#define SPECULAR_POWER_CONSTANT_COEFFICIENT 0.01451685f
|
||||
//#define SPECULAR_POWER_LOG_CONSTANT (-2.f * log2(SPECULAR_POWER_NUMERATOR_CONSTANT))
|
||||
#define SPECULAR_POWER_LOG_CONSTANT -9.8903942108154297f
|
||||
static float reconstruct_specular_power_from_c3(uint32_t c3_parameter)
|
||||
{
|
||||
float c3 = *(float*)&c3_parameter;
|
||||
|
||||
// FIXME: This handling is not correct, but is visually distinct without causing a crash.
|
||||
// It does not appear possible for a DirectX-generated value to be positive, so while this differs from hardware
|
||||
// behavior, it may be irrelevant in practice.
|
||||
float invert = 1.f;
|
||||
if (c3 > 0.0f) {
|
||||
invert = -1.f;
|
||||
c3 *= invert;
|
||||
}
|
||||
|
||||
c3 -= SPECULAR_POWER_CONSTANT_COEFFICIENT;
|
||||
float ret = SPECULAR_POWER_LOG_CONSTANT / log2(c3 / SPECULAR_POWER_COEFFICIENT_A);
|
||||
assert(!isnan(ret) && "Failed to reconstruct specular power factor");
|
||||
return ret * invert;
|
||||
}
|
||||
|
||||
DEF_METHOD_INC(NV097, SET_SPECULAR_PARAMS)
|
||||
{
|
||||
int slot = (method - NV097_SET_SPECULAR_PARAMS) / 4;
|
||||
NV2A_DPRINTF("NV097_SET_SPECULAR_PARAMS[%d] 0x%X\n", slot, parameter);
|
||||
if (slot == 3) {
|
||||
pg->specular_power = reconstruct_specular_power_from_c3(parameter);
|
||||
}
|
||||
}
|
||||
|
||||
DEF_METHOD_INC(NV097, SET_SCENE_AMBIENT_COLOR)
|
||||
{
|
||||
int slot = (method - NV097_SET_SCENE_AMBIENT_COLOR) / 4;
|
||||
|
@ -2790,6 +2828,15 @@ DEF_METHOD_INC(NV097, SET_SPECULAR_FOG_FACTOR)
|
|||
pgraph_reg_w(pg, NV_PGRAPH_SPECFOGFACTOR0 + slot*4, parameter);
|
||||
}
|
||||
|
||||
DEF_METHOD_INC(NV097, SET_SPECULAR_PARAMS_BACK)
|
||||
{
|
||||
int slot = (method - NV097_SET_SPECULAR_PARAMS_BACK) / 4;
|
||||
NV2A_DPRINTF("SET_SPECULAR_PARAMS_BACK[%d] 0x%X\n", slot, parameter);
|
||||
if (slot == 3) {
|
||||
pg->specular_power_back = reconstruct_specular_power_from_c3(parameter);
|
||||
}
|
||||
}
|
||||
|
||||
DEF_METHOD(NV097, SET_SHADER_CLIP_PLANE_MODE)
|
||||
{
|
||||
pgraph_reg_w(pg, NV_PGRAPH_SHADERCLIPMODE, parameter);
|
||||
|
|
|
@ -197,6 +197,9 @@ typedef struct PGRAPHState {
|
|||
float light_local_position[NV2A_MAX_LIGHTS][3];
|
||||
float light_local_attenuation[NV2A_MAX_LIGHTS][3];
|
||||
|
||||
float specular_power;
|
||||
float specular_power_back;
|
||||
|
||||
float point_params[8];
|
||||
|
||||
VertexAttribute vertex_attributes[NV2A_VERTEXSHADER_ATTRIBUTES];
|
||||
|
|
|
@ -96,6 +96,11 @@ 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;
|
||||
|
||||
/* vertex program stuff */
|
||||
state.vertex_program = vertex_program,
|
||||
|
|
|
@ -81,6 +81,9 @@ typedef struct ShaderState {
|
|||
|
||||
bool separate_specular;
|
||||
bool ignore_specular_alpha;
|
||||
bool local_eye;
|
||||
float specular_power;
|
||||
float specular_power_back;
|
||||
|
||||
bool lighting;
|
||||
enum VshLight light[NV2A_MAX_LIGHTS];
|
||||
|
|
Loading…
Reference in New Issue