diff --git a/source/include/light.h b/source/include/light.h index 2309e93..c83ae34 100644 --- a/source/include/light.h +++ b/source/include/light.h @@ -27,6 +27,10 @@ public: public: Light(LightType type = POINT_LIGHT, Tuple position=Point(0, 0, 0), Colour intensity=Colour(1, 1, 1)) : type(type), position(position), intensity(intensity) { }; + + bool operator==(const Light &b) const { return this->intensity == b.intensity && + this->position == b.position && + this->type == b.type; }; }; #endif //DORAYME_LIGHT_H diff --git a/source/include/shape.h b/source/include/shape.h index 8ad3fa1..ba0fa09 100644 --- a/source/include/shape.h +++ b/source/include/shape.h @@ -17,16 +17,25 @@ class Shape; #include #include +enum ShapeType +{ + SHAPE_NONE, + SHAPE_SPHERE, +}; + /* Base class for all object that can be presented in the world */ class Shape { +private: + ShapeType type; + public: Matrix transformMatrix; Matrix inverseTransform; Material material; public: - Shape(); + Shape(ShapeType = SHAPE_NONE); virtual Intersect intersect(Ray r); virtual Tuple normalAt(Tuple point); @@ -35,6 +44,11 @@ public: void setMaterial(Material material) { this->material = material; }; Ray transform(Ray r) { return Ray(this->transformMatrix * r.origin, this->transformMatrix * r.direction); }; Ray invTransform(Ray r) { return Ray(this->inverseTransform * r.origin, this->inverseTransform * r.direction); }; + + bool operator==(const Shape &b) const { return this->material == b.material && + this->type == b.type && + this->transformMatrix == b.transformMatrix; }; + }; #endif //DORAYME_SHAPE_H diff --git a/source/include/sphere.h b/source/include/sphere.h index a1d4ccc..23df51c 100644 --- a/source/include/sphere.h +++ b/source/include/sphere.h @@ -16,6 +16,7 @@ class Sphere : public Shape { public: + Sphere() : Shape(SHAPE_SPHERE) { }; /* All sphere are at (0, 0, 0) and radius 1 in the object space */ virtual Intersect intersect(Ray r); virtual Tuple normalAt(Tuple point); diff --git a/source/include/world.h b/source/include/world.h index 6ff1afe..a4116b3 100644 --- a/source/include/world.h +++ b/source/include/world.h @@ -12,6 +12,8 @@ #include #include #include +#include +#include class World { @@ -23,11 +25,22 @@ private: uint32_t allocatedObjectCount; uint32_t allocatedLightCount; - Light *lightList; - Shape *shapeList; + Light* *lightList; + Shape* *objectList; public: - World() : objectCount(0), lightCount(0) { }; + World(); + ~World(); + + void addObject(Shape *s); + void addLight(Light *l); + + /* Some debug things */ + bool lightIsIn(Light &l); + bool objectIsIn(Shape &s); + + Intersect intersect(Ray r); + }; #endif //DORAYME_WORLD_H diff --git a/source/include/worldbuilder.h b/source/include/worldbuilder.h index 2c291dd..39aa7f6 100644 --- a/source/include/worldbuilder.h +++ b/source/include/worldbuilder.h @@ -13,14 +13,14 @@ /* Let's keep a single header for now, will see later */ -class DefaultWorld : World +class DefaultWorld : public World { public: DefaultWorld(); }; /* Not implemented yet */ -class Hw3File : World +class Hw3File : public World { public: Hw3File(const char *filename); diff --git a/source/intersect.cpp b/source/intersect.cpp index 09da1d9..52b380f 100644 --- a/source/intersect.cpp +++ b/source/intersect.cpp @@ -17,16 +17,16 @@ Intersect::Intersect() { this->allocated = MIN_ALLOC; - this->list = (Intersection *)calloc(sizeof(Shape *), MIN_ALLOC); + this->list = (Intersection *)calloc(sizeof(Intersection *), MIN_ALLOC); this->num = 0; } void Intersect::add(Intersection i) { - if ((this->num + 1) < this->allocated) + if ((this->num + 1) > this->allocated) { this->allocated *= 2; - this->list = (Intersection *)realloc(this->list, sizeof(Shape *) * this->allocated); + this->list = (Intersection *)realloc(this->list, sizeof(Intersection *) * this->allocated); } this->list[this->num++] = i; } diff --git a/source/shapes/shape.cpp b/source/shapes/shape.cpp index 078e11d..5182a08 100644 --- a/source/shapes/shape.cpp +++ b/source/shapes/shape.cpp @@ -13,8 +13,9 @@ #include #include -Shape::Shape() +Shape::Shape(ShapeType type) { + this->type = type; this->transformMatrix = Matrix4().identity(); this->inverseTransform = this->transformMatrix.inverse(); } diff --git a/source/world.cpp b/source/world.cpp index f894007..936ab95 100644 --- a/source/world.cpp +++ b/source/world.cpp @@ -5,4 +5,89 @@ * Created by Manoƫl Trapier * Copyright (c) 2020 986-Studio. * - */ \ No newline at end of file + */ +#include +#include +#include + +#define MIN_ALLOC (2) + +World::World() : objectCount(0), lightCount(0) +{ + this->allocatedLightCount = MIN_ALLOC; + this->lightList = (Light **)calloc(sizeof(Light *), MIN_ALLOC); + this->lightCount = 0; + + this->allocatedObjectCount = MIN_ALLOC; + this->objectList = (Shape **)calloc(sizeof(Shape *), MIN_ALLOC); + this->objectCount = 0; +}; + +World::~World() +{ + /* We need to do some cleanup... */ +} + +void World::addObject(Shape *s) +{ + if ((this->objectCount + 1) > this->allocatedObjectCount) + { + this->allocatedObjectCount *= 2; + this->objectList = (Shape **)realloc(this->objectList, sizeof(Shape **) * this->allocatedObjectCount); + } + this->objectList[this->objectCount++] = s; +} + +void World::addLight(Light *l) +{ + if ((this->lightCount + 1) > this->allocatedLightCount) + { + this->allocatedLightCount *= 2; + this->lightList = (Light **)realloc(this->lightList, sizeof(Light **) * this->allocatedLightCount); + } + this->lightList[this->lightCount++] = l; +} + +bool World::lightIsIn(Light &l) +{ + int i; + for(i = 0; i < this->lightCount; i++) + { + if (*this->lightList[i] == l) + { + return true; + } + } + return false; +} + +bool World::objectIsIn(Shape &s) +{ + int i; + for(i = 0; i < this->objectCount; i++) + { + if (*this->objectList[i] == s) + { + return true; + } + } + return false; +} + +Intersect World::intersect(Ray r) +{ + Intersect ret; + int i, j; + + for(i = 0; i < this->objectCount; i++) + { + Intersect xs = this->objectList[i]->intersect(r); + + for(j = 0; xs.count(); j++) + { + ret.add(xs[i]); + } + } + + return ret; +} \ No newline at end of file diff --git a/source/worldbuilder/default_world.cpp b/source/worldbuilder/default_world.cpp index b64d130..17b59bf 100644 --- a/source/worldbuilder/default_world.cpp +++ b/source/worldbuilder/default_world.cpp @@ -9,7 +9,26 @@ #include #include +#include +#include +#include +#include + DefaultWorld::DefaultWorld() { + Light *l = new Light(POINT_LIGHT, Point(-10, 10, -10), Colour(1, 1, 1)); + Sphere *s1 = new Sphere(); + Sphere *s2 = new Sphere(); + Material s1Mat = Material(); + s1Mat.colour = Colour(0.8, 1.0, 0.6); + s1Mat.diffuse = 0.7; + s1Mat.specular = 0.2; + s1->setMaterial(s1Mat); -} \ No newline at end of file + s2->setTransform(scaling(0.5, 0.5,0.5)); + + this->addLight(l); + + this->addObject(s1); + this->addObject(s2); +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7b43349..bf52b63 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -4,7 +4,7 @@ set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) set(TESTS_SRC tuple_test.cpp colour_test.cpp canvas_test.cpp matrix_test.cpp transformation_test.cpp ray_test.cpp - intersect_test.cpp sphere_test.cpp light_test.cpp material_test.cpp) + intersect_test.cpp sphere_test.cpp light_test.cpp material_test.cpp world_test.cpp) add_executable(testMyRays) target_include_directories(testMyRays PUBLIC ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR}) diff --git a/tests/world_test.cpp b/tests/world_test.cpp index c0a00c1..c971c01 100644 --- a/tests/world_test.cpp +++ b/tests/world_test.cpp @@ -7,11 +7,54 @@ * */ #include +#include +#include +#include +#include +#include #include #include -TEST(WorldTest, Test_for_an_empty_world) +TEST(WorldTest, Creating_a_world) { + World w; + + ASSERT_EQ(w.lightCount, 0); + ASSERT_EQ(w.objectCount, 0); +} + +TEST(WorldTest, The_default_world) +{ + World w = DefaultWorld(); + + Light l = Light(POINT_LIGHT, Point(-10, 10, -10), Colour(1, 1, 1)); + Sphere s1 = Sphere(); + Sphere s2 = Sphere(); + Material s1Mat = Material(); + s1Mat.colour = Colour(0.8, 1.0, 0.6); + s1Mat.diffuse = 0.7; + s1Mat.specular = 0.2; + s1.setMaterial(s1Mat); + + s2.setTransform(scaling(0.5, 0.5,0.5)); + + ASSERT_TRUE(w.lightIsIn(l)); + ASSERT_TRUE(w.objectIsIn(s1)); + ASSERT_TRUE(w.objectIsIn(s2)); +}; + +TEST(WorldTest, Intersect_a_world_with_a_ray) +{ + World w = DefaultWorld(); + Ray r = Ray(Point(0, 0, -5), Vector(0, 0, 1)); + + Intersect xs = w.intersect(r); + + ASSERT_EQ(xs.count(), 4); + ASSERT_EQ(xs[0].t, 4); + ASSERT_EQ(xs[1].t, 4.5); + ASSERT_EQ(xs[2].t, 5.5); + ASSERT_EQ(xs[3].t, 6); +} -} \ No newline at end of file