320 lines
12 KiB
C
320 lines
12 KiB
C
#include "lights.h"
|
|
#include "material.h"
|
|
#include "pattern.h"
|
|
#include "test_world_utils.h"
|
|
#include "../testutils.h"
|
|
#include <sphere.h>
|
|
#include <unity.h>
|
|
|
|
SPHERE_Sphere *sphere;
|
|
void setUp(void) { sphere = SPHERE_new(); }
|
|
void tearDown(void) { SPHERE_delete(sphere); }
|
|
|
|
void test_default_material(void) {
|
|
MATERIAL_Material *m = MATERIAL_new();
|
|
TUPLES_Color *c = TUPLES_new_color(1, 1, 1);
|
|
TEST_ASSERT_TRUE(TUPLES_is_equal(c, &m->color));
|
|
TEST_ASSERT_EQUAL_DOUBLE(0.1, m->ambient);
|
|
TEST_ASSERT_EQUAL_DOUBLE(0.9, m->diffuse);
|
|
TEST_ASSERT_EQUAL_DOUBLE(0.9, m->specular);
|
|
TEST_ASSERT_EQUAL_DOUBLE(200.0, m->shininess);
|
|
TUPLES_delete(c);
|
|
MATERIAL_delete(m);
|
|
}
|
|
|
|
void test_lighting_with_eye_between_light_and_surface_in_shadow(void) {
|
|
MATERIAL_Material *material = MATERIAL_new();
|
|
TUPLES_Point *position = TUPLES_new_point(0, 0, 0);
|
|
TUPLES_Vector *eyev = TUPLES_new_vector(0, 0, -1);
|
|
TUPLES_Vector *normalv = TUPLES_new_vector(0, 0, -1);
|
|
|
|
TUPLES_Point *light_position = TUPLES_new_point(0, 0, -10);
|
|
TUPLES_Color *light_color = TUPLES_new_color(1, 1, 1);
|
|
LIGHTS_Light *pl = LIGHTS_new_pointlight(light_position, light_color);
|
|
|
|
SPHERE_set_material(sphere, material);
|
|
TUPLES_Color result;
|
|
MATERIAL_lighting(&result, sphere, pl, position, eyev, normalv, 0.0);
|
|
|
|
TUPLES_Color *expected_result = TUPLES_new_color(0.1, 0.1, 0.1);
|
|
test_tuples(expected_result, &result);
|
|
LIGHTS_delete(pl);
|
|
MATERIAL_delete(material);
|
|
TUPLES_delete_all(position, eyev, normalv, light_position, light_color, expected_result);
|
|
}
|
|
|
|
void test_lighting_with_eye_between_light_and_surface(void) {
|
|
MATERIAL_Material *material = MATERIAL_new();
|
|
SPHERE_set_material(sphere, material);
|
|
TUPLES_Point *position = TUPLES_new_point(0, 0, 0);
|
|
TUPLES_Vector *eyev = TUPLES_new_vector(0, 0, -1);
|
|
TUPLES_Vector *normalv = TUPLES_new_vector(0, 0, -1);
|
|
|
|
TUPLES_Point *light_position = TUPLES_new_point(0, 0, -10);
|
|
TUPLES_Color *light_color = TUPLES_new_color(1, 1, 1);
|
|
LIGHTS_Light *pl = LIGHTS_new_pointlight(light_position, light_color);
|
|
|
|
TUPLES_Color result;
|
|
MATERIAL_lighting(&result, sphere, pl, position, eyev, normalv, 1.0);
|
|
|
|
TUPLES_Color *expected_result = TUPLES_new_color(1.9, 1.9, 1.9);
|
|
test_tuples(expected_result, &result);
|
|
LIGHTS_delete(pl);
|
|
MATERIAL_delete(material);
|
|
TUPLES_delete_all(position, eyev, normalv, light_position, light_color, expected_result);
|
|
}
|
|
|
|
void test_lighting_with_eye_between_light_and_surface_eye_offset_45_deg(void) {
|
|
MATERIAL_Material *material = MATERIAL_new();
|
|
TUPLES_Point *position = TUPLES_new_point(0, 0, 0);
|
|
TUPLES_Vector *eyev = TUPLES_new_vector(0, sqrt(2.0) / 2.0, sqrt(2.0) / 2.0);
|
|
TUPLES_Vector *normalv = TUPLES_new_vector(0, 0, -1);
|
|
|
|
TUPLES_Point *light_position = TUPLES_new_point(0, 0, -10);
|
|
TUPLES_Color *light_color = TUPLES_new_color(1, 1, 1);
|
|
LIGHTS_Light *pl = LIGHTS_new_pointlight(light_position, light_color);
|
|
|
|
SPHERE_set_material(sphere, material);
|
|
TUPLES_Color result;
|
|
MATERIAL_lighting(&result, sphere, pl, position, eyev, normalv, 1.0);
|
|
|
|
TUPLES_Color *expected_result = TUPLES_new_color(1.0, 1.0, 1.0);
|
|
test_tuples(expected_result, &result);
|
|
LIGHTS_delete(pl);
|
|
MATERIAL_delete(material);
|
|
TUPLES_delete_all(position, eyev, normalv, light_position, light_color, expected_result);
|
|
}
|
|
|
|
void test_lighting_with_eye_opposite_surface_light_offset_45_deg(void) {
|
|
MATERIAL_Material *material = MATERIAL_new();
|
|
TUPLES_Point *position = TUPLES_new_point(0, 0, 0);
|
|
TUPLES_Vector *eyev = TUPLES_new_vector(0, 0, -1);
|
|
TUPLES_Vector *normalv = TUPLES_new_vector(0, 0, -1);
|
|
|
|
TUPLES_Point *light_position = TUPLES_new_point(0, 10, -10);
|
|
TUPLES_Color *light_color = TUPLES_new_color(1, 1, 1);
|
|
LIGHTS_Light *pl = LIGHTS_new_pointlight(light_position, light_color);
|
|
|
|
SPHERE_set_material(sphere, material);
|
|
TUPLES_Color result;
|
|
MATERIAL_lighting(&result, sphere, pl, position, eyev, normalv, 1.0);
|
|
|
|
TUPLES_Color *expected_result = TUPLES_new_color(0.7364, 0.7364, 0.7364);
|
|
test_tuples(expected_result, &result);
|
|
LIGHTS_delete(pl);
|
|
MATERIAL_delete(material);
|
|
TUPLES_delete_all(position, eyev, normalv, light_position, light_color, expected_result);
|
|
}
|
|
|
|
void test_lighting_with_eye_in_path_of_reflection_vector(void) {
|
|
MATERIAL_Material *material = MATERIAL_new();
|
|
TUPLES_Point *position = TUPLES_new_point(0, 0, 0);
|
|
TUPLES_Vector *eyev = TUPLES_new_vector(0, -sqrt(2.0) / 2.0, -sqrt(2.0) / 2.0);
|
|
TUPLES_Vector *normalv = TUPLES_new_vector(0, 0, -1);
|
|
|
|
TUPLES_Point *light_position = TUPLES_new_point(0, 10, -10);
|
|
TUPLES_Color *light_color = TUPLES_new_color(1, 1, 1);
|
|
LIGHTS_Light *pl = LIGHTS_new_pointlight(light_position, light_color);
|
|
|
|
SPHERE_set_material(sphere, material);
|
|
TUPLES_Color result;
|
|
MATERIAL_lighting(&result, sphere, pl, position, eyev, normalv, 1.0);
|
|
|
|
TUPLES_Color *expected_result = TUPLES_new_color(1.6364, 1.6364, 1.6364);
|
|
test_tuples(expected_result, &result);
|
|
LIGHTS_delete(pl);
|
|
MATERIAL_delete(material);
|
|
TUPLES_delete_all(position, eyev, normalv, light_position, light_color, expected_result);
|
|
}
|
|
|
|
void test_lighting_with_light_behind_surface(void) {
|
|
MATERIAL_Material *material = MATERIAL_new();
|
|
TUPLES_Point *position = TUPLES_new_point(0, 0, 0);
|
|
TUPLES_Vector *eyev = TUPLES_new_vector(0, 0, -1);
|
|
TUPLES_Vector *normalv = TUPLES_new_vector(0, 0, -1);
|
|
|
|
TUPLES_Point *light_position = TUPLES_new_point(0, 0, 10);
|
|
TUPLES_Color *light_color = TUPLES_new_color(1, 1, 1);
|
|
LIGHTS_Light *pl = LIGHTS_new_pointlight(light_position, light_color);
|
|
|
|
SPHERE_set_material(sphere, material);
|
|
TUPLES_Color result;
|
|
MATERIAL_lighting(&result, sphere, pl, position, eyev, normalv, 1.0);
|
|
|
|
TUPLES_Color *expected_result = TUPLES_new_color(0.1, 0.1, 0.1);
|
|
TEST_ASSERT_TRUE(TUPLES_is_equal(expected_result, &result));
|
|
LIGHTS_delete(pl);
|
|
MATERIAL_delete(material);
|
|
TUPLES_delete_all(position, eyev, normalv, light_position, light_color, expected_result);
|
|
}
|
|
|
|
void test_lighting_with_a_pattern(void) {
|
|
MATERIAL_Material *material = MATERIAL_new();
|
|
TUPLES_Color *white = TUPLES_new_color(1, 1, 1);
|
|
TUPLES_Color *black = TUPLES_new_color(0, 0, 0);
|
|
PATTERN_Pattern *pattern = PATTERN_new_stripe(white, black);
|
|
MATERIAL_set_pattern(material, pattern);
|
|
material->ambient = 1;
|
|
material->diffuse = 0;
|
|
material->specular = 0;
|
|
TUPLES_Vector *eyev = TUPLES_new_vector(0, 0, -1);
|
|
TUPLES_Vector *normalv = TUPLES_new_vector(0, 0, -1);
|
|
|
|
TUPLES_Point *light_position = TUPLES_new_point(0, 0, 10);
|
|
TUPLES_Color *light_color = TUPLES_new_color(1, 1, 1);
|
|
LIGHTS_Light *pl = LIGHTS_new_pointlight(light_position, light_color);
|
|
|
|
TUPLES_Point *p1 = TUPLES_new_point(0.9, 0, 0);
|
|
TUPLES_Color c1;
|
|
SPHERE_set_material(sphere, material);
|
|
MATERIAL_lighting(&c1, sphere, pl, p1, eyev, normalv, 1.0);
|
|
TEST_ASSERT_TRUE(TUPLES_is_equal(white, &c1));
|
|
|
|
TUPLES_Point *p2 = TUPLES_new_point(1.1, 0, 0);
|
|
TUPLES_Color c2;
|
|
MATERIAL_lighting(&c2, sphere, pl, p2, eyev, normalv, 1.0);
|
|
TEST_ASSERT_TRUE(TUPLES_is_equal(black, &c2));
|
|
|
|
TUPLES_delete_all(white, black, eyev, normalv, light_color, light_position, p1, p2);
|
|
PATTERN_delete(pattern);
|
|
MATERIAL_delete(material);
|
|
LIGHTS_delete(pl);
|
|
}
|
|
|
|
void test_material_default_reflective_property(void) {
|
|
MATERIAL_Material *mat = MATERIAL_new();
|
|
TEST_ASSERT_EQUAL_DOUBLE(0.0, mat->reflective);
|
|
MATERIAL_delete(mat);
|
|
}
|
|
|
|
void test_material_default_transparency_and_refractive_index(void) {
|
|
MATERIAL_Material *mat = MATERIAL_new();
|
|
TEST_ASSERT_EQUAL_DOUBLE(0.0, mat->transparency);
|
|
TEST_ASSERT_EQUAL_DOUBLE(1.0, mat->refractive_index);
|
|
MATERIAL_delete(mat);
|
|
}
|
|
|
|
void use_light_intensity_to_attenuate_color(double intensity, double r, double g, double b) {
|
|
WORLD_World *world = construct_test_world();
|
|
TUPLES_Point lp;
|
|
TUPLES_init_point(&lp, 0, 0, -10);
|
|
TUPLES_Color lc;
|
|
TUPLES_init_color(&lc, 1, 1, 1);
|
|
LIGHTS_Light *light = LIGHTS_new_pointlight(&lp, &lc);
|
|
WORLD_set_light(world, light);
|
|
|
|
SHAPE_Shape *shape = WORLD_get_object(world, 0);
|
|
MATERIAL_Material *m = SHAPE_get_material(shape);
|
|
m->ambient = 0.1;
|
|
m->diffuse = 0.9;
|
|
m->specular = 0.0;
|
|
TUPLES_init_color(&m->color, 1, 1, 1);
|
|
|
|
TUPLES_Point pt;
|
|
TUPLES_init_point(&pt, 0, 0, -1);
|
|
|
|
TUPLES_Vector eyev, normalv;
|
|
TUPLES_init_vector(&eyev, 0, 0, -1);
|
|
TUPLES_init_vector(&normalv, 0, 0, -1);
|
|
|
|
TUPLES_Color result, expected_result;
|
|
TUPLES_init_color(&expected_result, r, g, b);
|
|
MATERIAL_lighting(&result, shape, light, &pt, &eyev, &normalv, intensity);
|
|
|
|
test_tuples(&expected_result, &result);
|
|
LIGHTS_delete(light);
|
|
destruct_test_world(world);
|
|
}
|
|
|
|
void test_use_light_intensity_to_attenuate_color(void) {
|
|
use_light_intensity_to_attenuate_color(1.0, 1, 1, 1);
|
|
use_light_intensity_to_attenuate_color(0.5, 0.55, 0.55, 0.55);
|
|
use_light_intensity_to_attenuate_color(0.0, 0.1, 0.1, 0.1);
|
|
}
|
|
|
|
void lighting_function_samples_area_light(double x, double y, double z, double r, double g, double b) {
|
|
TUPLES_Point corner;
|
|
TUPLES_init_point(&corner, -0.5, -0.5, -5);
|
|
TUPLES_Vector v1, v2;
|
|
TUPLES_init_vector(&v1, 1, 0, 0);
|
|
TUPLES_init_vector(&v2, 0, 1, 0);
|
|
TUPLES_Color light_color;
|
|
TUPLES_init_color(&light_color, 1, 1, 1);
|
|
LIGHTS_Light *light = LIGHTS_new_arealight(&corner, &v1, 2, &v2, 2, &light_color);
|
|
SPHERE_Sphere *sphere = SPHERE_new();
|
|
MATERIAL_Material *sphere_mat = SPHERE_get_material(sphere);
|
|
sphere_mat->ambient = 0.1;
|
|
sphere_mat->diffuse = 0.9;
|
|
sphere_mat->specular = 0;
|
|
TUPLES_copy(&sphere_mat->color, &light_color);
|
|
TUPLES_Point eye;
|
|
TUPLES_init_point(&eye, 0, 0, -5);
|
|
TUPLES_Point pt;
|
|
TUPLES_init_point(&pt, x, y, z);
|
|
TUPLES_Vector eyev;
|
|
TUPLES_subtract(&eyev, &eye, &pt);
|
|
TUPLES_normalize(&eyev);
|
|
TUPLES_Vector normal_v;
|
|
TUPLES_init_vector(&normal_v, x, y, z);
|
|
TUPLES_Color result, expected_result;
|
|
TUPLES_init_color(&expected_result, r, g, b);
|
|
MATERIAL_lighting(&result, (SHAPE_Shape *)sphere, light, &pt, &eyev, &normal_v, 1.0);
|
|
test_tuples(&expected_result, &result);
|
|
SPHERE_delete(sphere);
|
|
LIGHTS_delete(light);
|
|
}
|
|
|
|
void test_lighting_function_samples_area_light(void) {
|
|
lighting_function_samples_area_light(0, 0, -1, 0.9965, 0.9965, 0.9965);
|
|
lighting_function_samples_area_light(0, 0.7071, -0.7071, 0.6232, 0.6232, 0.6232);
|
|
}
|
|
|
|
void test_create_material_from_yaml(void) {
|
|
char data[] = "\n"
|
|
" color: [0, 0.2, 0.75]\n"
|
|
" ambient: 0.1\n"
|
|
" diffuse: 0.4\n"
|
|
" specular: 0.9\n"
|
|
" shininess: 300\n"
|
|
" reflective: 0.7\n"
|
|
" transparency: 0.8\n"
|
|
" refractive-index: 1.5\n"
|
|
" shadow: false\n\n";
|
|
|
|
MATERIAL_Material *result = MATERIAL_parse_material(data);
|
|
TEST_ASSERT_NOT_NULL(result);
|
|
|
|
TUPLES_Color expected_color;
|
|
TUPLES_init_color(&expected_color, 0, 0.2, 0.75);
|
|
test_tuples(&expected_color, &result->color);
|
|
|
|
TEST_ASSERT_EQUAL_DOUBLE(0.1, result->ambient);
|
|
TEST_ASSERT_EQUAL_DOUBLE(0.4, result->diffuse);
|
|
TEST_ASSERT_EQUAL_DOUBLE(0.9, result->specular);
|
|
TEST_ASSERT_EQUAL_DOUBLE(300, result->shininess);
|
|
TEST_ASSERT_EQUAL_DOUBLE(0.7, result->reflective);
|
|
TEST_ASSERT_EQUAL_DOUBLE(0.8, result->transparency);
|
|
TEST_ASSERT_EQUAL_DOUBLE(1.5, result->refractive_index);
|
|
TEST_ASSERT_FALSE(result->shadow_calc);
|
|
|
|
MATERIAL_delete(result);
|
|
}
|
|
|
|
int main(void) {
|
|
UNITY_BEGIN();
|
|
RUN_TEST(test_default_material);
|
|
RUN_TEST(test_lighting_with_eye_between_light_and_surface);
|
|
RUN_TEST(test_lighting_with_eye_between_light_and_surface_eye_offset_45_deg);
|
|
RUN_TEST(test_lighting_with_eye_opposite_surface_light_offset_45_deg);
|
|
RUN_TEST(test_lighting_with_eye_in_path_of_reflection_vector);
|
|
RUN_TEST(test_lighting_with_light_behind_surface);
|
|
RUN_TEST(test_lighting_with_eye_between_light_and_surface_in_shadow);
|
|
RUN_TEST(test_lighting_with_a_pattern);
|
|
RUN_TEST(test_material_default_reflective_property);
|
|
RUN_TEST(test_material_default_transparency_and_refractive_index);
|
|
RUN_TEST(test_use_light_intensity_to_attenuate_color);
|
|
RUN_TEST(test_lighting_function_samples_area_light);
|
|
RUN_TEST(test_create_material_from_yaml);
|
|
return UNITY_END();
|
|
}
|