Signed-off-by: Paul Gofman gofmanp@gmail.com --- v2 changes: - rename dot_vec3 to wined3d_vec3_dot(); - use wined3d_vec3_dot() in normalize_vec3(); - use functions with explicit types instead of madd_vec(); - rename multiply_vector3_matrix() to multiply_vector3_matrix3(); - introduce 'struct wined3d_matrix3' and use it in multiply_vector3_matrix3(). - increase bit field size for light count.
dlls/ddraw/tests/ddraw1.c | 4 +- dlls/wined3d/device.c | 310 +++++++++++++++++++++++++++++++-- dlls/wined3d/wined3d_private.h | 1 + 3 files changed, 298 insertions(+), 17 deletions(-)
diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c index 7dda6eba20..9525b2dc0c 100644 --- a/dlls/ddraw/tests/ddraw1.c +++ b/dlls/ddraw/tests/ddraw1.c @@ -5894,7 +5894,7 @@ static void test_material(void) ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr); color = get_surface_color(rt, 320, 240); if (test_data[i].material) - todo_wine ok(compare_color(color, test_data[i].expected_color, 1) + ok(compare_color(color, test_data[i].expected_color, 1) /* The Windows 8 testbot appears to return undefined results. */ || broken(TRUE), "Got unexpected color 0x%08x, test %u.\n", color, i); @@ -6273,7 +6273,7 @@ static void test_lighting(void) ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
color = get_surface_color(rt, 320, 240); - todo_wine ok(color == tests[i].expected, "%s has color 0x%08x.\n", tests[i].message, color); + ok(color == tests[i].expected, "%s has color 0x%08x.\n", tests[i].message, color); }
IDirect3DExecuteBuffer_Release(execute_buffer); diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 81a76398a7..8576012f21 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -3174,6 +3174,11 @@ static void color_from_mcs(struct wined3d_color *color, enum wined3d_material_co wined3d_format_get_color(element->format, element->data.addr + index * element->stride, color); }
+static float wined3d_vec3_dot(const struct wined3d_vec3 *src1, const struct wined3d_vec3 *src2) +{ + return src1->x * src2->x + src1->y * src2->y + src1->z * src2->z; +} + static float clamp(float value, float min_value, float max_value) { return value < min_value ? min_value : value > max_value ? max_value : value; @@ -3188,12 +3193,220 @@ static void wined3d_color_clamp(struct wined3d_color *dst, const struct wined3d_ dst->a = clamp(src->a, min_value, max_value); }
+static void normalize_vec3(struct wined3d_vec3 *dest, const struct wined3d_vec3 *src) +{ + float rnorm = 1.0f / sqrtf(wined3d_vec3_dot(src, src)); + + *dest = *src; + if (isfinite(rnorm)) + { + dest->x *= rnorm; + dest->y *= rnorm; + dest->z *= rnorm; + } +} + +static void madd_color_rgb(struct wined3d_color *dst, const struct wined3d_color *src, float c) +{ + dst->r += src->r * c; + dst->g += src->g * c; + dst->b += src->b * c; +} + +static void madd_color(struct wined3d_color *dst, const struct wined3d_color *src, float c) +{ + dst->r += src->r * c; + dst->g += src->g * c; + dst->b += src->b * c; + dst->a += src->a * c; +} + +struct wined3d_matrix3 +{ + float _11, _12, _13; + float _21, _22, _23; + float _31, _32, _33; +}; + +static void multiply_vector3_matrix3(struct wined3d_vec3 *dest, const struct wined3d_vec3 *src1, + const struct wined3d_matrix3 *mat) +{ + struct wined3d_vec3 temp; + + temp.x = (src1->x * mat->_11) + (src1->y * mat->_21) + (src1->z * mat->_31); + temp.y = (src1->x * mat->_12) + (src1->y * mat->_22) + (src1->z * mat->_32); + temp.z = (src1->x * mat->_13) + (src1->y * mat->_23) + (src1->z * mat->_33); + + *dest = temp; +} + +struct light_transformed +{ + struct wined3d_color diffuse, specular, ambient; + struct wined3d_vec4 position; + struct wined3d_vec3 direction; + float range, falloff, c_att, l_att, q_att, cos_htheta, cos_hphi; +}; + +struct lights_settings +{ + struct light_transformed lights[WINED3D_MAX_SOFTWARE_ACTIVE_LIGHTS]; + struct wined3d_color ambient_light; + struct wined3d_matrix modelview_matrix; + struct wined3d_matrix3 normal_matrix; + + DWORD point_light_count : 8; + DWORD spot_light_count : 8; + DWORD directional_light_count : 8; + DWORD parallel_point_light_count : 8; + DWORD legacy_lighting : 1; + DWORD normalize : 1; + DWORD localviewer : 1; + DWORD padding : 29; +}; + +static void init_transformed_lights(struct lights_settings *ls, const struct wined3d_state *state, + BOOL legacy_lighting) +{ + const struct wined3d_light_info *lights[WINED3D_MAX_SOFTWARE_ACTIVE_LIGHTS]; + const struct wined3d_light_info *light_info; + struct light_transformed *light; + unsigned int lights_count; + struct wined3d_vec4 vec4; + unsigned int i, index; + + memset(ls, 0, sizeof(*ls)); + + wined3d_color_from_d3dcolor(&ls->ambient_light, state->render_states[WINED3D_RS_AMBIENT]); + ls->legacy_lighting = !!legacy_lighting; + ls->normalize = !!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); + + index = 0; + for (i = 0; i < LIGHTMAP_SIZE && index < WINED3D_MAX_SOFTWARE_ACTIVE_LIGHTS; ++i) + { + LIST_FOR_EACH_ENTRY(light_info, &state->light_state.light_map[i], struct wined3d_light_info, entry) + { + if (!light_info->enabled) + continue; + + switch (light_info->OriginalParms.type) + { + case WINED3D_LIGHT_DIRECTIONAL: + ++ls->directional_light_count; + break; + default: + FIXME("Unhandled light type %#x.\n", light_info->OriginalParms.type); + continue; + } + lights[index] = light_info; + if (++index == WINED3D_MAX_SOFTWARE_ACTIVE_LIGHTS) + break; + } + } + + lights_count = index; + index = 0; + for (i = 0; i < lights_count; ++i) + { + light_info = lights[i]; + if (light_info->OriginalParms.type != WINED3D_LIGHT_DIRECTIONAL) + continue; + + light = &ls->lights[index]; + multiply_vector_matrix(&vec4, &light_info->direction, &state->transforms[WINED3D_TS_VIEW]); + normalize_vec3(&light->direction, (const struct wined3d_vec3 *)&vec4); + + light->diffuse = light_info->OriginalParms.diffuse; + light->ambient = light_info->OriginalParms.ambient; + light->specular = light_info->OriginalParms.specular; + ++index; + } +} + +static void update_light_diffuse_specular(struct wined3d_color *diffuse, struct wined3d_color *specular, + const struct wined3d_vec3 *dir, float att, float material_shininess, + const struct wined3d_vec3 *normal_transformed, + const struct wined3d_vec3 *position_transformed_normalized, + const struct light_transformed *light, const struct lights_settings *ls) +{ + struct wined3d_vec3 vec3; + float t, c; + + c = clamp(wined3d_vec3_dot(dir, normal_transformed), 0.0f, 1.0f); + madd_color_rgb(diffuse, &light->diffuse, c * att); + + if (ls->localviewer) + { + vec3.x = dir->x - position_transformed_normalized->x; + vec3.y = dir->y - position_transformed_normalized->y; + vec3.z = dir->z - position_transformed_normalized->z; + } + else + { + vec3.x = dir->x; + vec3.y = dir->y; + vec3.z = dir->z - 1.0f; + } + normalize_vec3(&vec3, &vec3); + t = wined3d_vec3_dot(normal_transformed, &vec3); + if (t > 0.0f && (!ls->legacy_lighting || material_shininess > 0.0f) + && wined3d_vec3_dot(dir, normal_transformed) > 0.0f) + madd_color(specular, &light->specular, att * powf(t, material_shininess)); +} + +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_vec3 position_transformed_normalized; + struct wined3d_vec3 normal_transformed = {0.0f}; + struct wined3d_vec4 position_transformed; + const struct light_transformed *light; + unsigned int i, index; + float rcp_w; + + multiply_vector_matrix(&position_transformed, position, &ls->modelview_matrix); + rcp_w = 1.0f / position_transformed.w; + position_transformed.x *= rcp_w; + position_transformed.y *= rcp_w; + position_transformed.z *= rcp_w; + position_transformed.w = 1.0f; + normalize_vec3(&position_transformed_normalized, (const struct wined3d_vec3 *)&position_transformed); + + if (normal) + { + multiply_vector3_matrix3(&normal_transformed, normal, &ls->normal_matrix); + if (ls->normalize) + normalize_vec3(&normal_transformed, &normal_transformed); + } + + diffuse->r = diffuse->g = diffuse->b = diffuse->a = 0.0f; + *specular = *diffuse; + *ambient = ls->ambient_light; + + index = 0; + for (i = 0; i < ls->directional_light_count; ++i, ++index) + { + light = &ls->lights[index]; + + madd_color_rgb(ambient, &light->ambient, 1.0f); + if (normal) + update_light_diffuse_specular(diffuse, specular, &light->direction, 1.0f, material_shininess, + &normal_transformed, &position_transformed_normalized, light, 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, const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD flags, DWORD dst_fvf) { - enum wined3d_material_color_source diffuse_source, specular_source; + enum wined3d_material_color_source ambient_source, diffuse_source, emissive_source, specular_source; const struct wined3d_color *material_specular_state_color; struct wined3d_matrix mat, proj_mat, view_mat, world_mat; const struct wined3d_state *state = &device->state; @@ -3202,6 +3415,7 @@ static HRESULT process_vertices_strided(const struct wined3d_device *device, DWO struct wined3d_map_desc map_desc; struct wined3d_box box = {0}; struct wined3d_viewport vp; + struct lights_settings ls; unsigned int vertex_size; BOOL doClip, lighting; DWORD numTextures; @@ -3209,11 +3423,6 @@ static HRESULT process_vertices_strided(const struct wined3d_device *device, DWO BYTE *dest_ptr; HRESULT hr;
- if (stream_info->use_map & (1u << WINED3D_FFP_NORMAL)) - { - WARN(" lighting state not saved yet... Some strange stuff may happen !\n"); - } - if (!(stream_info->use_map & (1u << WINED3D_FFP_POSITION))) { ERR("Source has no position mask.\n"); @@ -3291,13 +3500,19 @@ static HRESULT process_vertices_strided(const struct wined3d_device *device, DWO { diffuse_source = validate_material_colour_source(stream_info->use_map, state->render_states[WINED3D_RS_DIFFUSEMATERIALSOURCE]); + ambient_source = validate_material_colour_source(stream_info->use_map, + state->render_states[WINED3D_RS_AMBIENTMATERIALSOURCE]); + emissive_source = validate_material_colour_source(stream_info->use_map, + state->render_states[WINED3D_RS_EMISSIVEMATERIALSOURCE]); specular_source = validate_material_colour_source(stream_info->use_map, state->render_states[WINED3D_RS_SPECULARMATERIALSOURCE]); } else { - diffuse_source = specular_source = WINED3D_MCS_MATERIAL; + ambient_source = diffuse_source = emissive_source = specular_source = WINED3D_MCS_MATERIAL; } + init_transformed_lights(&ls, state, device->adapter->d3d_info.wined3d_creation_flags + & WINED3D_LEGACY_FFP_LIGHTING); } else { @@ -3309,13 +3524,15 @@ static HRESULT process_vertices_strided(const struct wined3d_device *device, DWO ? &state->material.specular : &black;
for (i = 0; i < dwCount; i+= 1) { + struct wined3d_color ambient, diffuse, specular; + 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); unsigned int tex_index;
if ( ((dst_fvf & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) || ((dst_fvf & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) { /* The position first */ - const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION]; - const float *p = (const float *)(element->data.addr + i * element->stride); float x, y, z, rhw; TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
@@ -3423,25 +3640,88 @@ static HRESULT process_vertices_strided(const struct wined3d_device *device, DWO copy_and_next(dest_ptr, normal, 3 * sizeof(float)); }
+ 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]; + normal = (struct wined3d_vec3 *)(element->data.addr + i * element->stride); + } + else + { + normal = NULL; + } + compute_light(&ambient, &diffuse, &specular, &ls, normal, &position, + state->render_states[WINED3D_RS_SPECULARENABLE] ? state->material.power : 0.0f); + } + if (dst_fvf & WINED3DFVF_DIFFUSE) { - struct wined3d_color material_diffuse; + struct wined3d_color material_diffuse, material_ambient, material_emissive, diffuse_color;
color_from_mcs(&material_diffuse, diffuse_source, &state->material.diffuse, i, stream_info);
- wined3d_color_clamp(&material_diffuse, &material_diffuse, 0.0f, 1.0f); - *((DWORD *)dest_ptr) = wined3d_format_convert_from_float(output_color_format, &material_diffuse); + if (lighting) + { + color_from_mcs(&material_ambient, ambient_source, &state->material.ambient, i, stream_info); + color_from_mcs(&material_emissive, emissive_source, &state->material.emissive, i, stream_info); + + diffuse_color.a = material_diffuse.a; + diffuse_color.r = ambient.r * material_ambient.r + + diffuse.r * material_diffuse.r + material_emissive.r; + diffuse_color.g = ambient.g * material_ambient.g + + diffuse.g * material_diffuse.g + material_emissive.g; + diffuse_color.b = ambient.b * material_ambient.b + + diffuse.b * material_diffuse.b + material_emissive.b; + } + else + { + diffuse_color = material_diffuse; + } + wined3d_color_clamp(&diffuse_color, &diffuse_color, 0.0f, 1.0f); + *((DWORD *)dest_ptr) = wined3d_format_convert_from_float(output_color_format, &diffuse_color); dest_ptr += sizeof(DWORD); }
if (dst_fvf & WINED3DFVF_SPECULAR) { - struct wined3d_color material_specular; + struct wined3d_color material_specular, specular_color;
color_from_mcs(&material_specular, specular_source, material_specular_state_color, i, stream_info);
- wined3d_color_clamp(&material_specular, &material_specular, 0.0f, 1.0f); - *((DWORD *)dest_ptr) = wined3d_format_convert_from_float(output_color_format, &material_specular); + if (lighting) + { + specular_color.a = specular.a * material_specular.a; + specular_color.r = specular.r * material_specular.r; + specular_color.g = specular.g * material_specular.g; + specular_color.b = specular.b * material_specular.b; + if (state->render_states[WINED3D_RS_FOGENABLE]) + { + static BOOL warned; + + if (!warned) + { + FIXME("Fog factor is not implemented.\n"); + warned = TRUE; + } + specular_color.a = 1.0f; + } + } + else + { + specular_color = material_specular; + } + wined3d_color_clamp(&specular_color, &specular_color, 0.0f, 1.0f); + *((DWORD *)dest_ptr) = wined3d_format_convert_from_float(output_color_format, &specular_color); dest_ptr += sizeof(DWORD); }
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 9029ca18f3..bd77881e27 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -270,6 +270,7 @@ static inline enum complex_fixup get_complex_fixup(struct color_fixup_desc fixup #define WINED3D_MAX_VERTEX_SAMPLERS 4 #define WINED3D_MAX_COMBINED_SAMPLERS (WINED3D_MAX_FRAGMENT_SAMPLERS + WINED3D_MAX_VERTEX_SAMPLERS) #define WINED3D_MAX_ACTIVE_LIGHTS 8 +#define WINED3D_MAX_SOFTWARE_ACTIVE_LIGHTS 32 #define WINED3D_MAX_CLIP_DISTANCES 8 #define MAX_CONSTANT_BUFFERS 15 #define MAX_SAMPLER_OBJECTS 16