Extracted to libraries renderer interface and utility functions like matrices or line drawing

This commit is contained in:
Andrew Golovashevich 2024-12-08 06:50:58 +03:00
parent f285b093cc
commit cdc8337219
13 changed files with 795 additions and 2 deletions

View File

@ -3,7 +3,7 @@ project(cg1)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
find_package (Qt5Widgets REQUIRED) find_package(Qt5Widgets REQUIRED)
set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOMOC ON)
add_executable( add_executable(
@ -23,4 +23,7 @@ add_executable(
src/ui.cpp src/ui.cpp
) )
qt5_use_modules(cg1 Widgets) qt5_use_modules(cg1 Widgets)
add_subdirectory(renderer-api)
add_subdirectory(utilities)

View File

@ -0,0 +1,2 @@
add_library(renderer_api INTERFACE)
target_include_directories(renderer_api INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)

View File

@ -0,0 +1,38 @@
#pragma once
#include <cstdint>
namespace BGTU::ComputerGraphicsLabWork::RendererApi {
class Color {
public:
using component_fast_t = std::uint_fast8_t;
using component_compact_t = std::uint_least8_t;
static constexpr component_fast_t component_min_value = 0;
static constexpr component_fast_t component_max_value = 255;
component_compact_t red;
component_compact_t green;
component_compact_t blue;
inline Color() : red{0}, green{0}, blue{0} {}
inline Color(component_fast_t red, component_fast_t green, component_fast_t blue) : red{red}, green{green}, blue{blue} {}
class Transparent {
public:
component_compact_t red;
component_compact_t green;
component_compact_t blue;
component_compact_t alpha;
inline Transparent() : red{component_min_value}, green{component_min_value}, blue{component_min_value}, alpha{component_max_value} {}
inline Transparent(component_fast_t red, component_fast_t green, component_fast_t blue) : red{red}, green{green}, blue{blue}, alpha{component_max_value} {}
inline Transparent(component_fast_t red, component_fast_t green, component_fast_t blue, component_fast_t alpha) : red{red}, green{green}, blue{blue}, alpha{alpha} {}
inline Transparent(Color c) : red{c.red}, green{c.green}, blue{c.blue}, alpha{component_max_value} {}
};
};
}

View File

@ -0,0 +1,39 @@
#pragma once
#include <cstdint>
namespace BGTU::ComputerGraphicsLabWork::RendererApi {
template<unsigned DIMENSIONS, class _component_t>
class Point {
static_assert(DIMENSIONS == 2 || DIMENSIONS == 3);
};
template<class _component_t>
class Point<2, _component_t> {
public:
using component_t = _component_t;
component_t x;
component_t y;
inline Point(component_t x, component_t y) : x{x}, y{y} {}
};
template<class _component_t>
class Point<3, _component_t> {
public:
using component_t = _component_t;
component_t x;
component_t y;
component_t z;
inline Point(component_t x, component_t y, component_t z) : x{x}, y{y}, z{z} {}
};
template<unsigned DIMENSIONS>
using PointI = Point<DIMENSIONS, long long>;
template<unsigned DIMENSIONS>
using PointF = Point<DIMENSIONS, double>;
}

View File

@ -0,0 +1,10 @@
#pragma once
#include "point.hpp"
namespace BGTU::ComputerGraphicsLabWork::RendererApi {
class Projection {
public:
virtual PointI<2> project(PointF<3> point) = 0;
};
}

View File

@ -0,0 +1,14 @@
#pragma once
#include "voxel_drawer.hpp"
#include "projection.hpp"
namespace BGTU::ComputerGraphicsLabWork::RendererApi {
template<class data_t>
class Sprite {
public:
virtual void draw(VoxelDrawer *frame, Projection *projection, data_t *data) const = 0;
virtual void clicked() {};
};
}

View File

@ -0,0 +1,31 @@
#pragma once
#include <cstdint>
#include <limits>
#include "color.hpp"
#include "point.hpp"
namespace BGTU::ComputerGraphicsLabWork::RendererApi {
class VoxelDrawer {
public:
using visible_pixel_coordinate_fast_t = std::uint_fast16_t;
using visible_pixel_coordinate_compact_t = std::uint_least16_t;
static constexpr visible_pixel_coordinate_fast_t visible_pixel_min_x = 0;
static constexpr visible_pixel_coordinate_fast_t visible_pixel_min_y = 0;
static constexpr visible_pixel_coordinate_fast_t visible_pixel_max_x = std::numeric_limits<visible_pixel_coordinate_compact_t>::max();
static constexpr visible_pixel_coordinate_fast_t visible_pixel_max_y = std::numeric_limits<visible_pixel_coordinate_compact_t>::max();
[[nodiscard]] virtual visible_pixel_coordinate_fast_t width() const = 0;
[[nodiscard]] virtual visible_pixel_coordinate_fast_t height() const = 0;
virtual void update_pixel(PointI<2>::component_t x, PointI<2>::component_t y, double z, Color::Transparent c) = 0;
inline void update_pixel(PointI<2> p, double z, Color::Transparent c) {
return this->update_pixel(p.x, p.y, z, c);
}
};
}

3
utilities/CMakeLists.txt Normal file
View File

@ -0,0 +1,3 @@
add_library(utilities OBJECT src/shader.cpp)
target_include_directories(utilities PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(utilities PUBLIC renderer_api)

View File

@ -0,0 +1,105 @@
#pragma once
#include <cstdlib>
#include <bgtu/computer_graphics_lab_work/renderer_api/point.hpp>
namespace BGTU::ComputerGraphicsLabWork::Utilities {
class brezenham_line_iterable {
private:
RendererApi::PointI<2>::component_t start_arg, start_ret, end_arg;
RendererApi::PointI<2>::component_t delta_ret;
RendererApi::PointI<2>::component_t delta_error, error_threshold;
bool swap_flag;
public:
inline brezenham_line_iterable(RendererApi::PointI<2>::component_t x1, RendererApi::PointI<2>::component_t y1, RendererApi::PointI<2>::component_t x2, RendererApi::PointI<2>::component_t y2) {
RendererApi::PointI<2>::component_t delta_x = (x1 > x2) ? (x1 - x2) : (x2 - x1);
RendererApi::PointI<2>::component_t delta_y = (y1 > y2) ? (y1 - y2) : (y2 - y1);
if (delta_x > delta_y) {
this->start_arg = x1;
this->start_ret = y1;
this->end_arg = x2;
this->delta_error = (RendererApi::PointI<2>::component_t) (delta_y + 1);
this->error_threshold = (RendererApi::PointI<2>::component_t) (delta_x + 1);
this->delta_ret = (y2 > y1) ? 1 : -1;
this->swap_flag = false;
} else {
this->start_arg = y1;
this->start_ret = x1;
this->end_arg = y2;
this->delta_error = (RendererApi::PointI<2>::component_t) (delta_x + 1);
this->error_threshold = (RendererApi::PointI<2>::component_t) (delta_y + 1);
this->delta_ret = (x2 > x1) ? 1 : -1;
this->swap_flag = true;
}
}
struct point {
public:
RendererApi::PointI<2>::component_t x, y;
inline point(RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t y) : x{x}, y{y} {}
};
class iterator {
private:
RendererApi::PointI<2>::component_t arg, ret, end_arg;
RendererApi::PointI<2>::component_t delta_ret;
RendererApi::PointI<2>::component_t error, delta_error, error_threshold;
bool swap_flag;
inline iterator(
RendererApi::PointI<2>::component_t arg, RendererApi::PointI<2>::component_t ret, RendererApi::PointI<2>::component_t end_arg,
RendererApi::PointI<2>::component_t delta_ret,
RendererApi::PointI<2>::component_t delta_error, RendererApi::PointI<2>::component_t error_threshold,
bool swap_flag
) : arg{arg}, ret{ret}, end_arg{end_arg}, delta_ret{delta_ret}, error{0}, delta_error{delta_error}, swap_flag{swap_flag}, error_threshold{error_threshold} {}
friend class brezenham_line_iterable;
public:
inline iterator &operator++() {
this->arg++;
this->error += this->delta_error;
if (this->error >= this->error_threshold) {
this->ret += this->delta_ret;
this->error -= this->error_threshold;
}
return *this;
}
inline iterator operator++(int) {
iterator next = *this;
++(*this);
return next;
}
inline point operator*() const {
if (this->swap_flag)
return point{this->ret, this->arg};
else
return point{this->arg, this->ret};
}
inline bool operator==(std::nullptr_t) const {
return this->arg > this->end_arg;
}
inline bool operator!=(std::nullptr_t) const {
return this->arg <= this->end_arg;
}
};
[[nodiscard]] inline iterator begin() const {
return iterator{
this->start_arg, this->start_ret, this->end_arg,
this->delta_ret,
this->delta_error, this->error_threshold,
this->swap_flag
};
}
[[nodiscard]] inline std::nullptr_t end() const {
return nullptr;
}
};
}

View File

@ -0,0 +1,273 @@
#pragma once
#include <cstdlib>
#include <cmath>
#include <bgtu/computer_graphics_lab_work/renderer_api/point.hpp>
namespace BGTU::ComputerGraphicsLabWork::Utilities {
template<class elem_t>
class Matrix3 {
private:
elem_t data[3][3];
public:
inline Matrix3(
elem_t e00, elem_t e01, elem_t e02,
elem_t e10, elem_t e11, elem_t e12,
elem_t e20, elem_t e21, elem_t e22
) : data{e00, e01, e02, e10, e11, e12, e20, e21, e22} {}
static inline const Matrix3<elem_t> I{1, 0, 0,
0, 1, 0,
0, 0, 1};
private:
static inline const Matrix3<elem_t> _tmp{};
template<class operator_t>
Matrix3<elem_t> _zipmap_matrix(Matrix3<elem_t> const *other, operator_t op) const {
Matrix3<elem_t> dst;
auto _map_row = [&](std::size_t row_index) {
dst.data[row_index][0] = op(row_index, 0, this->data[row_index][0], other->data[row_index][0]);
dst.data[row_index][1] = op(row_index, 1, this->data[row_index][1], other->data[row_index][1]);
dst.data[row_index][2] = op(row_index, 2, this->data[row_index][2], other->data[row_index][2]);
};
_map_row(0);
_map_row(1);
_map_row(2);
return dst;
}
public:
inline Matrix3<elem_t> operator+(Matrix3<elem_t> const &other) const {
return this->_zipmap_matrix(&other, [](auto, auto, auto s, auto o) { return s + o; });
}
inline Matrix3<elem_t> operator-(Matrix3<elem_t> const &other) const {
return this->_zipmap_matrix(&other, [](auto, auto, auto s, auto o) { return s - o; });
}
inline Matrix3<elem_t> operator*(int other) const {
return this->_zipmap_matrix(&Matrix3::_tmp, [=](auto, auto, auto s, auto) { return s * other; });
}
inline Matrix3<elem_t> operator*(long other) const {
return this->_zipmap_matrix(&Matrix3::_tmp, [=](auto, auto, auto s, auto) { return s * other; });
}
inline Matrix3<elem_t> operator*(float other) const {
return this->_zipmap_matrix(&Matrix3::_tmp, [=](auto, auto, auto s, auto) { return s * other; });
}
inline Matrix3<elem_t> operator*(double other) const {
return this->_zipmap_matrix(&Matrix3::_tmp, [=](auto, auto, auto s, auto) { return s * other; });
}
inline Matrix3<elem_t> operator/(int other) const {
return this->_zipmap_matrix(&Matrix3::_tmp, [=](auto, auto, auto s, auto) { return s / other; });
}
inline Matrix3<elem_t> operator/(long other) const {
return this->_zipmap_matrix(&Matrix3::_tmp, [=](auto, auto, auto s, auto) { return s / other; });
}
inline Matrix3<elem_t> operator/(float other) const {
return this->_zipmap_matrix(&Matrix3::_tmp, [=](auto, auto, auto s, auto) { return s / other; });
}
inline Matrix3<elem_t> operator/(double other) const {
return this->_zipmap_matrix(&Matrix3::_tmp, [=](auto, auto, auto s, auto) { return s / other; });
}
inline Matrix3<elem_t> operator*(Matrix3<elem_t> const &other) const {
return this->_zipmap_matrix(&Matrix3::_tmp, [&](auto y, auto x, auto, auto) {
return this->data[y][0] * other.data[0][x] + this->data[y][1] * other.data[1][x] + this->data[y][2] * other.data[2][x];
});
}
static Matrix3<elem_t> scale(elem_t x, elem_t y) {
return Matrix3<elem_t>{x, 0, 0,
0, y, 0,
0, 0, 1};
}
static Matrix3<elem_t> rotate(elem_t radians) {
auto s = std::sin(radians);
auto c = std::cos(radians);
return Matrix3<elem_t>{c, -s, 0,
s, c, 0,
0, 0, 1};
}
static Matrix3<elem_t> shift(elem_t x, elem_t y) {
return Matrix3<elem_t>{1, 0, x,
0, 1, y,
0, 0, 1};
}
RendererApi::Point<2, elem_t> operator*(RendererApi::Point<2, elem_t> other) const {
return RendererApi::Point<2, elem_t>{
this->data[0][0] * other.x + this->data[0][1] * other.y + this->data[0][2],
this->data[1][0] * other.x + this->data[1][1] * other.y + this->data[1][2],
};
}
};
using Matrix3i = Matrix3<int>;
using Matrix3l = Matrix3<long>;
using Matrix3f = Matrix3<float>;
using Matrix3d = Matrix3<double>;
template<class elem_t>
class Matrix4 {
private:
elem_t data[4][4];
Matrix4() = default;
public:
#if 0
inline Matrix4(
std::initializer_list<elem_t> r0,
std::initializer_list<elem_t> r1,
std::initializer_list<elem_t> r2,
std::initializer_list<elem_t> r3
) : data{r0, r1, r2, r3} {}
#endif
inline Matrix4(
elem_t e00, elem_t e01, elem_t e02, elem_t e03,
elem_t e10, elem_t e11, elem_t e12, elem_t e13,
elem_t e20, elem_t e21, elem_t e22, elem_t e23,
elem_t e30, elem_t e31, elem_t e32, elem_t e33
) : data{e00, e01, e02, e03, e10, e11, e12, e13, e20, e21, e22, e23, e30, e31, e32, e33} {}
static inline const Matrix4<elem_t> I{1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1};
private:
static inline const Matrix4<elem_t> _tmp{};
template<class operator_t>
Matrix4<elem_t> _zipmap_matrix(Matrix4<elem_t> const *other, operator_t op) const {
Matrix4<elem_t> dst;
auto _map_row = [&](std::size_t row_index) {
dst.data[row_index][0] = op(row_index, 0, this->data[row_index][0], other->data[row_index][0]);
dst.data[row_index][1] = op(row_index, 1, this->data[row_index][1], other->data[row_index][1]);
dst.data[row_index][2] = op(row_index, 2, this->data[row_index][2], other->data[row_index][2]);
dst.data[row_index][3] = op(row_index, 3, this->data[row_index][3], other->data[row_index][3]);
};
_map_row(0);
_map_row(1);
_map_row(2);
_map_row(3);
return dst;
}
public:
inline Matrix4<elem_t> operator+(Matrix4<elem_t> const &other) const {
return this->_zipmap_matrix(&other, [](auto, auto, auto s, auto o) { return s + o; });
}
inline Matrix4<elem_t> operator-(Matrix4<elem_t> const &other) const {
return this->_zipmap_matrix(&other, [](auto, auto, auto s, auto o) { return s - o; });
}
inline Matrix4<elem_t> operator*(int other) const {
return this->_zipmap_matrix(&Matrix4::_tmp, [=](auto, auto, auto s, auto) { return s * other; });
}
inline Matrix4<elem_t> operator*(long other) const {
return this->_zipmap_matrix(&Matrix4::_tmp, [=](auto, auto, auto s, auto) { return s * other; });
}
inline Matrix4<elem_t> operator*(float other) const {
return this->_zipmap_matrix(&Matrix4::_tmp, [=](auto, auto, auto s, auto) { return s * other; });
}
inline Matrix4<elem_t> operator*(double other) const {
return this->_zipmap_matrix(&Matrix4::_tmp, [=](auto, auto, auto s, auto) { return s * other; });
}
inline Matrix4<elem_t> operator/(int other) const {
return this->_zipmap_matrix(&Matrix4::_tmp, [=](auto, auto, auto s, auto) { return s / other; });
}
inline Matrix4<elem_t> operator/(long other) const {
return this->_zipmap_matrix(&Matrix4::_tmp, [=](auto, auto, auto s, auto) { return s / other; });
}
inline Matrix4<elem_t> operator/(float other) const {
return this->_zipmap_matrix(&Matrix4::_tmp, [=](auto, auto, auto s, auto) { return s / other; });
}
inline Matrix4<elem_t> operator/(double other) const {
return this->_zipmap_matrix(&Matrix4::_tmp, [=](auto, auto, auto s, auto) { return s / other; });
}
inline Matrix4<elem_t> operator*(Matrix4<elem_t> const &other) const {
return this->_zipmap_matrix(&Matrix4::_tmp, [&](auto y, auto x, auto, auto) {
return this->data[y][0] * other.data[0][x] + this->data[y][1] * other.data[1][x] + this->data[y][2] * other.data[2][x] + this->data[y][3] * other.data[3][x];
});
}
static Matrix4<elem_t> scale(elem_t x, elem_t y, elem_t z) {
return Matrix4<elem_t>{x, 0, 0, 0,
0, y, 0, 0,
0, 0, z, 0,
0, 0, 0, 1};
}
static Matrix4<elem_t> rotate_x(elem_t radians) {
auto s = std::sin(radians);
auto c = std::cos(radians);
return Matrix4<elem_t>{1, 0, 0, 0,
0, c, -s, 0,
0, s, c, 0,
0, 0, 0, 1};
}
static Matrix4<elem_t> rotate_y(elem_t radians) {
auto s = std::sin(radians);
auto c = std::cos(radians);
return Matrix4<elem_t>{c, 0, s, 0,
0, 1, 0, 0,
-s, 0, c, 0,
0, 0, 0, 1};
}
static Matrix4<elem_t> rotate_z(elem_t radians) {
auto s = std::sin(radians);
auto c = std::cos(radians);
return Matrix4<elem_t>{c, -s, 0, 0,
s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1};
}
static Matrix4<elem_t> shift(elem_t x, elem_t y, elem_t z) {
return Matrix4<elem_t>{1, 0, 0, x,
0, 1, 0, y,
0, 0, 1, z,
0, 0, 0, 1};
}
RendererApi::Point<3, elem_t> operator*(RendererApi::Point<3, elem_t> other) const {
return RendererApi::Point<3, elem_t>{
this->data[0][0] * other.x + this->data[0][1] * other.y + this->data[0][2] * other.z + this->data[0][3],
this->data[1][0] * other.x + this->data[1][1] * other.y + this->data[1][2] * other.z + this->data[1][3],
this->data[2][0] * other.x + this->data[2][1] * other.y + this->data[2][2] * other.z + this->data[2][3],
};
}
};
using Matrix4i = Matrix4<int>;
using Matrix4l = Matrix4<long>;
using Matrix4f = Matrix4<float>;
using Matrix4d = Matrix4<double>;
}

View File

@ -0,0 +1,42 @@
#pragma once
#include <bgtu/computer_graphics_lab_work/renderer_api/color.hpp>
#include "matrix.hpp"
namespace BGTU::ComputerGraphicsLabWork::Utilities {
class Shader {
public:
[[nodiscard]] virtual RendererApi::Color::Transparent get_color(double x, double y) const = 0;
static Shader const *empty_shader;
};
class MonoShader : public Shader {
private:
RendererApi::Color::Transparent c;
public:
inline explicit MonoShader(RendererApi::Color::Transparent c) : c{c} {}
[[nodiscard]] inline RendererApi::Color::Transparent get_color(double x, double y) const override {
return this->c;
};
};
class TransformedShader : public Shader {
private:
Shader const *shader;
Matrix4d transform;
public:
inline TransformedShader(Shader const *s, Matrix4d t) : shader{s}, transform{t} {}
[[nodiscard]] inline RendererApi::Color::Transparent get_color(double x, double y) const override {
RendererApi::PointF<3> in{x, y, 0};
RendererApi::PointF<3> out = this->transform * in;
return this->shader->get_color(out.x, out.y);
}
};
}

View File

@ -0,0 +1,214 @@
#pragma once
#include <cstdlib>
#include <utility>
#include <limits>
#include <bgtu/computer_graphics_lab_work/renderer_api/point.hpp>
#include "brezenham.hpp"
namespace BGTU::ComputerGraphicsLabWork::Utilities {
template<class receiver_t>
void fill_triangle(
RendererApi::PointI<2>::component_t x0, RendererApi::PointI<2>::component_t y0,
RendererApi::PointI<2>::component_t x1, RendererApi::PointI<2>::component_t y1,
RendererApi::PointI<2>::component_t x2, RendererApi::PointI<2>::component_t y2,
receiver_t receiver
) noexcept(receiver(static_cast<bool>(false), static_cast<RendererApi::PointI<2>::component_t>(0), static_cast<RendererApi::PointI<2>::component_t>(0)));
class triangle_fill_iterable {
private:
brezenham_line_iterable upper_left;
brezenham_line_iterable lower_left;
brezenham_line_iterable right;
template<class receiver_t>
friend
void fill_triangle(
RendererApi::PointI<2>::component_t x0, RendererApi::PointI<2>::component_t y0,
RendererApi::PointI<2>::component_t x1, RendererApi::PointI<2>::component_t y1,
RendererApi::PointI<2>::component_t x2, RendererApi::PointI<2>::component_t y2,
receiver_t
) noexcept(std::declval<receiver_t>()(static_cast<bool>(false), static_cast<RendererApi::PointI<2>::component_t>(0), static_cast<RendererApi::PointI<2>::component_t>(0)));
inline triangle_fill_iterable(
brezenham_line_iterable upper_left,
brezenham_line_iterable lower_left,
brezenham_line_iterable right
) : upper_left{upper_left}, lower_left{lower_left}, right{right} {}
struct _pre_constructor {
private:
inline static void sort_points(RendererApi::PointI<2>::component_t *x0, RendererApi::PointI<2>::component_t *y0, RendererApi::PointI<2>::component_t *x1,RendererApi::PointI<2>::component_t *y1, RendererApi::PointI<2>::component_t *x2, RendererApi::PointI<2>::component_t *y2) {
auto _swap = [](RendererApi::PointI<2>::component_t *sx0, RendererApi::PointI<2>::component_t *sy0, RendererApi::PointI<2>::component_t *sx1, RendererApi::PointI<2>::component_t *sy1) {
RendererApi::PointI<2>::component_t tmp;
tmp = *sx0;
*sx0 = *sx1;
*sx1 = tmp;
tmp = *sy0;
*sy0 = *sy1;
*sy1 = tmp;
};
if (*y0 < *y1)
_swap(x0, y0, x1, y1);
if (*y1 < *y2)
_swap(x1, y1, x2, y2);
if (*y0 < *y1)
_swap(x0, y0, x1, y1);
if (*y0 == *y1 && *x0 < *x1)
_swap(x0, y0, x1, y1);
if (*y1 == *y2 && *x2 < *x1)
_swap(x1, y1, x2, y2);
}
public:
static inline triangle_fill_iterable create(
RendererApi::PointI<2>::component_t x0, RendererApi::PointI<2>::component_t y0,
RendererApi::PointI<2>::component_t x1, RendererApi::PointI<2>::component_t y1,
RendererApi::PointI<2>::component_t x2, RendererApi::PointI<2>::component_t y2
) {
_pre_constructor::sort_points(&x0, &y0, &x1, &y1, &x2, &y2);
return triangle_fill_iterable{brezenham_line_iterable{x0, y0, x1, y1}, brezenham_line_iterable{x1, y1, x2, y2}, brezenham_line_iterable{x0, y0, x2, y2}};
}
};
public:
inline triangle_fill_iterable(
RendererApi::PointI<2>::component_t x0, RendererApi::PointI<2>::component_t y0,
RendererApi::PointI<2>::component_t x1, RendererApi::PointI<2>::component_t y1,
RendererApi::PointI<2>::component_t x2, RendererApi::PointI<2>::component_t y2
) : triangle_fill_iterable{_pre_constructor::create(x0, y0, x1, y1, x2, y2)} {
}
#if 0
class iterator {
private:
brezenham_line_iterable::iterator upper_left;
brezenham_line_iterable::iterator lower_left;
brezenham_line_iterable::iterator right;
RendererApi::PointI<2>::component_t cx, ex, cy;
friend class triangle_fill;
inline iterator(
brezenham_line_iterable const &upper_left,
brezenham_line_iterable const &lower_left,
brezenham_line_iterable const &right
) : upper_left{upper_left.begin()}, lower_left{lower_left.begin()}, right{right.begin()}, cx{(*this->upper_left).x}, ex{(*this->right).x}, cy{(*this->upper_left).y} {}
brezenham_line_iterable::iterator &_left() {
if (this->upper_left == nullptr)
return this->lower_left;
else
return this->upper_left;
}
public:
inline iterator &operator++() {
if (this->cx < this->ex) {
this->cx++;
return *this;
}
if (this->upper_left != nullptr) {
RendererApi::PointI<2>::component_t sx = (*(this->upper_left)).x;
while (true) {
this->upper_left++;
if (this->upper_left == nullptr)
goto LOWER;
if ((*(this->upper_left)).y < this->cy)
{
this->cy--;
return *this;
(*++(this->upper_left)).y >= this->cy
if ((*(this->upper_left)).x < sx)
return *this;
}
} else {
LOWER:
RendererApi::PointI<2>::component_t sx = (*(this->upper_left)).x;
}
while ((*++(this->right)).y >= this->cy) {
if ((*(this->right)).x > this->ex)
return *this;
}
this->cy--;
}
inline iterator operator++(int) {
iterator next = *this;
++(*this);
return next;
}
inline point operator*() const {
if (this->swap_flag)
return point{this->ret, this->arg};
else
return point{this->arg, this->ret};
}
inline bool operator==(std::nullptr_t) const {
return this->arg >= this->end_arg;
}
inline bool operator!=(std::nullptr_t) const {
return this->arg < this->end_arg;
}
};
#endif
};
template<class receiver_t>
void fill_triangle(
RendererApi::PointI<2>::component_t x0, RendererApi::PointI<2>::component_t y0,
RendererApi::PointI<2>::component_t x1, RendererApi::PointI<2>::component_t y1,
RendererApi::PointI<2>::component_t x2, RendererApi::PointI<2>::component_t y2,
receiver_t receiver
) noexcept(receiver(static_cast<bool>(false), static_cast<RendererApi::PointI<2>::component_t>(0), static_cast<RendererApi::PointI<2>::component_t>(0))) {
triangle_fill_iterable init{x0, y0, x1, y1, x2, y2};
auto right = init.right.begin();
RendererApi::PointI<2>::component_t cy = (*right).y;
RendererApi::PointI<2>::component_t sx = std::numeric_limits<RendererApi::PointI<2>::component_t>::min();
RendererApi::PointI<2>::component_t ex = std::numeric_limits<RendererApi::PointI<2>::component_t>::max();
auto loop = [&](brezenham_line_iterable left) {
for (auto lp: left) {
if (lp.y == cy) {
receiver(true, lp.x, lp.y);
sx = (lp.x > sx) ? (lp.x) : sx;
continue;
}
for (; (*right).y > lp.y; right++) {
if ((*right).x > sx)
receiver(true, (*right).x, (*right).y);
ex = ((*right).x < ex) ? ((*right).x) : ex;
}
for (RendererApi::PointI<2>::component_t x = sx + 1; x < ex; x++)
receiver(false, x, cy);
cy--;
receiver(true, lp.x, lp.y);
}
};
loop(init.upper_left);
loop(init.lower_left);
for (; right != nullptr; right++) {
if ((*right).x > sx)
receiver(true, (*right).x, (*right).y);
}
}
}

19
utilities/src/shader.cpp Normal file
View File

@ -0,0 +1,19 @@
#include <bgtu/computer_graphics_lab_work/renderer_api/color.hpp>
#include <bgtu/computer_graphics_lab_work/utilities/shader.hpp>
namespace BGTU::ComputerGraphicsLabWork::Utilities {
class EmptyShader : public Shader {
public:
EmptyShader() = default;
[[nodiscard]] RendererApi::Color::Transparent get_color(double x, double y) const override {
return RendererApi::Color::Transparent{0, 0, 0, 0};
}
};
static const EmptyShader empty_shader_instance;
Shader const *Shader::empty_shader = &empty_shader_instance;
}