diff --git a/programs/lab1/src/main.cpp b/programs/lab1/src/main.cpp index 3f88957..9016d43 100644 --- a/programs/lab1/src/main.cpp +++ b/programs/lab1/src/main.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -37,10 +38,10 @@ int main(int argc, char **argv) { o oo{&frames}; - BGTU::ComputerGraphicsLabWork::QtUtilities::SeparateThreadedDefaultRendererLinear renderer{}; + BGTU::ComputerGraphicsLabWork::QtUtilities::SeparateThreadedDefaultRendererLinear renderer{}; QObject::connect(&renderer, &BGTU::ComputerGraphicsLabWork::QtUtilities::_SeparateThreadedRenderer_Signals::frame_rendered, &oo, &o::hit); renderer.set_background(BGTU::ComputerGraphicsLabWork::RendererApi::Color{0, 0, 0}); - BGTU::ComputerGraphicsLabWork::QtUtilities::RendererWidget canvas{&renderer, &w}; + BGTU::ComputerGraphicsLabWork::QtUtilities::RendererWidget canvas{&renderer, &w}; w.setCentralWidget(&canvas); w.show(); 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 b9badb7..20b672b 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 @@ -14,7 +14,7 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { template - using _SeparateThreadedRenderer_RenderProcedureType = void (renderer_context_t::*)(RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::Exporter *, RendererApi::Color, RendererApi::Projection const *, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *); + using _SeparateThreadedRenderer_RenderProcedureType = void (renderer_context_t::*)(RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t, RendererApi::VoxelDrawer::Exporter *, RendererApi::Color, RendererApi::Sprite *const *, std::size_t, sprite_data_t const *); template> class SeparateThreadedRenderer; 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 e916450..050d822 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 @@ -14,6 +14,8 @@ #include "owned_qimage.hpp" #include "_separate_threaded_renderer.hpp" +#define has_BGTU_ComputerGraphicsLabWork_QtUtilities_SeparateThreadedRenderer + namespace BGTU::ComputerGraphicsLabWork::QtUtilities { template renderer_procedure> class SeparateThreadedRenderer : public _SeparateThreadedRenderer_Signals { @@ -22,10 +24,9 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { public: RendererApi::Sprite *const *sprites; std::size_t sprites_count; - sprite_data_t const *sprite_data; + RendererApi::Sprite::SpriteDataProvider *sprite_data_provider; std::uint_fast64_t ms_per_frame; RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t width, height; - RendererApi::Projection *projection; RendererApi::Color bg; }; @@ -77,9 +78,7 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { void set_sprites(RendererApi::Sprite *const *sprites, std::size_t sprites_count); - void set_sprite_data(sprite_data_t const *data); - - void set_sprites_and_data(RendererApi::Sprite *const *sprites, std::size_t sprites_count, sprite_data_t const *data); + void set_sprite_data_provider(RendererApi::Sprite::SpriteDataProvider *provider); void set_background(RendererApi::Color) final; @@ -98,11 +97,10 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { next_data{ .sprites = nullptr, .sprites_count = 0, - .sprite_data = nullptr, + .sprite_data_provider = nullptr, .ms_per_frame = 1000 / 60, .width = 0, .height = 0, - .projection = nullptr } { this->thread->start(); } @@ -133,24 +131,13 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { } template renderer_procedure> - void SeparateThreadedRenderer::set_sprite_data(sprite_data_t const *sprite_data) { + void SeparateThreadedRenderer::set_sprite_data_provider(RendererApi::Sprite::SpriteDataProvider *provider) { this->sync.lock(); - const_cast(&this->next_data)->sprite_data = sprite_data; + const_cast(&this->next_data)->sprite_data_provider = provider; this->thread->force_redraw(); this->sync.unlock(); } - template renderer_procedure> - void SeparateThreadedRenderer::set_sprites_and_data(RendererApi::Sprite *const *sprites, std::size_t sprites_count, sprite_data_t const *sprite_data) { - this->sync.lock(); - 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->thread->force_redraw(); - this->sync.unlock(); - } - - template renderer_procedure> void SeparateThreadedRenderer::set_background(RendererApi::Color c) { this->sync.lock(); @@ -191,13 +178,24 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { } } img{cached.width, cached.height}; + union { + sprite_data_t data; + bool nothing; + } sprite_data_storage; + sprite_data_t const *sprite_data; + if (cached.sprite_data_provider != nullptr) { + sprite_data_storage.data = cached.sprite_data_provider->get_sprite_data(); + sprite_data = &(sprite_data_storage.data); + } else { + sprite_data = nullptr; + } + (this->owner->renderer_context->*renderer_procedure)( cached.width, cached.height, &img, cached.bg, - cached.projection, cached.sprites, cached.sprites_count, - cached.sprite_data + sprite_data ); emit this->owner->frame_rendered(new OwnedQImage{img.pixels_argb, img.w, img.h, QImage::Format_RGB32, img.owners, OwnedQImage::DelegateBuffers}); auto elapsed = timer.elapsed(); @@ -215,4 +213,13 @@ namespace BGTU::ComputerGraphicsLabWork::QtUtilities { this->thread->requestInterruption(); this->thread->wait(); } + + + template + class SeparateThreadedDefaultRendererLinear : public SeparateThreadedRenderer> { + private: + Utilities::DefaultVoxelDrawerCache context; + public: + explicit SeparateThreadedDefaultRendererLinear(QObject *owner = nullptr) : SeparateThreadedRenderer>{&this->context, owner} {}; + }; } \ 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 f29ac1f..abdabd7 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 @@ -12,6 +12,11 @@ namespace BGTU::ComputerGraphicsLabWork::RendererApi { template class Sprite : public SpriteMetadata { public: - virtual void draw(VoxelDrawer *frame, Projection const *projection, data_t const *data) const = 0; + virtual void draw(VoxelDrawer *frame, data_t const *data) const = 0; + + class SpriteDataProvider { + public: + virtual data_t get_sprite_data() = 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 96502b2..35af234 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 @@ -15,228 +15,210 @@ class QObject; -namespace BGTU::ComputerGraphicsLabWork { - namespace Utilities { - class DefaultVoxelDrawerCache { - private: - class ZElement { - public: - ZElement *next; - double const z; - RendererApi::Color::Transparent const color; - RendererApi::SpriteMetadata *const 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; - this->next = new_next; - } - }; - - class ZElementAllocationBuffer { - private: - union Cell { - ZElement allocated; - struct Empty { - Cell *next_empty; - } empty; - }; - - - class Page { - public: - Page *next; - private: - - std::size_t initialized; - std::size_t capacity; - - Cell buffer[0]; - - public: - explicit Page(Page *next, std::size_t capacity) : next{next}, initialized{0}, capacity{capacity}, buffer{} {}; - - Cell *try_allocate(); - - static std::size_t calc_capacity(std::size_t bytes) { - return (bytes - offsetof(Page, buffer)) / sizeof(Cell); - }; - - void reset_allocations() { - this->initialized = 0; - } - }; - - Cell *next_unallocated; - Page *last_page; - Page sentinel; - - public: - ZElementAllocationBuffer() : next_unallocated{nullptr}, sentinel{nullptr, 0}, last_page{&this->sentinel} {}; - - private: - Page *_native_extend(); - - public: - template - ZElement *alloc_elem(args_t...args); - - void free_elem(ZElement *e); - - private: - void _native_free_page(Page *p); - - public: - void release_resources(); - - void reset_allocations(); - - ~ZElementAllocationBuffer(); - }; - - struct pixel_trace_metadata { - public: - pixel_trace_metadata() : nearest_z{std::numeric_limits::max()}, voxels{nullptr} {}; - - double nearest_z; - ZElement *voxels; - }; - - class VoxelDrawerImpl : public RendererApi::VoxelDrawer { - public: - 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; - 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); - - [[nodiscard]] inline RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t width() const final { - return this->_width; - } - - [[nodiscard]] inline RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t height() const final { - return this->_height; - } - - inline pixel_trace_metadata *at(std::uint_fast16_t x, std::uint_fast16_t y) { - return &(this->pixels_metadata[y * this->_width + x]); - } - - void add_voxel(long long x, long long y, double z, RendererApi::Color::Transparent c) final; - }; - - - struct { - pixel_trace_metadata *buffer; - std::size_t size; - } pixel_metadata_cache; - ZElementAllocationBuffer pixel_trace_elements_allocator; - +namespace BGTU::ComputerGraphicsLabWork::Utilities { + class DefaultVoxelDrawerCache { + private: + class ZElement { public: - DefaultVoxelDrawerCache(); + ZElement *next; + double const z; + RendererApi::Color::Transparent const color; + RendererApi::SpriteMetadata *const owner; - private: - static ZElement *sort_zelements_desc(DefaultVoxelDrawerCache::ZElement *start) noexcept; + ZElement(ZElement *next, double z, RendererApi::Color::Transparent color, RendererApi::SpriteMetadata *owner) : next{next}, z{z}, color{color}, owner{owner} {} - public: - template - void render( - RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t w, - RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t h, - 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 - ); - - ~DefaultVoxelDrawerCache(); + void link_after(ZElement *new_next) { + new_next->next = this->next; + this->next = new_next; + } }; - template - DefaultVoxelDrawerCache::ZElement *DefaultVoxelDrawerCache::ZElementAllocationBuffer::alloc_elem(args_t... args) { - auto cell = this->next_unallocated; - if (cell != nullptr) { - this->next_unallocated = cell->empty.next_empty; - return &(cell->allocated); + class ZElementAllocationBuffer { + private: + union Cell { + ZElement allocated; + struct Empty { + Cell *next_empty; + } empty; + }; + + + class Page { + public: + Page *next; + private: + + std::size_t initialized; + std::size_t capacity; + + Cell buffer[0]; + + public: + explicit Page(Page *next, std::size_t capacity) : next{next}, initialized{0}, capacity{capacity}, buffer{} {}; + + Cell *try_allocate(); + + static std::size_t calc_capacity(std::size_t bytes) { + return (bytes - offsetof(Page, buffer)) / sizeof(Cell); + }; + + void reset_allocations() { + this->initialized = 0; + } + }; + + Cell *next_unallocated; + Page *last_page; + Page sentinel; + + public: + ZElementAllocationBuffer() : next_unallocated{nullptr}, sentinel{nullptr, 0}, last_page{&this->sentinel} {}; + + private: + Page *_native_extend(); + + public: + template + ZElement *alloc_elem(args_t...args); + + void free_elem(ZElement *e); + + private: + void _native_free_page(Page *p); + + public: + void release_resources(); + + void reset_allocations(); + + ~ZElementAllocationBuffer(); + }; + + struct pixel_trace_metadata { + public: + pixel_trace_metadata() : nearest_z{std::numeric_limits::max()}, voxels{nullptr} {}; + + double nearest_z; + ZElement *voxels; + }; + + class VoxelDrawerImpl : public RendererApi::VoxelDrawer { + public: + 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; + 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); + + [[nodiscard]] inline RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t width() const final { + return this->_width; } - while ((cell = this->last_page->try_allocate()) == nullptr) - this->_native_extend(); + [[nodiscard]] inline RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t height() const final { + return this->_height; + } - return new(&(cell->allocated)) ZElement{args...}; - } + inline pixel_trace_metadata *at(std::uint_fast16_t x, std::uint_fast16_t y) { + return &(this->pixels_metadata[y * this->_width + x]); + } + + void add_voxel(long long x, long long y, double z, RendererApi::Color::Transparent c) final; + }; + struct { + pixel_trace_metadata *buffer; + std::size_t size; + } pixel_metadata_cache; + ZElementAllocationBuffer pixel_trace_elements_allocator; + + public: + DefaultVoxelDrawerCache(); + + private: + static ZElement *sort_zelements_desc(DefaultVoxelDrawerCache::ZElement *start) noexcept; + + public: template - void DefaultVoxelDrawerCache::render( + void render( RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t w, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t h, 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; + ~DefaultVoxelDrawerCache(); + }; + + template + DefaultVoxelDrawerCache::ZElement *DefaultVoxelDrawerCache::ZElementAllocationBuffer::alloc_elem(args_t... args) { + auto cell = this->next_unallocated; + if (cell != nullptr) { + this->next_unallocated = cell->empty.next_empty; + return &(cell->allocated); + } + + while ((cell = this->last_page->try_allocate()) == nullptr) + this->_native_extend(); + + return new(&(cell->allocated)) ZElement{args...}; + } + + + template + void DefaultVoxelDrawerCache::render( + RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t w, + RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t h, + RendererApi::VoxelDrawer::Exporter *frame, + RendererApi::Color bg, + 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; + } + + this->pixel_trace_elements_allocator.reset_allocations(); + VoxelDrawerImpl painter{w, h, this->pixel_metadata_cache.buffer, &this->pixel_trace_elements_allocator}; + + for (std::int_fast64_t i = w * h - 1; i >= 0; i--) { + new(&this->pixel_metadata_cache.buffer[i]) pixel_trace_metadata{}; + } + + for (; sprites_count-- > 0; sprites++) { + painter.current_artist = *sprites; + (*sprites)->draw(&painter, sprite_data); + } + + std::uint_fast16_t y = 0; + std::uint_fast16_t x = 0; + + for (std::int_fast64_t i = w * h - 1; i >= 0; i--) { + this->pixel_metadata_cache.buffer[i].voxels = sort_zelements_desc(this->pixel_metadata_cache.buffer[i].voxels); + RendererApi::Color cc = bg; + RendererApi::SpriteMetadata *owner = nullptr; + for (auto p = this->pixel_metadata_cache.buffer[i].voxels; p != nullptr; p = p->next) { + cc = apply_transparent_color(cc, p->color); + owner = p->owner; } + frame->set_pixel(x, y, cc, owner); - this->pixel_trace_elements_allocator.reset_allocations(); - VoxelDrawerImpl painter{w, h, this->pixel_metadata_cache.buffer, &this->pixel_trace_elements_allocator}; - - for (std::int_fast64_t i = w * h - 1; i >= 0; i--) { - new(&this->pixel_metadata_cache.buffer[i]) pixel_trace_metadata{}; - } - - for (; sprites_count-- > 0; sprites++) { - painter.current_artist = *sprites; - (*sprites)->draw(&painter, projection, sprite_data); - } - - std::uint_fast16_t y = 0; - std::uint_fast16_t x = 0; - - for (std::int_fast64_t i = w * h - 1; i >= 0; i--) { - this->pixel_metadata_cache.buffer[i].voxels = sort_zelements_desc(this->pixel_metadata_cache.buffer[i].voxels); - RendererApi::Color cc = bg; - RendererApi::SpriteMetadata *owner = nullptr; - for (auto p = this->pixel_metadata_cache.buffer[i].voxels; p != nullptr; p = p->next) { - cc = apply_transparent_color(cc, p->color); - owner = p->owner; - } - frame->set_pixel(x, y, cc, owner); - - if (++x >= w) { - y++; - x = 0; - } + if (++x >= w) { + y++; + x = 0; } } } - - namespace QtUtilities { - template *const *, std::size_t, sprite_data_t const *)> - class SeparateThreadedRenderer; - - - template - class SeparateThreadedDefaultRendererLinear : public SeparateThreadedRenderer> { - private: - Utilities::DefaultVoxelDrawerCache context; - public: - explicit SeparateThreadedDefaultRendererLinear(QObject *owner = nullptr) : SeparateThreadedRenderer>{&this->context, owner} {}; - }; - } } \ No newline at end of file