Triangle fill iterator function and fixes in line drawing

This commit is contained in:
Andrew Golovashevich 2024-12-25 03:52:09 +03:00
parent 9f129fcbe4
commit fa7f0bd020
6 changed files with 391 additions and 225 deletions

View File

@ -10,6 +10,7 @@
#include <bgtu/computer_graphics_lab_work/qt_utilities/separate_threaded_renderer.hpp> #include <bgtu/computer_graphics_lab_work/qt_utilities/separate_threaded_renderer.hpp>
#include <bgtu/computer_graphics_lab_work/qt_utilities/renderer_widget.hpp> #include <bgtu/computer_graphics_lab_work/qt_utilities/renderer_widget.hpp>
#include <bgtu/computer_graphics_lab_work/qt_utilities/owned_qimage.hpp> #include <bgtu/computer_graphics_lab_work/qt_utilities/owned_qimage.hpp>
#include <bgtu/computer_graphics_lab_work/utilities/shapes/triangle.hpp>
#include "variants/sprite_data.hpp" #include "variants/sprite_data.hpp"
#include "keyboard_catcher_widget.hpp" #include "keyboard_catcher_widget.hpp"
#include "pixel_grid_sprite.hpp" #include "pixel_grid_sprite.hpp"
@ -77,15 +78,29 @@ namespace BGTU::ComputerGraphicsLabWork::Impl {
return 0; return 0;
#else #else
//Utilities::Shapes::iterate_line(-3,-3, 3, 0, [](long long x, long long y) {
// std::cout << x << "\t\t" << y << std::endl;
//});
//return 0;
for (int y = 3; y >= -3; y--) { Utilities::Shapes::iterate_triangle_fill_h_lines(
for (int x = -3; x <= 3; x++) { -1, -3,
// if (x != 0) { 3, 0,
std::cout /*<< '(' << y << ',' << x << '|' << (double)y / (double)x << '|'*/ << std::atan2((double) y , (double) x) / std::numbers::pi_v<double> * 360 << "\t "; -2, 3,
// } [](long long x, long long y) {
} std::cout << x << "\t" << y << std::endl;
std::cout << std::endl; },
} [](long long y, long long x1, long long x2) { std::cout << x1 << ">" << x2 << '\t' << y << std::endl; }
);
// for (int y = 3; y >= -3; y--) {
// for (int x = -3; x <= 3; x++) {
//// if (x != 0) {
// std::cout /*<< '(' << y << ',' << x << '|' << (double)y / (double)x << '|'*/ << std::atan2((double) y , (double) x) / std::numbers::pi_v<double> * 360 << "\t ";
//// }
// }
// std::cout << std::endl;
// }
// auto c = Utilities::apply_transparent_color(*(RendererApi::Color *) &bg, fg); // auto c = Utilities::apply_transparent_color(*(RendererApi::Color *) &bg, fg);
// std::cout << c.red << c.green << c.blue << std::endl; // std::cout << c.red << c.green << c.blue << std::endl;

View File

@ -2,12 +2,30 @@
#include <numbers> #include <numbers>
#include <QMutex> #include <QMutex>
#include <bgtu/computer_graphics_lab_work/utilities/shapes/circle.hpp> #include <bgtu/computer_graphics_lab_work/utilities/shapes/circle.hpp>
#include <bgtu/computer_graphics_lab_work/utilities/shapes/triangle.hpp>
#include <bgtu/computer_graphics_lab_work/utilities/shader.hpp> #include <bgtu/computer_graphics_lab_work/utilities/shader.hpp>
#include "../variants.hpp" #include "../variants.hpp"
#include "../sprite_data.hpp" #include "../sprite_data.hpp"
namespace BGTU::ComputerGraphicsLabWork::Impl::Variants::Lab2 { namespace BGTU::ComputerGraphicsLabWork::Impl::Variants::Lab2 {
namespace { namespace {
class HsvSectorShader : public Utilities::Shader {
private:
RendererApi::PointF<2>::component_t cx, cy;
double angle_offset_radians;
public:
HsvSectorShader(RendererApi::PointF<2>::component_t cx, RendererApi::PointF<2>::component_t cy, double angle_offset_radians) : cx{cx}, cy{cy}, angle_offset_radians{angle_offset_radians} {}
HsvSectorShader(RendererApi::PointF<2> c, double angle_offset_radians) : cx{c.x}, cy{c.y}, angle_offset_radians{angle_offset_radians} {}
HsvSectorShader(RendererApi::PointI<2> c, double angle_offset_radians) : cx{(double) c.x}, cy{(double) c.y}, angle_offset_radians{angle_offset_radians} {}
[[nodiscard]] RendererApi::Color::Transparent get_color(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const final {
double angle = std::atan2(static_cast<double>(y - this->cy), static_cast<double>(x - this->cx)) + this->angle_offset_radians;
return Utilities::hsv_to_rgb_360_1_1(std::fmod(std::fmod(angle / std::numbers::pi_v<double> * 180, 360.0) + 360, 360.0), 1.0, 1.0);
}
};
template<double z, RendererApi::Color::Transparent edge_color, double center_distance_multiplier, double center_angle_degrees, double radius_multiplier> template<double z, RendererApi::Color::Transparent edge_color, double center_distance_multiplier, double center_angle_degrees, double radius_multiplier>
class Circle : public RendererApi::Sprite<SpriteData::ShapeData, Utilities::ZoomedVoxelPainter<Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl>> { class Circle : public RendererApi::Sprite<SpriteData::ShapeData, Utilities::ZoomedVoxelPainter<Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl>> {
private: private:
@ -40,23 +58,6 @@ namespace BGTU::ComputerGraphicsLabWork::Impl::Variants::Lab2 {
} }
}; };
class HsvSectorShader : public Utilities::Shader {
private:
RendererApi::PointF<2>::component_t cx, cy;
double angle_offset_radians;
public:
HsvSectorShader(RendererApi::PointF<2>::component_t cx, RendererApi::PointF<2>::component_t cy, double angle_offset_radians) : cx{cx}, cy{cy}, angle_offset_radians{angle_offset_radians} {}
HsvSectorShader(RendererApi::PointF<2> c, double angle_offset_radians) : cx{c.x}, cy{c.y}, angle_offset_radians{angle_offset_radians} {}
HsvSectorShader(RendererApi::PointI<2> c, double angle_offset_radians) : cx{(double) c.x}, cy{(double) c.y}, angle_offset_radians{angle_offset_radians} {}
[[nodiscard]] RendererApi::Color::Transparent get_color(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const final {
double angle = std::atan2(static_cast<double>(y - this->cy), static_cast<double>(x - this->cx)) + this->angle_offset_radians;
return Utilities::hsv_to_rgb_360_1_1(std::fmod(std::fmod(angle / std::numbers::pi_v<double> * 180, 360.0) + 360, 360.0), 1.0, 1.0);
}
};
enum class ShaderType : unsigned { enum class ShaderType : unsigned {
SOLID_RED, SOLID_RED,
SOLID_GREEN, SOLID_GREEN,
@ -216,9 +217,111 @@ namespace BGTU::ComputerGraphicsLabWork::Impl::Variants::Lab2 {
this->sync.unlock(); this->sync.unlock();
} }
}; };
template<double z, RendererApi::Color::Transparent edge_color, double radius_multiplier>
class Triangle : public RendererApi::Sprite<SpriteData::ShapeData, Utilities::ZoomedVoxelPainter<Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl>> {
private:
enum class ShaderType : unsigned {
SOLID_RED,
SOLID_GREEN,
SOLID_BLUE,
SECTOR_STATIC,
SECTOR_ROTATED_POS,
SECTOR_ROTATED_NEG,
BARYCENTRIC,
BARYCENTRIC_SEMI_TRANSPARENT,
};
static inline ShaderType const next_shader_type[] = {
ShaderType::SOLID_GREEN,
ShaderType::SOLID_BLUE,
ShaderType::SECTOR_STATIC,
ShaderType::SECTOR_ROTATED_POS,
ShaderType::SECTOR_ROTATED_NEG,
ShaderType::BARYCENTRIC,
ShaderType::BARYCENTRIC_SEMI_TRANSPARENT,
ShaderType::SOLID_RED,
};
QMutex sync;
ShaderType current_shader;
template<class receiver_t>
void _select_shader(SpriteData::ShapeData const *data, receiver_t receiver) const {
const_cast<QMutex *>(&(this->sync))->lock();
ShaderType t = this->current_shader;
const_cast<QMutex *>(&(this->sync))->unlock();
switch (t) {
case ShaderType::SOLID_RED: {
auto s = Utilities::MonoShader::static_<RendererApi::Color{255, 0, 0}>;
receiver(s);
return;
}
case ShaderType::SOLID_GREEN: {
auto s = Utilities::MonoShader::static_<RendererApi::Color{0, 255, 0}>;
receiver(s);
return;
}
case ShaderType::SOLID_BLUE: {
auto s = Utilities::MonoShader::static_<RendererApi::Color{0, 0, 255}>;
receiver(s);
return;
}
case ShaderType::SECTOR_STATIC: {
HsvSectorShader s{0, 0, 0};
receiver(s);
return;
}
case ShaderType::SECTOR_ROTATED_POS: {
HsvSectorShader s{0, 0, data->rotation_radians};
receiver(s);
return;
}
case ShaderType::SECTOR_ROTATED_NEG: {
HsvSectorShader s{0, 0, -data->rotation_radians};
receiver(s);
return;
}
case ShaderType::BARYCENTRIC:
case ShaderType::BARYCENTRIC_SEMI_TRANSPARENT:;
}
};
public:
Triangle() : sync{}, current_shader{ShaderType::SOLID_RED} {}
Triangle(Triangle &&other) noexcept: sync{}, current_shader{other.current_shader} {}
void draw(Utilities::ZoomedVoxelPainter<Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl> *frame, SpriteData::ShapeData const *data) const final {
this->_select_shader(
data,
[&]<class shader_t>(shader_t const &shader) {
Utilities::Shapes::iterate_triangle_fill(
data->pos_rotated(data->radius * radius_multiplier, -120.0),
data->pos_rotated(data->radius * radius_multiplier, 0.0),
data->pos_rotated(data->radius * radius_multiplier, 120.0),
[&](bool is_edge, RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t y) {
if (is_edge) {
frame->add_voxel(x, y, z, edge_color);
} else {
frame->add_voxel(x, y, z, shader.get_color(x, y));
}
}
);
}
);
}
void clicked() final {
this->sync.lock();
this->current_shader = next_shader_type[(unsigned) this->current_shader];
this->sync.unlock();
}
};
} }
variant_sprites variant3 = variant_sprites::make( variant_sprites variant3 = variant_sprites::make(
Circle<4.0, {255, 255, 255}, 0.0, 0.0, 1.0>{}, Circle<4.0, {255, 255, 255}, 0.0, 0.0, 1.0>{},
Triangle<3.0, {255, 255, 255}, 1.0>{},
Circle<2.0, {255, 255, 255}, 0.6666666666666, 0.0, 0.16666666666666666>{}, Circle<2.0, {255, 255, 255}, 0.6666666666666, 0.0, 0.16666666666666666>{},
Circle<2.0, {255, 255, 255}, 0.6666666666666, 120.0, 0.16666666666666666>{}, Circle<2.0, {255, 255, 255}, 0.6666666666666, 120.0, 0.16666666666666666>{},
Circle<2.0, {255, 255, 255}, 0.6666666666666, -120.0, 0.16666666666666666>{}, Circle<2.0, {255, 255, 255}, 0.6666666666666, -120.0, 0.16666666666666666>{},

View File

@ -87,7 +87,7 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities {
return dynamic_cast<Shader::Empty const *>(other) == nullptr; return dynamic_cast<Shader::Empty const *>(other) == nullptr;
} }
constexpr Shader::Empty const Shader::empty{}; constexpr inline Shader::Empty const Shader::empty{};
class MonoShader : public Shader { class MonoShader : public Shader {
private: private:

View File

@ -8,8 +8,9 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes {
class brezenham_line_iterable { class brezenham_line_iterable {
private: private:
RendererApi::PointI<2>::component_t start_arg, start_ret, end_arg; RendererApi::PointI<2>::component_t start_arg, start_ret, end_arg;
RendererApi::PointI<2>::component_t delta_ret, delta_arg; RendererApi::PointI<2>::component_t delta_ret;
RendererApi::PointI<2>::component_t delta_error, error_threshold; RendererApi::PointI<2>::component_t delta_error, error_threshold;
bool is_reverse;
bool swap_flag; bool swap_flag;
public: public:
constexpr brezenham_line_iterable( constexpr brezenham_line_iterable(
@ -37,7 +38,7 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes {
this->delta_ret = (x2 > x1) ? 1 : -1; this->delta_ret = (x2 > x1) ? 1 : -1;
this->swap_flag = true; this->swap_flag = true;
} }
this->delta_arg = (this->end_arg > this->start_arg) ? 1 : -1; this->is_reverse = this->end_arg < this->start_arg;
} }
constexpr brezenham_line_iterable( constexpr brezenham_line_iterable(
@ -48,29 +49,54 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes {
class iterator { class iterator {
private: private:
RendererApi::PointI<2>::component_t arg, ret, end_arg; RendererApi::PointI<2>::component_t arg, ret, end_arg;
RendererApi::PointI<2>::component_t delta_ret, delta_arg; RendererApi::PointI<2>::component_t delta_ret;
RendererApi::PointI<2>::component_t error, delta_error, error_threshold; RendererApi::PointI<2>::component_t error, delta_error, error_threshold;
bool swap_flag; bool swap_flag;
RendererApi::PointI<2> point;
bool is_ended;
bool is_reverse;
constexpr iterator( constexpr 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 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_arg, RendererApi::PointI<2>::component_t delta_ret,
RendererApi::PointI<2>::component_t delta_error, RendererApi::PointI<2>::component_t error_threshold, RendererApi::PointI<2>::component_t delta_error, RendererApi::PointI<2>::component_t error_threshold,
bool swap_flag bool swap_flag,
) noexcept: arg{arg}, ret{ret}, end_arg{end_arg}, delta_ret{delta_ret}, delta_arg{delta_arg}, error{0}, delta_error{delta_error}, swap_flag{swap_flag}, error_threshold{error_threshold} {} bool is_reverse
) noexcept:
arg{arg}, ret{ret}, end_arg{end_arg},
delta_ret{delta_ret},
error{0}, delta_error{delta_error}, error_threshold{error_threshold},
swap_flag{swap_flag}, point{swap_flag ? ret : arg, swap_flag ? arg : ret},
is_ended{false},
is_reverse{is_reverse} {}
friend class brezenham_line_iterable; friend class brezenham_line_iterable;
public: public:
constexpr iterator &operator++() noexcept { constexpr iterator &operator++() noexcept {
if (*this == nullptr) if (this->is_ended)
return *this; return *this;
this->arg += this->delta_arg; if (this->is_reverse) {
this->error += this->delta_error; this->arg--;
if (this->error >= this->error_threshold) { this->error += this->delta_error;
this->ret += this->delta_ret; if (this->error >= this->error_threshold) {
this->error -= this->error_threshold; this->ret += this->delta_ret;
this->error -= this->error_threshold;
}
this->is_ended = this->arg < this->end_arg;
} else {
this->arg++;
this->error += this->delta_error;
if (this->error >= this->error_threshold) {
this->ret += this->delta_ret;
this->error -= this->error_threshold;
}
this->is_ended = this->arg > this->end_arg;
} }
if (this->swap_flag)
this->point = {this->ret, this->arg};
else
this->point = {this->arg, this->ret};
return *this; return *this;
} }
@ -81,27 +107,29 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes {
} }
constexpr RendererApi::PointI<2> operator*() const noexcept { constexpr RendererApi::PointI<2> operator*() const noexcept {
if (this->swap_flag) return this->point;
return {this->ret, this->arg}; }
else
return {this->arg, this->ret}; constexpr RendererApi::PointI<2> const *operator->() const noexcept {
return &this->point;
} }
constexpr bool operator==(std::nullptr_t) const noexcept { constexpr bool operator==(std::nullptr_t) const noexcept {
return (this->arg > this->end_arg) ^ (this->delta_arg < 0); return this->is_ended;
} }
constexpr bool operator!=(std::nullptr_t) const noexcept { constexpr bool operator!=(std::nullptr_t) const noexcept {
return !(*this == nullptr); return !this->is_ended;
} }
}; };
[[nodiscard]] constexpr iterator begin() const noexcept { [[nodiscard]] constexpr iterator begin() const noexcept {
return iterator{ return iterator{
this->start_arg, this->start_ret, this->end_arg, this->start_arg, this->start_ret, this->end_arg,
this->delta_ret, this->delta_arg, this->delta_ret,
this->delta_error, this->error_threshold, this->delta_error, this->error_threshold,
this->swap_flag this->swap_flag,
this->is_reverse
}; };
} }
@ -133,7 +161,7 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes {
) { ) {
if (y2 < y1) if (y2 < y1)
std::swap(y1, y2); std::swap(y1, y2);
for (RendererApi::PointI<2>::component_t y = y1; x <= y2; y++) { for (RendererApi::PointI<2>::component_t y = y1; y <= y2; y++) {
receiver(x, y); receiver(x, y);
} }
} }

View File

@ -27,14 +27,14 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes {
auto it = brezenham_line_iterable{points[i - 1], points[i]}.begin(); auto it = brezenham_line_iterable{points[i - 1], points[i]}.begin();
// it++; // it++;
for (; it != nullptr; it++) { for (; it != nullptr; it++) {
receiver((*it).x, (*it).y); receiver(it->x, it->y);
} }
} }
if (points[0] != points[points_count - 1]) { if (points[0] != points[points_count - 1]) {
auto it = brezenham_line_iterable{points[points_count - 1], points[0]}.begin(); auto it = brezenham_line_iterable{points[points_count - 1], points[0]}.begin();
// it++; // it++;
for (; it != nullptr; it++) { for (; it != nullptr; it++) {
receiver((*it).x, (*it).y); receiver(it->x, it->y);
} }
} }
} }

View File

@ -6,170 +6,213 @@
#include <limits> #include <limits>
#include <bgtu/computer_graphics_lab_work/renderer_api/point.hpp> #include <bgtu/computer_graphics_lab_work/renderer_api/point.hpp>
#include "line.hpp" #include "line.hpp"
#include "../shader.hpp"
namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes { namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes {
template<class edge_point_receiver_t, class fill_line_receiver_t>
template<class receiver_t> void iterate_triangle_fill_h_lines(
void iterate_triangle_fill(
RendererApi::PointI<2>::component_t x0, RendererApi::PointI<2>::component_t y0, 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 x1, RendererApi::PointI<2>::component_t y1,
RendererApi::PointI<2>::component_t x2, RendererApi::PointI<2>::component_t y2, RendererApi::PointI<2>::component_t x2, RendererApi::PointI<2>::component_t y2,
receiver_t receiver edge_point_receiver_t edge_point_receiver,
); fill_line_receiver_t fill_line_receiver
) {
class triangle_fill_iterable { 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) {
private: RendererApi::PointI<2>::component_t tmp;
brezenham_line_iterable upper_left; (tmp = *sx0), (*sx0 = *sx1), (*sx1 = tmp);
brezenham_line_iterable lower_left; (tmp = *sy0), (*sy0 = *sy1), (*sy1 = tmp);
brezenham_line_iterable right;
template<class receiver_t>
friend
void iterate_triangle_fill(
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
);
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: if (y0 < y1)
inline triangle_fill_iterable( _swap(&x0, &y0, &x1, &y1);
RendererApi::PointI<2>::component_t x0, RendererApi::PointI<2>::component_t y0, if (y1 < y2)
RendererApi::PointI<2>::component_t x1, RendererApi::PointI<2>::component_t y1, _swap(&x1, &y1, &x2, &y2);
RendererApi::PointI<2>::component_t x2, RendererApi::PointI<2>::component_t y2 if (y0 < y1)
) : triangle_fill_iterable{_pre_constructor::create(x0, y0, x1, y1, x2, y2)} { _swap(&x0, &y0, &x1, &y1);
} if (y0 == y1 && x0 < x1 && y0 != y2)
_swap(&x0, &y0, &x1, &y1);
#if 0 if (y1 == y2 && x2 < x1)
class iterator { _swap(&x1, &y1, &x2, &y2);
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() { auto _impl = [&]<bool is_r2l>(
if (this->upper_left == nullptr) brezenham_line_iterable::iterator upper_cathetus,
return this->lower_left; brezenham_line_iterable::iterator lower_cathetus,
else brezenham_line_iterable::iterator hypotenuse
return this->upper_left; ) {
} RendererApi::PointI<2>::component_t x, ex, y;
public: x = upper_cathetus->x;
inline iterator &operator++() { y = upper_cathetus->y;
if (this->cx < this->ex) { edge_point_receiver(x, y);
this->cx++;
return *this; UPPER_CATHETUS:
upper_cathetus++;
if (upper_cathetus == nullptr) {
goto LOWER_CATHETUS;
} }
if (this->upper_left != nullptr) { if (upper_cathetus->y < y) {
RendererApi::PointI<2>::component_t sx = (*(this->upper_left)).x;
while (true) { while (true) {
this->upper_left++; if constexpr (is_r2l) {
if (this->upper_left == nullptr) if (hypotenuse->x < x) {
goto LOWER; edge_point_receiver(hypotenuse->x, hypotenuse->y);
if ((*(this->upper_left)).y < this->cy) ex = hypotenuse->x;
{ goto HYPOTENUSE_UPPER;
this->cy--; }
return *this; } else {
if (hypotenuse->x > x) {
edge_point_receiver(hypotenuse->x, hypotenuse->y);
ex = hypotenuse->x;
goto HYPOTENUSE_UPPER;
}
}
(*++(this->upper_left)).y >= this->cy hypotenuse++;
if ((*(this->upper_left)).x < sx) if (hypotenuse->y < y) {
return *this; edge_point_receiver(upper_cathetus->x, upper_cathetus->y);
x = upper_cathetus->x;
y = upper_cathetus->y;
goto UPPER_CATHETUS;
}
} }
}
edge_point_receiver(upper_cathetus->x, upper_cathetus->y);
if constexpr (is_r2l) {
x = ((x < upper_cathetus->x) ? x : (upper_cathetus->x));
} else { } else {
LOWER: x = ((x > upper_cathetus->x) ? x : (upper_cathetus->x));
RendererApi::PointI<2>::component_t sx = (*(this->upper_left)).x;
} }
while ((*++(this->right)).y >= this->cy) { goto UPPER_CATHETUS;
if ((*(this->right)).x > this->ex)
return *this; HYPOTENUSE_UPPER:
hypotenuse++;
if (hypotenuse->y < y) {
if constexpr (is_r2l) {
fill_line_receiver(y, ex + 1, x);
} else {
fill_line_receiver(y, x + 1, ex);
}
y--;
x = upper_cathetus->x;
edge_point_receiver(upper_cathetus->x, y);
goto UPPER_CATHETUS;
} }
this->cy--; if constexpr (is_r2l) {
ex = ((ex > hypotenuse->x) ? ex : (hypotenuse->x));
if (hypotenuse->x < x)
edge_point_receiver(hypotenuse->x, hypotenuse->y);
} else {
ex = ((ex < hypotenuse->x) ? ex : (hypotenuse->x));
if (hypotenuse->x > x)
edge_point_receiver(hypotenuse->x, hypotenuse->y);
}
goto HYPOTENUSE_UPPER;
LOWER_CATHETUS:
lower_cathetus++;
if (lower_cathetus == nullptr) {
ex = x;
goto HYPOTENUSE_LOWER;
}
if (lower_cathetus->y < y) {
while (true) {
if constexpr (is_r2l) {
if (hypotenuse->x < x) {
edge_point_receiver(hypotenuse->x, hypotenuse->y);
ex = hypotenuse->x;
goto HYPOTENUSE_LOWER;
}
} else {
if (hypotenuse->x > x) {
edge_point_receiver(hypotenuse->x, hypotenuse->y);
ex = hypotenuse->x;
goto HYPOTENUSE_LOWER;
}
}
hypotenuse++;
if (hypotenuse->y < y) {
edge_point_receiver(lower_cathetus->x, lower_cathetus->y);
x = lower_cathetus->x;
y = lower_cathetus->y;
goto LOWER_CATHETUS;
}
}
}
edge_point_receiver(lower_cathetus->x, lower_cathetus->y);
if constexpr (is_r2l) {
x = ((x < lower_cathetus->x) ? x : (lower_cathetus->x));
} else {
x = ((x > lower_cathetus->x) ? x : (lower_cathetus->x));
}
goto LOWER_CATHETUS;
HYPOTENUSE_LOWER:
hypotenuse++;
if (hypotenuse == nullptr) {
return;
}
if (hypotenuse->y < y) {
if constexpr (is_r2l) {
fill_line_receiver(y, ex + 1, x);
} else {
fill_line_receiver(y, x + 1, ex);
}
y--;
x = lower_cathetus->x;
edge_point_receiver(lower_cathetus->x, y);
goto LOWER_CATHETUS;
}
if constexpr (is_r2l) {
ex = ((ex > hypotenuse->x) ? ex : (hypotenuse->x));
if (hypotenuse->x < x)
edge_point_receiver(hypotenuse->x, hypotenuse->y);
} else {
ex = ((ex < hypotenuse->x) ? ex : (hypotenuse->x));
if (hypotenuse->x > x)
edge_point_receiver(hypotenuse->x, hypotenuse->y);
}
goto HYPOTENUSE_LOWER;
};
auto dir = (x0 - x1) * (y2 - y1) - (x2 - x1) * (y0 - y1);
if (dir > 0) {
_impl.template operator()<true>(
brezenham_line_iterable{x0, y0, x1, y1}.begin(),
brezenham_line_iterable{x1, y1, x2, y2}.begin(),
brezenham_line_iterable{x0, y0, x2, y2}.begin()
);
} else if (dir < 0) {
_impl.template operator()<false>(
brezenham_line_iterable{x0, y0, x1, y1}.begin(),
brezenham_line_iterable{x1, y1, x2, y2}.begin(),
brezenham_line_iterable{x0, y0, x2, y2}.begin()
);
} else {
iterate_line(x0, y0, x2, y2, edge_point_receiver);
} }
}
inline iterator operator++(int) { template<class edge_point_receiver_t, class fill_line_receiver_t>
iterator next = *this; void iterate_triangle_fill_h_lines(
++(*this); RendererApi::PointI<2> p0,
return next; RendererApi::PointI<2> p1,
} RendererApi::PointI<2> p2,
edge_point_receiver_t edge_point_receiver,
inline point operator*() const { fill_line_receiver_t fill_line_receiver
if (this->swap_flag) ) {
return point{this->ret, this->arg}; iterate_triangle_fill_h_lines(
else p0.x, p0.y,
return point{this->arg, this->ret}; p1.x, p1.y,
} p2.x, p2.y,
edge_point_receiver,
inline bool operator==(std::nullptr_t) const { fill_line_receiver
return this->arg >= this->end_arg; );
} }
inline bool operator!=(std::nullptr_t) const {
return this->arg < this->end_arg;
}
};
#endif
};
template<class receiver_t> template<class receiver_t>
void iterate_triangle_fill( void iterate_triangle_fill(
@ -178,40 +221,16 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes {
RendererApi::PointI<2>::component_t x2, RendererApi::PointI<2>::component_t y2, RendererApi::PointI<2>::component_t x2, RendererApi::PointI<2>::component_t y2,
receiver_t receiver receiver_t receiver
) { ) {
triangle_fill_iterable init{x0, y0, x1, y1, x2, y2}; iterate_triangle_fill_h_lines(
auto right = init.right.begin(); x0, y0,
RendererApi::PointI<2>::component_t cy = (*right).y; x1, y1,
RendererApi::PointI<2>::component_t sx = std::numeric_limits<RendererApi::PointI<2>::component_t>::min(); x2, y2,
RendererApi::PointI<2>::component_t ex = std::numeric_limits<RendererApi::PointI<2>::component_t>::max(); [&](RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t y) { receiver(true, x, y); },
[&](RendererApi::PointI<2>::component_t y, RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t ex) {
auto loop = [&](brezenham_line_iterable left) { for (; x < ex; x++)
receiver(false, x, y);
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);
}
} }
template<class receiver_t> template<class receiver_t>
@ -255,7 +274,7 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes {
RendererApi::PointI<2> p1, RendererApi::PointI<2> p1,
RendererApi::PointI<2> p2 RendererApi::PointI<2> p2
) noexcept { ) noexcept {
return (p2.x - p1.x) * (p2.y - p0.y) + (p2.x - p0.x) * (p1.y - p0.y); return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
} }
@ -302,7 +321,7 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes {
} }
}; };
#if 0
class triangle_barycentric_shader : public Shader { class triangle_barycentric_shader : public Shader {
private: private:
triangle_barycentric_interpolator<RendererApi::Color::Transparent> interpolator; triangle_barycentric_interpolator<RendererApi::Color::Transparent> interpolator;
@ -317,4 +336,5 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes {
return this->interpolator.interpolate_point(x, y); return this->interpolator.interpolate_point(x, y);
} }
}; };
#endif
} }