2#include "PotreeSystem.h"
3#include "Foundation/Logging/Logger.h"
4#include "Foundation/Platform/IO.h"
11 float getFloat32(
const uint8_t* ptr)
17 t.u = uint32_t(ptr[0]) | (uint32_t(ptr[1]) << 8) | (uint32_t(ptr[2]) << 16) | (uint32_t(ptr[3]) << 24);
22 uint32_t getUint32(
const uint8_t* ptr)
24 return int32_t(ptr[0]) | (uint32_t(ptr[1]) << 8) | (uint32_t(ptr[2]) << 16) | (uint32_t(ptr[3]) << 24);
27 uint16_t getUint16(
const uint8_t* ptr)
29 return uint16_t(ptr[0]) | (uint16_t(ptr[1]) << 8);
32 uint32_t unMorton3(uint32_t v)
35 uint32_t t0 = 0b0001000001000001000001 & v;
37 uint32_t t1 = 0b1000001000001000001000 & v;
39 uint32_t t2 = t0 | (t1 >> 2);
41 uint32_t t3 = 0b0000000011000000000011 & t2;
43 uint32_t t4 = 0b0011000000000011000000 & t2;
45 uint32_t t5 = t3 | (t4 >> 4);
47 uint32_t t6 = 0b0000000000000000001111 & t5;
49 uint32_t t7 = 0b0000001111000000000000 & t5;
52 uint32_t t8 = t6 | (t7 >> 8u);
62 float cellSizeAtLevel = std::exp2f(-
float(in.cellPos.w));
63 glm::vec3 occupancyShift = (in.fullBBoxMin +
64 in.fullBBoxSize * cellSizeAtLevel * glm::vec3(in.cellPos));
65 glm::vec3 occupancyScale = cellSizeAtLevel * in.fullBBoxSize;
66 glm::vec3 occupancyMaxIndex = glm::vec3(in.occGridDim - 1.f);
67 out.occupancyTmpData.resize(in.occGridDim * in.occGridDim * in.occGridDim);
68 std::memset(out.occupancyTmpData.data(), 0,
sizeof(out.occupancyTmpData[0]) * out.occupancyTmpData.size());
70 out.points.resize(out.pointCount);
72 out.nonEmptyCells = 0;
73 out.lo = glm::vec3(std::numeric_limits<float>::max());
74 out.hi = glm::vec3(-std::numeric_limits<float>::max());
75 for (
size_t i = 0; i < out.pointCount; i++) {
76 const glm::vec3 p = *
reinterpret_cast<const glm::vec3*
>(
reinterpret_cast<const uint8_t*
>(out.vertexData.data()) + i * in.layoutInfo.stride);
77 out.lo = glm::min(out.lo, p);
78 out.hi = glm::max(out.hi, p);
81 glm::vec3 bucket = glm::clamp((p - occupancyShift), glm::vec3(0.0), occupancyMaxIndex);
82 size_t bucketIndex = (
static_cast<size_t>(bucket.x) +
83 in.occGridDim *
static_cast<size_t>(bucket.y) +
84 in.occGridDim * in.occGridDim *
static_cast<size_t>(bucket.z));
85 if (out.occupancyTmpData[bucketIndex] == 0) {
86 out.occupancyTmpData[bucketIndex] = 1;
96 const std::span<const uint8_t> src)
98 struct DataChannel { PotreeAttributes kind = PotreeAttributes::COUNT;
size_t sourceOffset = 0u; };
100 DataChannel position;
103 DataChannel intensity;
104 DataChannel classification;
107 for (
const PotreeAttributes& attribute : in.attributes) {
109 case PotreeAttributes::POSITION_CARTESIAN:
110 position.kind = attribute;
111 position.sourceOffset = size;
112 size += 3 *
sizeof(uint32_t);
114 case PotreeAttributes::RGBA_PACKED:
115 color.kind = attribute;
116 color.sourceOffset = size;
117 size += 4 *
sizeof(uint8_t);
119 case PotreeAttributes::RGB_U8_PACKED:
120 color.kind = attribute;
121 color.sourceOffset = size;
122 size += 3 *
sizeof(uint8_t);
124 case PotreeAttributes::RGB_U16_PACKED:
125 color.kind = attribute;
126 color.sourceOffset = size;
127 size += 3 *
sizeof(uint16_t);
129 case PotreeAttributes::NORMAL:
130 normal.kind = attribute;
131 normal.sourceOffset = size;
132 size += 3 *
sizeof(uint32_t);
134 case PotreeAttributes::FILLER_1B:
135 size += 1 *
sizeof(uint8_t);
137 case PotreeAttributes::NORMAL_SPHEREMAPPED:
138 case PotreeAttributes::NORMAL_OCT16:
139 normal.kind = attribute;
140 normal.sourceOffset = size;
141 size += 2 *
sizeof(uint8_t);
143 case PotreeAttributes::INTENSITY_U16:
144 intensity.kind = attribute;
145 intensity.sourceOffset = size;
146 size += 1 *
sizeof(uint16_t);
148 case PotreeAttributes::CLASSIFICATION:
149 classification.kind = attribute;
150 classification.sourceOffset = size;
151 size += 1 *
sizeof(uint8_t);
154 assert(
false &&
"Invalid attribute enum value");
158 assert(position.kind != PotreeAttributes::COUNT &&
"We should never get this far without a position");
162 out.pointCount = src.size_bytes() / size;
163 if (out.pointCount * size != src.size_bytes()) {
164 LOG_ERROR(logger,
"Cell data size is not a multiple of deduced point data size");
168 assert(in.layoutInfo.stride != ~0u);
170 out.vertexData.resize(in.layoutInfo.stride * out.pointCount,
false);
173 if (position.kind == PotreeAttributes::POSITION_CARTESIAN) {
174 assert(in.layoutInfo.positionOffset != ~0u);
175 auto* sptr = src.data() + position.sourceOffset;
176 auto* dptr =
reinterpret_cast<uint8_t*
>(out.vertexData.data());
178 for (
size_t i = 0; i < out.pointCount; i++) {
179 const glm::vec3 p = in.posScale * glm::vec3(getUint32(sptr + 0),
181 getUint32(sptr + 8)) + in.posShift;
182 *
reinterpret_cast<glm::vec3*
>(dptr) = p;
184 dptr += in.layoutInfo.stride;
187 else { assert(position.kind == PotreeAttributes::COUNT); }
190 if (color.kind == PotreeAttributes::RGB_U8_PACKED) {
191 assert(in.layoutInfo.colorOffset != ~0u);
192 const auto* sptr = src.data() + color.sourceOffset;
193 auto* dptr =
reinterpret_cast<uint8_t*
>(out.vertexData.data()) + in.layoutInfo.colorOffset;
194 for (
size_t i = 0; i < out.pointCount; i++) {
195 for (
size_t k = 0; k < 3; k++) {
200 dptr += in.layoutInfo.stride;
203 else if (color.kind == PotreeAttributes::RGB_U16_PACKED) {
204 assert(in.layoutInfo.colorOffset != ~0u);
205 const auto* sptr = src.data() + color.sourceOffset;
206 auto* dptr =
reinterpret_cast<uint8_t*
>(out.vertexData.data()) + in.layoutInfo.colorOffset;
207 for (
size_t i = 0; i < out.pointCount; i++) {
208 for (
size_t k = 0; k < 3; k++) {
210 dptr[k] =
static_cast<uint8_t
>(getUint16(sptr +
sizeof(uint16_t) * k) >> 8);
214 dptr += in.layoutInfo.stride;
217 else if (color.kind == PotreeAttributes::RGBA_PACKED) {
218 assert(in.layoutInfo.colorOffset != ~0u);
219 const auto* sptr = src.data() + color.sourceOffset;
220 auto* dptr =
reinterpret_cast<uint8_t*
>(out.vertexData.data()) + in.layoutInfo.colorOffset;
221 for (
size_t i = 0; i < out.pointCount; i++) {
222 for (
size_t k = 0; k < 4; k++) {
226 dptr += in.layoutInfo.stride;
229 else { assert(color.kind == PotreeAttributes::COUNT); }
232 if (intensity.kind == PotreeAttributes::INTENSITY_U16) {
233 assert(in.layoutInfo.intensityOffset != ~0u);
234 const auto* sptr = src.data() + intensity.sourceOffset;
235 auto* dptr =
reinterpret_cast<uint8_t*
>(out.vertexData.data()) + in.layoutInfo.intensityOffset;
236 for (
size_t i = 0; i < out.pointCount; i++) {
237 *
reinterpret_cast<float*
>(dptr) = (1.f / 65535.f) * (
static_cast<float>(getUint16(sptr)) + 0.5f);
239 dptr += in.layoutInfo.stride;
242 else { assert(intensity.kind == PotreeAttributes::COUNT); }
250 const std::span<const uint8_t> src)
252 uint8_t attributeByteSize[
static_cast<size_t>(PotreeAttributes::COUNT)] = {
266 size_t pointByteSize = 0;
267 for (
auto& attribute : in.attributes) {
268 assert(
static_cast<size_t>(attribute) <
static_cast<size_t>(PotreeAttributes::COUNT));
269 pointByteSize += attributeByteSize[
static_cast<size_t>(attribute)];
271 out.pointCount = src.size_bytes() / pointByteSize;
272 if (out.pointCount * pointByteSize != src.size_bytes()) {
273 LOG_ERROR(logger,
"Calculated byte size does not match actual size.");
277 assert(in.layoutInfo.stride != ~0u);
278 out.vertexData.resize(in.layoutInfo.stride * out.pointCount,
false);
280 const uint8_t* ptr = src.data();
281 for (
const PotreeAttributes& attribute : in.attributes) {
282 const size_t byteSize = attributeByteSize[
static_cast<size_t>(attribute)];
284 case PotreeAttributes::POSITION_CARTESIAN: {
285 assert(in.layoutInfo.positionOffset != ~0u);
286 uint8_t* dptr =
reinterpret_cast<uint8_t*
>(out.vertexData.data());
288 glm::vec3 lo(std::numeric_limits<float>::max());
289 glm::vec3 hi(-std::numeric_limits<float>::max());
290 for (
size_t i = 0; i < out.pointCount; i++) {
291 uint32_t t0 = ptr[ 8] | (ptr[ 9] << 8) | (ptr[10] << 16);
292 uint32_t t1 = ptr[11] | (ptr[12] << 8) | (ptr[13] << 16);
293 uint32_t t2 = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16);
294 uint32_t t3 = ptr[3] | (ptr[4] << 8) | (ptr[5] << 16);
295 uint32_t xl = unMorton3(t0 >> 0u) | (unMorton3(t1 >> 0u) << 8);
296 uint32_t yl = unMorton3(t0 >> 1u) | (unMorton3(t1 >> 1u) << 8);
297 uint32_t zl = unMorton3(t0 >> 2u) | (unMorton3(t1 >> 2u) << 8);
298 uint32_t xh = (unMorton3(t2 >> 0u) << 16) | (unMorton3(t3 >> 0u) << 24);
299 uint32_t yh = (unMorton3(t2 >> 1u) << 16) | (unMorton3(t3 >> 1u) << 24);
300 uint32_t zh = (unMorton3(t2 >> 2u) << 16) | (unMorton3(t3 >> 2u) << 24);
301 const glm::vec3 p = in.posScale * glm::vec3((xl + xh),
303 (zl + zh)) + in.posShift;
304 *
reinterpret_cast<glm::vec3*
>(dptr) = p;
305 dptr += in.layoutInfo.stride;
310 case PotreeAttributes::RGBA_PACKED:
311 case PotreeAttributes::RGB_U8_PACKED:
312 case PotreeAttributes::RGB_U16_PACKED: {
313 assert(in.layoutInfo.colorOffset != ~0u);
314 auto* dptr =
reinterpret_cast<uint8_t*
>(out.vertexData.data()) + in.layoutInfo.colorOffset;
315 for (
size_t i = 0; i < out.pointCount; i++) {
316 uint32_t t0 = ptr[0] | (ptr[1] << 8u) | (ptr[2] << 16u);
317 uint32_t t1 = ptr[3] | (ptr[4] << 8u) | (ptr[5] << 16u);
318 uint32_t r = unMorton3(t0 >> 0u) | (unMorton3(t1 >> 0u) << 8u);
319 uint32_t g = unMorton3(t0 >> 1u) | (unMorton3(t1 >> 1u) << 8u);
320 uint32_t b = unMorton3(t0 >> 2u) | (unMorton3(t1 >> 2u) << 8u);
321 dptr[0] =
static_cast<uint8_t
>((r <= 0xff) ? r : (r >> 8u));
322 dptr[1] =
static_cast<uint8_t
>((g <= 0xff) ? g : (g >> 8u));
323 dptr[2] =
static_cast<uint8_t
>((b <= 0xff) ? b : (b >> 8u));
325 dptr += in.layoutInfo.stride;
330 case PotreeAttributes::NORMAL:
331 case PotreeAttributes::FILLER_1B:
332 case PotreeAttributes::NORMAL_SPHEREMAPPED:
333 case PotreeAttributes::NORMAL_OCT16:
334 ptr += out.pointCount * byteSize;
336 case PotreeAttributes::INTENSITY_U16: {
337 assert(in.layoutInfo.intensityOffset != ~0u);
338 auto* dptr =
reinterpret_cast<uint8_t*
>(out.vertexData.data()) + in.layoutInfo.intensityOffset;
339 for (
size_t i = 0; i < out.pointCount; i++) {
340 *
reinterpret_cast<float*
>(dptr) = (1.f / 65535.f)* (
static_cast<float>(getUint16(ptr)) + 0.5f);
341 dptr += in.layoutInfo.stride;
346 case PotreeAttributes::CLASSIFICATION:
347 ptr += out.pointCount * byteSize;
350 assert(
false &&
"Invalid attribute enum value");
354 assert(ptr == src.data() + src.size());
364 switch (in.encoding) {
365 case PotreeEnconding::Default:
366 if (!decodeDefault(out, in, std::span < const uint8_t > (inData.
ptr, inData.
size))) {
367 out.state = PotreeDecodeOutData::State::DecodingFailed;
371 case PotreeEnconding::ZStd:
373 LOG_ERROR(logger,
"Parsing bin: ZStd-compressed data was unexpectely not decompressed during transit");
374 out.state = PotreeDecodeOutData::State::DecodingFailed;
377 if (!decodeDefault(out, in, std::span < const uint8_t > (inData.
ptr, inData.
size))) {
378 out.state = PotreeDecodeOutData::State::DecodingFailed;
382 case PotreeEnconding::Brotli:
384 LOG_ERROR(logger,
"Parsing bin: Brotli-compressed data was unexpectely not decompressed during transit");
385 out.state = PotreeDecodeOutData::State::DecodingFailed;
388 if (!decodeMorton(out, in, std::span < const uint8_t > (inData.
ptr, inData.
size))) {
389 out.state = PotreeDecodeOutData::State::DecodingFailed;
394 assert(
false &&
"Invalid encoding enum value");
397 postProcessPoints(out, in);
Log implementation class.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
constexpr Log getLogger(const char(&name)[LEN]) noexcept
@ BrotliDecompress
A hint that the contents are Brotli (Google) compressed and is allowed to be decompressed during tran...
@ ZStdDecompress
A hint that the contents are Zstandard (Facebook) compressed and is allowed to be decompressed during...
Abstract base class storing data read from a file.
size_t size
Number of data bytes.
const uint8_t * ptr
Start of buffer storing file data. Use.