Extracted to libraries renderer interface and utility functions like matrices or line drawing
This commit is contained in:
parent
f285b093cc
commit
cdc8337219
@ -3,7 +3,7 @@ project(cg1)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
find_package (Qt5Widgets REQUIRED)
|
||||
find_package(Qt5Widgets REQUIRED)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
add_executable(
|
||||
@ -23,4 +23,7 @@ add_executable(
|
||||
src/ui.cpp
|
||||
)
|
||||
|
||||
qt5_use_modules(cg1 Widgets)
|
||||
qt5_use_modules(cg1 Widgets)
|
||||
|
||||
add_subdirectory(renderer-api)
|
||||
add_subdirectory(utilities)
|
2
renderer-api/CMakeLists.txt
Normal file
2
renderer-api/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
||||
add_library(renderer_api INTERFACE)
|
||||
target_include_directories(renderer_api INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
@ -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} {}
|
||||
};
|
||||
};
|
||||
}
|
@ -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>;
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "point.hpp"
|
||||
|
||||
namespace BGTU::ComputerGraphicsLabWork::RendererApi {
|
||||
class Projection {
|
||||
public:
|
||||
virtual PointI<2> project(PointF<3> point) = 0;
|
||||
};
|
||||
}
|
@ -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() {};
|
||||
};
|
||||
}
|
@ -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
3
utilities/CMakeLists.txt
Normal 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)
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
@ -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>;
|
||||
}
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
@ -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
19
utilities/src/shader.cpp
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user