refactor out debug functions and common, store hdri in exe
This commit is contained in:
parent
1b40cd52cc
commit
8bc7ae09c6
13
common.h
Normal file
13
common.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Structure to hold voxel information
|
||||||
|
struct newVoxel {
|
||||||
|
uint32_t x, y, z; // 3D coordinates
|
||||||
|
uint8_t color; // Color value
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct dsVoxel {
|
||||||
|
uint8_t layer;
|
||||||
|
uint8_t color;
|
||||||
|
};
|
||||||
586
debug.cpp
Normal file
586
debug.cpp
Normal file
@ -0,0 +1,586 @@
|
|||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes a voxel's layercolor and color from the ds data stream
|
||||||
|
*
|
||||||
|
* @param dsData The raw ds data stream containing layer-color pairs
|
||||||
|
* @return A vector of Voxel structures with explicit coordinates and colors
|
||||||
|
*/
|
||||||
|
std::vector<newVoxel> decodeVoxels2(const std::vector<uint8_t>& dsData, int mortonOffset) {
|
||||||
|
std::vector<newVoxel> voxels;
|
||||||
|
for (int i = 0; i < dsData.size() - 1; i += 2) {
|
||||||
|
dsVoxel _vxVoxel; // VoxelMax data
|
||||||
|
_vxVoxel.layer = static_cast<int>(dsData[i]);
|
||||||
|
_vxVoxel.color = static_cast<uint8_t>(dsData[i + 1]);
|
||||||
|
uint32_t dx, dy, dz;
|
||||||
|
decodeMorton3DOptimized(i/2 + mortonOffset, dx, dy, dz); // index IS the morton code
|
||||||
|
if (_vxVoxel.color != 0) {
|
||||||
|
newVoxel voxel = {dx, dy, dz, _vxVoxel.color};
|
||||||
|
voxels.push_back(voxel);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return voxels;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print a plist node's contents recursively.
|
||||||
|
* This function takes a plist node and prints its contents in a human-readable format.
|
||||||
|
* It handles all types of plist nodes (dictionaries, arrays, strings, etc.) by using
|
||||||
|
* recursion to traverse the entire plist structure.
|
||||||
|
*
|
||||||
|
* @param node The plist node to print (plist_t is a pointer to the internal plist structure)
|
||||||
|
* @param indent The current indentation level (defaults to 0 for the root node)
|
||||||
|
*/
|
||||||
|
void printPlistNode(const plist_t& node, int indent ) {
|
||||||
|
// Early return if node is null (safety check)
|
||||||
|
if (!node) return;
|
||||||
|
|
||||||
|
// Create a string with 'indent * 2' spaces for proper indentation
|
||||||
|
// This helps visualize the hierarchy of nested structures
|
||||||
|
std::string indentStr(indent * 2, ' ');
|
||||||
|
|
||||||
|
// Get the type of the current node (dictionary, array, string, etc.)
|
||||||
|
plist_type nodeType = plist_get_node_type(node);
|
||||||
|
|
||||||
|
// Handle each type of node differently
|
||||||
|
switch (nodeType) {
|
||||||
|
case PLIST_DICT: {
|
||||||
|
std::cout << indentStr << "Dictionary:" << std::endl;
|
||||||
|
|
||||||
|
// Create an iterator for the dictionary
|
||||||
|
// nullptr is passed as initial value; the iterator will be allocated by plist_dict_new_iter
|
||||||
|
plist_dict_iter it = nullptr;
|
||||||
|
plist_dict_new_iter(node, &it);
|
||||||
|
|
||||||
|
// Variables to store the current key-value pair
|
||||||
|
char* key = nullptr; // Will hold the dictionary key (needs to be freed)
|
||||||
|
plist_t value = nullptr; // Will hold the value node
|
||||||
|
|
||||||
|
// Iterate through all items in the dictionary
|
||||||
|
while (true) {
|
||||||
|
// Get the next key-value pair
|
||||||
|
plist_dict_next_item(node, it, &key, &value);
|
||||||
|
|
||||||
|
// Break if we've reached the end of the dictionary
|
||||||
|
if (!key || !value) break;
|
||||||
|
|
||||||
|
// Print the key and recursively print its value
|
||||||
|
std::cout << indentStr << " " << key << ":" << std::endl;
|
||||||
|
printPlistNode(value, indent + 2); // Increase indent for nested values
|
||||||
|
|
||||||
|
// Free the key string (allocated by plist_dict_next_item)
|
||||||
|
free(key);
|
||||||
|
key = nullptr; // Set to nullptr to avoid double-free
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free the iterator when done
|
||||||
|
free(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PLIST_ARRAY: {
|
||||||
|
std::cout << indentStr << "Array:" << std::endl;
|
||||||
|
uint32_t size = plist_array_get_size(node);
|
||||||
|
for (uint32_t i = 0; i < size; i++) {
|
||||||
|
plist_t item = plist_array_get_item(node, i);
|
||||||
|
std::cout << indentStr << " [" << i << "]:" << std::endl;
|
||||||
|
printPlistNode(item, indent + 2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PLIST_STRING: {
|
||||||
|
char* str = nullptr;
|
||||||
|
plist_get_string_val(node, &str);
|
||||||
|
std::cout << indentStr << "String: " << (str ? str : "(null)") << std::endl;
|
||||||
|
free(str);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PLIST_BOOLEAN: {
|
||||||
|
uint8_t bval;
|
||||||
|
plist_get_bool_val(node, &bval);
|
||||||
|
std::cout << indentStr << "Boolean: " << (bval ? "true" : "false") << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PLIST_UINT: {
|
||||||
|
uint64_t val;
|
||||||
|
plist_get_uint_val(node, &val);
|
||||||
|
std::cout << indentStr << "Integer: " << val << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PLIST_REAL: {
|
||||||
|
double val;
|
||||||
|
plist_get_real_val(node, &val);
|
||||||
|
std::cout << indentStr << "Real: " << val << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PLIST_DATE: {
|
||||||
|
int32_t sec = 0;
|
||||||
|
int32_t usec = 0;
|
||||||
|
plist_get_date_val(node, &sec, &usec);
|
||||||
|
std::cout << indentStr << "Date: " << sec << "." << usec << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PLIST_DATA: {
|
||||||
|
char* data = nullptr;
|
||||||
|
uint64_t length = 0;
|
||||||
|
plist_get_data_val(node, &data, &length);
|
||||||
|
std::cout << indentStr << "Data: <" << length << " bytes>" << std::endl;
|
||||||
|
free(data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
std::cout << indentStr << "Unknown type" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* New visualization function that definitely uses the correct z-plane
|
||||||
|
*
|
||||||
|
* @param voxels The vector of decoded voxels
|
||||||
|
* @param zPlane The z-coordinate of the plane to visualize
|
||||||
|
* @param size The size of the grid (default: 32x32)
|
||||||
|
*/
|
||||||
|
void visualizeZPlaneFixed(const std::vector<newVoxel>& voxels, int zPlane, int size ) {
|
||||||
|
// Bounds checking
|
||||||
|
const int MIN_Z = 0;
|
||||||
|
const int MAX_Z = 31;
|
||||||
|
if (zPlane < MIN_Z || zPlane > MAX_Z) {
|
||||||
|
std::cout << "WARNING: z-plane value " << zPlane << " is out of bounds. Valid range is " << MIN_Z << "-" << MAX_Z << ". Using z=0 instead." << std::endl;
|
||||||
|
zPlane = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Visualizing z-plane: " << zPlane << std::endl;
|
||||||
|
|
||||||
|
// Create a 2D grid for visualization
|
||||||
|
std::vector<std::vector<char>> grid(size, std::vector<char>(size, ' '));
|
||||||
|
|
||||||
|
// Count voxels for statistics
|
||||||
|
int totalVoxels = voxels.size();
|
||||||
|
int voxelsAtRequestedZ = 0;
|
||||||
|
int coloredVoxels = 0;
|
||||||
|
int clearVoxels = 0;
|
||||||
|
|
||||||
|
// Loop 1: Debug output for the first few matching voxels
|
||||||
|
int debugCount = 0;
|
||||||
|
for (const auto& voxel : voxels) {
|
||||||
|
if (voxel.z == zPlane) {
|
||||||
|
voxelsAtRequestedZ++;
|
||||||
|
|
||||||
|
// Update the grid and count color types
|
||||||
|
if (voxel.x >= 0 && voxel.x < size && voxel.y >= 0 && voxel.y < size) {
|
||||||
|
if (voxel.color == 0x00) {
|
||||||
|
grid[voxel.y][voxel.x] = '.'; // Clear voxel (0x00)
|
||||||
|
clearVoxels++;
|
||||||
|
} else if (voxel.color == 0x25) {
|
||||||
|
grid[voxel.y][voxel.x] = '#'; // Colored voxel (0x25)
|
||||||
|
coloredVoxels++;
|
||||||
|
} else {
|
||||||
|
grid[voxel.y][voxel.x] = 'X'; // Other color
|
||||||
|
coloredVoxels++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print statistics
|
||||||
|
std::cout << "\nVisualization Statistics:" << std::endl;
|
||||||
|
std::cout << "- Total voxels in data: " << totalVoxels << std::endl;
|
||||||
|
std::cout << "- Voxels at z=" << zPlane << ": " << voxelsAtRequestedZ << std::endl;
|
||||||
|
std::cout << "- Colored voxels: " << coloredVoxels << " (shown as '#' or 'X')" << std::endl;
|
||||||
|
std::cout << "- Clear voxels: " << clearVoxels << " (shown as '.')" << std::endl;
|
||||||
|
|
||||||
|
// If no matching voxels were found, print a message and return
|
||||||
|
if (voxelsAtRequestedZ == 0) {
|
||||||
|
std::cout << "\n*** NO VOXELS FOUND AT Z=" << zPlane << " ***\n" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print legend
|
||||||
|
std::cout << "\nLegend:" << std::endl;
|
||||||
|
std::cout << "- '#': Color 0x25" << std::endl;
|
||||||
|
std::cout << "- '.': Clear (0x00)" << std::endl;
|
||||||
|
std::cout << "- 'X': Other colors" << std::endl;
|
||||||
|
std::cout << "- ' ': No voxel present" << std::endl;
|
||||||
|
std::cout << "- Each 8x4 section represents one subchunk" << std::endl;
|
||||||
|
|
||||||
|
// Print x-axis header
|
||||||
|
std::cout << "\n ";
|
||||||
|
for (int x = 0; x < size; x++) {
|
||||||
|
if (x % 8 == 0) {
|
||||||
|
std::cout << "|"; // Mark subchunk boundaries
|
||||||
|
} else {
|
||||||
|
std::cout << x % 10; // Print digit for readability
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
// Print divider line
|
||||||
|
std::cout << " ";
|
||||||
|
for (int x = 0; x < size; x++) {
|
||||||
|
if (x % 8 == 0) {
|
||||||
|
std::cout << "+"; // Mark subchunk corners
|
||||||
|
} else {
|
||||||
|
std::cout << "-";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
// Print grid with y-axis labels and subchunk markers
|
||||||
|
for (int y = 0; y < size; y++) {
|
||||||
|
std::cout << std::setw(2) << y << " ";
|
||||||
|
|
||||||
|
// Mark subchunk boundaries on y-axis
|
||||||
|
if (y % 4 == 0) {
|
||||||
|
std::cout << "+";
|
||||||
|
} else {
|
||||||
|
std::cout << "|";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the actual voxel data for this row
|
||||||
|
for (int x = 0; x < size; x++) {
|
||||||
|
std::cout << grid[y][x];
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "\n===============================================\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Examines a specific array element at the given index from a plist file.
|
||||||
|
* This function allows inspection of individual chunks/snapshots in the data.
|
||||||
|
*
|
||||||
|
* @param plistFilePath Path to the plist file
|
||||||
|
* @param index The index of the array element to examine
|
||||||
|
* @param arrayPath The path to the array in the plist structure
|
||||||
|
* @return true if successful, false if any errors occurred
|
||||||
|
*/
|
||||||
|
bool examinePlistNode(const plist_t& root_node, int snapshotIndex, int zIndex, const std::string& arrayPath) {
|
||||||
|
std::cout << "Examining Plist array at snapshot " << snapshotIndex << " zIndex " << zIndex << std::endl;
|
||||||
|
|
||||||
|
if (!root_node) {
|
||||||
|
std::cerr << "Failed to process Plist data" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
plist_t current_node = root_node;
|
||||||
|
// if the array path contains slashes, we need to navigate through the structure
|
||||||
|
std::string path = arrayPath;
|
||||||
|
size_t pos = 0;
|
||||||
|
std::string token;
|
||||||
|
while ((pos = path.find('/')) != std::string::npos) {
|
||||||
|
token = path.substr(0, pos);
|
||||||
|
path.erase(0, pos + 1);
|
||||||
|
|
||||||
|
// current node must be a dictionary
|
||||||
|
if (plist_get_node_type(current_node) != PLIST_DICT) {
|
||||||
|
std::cerr << "error: expected dictionary at path component '" << token << "'" << std::endl;
|
||||||
|
//plist_free(root_node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the next node in the path
|
||||||
|
current_node = plist_dict_get_item(current_node, token.c_str());
|
||||||
|
if (!current_node) {
|
||||||
|
std::cerr << "error: could not find key '" << token << "' in dictionary" << std::endl;
|
||||||
|
//plist_free(root_node);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now path contains the final key name
|
||||||
|
if (!path.empty() && plist_get_node_type(current_node) == PLIST_DICT) {
|
||||||
|
current_node = plist_dict_get_item(current_node, path.c_str());
|
||||||
|
if (!current_node) {
|
||||||
|
std::cerr << "Error: Could not find key '" << path << "' in dictionary" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we found an array
|
||||||
|
if (plist_get_node_type(current_node) != PLIST_ARRAY) {
|
||||||
|
std::cerr << "Error: '" << "arrayPath" << "' is not an array" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Plist node array size
|
||||||
|
uint32_t arraySize = plist_array_get_size(current_node);
|
||||||
|
if (snapshotIndex < 0 || snapshotIndex >= static_cast<int>(arraySize)) {
|
||||||
|
std::cerr << "Error: Index " << snapshotIndex << " is out of range (array size: " << arraySize << ")" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the Plist node at the specified index
|
||||||
|
plist_t element = plist_array_get_item(current_node, snapshotIndex);
|
||||||
|
if (!element) {
|
||||||
|
std::cerr << "Error: Could not get Plist node at snapshot " << snapshotIndex << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Array size: " << arraySize << std::endl;
|
||||||
|
std::cout << "Plist node details at snapshot " << snapshotIndex << " zIndex " << zIndex << ":" << std::endl;
|
||||||
|
printPlistNode(element);
|
||||||
|
debugSnapshots(element, snapshotIndex, zIndex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Handles 's' dictionary in a Plist node holding 32x32x32 chunks of voxel data.
|
||||||
|
*
|
||||||
|
* @param element The Plist node to examine
|
||||||
|
* @return true if successful, false if any errors occurred
|
||||||
|
*/
|
||||||
|
bool debugSnapshots(plist_t element, int snapshotIndex, int zIndex) {
|
||||||
|
std::cout << "Debugging snapshots" << std::endl;
|
||||||
|
// Special handling for 's' dictionaries
|
||||||
|
if (plist_get_node_type(element) == PLIST_DICT) {
|
||||||
|
plist_t sNode = plist_dict_get_item(element, "s");
|
||||||
|
if (sNode) {
|
||||||
|
// Look for specific keys of interest in the 's' dictionary
|
||||||
|
if (plist_get_node_type(sNode) == PLIST_DICT) {
|
||||||
|
// Check for 'ds' (data stream) in the 's' dictionary
|
||||||
|
plist_t dsNode = plist_dict_get_item(sNode, "ds");
|
||||||
|
if (dsNode && plist_get_node_type(dsNode) == PLIST_DATA) {
|
||||||
|
char* data = nullptr;
|
||||||
|
uint64_t length = 0;
|
||||||
|
plist_get_data_val(dsNode, &data, &length);
|
||||||
|
|
||||||
|
std::cout << "\nDetailed analysis of 'ds' data stream (size: " << length << " bytes):" << std::endl;
|
||||||
|
|
||||||
|
// Detailed analysis of the data stream
|
||||||
|
if (length > 0 && data) {
|
||||||
|
// Display as hex bytes - increased to 384 bytes
|
||||||
|
std::cout << "First 384 bytes (hex):" << std::endl;
|
||||||
|
size_t bytesToShow = std::min(static_cast<size_t>(384), static_cast<size_t>(length));
|
||||||
|
for (size_t i = 0; i < bytesToShow; i++) {
|
||||||
|
std::cout << std::hex << std::setw(2) << std::setfill('0')
|
||||||
|
<< static_cast<int>(static_cast<uint8_t>(data[i])) << " ";
|
||||||
|
if ((i + 1) % 16 == 0) std::cout << std::endl;
|
||||||
|
}
|
||||||
|
std::cout << std::dec << std::endl;
|
||||||
|
|
||||||
|
// If data appears to be position-color pairs (as in voxel data)
|
||||||
|
if (length % 2 == 0) {
|
||||||
|
size_t numPairs = length / 2;
|
||||||
|
std::cout << "Data appears to contain " << numPairs << " position-color pairs" << std::endl;
|
||||||
|
|
||||||
|
// Check if all positions are 0 (common for optimized voxel data)
|
||||||
|
bool allPositionsZero = true;
|
||||||
|
for (size_t i = 0; i < std::min(numPairs, static_cast<size_t>(100)); i++) {
|
||||||
|
if (static_cast<uint8_t>(data[i * 2]) != 0) {
|
||||||
|
allPositionsZero = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allPositionsZero) {
|
||||||
|
// Show only color values for more compact analysis
|
||||||
|
std::cout << "\nAll position values are 0. Showing only color values:" << std::endl;
|
||||||
|
std::cout << "First 384 color values (hex):" << std::endl;
|
||||||
|
size_t colorsToShow = std::min(static_cast<size_t>(384), numPairs);
|
||||||
|
for (size_t i = 0; i < colorsToShow; i++) {
|
||||||
|
std::cout << std::hex << std::setw(2) << std::setfill('0')
|
||||||
|
<< static_cast<int>(static_cast<uint8_t>(data[i * 2 + 1])) << " ";
|
||||||
|
if ((i + 1) % 16 == 0) std::cout << std::endl;
|
||||||
|
}
|
||||||
|
std::cout << std::dec << std::endl;
|
||||||
|
} else {
|
||||||
|
// Show position-color pairs if positions vary
|
||||||
|
std::cout << "\nFirst 10 position-color pairs:" << std::endl;
|
||||||
|
std::cout << "Index | Position | Color" << std::endl;
|
||||||
|
std::cout << "------|----------|------" << std::endl;
|
||||||
|
|
||||||
|
size_t pairsToShow = std::min(static_cast<size_t>(10), numPairs);
|
||||||
|
for (size_t i = 0; i < pairsToShow; i++) {
|
||||||
|
uint8_t position = static_cast<uint8_t>(data[i * 2]);
|
||||||
|
uint8_t color = static_cast<uint8_t>(data[i * 2 + 1]);
|
||||||
|
|
||||||
|
std::cout << std::setw(5) << i << " | "
|
||||||
|
<< std::setw(8) << std::hex << std::setfill('0')
|
||||||
|
<< static_cast<int>(position) << std::dec << std::setfill(' ') << " | "
|
||||||
|
<< std::setw(5) << std::hex << std::setfill('0')
|
||||||
|
<< static_cast<int>(color) << std::dec << std::setfill(' ') << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Analyze and print color runs
|
||||||
|
std::cout << "\nAnalyzing color runs:" << std::endl;
|
||||||
|
|
||||||
|
if (numPairs > 0) {
|
||||||
|
uint8_t currentColor = static_cast<uint8_t>(data[1]); // First color
|
||||||
|
size_t runStart = 0;
|
||||||
|
size_t runLength = 1;
|
||||||
|
|
||||||
|
// Find all runs
|
||||||
|
std::vector<std::tuple<size_t, size_t, uint8_t>> colorRuns;
|
||||||
|
|
||||||
|
for (size_t i = 1; i < numPairs; i++) {
|
||||||
|
uint8_t color = static_cast<uint8_t>(data[i * 2 + 1]);
|
||||||
|
|
||||||
|
if (color == currentColor) {
|
||||||
|
// Continue the current run
|
||||||
|
runLength++;
|
||||||
|
} else {
|
||||||
|
// End the current run and start a new one
|
||||||
|
colorRuns.emplace_back(runStart, runStart + runLength - 1, currentColor);
|
||||||
|
currentColor = color;
|
||||||
|
runStart = i;
|
||||||
|
runLength = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the last run
|
||||||
|
colorRuns.emplace_back(runStart, runStart + runLength - 1, currentColor);
|
||||||
|
|
||||||
|
// Print the runs in a condensed format
|
||||||
|
std::cout << "Found " << colorRuns.size() << " color runs:" << std::endl;
|
||||||
|
std::cout << "Color | Voxel Count | Range" << std::endl;
|
||||||
|
std::cout << "------|-------------|------" << std::endl;
|
||||||
|
|
||||||
|
for (const auto& run : colorRuns) {
|
||||||
|
size_t start = std::get<0>(run);
|
||||||
|
size_t end = std::get<1>(run);
|
||||||
|
uint8_t color = std::get<2>(run);
|
||||||
|
size_t length = end - start + 1;
|
||||||
|
|
||||||
|
std::cout << " 0x" << std::hex << std::setw(2) << std::setfill('0')
|
||||||
|
<< static_cast<int>(color) << " | "
|
||||||
|
<< std::dec << std::setfill(' ') << std::setw(11) << length << " | "
|
||||||
|
<< std::setw(5) << start << "-" << std::setw(5) << end
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add special notice for full-voxel-space runs
|
||||||
|
if (colorRuns.size() == 1) {
|
||||||
|
const auto& singleRun = colorRuns[0];
|
||||||
|
size_t start = std::get<0>(singleRun);
|
||||||
|
size_t end = std::get<1>(singleRun);
|
||||||
|
size_t length = end - start + 1;
|
||||||
|
uint8_t color = std::get<2>(singleRun);
|
||||||
|
|
||||||
|
if (start == 0 && length == 32768) {
|
||||||
|
std::cout << "\nNOTICE: This chunk contains a single color (0x"
|
||||||
|
<< std::hex << static_cast<int>(color) << std::dec
|
||||||
|
<< ") for all 32,768 voxels, which would fill a complete 32x32x32 voxel space." << std::endl;
|
||||||
|
std::cout << "This could indicate:";
|
||||||
|
std::cout << "\n - A solid block of one color";
|
||||||
|
std::cout << "\n - A special encoding for empty/default chunks";
|
||||||
|
std::cout << "\n - A placeholder or initialization state" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode voxels for visualization
|
||||||
|
// @param TODO: get morton offset from the 'lt' dictionary
|
||||||
|
std::vector<newVoxel> voxels = decodeVoxels2(std::vector<uint8_t>(data, data + length), 0);
|
||||||
|
|
||||||
|
printVoxelTable(voxels, 100);
|
||||||
|
|
||||||
|
// Explicitly decode the voxels for visualization
|
||||||
|
char* data = nullptr;
|
||||||
|
uint64_t length = 0;
|
||||||
|
plist_get_data_val(dsNode, &data, &length);
|
||||||
|
|
||||||
|
if (length > 0 && data) {
|
||||||
|
std::vector<newVoxel> voxels = decodeVoxels2(std::vector<uint8_t>(data, data + length), 0);
|
||||||
|
visualizeZPlaneFixed(voxels, zIndex);
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for 'id' dictionary to get chunk information
|
||||||
|
plist_t idNode = plist_dict_get_item(sNode, "id");
|
||||||
|
if (idNode && plist_get_node_type(idNode) == PLIST_DICT) {
|
||||||
|
plist_t chunkIdNode = plist_dict_get_item(idNode, "c");
|
||||||
|
if (chunkIdNode && plist_get_node_type(chunkIdNode) == PLIST_UINT) {
|
||||||
|
uint64_t chunkId;
|
||||||
|
plist_get_uint_val(chunkIdNode, &chunkId);
|
||||||
|
std::cout << "\nChunk ID: " << chunkId << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for 'lt' (location table)
|
||||||
|
plist_t ltNode = plist_dict_get_item(sNode, "lt");
|
||||||
|
if (ltNode && plist_get_node_type(ltNode) == PLIST_DATA) {
|
||||||
|
char* data = nullptr;
|
||||||
|
uint64_t length = 0;
|
||||||
|
plist_get_data_val(ltNode, &data, &length);
|
||||||
|
|
||||||
|
std::cout << "\nLocation table size: " << length << " bytes" << std::endl;
|
||||||
|
if (length > 0 && data) {
|
||||||
|
std::cout << "First 16 bytes of location table:" << std::endl;
|
||||||
|
size_t bytesToShow = std::min(static_cast<size_t>(16), static_cast<size_t>(length));
|
||||||
|
for (size_t i = 0; i < bytesToShow; i++) {
|
||||||
|
std::cout << std::hex << std::setw(2) << std::setfill('0')
|
||||||
|
<< static_cast<int>(static_cast<uint8_t>(data[i])) << " ";
|
||||||
|
}
|
||||||
|
std::cout << std::dec << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints a table of voxel positions and colors
|
||||||
|
*
|
||||||
|
* @param voxels The vector of decoded voxels
|
||||||
|
* @param limit Maximum number of voxels to display (0 for all)
|
||||||
|
* @param filterZ Optional z-value to filter by
|
||||||
|
*/
|
||||||
|
void printVoxelTable(const std::vector<newVoxel>& voxels, size_t limit , int filterZ ) {
|
||||||
|
int emptyVoxels = 32768 - voxels.size();
|
||||||
|
std::cout << "Voxels: " << voxels.size() << " Empty: " << emptyVoxels << std::endl;
|
||||||
|
|
||||||
|
// Count voxels at the filtered z-level if filtering is active
|
||||||
|
int filteredCount = 0;
|
||||||
|
if (filterZ >= 0) {
|
||||||
|
for (const auto& voxel : voxels) {
|
||||||
|
if (voxel.z == filterZ) filteredCount++;
|
||||||
|
}
|
||||||
|
std::cout << "Voxels at z=" << filterZ << ": " << filteredCount << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Index | X | Y | Z | Color" << std::endl;
|
||||||
|
std::cout << "------|----|----|----|---------" << std::endl;
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
int shownCount = 0;
|
||||||
|
for (size_t i = 0; i < voxels.size(); i++) {
|
||||||
|
const auto& voxel = voxels[i];
|
||||||
|
|
||||||
|
// Skip if we're filtering by z and this doesn't match
|
||||||
|
if (filterZ >= 0 && voxel.z != filterZ) continue;
|
||||||
|
|
||||||
|
std::cout << std::setw(6) << i << " | ";
|
||||||
|
std::cout << std::setw(2) << voxel.x << " | ";
|
||||||
|
std::cout << std::setw(2) << voxel.y << " | ";
|
||||||
|
std::cout << std::setw(2) << voxel.z << " | ";
|
||||||
|
std::cout << "0x" << std::hex << std::setw(2) << std::setfill('0')
|
||||||
|
<< static_cast<int>(voxel.color) << std::dec << std::setfill(' ') << std::endl;
|
||||||
|
|
||||||
|
// Count shown voxels
|
||||||
|
shownCount++;
|
||||||
|
|
||||||
|
// Check if we've reached the limit
|
||||||
|
if (limit > 0 && shownCount >= limit) {
|
||||||
|
if (filterZ >= 0) {
|
||||||
|
int remaining = filteredCount - shownCount;
|
||||||
|
if (remaining > 0) {
|
||||||
|
std::cout << "... (output truncated, " << remaining << " more voxels at z=" << filterZ << ")" << std::endl;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::cout << "... (output truncated, " << (voxels.size() - shownCount) << " more voxels)" << std::endl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
24
debug.h
Normal file
24
debug.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iomanip>
|
||||||
|
#include "../libplist/include/plist/plist.h" // Library for handling Apple property list files
|
||||||
|
#include "common.h" // Debugging functions
|
||||||
|
// Include any necessary structures
|
||||||
|
|
||||||
|
// Optimized function to compact bits (From VoxelMax)
|
||||||
|
uint32_t compactBits(uint32_t n);
|
||||||
|
// Optimized function to decode Morton code using parallel bit manipulation
|
||||||
|
void decodeMorton3DOptimized(uint32_t morton, uint32_t& x, uint32_t& y, uint32_t& z);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Function declarations
|
||||||
|
std::vector<newVoxel> decodeVoxels(const std::vector<uint8_t>& dsData, int mortonOffset);
|
||||||
|
void printPlistNode(const plist_t& node, int indent = 0);
|
||||||
|
bool examinePlistNode(const plist_t& root_node, int snapshotIndex, int zIndex, const std::string& arrayPath);
|
||||||
|
bool debugSnapshots(plist_t element, int snapshotIndex, int zIndex);
|
||||||
|
void printVoxelTable(const std::vector<newVoxel>& voxels, size_t limit = 100, int filterZ = -1);
|
||||||
|
void visualizeZPlaneFixed(const std::vector<newVoxel>& voxels, int zPlane, int size = 32);
|
||||||
70
extra.cpp
Normal file
70
extra.cpp
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#include "extra.h"
|
||||||
|
// Function that returns the license text for this program
|
||||||
|
std::string initializeGlobalLicense()
|
||||||
|
{
|
||||||
|
// R"(...)" is a C++ raw string literal - allows multi-line strings with preserved formatting
|
||||||
|
return R"(
|
||||||
|
vmax2bella
|
||||||
|
|
||||||
|
Copyright (c) 2025 Harvey Fong
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.)";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function that returns third-party license text
|
||||||
|
std::string initializeGlobalThirdPartyLicences()
|
||||||
|
{
|
||||||
|
return R"(
|
||||||
|
Bella SDK (Software Development Kit)
|
||||||
|
|
||||||
|
Copyright Diffuse Logic SCP, all rights reserved.
|
||||||
|
|
||||||
|
Permission is hereby granted to any person obtaining a copy of this software
|
||||||
|
(the "Software"), to use, copy, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. ALL
|
||||||
|
IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF MERCHANTABILITY
|
||||||
|
ARE HEREBY DISCLAIMED.)
|
||||||
|
|
||||||
|
===
|
||||||
|
|
||||||
|
lzfse
|
||||||
|
|
||||||
|
Copyright (c) 2015-2016, Apple Inc. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
)";
|
||||||
|
}
|
||||||
|
|
||||||
6
extra.h
Normal file
6
extra.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string> // For std::string
|
||||||
|
|
||||||
|
std::string initializeGlobalLicense();
|
||||||
|
std::string initializeGlobalThirdPartyLicences();
|
||||||
|
|
||||||
2
makefile
2
makefile
@ -77,7 +77,7 @@ CXX_FLAGS = $(COMMON_FLAGS) -std=c++17 -Wno-deprecated-declarations
|
|||||||
CPP_DEFINES = -DNDEBUG=1 -DDL_USE_SHARED
|
CPP_DEFINES = -DNDEBUG=1 -DDL_USE_SHARED
|
||||||
|
|
||||||
# Objects
|
# Objects
|
||||||
OBJECTS = vmax2bella.o
|
OBJECTS = vmax2bella.o extra.o debug.o
|
||||||
OBJECT_FILES = $(patsubst %,$(OBJ_DIR)/%,$(OBJECTS))
|
OBJECT_FILES = $(patsubst %,$(OBJ_DIR)/%,$(OBJECTS))
|
||||||
|
|
||||||
# Build rules
|
# Build rules
|
||||||
|
|||||||
1426
resources/DayEnvironmentHDRI019_1K-TONEMAPPED.h
Normal file
1426
resources/DayEnvironmentHDRI019_1K-TONEMAPPED.h
Normal file
File diff suppressed because it is too large
Load Diff
711
vmax2bella.cpp
711
vmax2bella.cpp
@ -181,7 +181,7 @@ The 't' field in the snapshot's 's.id' dictionary indicates the type of snapshot
|
|||||||
#include <set> // For set data structure
|
#include <set> // For set data structure
|
||||||
#include <algorithm> // For std::sort
|
#include <algorithm> // For std::sort
|
||||||
#include <sstream> // For std::ostringstream
|
#include <sstream> // For std::ostringstream
|
||||||
|
#include <string> // For std::string
|
||||||
// Bella SDK includes - external libraries for 3D rendering
|
// Bella SDK includes - external libraries for 3D rendering
|
||||||
#include "bella_sdk/bella_scene.h" // For creating and manipulating 3D scenes in Bella
|
#include "bella_sdk/bella_scene.h" // For creating and manipulating 3D scenes in Bella
|
||||||
#include "dl_core/dl_main.inl" // Core functionality from the Diffuse Logic engine
|
#include "dl_core/dl_main.inl" // Core functionality from the Diffuse Logic engine
|
||||||
@ -189,12 +189,19 @@ The 't' field in the snapshot's 's.id' dictionary indicates the type of snapshot
|
|||||||
#include "lzfse.h"
|
#include "lzfse.h"
|
||||||
|
|
||||||
#include "../libplist/include/plist/plist.h" // Library for handling Apple property list files
|
#include "../libplist/include/plist/plist.h" // Library for handling Apple property list files
|
||||||
|
|
||||||
// Define STB_IMAGE_IMPLEMENTATION before including to create the implementation
|
// Define STB_IMAGE_IMPLEMENTATION before including to create the implementation
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#include "stb_image.h" // We'll need to add this library
|
#include "stb_image.h" // We'll need to add this library
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "common.h" // Debugging functions
|
||||||
|
#include "extra.h" // License info and static blocks
|
||||||
|
#include "debug.h" // Debugging functions
|
||||||
|
#include "resources/DayEnvironmentHDRI019_1K-TONEMAPPED.h" // embedded image dome
|
||||||
|
|
||||||
// Namespaces allow you to use symbols from a library without prefixing them
|
// Namespaces allow you to use symbols from a library without prefixing them
|
||||||
namespace bsdk = dl::bella_sdk;
|
namespace bsdk = dl::bella_sdk;
|
||||||
|
|
||||||
@ -497,17 +504,6 @@ void decodeMorton3DOptimized(uint32_t morton, uint32_t& x, uint32_t& y, uint32_t
|
|||||||
z = compactBits(morton >> 2);
|
z = compactBits(morton >> 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Structure to hold voxel information
|
|
||||||
struct newVoxel {
|
|
||||||
uint32_t x, y, z; // 3D coordinates
|
|
||||||
uint8_t color; // Color value
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dsVoxel {
|
|
||||||
uint8_t layer;
|
|
||||||
uint8_t color;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Structure to represent a VoxelMax chunk
|
// Structure to represent a VoxelMax chunk
|
||||||
struct Chunk {
|
struct Chunk {
|
||||||
std::vector<Voxel> voxels;
|
std::vector<Voxel> voxels;
|
||||||
@ -598,286 +594,6 @@ std::vector<newVoxel> decodeVoxels(const std::vector<uint8_t>& dsData, int morto
|
|||||||
return voxels;
|
return voxels;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Prints a table of voxel positions and colors
|
|
||||||
*
|
|
||||||
* @param voxels The vector of decoded voxels
|
|
||||||
* @param limit Maximum number of voxels to display (0 for all)
|
|
||||||
* @param filterZ Optional z-value to filter by
|
|
||||||
*/
|
|
||||||
void printVoxelTable(const std::vector<newVoxel>& voxels, size_t limit = 100, int filterZ = -1) {
|
|
||||||
int emptyVoxels = 32768 - voxels.size();
|
|
||||||
std::cout << "Voxels: " << voxels.size() << " Empty: " << emptyVoxels << std::endl;
|
|
||||||
|
|
||||||
// Count voxels at the filtered z-level if filtering is active
|
|
||||||
int filteredCount = 0;
|
|
||||||
if (filterZ >= 0) {
|
|
||||||
for (const auto& voxel : voxels) {
|
|
||||||
if (voxel.z == filterZ) filteredCount++;
|
|
||||||
}
|
|
||||||
std::cout << "Voxels at z=" << filterZ << ": " << filteredCount << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "Index | X | Y | Z | Color" << std::endl;
|
|
||||||
std::cout << "------|----|----|----|---------" << std::endl;
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
int shownCount = 0;
|
|
||||||
for (size_t i = 0; i < voxels.size(); i++) {
|
|
||||||
const auto& voxel = voxels[i];
|
|
||||||
|
|
||||||
// Skip if we're filtering by z and this doesn't match
|
|
||||||
if (filterZ >= 0 && voxel.z != filterZ) continue;
|
|
||||||
|
|
||||||
std::cout << std::setw(6) << i << " | ";
|
|
||||||
std::cout << std::setw(2) << voxel.x << " | ";
|
|
||||||
std::cout << std::setw(2) << voxel.y << " | ";
|
|
||||||
std::cout << std::setw(2) << voxel.z << " | ";
|
|
||||||
std::cout << "0x" << std::hex << std::setw(2) << std::setfill('0')
|
|
||||||
<< static_cast<int>(voxel.color) << std::dec << std::setfill(' ') << std::endl;
|
|
||||||
|
|
||||||
// Count shown voxels
|
|
||||||
shownCount++;
|
|
||||||
|
|
||||||
// Check if we've reached the limit
|
|
||||||
if (limit > 0 && shownCount >= limit) {
|
|
||||||
if (filterZ >= 0) {
|
|
||||||
int remaining = filteredCount - shownCount;
|
|
||||||
if (remaining > 0) {
|
|
||||||
std::cout << "... (output truncated, " << remaining << " more voxels at z=" << filterZ << ")" << std::endl;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
std::cout << "... (output truncated, " << (voxels.size() - shownCount) << " more voxels)" << std::endl;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* New visualization function that definitely uses the correct z-plane
|
|
||||||
*
|
|
||||||
* @param voxels The vector of decoded voxels
|
|
||||||
* @param zPlane The z-coordinate of the plane to visualize
|
|
||||||
* @param size The size of the grid (default: 32x32)
|
|
||||||
*/
|
|
||||||
void visualizeZPlaneFixed(const std::vector<newVoxel>& voxels, int zPlane, int size = 32) {
|
|
||||||
// Bounds checking
|
|
||||||
const int MIN_Z = 0;
|
|
||||||
const int MAX_Z = 31;
|
|
||||||
if (zPlane < MIN_Z || zPlane > MAX_Z) {
|
|
||||||
std::cout << "WARNING: z-plane value " << zPlane << " is out of bounds. Valid range is " << MIN_Z << "-" << MAX_Z << ". Using z=0 instead." << std::endl;
|
|
||||||
zPlane = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "Visualizing z-plane: " << zPlane << std::endl;
|
|
||||||
|
|
||||||
// Create a 2D grid for visualization
|
|
||||||
std::vector<std::vector<char>> grid(size, std::vector<char>(size, ' '));
|
|
||||||
|
|
||||||
// Count voxels for statistics
|
|
||||||
int totalVoxels = voxels.size();
|
|
||||||
int voxelsAtRequestedZ = 0;
|
|
||||||
int coloredVoxels = 0;
|
|
||||||
int clearVoxels = 0;
|
|
||||||
|
|
||||||
// Loop 1: Debug output for the first few matching voxels
|
|
||||||
int debugCount = 0;
|
|
||||||
for (const auto& voxel : voxels) {
|
|
||||||
if (voxel.z == zPlane) {
|
|
||||||
voxelsAtRequestedZ++;
|
|
||||||
|
|
||||||
// Update the grid and count color types
|
|
||||||
if (voxel.x >= 0 && voxel.x < size && voxel.y >= 0 && voxel.y < size) {
|
|
||||||
if (voxel.color == 0x00) {
|
|
||||||
grid[voxel.y][voxel.x] = '.'; // Clear voxel (0x00)
|
|
||||||
clearVoxels++;
|
|
||||||
} else if (voxel.color == 0x25) {
|
|
||||||
grid[voxel.y][voxel.x] = '#'; // Colored voxel (0x25)
|
|
||||||
coloredVoxels++;
|
|
||||||
} else {
|
|
||||||
grid[voxel.y][voxel.x] = 'X'; // Other color
|
|
||||||
coloredVoxels++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print statistics
|
|
||||||
std::cout << "\nVisualization Statistics:" << std::endl;
|
|
||||||
std::cout << "- Total voxels in data: " << totalVoxels << std::endl;
|
|
||||||
std::cout << "- Voxels at z=" << zPlane << ": " << voxelsAtRequestedZ << std::endl;
|
|
||||||
std::cout << "- Colored voxels: " << coloredVoxels << " (shown as '#' or 'X')" << std::endl;
|
|
||||||
std::cout << "- Clear voxels: " << clearVoxels << " (shown as '.')" << std::endl;
|
|
||||||
|
|
||||||
// If no matching voxels were found, print a message and return
|
|
||||||
if (voxelsAtRequestedZ == 0) {
|
|
||||||
std::cout << "\n*** NO VOXELS FOUND AT Z=" << zPlane << " ***\n" << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print legend
|
|
||||||
std::cout << "\nLegend:" << std::endl;
|
|
||||||
std::cout << "- '#': Color 0x25" << std::endl;
|
|
||||||
std::cout << "- '.': Clear (0x00)" << std::endl;
|
|
||||||
std::cout << "- 'X': Other colors" << std::endl;
|
|
||||||
std::cout << "- ' ': No voxel present" << std::endl;
|
|
||||||
std::cout << "- Each 8x4 section represents one subchunk" << std::endl;
|
|
||||||
|
|
||||||
// Print x-axis header
|
|
||||||
std::cout << "\n ";
|
|
||||||
for (int x = 0; x < size; x++) {
|
|
||||||
if (x % 8 == 0) {
|
|
||||||
std::cout << "|"; // Mark subchunk boundaries
|
|
||||||
} else {
|
|
||||||
std::cout << x % 10; // Print digit for readability
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::cout << std::endl;
|
|
||||||
|
|
||||||
// Print divider line
|
|
||||||
std::cout << " ";
|
|
||||||
for (int x = 0; x < size; x++) {
|
|
||||||
if (x % 8 == 0) {
|
|
||||||
std::cout << "+"; // Mark subchunk corners
|
|
||||||
} else {
|
|
||||||
std::cout << "-";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::cout << std::endl;
|
|
||||||
|
|
||||||
// Print grid with y-axis labels and subchunk markers
|
|
||||||
for (int y = 0; y < size; y++) {
|
|
||||||
std::cout << std::setw(2) << y << " ";
|
|
||||||
|
|
||||||
// Mark subchunk boundaries on y-axis
|
|
||||||
if (y % 4 == 0) {
|
|
||||||
std::cout << "+";
|
|
||||||
} else {
|
|
||||||
std::cout << "|";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print the actual voxel data for this row
|
|
||||||
for (int x = 0; x < size; x++) {
|
|
||||||
std::cout << grid[y][x];
|
|
||||||
}
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "\n===============================================\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Print a plist node's contents recursively.
|
|
||||||
* This function takes a plist node and prints its contents in a human-readable format.
|
|
||||||
* It handles all types of plist nodes (dictionaries, arrays, strings, etc.) by using
|
|
||||||
* recursion to traverse the entire plist structure.
|
|
||||||
*
|
|
||||||
* @param node The plist node to print (plist_t is a pointer to the internal plist structure)
|
|
||||||
* @param indent The current indentation level (defaults to 0 for the root node)
|
|
||||||
*/
|
|
||||||
void printPlistNode(const plist_t& node, int indent = 0) {
|
|
||||||
// Early return if node is null (safety check)
|
|
||||||
if (!node) return;
|
|
||||||
|
|
||||||
// Create a string with 'indent * 2' spaces for proper indentation
|
|
||||||
// This helps visualize the hierarchy of nested structures
|
|
||||||
std::string indentStr(indent * 2, ' ');
|
|
||||||
|
|
||||||
// Get the type of the current node (dictionary, array, string, etc.)
|
|
||||||
plist_type nodeType = plist_get_node_type(node);
|
|
||||||
|
|
||||||
// Handle each type of node differently
|
|
||||||
switch (nodeType) {
|
|
||||||
case PLIST_DICT: {
|
|
||||||
std::cout << indentStr << "Dictionary:" << std::endl;
|
|
||||||
|
|
||||||
// Create an iterator for the dictionary
|
|
||||||
// nullptr is passed as initial value; the iterator will be allocated by plist_dict_new_iter
|
|
||||||
plist_dict_iter it = nullptr;
|
|
||||||
plist_dict_new_iter(node, &it);
|
|
||||||
|
|
||||||
// Variables to store the current key-value pair
|
|
||||||
char* key = nullptr; // Will hold the dictionary key (needs to be freed)
|
|
||||||
plist_t value = nullptr; // Will hold the value node
|
|
||||||
|
|
||||||
// Iterate through all items in the dictionary
|
|
||||||
while (true) {
|
|
||||||
// Get the next key-value pair
|
|
||||||
plist_dict_next_item(node, it, &key, &value);
|
|
||||||
|
|
||||||
// Break if we've reached the end of the dictionary
|
|
||||||
if (!key || !value) break;
|
|
||||||
|
|
||||||
// Print the key and recursively print its value
|
|
||||||
std::cout << indentStr << " " << key << ":" << std::endl;
|
|
||||||
printPlistNode(value, indent + 2); // Increase indent for nested values
|
|
||||||
|
|
||||||
// Free the key string (allocated by plist_dict_next_item)
|
|
||||||
free(key);
|
|
||||||
key = nullptr; // Set to nullptr to avoid double-free
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free the iterator when done
|
|
||||||
free(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLIST_ARRAY: {
|
|
||||||
std::cout << indentStr << "Array:" << std::endl;
|
|
||||||
uint32_t size = plist_array_get_size(node);
|
|
||||||
for (uint32_t i = 0; i < size; i++) {
|
|
||||||
plist_t item = plist_array_get_item(node, i);
|
|
||||||
std::cout << indentStr << " [" << i << "]:" << std::endl;
|
|
||||||
printPlistNode(item, indent + 2);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLIST_STRING: {
|
|
||||||
char* str = nullptr;
|
|
||||||
plist_get_string_val(node, &str);
|
|
||||||
std::cout << indentStr << "String: " << (str ? str : "(null)") << std::endl;
|
|
||||||
free(str);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLIST_BOOLEAN: {
|
|
||||||
uint8_t bval;
|
|
||||||
plist_get_bool_val(node, &bval);
|
|
||||||
std::cout << indentStr << "Boolean: " << (bval ? "true" : "false") << std::endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLIST_UINT: {
|
|
||||||
uint64_t val;
|
|
||||||
plist_get_uint_val(node, &val);
|
|
||||||
std::cout << indentStr << "Integer: " << val << std::endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLIST_REAL: {
|
|
||||||
double val;
|
|
||||||
plist_get_real_val(node, &val);
|
|
||||||
std::cout << indentStr << "Real: " << val << std::endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLIST_DATE: {
|
|
||||||
int32_t sec = 0;
|
|
||||||
int32_t usec = 0;
|
|
||||||
plist_get_date_val(node, &sec, &usec);
|
|
||||||
std::cout << indentStr << "Date: " << sec << "." << usec << std::endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PLIST_DATA: {
|
|
||||||
char* data = nullptr;
|
|
||||||
uint64_t length = 0;
|
|
||||||
plist_get_data_val(node, &data, &length);
|
|
||||||
std::cout << indentStr << "Data: <" << length << " bytes>" << std::endl;
|
|
||||||
free(data);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
std::cout << indentStr << "Unknown type" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -944,82 +660,6 @@ std::vector<plist_t> getAllSnapshots(const plist_t& root_node) {
|
|||||||
return snapshotChunks;
|
return snapshotChunks;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Examines a specific array element at the given index from a plist file.
|
|
||||||
* This function allows inspection of individual chunks/snapshots in the data.
|
|
||||||
*
|
|
||||||
* @param plistFilePath Path to the plist file
|
|
||||||
* @param index The index of the array element to examine
|
|
||||||
* @param arrayPath The path to the array in the plist structure
|
|
||||||
* @return true if successful, false if any errors occurred
|
|
||||||
*/
|
|
||||||
bool examinePlistNode(const plist_t& root_node, int snapshotIndex, int zIndex, const std::string& arrayPath) {
|
|
||||||
std::cout << "Examining Plist array at snapshot " << snapshotIndex << " zIndex " << zIndex << std::endl;
|
|
||||||
|
|
||||||
if (!root_node) {
|
|
||||||
std::cerr << "Failed to process Plist data" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
plist_t current_node = root_node;
|
|
||||||
// if the array path contains slashes, we need to navigate through the structure
|
|
||||||
std::string path = arrayPath;
|
|
||||||
size_t pos = 0;
|
|
||||||
std::string token;
|
|
||||||
while ((pos = path.find('/')) != std::string::npos) {
|
|
||||||
token = path.substr(0, pos);
|
|
||||||
path.erase(0, pos + 1);
|
|
||||||
|
|
||||||
// current node must be a dictionary
|
|
||||||
if (plist_get_node_type(current_node) != PLIST_DICT) {
|
|
||||||
std::cerr << "error: expected dictionary at path component '" << token << "'" << std::endl;
|
|
||||||
//plist_free(root_node);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the next node in the path
|
|
||||||
current_node = plist_dict_get_item(current_node, token.c_str());
|
|
||||||
if (!current_node) {
|
|
||||||
std::cerr << "error: could not find key '" << token << "' in dictionary" << std::endl;
|
|
||||||
//plist_free(root_node);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now path contains the final key name
|
|
||||||
if (!path.empty() && plist_get_node_type(current_node) == PLIST_DICT) {
|
|
||||||
current_node = plist_dict_get_item(current_node, path.c_str());
|
|
||||||
if (!current_node) {
|
|
||||||
std::cerr << "Error: Could not find key '" << path << "' in dictionary" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we found an array
|
|
||||||
if (plist_get_node_type(current_node) != PLIST_ARRAY) {
|
|
||||||
std::cerr << "Error: '" << "arrayPath" << "' is not an array" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get Plist node array size
|
|
||||||
uint32_t arraySize = plist_array_get_size(current_node);
|
|
||||||
if (snapshotIndex < 0 || snapshotIndex >= static_cast<int>(arraySize)) {
|
|
||||||
std::cerr << "Error: Index " << snapshotIndex << " is out of range (array size: " << arraySize << ")" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the Plist node at the specified index
|
|
||||||
plist_t element = plist_array_get_item(current_node, snapshotIndex);
|
|
||||||
if (!element) {
|
|
||||||
std::cerr << "Error: Could not get Plist node at snapshot " << snapshotIndex << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "Array size: " << arraySize << std::endl;
|
|
||||||
std::cout << "Plist node details at snapshot " << snapshotIndex << " zIndex " << zIndex << ":" << std::endl;
|
|
||||||
printPlistNode(element);
|
|
||||||
debugSnapshots(element, snapshotIndex, zIndex);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles 's' dictionary in a Plist node holding 32x32x32 chunks of voxel data.
|
* Handles 's' dictionary in a Plist node holding 32x32x32 chunks of voxel data.
|
||||||
@ -1045,209 +685,6 @@ std::vector<newVoxel> getSnapshotVoxels(plist_t dsNode, int mortonOffset) {
|
|||||||
return std::vector<newVoxel>(); // Return empty vector if no voxels found
|
return std::vector<newVoxel>(); // Return empty vector if no voxels found
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles 's' dictionary in a Plist node holding 32x32x32 chunks of voxel data.
|
|
||||||
*
|
|
||||||
* @param element The Plist node to examine
|
|
||||||
* @return true if successful, false if any errors occurred
|
|
||||||
*/
|
|
||||||
bool debugSnapshots(plist_t element, int snapshotIndex, int zIndex) {
|
|
||||||
std::cout << "Debugging snapshots" << std::endl;
|
|
||||||
// Special handling for 's' dictionaries
|
|
||||||
if (plist_get_node_type(element) == PLIST_DICT) {
|
|
||||||
plist_t sNode = plist_dict_get_item(element, "s");
|
|
||||||
if (sNode) {
|
|
||||||
// Look for specific keys of interest in the 's' dictionary
|
|
||||||
if (plist_get_node_type(sNode) == PLIST_DICT) {
|
|
||||||
// Check for 'ds' (data stream) in the 's' dictionary
|
|
||||||
plist_t dsNode = plist_dict_get_item(sNode, "ds");
|
|
||||||
if (dsNode && plist_get_node_type(dsNode) == PLIST_DATA) {
|
|
||||||
char* data = nullptr;
|
|
||||||
uint64_t length = 0;
|
|
||||||
plist_get_data_val(dsNode, &data, &length);
|
|
||||||
|
|
||||||
std::cout << "\nDetailed analysis of 'ds' data stream (size: " << length << " bytes):" << std::endl;
|
|
||||||
|
|
||||||
// Detailed analysis of the data stream
|
|
||||||
if (length > 0 && data) {
|
|
||||||
// Display as hex bytes - increased to 384 bytes
|
|
||||||
std::cout << "First 384 bytes (hex):" << std::endl;
|
|
||||||
size_t bytesToShow = std::min(static_cast<size_t>(384), static_cast<size_t>(length));
|
|
||||||
for (size_t i = 0; i < bytesToShow; i++) {
|
|
||||||
std::cout << std::hex << std::setw(2) << std::setfill('0')
|
|
||||||
<< static_cast<int>(static_cast<uint8_t>(data[i])) << " ";
|
|
||||||
if ((i + 1) % 16 == 0) std::cout << std::endl;
|
|
||||||
}
|
|
||||||
std::cout << std::dec << std::endl;
|
|
||||||
|
|
||||||
// If data appears to be position-color pairs (as in voxel data)
|
|
||||||
if (length % 2 == 0) {
|
|
||||||
size_t numPairs = length / 2;
|
|
||||||
std::cout << "Data appears to contain " << numPairs << " position-color pairs" << std::endl;
|
|
||||||
|
|
||||||
// Check if all positions are 0 (common for optimized voxel data)
|
|
||||||
bool allPositionsZero = true;
|
|
||||||
for (size_t i = 0; i < std::min(numPairs, static_cast<size_t>(100)); i++) {
|
|
||||||
if (static_cast<uint8_t>(data[i * 2]) != 0) {
|
|
||||||
allPositionsZero = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allPositionsZero) {
|
|
||||||
// Show only color values for more compact analysis
|
|
||||||
std::cout << "\nAll position values are 0. Showing only color values:" << std::endl;
|
|
||||||
std::cout << "First 384 color values (hex):" << std::endl;
|
|
||||||
size_t colorsToShow = std::min(static_cast<size_t>(384), numPairs);
|
|
||||||
for (size_t i = 0; i < colorsToShow; i++) {
|
|
||||||
std::cout << std::hex << std::setw(2) << std::setfill('0')
|
|
||||||
<< static_cast<int>(static_cast<uint8_t>(data[i * 2 + 1])) << " ";
|
|
||||||
if ((i + 1) % 16 == 0) std::cout << std::endl;
|
|
||||||
}
|
|
||||||
std::cout << std::dec << std::endl;
|
|
||||||
} else {
|
|
||||||
// Show position-color pairs if positions vary
|
|
||||||
std::cout << "\nFirst 10 position-color pairs:" << std::endl;
|
|
||||||
std::cout << "Index | Position | Color" << std::endl;
|
|
||||||
std::cout << "------|----------|------" << std::endl;
|
|
||||||
|
|
||||||
size_t pairsToShow = std::min(static_cast<size_t>(10), numPairs);
|
|
||||||
for (size_t i = 0; i < pairsToShow; i++) {
|
|
||||||
uint8_t position = static_cast<uint8_t>(data[i * 2]);
|
|
||||||
uint8_t color = static_cast<uint8_t>(data[i * 2 + 1]);
|
|
||||||
|
|
||||||
std::cout << std::setw(5) << i << " | "
|
|
||||||
<< std::setw(8) << std::hex << std::setfill('0')
|
|
||||||
<< static_cast<int>(position) << std::dec << std::setfill(' ') << " | "
|
|
||||||
<< std::setw(5) << std::hex << std::setfill('0')
|
|
||||||
<< static_cast<int>(color) << std::dec << std::setfill(' ') << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Analyze and print color runs
|
|
||||||
std::cout << "\nAnalyzing color runs:" << std::endl;
|
|
||||||
|
|
||||||
if (numPairs > 0) {
|
|
||||||
uint8_t currentColor = static_cast<uint8_t>(data[1]); // First color
|
|
||||||
size_t runStart = 0;
|
|
||||||
size_t runLength = 1;
|
|
||||||
|
|
||||||
// Find all runs
|
|
||||||
std::vector<std::tuple<size_t, size_t, uint8_t>> colorRuns;
|
|
||||||
|
|
||||||
for (size_t i = 1; i < numPairs; i++) {
|
|
||||||
uint8_t color = static_cast<uint8_t>(data[i * 2 + 1]);
|
|
||||||
|
|
||||||
if (color == currentColor) {
|
|
||||||
// Continue the current run
|
|
||||||
runLength++;
|
|
||||||
} else {
|
|
||||||
// End the current run and start a new one
|
|
||||||
colorRuns.emplace_back(runStart, runStart + runLength - 1, currentColor);
|
|
||||||
currentColor = color;
|
|
||||||
runStart = i;
|
|
||||||
runLength = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the last run
|
|
||||||
colorRuns.emplace_back(runStart, runStart + runLength - 1, currentColor);
|
|
||||||
|
|
||||||
// Print the runs in a condensed format
|
|
||||||
std::cout << "Found " << colorRuns.size() << " color runs:" << std::endl;
|
|
||||||
std::cout << "Color | Voxel Count | Range" << std::endl;
|
|
||||||
std::cout << "------|-------------|------" << std::endl;
|
|
||||||
|
|
||||||
for (const auto& run : colorRuns) {
|
|
||||||
size_t start = std::get<0>(run);
|
|
||||||
size_t end = std::get<1>(run);
|
|
||||||
uint8_t color = std::get<2>(run);
|
|
||||||
size_t length = end - start + 1;
|
|
||||||
|
|
||||||
std::cout << " 0x" << std::hex << std::setw(2) << std::setfill('0')
|
|
||||||
<< static_cast<int>(color) << " | "
|
|
||||||
<< std::dec << std::setfill(' ') << std::setw(11) << length << " | "
|
|
||||||
<< std::setw(5) << start << "-" << std::setw(5) << end
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add special notice for full-voxel-space runs
|
|
||||||
if (colorRuns.size() == 1) {
|
|
||||||
const auto& singleRun = colorRuns[0];
|
|
||||||
size_t start = std::get<0>(singleRun);
|
|
||||||
size_t end = std::get<1>(singleRun);
|
|
||||||
size_t length = end - start + 1;
|
|
||||||
uint8_t color = std::get<2>(singleRun);
|
|
||||||
|
|
||||||
if (start == 0 && length == 32768) {
|
|
||||||
std::cout << "\nNOTICE: This chunk contains a single color (0x"
|
|
||||||
<< std::hex << static_cast<int>(color) << std::dec
|
|
||||||
<< ") for all 32,768 voxels, which would fill a complete 32x32x32 voxel space." << std::endl;
|
|
||||||
std::cout << "This could indicate:";
|
|
||||||
std::cout << "\n - A solid block of one color";
|
|
||||||
std::cout << "\n - A special encoding for empty/default chunks";
|
|
||||||
std::cout << "\n - A placeholder or initialization state" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decode voxels for visualization
|
|
||||||
// @param TODO: get morton offset from the 'lt' dictionary
|
|
||||||
std::vector<newVoxel> voxels = decodeVoxels(std::vector<uint8_t>(data, data + length), 0);
|
|
||||||
|
|
||||||
printVoxelTable(voxels, 100);
|
|
||||||
|
|
||||||
// Explicitly decode the voxels for visualization
|
|
||||||
char* data = nullptr;
|
|
||||||
uint64_t length = 0;
|
|
||||||
plist_get_data_val(dsNode, &data, &length);
|
|
||||||
|
|
||||||
if (length > 0 && data) {
|
|
||||||
std::vector<newVoxel> voxels = decodeVoxels(std::vector<uint8_t>(data, data + length), 0);
|
|
||||||
visualizeZPlaneFixed(voxels, zIndex);
|
|
||||||
free(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for 'id' dictionary to get chunk information
|
|
||||||
plist_t idNode = plist_dict_get_item(sNode, "id");
|
|
||||||
if (idNode && plist_get_node_type(idNode) == PLIST_DICT) {
|
|
||||||
plist_t chunkIdNode = plist_dict_get_item(idNode, "c");
|
|
||||||
if (chunkIdNode && plist_get_node_type(chunkIdNode) == PLIST_UINT) {
|
|
||||||
uint64_t chunkId;
|
|
||||||
plist_get_uint_val(chunkIdNode, &chunkId);
|
|
||||||
std::cout << "\nChunk ID: " << chunkId << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for 'lt' (location table)
|
|
||||||
plist_t ltNode = plist_dict_get_item(sNode, "lt");
|
|
||||||
if (ltNode && plist_get_node_type(ltNode) == PLIST_DATA) {
|
|
||||||
char* data = nullptr;
|
|
||||||
uint64_t length = 0;
|
|
||||||
plist_get_data_val(ltNode, &data, &length);
|
|
||||||
|
|
||||||
std::cout << "\nLocation table size: " << length << " bytes" << std::endl;
|
|
||||||
if (length > 0 && data) {
|
|
||||||
std::cout << "First 16 bytes of location table:" << std::endl;
|
|
||||||
size_t bytesToShow = std::min(static_cast<size_t>(16), static_cast<size_t>(length));
|
|
||||||
for (size_t i = 0; i < bytesToShow; i++) {
|
|
||||||
std::cout << std::hex << std::setw(2) << std::setfill('0')
|
|
||||||
<< static_cast<int>(static_cast<uint8_t>(data[i])) << " ";
|
|
||||||
}
|
|
||||||
std::cout << std::dec << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Main function for the program
|
// Main function for the program
|
||||||
// This is where execution begins
|
// This is where execution begins
|
||||||
@ -1305,6 +742,29 @@ int DL_main(dl::Args& args)
|
|||||||
verbose = true;
|
verbose = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create hdri file if it doesn't exist
|
||||||
|
std::string hdriName = "DayEnvironmentHDRI019_1K-TONEMAPPED.jpg";
|
||||||
|
std::string resDir= "./res";
|
||||||
|
std::filesystem::path hdriFile = std::filesystem::path(resDir) / hdriName;
|
||||||
|
if (!std::filesystem::exists(hdriFile)) {
|
||||||
|
std::cout << "HDRI file not found, creating it" << std::endl;
|
||||||
|
std::filesystem::create_directories(resDir);
|
||||||
|
std::ofstream outFile(hdriFile, std::ios::binary);
|
||||||
|
if (!outFile) {
|
||||||
|
std::cerr << "HDRI failed to write" << hdriFile << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the data to the file using the exact length
|
||||||
|
outFile.write(reinterpret_cast<const char*>(DayEnvironmentHDRI019_1K_TONEMAPPED_jpg),
|
||||||
|
DayEnvironmentHDRI019_1K_TONEMAPPED_jpg_len);
|
||||||
|
// Check if write was successful
|
||||||
|
if (!outFile) {
|
||||||
|
std::cerr << "HDRI failed to write" << hdriFile << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get the input file path from command line arguments
|
// Get the input file path from command line arguments
|
||||||
if (args.have("--voxin"))
|
if (args.have("--voxin"))
|
||||||
{
|
{
|
||||||
@ -1368,17 +828,8 @@ int DL_main(dl::Args& args)
|
|||||||
zIndex = 0;
|
zIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//std::vector<newVoxel> voxels = getSnapshotVoxels(root_node, 0); // Get voxels for snapshot 0
|
examinePlistNode(root_node, 0, zIndex, "snapshots");
|
||||||
//std::cout << "VOXELS SIZE: " << voxels.size() << std::endl;
|
|
||||||
/*std::vector<plist_t> snapshotChunks = getAllSnapshots(root_node);
|
|
||||||
for (uint32_t i = 0; i < snapshotChunks.size(); i++) {
|
|
||||||
std::cout << "Snapshot chunk " << i << std::endl;
|
|
||||||
std::vector<newVoxel> voxels = getSnapshotVoxels(snapshotChunks[i]);
|
|
||||||
std::cout << "VOXELS SIZE: " << voxels.size() << std::endl;
|
|
||||||
//printVoxelTable(voxels, 100);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
//examinePlistNode(root_node, 0, zIndex, "snapshots");
|
|
||||||
writeBszScene(bszName, root_node, palette);
|
writeBszScene(bszName, root_node, palette);
|
||||||
|
|
||||||
plist_free(root_node);
|
plist_free(root_node);
|
||||||
@ -1427,7 +878,7 @@ int writeBszScene( const std::string& bszName, const plist_t root_node, const st
|
|||||||
|
|
||||||
// Configure environment (image-based lighting)
|
// Configure environment (image-based lighting)
|
||||||
imageDome["ext"] = ".jpg";
|
imageDome["ext"] = ".jpg";
|
||||||
imageDome["dir"] = "./resources";
|
imageDome["dir"] = "./res";
|
||||||
imageDome["multiplier"] = 6.0f;
|
imageDome["multiplier"] = 6.0f;
|
||||||
imageDome["file"] = "DayEnvironmentHDRI019_1K-TONEMAPPED";
|
imageDome["file"] = "DayEnvironmentHDRI019_1K-TONEMAPPED";
|
||||||
|
|
||||||
@ -1468,75 +919,6 @@ int writeBszScene( const std::string& bszName, const plist_t root_node, const st
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function that returns the license text for this program
|
|
||||||
std::string initializeGlobalLicense()
|
|
||||||
{
|
|
||||||
// R"(...)" is a C++ raw string literal - allows multi-line strings with preserved formatting
|
|
||||||
return R"(
|
|
||||||
vmax2bella
|
|
||||||
|
|
||||||
Copyright (c) 2025 Harvey Fong
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.)";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function that returns third-party license text
|
|
||||||
std::string initializeGlobalThirdPartyLicences()
|
|
||||||
{
|
|
||||||
return R"(
|
|
||||||
Bella SDK (Software Development Kit)
|
|
||||||
|
|
||||||
Copyright Diffuse Logic SCP, all rights reserved.
|
|
||||||
|
|
||||||
Permission is hereby granted to any person obtaining a copy of this software
|
|
||||||
(the "Software"), to use, copy, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. ALL
|
|
||||||
IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF MERCHANTABILITY
|
|
||||||
ARE HEREBY DISCLAIMED.)
|
|
||||||
|
|
||||||
===
|
|
||||||
|
|
||||||
lzfse
|
|
||||||
|
|
||||||
Copyright (c) 2015-2016, Apple Inc. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived
|
|
||||||
from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
||||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
)";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Function to write Bella voxels
|
// Function to write Bella voxels
|
||||||
@ -1553,12 +935,9 @@ void writeBellaVoxels(const plist_t& root_node,
|
|||||||
|
|
||||||
int snapshotCount = 0;
|
int snapshotCount = 0;
|
||||||
// Process all snapshots
|
// Process all snapshots
|
||||||
//for (size_t i = 0; i < snapshotsArray.size(); i++) {
|
|
||||||
|
|
||||||
//for(int i=255; i>=0; i--)
|
|
||||||
for(int i=0; i<256; i++)
|
for(int i=0; i<256; i++)
|
||||||
{
|
{
|
||||||
|
// Set the material color (convert 0-255 values to 0.0-1.0 range)
|
||||||
double dR = static_cast<double>(palette[i].r)/255.0;
|
double dR = static_cast<double>(palette[i].r)/255.0;
|
||||||
double dG = static_cast<double>(palette[i].g)/255.0;
|
double dG = static_cast<double>(palette[i].g)/255.0;
|
||||||
double dB = static_cast<double>(palette[i].b)/255.0;
|
double dB = static_cast<double>(palette[i].b)/255.0;
|
||||||
@ -1570,12 +949,7 @@ void writeBellaVoxels(const plist_t& root_node,
|
|||||||
auto voxMat = sceneWrite.createNode("orenNayar", nodeName, nodeName);
|
auto voxMat = sceneWrite.createNode("orenNayar", nodeName, nodeName);
|
||||||
{
|
{
|
||||||
bsdk::Scene::EventScope es(sceneWrite);
|
bsdk::Scene::EventScope es(sceneWrite);
|
||||||
// Commented out: Alternative material settings
|
// Convert sRGB form png to linear color space
|
||||||
//dielectric["ior"] = 1.41f;
|
|
||||||
//dielectric["roughness"] = 40.0f;
|
|
||||||
//dielectric["depth"] = 33.0f;
|
|
||||||
|
|
||||||
// Set the material color (convert 0-255 values to 0.0-1.0 range)
|
|
||||||
voxMat["reflectance"] = dl::Rgba{
|
voxMat["reflectance"] = dl::Rgba{
|
||||||
srgbToLinear(dR),
|
srgbToLinear(dR),
|
||||||
srgbToLinear(dG),
|
srgbToLinear(dG),
|
||||||
@ -1585,12 +959,9 @@ void writeBellaVoxels(const plist_t& root_node,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//get last chunkid only, because previous chunks are undo history
|
||||||
//get last chunkid only
|
|
||||||
std::vector<int32_t> usedChunkIDs;
|
std::vector<int32_t> usedChunkIDs;
|
||||||
for (size_t i = snapshotsArray.size() - 1; i != SIZE_MAX; i--) {
|
for (size_t i = snapshotsArray.size() - 1; i != SIZE_MAX; i--) {
|
||||||
// Loop body
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Assuming 'snapshot' is a plist_t node of dictionary type
|
// Assuming 'snapshot' is a plist_t node of dictionary type
|
||||||
plist_t snapNode = plist_dict_get_item(snapshotsArray[i], "s");
|
plist_t snapNode = plist_dict_get_item(snapshotsArray[i], "s");
|
||||||
@ -1604,16 +975,12 @@ void writeBellaVoxels(const plist_t& root_node,
|
|||||||
// Check if it's a dictionary type
|
// Check if it's a dictionary type
|
||||||
if (plist_get_node_type(stNode) != PLIST_DICT) continue;
|
if (plist_get_node_type(stNode) != PLIST_DICT) continue;
|
||||||
|
|
||||||
// Get the "c" item from idNode dictionary
|
// minNode array stores the min x,y,z coordinates of the voxel
|
||||||
|
// x y z are bitpacked into the 4th element of the array
|
||||||
plist_t minNode = plist_dict_get_item(stNode, "min");
|
plist_t minNode = plist_dict_get_item(stNode, "min");
|
||||||
if (!stNode) continue; // Skip if "c" key doesn't exist
|
if (!stNode) continue; // Skip if "c" key doesn't exist
|
||||||
int64_t _minx;
|
|
||||||
int64_t _miny;
|
|
||||||
int64_t _minz;
|
|
||||||
int64_t _minw;
|
int64_t _minw;
|
||||||
//plist_get_int_val(plist_array_get_item(minNode, 0), &_minx);
|
// Get morton code from minNode
|
||||||
//plist_get_int_val(plist_array_get_item(minNode, 1), &_miny);
|
|
||||||
//plist_get_int_val(plist_array_get_item(minNode, 2), &_minz);
|
|
||||||
plist_get_int_val(plist_array_get_item(minNode, 3), &_minw);
|
plist_get_int_val(plist_array_get_item(minNode, 3), &_minw);
|
||||||
|
|
||||||
// get world origin
|
// get world origin
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user