158 lines
4.7 KiB
C++
158 lines
4.7 KiB
C++
#include <cstdlib>
|
|
#include <bgtu/computer_graphics_lab_work/utilities/default_renderer_linear.hpp>
|
|
|
|
namespace BGTU::ComputerGraphicsLabWork::Utilities {
|
|
|
|
DefaultVoxelDrawerCache::ZElementAllocationBuffer::Cell *DefaultVoxelDrawerCache::ZElementAllocationBuffer::Page::try_allocate() {
|
|
if (this->initialized < this->capacity) {
|
|
Cell *cell = &(this->buffer[this->initialized++]);
|
|
return cell;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void DefaultVoxelDrawerCache::ZElementAllocationBuffer::free_elem(DefaultVoxelDrawerCache::ZElement *e) {
|
|
Cell *cell = reinterpret_cast<Cell *>(e);
|
|
cell->empty.next_empty = this->next_unallocated;
|
|
this->next_unallocated = cell;
|
|
}
|
|
|
|
void DefaultVoxelDrawerCache::ZElementAllocationBuffer::release_resources() {
|
|
Page *p;
|
|
while (this->first_allocated_page != nullptr) {
|
|
p = this->first_allocated_page;
|
|
this->first_allocated_page = p->next;
|
|
this->_native_free_page(p);
|
|
}
|
|
this->next_unallocated = nullptr;
|
|
this->last_allocated_page = nullptr;
|
|
this->next_unfinished_page = nullptr;
|
|
}
|
|
|
|
void DefaultVoxelDrawerCache::ZElementAllocationBuffer::reset_allocations() {
|
|
Page *p = this->first_allocated_page;
|
|
while (p != nullptr) {
|
|
p->reset_allocations();
|
|
p = p->next;
|
|
}
|
|
this->next_unallocated = nullptr;
|
|
this->next_unfinished_page = this->first_allocated_page;
|
|
}
|
|
|
|
DefaultVoxelDrawerCache::ZElementAllocationBuffer::~ZElementAllocationBuffer() {
|
|
this->release_resources();
|
|
}
|
|
|
|
DefaultVoxelDrawerCache::DefaultVoxelDrawerCache() : pixel_trace_elements_allocator{}, pixel_metadata_cache{.buffer = nullptr, .size = 0} {}
|
|
|
|
DefaultVoxelDrawerCache::~DefaultVoxelDrawerCache() {
|
|
if (this->pixel_metadata_cache.buffer != nullptr) {
|
|
std::free(this->pixel_metadata_cache.buffer);
|
|
this->pixel_metadata_cache.buffer = nullptr;
|
|
}
|
|
this->pixel_metadata_cache.size = 0;
|
|
}
|
|
|
|
DefaultVoxelDrawerCache::ZElement *DefaultVoxelDrawerCache::sort_zelements_desc(DefaultVoxelDrawerCache::ZElement *start) noexcept {
|
|
for (std::size_t frame_size = 1; 0 < frame_size && frame_size < std::numeric_limits<std::size_t>::max() / 4; frame_size *= 2) {
|
|
ZElement **before_left = &start;
|
|
|
|
while (true) {
|
|
ZElement **union_ptr = before_left;
|
|
ZElement *left_ptr = *before_left;
|
|
ZElement *right_ptr;
|
|
std::size_t left_counter = frame_size;
|
|
std::size_t right_counter = frame_size;
|
|
|
|
if (left_ptr == nullptr)
|
|
goto ROUND_DONE;
|
|
|
|
right_ptr = left_ptr;
|
|
while (left_counter-- > 0) {
|
|
right_ptr = right_ptr->next;
|
|
if (right_ptr == nullptr)
|
|
goto ROUND_DONE;
|
|
}
|
|
left_counter = frame_size;
|
|
|
|
while (left_counter > 0 && right_counter > 0) {
|
|
if (left_ptr->z >= right_ptr->z) {
|
|
*union_ptr = left_ptr;
|
|
left_ptr = left_ptr->next;
|
|
union_ptr = &((*union_ptr)->next);
|
|
if (left_counter-- == 0)
|
|
goto RIGHT_TAIL;
|
|
} else {
|
|
*union_ptr = right_ptr;
|
|
right_ptr = right_ptr->next;
|
|
union_ptr = &((*union_ptr)->next);
|
|
if (right_counter-- == 0)
|
|
goto LEFT_TAIL;
|
|
|
|
if (right_ptr == nullptr) {
|
|
goto LEFT_TAIL;
|
|
}
|
|
}
|
|
}
|
|
if (right_counter == 0) {
|
|
LEFT_TAIL:
|
|
while (right_counter-- > 1)
|
|
left_ptr = left_ptr->next;
|
|
left_ptr->next = right_ptr;
|
|
before_left = &(left_ptr->next);
|
|
}
|
|
if (left_counter == 0) {
|
|
RIGHT_TAIL:
|
|
*union_ptr = right_ptr;
|
|
while (right_counter-- > 1) {
|
|
right_ptr = right_ptr->next;
|
|
if (right_ptr == nullptr) {
|
|
goto ROUND_DONE;
|
|
}
|
|
}
|
|
before_left = &(right_ptr->next);
|
|
}
|
|
}
|
|
|
|
|
|
ROUND_DONE:
|
|
if (before_left == &start)
|
|
break;
|
|
}
|
|
return start;
|
|
}
|
|
|
|
|
|
DefaultVoxelDrawerCache::VoxelDrawerImpl::VoxelDrawerImpl(
|
|
RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t width,
|
|
RendererApi::VoxelDrawer::visible_pixel_coordinate_fast_t height,
|
|
DefaultVoxelDrawerCache::pixel_trace_metadata *pixels_metadata,
|
|
DefaultVoxelDrawerCache::ZElementAllocationBuffer *pixel_trace_elements_allocator
|
|
) : _width{width},
|
|
_height{height},
|
|
pixels_metadata{pixels_metadata},
|
|
pixel_trace_elements_allocator{pixel_trace_elements_allocator},
|
|
current_artist{nullptr} {}
|
|
|
|
|
|
void DefaultVoxelDrawerCache::VoxelDrawerImpl::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->pixel_trace_elements_allocator->free_elem(e);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
p->voxels = this->pixel_trace_elements_allocator->alloc_elem(p->voxels, z, c, this->current_artist);
|
|
}
|
|
} |