diff --git a/include/Map.h b/include/Map.h deleted file mode 100644 index 7366f54..0000000 --- a/include/Map.h +++ /dev/null @@ -1,120 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "util.hpp" - -#define _USE_MATH_DEFINES -#include - -#define CHUNK_DIM 32 -#define OCT_DIM 32 - -struct XYZHasher { - std::size_t operator()(const sf::Vector3i& k) const { - return ((std::hash()(k.x) - ^ (std::hash()(k.y) << 1)) >> 1) - ^ (std::hash()(k.z) << 1); - } -}; - -struct oct_state { - - int parent_stack_position = 0; - uint64_t parent_stack[32] = { 0 }; - - uint8_t scale = 0; - uint8_t idx_stack[32] = { 0 }; - - uint64_t current_descriptor; - -}; - -class Octree { -public: - Octree(); - ~Octree() {}; - - uint64_t *blob = new uint64_t[100000]; - - uint64_t root_index = 0; - uint64_t stack_pos = 0x8000; - uint64_t global_pos = 0; - - uint64_t copy_to_stack(std::vector children); - - // With a position and the head of the stack. Traverse down the voxel hierarchy to find - // the IDX and stack position of the highest resolution (maybe set resolution?) oct - bool get_voxel(sf::Vector3i position); - - void print_block(int block_pos); - -private: - - // (X, Y, Z) mask for the idx - const uint8_t idx_set_x_mask = 0x1; - const uint8_t idx_set_y_mask = 0x2; - const uint8_t idx_set_z_mask = 0x4; - - // Mask for - const uint8_t mask_8[8] = { - 0x1, 0x2, 0x4, 0x8, - 0x10, 0x20, 0x40, 0x80 - }; - - const uint8_t count_mask_8[8]{ - 0x1, 0x3, 0x7, 0xF, - 0x1F, 0x3F, 0x7F, 0xFF - }; - - const uint64_t child_pointer_mask = 0x0000000000007fff; - const uint64_t far_bit_mask = 0x8000; - const uint64_t valid_mask = 0xFF0000; - const uint64_t leaf_mask = 0xFF000000; - const uint64_t contour_pointer_mask = 0xFFFFFF00000000; - const uint64_t contour_mask = 0xFF00000000000000; - -}; - - -class Map { -public: - - Map(sf::Vector3i position); - - void generate_octree(); - - void setVoxel(sf::Vector3i position, int val); - - char getVoxelFromOctree(sf::Vector3i position); - - bool getVoxel(sf::Vector3i pos); - Octree a; - - void test_map(); - -private: - - // ======= DEBUG =========== - int counter = 0; - std::stringstream output_stream; - // ========================= - - uint64_t generate_children(sf::Vector3i pos, int dim); - - char* voxel_data = new char[OCT_DIM * OCT_DIM * OCT_DIM]; - -}; - - diff --git a/include/Ray.h b/include/Ray.h index 2f8a53a..bbbe534 100644 --- a/include/Ray.h +++ b/include/Ray.h @@ -1,7 +1,7 @@ #pragma once #include #include -#include "Map.h" +#include "map/Map.h" class Ray { diff --git a/include/map/Map.h b/include/map/Map.h new file mode 100644 index 0000000..cd770d0 --- /dev/null +++ b/include/map/Map.h @@ -0,0 +1,49 @@ +#pragma once +#include +#include +#include +#include +#include "util.hpp" +#include "map/Octree.h" + +#define _USE_MATH_DEFINES +#include + +struct XYZHasher { + std::size_t operator()(const sf::Vector3i& k) const { + return ((std::hash()(k.x) + ^ (std::hash()(k.y) << 1)) >> 1) + ^ (std::hash()(k.z) << 1); + } +}; + +class Map { +public: + + Map(uint32_t dimensions); + + void generate_octree(); + + void setVoxel(sf::Vector3i position, int val); + + bool getVoxelFromOctree(sf::Vector3i position); + + bool getVoxel(sf::Vector3i pos); + Octree a; + + void test_map(); + +private: + + // ======= DEBUG =========== + int counter = 0; + std::stringstream output_stream; + // ========================= + + uint64_t generate_children(sf::Vector3i pos, int dim); + + char* voxel_data; + +}; + + diff --git a/include/map/Octree.h b/include/map/Octree.h new file mode 100644 index 0000000..60d71ca --- /dev/null +++ b/include/map/Octree.h @@ -0,0 +1,52 @@ +#pragma once +#include +#include +#include "util.hpp" + +#define OCT_DIM 32 + +class Octree { +public: + Octree(); + ~Octree() {}; + + uint64_t *blob = new uint64_t[100000]; + + uint64_t root_index = 0; + uint64_t stack_pos = 0x8000; + uint64_t global_pos = 0; + + uint64_t copy_to_stack(std::vector children); + + // With a position and the head of the stack. Traverse down the voxel hierarchy to find + // the IDX and stack position of the highest resolution (maybe set resolution?) oct + bool get_voxel(sf::Vector3i position); + + void print_block(int block_pos); + +private: + + // (X, Y, Z) mask for the idx + const uint8_t idx_set_x_mask = 0x1; + const uint8_t idx_set_y_mask = 0x2; + const uint8_t idx_set_z_mask = 0x4; + + // Mask for + const uint8_t mask_8[8] = { + 0x1, 0x2, 0x4, 0x8, + 0x10, 0x20, 0x40, 0x80 + }; + + const uint8_t count_mask_8[8]{ + 0x1, 0x3, 0x7, 0xF, + 0x1F, 0x3F, 0x7F, 0xFF + }; + + const uint64_t child_pointer_mask = 0x0000000000007fff; + const uint64_t far_bit_mask = 0x8000; + const uint64_t valid_mask = 0xFF0000; + const uint64_t leaf_mask = 0xFF000000; + const uint64_t contour_pointer_mask = 0xFFFFFF00000000; + const uint64_t contour_mask = 0xFF00000000000000; + +}; diff --git a/include/Old_Map.h b/include/map/Old_Map.h similarity index 100% rename from include/Old_Map.h rename to include/map/Old_Map.h diff --git a/include/raycaster/Hardware_Caster.h b/include/raycaster/Hardware_Caster.h index e0c96c6..9c15317 100644 --- a/include/raycaster/Hardware_Caster.h +++ b/include/raycaster/Hardware_Caster.h @@ -5,7 +5,7 @@ #include #include #include "LightController.h" -#include "Old_Map.h" +#include "map/Old_Map.h" #include "Camera.h" #ifdef linux diff --git a/include/raycaster/RayCaster.h b/include/raycaster/RayCaster.h index 4790d73..27771e3 100644 --- a/include/raycaster/RayCaster.h +++ b/include/raycaster/RayCaster.h @@ -1,7 +1,7 @@ #pragma once #include #include -#include +#include class Old_Map; class Camera; diff --git a/include/raycaster/Software_Caster.h b/include/raycaster/Software_Caster.h index 9777c39..321bacc 100644 --- a/include/raycaster/Software_Caster.h +++ b/include/raycaster/Software_Caster.h @@ -1,7 +1,7 @@ #pragma once #include "raycaster/RayCaster.h" #include -#include "Old_Map.h" +#include "map/Old_Map.h" #include "Camera.h" struct PackedData; diff --git a/include/util.hpp b/include/util.hpp index dca47fb..1e87624 100644 --- a/include/util.hpp +++ b/include/util.hpp @@ -80,6 +80,18 @@ private: }; +struct oct_state { + + int parent_stack_position = 0; + uint64_t parent_stack[32] = { 0 }; + + uint8_t scale = 0; + uint8_t idx_stack[32] = { 0 }; + + uint64_t current_descriptor; + +}; + inline sf::Vector3f SphereToCart(sf::Vector2f i) { auto r = sf::Vector3f( @@ -237,4 +249,70 @@ inline int count_bits(int64_t v) { //right = ((right + (right >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count //return left + right; +} + +inline void SetBit(int position, char* c) { + *c |= (uint64_t)1 << position; +} + +inline void FlipBit(int position, char* c) { + *c ^= (uint64_t)1 << position; +} + +inline int GetBit(int position, char* c) { + return (*c >> position) & (uint64_t)1; +} + +inline void SetBit(int position, uint64_t* c) { + *c |= (uint64_t)1 << position; +} + +inline void FlipBit(int position, uint64_t* c) { + *c ^= (uint64_t)1 << position; +} + +inline int GetBit(int position, uint64_t* c) { + return (*c >> position) & (uint64_t)1; +} + +inline bool CheckLeafSign(const uint64_t descriptor) { + + uint64_t valid_mask = 0xFF0000; + + // Return true if all 1's, false if contiguous 0's + if ((descriptor & valid_mask) == valid_mask) { + return true; + } + if ((descriptor & valid_mask) == 0) { + return false; + } + + // Error out, something funky + abort(); +} + +inline bool CheckContiguousValid(const uint64_t c) { + uint64_t bitmask = 0xFF0000; + return (c & bitmask) == bitmask; +} + + + +inline bool IsLeaf(const uint64_t descriptor) { + + uint64_t leaf_mask = 0xFF000000; + uint64_t valid_mask = 0xFF0000; + + // Check for contiguous valid values of either 0's or 1's + if (((descriptor & valid_mask) == valid_mask) || ((descriptor & valid_mask) == 0)) { + + // Check for a full leaf mask + // Only if valid and leaf are contiguous, then it's a leaf + if ((descriptor & leaf_mask) == leaf_mask) + return true; + else + return false; + } + else + return false; } \ No newline at end of file diff --git a/src/Map.cpp b/src/Map.cpp deleted file mode 100644 index b111f2d..0000000 --- a/src/Map.cpp +++ /dev/null @@ -1,411 +0,0 @@ -#include "Map.h" - -void SetBit(int position, char* c) { - *c |= (uint64_t)1 << position; -} - -void FlipBit(int position, char* c) { - *c ^= (uint64_t)1 << position; -} - -int GetBit(int position, char* c) { - return (*c >> position) & (uint64_t)1; -} - -void SetBit(int position, uint64_t* c) { - *c |= (uint64_t)1 << position; -} - -void FlipBit(int position, uint64_t* c) { - *c ^= (uint64_t)1 << position; -} - -int GetBit(int position, uint64_t* c) { - return (*c >> position) & (uint64_t)1; -} - -bool CheckLeafSign(const uint64_t descriptor) { - - uint64_t valid_mask = 0xFF0000; - - // Return true if all 1's, false if contiguous 0's - if ((descriptor & valid_mask) == valid_mask) { - return true; - } - if ((descriptor & valid_mask) == 0) { - return false; - } - - // Error out, something funky - abort(); -} - -bool CheckContiguousValid(const uint64_t c) { - uint64_t bitmask = 0xFF0000; - return (c & bitmask) == bitmask; -} - - - -bool IsLeaf(const uint64_t descriptor) { - - uint64_t leaf_mask = 0xFF000000; - uint64_t valid_mask = 0xFF0000; - - // Check for contiguous valid values of either 0's or 1's - if (((descriptor & valid_mask) == valid_mask) || ((descriptor & valid_mask) == 0)) { - - // Check for a full leaf mask - // Only if valid and leaf are contiguous, then it's a leaf - if ((descriptor & leaf_mask) == leaf_mask) - return true; - else - return false; - } - else - return false; -} - -Map::Map(sf::Vector3i position) { - - srand(time(NULL)); - - for (int i = 0; i < OCT_DIM * OCT_DIM * OCT_DIM; i++) { - if (rand() % 25 < 2) - voxel_data[i] = 1; - else - voxel_data[i] = 1; - } - -} - -uint64_t Map::generate_children(sf::Vector3i pos, int voxel_scale) { - - - // The 8 subvoxel coords starting from the 1th direction, the direction of the origin of the 3d grid - // XY, Z++, XY - std::vector v = { - sf::Vector3i(pos.x , pos.y , pos.z), - sf::Vector3i(pos.x + voxel_scale, pos.y , pos.z), - sf::Vector3i(pos.x , pos.y + voxel_scale, pos.z), - sf::Vector3i(pos.x + voxel_scale, pos.y + voxel_scale, pos.z), - sf::Vector3i(pos.x , pos.y , pos.z + voxel_scale), - sf::Vector3i(pos.x + voxel_scale, pos.y , pos.z + voxel_scale), - sf::Vector3i(pos.x , pos.y + voxel_scale, pos.z + voxel_scale), - sf::Vector3i(pos.x + voxel_scale, pos.y + voxel_scale, pos.z + voxel_scale) - }; - - // If we hit the 1th voxel scale then we need to query the 3D grid - // and get the voxel at that position. I assume in the future when I - // want to do chunking / loading of raw data I can edit the voxel access - if (voxel_scale == 1) { - - // - uint64_t child_descriptor = 0; - - // Setting the individual valid mask bits - // These don't bound check, should they? - for (int i = 0; i < v.size(); i++) { - if (getVoxel(v.at(i))) - SetBit(i + 16, &child_descriptor); - } - - // We are querying leafs, so we need to fill the leaf mask - child_descriptor |= 0xFF000000; - - // This is where contours - // The CP will be left blank, contours will be added maybe - return child_descriptor; - - } - - // Init a blank child descriptor for this node - uint64_t child_descriptor = 0; - - std::vector descriptor_array; - - // Generate down the recursion, returning the descriptor of the current node - for (int i = 0; i < v.size(); i++) { - - uint64_t child = 0; - - // Get the child descriptor from the i'th to 8th subvoxel - child = generate_children(v.at(i), voxel_scale / 2); - - // =========== Debug =========== - PrettyPrintUINT64(child, &output_stream); - output_stream << " " << voxel_scale << " " << counter++ << std::endl; - // ============================= - - // If the child is a leaf (contiguous) of non-valid values - if (IsLeaf(child) && !CheckLeafSign(child)) { - // Leave the valid mask 0, set leaf mask to 1 - SetBit(i + 16 + 8, &child_descriptor); - } - - // If the child is valid and not a leaf - else { - - // Set the valid mask, and add it to the descriptor array - SetBit(i + 16, &child_descriptor); - descriptor_array.push_back(child); - } - } - - // Any free space between the child descriptors must be added here in order to - // interlace them and allow the memory handler to work correctly. - - // Copy the children to the stack and set the child_descriptors pointer to the correct value - child_descriptor |= a.copy_to_stack(descriptor_array); - - // Free space may also be allocated here as well - - // Return the node up the stack - return child_descriptor; -} - -void Map::generate_octree() { - - // Launch the recursive generator at (0,0,0) as the first point - // and the octree dimension as the initial block size - uint64_t root_node = generate_children(sf::Vector3i(0, 0, 0), OCT_DIM/2); - uint64_t tmp = 0; - - // ========= DEBUG ============== - PrettyPrintUINT64(root_node, &output_stream); - output_stream << " " << OCT_DIM << " " << counter++ << std::endl; - // ============================== - - a.root_index = a.copy_to_stack(std::vector{root_node}); - - // Dump the debug log - DumpLog(&output_stream, "raw_output.txt"); - -} - -void Map::setVoxel(sf::Vector3i world_position, int val) { - -} - -char Map::getVoxelFromOctree(sf::Vector3i position) -{ - return a.get_voxel(position); -} - -bool Map::getVoxel(sf::Vector3i pos){ - - if (voxel_data[pos.x + OCT_DIM * (pos.y + OCT_DIM * pos.z)]) { - return true; - } else { - return false; - } -} - -void Map::test_map() { - - std::cout << "Validating map..." << std::endl; - - for (int x = 0; x < OCT_DIM; x++) { - for (int y = 0; y < OCT_DIM; y++) { - for (int z = 0; z < OCT_DIM; z++) { - - sf::Vector3i pos(x, y, z); - - bool arr1 = getVoxel(pos); - bool arr2 = getVoxelFromOctree(pos); - - if (arr1 != arr2) { - std::cout << "X: " << pos.x << "Y: " << pos.y << "Z: " << pos.z << std::endl; - } - - } - } - } - - std::cout << "Done" << std::endl; - - sf::Clock timer; - - timer.restart(); - - for (int x = 0; x < OCT_DIM; x++) { - for (int y = 0; y < OCT_DIM; y++) { - for (int z = 0; z < OCT_DIM; z++) { - - sf::Vector3i pos(x, y, z); - - bool arr1 = getVoxel(pos); - } - } - } - - std::cout << "Array linear xyz access : "; - std::cout << timer.restart().asMicroseconds() << " microseconds" << std::endl; - - for (int x = 0; x < OCT_DIM; x++) { - for (int y = 0; y < OCT_DIM; y++) { - for (int z = 0; z < OCT_DIM; z++) { - - sf::Vector3i pos(x, y, z); - - bool arr2 = getVoxelFromOctree(pos); - } - } - } - - std::cout << "Octree linear xyz access : "; - std::cout << timer.restart().asMicroseconds() << " microseconds" << std::endl; - - - -} - -Octree::Octree() { - - // initialize the first stack block - - for (int i = 0; i < 0x8000; i++) { - blob[i] = 0; - } -} - -uint64_t Octree::copy_to_stack(std::vector children) { - - // Check for the 15 bit boundry - if (stack_pos - children.size() > stack_pos) { - global_pos = stack_pos; - stack_pos = 0x8000; - } - else { - stack_pos -= children.size(); - } - - // Check for the far bit - - memcpy(&blob[stack_pos + global_pos], children.data(), children.size() * sizeof(uint64_t)); - - // Return the bitmask encoding the index of that value - // If we tripped the far bit, allocate a far index to the stack and place - // it at the bottom of the child_descriptor node level array - // And then shift the far bit to 1 - - // If not, shift the index to its correct place - return stack_pos; -} - -bool Octree::get_voxel(sf::Vector3i position) { - - // Struct that holds the state necessary to continue the traversal from the found voxel - oct_state state; - - // push the root node to the parent stack - uint64_t head = blob[root_index]; - state.parent_stack[state.parent_stack_position] = head; - - // Set our initial dimension and the position at the corner of the oct to keep track of our position - int dimension = OCT_DIM; - sf::Vector3i quad_position(0, 0, 0); - - // While we are not at the required resolution - // Traverse down by setting the valid/leaf mask to the subvoxel - // Check to see if it is valid - // Yes? - // Check to see if it is a leaf - // No? Break - // Yes? Scale down to the next hierarchy, push the parent to the stack - // - // No? - // Break - while (dimension > 1) { - - // So we can be a little bit tricky here and increment our - // array index that holds our masks as we build the idx. - // Adding 1 for X, 2 for Y, and 4 for Z - int mask_index = 0; - - - // Do the logic steps to find which sub oct we step down into - if (position.x >= (dimension / 2) + quad_position.x) { - - // Set our voxel position to the (0,0) of the correct oct - quad_position.x += (dimension / 2); - - // increment the mask index and mentioned above - mask_index += 1; - - // Set the idx to represent the move - state.idx_stack[state.scale] |= idx_set_x_mask; - - } - if (position.y >= (dimension / 2) + quad_position.y) { - - quad_position.y |= (dimension / 2); - - mask_index += 2; - - state.idx_stack[state.scale] ^= idx_set_y_mask; - - } - if (position.z >= (dimension / 2) + quad_position.z) { - - quad_position.z += (dimension / 2); - - mask_index += 4; - - state.idx_stack[state.scale] |= idx_set_z_mask; - - } - - // Check to see if we are on a valid oct - if ((head >> 16) & mask_8[mask_index]) { - - // Check to see if it is a leaf - if ((head >> 24) & mask_8[mask_index]) { - - // If it is, then we cannot traverse further as CP's won't have been generated - return true; - } - - // If all went well and we found a valid non-leaf oct then we will traverse further down the hierarchy - state.scale++; - dimension /= 2; - - // Count the number of valid octs that come before and add it to the index to get the position - // Negate it by one as it counts itself - int count = count_bits((uint8_t)(head >> 16) & count_mask_8[mask_index]) - 1; - - // access the element at which head points to and then add the specified number of indices - // to get to the correct child descriptor - head = blob[(head & child_pointer_mask) + count]; - - // Increment the parent stack position and put the new oct node as the parent - state.parent_stack_position++; - state.parent_stack[state.parent_stack_position] = head; - - } - else { - // If the oct was not valid, then no CP's exists any further - // This implicitly says that if it's non-valid then it must be a leaf!! - - // It appears that the traversal is now working but I need - // to focus on how to now take care of the end condition. - // Currently it adds the last parent on the second to lowest - // oct CP. Not sure if thats correct - return false; - } - } - - return true; -} - -void Octree::print_block(int block_pos) { - - std::stringstream sss; - for (int i = block_pos; i < (int)pow(2, 15); i++) { - PrettyPrintUINT64(blob[i], &sss); - sss << "\n"; - } - DumpLog(&sss, "raw_data.txt"); - -} - diff --git a/src/Ray.cpp b/src/Ray.cpp index e1daad7..167651c 100644 --- a/src/Ray.cpp +++ b/src/Ray.cpp @@ -1,6 +1,6 @@ #include #include -#include "Map.h" +#include "map/Map.h" #include #include "util.hpp" diff --git a/src/main.cpp b/src/main.cpp index 54b607b..81c037a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,7 +28,7 @@ #include #include #include -#include "Old_Map.h" +#include "map/Old_Map.h" #include "raycaster/RayCaster.h" #include "raycaster/Hardware_Caster.h" #include "Vector4.hpp" @@ -40,7 +40,6 @@ #include "imgui/imgui-SFML.h" #include "imgui/imgui.h" - const int WINDOW_X = 1440; const int WINDOW_Y = 900; const int WORK_SIZE = WINDOW_X * WINDOW_Y; @@ -94,7 +93,7 @@ int main() { // ni.stop_listening_for_clients(); // ============================= - Map _map(sf::Vector3i(0, 0, 0)); + Map _map(32); _map.generate_octree(); _map.a.print_block(0); _map.test_map(); @@ -278,8 +277,8 @@ int main() { handle->set_position(light); } - light_pos[0] = sin(elapsed_time) * 100.0f + 300.0f; - light_pos[1] = sin(elapsed_time) * 100.0f + 300.0f; + light_pos[0] = static_cast(sin(elapsed_time) * 100.0f + 300.0f); + light_pos[1] = static_cast(sin(elapsed_time) * 100.0f + 300.0f); sf::Vector3f light(light_pos[0], light_pos[1], light_pos[2]); handle->set_position(light); diff --git a/src/map/Map.cpp b/src/map/Map.cpp new file mode 100644 index 0000000..5fffbbc --- /dev/null +++ b/src/map/Map.cpp @@ -0,0 +1,197 @@ +#include "map/Map.h" + + +Map::Map(uint32_t dimensions) { + + srand(time(nullptr)); + + voxel_data = new char[dimensions * dimensions * dimensions]; + + for (uint64_t i = 0; i < dimensions * dimensions * dimensions; i++) { + if (rand() % 25 < 2) + voxel_data[i] = 1; + else + voxel_data[i] = 1; + } + +} + +uint64_t Map::generate_children(sf::Vector3i pos, int voxel_scale) { + + + // The 8 subvoxel coords starting from the 1th direction, the direction of the origin of the 3d grid + // XY, Z++, XY + std::vector v = { + sf::Vector3i(pos.x , pos.y , pos.z), + sf::Vector3i(pos.x + voxel_scale, pos.y , pos.z), + sf::Vector3i(pos.x , pos.y + voxel_scale, pos.z), + sf::Vector3i(pos.x + voxel_scale, pos.y + voxel_scale, pos.z), + sf::Vector3i(pos.x , pos.y , pos.z + voxel_scale), + sf::Vector3i(pos.x + voxel_scale, pos.y , pos.z + voxel_scale), + sf::Vector3i(pos.x , pos.y + voxel_scale, pos.z + voxel_scale), + sf::Vector3i(pos.x + voxel_scale, pos.y + voxel_scale, pos.z + voxel_scale) + }; + + // If we hit the 1th voxel scale then we need to query the 3D grid + // and get the voxel at that position. I assume in the future when I + // want to do chunking / loading of raw data I can edit the voxel access + if (voxel_scale == 1) { + + // + uint64_t child_descriptor = 0; + + // Setting the individual valid mask bits + // These don't bound check, should they? + for (int i = 0; i < v.size(); i++) { + if (getVoxel(v.at(i))) + SetBit(i + 16, &child_descriptor); + } + + // We are querying leafs, so we need to fill the leaf mask + child_descriptor |= 0xFF000000; + + // This is where contours + // The CP will be left blank, contours will be added maybe + return child_descriptor; + + } + + // Init a blank child descriptor for this node + uint64_t child_descriptor = 0; + + std::vector descriptor_array; + + // Generate down the recursion, returning the descriptor of the current node + for (int i = 0; i < v.size(); i++) { + + uint64_t child = 0; + + // Get the child descriptor from the i'th to 8th subvoxel + child = generate_children(v.at(i), voxel_scale / 2); + + // =========== Debug =========== + PrettyPrintUINT64(child, &output_stream); + output_stream << " " << voxel_scale << " " << counter++ << std::endl; + // ============================= + + // If the child is a leaf (contiguous) of non-valid values + if (IsLeaf(child) && !CheckLeafSign(child)) { + // Leave the valid mask 0, set leaf mask to 1 + SetBit(i + 16 + 8, &child_descriptor); + } + + // If the child is valid and not a leaf + else { + + // Set the valid mask, and add it to the descriptor array + SetBit(i + 16, &child_descriptor); + descriptor_array.push_back(child); + } + } + + // Any free space between the child descriptors must be added here in order to + // interlace them and allow the memory handler to work correctly. + + // Copy the children to the stack and set the child_descriptors pointer to the correct value + child_descriptor |= a.copy_to_stack(descriptor_array); + + // Free space may also be allocated here as well + + // Return the node up the stack + return child_descriptor; +} + +void Map::generate_octree() { + + // Launch the recursive generator at (0,0,0) as the first point + // and the octree dimension as the initial block size + uint64_t root_node = generate_children(sf::Vector3i(0, 0, 0), OCT_DIM/2); + uint64_t tmp = 0; + + // ========= DEBUG ============== + PrettyPrintUINT64(root_node, &output_stream); + output_stream << " " << OCT_DIM << " " << counter++ << std::endl; + // ============================== + + a.root_index = a.copy_to_stack(std::vector{root_node}); + + // Dump the debug log + DumpLog(&output_stream, "raw_output.txt"); + +} + +void Map::setVoxel(sf::Vector3i world_position, int val) { + +} + +bool Map::getVoxelFromOctree(sf::Vector3i position) +{ + return a.get_voxel(position); +} + +bool Map::getVoxel(sf::Vector3i pos){ + + if (voxel_data[pos.x + OCT_DIM * (pos.y + OCT_DIM * pos.z)]) { + return true; + } else { + return false; + } +} + +void Map::test_map() { + + std::cout << "Validating map..." << std::endl; + + for (int x = 0; x < OCT_DIM; x++) { + for (int y = 0; y < OCT_DIM; y++) { + for (int z = 0; z < OCT_DIM; z++) { + + sf::Vector3i pos(x, y, z); + + bool arr1 = getVoxel(pos); + bool arr2 = getVoxelFromOctree(pos); + + if (arr1 != arr2) { + std::cout << "X: " << pos.x << "Y: " << pos.y << "Z: " << pos.z << std::endl; + } + + } + } + } + + std::cout << "Done" << std::endl; + + sf::Clock timer; + + timer.restart(); + + for (int x = 0; x < OCT_DIM; x++) { + for (int y = 0; y < OCT_DIM; y++) { + for (int z = 0; z < OCT_DIM; z++) { + + sf::Vector3i pos(x, y, z); + + bool arr1 = getVoxel(pos); + } + } + } + + std::cout << "Array linear xyz access : "; + std::cout << timer.restart().asMicroseconds() << " microseconds" << std::endl; + + for (int x = 0; x < OCT_DIM; x++) { + for (int y = 0; y < OCT_DIM; y++) { + for (int z = 0; z < OCT_DIM; z++) { + + sf::Vector3i pos(x, y, z); + + bool arr2 = getVoxelFromOctree(pos); + } + } + } + + std::cout << "Octree linear xyz access : "; + std::cout << timer.restart().asMicroseconds() << " microseconds" << std::endl; + +} + diff --git a/src/map/Octree.cpp b/src/map/Octree.cpp new file mode 100644 index 0000000..873c4be --- /dev/null +++ b/src/map/Octree.cpp @@ -0,0 +1,151 @@ +#include "map/Octree.h" + +Octree::Octree() { + + // initialize the first stack block + + for (int i = 0; i < 0x8000; i++) { + blob[i] = 0; + } +} + +uint64_t Octree::copy_to_stack(std::vector children) { + + // Check for the 15 bit boundry + if (stack_pos - children.size() > stack_pos) { + global_pos = stack_pos; + stack_pos = 0x8000; + } + else { + stack_pos -= children.size(); + } + + // Check for the far bit + + memcpy(&blob[stack_pos + global_pos], children.data(), children.size() * sizeof(uint64_t)); + + // Return the bitmask encoding the index of that value + // If we tripped the far bit, allocate a far index to the stack and place + // it at the bottom of the child_descriptor node level array + // And then shift the far bit to 1 + + // If not, shift the index to its correct place + return stack_pos; +} + +bool Octree::get_voxel(sf::Vector3i position) { + + // Struct that holds the state necessary to continue the traversal from the found voxel + oct_state state; + + // push the root node to the parent stack + uint64_t head = blob[root_index]; + state.parent_stack[state.parent_stack_position] = head; + + // Set our initial dimension and the position at the corner of the oct to keep track of our position + int dimension = OCT_DIM; + sf::Vector3i quad_position(0, 0, 0); + + // While we are not at the required resolution + // Traverse down by setting the valid/leaf mask to the subvoxel + // Check to see if it is valid + // Yes? + // Check to see if it is a leaf + // No? Break + // Yes? Scale down to the next hierarchy, push the parent to the stack + // + // No? + // Break + while (dimension > 1) { + + // So we can be a little bit tricky here and increment our + // array index that holds our masks as we build the idx. + // Adding 1 for X, 2 for Y, and 4 for Z + int mask_index = 0; + + + // Do the logic steps to find which sub oct we step down into + if (position.x >= (dimension / 2) + quad_position.x) { + + // Set our voxel position to the (0,0) of the correct oct + quad_position.x += (dimension / 2); + + // increment the mask index and mentioned above + mask_index += 1; + + // Set the idx to represent the move + state.idx_stack[state.scale] |= idx_set_x_mask; + + } + if (position.y >= (dimension / 2) + quad_position.y) { + + quad_position.y |= (dimension / 2); + + mask_index += 2; + + state.idx_stack[state.scale] ^= idx_set_y_mask; + + } + if (position.z >= (dimension / 2) + quad_position.z) { + + quad_position.z += (dimension / 2); + + mask_index += 4; + + state.idx_stack[state.scale] |= idx_set_z_mask; + + } + + // Check to see if we are on a valid oct + if ((head >> 16) & mask_8[mask_index]) { + + // Check to see if it is a leaf + if ((head >> 24) & mask_8[mask_index]) { + + // If it is, then we cannot traverse further as CP's won't have been generated + return true; + } + + // If all went well and we found a valid non-leaf oct then we will traverse further down the hierarchy + state.scale++; + dimension /= 2; + + // Count the number of valid octs that come before and add it to the index to get the position + // Negate it by one as it counts itself + int count = count_bits((uint8_t)(head >> 16) & count_mask_8[mask_index]) - 1; + + // access the element at which head points to and then add the specified number of indices + // to get to the correct child descriptor + head = blob[(head & child_pointer_mask) + count]; + + // Increment the parent stack position and put the new oct node as the parent + state.parent_stack_position++; + state.parent_stack[state.parent_stack_position] = head; + + } + else { + // If the oct was not valid, then no CP's exists any further + // This implicitly says that if it's non-valid then it must be a leaf!! + + // It appears that the traversal is now working but I need + // to focus on how to now take care of the end condition. + // Currently it adds the last parent on the second to lowest + // oct CP. Not sure if thats correct + return false; + } + } + + return true; +} + +void Octree::print_block(int block_pos) { + + std::stringstream sss; + for (int i = block_pos; i < (int)pow(2, 15); i++) { + PrettyPrintUINT64(blob[i], &sss); + sss << "\n"; + } + DumpLog(&sss, "raw_data.txt"); + +} + diff --git a/src/Old_Map.cpp b/src/map/Old_Map.cpp similarity index 99% rename from src/Old_Map.cpp rename to src/map/Old_Map.cpp index d4398d4..105ea02 100644 --- a/src/Old_Map.cpp +++ b/src/map/Old_Map.cpp @@ -2,7 +2,7 @@ #include #include #include "util.hpp" -#include +#include #include Old_Map::Old_Map(sf::Vector3i dim) {