[PATCH 07/11] wined3d: Implement lighting with directional lights in process_vertices_strided().
Paul Gofman
gofmanp at gmail.com
Wed May 15 10:06:54 CDT 2019
Signed-off-by: Paul Gofman <gofmanp at gmail.com>
---
dlls/ddraw/tests/ddraw1.c | 4 +-
dlls/wined3d/device.c | 296 +++++++++++++++++++++++++++++++--
dlls/wined3d/wined3d_private.h | 1 +
3 files changed, 284 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 938c420f5b..2f1ff4f5b5 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -3107,6 +3107,11 @@ static void color_from_mcs(struct wined3d_color *color, enum wined3d_material_co
wined3d_color_from_d3dcolor(color, element ? *(const DWORD *)(element->data.addr + index * element->stride) : 0);
}
+static float dot_vec3(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;
@@ -3121,17 +3126,212 @@ static void clamp_vec(float *dst, const float *src, unsigned int count,
dst[i] = clamp(src[i], min_value, max_value);
}
+static void normalize_vec3(struct wined3d_vec3 *dest, const struct wined3d_vec3 *src)
+{
+ float rnorm = 1.0f / sqrtf(src->x * src->x + src->y * src->y + src->z * src->z);
+
+ *dest = *src;
+ if (isfinite(rnorm))
+ {
+ dest->x *= rnorm;
+ dest->y *= rnorm;
+ dest->z *= rnorm;
+ }
+}
+
+static void madd_vec(float *dst, const float *src, unsigned int count, float c)
+{
+ unsigned int i;
+
+ for (i = 0; i < count; ++i)
+ dst[i] += src[i] * c;
+}
+
+static void multiply_vector3_matrix(struct wined3d_vec3 *dest, const struct wined3d_vec3 *src1,
+ const float *src2)
+{
+ struct wined3d_vec3 temp;
+
+ temp.x = (src1->x * src2[0]) + (src1->y * src2[3]) + (src1->z * src2[3 * 2]);
+ temp.y = (src1->x * src2[1]) + (src1->y * src2[3 + 1]) + (src1->z * src2[3 * 2 + 1]);
+ temp.z = (src1->x * src2[2]) + (src1->y * src2[3 + 2]) + (src1->z * src2[3 * 2 + 2]);
+
+ *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;
+ float normal_matrix[3 * 3];
+
+ DWORD point_light_count : 4;
+ DWORD spot_light_count : 4;
+ DWORD directional_light_count : 4;
+ DWORD parallel_point_light_count : 4;
+ DWORD legacy_lighting : 1;
+ DWORD normalize : 1;
+ DWORD localviewer : 1;
+ DWORD padding : 13;
+};
+
+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, 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(dot_vec3(dir, normal_transformed), 0.0f, 1.0f);
+ madd_vec(&diffuse->r, &light->diffuse.r, 3, 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 = dot_vec3(normal_transformed, &vec3);
+ if (t > 0.0f && (!ls->legacy_lighting || material_shininess > 0.0f)
+ && dot_vec3(dir, normal_transformed) > 0.0f)
+ madd_vec(&specular->r, &light->specular.r, 4, 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_matrix(&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_vec(&ambient->r, &light->ambient.r, 3, 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;
struct wined3d_matrix mat, proj_mat, view_mat, world_mat;
const struct wined3d_state *state = &device->state;
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;
@@ -3139,11 +3339,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");
@@ -3221,13 +3416,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
{
@@ -3236,13 +3437,15 @@ static HRESULT process_vertices_strided(const struct wined3d_device *device, DWO
}
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]);
@@ -3350,27 +3553,90 @@ 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);
- clamp_vec(&material_diffuse.r, &material_diffuse.r, 4, 0.0f, 1.0f);
- *((DWORD *)dest_ptr) = d3dcolor_from_wined3d_color(&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;
+ }
+ clamp_vec(&diffuse_color.r, &diffuse_color.r, 4, 0.0f, 1.0f);
+ *((DWORD *)dest_ptr) = d3dcolor_from_wined3d_color(&diffuse_color);
dest_ptr += sizeof(DWORD);
}
if (dst_fvf & WINED3DFVF_SPECULAR)
{
- struct wined3d_color material_specular;
+ struct wined3d_color material_specular, specular_color;
memset(&material_specular, 0, sizeof(material_specular));
color_from_mcs(&material_specular, specular_source, state->render_states[WINED3D_RS_SPECULARENABLE]
? &state->material.specular : &material_specular, i, stream_info);
- clamp_vec(&material_specular.r, &material_specular.r, 4, 0.0f, 1.0f);
- *((DWORD *)dest_ptr) = d3dcolor_from_wined3d_color(&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;
+ }
+ clamp_vec(&specular_color.r, &specular_color.r, 4, 0.0f, 1.0f);
+ *((DWORD *)dest_ptr) = d3dcolor_from_wined3d_color(&specular_color);
dest_ptr += sizeof(DWORD);
}
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 9616f31513..06c085e053 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
--
2.21.0
More information about the wine-devel
mailing list