#pragma once #include #include #include #include #include #include #include #include #include #include #include namespace BGTU::ComputerGraphicsLabWork::Impl { class _Lab5SpriteData_Provider; struct SpriteData { public: using Provider = _Lab5SpriteData_Provider; Utilities::Matrix4d transform; bool is_projection_enabled; double x_radius; double y_radius; explicit SpriteData(Utilities::Matrix4d transform, bool is_projection_enabled, double x_radius, double y_radius) : transform{transform}, is_projection_enabled{is_projection_enabled}, x_radius{x_radius}, y_radius{y_radius} {} [[nodiscard]] inline RendererApi::PointI<2> project_point(RendererApi::PointF<3> p) const { if (this->is_projection_enabled) return {static_cast::component_t>((p.x - this->x_radius) / (p.z * (1 / this->x_radius) + 1) + this->x_radius), static_cast::component_t>((p.y - this->y_radius) / (p.z * (1 / this->y_radius) + 1) + this->y_radius)}; else return RendererApi::PointI<2>{static_cast::component_t>(p.x), static_cast::component_t>(p.y)}; }; }; class _Lab5SpriteData_Provider : public QObject, public RendererApi::Sprite::SpriteDataProvider { Q_OBJECT private: QMutex sync; double x_angle; double y_angle; double scale; double x_angle_step; double y_angle_step; double scale_step; bool is_projection_enabled; RendererApi::VirtualVoxelPainter::visible_pixel_coordinate_fast_t w, h; public: explicit _Lab5SpriteData_Provider( double x_angle_step, double y_angle_step, double scale_step ) : x_angle{0}, y_angle{0}, scale{1}, x_angle_step{x_angle_step}, y_angle_step{y_angle_step}, scale_step{scale_step}, w{0}, h{0}, is_projection_enabled{false} {} SpriteData get_sprite_data() override { this->sync.lock(); double radius = (((this->w < this->h) ? this->w : this->h) * 7 / 16.0); SpriteData cached{ Utilities::Matrix4d::shift(0, 0, this->scale) * Utilities::Matrix4d::shift(this->w / 2, this->h / 2, radius * 2) * Utilities::Matrix4d::rotate_x(this->x_angle) * Utilities::Matrix4d::rotate_y(this->y_angle) * Utilities::Matrix4d::scale(radius), this->is_projection_enabled, this->w * 7 / 16.0, this->h * 7 / 16.0, }; this->sync.unlock(); return cached; } public slots: 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 inc_x_angle() { this->sync.lock(); this->x_angle += this->x_angle_step; this->sync.unlock(); } void dec_x_angle() { this->sync.lock(); this->x_angle -= this->x_angle_step; this->sync.unlock(); } void inc_y_angle() { this->sync.lock(); this->y_angle += this->y_angle_step; this->sync.unlock(); } void dec_y_angle() { this->sync.lock(); this->y_angle -= this->y_angle_step; this->sync.unlock(); } void inc_scale() { this->sync.lock(); this->scale += this->scale_step; this->sync.unlock(); } void dec_scale() { this->sync.lock(); this->scale -= this->scale_step; this->sync.unlock(); } void switch_projection() { this->sync.lock(); this->is_projection_enabled = !this->is_projection_enabled; this->sync.unlock(); } }; }