#include <gvox/gvox.h>
#include "../shared/gvox_octree.hpp"
#include <cstdlib>
#include <cstdint>
#include <bit>
#include <array>
#include <vector>
#include <new>
struct OctreeParseUserState {
size_t offset{};
Octree gvox_octree{};
};
extern "C" void gvox_parse_adapter_gvox_octree_create(GvoxAdapterContext *ctx, void const * ) {
auto *user_state_ptr = malloc(sizeof(OctreeParseUserState));
new (user_state_ptr) OctreeParseUserState();
gvox_adapter_set_user_pointer(ctx, user_state_ptr);
}
extern "C" void gvox_parse_adapter_gvox_octree_destroy(GvoxAdapterContext *ctx) {
auto &user_state = *static_cast<OctreeParseUserState *>(gvox_adapter_get_user_pointer(ctx));
user_state.~OctreeParseUserState();
free(&user_state);
}
extern "C" void gvox_parse_adapter_gvox_octree_blit_begin(GvoxBlitContext *blit_ctx, GvoxAdapterContext *ctx, GvoxRegionRange const * , uint32_t ) {
auto &user_state = *static_cast<OctreeParseUserState *>(gvox_adapter_get_user_pointer(ctx));
uint64_t magic = 0;
gvox_input_read(blit_ctx, user_state.offset, sizeof(magic), &magic);
user_state.offset += sizeof(magic);
if (magic != std::bit_cast<uint64_t>(std::array<char, 8>{'g', 'v', 'o', 'c', 't', 'r', 'e', 'e'})) {
gvox_adapter_push_error(ctx, GVOX_RESULT_ERROR_PARSE_ADAPTER_INVALID_INPUT, "parsing a RLE format must begin with a valid magic number");
return;
}
gvox_input_read(blit_ctx, user_state.offset, sizeof(GvoxRegionRange), &user_state.gvox_octree.range);
user_state.offset += sizeof(GvoxRegionRange);
uint32_t node_n = 0;
gvox_input_read(blit_ctx, user_state.offset, sizeof(node_n), &node_n);
user_state.offset += sizeof(node_n);
user_state.gvox_octree.nodes.resize(node_n);
gvox_input_read(blit_ctx, user_state.offset, sizeof(user_state.gvox_octree.nodes[0]) * node_n, user_state.gvox_octree.nodes.data());
}
extern "C" void gvox_parse_adapter_gvox_octree_blit_end(GvoxBlitContext * , GvoxAdapterContext * ) {
}
extern "C" auto gvox_parse_adapter_gvox_octree_query_details() -> GvoxParseAdapterDetails {
return {
.preferred_blit_mode = GVOX_BLIT_MODE_DONT_CARE,
};
}
extern "C" auto gvox_parse_adapter_gvox_octree_query_parsable_range(GvoxBlitContext * , GvoxAdapterContext *ctx) -> GvoxRegionRange {
auto &user_state = *static_cast<OctreeParseUserState *>(gvox_adapter_get_user_pointer(ctx));
return user_state.gvox_octree.range;
}
extern "C" auto gvox_parse_adapter_gvox_octree_sample_region(GvoxBlitContext * , GvoxAdapterContext *ctx, GvoxRegion const * , GvoxOffset3D const *offset, uint32_t ) -> GvoxSample {
auto &user_state = *static_cast<OctreeParseUserState *>(gvox_adapter_get_user_pointer(ctx));
if (user_state.gvox_octree.nodes.size() == 1) {
return {user_state.gvox_octree.nodes[0].leaf.color, 1u};
}
auto x_pos = static_cast<uint32_t>(offset->x - user_state.gvox_octree.range.offset.x);
auto y_pos = static_cast<uint32_t>(offset->y - user_state.gvox_octree.range.offset.y);
auto z_pos = static_cast<uint32_t>(offset->z - user_state.gvox_octree.range.offset.z);
uint32_t const voxel_data = user_state.gvox_octree.sample(user_state.gvox_octree.nodes[0].parent, x_pos, y_pos, z_pos);
return {voxel_data, 1u};
}
extern "C" auto gvox_parse_adapter_gvox_octree_query_region_flags(GvoxBlitContext * , GvoxAdapterContext * , GvoxRegionRange const * , uint32_t ) -> uint32_t {
return 0;
}
extern "C" auto gvox_parse_adapter_gvox_octree_load_region(GvoxBlitContext * , GvoxAdapterContext *ctx, GvoxRegionRange const *range, uint32_t channel_flags) -> GvoxRegion {
if ((channel_flags & ~static_cast<uint32_t>(GVOX_CHANNEL_BIT_COLOR)) != 0u) {
gvox_adapter_push_error(ctx, GVOX_RESULT_ERROR_PARSE_ADAPTER_REQUESTED_CHANNEL_NOT_PRESENT, "Tried loading a region with a channel that wasn't present in the original data");
}
GvoxRegion const region = {
.range = *range,
.channels = channel_flags & GVOX_CHANNEL_BIT_COLOR,
.flags = 0u,
.data = nullptr,
};
return region;
}
extern "C" void gvox_parse_adapter_gvox_octree_unload_region(GvoxBlitContext * , GvoxAdapterContext * , GvoxRegion * ) {
}
extern "C" void gvox_parse_adapter_gvox_octree_parse_region(GvoxBlitContext *blit_ctx, GvoxAdapterContext *ctx, GvoxRegionRange const *range, uint32_t channel_flags) {
if ((channel_flags & ~static_cast<uint32_t>(GVOX_CHANNEL_BIT_COLOR)) != 0u) {
gvox_adapter_push_error(ctx, GVOX_RESULT_ERROR_PARSE_ADAPTER_REQUESTED_CHANNEL_NOT_PRESENT, "Tried loading a region with a channel that wasn't present in the original data");
}
GvoxRegion const region = {
.range = *range,
.channels = channel_flags & GVOX_CHANNEL_BIT_COLOR,
.flags = 0u,
.data = nullptr,
};
gvox_emit_region(blit_ctx, ®ion);
}