A class is the central principle of the object-oriented programming paradigm and will be very useful for the architecture of our raytracer.
We will use classes for our mathematical modeling, which will greatly facilitate our operations.
For this example, we will model a color, which is simply a vector (or tuple) containing three values: red, green, and blue:
(r, g, b)
Red = (1, 0, 0)
Green = (0, 1, 0)
Blue = (0, 0, 1)
Yellow = (1, 1, 0)
....
White = (1, 1, 1)
Black = (0, 0, 0)
Have you ever heard of a pixel? It's actually a tuple containing the three floating point values for red, green, and blue!
In C++, we manage dependencies by first specifying the interfaces of our classes (using h files), and then implementing those interfaces in cpp files.
Let's define our interface to represent a color (in src/raymath/Color.hpp):
#pragma once#include <iostream>classColor{private:float r =0;float b =0;float g =0;public:Color();Color(floatr,floatg,floatb);~Color();floatR();floatG();floatB();Coloroperator+(Colorconst&col);Color&operator=(Colorconst&col);friendstd::ostream&operator<<(std::ostream&_stream,Colorconst&col);};
We define three private values, r, g, and b. We also define two constructor functions:
One that initializes the color to black
Another that takes three parameters and initializes the color accordingly.
It is always a good idea to include a destructor function—the function that will be called when the object instance is destroyed (to clean up the memory).
We have defined two operators that will make our lives easier when using this class:
+: which will allow us to use the + symbol between two objects of type Color, thus performing the color equivalent of an addition.
<<: which will allow us to serialize our Color in an iostream to facilitate debugging.
Now let's look at the implementation (in src/raymath/Color.cpp):
Compiling this library
We want to develop a number of classes such as Color in our project. It is useful to group them together in a library.
In CMake, we proceed as follows:
Add the file src/raymath/CMakeLists.txt, with the instruction to build our new class:
cmake_minimum_required(VERSION 3.5.0)
project(raytracer VERSION 0.1.0 LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
add_executable(raytracer main.cpp)
# Add these lines
target_include_directories(raytracer PUBLIC
"${PROJECT_BINARY_DIR}"
"${PROJECT_SOURCE_DIR}/src/raymath"
)
add_subdirectory(./src/raymath)
target_link_libraries(raytracer PUBLIC raymath)
#include <iostream>
// Include our class definition - we can read it thanks to `target_include_directories`
#include "Color.hpp"
using namespace std;
int main()
{
Color red(1, 0, 0);
Color green(0, 1, 0);
Color black;
// We can chain our color instances using << thanks to our operator !
cout << "Red : " << red << std::endl;
cout << "Green : " << green << std::endl;
cout << "Black : " << black << std::endl;
// We can perform an addition + operation thanks to our operator !
Color yellow = red + green;
cout << "Yellow : " << yellow << std::endl;
}