diff --git a/programs/lab1/src/main.cpp b/programs/lab1/src/main.cpp index 0d17f62..1261949 100644 --- a/programs/lab1/src/main.cpp +++ b/programs/lab1/src/main.cpp @@ -5,15 +5,19 @@ #include #include #include +#include int main(int argc, char **argv) { QApplication qApplication{argc, argv}; - QMainWindow w{}; + qRegisterMetaType("OwnedQImage"); + QMainWindow w{}; BGTU::ComputerGraphicsLabWork::QtUtilities::SeparateThreadedDefaultRendererLinear renderer{}; + renderer.set_background(BGTU::ComputerGraphicsLabWork::RendererApi::Color{0, 0, 0}); BGTU::ComputerGraphicsLabWork::QtUtilities::RendererWidget canvas{&renderer, &w}; w.setCentralWidget(&canvas); w.show(); + QApplication::exec(); } \ No newline at end of file diff --git a/qt-utilities/CMakeLists.txt b/qt-utilities/CMakeLists.txt index 8f4cccc..b1a6a34 100644 --- a/qt-utilities/CMakeLists.txt +++ b/qt-utilities/CMakeLists.txt @@ -1,3 +1,9 @@ -add_library(qt_utilities OBJECT include/bgtu/computer_graphics_lab_work/qt_utilities/_separate_threaded_renderer.hpp include/bgtu/computer_graphics_lab_work/qt_utilities/_renderer_widget.hpp) +add_library( + qt_utilities + OBJECT + include/bgtu/computer_graphics_lab_work/qt_utilities/_separate_threaded_renderer.hpp + include/bgtu/computer_graphics_lab_work/qt_utilities/_renderer_widget.hpp + include/bgtu/computer_graphics_lab_work/qt_utilities/owned_qimage.hpp +) target_include_directories(qt_utilities PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) target_link_libraries(qt_utilities PUBLIC Qt5::Core Qt5::Widgets Qt5::Gui renderer_api utilities) \ No newline at end of file diff --git a/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/_renderer_widget.hpp b/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/_renderer_widget.hpp index 1640bd4..25b3669 100644 --- a/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/_renderer_widget.hpp +++ b/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/_renderer_widget.hpp @@ -31,7 +31,7 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { private slots: - virtual void receive_image(OwnedQImage img) = 0; + virtual void receive_image(OwnedQImage img) = 0; }; } \ No newline at end of file diff --git a/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/_separate_threaded_renderer.hpp b/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/_separate_threaded_renderer.hpp index e7dccd8..fbb790c 100644 --- a/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/_separate_threaded_renderer.hpp +++ b/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/_separate_threaded_renderer.hpp @@ -13,13 +13,13 @@ #include "owned_qimage.hpp" namespace BGTU::ComputerGraphicsLabWork::QtUtilities { - template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> + template *const *, std::size_t, sprite_data_t const *)> class SeparateThreadedRenderer; class _SeparateThreadedRenderer_Signals : public QObject { Q_OBJECT - template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> + template *const *, std::size_t, sprite_data_t const *)> friend class SeparateThreadedRenderer; @@ -27,6 +27,6 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { explicit _SeparateThreadedRenderer_Signals(QObject *owner = nullptr) : QObject{owner} {} signals: - void frame_rendered(OwnedQImage img); + void frame_rendered(OwnedQImage img); }; } \ No newline at end of file diff --git a/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/owned_qimage.hpp b/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/owned_qimage.hpp index 1dba855..c72c94a 100644 --- a/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/owned_qimage.hpp +++ b/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/owned_qimage.hpp @@ -11,36 +11,41 @@ #include namespace BGTU::ComputerGraphicsLabWork::QtUtilities { - template - class OwnedQImage : public QImage, public RendererApi::VoxelDrawer::Exporter { + class OwnedQImage : public QImage, public RendererApi::VoxelDrawer::Exporter { private: - RendererApi::Sprite const **owners; + RendererApi::SpriteMetadata const **owners; public: - OwnedQImage(unsigned width, unsigned height) : QImage(width, height, QImage::Format_ARGB32), owners{new RendererApi::Sprite const *[width * height]} { - for (RendererApi::Sprite const **p = this->owners - 1; p-- >= this->owners;) { - *p = nullptr; + OwnedQImage(unsigned width, unsigned height) : + QImage(width, height, QImage::Format_ARGB32) { + if (width == 0 || height == 0) { + this->owners = nullptr; + } else { + this->owners = new RendererApi::SpriteMetadata const *[width * height]; + for (RendererApi::SpriteMetadata const **p = this->owners - 1; p-- >= this->owners;) { + *p = nullptr; + } } } OwnedQImage() : QImage(), owners{nullptr} {} - void setPixelOwner(unsigned x, unsigned y, RendererApi::Sprite const *o) { + void setPixelOwner(unsigned x, unsigned y, RendererApi::SpriteMetadata const *o) { assert(x < this->width()); assert(y < this->height()); this->owners[y * this->width() + x] = o; } - RendererApi::Sprite const *getPixelOwner(unsigned x, unsigned y) const { + RendererApi::SpriteMetadata const *getPixelOwner(unsigned x, unsigned y) const { assert(x < this->width()); assert(y < this->height()); return this->owners[y * this->width() + x]; } - void set_pixel(RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t y, RendererApi::Color c, RendererApi::Sprite const *owner) final { + void set_pixel(RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t y, RendererApi::Color c, RendererApi::SpriteMetadata const *owner) final { this->setPixelColor(x, y, QColor{c.red, c.green, c.blue}); this->setPixelOwner(x, y, owner); } diff --git a/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/renderer_widget.hpp b/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/renderer_widget.hpp index 959c983..2f283eb 100644 --- a/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/renderer_widget.hpp +++ b/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/renderer_widget.hpp @@ -21,13 +21,13 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { class RendererWidget : public _RendererWidget_Slots { private: QMutex sync; - OwnedQImage next_image; - OwnedQImage current_image; + OwnedQImage next_image; + OwnedQImage current_image; _SeparateThreadedRenderer_Signals *renderer; private slots: - void receive_image(OwnedQImage img) { + void receive_image(OwnedQImage img) { this->sync.lock(); std::swap(this->next_image, img); this->sync.unlock(); @@ -48,8 +48,9 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { QPainter painter; painter.begin(this); + painter.setPen(Qt::NoPen); painter.setBrush(QApplication::style()->standardPalette().brush(QPalette::Background)); - painter.drawRect(this->rect()); + painter.drawRect(this->rect().x(), this->rect().y(), this->rect().width()-1, this->rect().height()-1); painter.drawImage(this->current_image.rect(), this->current_image); painter.end(); } diff --git a/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/separate_threaded_renderer.hpp b/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/separate_threaded_renderer.hpp index 14dcb41..98b6a77 100644 --- a/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/separate_threaded_renderer.hpp +++ b/qt-utilities/include/bgtu/computer_graphics_lab_work/qt_utilities/separate_threaded_renderer.hpp @@ -8,13 +8,14 @@ #include #include #include +#include #include #include #include "owned_qimage.hpp" #include "_separate_threaded_renderer.hpp" namespace BGTU::ComputerGraphicsLabWork::QtUtilities { - template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> + template *const *, std::size_t, sprite_data_t const *)> class SeparateThreadedRenderer : public _SeparateThreadedRenderer_Signals { private: struct data { @@ -32,12 +33,27 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { private: SeparateThreadedRenderer *owner; - + QWaitCondition intr; public: - explicit inline RendererThread(SeparateThreadedRenderer *owner) : QThread{owner}, owner{owner} {}; + + explicit inline RendererThread(SeparateThreadedRenderer *owner) : QThread{owner}, owner{owner}, intr{} { + }; + + void requestInterruption() { + QThread::requestInterruption(); + this->intr.wakeAll(); + } protected: void run() final; + + private: + void sleepms(std::uint_fast64_t ms) { + QMutex m{}; + m.lock(); + this->intr.wait(&m, ms); + m.unlock(); + } }; @@ -62,10 +78,13 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { void set_sprites_and_data(RendererApi::Sprite *const *sprites, std::size_t sprites_count, sprite_data_t const *data); void set_background(RendererApi::Color); + + public: + ~SeparateThreadedRenderer(); }; - template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> + template *const *, std::size_t, sprite_data_t const *)> SeparateThreadedRenderer::SeparateThreadedRenderer(renderer_context_t *renderer_context, QObject *owner): _SeparateThreadedRenderer_Signals{owner}, sync{}, @@ -81,66 +100,67 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { .height = 0, .projection = nullptr } { + this->thread->start(); } - template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> + template *const *, std::size_t, sprite_data_t const *)> void SeparateThreadedRenderer::set_frame_size(RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t width, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t height) { this->sync.lock(); - this->next_data.width = width; - this->next_data.height = height; + const_cast(&this->next_data)->width = width; + const_cast(&this->next_data)->height = height; this->sync.unlock(); } - template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> + template *const *, std::size_t, sprite_data_t const *)> void SeparateThreadedRenderer::set_ms_per_frame(std::uint_fast64_t ms) { this->sync.lock(); - this->next_data.ms_per_frame = ms; + const_cast(&this->next_data)->ms_per_frame = ms; this->sync.unlock(); } - template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> + template *const *, std::size_t, sprite_data_t const *)> void SeparateThreadedRenderer::set_sprites(RendererApi::Sprite *const *sprites, std::size_t sprites_count) { this->sync.lock(); - this->next_data.sprites = sprites; - this->next_data.sprites_count = sprites_count; + const_cast(&this->next_data)->sprites = sprites; + const_cast(&this->next_data)->sprites_count = sprites_count; this->sync.unlock(); } - template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> - void SeparateThreadedRenderer::set_sprite_data(sprite_data_t const *data) { + template *const *, std::size_t, sprite_data_t const *)> + void SeparateThreadedRenderer::set_sprite_data(sprite_data_t const *sprite_data) { this->sync.lock(); - this->next_data.sprite_data = data; + const_cast(&this->next_data)->sprite_data = sprite_data; this->sync.unlock(); } - template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> - void SeparateThreadedRenderer::set_sprites_and_data(RendererApi::Sprite *const *sprites, std::size_t sprites_count, sprite_data_t const *data) { + template *const *, std::size_t, sprite_data_t const *)> + void SeparateThreadedRenderer::set_sprites_and_data(RendererApi::Sprite *const *sprites, std::size_t sprites_count, sprite_data_t const *sprite_data) { this->sync.lock(); - this->next_data.sprites = sprites; - this->next_data.sprites_count = sprites_count; - this->next_data.sprite_data = data; + const_cast(&this->next_data)->sprites = sprites; + const_cast(&this->next_data)->sprites_count = sprites_count; + const_cast(&this->next_data)->sprite_data = sprite_data; this->sync.unlock(); } - template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> + template *const *, std::size_t, sprite_data_t const *)> void SeparateThreadedRenderer::set_background(RendererApi::Color c) { this->sync.lock(); - this->next_data.bg = c; + const_cast(&this->next_data)->bg = c; this->sync.unlock(); } - template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> + template *const *, std::size_t, sprite_data_t const *)> void SeparateThreadedRenderer::RendererThread::run() { try { QElapsedTimer timer; - while (true) { + while (!this->isInterruptionRequested()) { timer.start(); this->owner->sync.lock(); data cached = *const_cast(&this->owner->next_data); this->owner->sync.unlock(); - OwnedQImage img{cached.width, cached.height}; + OwnedQImage img{cached.width, cached.height}; (this->owner->renderer_context->*renderer_procedure)( cached.width, cached.height, &img, @@ -149,12 +169,18 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { cached.sprites, cached.sprites_count, cached.sprite_data ); - emit this->owner->frame_rendered(std::move(*reinterpret_cast *>(&img))); - QThread::msleep(std::max(cached.ms_per_frame - static_cast(timer.elapsed()), 0)); + emit this->owner->frame_rendered(img); + this->sleepms(std::max(cached.ms_per_frame - static_cast(timer.elapsed()), 0)); } } catch (std::exception const &e) { qCritical() << typeid(e).name() << ": " << e.what() << "\n" << "Renderer thread died" << "\n"; } } + + template *const *, std::size_t, sprite_data_t const *)> + SeparateThreadedRenderer::~SeparateThreadedRenderer() { + this->thread->requestInterruption(); + this->thread->wait(); + } } \ No newline at end of file diff --git a/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/sprite.hpp b/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/sprite.hpp index 83bfdc2..f29ac1f 100644 --- a/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/sprite.hpp +++ b/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/sprite.hpp @@ -4,11 +4,14 @@ #include "projection.hpp" namespace BGTU::ComputerGraphicsLabWork::RendererApi { - template - class Sprite { + class SpriteMetadata { public: - virtual void draw(VoxelDrawer *frame, Projection const *projection, data_t const *data) const = 0; - virtual void clicked() {}; }; + + template + class Sprite : public SpriteMetadata { + public: + virtual void draw(VoxelDrawer *frame, Projection const *projection, data_t const *data) const = 0; + }; } \ No newline at end of file diff --git a/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/voxel_drawer.hpp b/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/voxel_drawer.hpp index a30c532..c98ab59 100644 --- a/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/voxel_drawer.hpp +++ b/renderer-api/include/bgtu/computer_graphics_lab_work/renderer_api/voxel_drawer.hpp @@ -7,8 +7,7 @@ #include "point.hpp" namespace BGTU::ComputerGraphicsLabWork::RendererApi { - template - class Sprite; + class SpriteMetadata; class VoxelDrawer { public: @@ -31,10 +30,9 @@ namespace BGTU::ComputerGraphicsLabWork::RendererApi { return this->add_voxel(p.x, p.y, z, c); } - template class Exporter { public: - virtual void set_pixel(PointI<2>::component_t x, PointI<2>::component_t y, Color c, Sprite const* owner) = 0; + virtual void set_pixel(PointI<2>::component_t x, PointI<2>::component_t y, Color c, SpriteMetadata const* owner) = 0; }; }; } \ No newline at end of file diff --git a/utilities/include/bgtu/computer_graphics_lab_work/utilities/default_renderer_linear.hpp b/utilities/include/bgtu/computer_graphics_lab_work/utilities/default_renderer_linear.hpp index 3a061b0..5649744 100644 --- a/utilities/include/bgtu/computer_graphics_lab_work/utilities/default_renderer_linear.hpp +++ b/utilities/include/bgtu/computer_graphics_lab_work/utilities/default_renderer_linear.hpp @@ -24,9 +24,9 @@ namespace BGTU::ComputerGraphicsLabWork { ZElement *next; double const z; RendererApi::Color::Transparent const color; - RendererApi::Sprite *const owner; + RendererApi::SpriteMetadata *const owner; - ZElement(ZElement *next, double z, RendererApi::Color::Transparent color, RendererApi::Sprite *owner) : next{next}, z{z}, color{color}, owner{owner} {} + ZElement(ZElement *next, double z, RendererApi::Color::Transparent color, RendererApi::SpriteMetadata *owner) : next{next}, z{z}, color{color}, owner{owner} {} void link_after(ZElement *new_next) { new_next->next = this->next; @@ -112,7 +112,7 @@ namespace BGTU::ComputerGraphicsLabWork { pixel_trace_metadata *pixels_metadata; ZElementAllocationBuffer *pixel_trace_elements_allocator; - RendererApi::Sprite *current_artist; + RendererApi::SpriteMetadata *current_artist; VoxelDrawerImpl(RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t width, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t height, pixel_trace_metadata *pixels_metadata, ZElementAllocationBuffer *pixel_trace_elements_allocator); @@ -146,7 +146,7 @@ namespace BGTU::ComputerGraphicsLabWork { void render( RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t w, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t h, - RendererApi::VoxelDrawer::Exporter *frame, + RendererApi::VoxelDrawer::Exporter *frame, RendererApi::Color bg, RendererApi::Projection const *projection, RendererApi::Sprite *const *sprites, @@ -170,7 +170,6 @@ namespace BGTU::ComputerGraphicsLabWork { current_artist{nullptr} {} - template DefaultVoxelDrawerCache::ZElement *DefaultVoxelDrawerCache::ZElementAllocationBuffer::alloc_elem(args_t... args) { auto cell = this->next_unallocated; @@ -211,13 +210,16 @@ namespace BGTU::ComputerGraphicsLabWork { void DefaultVoxelDrawerCache::render( RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t w, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t h, - RendererApi::VoxelDrawer::Exporter *frame, + RendererApi::VoxelDrawer::Exporter *frame, RendererApi::Color bg, RendererApi::Projection const *projection, RendererApi::Sprite *const *sprites, std::size_t sprites_count, sprite_data_t const *sprite_data ) { + if (w == 0 || h == 0) + return; + if (this->pixel_metadata_cache.buffer == nullptr || this->pixel_metadata_cache.size < w * h) { this->pixel_metadata_cache.buffer = static_cast(std::realloc(this->pixel_metadata_cache.buffer, w * h * sizeof(pixel_trace_metadata))); this->pixel_metadata_cache.size = w * h; @@ -254,7 +256,7 @@ namespace BGTU::ComputerGraphicsLabWork { } namespace QtUtilities { - template *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *)> + template *const *, std::size_t, sprite_data_t const *)> class SeparateThreadedRenderer;