From: Paul Gofman gofmanp@gmail.com
Signed-off-by: Paul Gofman gofmanp@gmail.com Signed-off-by: Henri Verbeet hverbeet@codeweavers.com --- dlls/ddraw/tests/ddraw1.c | 26 ++++++++++++++++ dlls/wined3d/device.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+)
diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c index 5c9ccba63bf..ee0b1b431a7 100644 --- a/dlls/ddraw/tests/ddraw1.c +++ b/dlls/ddraw/tests/ddraw1.c @@ -6368,6 +6368,18 @@ static void test_specular_lighting(void) 0.0f, 0.0f, 0.0f, 1.0f, }, + spot = + { + sizeof(D3DLIGHT2), + D3DLIGHT_SPOT, + {{1.0f}, {1.0f}, {1.0f}, {0.0f}}, + {{0.0f}, {0.0f}, {0.0f}}, + {{0.0f}, {0.0f}, {1.0f}}, + 100.0f, + 1.0f, + 0.0f, 0.0f, 1.0f, + M_PI / 12.0f, M_PI / 3.0f + }, point_side = { sizeof(D3DLIGHT2), @@ -6419,6 +6431,18 @@ static void test_specular_lighting(void) {320, 360, 0x00090909}, {480, 360, 0x00000000}, }, + expected_spot_local[] = + { + {160, 120, 0x00000000}, + {320, 120, 0x00020202}, + {480, 120, 0x00000000}, + {160, 240, 0x00020202}, + {320, 240, 0x00fafafa}, + {480, 240, 0x00020202}, + {160, 360, 0x00000000}, + {320, 360, 0x00020202}, + {480, 360, 0x00000000}, + }, expected_point_far[] = { {160, 120, 0x00000000}, @@ -6454,10 +6478,12 @@ static void test_specular_lighting(void) { {&directional, 30.0f, expected_directional_local, ARRAY_SIZE(expected_directional_local)}, {&point, 30.0f, expected_point_local, ARRAY_SIZE(expected_point_local)}, + {&spot, 30.0f, expected_spot_local, ARRAY_SIZE(expected_spot_local)}, {&point_side, 0.0f, expected_zero, ARRAY_SIZE(expected_zero)}, {&point_far, 1.0f, expected_point_far, ARRAY_SIZE(expected_point_far)}, {&directional, 0.0f, expected_zero, ARRAY_SIZE(expected_zero)}, {&point, 0.0f, expected_zero, ARRAY_SIZE(expected_zero)}, + {&spot, 0.0f, expected_zero, ARRAY_SIZE(expected_zero)}, {&point_far, 0.0f, expected_zero, ARRAY_SIZE(expected_zero)}, };
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index f5b9caadd28..33aba881cc6 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -3296,6 +3296,10 @@ static void init_transformed_lights(struct lights_settings *ls, ++ls->point_light_count; break;
+ case WINED3D_LIGHT_SPOT: + ++ls->spot_light_count; + break; + default: FIXME("Unhandled light type %#x.\n", light_info->OriginalParms.type); continue; @@ -3343,6 +3347,32 @@ static void init_transformed_lights(struct lights_settings *ls, light->specular = light_info->OriginalParms.specular; ++index; } + + for (i = 0; i < light_count; ++i) + { + light_info = lights[i]; + if (light_info->OriginalParms.type != WINED3D_LIGHT_SPOT) + continue; + + light = &ls->lights[index]; + + wined3d_vec4_transform(&light->position, &light_info->position, &state->transforms[WINED3D_TS_VIEW]); + wined3d_vec4_transform(&vec4, &light_info->direction, &state->transforms[WINED3D_TS_VIEW]); + light->direction = *(struct wined3d_vec3 *)&vec4; + wined3d_vec3_normalise(&light->direction); + light->range = light_info->OriginalParms.range; + light->falloff = light_info->OriginalParms.falloff; + light->c_att = light_info->OriginalParms.attenuation0; + light->l_att = light_info->OriginalParms.attenuation1; + light->q_att = light_info->OriginalParms.attenuation2; + light->cos_htheta = cosf(light_info->OriginalParms.theta / 2.0f); + light->cos_hphi = cosf(light_info->OriginalParms.phi / 2.0f); + + 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, @@ -3442,6 +3472,54 @@ static void compute_light(struct wined3d_color *ambient, struct wined3d_color *d &normal_transformed, &position_transformed_normalised, light, ls); } } + + for (i = 0; i < ls->spot_light_count; ++i, ++index) + { + float t; + + 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; + + dst.z = wined3d_vec3_dot(&dir, &dir); + dst.y = sqrtf(dst.z); + dst.x = 1.0f; + + if (ls->legacy_lighting) + { + dst.y = (light->range - dst.y) / light->range; + if (!(dst.y > 0.0f)) + continue; + dst.z = dst.y * dst.y; + } + else + { + if (!(dst.y <= light->range)) + continue; + } + wined3d_vec3_normalise(&dir); + t = -wined3d_vec3_dot(&dir, &light->direction); + if (t > light->cos_htheta) + att = 1.0f; + else if (t <= light->cos_hphi) + att = 0.0f; + else + att = powf((t - light->cos_hphi) / (light->cos_htheta - light->cos_hphi), light->falloff); + + t = dst.x * light->c_att + dst.y * light->l_att + dst.z * light->q_att; + if (ls->legacy_lighting) + att *= t; + else + att /= t; + + wined3d_color_rgb_mul_add(ambient, &light->ambient, att); + + if (normal) + update_light_diffuse_specular(diffuse, specular, &dir, att, material_shininess, + &normal_transformed, &position_transformed_normalised, light, ls); + } }
/* Context activation is done by the caller. */