Circular shaders
This commit is contained in:
parent
3360e35186
commit
9f129fcbe4
@ -1,3 +1,4 @@
|
||||
#include <cmath>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <QApplication>
|
||||
@ -77,12 +78,19 @@ namespace BGTU::ComputerGraphicsLabWork::Impl {
|
||||
return 0;
|
||||
#else
|
||||
|
||||
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);
|
||||
// std::cout << c.red << c.green << c.blue << std::endl;
|
||||
|
||||
auto c = Utilities::apply_transparent_color(*(RendererApi::Color*)&bg, fg);
|
||||
std::cout << c.red << c.green << c.blue << std::endl;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
#include <cmath>
|
||||
#include <numbers>
|
||||
#include <QMutex>
|
||||
#include <bgtu/computer_graphics_lab_work/utilities/shapes/circle.hpp>
|
||||
#include <bgtu/computer_graphics_lab_work/utilities/shader.hpp>
|
||||
@ -9,7 +11,51 @@ namespace BGTU::ComputerGraphicsLabWork::Impl::Variants::Lab2 {
|
||||
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>> {
|
||||
private:
|
||||
QMutex sync;
|
||||
template<RendererApi::Color::Transparent c1, RendererApi::Color::Transparent c2>
|
||||
class RadialShader : public Utilities::Shader {
|
||||
private:
|
||||
RendererApi::PointF<2>::component_t cx, cy;
|
||||
RendererApi::PointF<2>::component_t radius;
|
||||
public:
|
||||
RadialShader(RendererApi::PointF<2>::component_t cx, RendererApi::PointF<2>::component_t cy, RendererApi::PointF<2>::component_t radius) : cx{cx}, cy{cy}, radius{radius} {}
|
||||
|
||||
RadialShader(RendererApi::PointF<2> c, RendererApi::PointF<2>::component_t radius) : cx{c.x}, cy{c.y}, radius{radius} {}
|
||||
|
||||
RadialShader(RendererApi::PointI<2> c, RendererApi::PointF<2>::component_t radius) : cx{(double) c.x}, cy{(double) c.y}, radius{radius} {}
|
||||
|
||||
[[nodiscard]] RendererApi::Color::Transparent get_color(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const final {
|
||||
RendererApi::PointF<2>::component_t distance = std::hypot(x - this->cx, y - this->cy);
|
||||
double ratio = distance / this->radius;
|
||||
float c1v;
|
||||
|
||||
if (ratio < 0.5) {
|
||||
c1v = (float) (std::fabs(ratio - 0.25) * 4);
|
||||
} else if (ratio < 1.0) {
|
||||
c1v = (float) (std::fabs(ratio - 0.75) * 4);
|
||||
} else {
|
||||
return c1;
|
||||
}
|
||||
|
||||
return Utilities::colors_gradient(c1, c1v, c2);
|
||||
}
|
||||
};
|
||||
|
||||
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 {
|
||||
SOLID_RED,
|
||||
@ -29,8 +75,31 @@ namespace BGTU::ComputerGraphicsLabWork::Impl::Variants::Lab2 {
|
||||
SECTOR_ROTATED_NEG,
|
||||
};
|
||||
|
||||
static inline ShaderType const next_shader_type[] = {
|
||||
ShaderType::SOLID_GREEN,
|
||||
ShaderType::SOLID_BLUE,
|
||||
ShaderType::RADIAL_DARK_RED,
|
||||
ShaderType::RADIAL_DARK_GREEN,
|
||||
ShaderType::RADIAL_DARK_BLUE,
|
||||
ShaderType::RADIAL_LIGHT_RED,
|
||||
ShaderType::RADIAL_LIGHT_GREEN,
|
||||
ShaderType::RADIAL_LIGHT_BLUE,
|
||||
ShaderType::RADIAL_TRANSPARENT_RED,
|
||||
ShaderType::RADIAL_TRANSPARENT_GREEN,
|
||||
ShaderType::RADIAL_TRANSPARENT_BLUE,
|
||||
ShaderType::SECTOR_STATIC,
|
||||
ShaderType::SECTOR_ROTATED_POS,
|
||||
ShaderType::SECTOR_ROTATED_NEG,
|
||||
ShaderType::SOLID_RED
|
||||
};
|
||||
|
||||
QMutex sync;
|
||||
ShaderType current_shader;
|
||||
|
||||
RendererApi::PointI<2> center(SpriteData::ShapeData const *data) const {
|
||||
return data->pos_rotated(data->radius * center_distance_multiplier, center_angle_degrees);
|
||||
}
|
||||
|
||||
template<class receiver_t>
|
||||
void _select_shader(SpriteData::ShapeData const *data, receiver_t receiver) const {
|
||||
const_cast<QMutex *>(&(this->sync))->lock();
|
||||
@ -52,45 +121,73 @@ namespace BGTU::ComputerGraphicsLabWork::Impl::Variants::Lab2 {
|
||||
receiver(s);
|
||||
return;
|
||||
}
|
||||
case ShaderType::RADIAL_DARK_RED:
|
||||
case ShaderType::RADIAL_DARK_GREEN:
|
||||
case ShaderType::RADIAL_DARK_BLUE:
|
||||
case ShaderType::RADIAL_LIGHT_RED:
|
||||
case ShaderType::RADIAL_LIGHT_GREEN:
|
||||
case ShaderType::RADIAL_LIGHT_BLUE:
|
||||
case ShaderType::RADIAL_TRANSPARENT_RED:
|
||||
case ShaderType::RADIAL_TRANSPARENT_GREEN:
|
||||
case ShaderType::RADIAL_TRANSPARENT_BLUE:
|
||||
case ShaderType::SECTOR_STATIC:
|
||||
case ShaderType::SECTOR_ROTATED_POS:
|
||||
case ShaderType::SECTOR_ROTATED_NEG:;
|
||||
case ShaderType::RADIAL_DARK_RED: {
|
||||
RadialShader<RendererApi::Color{255, 0, 0}, RendererApi::Color{0, 0, 0}> s{this->center(data), data->radius * radius_multiplier - 1};
|
||||
receiver(s);
|
||||
return;
|
||||
}
|
||||
case ShaderType::RADIAL_DARK_GREEN: {
|
||||
RadialShader<RendererApi::Color{0, 255, 0}, RendererApi::Color{0, 0, 0}> s{this->center(data), data->radius * radius_multiplier - 1};
|
||||
receiver(s);
|
||||
return;
|
||||
}
|
||||
case ShaderType::RADIAL_DARK_BLUE: {
|
||||
RadialShader<RendererApi::Color{0, 0, 255}, RendererApi::Color{0, 0, 0}> s{this->center(data), data->radius * radius_multiplier - 1};
|
||||
receiver(s);
|
||||
return;
|
||||
}
|
||||
case ShaderType::RADIAL_LIGHT_RED: {
|
||||
RadialShader<RendererApi::Color{255, 0, 0}, RendererApi::Color{255, 255, 255}> s{this->center(data), data->radius * radius_multiplier - 1};
|
||||
receiver(s);
|
||||
return;
|
||||
}
|
||||
case ShaderType::RADIAL_LIGHT_GREEN: {
|
||||
RadialShader<RendererApi::Color{0, 255, 0}, RendererApi::Color{255, 255, 255}> s{this->center(data), data->radius * radius_multiplier - 1};
|
||||
receiver(s);
|
||||
return;
|
||||
}
|
||||
case ShaderType::RADIAL_LIGHT_BLUE: {
|
||||
RadialShader<RendererApi::Color{0, 0, 255}, RendererApi::Color{255, 255, 255}> s{this->center(data), data->radius * radius_multiplier - 1};
|
||||
receiver(s);
|
||||
return;
|
||||
}
|
||||
case ShaderType::RADIAL_TRANSPARENT_RED: {
|
||||
RadialShader<RendererApi::Color::Transparent{255, 0, 0, 255}, RendererApi::Color::Transparent{255, 0, 0, 0}> s{this->center(data), data->radius * radius_multiplier - 1};
|
||||
receiver(s);
|
||||
return;
|
||||
}
|
||||
case ShaderType::RADIAL_TRANSPARENT_GREEN: {
|
||||
RadialShader<RendererApi::Color::Transparent{0, 255, 0, 255}, RendererApi::Color::Transparent{0, 255, 0, 0}> s{this->center(data), data->radius * radius_multiplier - 1};
|
||||
receiver(s);
|
||||
return;
|
||||
}
|
||||
case ShaderType::RADIAL_TRANSPARENT_BLUE: {
|
||||
RadialShader<RendererApi::Color::Transparent{0, 0, 255, 255}, RendererApi::Color::Transparent{0, 0, 255, 0}> s{this->center(data), data->radius * radius_multiplier - 1};
|
||||
receiver(s);
|
||||
return;
|
||||
}
|
||||
case ShaderType::SECTOR_STATIC: {
|
||||
HsvSectorShader s{this->center(data), 0};
|
||||
receiver(s);
|
||||
return;
|
||||
}
|
||||
case ShaderType::SECTOR_ROTATED_POS: {
|
||||
HsvSectorShader s{this->center(data), data->rotation_radians};
|
||||
receiver(s);
|
||||
return;
|
||||
}
|
||||
case ShaderType::SECTOR_ROTATED_NEG: {
|
||||
HsvSectorShader s{this->center(data), -data->rotation_radians};
|
||||
receiver(s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static inline ShaderType const next_shader_type[] = {
|
||||
ShaderType::SOLID_GREEN,
|
||||
ShaderType::SOLID_BLUE,
|
||||
ShaderType::RADIAL_DARK_RED,
|
||||
ShaderType::RADIAL_DARK_GREEN,
|
||||
ShaderType::RADIAL_DARK_BLUE,
|
||||
ShaderType::RADIAL_LIGHT_RED,
|
||||
ShaderType::RADIAL_LIGHT_GREEN,
|
||||
ShaderType::RADIAL_LIGHT_BLUE,
|
||||
ShaderType::RADIAL_TRANSPARENT_RED,
|
||||
ShaderType::RADIAL_TRANSPARENT_GREEN,
|
||||
ShaderType::RADIAL_TRANSPARENT_BLUE,
|
||||
ShaderType::SECTOR_STATIC,
|
||||
ShaderType::SECTOR_ROTATED_POS,
|
||||
ShaderType::SECTOR_ROTATED_NEG,
|
||||
ShaderType::SOLID_RED
|
||||
};
|
||||
|
||||
public:
|
||||
Circle() : sync{}, current_shader{ShaderType::SOLID_RED} {}
|
||||
|
||||
|
||||
Circle(Circle &&other) : sync{}, current_shader{other.current_shader} {
|
||||
Circle(Circle &&other) noexcept: sync{}, current_shader{other.current_shader} {
|
||||
|
||||
}
|
||||
|
||||
@ -99,7 +196,7 @@ namespace BGTU::ComputerGraphicsLabWork::Impl::Variants::Lab2 {
|
||||
data,
|
||||
[&]<class shader_t>(shader_t const &shader) {
|
||||
Utilities::Shapes::iterate_circle_fill(
|
||||
data->pos_rotated(data->radius * center_distance_multiplier, center_angle_degrees),
|
||||
this->center(data),
|
||||
data->radius * radius_multiplier,
|
||||
[&](bool is_edge, RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t y) {
|
||||
if (is_edge) {
|
||||
@ -115,7 +212,7 @@ namespace BGTU::ComputerGraphicsLabWork::Impl::Variants::Lab2 {
|
||||
|
||||
void clicked() final {
|
||||
this->sync.lock();
|
||||
this->current_shader = next_shader_type[(unsigned)this->current_shader];
|
||||
this->current_shader = next_shader_type[(unsigned) this->current_shader];
|
||||
this->sync.unlock();
|
||||
}
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <bgtu/computer_graphics_lab_work/renderer_api/color.hpp>
|
||||
|
||||
|
||||
@ -24,8 +25,8 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities {
|
||||
const float neg_alpha_f = 255.f - alpha_f;
|
||||
|
||||
// mulps
|
||||
const float bg_alpha[4]{bg_f[0] * neg_alpha_f, bg_f[1] * neg_alpha_f, bg_f[1] * neg_alpha_f};
|
||||
const float fg_alpha[4]{fg_f[0] * alpha_f, fg_f[1] * alpha_f, fg_f[1] * alpha_f};
|
||||
const float bg_alpha[4]{bg_f[0] * neg_alpha_f, bg_f[1] * neg_alpha_f, bg_f[2] * neg_alpha_f};
|
||||
const float fg_alpha[4]{fg_f[0] * alpha_f, fg_f[1] * alpha_f, fg_f[2] * alpha_f};
|
||||
|
||||
// addps
|
||||
const float sum_f[4]{bg_alpha[0] + fg_alpha[0], bg_alpha[1] + fg_alpha[1], bg_alpha[2] + fg_alpha[2]};
|
||||
@ -185,4 +186,88 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities {
|
||||
buffer[offset + 2] = color.red;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr RendererApi::Color::Transparent colors_gradient(RendererApi::Color::Transparent c1, float c1v, RendererApi::Color::Transparent c2) {
|
||||
// pmovzxbd
|
||||
const std::uint_fast32_t c1_i32[4]{c1.red, c1.green, c1.blue, c1.alpha};
|
||||
const std::uint_fast32_t c2_i32[4]{c2.red, c2.green, c2.blue, c2.alpha};
|
||||
|
||||
// cvtdq2pd
|
||||
const float c1_f[4]{(float) c1_i32[0], (float) c1_i32[1], (float) c1_i32[2], (float) c1_i32[3]};
|
||||
const float c2_f[4]{(float) c2_i32[0], (float) c2_i32[1], (float) c2_i32[2], (float) c2_i32[3]};
|
||||
|
||||
float c2v = 1 - c1v;
|
||||
|
||||
// mulps
|
||||
const float c1_part[4]{c1_f[0] * c1v, c1_f[1] * c1v, c1_f[2] * c1v, c1_f[3] * c1v};
|
||||
const float c2_part[4]{c2_f[0] * c2v, c2_f[1] * c2v, c2_f[2] * c2v, c2_f[3] * c2v};
|
||||
|
||||
// addps
|
||||
const float sum_f[4]{c1_part[0] + c2_part[0], c1_part[1] + c2_part[1], c1_part[2] + c2_part[2], c1_part[3] + c2_part[3]};
|
||||
|
||||
return {
|
||||
(RendererApi::Color::component_compact_t) sum_f[0],
|
||||
(RendererApi::Color::component_compact_t) sum_f[1],
|
||||
(RendererApi::Color::component_compact_t) sum_f[2],
|
||||
(RendererApi::Color::component_compact_t) sum_f[3],
|
||||
};
|
||||
}
|
||||
|
||||
constexpr RendererApi::Color::Transparent colors_gradient(RendererApi::Color::Transparent c1, float c1v, RendererApi::Color::Transparent c2, float c2v, RendererApi::Color::Transparent c3) {
|
||||
// pmovzxbd
|
||||
const std::uint_fast32_t c1_i32[4]{c1.red, c1.green, c1.blue, c1.alpha};
|
||||
const std::uint_fast32_t c2_i32[4]{c2.red, c2.green, c2.blue, c2.alpha};
|
||||
const std::uint_fast32_t c3_i32[4]{c3.red, c3.green, c3.blue, c3.alpha};
|
||||
|
||||
// cvtdq2pd
|
||||
const float c1_f[4]{(float) c1_i32[0], (float) c1_i32[1], (float) c1_i32[2], (float) c1_i32[3]};
|
||||
const float c2_f[4]{(float) c2_i32[0], (float) c2_i32[1], (float) c2_i32[2], (float) c2_i32[3]};
|
||||
const float c3_f[4]{(float) c3_i32[0], (float) c3_i32[1], (float) c3_i32[2], (float) c3_i32[3]};
|
||||
|
||||
float c3v = 1 - c1v - c2v;
|
||||
|
||||
// mulps
|
||||
const float c1_part[4]{c1_f[0] * c1v, c1_f[1] * c1v, c1_f[2] * c1v, c1_f[3] * c1v};
|
||||
const float c2_part[4]{c2_f[0] * c2v, c2_f[1] * c2v, c2_f[2] * c2v, c2_f[3] * c2v};
|
||||
const float c3_part[4]{c3_f[0] * c3v, c3_f[1] * c3v, c3_f[2] * c3v, c3_f[3] * c3v};
|
||||
|
||||
// addps
|
||||
const float sum_f[4]{
|
||||
c1_part[0] + c2_part[0] + c3_part[0],
|
||||
c1_part[1] + c2_part[1] + c3_part[1],
|
||||
c1_part[2] + c2_part[2] + c3_part[2],
|
||||
c1_part[3] + c2_part[3] + c3_part[3]
|
||||
};
|
||||
|
||||
return {
|
||||
(RendererApi::Color::component_compact_t) sum_f[0],
|
||||
(RendererApi::Color::component_compact_t) sum_f[1],
|
||||
(RendererApi::Color::component_compact_t) sum_f[2],
|
||||
(RendererApi::Color::component_compact_t) sum_f[3],
|
||||
};
|
||||
}
|
||||
|
||||
[[deprecated]] inline RendererApi::Color hsv_to_rgb_360_1_1(double hue, double saturation, double value) {
|
||||
int hi = int(std::floor(hue / 60)) % 6;
|
||||
double f = hue / 60 - std::floor(hue / 60);
|
||||
value = value * 255;
|
||||
const auto v = (RendererApi::Color::component_fast_t) (value);
|
||||
const auto p = (RendererApi::Color::component_fast_t) (value * (1 - saturation));
|
||||
const auto q = (RendererApi::Color::component_fast_t) (value * (1 - f * saturation));
|
||||
const auto t = (RendererApi::Color::component_fast_t) (value * (1 - (1 - f) * saturation));
|
||||
switch (hi) {
|
||||
case 0:
|
||||
return {v, t, p};
|
||||
case 1:
|
||||
return {q, v, p};
|
||||
case 2:
|
||||
return {p, v, t};
|
||||
case 3:
|
||||
return {p, q, v};
|
||||
case 4:
|
||||
return {t, p, v};
|
||||
default:
|
||||
return {v, p, q};
|
||||
}
|
||||
}
|
||||
}
|
@ -20,7 +20,7 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes {
|
||||
RendererApi::PointI<2>::component_t x = 0, y = r;
|
||||
RendererApi::PointI<2>::component_t last_y = r + 1;
|
||||
RendererApi::PointI<2>::component_t _r2 = r * r;
|
||||
while (x < y) {
|
||||
while (true) {
|
||||
RendererApi::PointI<2>::component_t _x2 = x * x;
|
||||
RendererApi::PointI<2>::component_t _y_1 = y - 1;
|
||||
RendererApi::PointI<2>::component_t D1 = _x2 + y * y - _r2;
|
||||
@ -29,6 +29,19 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities::Shapes {
|
||||
if (D1 > -D2)
|
||||
y--;
|
||||
|
||||
if (x == y) {
|
||||
edge_point_receiver(cx - x, cy + y);
|
||||
fill_line_receiver(cy + y, cx - x + 1, cx + x);
|
||||
edge_point_receiver(cx + x, cy + y);
|
||||
|
||||
edge_point_receiver(cx - x, cy - y);
|
||||
fill_line_receiver(cy - y, cx - x + 1, cx + x);
|
||||
edge_point_receiver(cx + x, cy - y);
|
||||
break;
|
||||
} else if (x > y) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (y < last_y) {
|
||||
edge_point_receiver(cx - x, cy + y);
|
||||
fill_line_receiver(cy + y, cx - x + 1, cx + x);
|
||||
|
Loading…
Reference in New Issue
Block a user