Utilities module for Qt, default voxel drawer and minor improvements
This commit is contained in:
parent
cdc8337219
commit
08ced011c6
@ -1,9 +1,9 @@
|
|||||||
cmake_minimum_required(VERSION 3.29)
|
cmake_minimum_required(VERSION 3.25)
|
||||||
project(cg1)
|
project(cg1)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
find_package(Qt5Widgets REQUIRED)
|
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui)
|
||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
|
||||||
add_executable(
|
add_executable(
|
||||||
@ -27,3 +27,4 @@ qt5_use_modules(cg1 Widgets)
|
|||||||
|
|
||||||
add_subdirectory(renderer-api)
|
add_subdirectory(renderer-api)
|
||||||
add_subdirectory(utilities)
|
add_subdirectory(utilities)
|
||||||
|
add_subdirectory(qt-utilities)
|
3
qt-utilities/CMakeLists.txt
Normal file
3
qt-utilities/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
add_library(qt_utilities OBJECT src/separate_threaded_renderer.cpp)
|
||||||
|
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)
|
@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <Qt>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QImage>
|
||||||
|
#include <bgtu/computer_graphics_lab_work/renderer_api/voxel_drawer.hpp>
|
||||||
|
#include <bgtu/computer_graphics_lab_work/renderer_api/sprite.hpp>
|
||||||
|
|
||||||
|
namespace BGTU::ComputerGraphicsLabWork::QtUtilities {
|
||||||
|
template<class sprite_data_t>
|
||||||
|
class OwnedQImage : public QImage, public RendererApi::VoxelDrawer::Exporter<sprite_data_t> {
|
||||||
|
private:
|
||||||
|
RendererApi::Sprite<sprite_data_t> const *owners;
|
||||||
|
|
||||||
|
public:
|
||||||
|
OwnedQImage(unsigned width, unsigned height) : QImage(width, height, QImage::Format_ARGB32), owners{new RendererApi::Sprite<sprite_data_t> const *[width * height]} {
|
||||||
|
for (RendererApi::Sprite<sprite_data_t> const *&e: this->owners) {
|
||||||
|
e = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPixelOwner(unsigned x, unsigned y, RendererApi::Sprite<sprite_data_t> const *o) {
|
||||||
|
assert(x < this->width());
|
||||||
|
assert(y < this->height());
|
||||||
|
|
||||||
|
this->owners[y * this->width() + x] = o;
|
||||||
|
}
|
||||||
|
|
||||||
|
RendererApi::Sprite<sprite_data_t> const *getPixelOwner(unsigned x, unsigned y) const {
|
||||||
|
assert(x < this->width());
|
||||||
|
assert(y < this->height());
|
||||||
|
|
||||||
|
return this->owners[y * this->width() + x];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Qt>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QMutex>
|
||||||
|
#include "owned_qimage.hpp"
|
||||||
|
#include "separate_threaded_renderer.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace BGTU::ComputerGraphicsLabWork::QtUtilities {
|
||||||
|
template<class sprite_data_t>
|
||||||
|
class RendererWidget : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMutex sync;
|
||||||
|
OwnedQImage <sprite_data_t> *next_image;
|
||||||
|
OwnedQImage <sprite_data_t> *current_image;
|
||||||
|
SeparateThreadedRenderer
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,143 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Qt>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QElapsedTimer>
|
||||||
|
#include <bgtu/computer_graphics_lab_work/renderer_api/voxel_drawer.hpp>
|
||||||
|
#include <bgtu/computer_graphics_lab_work/renderer_api/sprite.hpp>
|
||||||
|
#include "owned_qimage.hpp"
|
||||||
|
|
||||||
|
namespace BGTU::ComputerGraphicsLabWork::QtUtilities {
|
||||||
|
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, sprite_data_t *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t)>
|
||||||
|
class SeparateThreadedRenderer : public QObject {
|
||||||
|
private:
|
||||||
|
struct data {
|
||||||
|
public:
|
||||||
|
RendererApi::Sprite<sprite_data_t> *const *sprites;
|
||||||
|
std::size_t sprites_count;
|
||||||
|
sprite_data_t const *sprite_data;
|
||||||
|
std::uint_fast64_t ms_per_frame;
|
||||||
|
RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t width, height;
|
||||||
|
RendererApi::Projection *projection;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RendererThread : public QThread {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
SeparateThreadedRenderer *owner;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit inline RendererThread(SeparateThreadedRenderer *owner) : QThread{owner}, owner{owner} {};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void run() final;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
volatile data next_data;
|
||||||
|
QMutex sync;
|
||||||
|
RendererThread *thread;
|
||||||
|
QImage *sentinel_img;
|
||||||
|
renderer_context_t *renderer_context;
|
||||||
|
public:
|
||||||
|
explicit SeparateThreadedRenderer(renderer_context_t *renderer_context, QObject *owner = nullptr);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
void set_frame_size(RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t width, RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t height);
|
||||||
|
|
||||||
|
void set_ms_per_frame(std::uint_fast64_t ms);
|
||||||
|
|
||||||
|
void set_sprites(RendererApi::Sprite<sprite_data_t> *const *sprites, std::size_t sprites_count);
|
||||||
|
|
||||||
|
void set_sprite_data(sprite_data_t const *data);
|
||||||
|
|
||||||
|
void set_sprites_and_data(RendererApi::Sprite<sprite_data_t> *const *sprites, std::size_t sprites_count, sprite_data_t const *data);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void frame_rendered(OwnedQImage<sprite_data_t> *img);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, sprite_data_t *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t)>
|
||||||
|
SeparateThreadedRenderer<sprite_data_t, renderer_context_t, renderer_procedure>::SeparateThreadedRenderer(renderer_context_t *renderer_context, QObject *owner):
|
||||||
|
QObject{owner},
|
||||||
|
sync{},
|
||||||
|
renderer_context{renderer_context},
|
||||||
|
sentinel_img{new QImage(0, 0, QImage::Format_ARGB32)},
|
||||||
|
thread{new RendererThread(this)},
|
||||||
|
next_data{
|
||||||
|
.sprites = nullptr,
|
||||||
|
.sprites_count = 0,
|
||||||
|
.sprite_data = nullptr,
|
||||||
|
.ms_per_frame = 1000 / 60,
|
||||||
|
.width = 0,
|
||||||
|
.height = 0,
|
||||||
|
.projection = nullptr
|
||||||
|
} {
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, sprite_data_t *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t)>
|
||||||
|
void SeparateThreadedRenderer<sprite_data_t, renderer_context_t, renderer_procedure>::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;
|
||||||
|
this->sync.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, sprite_data_t *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t)>
|
||||||
|
void SeparateThreadedRenderer<sprite_data_t, renderer_context_t, renderer_procedure>::set_ms_per_frame(std::uint_fast64_t ms) {
|
||||||
|
this->sync.lock();
|
||||||
|
this->next_data.ms_per_frame = ms;
|
||||||
|
this->sync.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, sprite_data_t *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t)>
|
||||||
|
void SeparateThreadedRenderer<sprite_data_t, renderer_context_t, renderer_procedure>::set_sprites(RendererApi::Sprite<sprite_data_t> *const *sprites, std::size_t sprites_count) {
|
||||||
|
this->sync.lock();
|
||||||
|
this->next_data.sprites = sprites;
|
||||||
|
this->next_data.sprites_count = sprites_count;
|
||||||
|
this->sync.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, sprite_data_t *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t)>
|
||||||
|
void SeparateThreadedRenderer<sprite_data_t, renderer_context_t, renderer_procedure>::set_sprite_data(sprite_data_t const *data) {
|
||||||
|
this->sync.lock();
|
||||||
|
this->next_data.sprite_data = data;
|
||||||
|
this->sync.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, sprite_data_t *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t)>
|
||||||
|
void SeparateThreadedRenderer<sprite_data_t, renderer_context_t, renderer_procedure>::set_sprites_and_data(RendererApi::Sprite<sprite_data_t> *const *sprites, std::size_t sprites_count, sprite_data_t const *data) {
|
||||||
|
this->sync.lock();
|
||||||
|
this->next_data.sprites = sprites;
|
||||||
|
this->next_data.sprites_count = sprites_count;
|
||||||
|
this->next_data.sprite_data = data;
|
||||||
|
this->sync.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, sprite_data_t *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t)>
|
||||||
|
void SeparateThreadedRenderer<sprite_data_t, renderer_context_t, renderer_procedure>::RendererThread::run() {
|
||||||
|
try {
|
||||||
|
QElapsedTimer timer;
|
||||||
|
while (true) {
|
||||||
|
timer.start();
|
||||||
|
this->owner->sync.lock();
|
||||||
|
data cached = this->owner->next_data;
|
||||||
|
this->owner->sync.unlock();
|
||||||
|
|
||||||
|
auto img = new OwnedQImage<sprite_data_t>(cached.width, cached.height);
|
||||||
|
(this->owner->renderer_context->*renderer_procedure)(img, cached.sprite_data, cached.sprites, cached.sprites_count);
|
||||||
|
emit this->owner->frame_rendered(img);
|
||||||
|
QThread::msleep(std::max(cached.ms_per_frame - timer.elapsed(), 0));
|
||||||
|
}
|
||||||
|
} catch (std::exception const &e) {
|
||||||
|
qCritical() << typeid(e).name() << ": " << e.what() << "\n" << "Renderer thread died" << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
4
qt-utilities/src/separate_threaded_renderer.cpp
Normal file
4
qt-utilities/src/separate_threaded_renderer.cpp
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#include <bgtu/computer_graphics_lab_work/qt_utilities/separate_threaded_renderer.hpp>
|
||||||
|
#include <bgtu/computer_graphics_lab_work/qt_utilities/owned_qimage.hpp>
|
||||||
|
#include <bgtu/computer_graphics_lab_work/qt_utilities/renderer_widget.hpp>
|
||||||
|
#include <bgtu/computer_graphics_lab_work/utilities/default_renderer_linear.hpp>
|
@ -7,6 +7,9 @@
|
|||||||
#include "point.hpp"
|
#include "point.hpp"
|
||||||
|
|
||||||
namespace BGTU::ComputerGraphicsLabWork::RendererApi {
|
namespace BGTU::ComputerGraphicsLabWork::RendererApi {
|
||||||
|
template<class>
|
||||||
|
class Sprite;
|
||||||
|
|
||||||
class VoxelDrawer {
|
class VoxelDrawer {
|
||||||
public:
|
public:
|
||||||
using visible_pixel_coordinate_fast_t = std::uint_fast16_t;
|
using visible_pixel_coordinate_fast_t = std::uint_fast16_t;
|
||||||
@ -22,10 +25,15 @@ namespace BGTU::ComputerGraphicsLabWork::RendererApi {
|
|||||||
|
|
||||||
[[nodiscard]] virtual visible_pixel_coordinate_fast_t height() const = 0;
|
[[nodiscard]] virtual visible_pixel_coordinate_fast_t height() const = 0;
|
||||||
|
|
||||||
virtual void update_pixel(PointI<2>::component_t x, PointI<2>::component_t y, double z, Color::Transparent c) = 0;
|
virtual void add_voxel(PointI<2>::component_t x, PointI<2>::component_t y, double z, Color::Transparent c) = 0;
|
||||||
|
|
||||||
inline void update_pixel(PointI<2> p, double z, Color::Transparent c) {
|
inline void add_voxel(PointI<2> p, double z, Color::Transparent c) {
|
||||||
return this->update_pixel(p.x, p.y, z, c);
|
return this->add_voxel(p.x, p.y, z, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class sprite_data_t>
|
||||||
|
class Exporter {
|
||||||
|
virtual void set_pixel(PointI<2>::component_t x, PointI<2>::component_t y, Color c, Sprite<sprite_data_t> const* owner) = 0;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -1,3 +1,3 @@
|
|||||||
add_library(utilities OBJECT src/shader.cpp)
|
add_library(utilities OBJECT src/shader.cpp src/memory_pages_managment.cpp)
|
||||||
target_include_directories(utilities PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
target_include_directories(utilities PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
target_link_libraries(utilities PUBLIC renderer_api)
|
target_link_libraries(utilities PUBLIC renderer_api)
|
@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <climits>
|
||||||
|
// #include <emmintrin.h>
|
||||||
|
#include <bgtu/computer_graphics_lab_work/renderer_api/color.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace BGTU::ComputerGraphicsLabWork::Utilities {
|
||||||
|
RendererApi::Color apply_transparent_color(RendererApi::Color bg, RendererApi::Color::Transparent fg) {
|
||||||
|
#if 1
|
||||||
|
static auto calc = [&](RendererApi::Color::component_fast_t s, RendererApi::Color::component_fast_t o) {
|
||||||
|
auto oo = static_cast<std::uint_fast16_t>(o) * static_cast<std::uint_fast16_t>(fg.alpha);
|
||||||
|
auto ss = static_cast<std::uint_fast16_t>(s) * (static_cast<std::uint_fast16_t>(255) - static_cast<std::uint_fast16_t>(fg.alpha));
|
||||||
|
return static_cast<std::uint_fast8_t >((oo + ss) / 256);
|
||||||
|
};
|
||||||
|
return RendererApi::Color{
|
||||||
|
calc(bg.red, fg.red),
|
||||||
|
calc(bg.green, fg.green),
|
||||||
|
calc(bg.blue, fg.blue)
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
static __m128i vec_256 = _mm_set_epi16(256, 256, 256, 0, 0, 0, 0, 0);
|
||||||
|
__m128i vec_bg = _mm_set_epi16(bg.red, bg.green, bg.blue, 0, 0, 0, 0, 0);
|
||||||
|
__m128i vec_fg = _mm_set_epi16(fg.red, fg.green, fg.blue, 0, 0, 0, 0, 0);
|
||||||
|
__m128i vec_alpha = _mm_set_epi16(fg.alpha, fg.alpha, fg.alpha, 0, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
union {
|
||||||
|
std::uint_fast64_t packed = static_cast<std::uint_fast64_t>(_mm_cvtsi128_si64(_mm_srli_epi16(_mm_add_epi16(_mm_mullo_epi16(vec_fg, vec_alpha), _mm_mullo_epi16(vec_bg, _mm_sub_epi16(vec_256, vec_alpha))), 8)));
|
||||||
|
std::uint16_t unpacked[3];
|
||||||
|
} raw;
|
||||||
|
return RendererApi::Color{
|
||||||
|
static_cast<RendererApi::Color::component_compact_t>(raw.unpacked[0]),
|
||||||
|
static_cast<RendererApi::Color::component_compact_t>(raw.unpacked[1]),
|
||||||
|
static_cast<RendererApi::Color::component_compact_t>(raw.unpacked[2])
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,300 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <limits>
|
||||||
|
#include <new>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <bgtu/computer_graphics_lab_work/renderer_api/color.hpp>
|
||||||
|
#include <bgtu/computer_graphics_lab_work/renderer_api/point.hpp>
|
||||||
|
#include <bgtu/computer_graphics_lab_work/renderer_api/voxel_drawer.hpp>
|
||||||
|
#include <bgtu/computer_graphics_lab_work/renderer_api/sprite.hpp>
|
||||||
|
#include "color.hpp"
|
||||||
|
#include "matrix.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace BGTU::ComputerGraphicsLabWork {
|
||||||
|
namespace Utilities {
|
||||||
|
class DefaultVoxelDrawerLinear : public RendererApi::VoxelDrawer {
|
||||||
|
private:
|
||||||
|
class ZElement {
|
||||||
|
public:
|
||||||
|
ZElement *next;
|
||||||
|
double const z;
|
||||||
|
RendererApi::Color::Transparent const color;
|
||||||
|
RendererApi::Sprite<void> *const owner;
|
||||||
|
|
||||||
|
ZElement(ZElement *next, double z, RendererApi::Color::Transparent color, RendererApi::Sprite<void> *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} {};
|
||||||
|
|
||||||
|
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<class ...args_t>
|
||||||
|
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();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t _width;
|
||||||
|
RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t _height;
|
||||||
|
|
||||||
|
struct pixel_trace_metadata {
|
||||||
|
public:
|
||||||
|
pixel_trace_metadata() : nearest_z{std::numeric_limits<double>::max()}, voxels{nullptr} {};
|
||||||
|
|
||||||
|
double nearest_z;
|
||||||
|
ZElement *voxels;
|
||||||
|
} *pixels_metadata;
|
||||||
|
|
||||||
|
ZElementAllocationBuffer allocator;
|
||||||
|
RendererApi::Sprite<void> *current_artist;
|
||||||
|
public:
|
||||||
|
inline DefaultVoxelDrawerLinear(std::uint_fast16_t width, std::uint_fast16_t height);
|
||||||
|
|
||||||
|
~DefaultVoxelDrawerLinear();
|
||||||
|
|
||||||
|
template<class data_t>
|
||||||
|
void set_current_artist(RendererApi::Sprite<data_t> *sprite) {
|
||||||
|
this->current_artist = reinterpret_cast<RendererApi::Sprite<void> *>(sprite);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline std::uint_fast16_t height() const final {
|
||||||
|
return this->_height;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] inline std::uint_fast16_t width() const final {
|
||||||
|
return this->_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
pixel_trace_metadata *at(std::uint_fast16_t x, std::uint_fast16_t y) {
|
||||||
|
return &(this->pixels_metadata[y * this->_width + x]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void add_voxel(RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t y, double z, RendererApi::Color::Transparent c) final;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
template<class sdata_t>
|
||||||
|
void export_(RendererApi::Color background, RendererApi::VoxelDrawer::Exporter<sdata_t> *receiver);
|
||||||
|
|
||||||
|
void release_resources();
|
||||||
|
};
|
||||||
|
|
||||||
|
DefaultVoxelDrawerLinear::ZElementAllocationBuffer::Cell *DefaultVoxelDrawerLinear::ZElementAllocationBuffer::Page::try_allocate() {
|
||||||
|
if (this->initialized < this->capacity) {
|
||||||
|
Cell *cell = &(this->buffer[this->initialized++]);
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class... args_t>
|
||||||
|
DefaultVoxelDrawerLinear::ZElement *DefaultVoxelDrawerLinear::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...};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DefaultVoxelDrawerLinear::ZElementAllocationBuffer::free_elem(DefaultVoxelDrawerLinear::ZElement *e) {
|
||||||
|
Cell *cell = reinterpret_cast<Cell *>(e);
|
||||||
|
cell->empty.next_empty = this->next_unallocated;
|
||||||
|
this->next_unallocated = cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefaultVoxelDrawerLinear::ZElementAllocationBuffer::release_resources() {
|
||||||
|
Page *p;
|
||||||
|
while (this->last_page != nullptr) {
|
||||||
|
p = this->last_page;
|
||||||
|
this->last_page = p->next;
|
||||||
|
this->_native_free_page(p);
|
||||||
|
}
|
||||||
|
this->next_unallocated = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefaultVoxelDrawerLinear::ZElementAllocationBuffer::reset_allocations() {
|
||||||
|
Page *p = this->last_page;
|
||||||
|
while (p != nullptr) {
|
||||||
|
p->reset_allocations();
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
this->next_unallocated = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultVoxelDrawerLinear::ZElementAllocationBuffer::~ZElementAllocationBuffer() {
|
||||||
|
this->release_resources();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DefaultVoxelDrawerLinear::DefaultVoxelDrawerLinear(std::uint_fast16_t width, std::uint_fast16_t height) :
|
||||||
|
_width{width},
|
||||||
|
_height{height},
|
||||||
|
pixels_metadata{new pixel_trace_metadata[sizeof(ZElement) * width * height]{}},
|
||||||
|
allocator{},
|
||||||
|
current_artist{nullptr} {}
|
||||||
|
|
||||||
|
DefaultVoxelDrawerLinear::~DefaultVoxelDrawerLinear() {
|
||||||
|
delete[] this->pixels_metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefaultVoxelDrawerLinear::add_voxel(RendererApi::PointI<2>::component_t x, RendererApi::PointI<2>::component_t y, double z, RendererApi::Color::Transparent c) {
|
||||||
|
if (x < 0 || this->_width <= x) return;
|
||||||
|
if (y < 0 || this->_height <= y) return;
|
||||||
|
if (z < 0) return;
|
||||||
|
auto p = this->at(x, y);
|
||||||
|
if (z <= p->nearest_z) {
|
||||||
|
p->nearest_z = z;
|
||||||
|
#if 1
|
||||||
|
if (c.alpha == 255) {
|
||||||
|
ZElement *e;
|
||||||
|
while (p->voxels != nullptr) {
|
||||||
|
e = p->voxels;
|
||||||
|
p->voxels = e->next;
|
||||||
|
this->allocator.free_elem(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
p->voxels = this->allocator.alloc_elem(p->voxels, z, c, this->current_artist);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefaultVoxelDrawerLinear::release_resources() {
|
||||||
|
this->allocator.release_resources();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class sdata_t>
|
||||||
|
void DefaultVoxelDrawerLinear::export_(RendererApi::Color background, RendererApi::VoxelDrawer::Exporter<sdata_t> *receiver) {
|
||||||
|
std::vector<ZElement *> sorter;
|
||||||
|
std::uint_fast16_t y = 0;
|
||||||
|
std::uint_fast16_t x = 0;
|
||||||
|
|
||||||
|
for (std::int_fast64_t i = this->_width * this->_height - 1; i >= 0; i--) {
|
||||||
|
for (ZElement *e = this->pixels_metadata[i].voxels; e != nullptr; e = e->next) {
|
||||||
|
sorter.push_back(e);
|
||||||
|
}
|
||||||
|
std::sort(sorter.rbegin(), sorter.rend(), [](ZElement *l, ZElement *r) { return l->z < r->z; });
|
||||||
|
RendererApi::Color p = background;
|
||||||
|
for (auto a: sorter) {
|
||||||
|
p = apply_transparent_color(p, a->color);
|
||||||
|
}
|
||||||
|
receiver->export_pixel(x, y, p, sorter[sorter.size() - 1]->owner);
|
||||||
|
if (++x >= this->_width) {
|
||||||
|
y++;
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace QtUtilities {
|
||||||
|
template<class sprite_data_t, class renderer_context_t, void (renderer_context_t::*renderer_procedure)(RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, sprite_data_t *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t)>
|
||||||
|
class SeparateThreadedRenderer;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
template<class sprite_data_t, bool _private_param>
|
||||||
|
class _SeparateThreadedDefaultRendererLinear {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class sprite_data_t>
|
||||||
|
class _SeparateThreadedDefaultRendererLinear<sprite_data_t, false> {
|
||||||
|
template<class, bool>
|
||||||
|
friend
|
||||||
|
class _SeparateThreadedDefaultRendererLinear;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
_SeparateThreadedDefaultRendererLinear() = delete;
|
||||||
|
|
||||||
|
class Context : public Utilities::DefaultVoxelDrawerLinear<sprite_data_t> {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class _SeparateThreadedDefaultRendererLinear : public SeparateThreadedRenderer<sprite_data_t, SeparateThreadedDefaultRendererLinear < sprite_data_t>, &SeparateThreadedDefaultRendererLinear<sprite_data_t>::render
|
||||||
|
|
||||||
|
> {
|
||||||
|
public:
|
||||||
|
|
||||||
|
void render(RendererApi::VoxelDrawer::Exporter<sprite_data_t> *, sprite_data_t *, RendererApi::Sprite<sprite_data_t> *const *, std::size_t) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
@ -17,11 +17,9 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities {
|
|||||||
elem_t e20, elem_t e21, elem_t e22
|
elem_t e20, elem_t e21, elem_t e22
|
||||||
) : data{e00, e01, e02, e10, e11, e12, e20, e21, e22} {}
|
) : data{e00, e01, e02, e10, e11, e12, e20, e21, e22} {}
|
||||||
|
|
||||||
static inline const Matrix3<elem_t> I{1, 0, 0,
|
static const Matrix3<elem_t> I;
|
||||||
0, 1, 0,
|
|
||||||
0, 0, 1};
|
|
||||||
private:
|
private:
|
||||||
static inline const Matrix3<elem_t> _tmp{};
|
static const Matrix3<elem_t> _tmp;
|
||||||
|
|
||||||
|
|
||||||
template<class operator_t>
|
template<class operator_t>
|
||||||
@ -143,17 +141,14 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities {
|
|||||||
elem_t e30, elem_t e31, elem_t e32, elem_t e33
|
elem_t e30, elem_t e31, elem_t e32, elem_t e33
|
||||||
) : data{e00, e01, e02, e03, e10, e11, e12, e13, e20, e21, e22, e23, e30, e31, e32, e33} {}
|
) : data{e00, e01, e02, e03, e10, e11, e12, e13, e20, e21, e22, e23, e30, e31, e32, e33} {}
|
||||||
|
|
||||||
static inline const Matrix4<elem_t> I{1, 0, 0, 0,
|
static const Matrix4<elem_t> I;
|
||||||
0, 1, 0, 0,
|
|
||||||
0, 0, 1, 0,
|
|
||||||
0, 0, 0, 1};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static inline const Matrix4<elem_t> _tmp{};
|
static const Matrix4<elem_t> _tmp;
|
||||||
|
|
||||||
template<class operator_t>
|
template<class operator_t>
|
||||||
Matrix4<elem_t> _zipmap_matrix(Matrix4<elem_t> const *other, operator_t op) const {
|
Matrix4<elem_t> _zipmap_matrix(Matrix4<elem_t> const *other, operator_t op) const {
|
||||||
Matrix4<elem_t> dst;
|
Matrix4 < elem_t > dst;
|
||||||
auto _map_row = [&](std::size_t row_index) {
|
auto _map_row = [&](std::size_t row_index) {
|
||||||
dst.data[row_index][0] = op(row_index, 0, this->data[row_index][0], other->data[row_index][0]);
|
dst.data[row_index][0] = op(row_index, 0, this->data[row_index][0], other->data[row_index][0]);
|
||||||
dst.data[row_index][1] = op(row_index, 1, this->data[row_index][1], other->data[row_index][1]);
|
dst.data[row_index][1] = op(row_index, 1, this->data[row_index][1], other->data[row_index][1]);
|
||||||
@ -216,7 +211,7 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Matrix4<elem_t> scale(elem_t x, elem_t y, elem_t z) {
|
static Matrix4<elem_t> scale(elem_t x, elem_t y, elem_t z) {
|
||||||
return Matrix4<elem_t>{x, 0, 0, 0,
|
return Matrix4 < elem_t > {x, 0, 0, 0,
|
||||||
0, y, 0, 0,
|
0, y, 0, 0,
|
||||||
0, 0, z, 0,
|
0, 0, z, 0,
|
||||||
0, 0, 0, 1};
|
0, 0, 0, 1};
|
||||||
@ -266,6 +261,24 @@ namespace BGTU::ComputerGraphicsLabWork::Utilities {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class elem_t>
|
||||||
|
const Matrix3<elem_t> Matrix3<elem_t>::I{1, 0, 0, 0,
|
||||||
|
0, 1, 0, 0,
|
||||||
|
0, 0, 1, 0,
|
||||||
|
0, 0, 0, 1};
|
||||||
|
|
||||||
|
template<class elem_t>
|
||||||
|
const Matrix3<elem_t> Matrix3<elem_t>::_tmp{};
|
||||||
|
|
||||||
|
template<class elem_t>
|
||||||
|
const Matrix4<elem_t> Matrix4<elem_t>::I{1, 0, 0, 0,
|
||||||
|
0, 1, 0, 0,
|
||||||
|
0, 0, 1, 0,
|
||||||
|
0, 0, 0, 1};
|
||||||
|
|
||||||
|
template<class elem_t>
|
||||||
|
const Matrix4<elem_t> Matrix4<elem_t>::_tmp{};
|
||||||
|
|
||||||
using Matrix4i = Matrix4<int>;
|
using Matrix4i = Matrix4<int>;
|
||||||
using Matrix4l = Matrix4<long>;
|
using Matrix4l = Matrix4<long>;
|
||||||
using Matrix4f = Matrix4<float>;
|
using Matrix4f = Matrix4<float>;
|
||||||
|
29
utilities/src/memory_pages_managment.cpp
Normal file
29
utilities/src/memory_pages_managment.cpp
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#include <bgtu/computer_graphics_lab_work/utilities/default_renderer_linear.hpp>
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cassert>
|
||||||
|
#include <new>
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
namespace BGTU::ComputerGraphicsLabWork::Utilities {
|
||||||
|
DefaultVoxelDrawerLinear::ZElementAllocationBuffer::Page *DefaultVoxelDrawerLinear::ZElementAllocationBuffer::_native_extend() {
|
||||||
|
SYSTEM_INFO si;
|
||||||
|
GetSystemInfo(&si);
|
||||||
|
|
||||||
|
std::size_t size = max(si.dwPageSize, si.dwAllocationGranularity);
|
||||||
|
|
||||||
|
void *raw = VirtualAlloc(nullptr, max(si.dwPageSize, si.dwAllocationGranularity), MEM_COMMIT, PAGE_READWRITE);
|
||||||
|
if (raw != nullptr) throw std::bad_alloc{};
|
||||||
|
return this->last_page = new(raw)Page(this->last_page, Page::calc_capacity(size));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DefaultVoxelDrawerLinear::ZElementAllocationBuffer::_native_free_page(DefaultVoxelDrawerLinear::ZElementAllocationBuffer::Page *p) {
|
||||||
|
VirtualFree(p, 0, MEM_DECOMMIT | MEM_RELEASE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# error ""
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user