wined3d: Compute fog factor in process_vertices_strided().

Signed-off-by: Paul Gofman <gofmanp@gmail.com>
Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Paul Gofman 2019-06-10 13:11:49 +03:00 committed by Alexandre Julliard
parent 937891cc65
commit 057506908a
2 changed files with 111 additions and 29 deletions

View File

@ -58,16 +58,21 @@ struct lights_settings
struct wined3d_color ambient_light;
struct wined3d_matrix modelview_matrix;
struct wined3d_matrix_3x3 normal_matrix;
struct wined3d_vec4 position_transformed;
float fog_start, fog_end, fog_density;
uint32_t point_light_count : 8;
uint32_t spot_light_count : 8;
uint32_t directional_light_count : 8;
uint32_t parallel_point_light_count : 8;
uint32_t lighting : 1;
uint32_t legacy_lighting : 1;
uint32_t normalise : 1;
uint32_t localviewer : 1;
uint32_t padding : 29;
uint32_t fog_coord_mode : 2;
uint32_t fog_mode : 2;
uint32_t padding : 24;
};
/* Define the default light parameters as specified by MSDN. */
@ -3261,7 +3266,7 @@ static void wined3d_color_rgb_mul_add(struct wined3d_color *dst, const struct wi
}
static void init_transformed_lights(struct lights_settings *ls,
const struct wined3d_state *state, BOOL legacy_lighting)
const struct wined3d_state *state, BOOL legacy_lighting, BOOL compute_lighting)
{
const struct wined3d_light_info *lights[WINED3D_MAX_SOFTWARE_ACTIVE_LIGHTS];
const struct wined3d_light_info *light_info;
@ -3272,15 +3277,30 @@ static void init_transformed_lights(struct lights_settings *ls,
memset(ls, 0, sizeof(*ls));
ls->lighting = !!compute_lighting;
ls->fog_mode = state->render_states[WINED3D_RS_FOGVERTEXMODE];
ls->fog_coord_mode = state->render_states[WINED3D_RS_RANGEFOGENABLE]
? WINED3D_FFP_VS_FOG_RANGE : WINED3D_FFP_VS_FOG_DEPTH;
ls->fog_start = wined3d_get_float_state(state, WINED3D_RS_FOGSTART);
ls->fog_end = wined3d_get_float_state(state, WINED3D_RS_FOGEND);
ls->fog_density = wined3d_get_float_state(state, WINED3D_RS_FOGDENSITY);
if (ls->fog_mode == WINED3D_FOG_NONE && !compute_lighting)
return;
multiply_matrix(&ls->modelview_matrix, &state->transforms[WINED3D_TS_VIEW],
&state->transforms[WINED3D_TS_WORLD_MATRIX(0)]);
if (!compute_lighting)
return;
compute_normal_matrix(&ls->normal_matrix._11, legacy_lighting, &ls->modelview_matrix);
wined3d_color_from_d3dcolor(&ls->ambient_light, state->render_states[WINED3D_RS_AMBIENT]);
ls->legacy_lighting = !!legacy_lighting;
ls->normalise = !!state->render_states[WINED3D_RS_NORMALIZENORMALS];
ls->localviewer = !!state->render_states[WINED3D_RS_LOCALVIEWER];
multiply_matrix(&ls->modelview_matrix, &state->transforms[WINED3D_TS_VIEW],
&state->transforms[WINED3D_TS_WORLD_MATRIX(0)]);
compute_normal_matrix(&ls->normal_matrix._11, legacy_lighting, &ls->modelview_matrix);
for (i = 0, index = 0; i < LIGHTMAP_SIZE && index < ARRAY_SIZE(lights); ++i)
{
LIST_FOR_EACH_ENTRY(light_info, &state->light_state.light_map[i], struct wined3d_light_info, entry)
@ -3422,21 +3442,28 @@ static void update_light_diffuse_specular(struct wined3d_color *diffuse, struct
wined3d_color_rgb_mul_add(specular, &light->specular, att * powf(t, material_shininess));
}
static void light_set_vertex_data(struct lights_settings *ls,
const struct wined3d_vec4 *position)
{
if (ls->fog_mode == WINED3D_FOG_NONE && !ls->lighting)
return;
wined3d_vec4_transform(&ls->position_transformed, position, &ls->modelview_matrix);
wined3d_vec3_scale((struct wined3d_vec3 *)&ls->position_transformed, 1.0f / ls->position_transformed.w);
}
static void compute_light(struct wined3d_color *ambient, struct wined3d_color *diffuse,
struct wined3d_color *specular, const struct lights_settings *ls, const struct wined3d_vec3 *normal,
const struct wined3d_vec4 *position, float material_shininess)
struct wined3d_color *specular, struct lights_settings *ls, const struct wined3d_vec3 *normal,
float material_shininess)
{
struct wined3d_vec3 position_transformed_normalised;
struct wined3d_vec3 normal_transformed = {0.0f};
struct wined3d_vec4 position_transformed;
const struct light_transformed *light;
struct wined3d_vec3 dir, dst;
unsigned int i, index;
float att;
wined3d_vec4_transform(&position_transformed, position, &ls->modelview_matrix);
wined3d_vec3_scale((struct wined3d_vec3 *)&position_transformed, 1.0f / position_transformed.w);
position_transformed_normalised = *(const struct wined3d_vec3 *)&position_transformed;
position_transformed_normalised = *(const struct wined3d_vec3 *)&ls->position_transformed;
wined3d_vec3_normalise(&position_transformed_normalised);
if (normal)
@ -3464,9 +3491,9 @@ static void compute_light(struct wined3d_color *ambient, struct wined3d_color *d
for (i = 0; i < ls->point_light_count; ++i, ++index)
{
light = &ls->lights[index];
dir.x = light->position.x - position_transformed.x;
dir.y = light->position.y - position_transformed.y;
dir.z = light->position.z - position_transformed.z;
dir.x = light->position.x - ls->position_transformed.x;
dir.y = light->position.y - ls->position_transformed.y;
dir.z = light->position.z - ls->position_transformed.z;
dst.z = wined3d_vec3_dot(&dir, &dir);
dst.y = sqrtf(dst.z);
@ -3502,9 +3529,9 @@ static void compute_light(struct wined3d_color *ambient, struct wined3d_color *d
light = &ls->lights[index];
dir.x = light->position.x - position_transformed.x;
dir.y = light->position.y - position_transformed.y;
dir.z = light->position.z - position_transformed.z;
dir.x = light->position.x - ls->position_transformed.x;
dir.y = light->position.y - ls->position_transformed.y;
dir.z = light->position.z - ls->position_transformed.z;
dst.z = wined3d_vec3_dot(&dir, &dir);
dst.y = sqrtf(dst.z);
@ -3555,6 +3582,46 @@ static void compute_light(struct wined3d_color *ambient, struct wined3d_color *d
}
}
static float wined3d_calculate_fog_factor(float fog_coord, const struct lights_settings *ls)
{
switch (ls->fog_mode)
{
case WINED3D_FOG_NONE:
return fog_coord;
case WINED3D_FOG_LINEAR:
return (ls->fog_end - fog_coord) / (ls->fog_end - ls->fog_start);
case WINED3D_FOG_EXP:
return expf(-fog_coord * ls->fog_density);
case WINED3D_FOG_EXP2:
return expf(-fog_coord * fog_coord * ls->fog_density * ls->fog_density);
}
}
static void update_fog_factor(float *fog_factor, struct lights_settings *ls)
{
float fog_coord;
if (ls->fog_mode == WINED3D_FOG_NONE)
return;
switch (ls->fog_coord_mode)
{
case WINED3D_FFP_VS_FOG_RANGE:
fog_coord = sqrtf(wined3d_vec3_dot((const struct wined3d_vec3 *)&ls->position_transformed,
(const struct wined3d_vec3 *)&ls->position_transformed));
break;
case WINED3D_FFP_VS_FOG_DEPTH:
fog_coord = fabsf(ls->position_transformed.z);
break;
default:
ERR("Unhandled fog coordinate mode %#x.\n", ls->fog_coord_mode);
return;
}
*fog_factor = wined3d_calculate_fog_factor(fog_coord, ls);
}
/* Context activation is done by the caller. */
#define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
static HRESULT process_vertices_strided(const struct wined3d_device *device, DWORD dwDestIndex, DWORD dwCount,
@ -3653,17 +3720,24 @@ static HRESULT process_vertices_strided(const struct wined3d_device *device, DWO
output_colour_format = wined3d_get_format(device->adapter, WINED3DFMT_B8G8R8A8_UNORM, 0);
material_specular_state_colour = state->render_states[WINED3D_RS_SPECULARENABLE]
? &state->material.specular : &black;
if (lighting)
init_transformed_lights(&ls, state,
device->adapter->d3d_info.wined3d_creation_flags & WINED3D_LEGACY_FFP_LIGHTING);
init_transformed_lights(&ls, state, device->adapter->d3d_info.wined3d_creation_flags
& WINED3D_LEGACY_FFP_LIGHTING, lighting);
for (i = 0; i < dwCount; ++i)
{
const struct wined3d_stream_info_element *position_element = &stream_info->elements[WINED3D_FFP_POSITION];
const float *p = (const float *)&position_element->data.addr[i * position_element->stride];
struct wined3d_color ambient, diffuse, specular;
struct wined3d_vec4 position;
unsigned int tex_index;
position.x = p[0];
position.y = p[1];
position.z = p[2];
position.w = 1.0f;
light_set_vertex_data(&ls, &position);
if ( ((dst_fvf & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
((dst_fvf & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
/* The position first */
@ -3775,14 +3849,8 @@ static HRESULT process_vertices_strided(const struct wined3d_device *device, DWO
if (lighting)
{
const struct wined3d_stream_info_element *element;
struct wined3d_vec4 position;
struct wined3d_vec3 *normal;
position.x = p[0];
position.y = p[1];
position.z = p[2];
position.w = 1.0f;
if (stream_info->use_map & (1u << WINED3D_FFP_NORMAL))
{
element = &stream_info->elements[WINED3D_FFP_NORMAL];
@ -3792,7 +3860,7 @@ static HRESULT process_vertices_strided(const struct wined3d_device *device, DWO
{
normal = NULL;
}
compute_light(&ambient, &diffuse, &specular, &ls, normal, &position,
compute_light(&ambient, &diffuse, &specular, &ls, normal,
state->render_states[WINED3D_RS_SPECULARENABLE] ? state->material.power : 0.0f);
}
@ -3845,6 +3913,7 @@ static HRESULT process_vertices_strided(const struct wined3d_device *device, DWO
{
specular_colour = material_specular;
}
update_fog_factor(&specular_colour.a, &ls);
wined3d_color_clamp(&specular_colour, &specular_colour, 0.0f, 1.0f);
*((DWORD *)dest_ptr) = wined3d_format_convert_from_float(output_colour_format, &specular_colour);
dest_ptr += sizeof(DWORD);

View File

@ -4927,6 +4927,19 @@ static inline void context_release(struct wined3d_context *context)
context->device->adapter->adapter_ops->adapter_release_context(context);
}
static inline float wined3d_get_float_state(const struct wined3d_state *state, enum wined3d_render_state rs)
{
union
{
DWORD d;
float f;
}
tmpvalue;
tmpvalue.d = state->render_states[rs];
return tmpvalue.f;
}
/* The WNDCLASS-Name for the fake window which we use to retrieve the GL capabilities */
#define WINED3D_OPENGL_WINDOW_CLASS_NAME "WineD3D_OpenGL"