Skip to content

Commit 6fbf080

Browse files
stevenewaldglasss13
authored andcommitted
Added colors and display coordinate abstraction
1 parent 53e7190 commit 6fbf080

9 files changed

+275
-75
lines changed

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ add_library(
1919
fractal-generator_lib OBJECT
2020
source/lib.cpp
2121
source/graphics/basic_display.cpp
22+
source/graphics/color_conversions.cpp
2223
)
2324

2425
target_include_directories(

source/config.hpp

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
#pragma once
22

3+
#include <cstddef>
4+
35
namespace fractal {
4-
constexpr auto WINDOW_WIDTH = 800UZ;
5-
constexpr auto WINDOW_HEIGHT = 600UZ;
6-
constexpr auto FRAME_RATE{60UZ};
6+
constexpr std::size_t WINDOW_WIDTH = 800UZ;
7+
constexpr std::size_t WINDOW_HEIGHT = 600UZ;
8+
constexpr std::size_t FRAME_RATE = 60UZ;
79
} // namespace fractal

source/coordinates.hpp

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#pragma once
2+
3+
#include <complex>
4+
5+
namespace fractal {
6+
using display_coordinate = std::pair<uint16_t, uint16_t>;
7+
using complex_coordinate = std::complex<float>;
8+
9+
struct display_domain {
10+
display_coordinate start_coordinate;
11+
display_coordinate end_coordinate;
12+
13+
class DisplayCoordinateIterator {
14+
display_coordinate current_coordinate_;
15+
display_coordinate end_coordinate_;
16+
17+
public:
18+
explicit DisplayCoordinateIterator(const display_domain& domain) :
19+
current_coordinate_{domain.start_coordinate},
20+
end_coordinate_{domain.end_coordinate}
21+
{}
22+
23+
const display_coordinate& operator*() const { return current_coordinate_; }
24+
25+
DisplayCoordinateIterator& operator++()
26+
{
27+
if (current_coordinate_.first == end_coordinate_.first) [[unlikely]] {
28+
current_coordinate_.first = 0;
29+
current_coordinate_.second++;
30+
}
31+
else {
32+
current_coordinate_.first++;
33+
}
34+
return *this;
35+
}
36+
37+
bool operator==(const DisplayCoordinateIterator&) const = default;
38+
};
39+
40+
DisplayCoordinateIterator begin() const { return DisplayCoordinateIterator{*this}; }
41+
42+
DisplayCoordinateIterator end() const
43+
{
44+
return DisplayCoordinateIterator{
45+
display_domain{end_coordinate, end_coordinate}
46+
};
47+
}
48+
};
49+
50+
struct complex_domain {
51+
complex_coordinate start_coordinate;
52+
complex_coordinate end_coordinate;
53+
};
54+
55+
inline float real_domain_size(const complex_domain& domain)
56+
{
57+
return domain.end_coordinate.real() - domain.start_coordinate.real();
58+
}
59+
60+
inline float imaginary_domain_size(const complex_domain& domain)
61+
{
62+
return domain.end_coordinate.imag() - domain.start_coordinate.imag();
63+
}
64+
65+
} // namespace fractal

source/graphics/basic_display.cpp

+20-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,27 @@
11
#include "basic_display.hpp"
22

3+
#include "graphics/color_conversions.hpp"
4+
35
#include <fmt/format.h>
46
#include <SFML/Graphics.hpp>
57
#include <SFML/Graphics/RectangleShape.hpp>
68

9+
#include <cmath>
10+
711
namespace fractal {
8-
void BasicDisplay::set_pixel(std::size_t x_pos, std::size_t y_pos, uint8_t value)
12+
void BasicDisplay::set_pixel(display_coordinate coordinate, uint16_t value)
13+
{
14+
pixels_.at(coordinate.first).at(coordinate.second) = value;
15+
}
16+
17+
std::tuple<int, int, int> interpolateColor(
18+
float t, std::tuple<int, int, int> color1, std::tuple<int, int, int> color2
19+
)
920
{
10-
pixels_.at(x_pos).at(y_pos) = value;
21+
int r = std::get<0>(color1) + t * (std::get<0>(color2) - std::get<0>(color1));
22+
int g = std::get<1>(color1) + t * (std::get<1>(color2) - std::get<1>(color1));
23+
int b = std::get<2>(color1) + t * (std::get<2>(color2) - std::get<2>(color1));
24+
return {r, g, b};
1125
}
1226

1327
void BasicDisplay::display_window()
@@ -20,10 +34,12 @@ void BasicDisplay::display_window()
2034
image.create(WINDOW_WIDTH, WINDOW_HEIGHT);
2135
for (std::size_t x_pos = 0; x_pos < WINDOW_WIDTH; ++x_pos) {
2236
for (std::size_t y_pos = 0; y_pos < WINDOW_HEIGHT; ++y_pos) {
23-
std::uint8_t pixel_value = pixels_.at(x_pos).at(y_pos);
37+
std::uint16_t pixel_value = pixels_.at(x_pos).at(y_pos);
38+
auto tuple = number_to_rgb(pixel_value);
39+
2440
image.setPixel(
2541
static_cast<unsigned int>(x_pos), static_cast<unsigned int>(y_pos),
26-
sf::Color(pixel_value, pixel_value, pixel_value)
42+
sf::Color(std::get<0>(tuple), std::get<1>(tuple), std::get<2>(tuple))
2743
);
2844
}
2945
}

source/graphics/basic_display.hpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include "config.hpp"
4+
#include "coordinates.hpp"
45

56
#include <SFML/System/Vector2.hpp>
67

@@ -12,7 +13,7 @@
1213

1314
namespace fractal {
1415
class BasicDisplay {
15-
std::array<std::array<uint8_t, WINDOW_HEIGHT>, WINDOW_WIDTH> pixels_{};
16+
std::array<std::array<uint16_t, WINDOW_HEIGHT>, WINDOW_WIDTH> pixels_{};
1617
std::function<void(sf::Vector2f, sf::Vector2f)> on_resize_;
1718

1819
public:
@@ -22,7 +23,7 @@ class BasicDisplay {
2223
) : on_resize_(std::move(on_resize))
2324
{}
2425

25-
void set_pixel(std::size_t x_pos, std::size_t y_pos, std::uint8_t value);
26+
void set_pixel(display_coordinate coordinate, uint16_t value);
2627
void display_window();
2728
};
2829
} // namespace fractal

source/graphics/color_conversions.cpp

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#include "color_conversions.hpp"
2+
3+
#include <cmath>
4+
5+
namespace fractal {
6+
std::tuple<uint16_t, uint16_t, uint16_t>
7+
hsv_to_rgb(float hue, float saturation, float value)
8+
{
9+
float chroma = value * saturation;
10+
float hue_prime = hue / 60.0f;
11+
float uint16_termediate =
12+
chroma * (1 - static_cast<float>(std::fabs(std::fmod(hue_prime, 2) - 1)));
13+
float red_temp = 0.0f;
14+
float green_temp = 0.0f;
15+
float blue_temp = 0.0f;
16+
17+
if (0 <= hue_prime && hue_prime < 1) {
18+
red_temp = chroma;
19+
green_temp = uint16_termediate;
20+
blue_temp = 0;
21+
}
22+
else if (1 <= hue_prime && hue_prime < 2) {
23+
red_temp = uint16_termediate;
24+
green_temp = chroma;
25+
blue_temp = 0;
26+
}
27+
else if (2 <= hue_prime && hue_prime < 3) {
28+
red_temp = 0;
29+
green_temp = chroma;
30+
blue_temp = uint16_termediate;
31+
}
32+
else if (3 <= hue_prime && hue_prime < 4) {
33+
red_temp = 0;
34+
green_temp = uint16_termediate;
35+
blue_temp = chroma;
36+
}
37+
else if (4 <= hue_prime && hue_prime < 5) {
38+
red_temp = uint16_termediate;
39+
green_temp = 0;
40+
blue_temp = chroma;
41+
}
42+
else if (5 <= hue_prime && hue_prime < 6) {
43+
red_temp = chroma;
44+
green_temp = 0;
45+
blue_temp = uint16_termediate;
46+
}
47+
48+
float match_value = value - chroma;
49+
float red = red_temp + match_value;
50+
float green = green_temp + match_value;
51+
float blue = blue_temp + match_value;
52+
53+
auto red_int = static_cast<uint16_t>(red * 255);
54+
auto green_int = static_cast<uint16_t>(green * 255);
55+
auto blue_int = static_cast<uint16_t>(blue * 255);
56+
57+
return {red_int, green_int, blue_int};
58+
}
59+
60+
std::tuple<uint16_t, uint16_t, uint16_t> number_to_rgb(uint16_t number)
61+
{
62+
float hue = (static_cast<float>(number) / 65535.0f) * 360.0f;
63+
float saturation = 1.0f;
64+
float value = 1.0f;
65+
66+
return hsv_to_rgb(hue, saturation, value);
67+
}
68+
} // namespace fractal

source/graphics/color_conversions.hpp

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#pragma once
2+
3+
#include <cstdint>
4+
5+
#include <tuple>
6+
7+
namespace fractal {
8+
std::tuple<uint16_t, uint16_t, uint16_t>
9+
hsv_to_rgb(float hue, float saturation, float value);
10+
11+
std::tuple<uint16_t, uint16_t, uint16_t> number_to_rgb(uint16_t number);
12+
} // namespace fractal
+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#pragma once
2+
3+
#include "coordinates.hpp"
4+
5+
#include <complex>
6+
7+
namespace fractal {
8+
class DisplayToComplexCoordinates {
9+
float real_scaling_factor_;
10+
float imaginary_scaling_factor_;
11+
complex_coordinate complex_domain_start_;
12+
13+
static float real_scaling_factor(
14+
const display_coordinate& display_top_right,
15+
const complex_domain& complex_domain
16+
)
17+
{
18+
float real_d_size = real_domain_size(complex_domain);
19+
return real_d_size / static_cast<float>(display_top_right.first);
20+
}
21+
22+
static float imaginary_scaling_factor(
23+
const display_coordinate& display_top_right,
24+
const complex_domain& complex_domain
25+
)
26+
{
27+
float imaginary_d_size = imaginary_domain_size(complex_domain);
28+
return imaginary_d_size / static_cast<float>(display_top_right.second);
29+
}
30+
31+
static complex_coordinate to_complex(display_coordinate coordinate)
32+
{
33+
return {
34+
static_cast<float>(coordinate.first), static_cast<float>(coordinate.second)
35+
};
36+
}
37+
38+
public:
39+
DisplayToComplexCoordinates(
40+
display_coordinate display_top_right, const complex_domain& complex_domain
41+
) :
42+
real_scaling_factor_(real_scaling_factor(display_top_right, complex_domain)),
43+
imaginary_scaling_factor_(
44+
imaginary_scaling_factor(display_top_right, complex_domain)
45+
),
46+
complex_domain_start_(complex_domain.start_coordinate)
47+
{}
48+
49+
complex_coordinate to_complex_projection(display_coordinate display_coord)
50+
{
51+
std::complex<float> raw_complex_coord = to_complex(display_coord);
52+
std::complex offset = {
53+
real_scaling_factor_ * raw_complex_coord.real(),
54+
imaginary_scaling_factor_ * raw_complex_coord.imag()
55+
};
56+
return complex_domain_start_ + offset;
57+
}
58+
};
59+
} // namespace fractal

0 commit comments

Comments
 (0)