#include #include 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(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::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); } }