raytracer-c/test/module_raytracer/test_lights.c

258 lines
9.1 KiB
C

#include <lights.h>
#include <sequences.h>
#include <tuples.h>
#include <unity.h>
#include "test_world_utils.h"
#include "../testutils.h"
void setUp(void) {}
void tearDown(void) {}
void test_pointlight_has_position_and_intensity(void) {
TUPLES_Color *c = TUPLES_new_color(1, 1, 1);
TUPLES_Point *p = TUPLES_new_point(0, 0, 0);
LIGHTS_Light *pl = LIGHTS_new_pointlight(p, c);
TEST_ASSERT_TRUE(TUPLES_is_equal(c, &pl->intensity));
TEST_ASSERT_TRUE(TUPLES_is_equal(p, &pl->corner));
TUPLES_delete_all(c, p);
LIGHTS_delete(pl);
}
void test_get_color(void) {
TUPLES_Color *c = TUPLES_new_color(0.1, 0.2, 0.3);
TUPLES_Point *p = TUPLES_new_point(0.4, 0.5, 0.6);
LIGHTS_Light *pl = LIGHTS_new_pointlight(p, c);
const TUPLES_Color *c_returned = LIGHTS_get_color(pl);
TEST_ASSERT_TRUE(TUPLES_is_equal(c, c_returned));
TUPLES_delete_all(c, p);
LIGHTS_delete(pl);
}
void point_lights_evaluate_intensity_at_single_point(double x, double y, double z, double expected_result) {
WORLD_World *world = construct_test_world();
const LIGHTS_Light *light = WORLD_get_light(world);
TUPLES_Point p;
TUPLES_init_point(&p, x, y, z);
double result = LIGHTS_intensity_at(light, &p, world);
if (!double_equal(expected_result, result)) {
printf("Failed for %f, %f, %f expected %f but got %f\n", x, y, z, expected_result, result);
TEST_FAIL();
}
destruct_test_world(world);
}
void test_point_lights_evaluate_intensity_at_single_point(void) {
point_lights_evaluate_intensity_at_single_point(0, 1.0001, 0, 1.0);
point_lights_evaluate_intensity_at_single_point(-1.0001, 0, 0, 1.0);
point_lights_evaluate_intensity_at_single_point(0, 0, -1.0001, 1.0);
point_lights_evaluate_intensity_at_single_point(0, 0, 1.0001, 0.0);
point_lights_evaluate_intensity_at_single_point(1.0001, 0, 0, 0.0);
point_lights_evaluate_intensity_at_single_point(0, -1.0001, 0, 0.0);
point_lights_evaluate_intensity_at_single_point(0, 0, 0, 0.0);
}
void test_create_area_light(void) {
TUPLES_Point corner;
TUPLES_init_point(&corner, 0, 0, 0);
TUPLES_Vector v1, v2;
TUPLES_init_vector(&v1, 2, 0, 0);
TUPLES_init_vector(&v2, 0, 0, 1);
TUPLES_Color color;
TUPLES_init_color(&color, 1, 1, 1);
LIGHTS_Light *light = LIGHTS_new_arealight(&corner, &v1, 4, &v2, 2, &color);
TEST_ASSERT_TRUE(TUPLES_is_equal(&corner, &light->corner));
TUPLES_Vector expected;
TUPLES_init_vector(&expected, 0.5, 0, 0);
TEST_ASSERT_TRUE(TUPLES_is_equal(&light->uvec, &expected));
TUPLES_init_vector(&expected, 0, 0, 0.5);
TEST_ASSERT_TRUE(TUPLES_is_equal(&light->vvec, &expected));
TEST_ASSERT_EQUAL_UINT(4, light->usteps);
TEST_ASSERT_EQUAL_UINT(2, light->vsteps);
TEST_ASSERT_EQUAL_UINT(8, light->samples);
LIGHTS_delete(light);
}
void find_single_point_on_an_area_light(unsigned int u, unsigned int v, double x, double y, double z) {
TUPLES_Point corner;
TUPLES_init_point(&corner, 0, 0, 0);
TUPLES_Vector v1, v2;
TUPLES_init_vector(&v1, 2, 0, 0);
TUPLES_init_vector(&v2, 0, 0, 1);
TUPLES_Color color;
TUPLES_init_color(&color, 1, 1, 1);
LIGHTS_Light *light = LIGHTS_new_arealight(&corner, &v1, 4, &v2, 2, &color);
TUPLES_Point result, expected_result;
LIGHTS_point_on_area_light(&result, light, u, v);
TUPLES_init_point(&expected_result, x, y, z);
TEST_ASSERT_TRUE(TUPLES_is_equal(&expected_result, &result));
LIGHTS_delete(light);
}
void test_find_single_point_on_an_area_light(void) {
find_single_point_on_an_area_light(0, 0, 0.25, 0, 0.25);
find_single_point_on_an_area_light(1, 0, 0.75, 0, 0.25);
find_single_point_on_an_area_light(0, 1, 0.25, 0, 0.75);
find_single_point_on_an_area_light(2, 0, 1.25, 0, 0.25);
find_single_point_on_an_area_light(3, 1, 1.75, 0, 0.75);
}
void area_light_intensity_function(double x, double y, double z, double expected) {
WORLD_World *world = construct_test_world();
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 color;
TUPLES_init_color(&color, 1, 1, 1);
LIGHTS_Light *light = LIGHTS_new_arealight(&corner, &v1, 2, &v2, 2, &color);
TUPLES_Point point;
TUPLES_init_point(&point, x, y, z);
double result = LIGHTS_intensity_at(light, &point, world);
TEST_ASSERT_EQUAL_DOUBLE(expected, result);
destruct_test_world(world);
LIGHTS_delete(light);
}
void test_area_light_intensity_function(void) {
area_light_intensity_function(0, 0, 2, 0);
area_light_intensity_function(1, -1, 2, 0.25);
area_light_intensity_function(1.5, 0, 2, 0.5);
area_light_intensity_function(1.25, 1.25, 3, 0.75);
area_light_intensity_function(0, 0, -2, 1);
}
void find_single_point_on_a_jittered_area(unsigned int u, unsigned int v, double x, double y, double z) {
TUPLES_Point corner;
TUPLES_init_point(&corner, 0, 0, 0);
TUPLES_Vector v1, v2;
TUPLES_init_vector(&v1, 2, 0, 0);
TUPLES_init_vector(&v2, 0, 0, 1);
TUPLES_Color color;
TUPLES_init_color(&color, 1, 1, 1);
LIGHTS_Light *light = LIGHTS_new_arealight(&corner, &v1, 4, &v2, 2, &color);
SEQUENCES_Sequence *seq = SEQUENCES_new(2, (double[]){0.3, 0.7});
LIGHTS_set_jitter_on_area_light(light, seq);
SEQUENCES_delete(seq);
TUPLES_Point expected, result;
TUPLES_init_point(&expected, x, y, z);
LIGHTS_point_on_area_light(&result, light, u, v);
test_tuples(&expected, &result);
LIGHTS_delete(light);
}
void test_find_single_point_on_a_jittered_area(void) {
find_single_point_on_a_jittered_area(0, 0, 0.15, 0, 0.35);
find_single_point_on_a_jittered_area(1, 0, 0.65, 0, 0.35);
find_single_point_on_a_jittered_area(0, 1, 0.15, 0, 0.85);
find_single_point_on_a_jittered_area(2, 0, 1.15, 0, 0.35);
find_single_point_on_a_jittered_area(3, 1, 1.65, 0, 0.85);
}
void area_light_with_jittered_samples(double x, double y, double z, double expected_intensity) {
WORLD_World *world = construct_test_world();
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 color;
TUPLES_init_color(&color, 1, 1, 1);
LIGHTS_Light *light = LIGHTS_new_arealight(&corner, &v1, 2, &v2, 2, &color);
SEQUENCES_Sequence *seq = SEQUENCES_new(5, (double[]){0.7, 0.3, 0.9, 0.1, 0.5});
LIGHTS_set_jitter_on_area_light(light, seq);
SEQUENCES_delete(seq);
TUPLES_Point test_point;
TUPLES_init_point(&test_point, x, y, z);
double result = LIGHTS_intensity_at((LIGHTS_Light *)light, &test_point, world);
TEST_ASSERT_EQUAL_DOUBLE(expected_intensity, result);
destruct_test_world(world);
LIGHTS_delete(light);
}
void test_area_light_with_jittered_samples(void) {
area_light_with_jittered_samples(0, 0, 2, 0.0);
area_light_with_jittered_samples(1, -1, 2, 0.5);
area_light_with_jittered_samples(1.5, 0, 2, 0.75);
area_light_with_jittered_samples(1.25, 1.25, 3, 0.75);
area_light_with_jittered_samples(0, 0, -2, 1.0);
}
void test_get_point_light_from_yaml(void) {
char data[] = "\n"
" at: [ -10, 10, -10 ] \n"
" intensity: [0.5, 0.25, 0.75]\n"
"\n";
LIGHTS_Light *result = LIGHTS_parse_light(data);
TEST_ASSERT_NOT_NULL(result);
TUPLES_Point p;
TUPLES_Color i;
TUPLES_Vector uvec, vvec;
TUPLES_init_point(&p, -10, 10, -10);
TUPLES_init_color(&i, 0.5, 0.25, 0.75);
TUPLES_init_vector(&uvec, 0, 0, 0);
TUPLES_init_vector(&vvec, 0, 0, 0);
test_tuples_str(&p, &result->corner, "Corner");
test_tuples_str(&i, &result->intensity, "Intensity");
test_tuples_str(&uvec, &result->uvec, "uvec");
test_tuples_str(&vvec, &result->vvec, "vvec");
TEST_ASSERT_EQUAL(1, result->usteps);
TEST_ASSERT_EQUAL(1, result->vsteps);
LIGHTS_delete(result);
}
void test_get_area_light_from_yaml(void) {
char data[] = "\n"
" corner: [-1, 2, 4]\n"
" uvec: [2, 0, 0]\n"
" vvec: [0, 2, 0]\n"
" usteps: 10\n"
" vsteps: 20\n"
" jitter: true\n"
" intensity: [1.5, 1.5, 1.5]\n"
"\n";
LIGHTS_Light *result = LIGHTS_parse_light(data);
TEST_ASSERT_NOT_NULL(result);
TUPLES_Point p;
TUPLES_Color i;
TUPLES_Vector uvec, vvec;
TUPLES_init_point(&p, -1, 2, 4);
TUPLES_init_color(&i, 1.5, 1.5, 1.5);
TUPLES_init_vector(&uvec, 0.2, 0, 0);
TUPLES_init_vector(&vvec, 0, 0.1, 0);
test_tuples_str(&p, &result->corner, "Corner");
test_tuples_str(&i, &result->intensity, "Intensity");
test_tuples_str(&uvec, &result->uvec, "uvec");
test_tuples_str(&vvec, &result->vvec, "vvec");
TEST_ASSERT_EQUAL(10, result->usteps);
TEST_ASSERT_EQUAL(20, result->vsteps);
TEST_ASSERT_NOT_NULL(result->sequence);
LIGHTS_delete(result);
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_pointlight_has_position_and_intensity);
RUN_TEST(test_get_color);
RUN_TEST(test_point_lights_evaluate_intensity_at_single_point);
RUN_TEST(test_create_area_light);
RUN_TEST(test_find_single_point_on_an_area_light);
RUN_TEST(test_area_light_intensity_function);
RUN_TEST(test_find_single_point_on_a_jittered_area);
RUN_TEST(test_area_light_with_jittered_samples);
RUN_TEST(test_get_point_light_from_yaml);
RUN_TEST(test_get_area_light_from_yaml);
return UNITY_END();
}