bresenham-0.rs/programs/lab3/src/variant1.cpp

185 lines
8.5 KiB
C++

#include <utility>
#include <bgtu/computer_graphics_lab_work/utilities/shader.hpp>
#include <bgtu/computer_graphics_lab_work/utilities/shapes/circle.hpp>
#include "variant1.hpp"
namespace BGTU::ComputerGraphicsLabWork::Impl {
namespace {
template<class real_shader_t>
class TransformedShader : public Utilities::Shader {
private:
Utilities::Matrix3d transform;
real_shader_t real_shader;
public:
TransformedShader(Utilities::Matrix3d transform, real_shader_t real_shader) : transform{transform}, real_shader{real_shader} {};
[[nodiscard]] RendererApi::Color::Transparent get_color(RendererApi::PointF<2>::component_t x, RendererApi::PointF<2>::component_t y) const final {
auto p = this->transform * RendererApi::PointF<2>{x, y};
return this->real_shader.get_color(p.x, p.y);
}
};
template<double radius>
class SunShader : public Utilities::Shader {
private:
public:
SunShader() = default;
[[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, y) / radius;
if (distance > 1)
return RendererApi::Color::Transparent{255, 255, 0, 0};
else if (distance > 0.8)
return Utilities::colors_gradient(RendererApi::Color::Transparent{255, 255, 0, 0}, (distance - 0.8) * 5, RendererApi::Color::Transparent{255, 255, 0, 255});
else if (distance > 0.3)
return Utilities::colors_gradient(RendererApi::Color::Transparent{255, 255, 0, 255}, (distance - 0.3) * 10 / 5, RendererApi::Color::Transparent{255, 255, 200, 255});
else
return RendererApi::Color::Transparent{255, 255, 200, 255};
}
};
template<double z, double radius>
class SunSprite : public RendererApi::Sprite<SpriteData, Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl> {
public:
SunSprite() = default;
void draw(BGTU::ComputerGraphicsLabWork::Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl *frame, const BGTU::ComputerGraphicsLabWork::Impl::SpriteData *data) const final {
TransformedShader<SunShader<radius>> shader{data->planets_transform[0].inversed(), SunShader<radius>{}};
Utilities::Shapes::iterate_circle_fill(
static_cast< RendererApi::PointI<2>>(data->planets_transform[0] * RendererApi::PointF<2>{0, 0}),
data->radius_multiplier * radius,
[&](bool, RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t y) {
frame->add_voxel(x, y, z, shader.get_color(x, y));
}
);
}
};
template<double brightness_coefficient, double radius, class underlying_shader_t>
class SunlightReflectionShaderModifier : public Utilities::Shader {
private:
static_assert(brightness_coefficient >= 0.0);
static_assert(brightness_coefficient <= 1.0);
static constexpr RendererApi::Color::Transparent light{63, 63, 0, static_cast<RendererApi::Color::component_fast_t>(55 * brightness_coefficient)};
static constexpr RendererApi::Color::Transparent darkness{0, 0, 0, 255 - static_cast<RendererApi::Color::component_fast_t>(55 * brightness_coefficient)};
static constexpr RendererApi::Color::Transparent middle = Utilities::colors_gradient(light, 0.3, darkness);
underlying_shader_t underlying_shader;
public:
explicit SunlightReflectionShaderModifier(underlying_shader_t underlying_shader) : underlying_shader{underlying_shader} {}
[[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, y + radius) / radius;
if (distance > 2)
return underlying_shader.get_color(x, y);
else if (distance > 1)
return Utilities::apply_transparent_color(underlying_shader.get_color(x, y), Utilities::colors_gradient(darkness, (distance - 1), middle));
else
return Utilities::apply_transparent_color(underlying_shader.get_color(x, y), Utilities::colors_gradient(middle, distance, light));
}
};
template<double orbit_z, double orbit_radius, RendererApi::Color::Transparent orbit_color, std::size_t transform_id, double planet_z, double planet_radius, double atmosphere_radius, auto planet_shader, double brightness_coefficient>
class PlanetSprite : public RendererApi::Sprite<SpriteData, Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl> {
public:
PlanetSprite() = default;
void draw(BGTU::ComputerGraphicsLabWork::Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl *frame, const BGTU::ComputerGraphicsLabWork::Impl::SpriteData *data) const final {
Utilities::Shapes::iterate_circle_fill(
static_cast< RendererApi::PointI<2>>(data->planets_transform[transform_id] * RendererApi::PointF<2>{0, 0}),
data->radius_multiplier * orbit_radius,
[&](bool is_edge, RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t y) {
if (is_edge)
frame->add_voxel(x, y, orbit_z, orbit_color);
}
);
auto planet_center = data->planets_transform[transform_id] * Utilities::Matrix3d::shift(0, orbit_radius);
TransformedShader<SunlightReflectionShaderModifier<brightness_coefficient, planet_radius, decltype(planet_shader)>> shader{
planet_center.inversed(),
SunlightReflectionShaderModifier<brightness_coefficient, planet_radius, decltype(planet_shader)>{planet_shader}
};
Utilities::Shapes::iterate_circle_fill(
static_cast< RendererApi::PointI<2>>(planet_center * RendererApi::PointF<2>{0, 0}),
data->radius_multiplier * planet_radius * atmosphere_radius,
[&](bool, RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t y) {
frame->add_voxel(x, y, planet_z, shader.get_color(x, y));
}
);
}
};
template<double orbit_radius, double radius, double z, double angle_offset, auto planet_shader = SunShader<radius>{}>
class StartSprite : public RendererApi::Sprite<SpriteData, Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl> {
public:
StartSprite() = default;
void draw(BGTU::ComputerGraphicsLabWork::Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl *frame, const BGTU::ComputerGraphicsLabWork::Impl::SpriteData *data) const final {
auto planet_center = data->stars_transform * Utilities::Matrix3d::rotate(angle_offset) * Utilities::Matrix3d::shift(0, orbit_radius);
TransformedShader<decltype(planet_shader)> shader{
planet_center.inversed(),
planet_shader
};
Utilities::Shapes::iterate_circle_fill(
static_cast< RendererApi::PointI<2>>(planet_center * RendererApi::PointF<2>{0, 0}),
data->radius_multiplier * radius,
[&](bool, RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t y) {
frame->add_voxel(x, y, z, shader.get_color(x, y));
}
);
}
};
constexpr RendererApi::Color::Transparent default_orbit_color{255, 255, 255, 127};
constexpr double orbit_z = 2.0;
SunSprite<1.0, 0.25> sun_sprite{};
PlanetSprite<orbit_z, 0.325, default_orbit_color, 1, 1.0, 0.03, 1.0, Utilities::MonoShader::Static<RendererApi::Color::Transparent{168, 118, 67}>{}, 0.3> mercury;
PlanetSprite<orbit_z, 0.45, default_orbit_color, 2, 1.0, 0.03, 1.0, Utilities::MonoShader::Static<RendererApi::Color::Transparent{226, 170, 72}>{}, 0.2> venus;
PlanetSprite<orbit_z, 0.57, default_orbit_color, 3, 1.0, 0.05, 1.0, Utilities::MonoShader::Static<RendererApi::Color::Transparent{0, 255, 127}>{}, 0.27> earth;
PlanetSprite<orbit_z, 0.69, default_orbit_color, 4, 1.0, 0.05, 1.0, Utilities::MonoShader::Static<RendererApi::Color::Transparent{254, 132, 94}>{}, 0.25> mars;
PlanetSprite<orbit_z, 0.85, default_orbit_color, 5, 1.0, 0.1, 1.0, Utilities::MonoShader::Static<RendererApi::Color::Transparent{238, 204, 140}>{}, 0.2> jupiter;
PlanetSprite<orbit_z, 1.1, default_orbit_color, 5, 1.0, 0.1, 1.0, Utilities::MonoShader::Static<RendererApi::Color::Transparent{238, 50, 240}>{}, 0.18> saturn;
StartSprite<1.8-0.4, 0.4, 3.0, 0.0> star1;
StartSprite<1.7-0.4, 0.5, 3.0, 1.0> star2;
StartSprite<1.9-0.4, 0.4, 3.0, 2.0> star3;
StartSprite<1.6-0.4, 0.5, 3.0, 3.0> star4;
StartSprite<2.0-0.4, 0.4, 3.0, 4.0> star5;
StartSprite<2.1-0.4, 0.3, 3.0, 5.0> star6;
RendererApi::Sprite<SpriteData, Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl> *_sprites[]{
&sun_sprite,
&mercury,
&venus,
&earth,
&mars,
&jupiter,
&saturn,
&star1,
&star2,
&star3,
&star4,
&star5,
&star6,
};
}
RendererApi::Sprite<SpriteData, Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl> **const sprites = _sprites;
std::size_t sprites_count = 7 + 6;
}