diff --git a/raytracing/CMakeLists.txt b/raytracing/CMakeLists.txt index 22bde6f..a4f2e44 100644 --- a/raytracing/CMakeLists.txt +++ b/raytracing/CMakeLists.txt @@ -21,7 +21,10 @@ add_library(raytracing src/lights/point-light.cpp + src/patterns/checkers-pattern.cpp + src/patterns/gradient-pattern.cpp src/patterns/pattern.cpp + src/patterns/ring-pattern.cpp src/patterns/stripe-pattern.cpp src/renderer/camera.cpp diff --git a/raytracing/include/raytracing.h b/raytracing/include/raytracing.h index c50b178..92cece7 100644 --- a/raytracing/include/raytracing.h +++ b/raytracing/include/raytracing.h @@ -35,6 +35,9 @@ #include "lights/point-light.h" +#include "patterns/checkers-pattern.h" +#include "patterns/gradient-pattern.h" +#include "patterns/ring-pattern.h" #include "patterns/stripe-pattern.h" #include "renderer/camera.h" diff --git a/raytracing/src/patterns/checkers-pattern.cpp b/raytracing/src/patterns/checkers-pattern.cpp new file mode 100644 index 0000000..c02e99d --- /dev/null +++ b/raytracing/src/patterns/checkers-pattern.cpp @@ -0,0 +1,55 @@ +/*! + * checkers-pattern.cpp + * + * Copyright (c) 2024, NADAL Jean-Baptiste. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * @Author: NADAL Jean-Baptiste + * @Date: 04/03/2024 + * + */ + +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com + +/* ------------------------------------------------------------------------- */ + +#include + +#include "core/common.h" + +#include "checkers-pattern.h" + +using namespace Raytracer; + +/* ------------------------------------------------------------------------- */ + +CheckersPattern::CheckersPattern(const Color &a_color_a, const Color &a_color_b) : + Pattern(a_color_a, a_color_b) +{ +} + +/* ------------------------------------------------------------------------- */ + +const Color CheckersPattern::pattern_at(const Tuple &a_point) const +{ + double the_sum = std::floor(a_point.x()) + std::floor(a_point.y()) + std::floor(a_point.z()); + if (((int)the_sum % 2) == 0) + return m_a; + + return m_b; +} diff --git a/raytracing/src/patterns/checkers-pattern.h b/raytracing/src/patterns/checkers-pattern.h new file mode 100644 index 0000000..7755467 --- /dev/null +++ b/raytracing/src/patterns/checkers-pattern.h @@ -0,0 +1,52 @@ +/*! + * checkers-pattern.h + * + * Copyright (c) 2024, NADAL Jean-Baptiste. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * @Author: NADAL Jean-Baptiste + * @Date: 04/03/2024 + * + */ + +#ifndef _RAYTRACER_CHECKERS_PATTERN_H +#define _RAYTRACER_CHECKERS_PATTERN_H + +/* ------------------------------------------------------------------------- */ + +#include "core/color.h" +#include "core/matrix.h" +#include "core/tuple.h" + +#include "patterns/pattern.h" + +#include "shapes/shape.h" + +/* ------------------------------------------------------------------------- */ + +namespace Raytracer +{ + class CheckersPattern : public Pattern + { + public: + CheckersPattern(const Color &a_color_a, const Color &a_color_b); + + const Color pattern_at(const Tuple &a_point) const override; + }; +}; // namespace Raytracer + +#endif /* _RAYTRACER_CHECKERS_PATTERN_H */ diff --git a/raytracing/src/patterns/gradient-pattern.cpp b/raytracing/src/patterns/gradient-pattern.cpp new file mode 100644 index 0000000..e832865 --- /dev/null +++ b/raytracing/src/patterns/gradient-pattern.cpp @@ -0,0 +1,54 @@ +/*! + * gradient-pattern.cpp + * + * Copyright (c) 2024, NADAL Jean-Baptiste. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * @Author: NADAL Jean-Baptiste + * @Date: 03/03/2024 + * + */ + +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com + +/* ------------------------------------------------------------------------- */ + +#include + +#include "core/common.h" + +#include "gradient-pattern.h" + +using namespace Raytracer; + +/* ------------------------------------------------------------------------- */ + +GradientPattern::GradientPattern(const Color &a_color_a, const Color &a_color_b) : + Pattern(a_color_a, a_color_b) +{ +} + +/* ------------------------------------------------------------------------- */ + +const Color GradientPattern::pattern_at(const Tuple &a_point) const +{ + Color the_distance = m_b - m_a; + double the_fraction = a_point.x() - std::floor(a_point.x()); + + return m_a + the_distance * the_fraction; +} diff --git a/raytracing/src/patterns/gradient-pattern.h b/raytracing/src/patterns/gradient-pattern.h new file mode 100644 index 0000000..355560c --- /dev/null +++ b/raytracing/src/patterns/gradient-pattern.h @@ -0,0 +1,52 @@ +/*! + * gradient-pattern.h + * + * Copyright (c) 2024, NADAL Jean-Baptiste. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * @Author: NADAL Jean-Baptiste + * @Date: 04/03/2024 + * + */ + +#ifndef _RAYTRACER_GRADIENT_PATTERN_H +#define _RAYTRACER_GRADIENT_PATTERN_H + +/* ------------------------------------------------------------------------- */ + +#include "core/color.h" +#include "core/matrix.h" +#include "core/tuple.h" + +#include "patterns/pattern.h" + +#include "shapes/shape.h" + +/* ------------------------------------------------------------------------- */ + +namespace Raytracer +{ + class GradientPattern : public Pattern + { + public: + GradientPattern(const Color &a_color_a, const Color &a_color_b); + + const Color pattern_at(const Tuple &a_point) const override; + }; +}; // namespace Raytracer + +#endif /* _RAYTRACER_GRADIENT_PATTERN_H */ diff --git a/raytracing/src/patterns/pattern.cpp b/raytracing/src/patterns/pattern.cpp index 51845c0..25d3c5a 100644 --- a/raytracing/src/patterns/pattern.cpp +++ b/raytracing/src/patterns/pattern.cpp @@ -38,13 +38,31 @@ using namespace Raytracer; /* ------------------------------------------------------------------------- */ -Pattern::Pattern(void) +Pattern::Pattern(void) : + m_a(Color::Black()), + m_b(Color::Black()) { m_transform = Matrix::identity(); } /* ------------------------------------------------------------------------- */ +Pattern::Pattern(const Color &a_color_a, const Color &a_color_b) : + m_a(a_color_a), + m_b(a_color_b) +{ + m_transform = Matrix::identity(); +} + +/* ------------------------------------------------------------------------- */ + +bool Pattern::operator==(const Pattern &a_pattern) const +{ + return (m_a == a_pattern.m_a) && (m_b == a_pattern.m_b) && (m_transform == a_pattern.m_transform); +} + +/* ------------------------------------------------------------------------- */ + const Matrix &Pattern::transform(void) const { return m_transform; @@ -59,9 +77,23 @@ void Pattern::set_transform(const Matrix &a_transform_matrix) /* ------------------------------------------------------------------------- */ +const Color &Pattern::a(void) const +{ + return m_a; +} + +/* ------------------------------------------------------------------------- */ + +const Color &Pattern::b(void) const +{ + return m_b; +} + +/* ------------------------------------------------------------------------- */ + const Color Pattern::pattern_at_shape(Shape *a_shape, const Tuple &a_world_point) const { - Tuple the_objet_point = a_shape->transform().inverse() * a_world_point; + Tuple the_objet_point = a_shape->transform().inverse() * a_world_point; Tuple the_pattern_point = m_transform.inverse() * the_objet_point; return pattern_at(the_pattern_point); diff --git a/raytracing/src/patterns/pattern.h b/raytracing/src/patterns/pattern.h index 7ee978c..f5dfe47 100644 --- a/raytracing/src/patterns/pattern.h +++ b/raytracing/src/patterns/pattern.h @@ -42,14 +42,24 @@ namespace Raytracer { public: Pattern(void); + Pattern(const Color &a_color_a, const Color &a_color_b); + + bool operator==(const Pattern &a_pattern) const; const Matrix &transform(void) const; void set_transform(const Matrix &a_transform_matrix); + const Color &a(void) const; + const Color &b(void) const; + const Color pattern_at_shape(Shape *a_shape, const Tuple &a_world_point) const; virtual const Color pattern_at(const Tuple &a_point) const = 0; + protected: + Color m_a; + Color m_b; + private: Matrix m_transform; }; diff --git a/raytracing/src/patterns/ring-pattern.cpp b/raytracing/src/patterns/ring-pattern.cpp new file mode 100644 index 0000000..e12973f --- /dev/null +++ b/raytracing/src/patterns/ring-pattern.cpp @@ -0,0 +1,55 @@ +/*! + * ring-pattern.cpp + * + * Copyright (c) 2024, NADAL Jean-Baptiste. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * @Author: NADAL Jean-Baptiste + * @Date: 03/03/2024 + * + */ + +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com + +/* ------------------------------------------------------------------------- */ + +#include + +#include "core/common.h" + +#include "ring-pattern.h" + +using namespace Raytracer; + +/* ------------------------------------------------------------------------- */ + +RingPattern::RingPattern(const Color &a_color_a, const Color &a_color_b) : + Pattern(a_color_a, a_color_b) +{ +} + +/* ------------------------------------------------------------------------- */ + +const Color RingPattern::pattern_at(const Tuple &a_point) const +{ + double the_sqrt = std::sqrt((a_point.x() * a_point.x()) + (a_point.z() * a_point.z())); + if (((int)std::floor(the_sqrt) % 2) == 0) + return m_a; + + return m_b; +} diff --git a/raytracing/src/patterns/ring-pattern.h b/raytracing/src/patterns/ring-pattern.h new file mode 100644 index 0000000..ffb88f4 --- /dev/null +++ b/raytracing/src/patterns/ring-pattern.h @@ -0,0 +1,52 @@ +/*! + * ring-pattern.h + * + * Copyright (c) 2024, NADAL Jean-Baptiste. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * @Author: NADAL Jean-Baptiste + * @Date: 04/03/2024 + * + */ + +#ifndef _RAYTRACER_RING_PATTERN_H +#define _RAYTRACER_RING_PATTERN_H + +/* ------------------------------------------------------------------------- */ + +#include "core/color.h" +#include "core/matrix.h" +#include "core/tuple.h" + +#include "patterns/pattern.h" + +#include "shapes/shape.h" + +/* ------------------------------------------------------------------------- */ + +namespace Raytracer +{ + class RingPattern : public Pattern + { + public: + RingPattern(const Color &a_color_a, const Color &a_color_b); + + const Color pattern_at(const Tuple &a_point) const override; + }; +}; // namespace Raytracer + +#endif /* _RAYTRACER_RING_PATTERN_H */ diff --git a/raytracing/src/patterns/stripe-pattern.cpp b/raytracing/src/patterns/stripe-pattern.cpp index 6939758..926d031 100644 --- a/raytracing/src/patterns/stripe-pattern.cpp +++ b/raytracing/src/patterns/stripe-pattern.cpp @@ -38,33 +38,13 @@ using namespace Raytracer; /* ------------------------------------------------------------------------- */ -StripePattern::StripePattern(const Color &a_color_a, const Color &a_color_b) : Pattern(), m_a(a_color_a), m_b(a_color_b) +StripePattern::StripePattern(const Color &a_color_a, const Color &a_color_b) : + Pattern(a_color_a, a_color_b) { } /* ------------------------------------------------------------------------- */ -bool StripePattern::operator==(const StripePattern &a_pattern) const -{ - return (m_a == a_pattern.m_a) && (m_b == a_pattern.m_b); -} - -/* ------------------------------------------------------------------------- */ - -const Color &StripePattern::a(void) const -{ - return m_a; -} - -/* ------------------------------------------------------------------------- */ - -const Color &StripePattern::b(void) const -{ - return m_b; -} - -/* ------------------------------------------------------------------------- */ - const Color StripePattern::pattern_at(const Tuple &a_point) const { if (((int)std::floor(a_point.x()) % 2) == 0) diff --git a/raytracing/src/patterns/stripe-pattern.h b/raytracing/src/patterns/stripe-pattern.h index 7144660..72a49ae 100644 --- a/raytracing/src/patterns/stripe-pattern.h +++ b/raytracing/src/patterns/stripe-pattern.h @@ -45,16 +45,7 @@ namespace Raytracer public: StripePattern(const Color &a_color_a, const Color &a_color_b); - bool operator==(const StripePattern &a_pattern) const; - - const Color &a(void) const; - const Color &b(void) const; - const Color pattern_at(const Tuple &a_point) const override; - - private: - Color m_a; - Color m_b; }; }; // namespace Raytracer diff --git a/tests/10_patterns.cpp b/tests/10_patterns.cpp index f442ea4..a229c0b 100644 --- a/tests/10_patterns.cpp +++ b/tests/10_patterns.cpp @@ -393,3 +393,122 @@ SCENARIO("A pattern with both an object and a pattern transformation", "[feature } } } + +/* ------------------------------------------------------------------------- */ + +SCENARIO("A gradient linearly interpolates between colors", "[features/patterns.feature]") +{ + GIVEN("pattern <- gradient_pattern(white, black)") + { + GradientPattern pattern(Color::White(), Color::Black()); + THEN("pattern_at(pattern, point(0, 0, 0)) == white") + { + REQUIRE(pattern.pattern_at(Tuple::Point(0, 0, 0)) == Color::White()); + } + AND_THEN("pattern_at(pattern, point(0.25, 0, 0)) == color(0.75, 0.75, 0.75)") + { + REQUIRE(pattern.pattern_at(Tuple::Point(0.25, 0, 0)) == Color(0.75, 0.75, 0.75)); + } + AND_THEN("pattern_at(pattern, point(0.5, 0, 0)) == color(0.5, 0.5, 0.5)") + { + REQUIRE(pattern.pattern_at(Tuple::Point(0.5, 0, 0)) == Color(0.5, 0.5, 0.5)); + } + AND_THEN("pattern_at(pattern, point(0.75, 0, 0)) == color(0,25, 0.25, 0.25)") + { + REQUIRE(pattern.pattern_at(Tuple::Point(0.75, 0, 0)) == Color(0.25, 0.25, 0.25)); + } + } +} + +/* ------------------------------------------------------------------------- */ + +SCENARIO("A ring should extend in both x and z", "[features/patterns.feature]") +{ + GIVEN("pattern <- ring_pattern(white, black)") + { + RingPattern pattern(Color::White(), Color::Black()); + THEN("pattern_at(pattern, point(0, 0, 0)) == white") + { + REQUIRE(pattern.pattern_at(Tuple::Point(0, 0, 0)) == Color::White()); + } + AND_THEN("pattern_at(pattern, point(1, 0, 0)) == black") + { + REQUIRE(pattern.pattern_at(Tuple::Point(1, 0, 0)) == Color::Black()); + } + AND_THEN("pattern_at(pattern, point(0, 0, 1)) == black") + { + REQUIRE(pattern.pattern_at(Tuple::Point(0, 0, 1)) == Color::Black()); + } + // 0.708 = just slightly more than sqrt(2)2 + AND_THEN("pattern_at(pattern, point(0.708, 0, 0.708)) == black") + { + REQUIRE(pattern.pattern_at(Tuple::Point(0.708, 0, 0.708)) == Color::Black()); + } + } +} + +/* ------------------------------------------------------------------------- */ + +SCENARIO("Checkers should repeat in x", "[features/patterns.feature]") +{ + GIVEN("pattern <- checkers_pattern(white, black)") + { + CheckersPattern pattern(Color::White(), Color::Black()); + THEN("pattern_at(pattern, point(0, 0, 0)) == white") + { + REQUIRE(pattern.pattern_at(Tuple::Point(0, 0, 0)) == Color::White()); + } + AND_THEN("pattern_at(pattern, point(0.99, 0, 0)) == white") + { + REQUIRE(pattern.pattern_at(Tuple::Point(0.99, 0, 0)) == Color::White()); + } + AND_THEN("pattern_at(pattern, point(1.01, 0, 0)) == black") + { + REQUIRE(pattern.pattern_at(Tuple::Point(1.01, 0, 0)) == Color::Black()); + } + } +} + +/* ------------------------------------------------------------------------- */ + +SCENARIO("Checkers should repeat in y", "[features/patterns.feature]") +{ + GIVEN("pattern <- checkers_pattern(white, black)") + { + CheckersPattern pattern(Color::White(), Color::Black()); + THEN("pattern_at(pattern, point(0, 0, 0)) == white") + { + REQUIRE(pattern.pattern_at(Tuple::Point(0, 0, 0)) == Color::White()); + } + AND_THEN("pattern_at(pattern, point(0, 0.99, 0)) == white") + { + REQUIRE(pattern.pattern_at(Tuple::Point(0, 0.99, 0)) == Color::White()); + } + AND_THEN("pattern_at(pattern, point(0, 1.01, 0)) == black") + { + REQUIRE(pattern.pattern_at(Tuple::Point(0, 1.01, 0)) == Color::Black()); + } + } +} + +/* ------------------------------------------------------------------------- */ + +SCENARIO("Checkers should repeat in z", "[features/patterns.feature]") +{ + GIVEN("pattern <- checkers_pattern(white, black)") + { + CheckersPattern pattern(Color::White(), Color::Black()); + THEN("pattern_at(pattern, point(0, 0, 0)) == white") + { + REQUIRE(pattern.pattern_at(Tuple::Point(0, 0, 0)) == Color::White()); + } + AND_THEN("pattern_at(pattern, point(0, 0, 0.99)) == white") + { + REQUIRE(pattern.pattern_at(Tuple::Point(0, 0, 0.99)) == Color::White()); + } + AND_THEN("pattern_at(pattern, point(0, 0, 1.01)) == black") + { + REQUIRE(pattern.pattern_at(Tuple::Point(0, 0, 1.01)) == Color::Black()); + } + } +}