#include #include #include #include "variant1.hpp" namespace BGTU::ComputerGraphicsLabWork::Impl { namespace { template 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 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 class SunSprite : public RendererApi::Sprite { public: SunSprite() = default; void draw(BGTU::ComputerGraphicsLabWork::Utilities::DefaultVoxelDrawerCache::VoxelPainterImpl *frame, const BGTU::ComputerGraphicsLabWork::Impl::SpriteData *data) const final { TransformedShader> shader{data->planets_transform[0].inversed(), SunShader{}}; 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 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(55 * brightness_coefficient)}; static constexpr RendererApi::Color::Transparent darkness{0, 0, 0, 255 - static_cast(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 class PlanetSprite : public RendererApi::Sprite { 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> shader{ planet_center.inversed(), SunlightReflectionShaderModifier{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{}> class StartSprite : public RendererApi::Sprite { 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 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{}, 0.3> mercury; PlanetSprite{}, 0.2> venus; PlanetSprite{}, 0.27> earth; PlanetSprite{}, 0.25> mars; PlanetSprite{}, 0.2> jupiter; PlanetSprite{}, 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 *_sprites[]{ &sun_sprite, &mercury, &venus, &earth, &mars, &jupiter, &saturn, &star1, &star2, &star3, &star4, &star5, &star6, }; } RendererApi::Sprite **const sprites = _sprites; std::size_t sprites_count = 7 + 6; }