#pragma once #include #include #include #include #include #include #include #include #include #include #include namespace BGTU::ComputerGraphicsLabWork::Lab1 { class _Lab1SpriteData_Provider; struct Lab1SpriteData { public: struct ShapeData { public: double rotation_radians; RendererApi::PointI<2>::component_t radius; RendererApi::PointI<2>::component_t diameter; private: [[nodiscard]] inline RendererApi::PointI<2> _rotated(RendererApi::PointI<2>::component_t custom_radius, double base_angle_radians, double angle_degrees) const { double angle_radians = angle_degrees * (std::numbers::pi_v / 180); return { (RendererApi::PointI<2>::component_t) (std::cos(base_angle_radians + angle_radians) * custom_radius), (RendererApi::PointI<2>::component_t) (std::sin(base_angle_radians + angle_radians) * custom_radius), }; } public: [[nodiscard]] inline RendererApi::PointI<2> static_rotated(RendererApi::PointI<2>::component_t custom_radius, double angle_degrees) const { return this->_rotated(custom_radius, 0, angle_degrees); } [[nodiscard]] inline RendererApi::PointI<2> pos_rotated(RendererApi::PointI<2>::component_t custom_radius, double angle_degrees) const { return this->_rotated(custom_radius, this->rotation_radians, angle_degrees); } [[nodiscard]] inline RendererApi::PointI<2> neg_rotated(RendererApi::PointI<2>::component_t custom_radius, double angle_degrees) const { return this->_rotated(custom_radius, -this->rotation_radians, angle_degrees); } }; RendererApi::PointI<2> central_pixel_tl; std::size_t pixel_size; bool show_grid; ShapeData shape_data; RendererApi::Sprite> *const *sub_sprites; std::size_t sub_sprites_count; using Provider = _Lab1SpriteData_Provider; }; class _Lab1SpriteData_Provider : public QObject, public RendererApi::Sprite::SpriteDataProvider { Q_OBJECT private: QMutex sync; QElapsedTimer time; std::size_t pixel_size; double radians_per_second; bool show_grid; RendererApi::VirtualVoxelPainter::visible_pixel_coordinate_fast_t w, h; RendererApi::Sprite> *const *sub_sprites; std::size_t sub_sprites_count; public: explicit _Lab1SpriteData_Provider(double radians_per_second) : sync{}, time{}, pixel_size{1}, radians_per_second{radians_per_second}, show_grid{false}, w{0}, h{0}, sub_sprites{nullptr}, sub_sprites_count{0} {} Lab1SpriteData get_sprite_data() override { this->sync.lock(); RendererApi::PointI<2>::component_t radius = (((this->w < this->h) ? this->w : this->h) * 7 / 16) / this->pixel_size; Lab1SpriteData cached{ .central_pixel_tl = (RendererApi::PointI<2>) (RendererApi::PointF<2>(this->w, this->h) / 2.0 - RendererApi::PointF<2>(this->pixel_size, this->pixel_size) / 2.0), .pixel_size = this->pixel_size, .show_grid = this->show_grid, .shape_data = { .rotation_radians = std::fmod(this->time.elapsed() / 1000.0 * radians_per_second, std::numbers::pi * 2), .radius = radius, .diameter = radius * 2 }, .sub_sprites = this->sub_sprites, .sub_sprites_count = this->sub_sprites_count, }; this->sync.unlock(); return cached; } public slots: void set_pixel_size(std::size_t s) { this->sync.lock(); this->pixel_size = s; this->sync.unlock(); } void increase_pixel_size() { this->sync.lock(); this->pixel_size++; this->sync.unlock(); } void decrease_pixel_size() { this->sync.lock(); if (this->pixel_size > 1) this->pixel_size--; this->sync.unlock(); } void set_frame_size(RendererApi::VirtualVoxelPainter::visible_pixel_coordinate_fast_t ww, RendererApi::VirtualVoxelPainter::visible_pixel_coordinate_fast_t hh) { this->sync.lock(); this->w = ww; this->h = hh; this->sync.unlock(); } void set_show_grid(bool f) { this->sync.lock(); this->show_grid = f; this->sync.unlock(); } void invert_show_grid() { this->sync.lock(); this->show_grid = !this->show_grid; this->sync.unlock(); } void set_sub_sprites(RendererApi::Sprite> *const *s, std::size_t c) { this->sync.lock(); this->sub_sprites = s; this->sub_sprites_count = c; this->sync.unlock(); } }; }