computer-graphics-0/utilities/src/default_renderer_linear.cpp

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);
}
}