From c35f867c76b68fba3dd6ba3b405d6175e1a4dcf2 Mon Sep 17 00:00:00 2001 From: MitchellHansen Date: Tue, 17 Oct 2017 23:59:15 -0700 Subject: [PATCH] Shuffling the map stuff around to make more sense structurally. Also shrunk the scope of the demos wayyyy down to facilitate easier debugging in my next planned steps --- include/Application.h | 12 +- include/CLCaster.h | 8 +- include/Camera.h | 2 +- include/map/ArrayMap.h | 35 ++++ include/map/Map.h | 61 ++++-- include/map/Octree.h | 7 + include/map/Old_Map.h | 42 ---- src/Application.cpp | 26 +-- src/CLCaster.cpp | 20 +- src/Input.cpp | 8 +- src/map/ArrayMap.cpp | 147 ++++++++++++++ src/map/Map.cpp | 431 ++++++++++++++++------------------------- src/map/Octree.cpp | 215 ++++++++++++++++++++ src/map/Old_Map.cpp | 397 ------------------------------------- 14 files changed, 639 insertions(+), 772 deletions(-) create mode 100644 include/map/ArrayMap.h delete mode 100644 include/map/Old_Map.h create mode 100644 src/map/ArrayMap.cpp delete mode 100644 src/map/Old_Map.cpp diff --git a/include/Application.h b/include/Application.h index e75400b..06000a9 100644 --- a/include/Application.h +++ b/include/Application.h @@ -23,13 +23,14 @@ #include "util.hpp" #include -#include "map/Old_Map.h" #include "CLCaster.h" #include "Camera.h" #include "Input.h" #include "LightController.h" #include "LightHandle.h" #include "map/Map.h" +#include +#include "imgui/imgui-SFML.h" // Srsly people who macro error codes are the devil #undef ERROR @@ -41,9 +42,9 @@ public: const int WINDOW_X = 1600; const int WINDOW_Y = 900; - const int MAP_X = 256; - const int MAP_Y = 256; - const int MAP_Z = 256; + const int MAP_X = 64; + const int MAP_Y = 64; + const int MAP_Z = 64; Application(); ~Application(); @@ -62,8 +63,7 @@ private: sf::Texture spritesheet; std::shared_ptr window; - std::shared_ptr map; - std::shared_ptr octree; + std::shared_ptr map; std::shared_ptr camera; std::shared_ptr raycaster; std::shared_ptr light_handle; diff --git a/include/CLCaster.h b/include/CLCaster.h index f172945..1813a30 100644 --- a/include/CLCaster.h +++ b/include/CLCaster.h @@ -5,7 +5,6 @@ #include #include #include "LightController.h" -#include "map/Old_Map.h" #include "Camera.h" #include #include @@ -115,11 +114,11 @@ public: bool assign_lights(std::vector *data) ; // We take a ptr to the map and create the map, and map_dimensions buffer for the GPU - bool assign_map(std::shared_ptr map); + bool assign_map(std::shared_ptr map); bool release_map(); // We take a ptr to the map and create the map, and map_dimensions buffer for the GPU - bool assign_octree(std::shared_ptr octree); + bool assign_octree(std::shared_ptr map); bool release_octree(); // We take a ptr to the camera and create a camera direction and position buffer @@ -287,8 +286,7 @@ private: sf::Vector2i viewport_resolution; std::shared_ptr camera; - std::shared_ptr map; - std::shared_ptr octree; + std::shared_ptr map; std::vector *lights; int light_count = 0; diff --git a/include/Camera.h b/include/Camera.h index 04c00aa..dc5d262 100644 --- a/include/Camera.h +++ b/include/Camera.h @@ -48,7 +48,7 @@ public: private: float friction_coefficient = 0.1f; - float default_impulse = 1.0f; + float default_impulse = 0.3f; // 3D vector sf::Vector3f movement; diff --git a/include/map/ArrayMap.h b/include/map/ArrayMap.h new file mode 100644 index 0000000..fbe9988 --- /dev/null +++ b/include/map/ArrayMap.h @@ -0,0 +1,35 @@ +#pragma once +#include +#include +#include "util.hpp" +#include +#include + +class ArrayMap { + + +public: + + ArrayMap(sf::Vector3i dimensions); + ~ArrayMap(); + + char getVoxel(sf::Vector3i position); + void setVoxel(sf::Vector3i position, char value); + sf::Vector3i getDimensions(); + + // =========== DEBUG =========== // + char* getDataPtr(); + + std::vector> ArrayMap::CastRayCharArray( + char* map, + sf::Vector3i* map_dim, + sf::Vector2f* cam_dir, + sf::Vector3f* cam_pos + ); + +private: + + char *voxel_data; + sf::Vector3i dimensions; + +}; \ No newline at end of file diff --git a/include/map/Map.h b/include/map/Map.h index c5179b5..a3a9cb9 100644 --- a/include/map/Map.h +++ b/include/map/Map.h @@ -7,16 +7,35 @@ #include "util.hpp" #include "map/Octree.h" #include -#include "map/Old_Map.h" +#include "map/ArrayMap.h" #define _USE_MATH_DEFINES #include + + +// MonolithicMap +// Octree +// Map + +// Player +// Camera +// Movement interface +// Subscription to joystick events? + +// Player needs to have some way to query the map +// Map could return collision result +// Could handle multiple collision types, aabb, ray +// player could query map and generate collision +// Wouldn't need to make map more complex + + + class Map { public: // Currently takes a - Map(uint32_t dimensions, Old_Map* array_map); + Map(uint32_t dimensions); // Sets a voxel in the 3D char dataset void setVoxel(sf::Vector3i position, int val); @@ -24,37 +43,37 @@ public: // Gets a voxel at the 3D position in the octree char getVoxel(sf::Vector3i pos); - std::vector> CastRayOctree( - Octree *octree, - sf::Vector3i* map_dim, - sf::Vector2f* cam_dir, - sf::Vector3f* cam_pos - ); - - std::vector> CastRayCharArray( - char *map, - sf::Vector3i* map_dim, - sf::Vector2f* cam_dir, - sf::Vector3f* cam_pos - ); + // Return the position at which a generalized ray hits a voxel + sf::Vector3f LongRayIntersection(sf::Vector3f origin, sf::Vector3f magnitude); + // Return the voxels that a box intersects / contains + std::vector BoxIntersection(sf::Vector3f origin, sf::Vector3f magnitude); + + // Return a normalized ray opposite of the intersected normals + sf::Vector3f ShortRayIntersection(sf::Vector3f origin, sf::Vector3f magnitude); + + sf::Image GenerateHeightBitmap(sf::Vector3i dimensions); + + void ApplyHeightmap(sf::Image bitmap); + // Octree handles all basic octree operations Octree octree; + ArrayMap array_map; private: - bool test_oct_arr_traversal(sf::Vector3i dimensions); - // ======= DEBUG =========== int counter = 0; std::stringstream output_stream; - // The 3D char dataset that is generated at runtime. This will be replaced by two different interactions. - // The first a file loading function that loads binary octree data. - // The second being an import tool which will allow Any -> Octree transformation. - char* voxel_data; + sf::Vector3i dimensions; // ========================= + double Sample(int x, int y, double *height_map); + void SetSample(int x, int y, double value, double *height_map); + void SampleSquare(int x, int y, int size, double value, double *height_map); + void SampleDiamond(int x, int y, int size, double value, double *height_map); + }; // Might possibly use this struct for hashing XYZ chunk values into a dict for storage and loading diff --git a/include/map/Octree.h b/include/map/Octree.h index 4002e80..174bbf5 100644 --- a/include/map/Octree.h +++ b/include/map/Octree.h @@ -91,6 +91,13 @@ public: static const uint64_t contour_pointer_mask = 0xFFFFFF00000000; static const uint64_t contour_mask = 0xFF00000000000000; + std::vector> Octree::CastRayOctree( + Octree *octree, + sf::Vector3i* map_dim, + sf::Vector2f* cam_dir, + sf::Vector3f* cam_pos + ); + private: unsigned int oct_dimensions = 1; diff --git a/include/map/Old_Map.h b/include/map/Old_Map.h deleted file mode 100644 index bbb9069..0000000 --- a/include/map/Old_Map.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include - -#define _USE_MATH_DEFINES -#include - -#include - -class Old_Map { -public: - - Old_Map(sf::Vector3i dim); - ~Old_Map(); - - void generate_terrain(); - - sf::Vector3i getDimensions(); - char* get_voxel_data(); - -protected: - -private: - - double* height_map; - char *voxel_data; - sf::Vector3i dimensions; - - void set_voxel(sf::Vector3i position, int val); - double sample(int x, int y); - void set_sample(int x, int y, double value); - void sample_square(int x, int y, int size, double value); - void sample_diamond(int x, int y, int size, double value); - void diamond_square(int stepsize, double scale); - - -}; diff --git a/src/Application.cpp b/src/Application.cpp index 86ea2e9..a866852 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -1,9 +1,7 @@ #include "Application.h" -#include -#include "imgui/imgui-SFML.h" + Application::Application() { - //srand(time(nullptr)); window = std::make_shared(sf::VideoMode(WINDOW_X, WINDOW_Y), "SFML"); window->setMouseCursorVisible(false); @@ -28,23 +26,17 @@ bool Application::init_clcaster() { if (!raycaster->init()) abort(); - // Create and generate the old 3d array style map - map = std::make_shared(sf::Vector3i(MAP_X, MAP_Y, MAP_Z)); - map->generate_terrain(); + map = std::make_shared(MAP_X); + sf::Image bitmap = map->GenerateHeightBitmap(sf::Vector3i(MAP_X, MAP_Y, MAP_Z)); + map->ApplyHeightmap(bitmap); - // Send the data to the GPU + raycaster->assign_octree(map); raycaster->assign_map(map); - // Init the raycaster with a specified dimension and a pointer to the source - // array style data - octree = std::make_shared(256, map.get()); - raycaster->assign_octree(octree); - - // Create a new camera with (starting position, direction) camera = std::make_shared( - sf::Vector3f(50, 50, 50), - sf::Vector2f(1.5f, 0.0f), + sf::Vector3f(50, 60, 10), + sf::Vector2f(1.5f, -2.0f), window.get() ); @@ -59,9 +51,9 @@ bool Application::init_clcaster() { // Create a light prototype, send it to the controller, and get the handle back LightPrototype prototype( - sf::Vector3f(100.0f, 156.0f, 58.0f), + sf::Vector3f(30, 30.0f, 30.0f), sf::Vector3f(-1.0f, -1.0f, -1.5f), - sf::Vector4f(0.1f, 0.1f, 0.1f, 0.8f) + sf::Vector4f(0.01f, 0.01f, 0.01f, 0.2f) ); light_handle = light_controller->create_light(prototype); diff --git a/src/CLCaster.cpp b/src/CLCaster.cpp index acb394c..0d23166 100644 --- a/src/CLCaster.cpp +++ b/src/CLCaster.cpp @@ -66,12 +66,12 @@ bool CLCaster::init() { } -bool CLCaster::assign_map(std::shared_ptr map) { +bool CLCaster::assign_map(std::shared_ptr map) { this->map = map; - auto dimensions = map->getDimensions(); + auto dimensions = map->array_map.getDimensions(); - if (!create_buffer("map", sizeof(char) * dimensions.x * dimensions.y * dimensions.z, map->get_voxel_data())) + if (!create_buffer("map", sizeof(char) * dimensions.x * dimensions.y * dimensions.z, map->array_map.getDataPtr())) return false; if (!create_buffer("map_dimensions", sizeof(int) * 3, &dimensions)) return false; @@ -92,17 +92,17 @@ bool CLCaster::release_map() { } -bool CLCaster::assign_octree(std::shared_ptr octree) { +bool CLCaster::assign_octree(std::shared_ptr map) { - this->octree = octree; + this->map = map; - if (!create_buffer("octree_descriptor_buffer", octree->octree.buffer_size * sizeof(uint64_t), octree->octree.descriptor_buffer)) + if (!create_buffer("octree_descriptor_buffer", map->octree.buffer_size * sizeof(uint64_t), map->octree.descriptor_buffer)) return false; - if (!create_buffer("octree_attachment_lookup_buffer", octree->octree.buffer_size * sizeof(uint32_t), octree->octree.attachment_lookup)) + if (!create_buffer("octree_attachment_lookup_buffer", map->octree.buffer_size * sizeof(uint32_t), map->octree.attachment_lookup)) return false; - if (!create_buffer("octree_attachment_buffer", octree->octree.buffer_size * sizeof(uint64_t), octree->octree.attachment_buffer)) + if (!create_buffer("octree_attachment_buffer", map->octree.buffer_size * sizeof(uint64_t), map->octree.attachment_buffer)) return false; - if (!create_buffer("settings_buffer", sizeof(uint64_t), &octree->octree.root_index)) + if (!create_buffer("settings_buffer", sizeof(uint64_t), &map->octree.root_index)) return false; return true; @@ -111,7 +111,7 @@ bool CLCaster::assign_octree(std::shared_ptr octree) { bool CLCaster::release_octree() { - this->octree = nullptr; + this->map = nullptr; if (!release_buffer("octree_descriptor_buffer")) return false; diff --git a/src/Input.cpp b/src/Input.cpp index 98010ff..0ab0c81 100644 --- a/src/Input.cpp +++ b/src/Input.cpp @@ -9,13 +9,11 @@ Input::Input() : keyboard_flags(sf::Keyboard::Key::KeyCount, false), - mouse_flags(sf::Mouse::Button::ButtonCount, false) -{ + mouse_flags(sf::Mouse::Button::ButtonCount, false){ } -Input::~Input() -{ +Input::~Input() { } @@ -218,7 +216,7 @@ void Input::transpose_sf_events(std::list sf_event_queue) { break; }; - // Mouse wheel moved will generate a MouseWheelScrolled event with the defaul vertical wheel + // Mouse wheel moved will generate a MouseWheelScrolled event with the default vertical wheel case sf::Event::MouseWheelMoved: { event_queue.emplace_back(std::make_unique(vr::MouseWheelScrolled(sf::Mouse::VerticalWheel, sf_event.mouseWheelScroll.delta, sf_event.mouseWheelScroll.x, sf_event.mouseWheelScroll.y))); break; diff --git a/src/map/ArrayMap.cpp b/src/map/ArrayMap.cpp new file mode 100644 index 0000000..33d5852 --- /dev/null +++ b/src/map/ArrayMap.cpp @@ -0,0 +1,147 @@ +#include + + + +ArrayMap::ArrayMap(sf::Vector3i dimensions) { + + this->dimensions = dimensions; + + voxel_data = new char[dimensions.x * dimensions.y * dimensions.z]; + for (int i = 0; i < dimensions.x * dimensions.y * dimensions.z; i++) { + voxel_data[i] = 0; + } + + for (int x = 0; x < dimensions.x; x++) { + for (int y = 0; y < dimensions.y; y++) { + setVoxel(sf::Vector3i(x, y, 1), 5); + } + } +} + + +ArrayMap::~ArrayMap() { + delete[] voxel_data; +} + +char ArrayMap::getVoxel(sf::Vector3i position) { + return voxel_data[position.x + dimensions.x * (position.y + dimensions.z * position.z)]; +} + + +void ArrayMap::setVoxel(sf::Vector3i position, char value) { + voxel_data[position.x + dimensions.x * (position.y + dimensions.z * position.z)] = value; +} + +sf::Vector3i ArrayMap::getDimensions() { + return dimensions; +} + +char* ArrayMap::getDataPtr() { + return voxel_data; +} + +std::vector> ArrayMap::CastRayCharArray( + char* map, + sf::Vector3i* map_dim, + sf::Vector2f* cam_dir, + sf::Vector3f* cam_pos +) { + // Setup the voxel coords from the camera origin + sf::Vector3i voxel(*cam_pos); + + std::vector> travel_path; + + sf::Vector3f ray_dir(1, 0, 0); + + // Pitch + ray_dir = sf::Vector3f( + ray_dir.z * sin((*cam_dir).x) + ray_dir.x * cos((*cam_dir).x), + ray_dir.y, + ray_dir.z * cos((*cam_dir).x) - ray_dir.x * sin((*cam_dir).x) + ); + + // Yaw + ray_dir = sf::Vector3f( + ray_dir.x * cos((*cam_dir).y) - ray_dir.y * sin((*cam_dir).y), + ray_dir.x * sin((*cam_dir).y) + ray_dir.y * cos((*cam_dir).y), + ray_dir.z + ); + + // correct for the base ray pointing to (1, 0, 0) as (0, 0). Should equal (1.57, 0) + ray_dir = sf::Vector3f( + static_cast(ray_dir.z * sin(-1.57) + ray_dir.x * cos(-1.57)), + static_cast(ray_dir.y), + static_cast(ray_dir.z * cos(-1.57) - ray_dir.x * sin(-1.57)) + ); + + + // Setup the voxel step based on what direction the ray is pointing + sf::Vector3i voxel_step(1, 1, 1); + + voxel_step.x *= (ray_dir.x > 0) - (ray_dir.x < 0); + voxel_step.y *= (ray_dir.y > 0) - (ray_dir.y < 0); + voxel_step.z *= (ray_dir.z > 0) - (ray_dir.z < 0); + + + // Delta T is the units a ray must travel along an axis in order to + // traverse an integer split + sf::Vector3f delta_t( + fabs(1.0f / ray_dir.x), + fabs(1.0f / ray_dir.y), + fabs(1.0f / ray_dir.z) + ); + + // offset is how far we are into a voxel, enables sub voxel movement + // Intersection T is the collection of the next intersection points + // for all 3 axis XYZ. + sf::Vector3f intersection_t( + delta_t.x * (cam_pos->x - floor(cam_pos->x)) * voxel_step.x, + delta_t.y * (cam_pos->y - floor(cam_pos->y)) * voxel_step.y, + delta_t.z * (cam_pos->z - floor(cam_pos->z)) * voxel_step.z + ); + + // for negative values, wrap around the delta_t + intersection_t.x -= delta_t.x * (std::min(intersection_t.x, 0.0f)); + intersection_t.y -= delta_t.y * (std::min(intersection_t.y, 0.0f)); + intersection_t.z -= delta_t.z * (std::min(intersection_t.z, 0.0f)); + + + int dist = 0; + sf::Vector3i face_mask(0, 0, 0); + int voxel_data = 0; + + // Andrew Woo's raycasting algo + do { + + face_mask.x = intersection_t.x <= std::min(intersection_t.y, intersection_t.z); + face_mask.y = intersection_t.y <= std::min(intersection_t.z, intersection_t.x); + face_mask.z = intersection_t.z <= std::min(intersection_t.x, intersection_t.y); + + intersection_t.x += delta_t.x * fabs(face_mask.x); + intersection_t.y += delta_t.y * fabs(face_mask.y); + intersection_t.z += delta_t.z * fabs(face_mask.z); + + voxel.x += voxel_step.x * face_mask.x; + voxel.y += voxel_step.y * face_mask.y; + voxel.z += voxel_step.z * face_mask.z; + + if (voxel.x >= map_dim->x || voxel.y >= map_dim->y || voxel.z >= map_dim->z) { + return travel_path; + } + if (voxel.x < 0 || voxel.y < 0 || voxel.z < 0) { + return travel_path; + } + + // If we hit a voxel + voxel_data = map[voxel.x + (*map_dim).x * (voxel.y + (*map_dim).z * (voxel.z))]; + + travel_path.push_back(std::make_tuple(voxel, voxel_data)); + + if (voxel_data != 0) + return travel_path; + + + } while (++dist < 700.0f); + + return travel_path; +} \ No newline at end of file diff --git a/src/map/Map.cpp b/src/map/Map.cpp index 39e1b43..689a43e 100644 --- a/src/map/Map.cpp +++ b/src/map/Map.cpp @@ -2,104 +2,53 @@ #include "Logger.h" -Map::Map(uint32_t dimensions, Old_Map* array_map) { - +Map::Map(uint32_t dimensions) : array_map(sf::Vector3i(dimensions, dimensions, dimensions)) { if ((int)pow(2, (int)log2(dimensions)) != dimensions) Logger::log("Map dimensions not an even exponent of 2", Logger::LogLevel::ERROR, __LINE__, __FILE__); - voxel_data = new char[dimensions * dimensions * dimensions]; - - // randomly set the voxel data for testing - for (uint64_t i = 0; i < dimensions * dimensions * dimensions; i++) { - //if (rand() % 10000 < 3) - // voxel_data[i] = 1; - //else - voxel_data[i] = 0; - } - - char* char_array = array_map->get_voxel_data(); - sf::Vector3i arr_dimensions = array_map->getDimensions(); - - for (int x = 0; x < dimensions; x++) { - for (int y = 0; y < dimensions; y++) { - for (int z = 0; z < dimensions; z++) { - - char v = char_array[x + arr_dimensions.x * (y + arr_dimensions.z * z)]; - if (v) - voxel_data[x + dimensions * (y + dimensions * z)] = 1; - } - } - } - sf::Vector3i dim3(dimensions, dimensions, dimensions); Logger::log("Generating Octree", Logger::LogLevel::INFO); - octree.Generate(voxel_data, dim3); + octree.Generate(array_map.getDataPtr(), dim3); Logger::log("Validating Octree", Logger::LogLevel::INFO); - if (!octree.Validate(voxel_data, dim3)) { + if (!octree.Validate(array_map.getDataPtr(), dim3)) { Logger::log("Octree validation failed", Logger::LogLevel::ERROR, __LINE__, __FILE__); } - - // TODO: Create test with mock octree data and defined test framework - Logger::log("Testing Array vs Octree ray traversal", Logger::LogLevel::INFO); - if (!test_oct_arr_traversal(dim3)) { - Logger::log("Array and Octree traversals DID NOT MATCH!!!", Logger::LogLevel::ERROR, __LINE__, __FILE__); - } - -} - -bool Map::test_oct_arr_traversal(sf::Vector3i dimensions) { - - //sf::Vector2f cam_dir(0.95, 0.81); - //sf::Vector3f cam_pos(10.5, 10.5, 10.5); - //std::vector> list1 = CastRayCharArray(voxel_data, &dimensions, &cam_dir, &cam_pos); - //std::vector> list2 = CastRayOctree(&octree, &dimensions, &cam_dir, &cam_pos); - - //if (list1 != list2) { - // return false; - //} else { - // return true; - //} - - - return false; } void Map::setVoxel(sf::Vector3i pos, int val) { - voxel_data[pos.x + octree.getDimensions() * (pos.y + octree.getDimensions() * pos.z)] = val; + array_map.getDataPtr()[pos.x + array_map.getDimensions().x * (pos.y + array_map.getDimensions().z * pos.z)] = val; } char Map::getVoxel(sf::Vector3i pos){ + + return array_map.getDataPtr()[pos.x + array_map.getDimensions().x * (pos.y + array_map.getDimensions().z * pos.z)]; return octree.GetVoxel(pos).found; } - -std::vector> Map::CastRayCharArray( - char* map, - sf::Vector3i* map_dim, - sf::Vector2f* cam_dir, - sf::Vector3f* cam_pos -) { - // Setup the voxel coords from the camera origin - sf::Vector3i voxel(*cam_pos); +sf::Vector3f Map::LongRayIntersection(sf::Vector3f origin, sf::Vector3f magnitude) { + + sf::Vector3i voxel(origin); std::vector> travel_path; sf::Vector3f ray_dir(1, 0, 0); + sf::Vector3i map_dim = array_map.getDimensions(); + // Pitch ray_dir = sf::Vector3f( - ray_dir.z * sin((*cam_dir).x) + ray_dir.x * cos((*cam_dir).x), + ray_dir.z * sin(magnitude.x) + ray_dir.x * cos(magnitude.x), ray_dir.y, - ray_dir.z * cos((*cam_dir).x) - ray_dir.x * sin((*cam_dir).x) - ); + ray_dir.z * cos(magnitude.x) - ray_dir.x * sin(magnitude.x) + ); // Yaw ray_dir = sf::Vector3f( - ray_dir.x * cos((*cam_dir).y) - ray_dir.y * sin((*cam_dir).y), - ray_dir.x * sin((*cam_dir).y) + ray_dir.y * cos((*cam_dir).y), + ray_dir.x * cos(magnitude.y) - ray_dir.y * sin(magnitude.y), + ray_dir.x * sin(magnitude.y) + ray_dir.y * cos(magnitude.y), ray_dir.z ); @@ -131,9 +80,9 @@ std::vector> Map::CastRayCharArray( // Intersection T is the collection of the next intersection points // for all 3 axis XYZ. sf::Vector3f intersection_t( - delta_t.x * (cam_pos->x - floor(cam_pos->x)) * voxel_step.x, - delta_t.y * (cam_pos->y - floor(cam_pos->y)) * voxel_step.y, - delta_t.z * (cam_pos->z - floor(cam_pos->z)) * voxel_step.z + delta_t.x * (origin.x - floor(origin.x)) * voxel_step.x, + delta_t.y * (origin.y - floor(origin.y)) * voxel_step.y, + delta_t.z * (origin.z - floor(origin.z)) * voxel_step.z ); // for negative values, wrap around the delta_t @@ -161,239 +110,185 @@ std::vector> Map::CastRayCharArray( voxel.y += voxel_step.y * face_mask.y; voxel.z += voxel_step.z * face_mask.z; - if (voxel.x >= map_dim->x || voxel.y >= map_dim->y || voxel.z >= map_dim->z) { - return travel_path; + if (voxel.x >= map_dim.x || voxel.y >= map_dim.y || voxel.z >= map_dim.z) { + return intersection_t; } if (voxel.x < 0 || voxel.y < 0 || voxel.z < 0) { - return travel_path; + return intersection_t; } // If we hit a voxel - voxel_data = map[voxel.x + (*map_dim).x * (voxel.y + (*map_dim).z * (voxel.z))]; - - travel_path.push_back(std::make_tuple(voxel, voxel_data)); + voxel_data = array_map.getDataPtr()[voxel.x + map_dim.x * (voxel.y + map_dim.z * (voxel.z))]; if (voxel_data != 0) - return travel_path; - + return intersection_t; + } while (++dist < 700.0f); - return travel_path; + return intersection_t; } -class Octree; - -std::vector> Map::CastRayOctree( - Octree *octree, - sf::Vector3i* map_dim, - sf::Vector2f* cam_dir, - sf::Vector3f* cam_pos -) { - - // Setup the voxel coords from the camera origin - sf::Vector3i voxel(0,0,0); - - // THIS DOES NOT HAVE TO RETURN TRUE ON FOUND - // This function when passed an "air" voxel will return as far down - // the IDX stack as it could go. We use this oct-level to determine - // our first position and jump. Updating it as we go - OctState traversal_state = octree->GetVoxel(voxel); - - std::vector> travel_path; - - sf::Vector3f ray_dir(1, 0, 0); - - // Pitch - ray_dir = sf::Vector3f( - ray_dir.z * sin((*cam_dir).x) + ray_dir.x * cos((*cam_dir).x), - ray_dir.y, - ray_dir.z * cos((*cam_dir).x) - ray_dir.x * sin((*cam_dir).x) - ); - - // Yaw - ray_dir = sf::Vector3f( - ray_dir.x * cos((*cam_dir).y) - ray_dir.y * sin((*cam_dir).y), - ray_dir.x * sin((*cam_dir).y) + ray_dir.y * cos((*cam_dir).y), - ray_dir.z - ); - - // correct for the base ray pointing to (1, 0, 0) as (0, 0). Should equal (1.57, 0) - ray_dir = sf::Vector3f( - static_cast(ray_dir.z * sin(-1.57) + ray_dir.x * cos(-1.57)), - static_cast(ray_dir.y), - static_cast(ray_dir.z * cos(-1.57) - ray_dir.x * sin(-1.57)) - ); - - - // Setup the voxel step based on what direction the ray is pointing - sf::Vector3i voxel_step(1, 1, 1); - - voxel_step.x *= (ray_dir.x > 0) - (ray_dir.x < 0); - voxel_step.y *= (ray_dir.y > 0) - (ray_dir.y < 0); - voxel_step.z *= (ray_dir.z > 0) - (ray_dir.z < 0); - - // set the jump multiplier based on the traversal state vs the log base 2 of the maps dimensions - int jump_power = log2(map_dim->x) - traversal_state.scale; - +std::vector Map::BoxIntersection(sf::Vector3f origin, sf::Vector3f magnitude) { + return std::vector(); +} - // Delta T is the units a ray must travel along an axis in order to - // traverse an integer split - sf::Vector3f delta_t( - fabs(1.0f / ray_dir.x), - fabs(1.0f / ray_dir.y), - fabs(1.0f / ray_dir.z) - ); +sf::Vector3f Map::ShortRayIntersection(sf::Vector3f origin, sf::Vector3f magnitude) { + return sf::Vector3f(0,0,0); +} - delta_t *= static_cast(jump_power); +void Map::ApplyHeightmap(sf::Image bitmap) { - // TODO: start here - // Whats the issue? - // Using traversal_scale - // set intersection t to the current hierarchy level each time we change levels - // and use that to step +} - - // Intersection T is the collection of the next intersection points - // for all 3 axis XYZ. We take the full positive cardinality when - // subtracting the floor, so we must transfer the sign over from - // the voxel step - sf::Vector3f intersection_t( - delta_t.x * (cam_pos->y - floor(cam_pos->x)) * voxel_step.x, - delta_t.y * (cam_pos->x - floor(cam_pos->y)) * voxel_step.y, - delta_t.z * (cam_pos->z - floor(cam_pos->z)) * voxel_step.z - ); +sf::Image Map::GenerateHeightBitmap(sf::Vector3i dimensions) { - // When we transfer the sign over, we get the correct direction of - // the offset, but we merely transposed over the value instead of mirroring - // it over the axis like we want. So here, isless returns a boolean if intersection_t - // is less than 0 which dictates whether or not we subtract the delta which in effect - // mirrors the offset - intersection_t.x -= delta_t.x * (std::isless(intersection_t.x, 0.0f)); - intersection_t.y -= delta_t.y * (std::isless(intersection_t.y, 0.0f)); - intersection_t.z -= delta_t.z * (std::isless(intersection_t.z, 0.0f)); + std::mt19937 gen; + std::uniform_real_distribution dis(-1.0, 1.0); + auto f_rand = std::bind(dis, std::ref(gen)); - int dist = 0; - sf::Vector3i face_mask(0, 0, 0); - int voxel_data = 0; + double* height_map = new double[dimensions.x * dimensions.y]; + for (int i = 0; i < dimensions.x * dimensions.y; i++) { + height_map[i] = 0; + } - // Andrew Woo's raycasting algo - do { + //size of grid to generate, note this must be a + //value 2^n+1 + int DATA_SIZE = dimensions.x + 1; + //an initial seed value for the corners of the data + //srand(f_rand()); + double SEED = rand() % 10 + 55; + + //seed the data + SetSample(0, 0, SEED, height_map); + SetSample(0, dimensions.y, SEED, height_map); + SetSample(dimensions.x, 0, SEED, height_map); + SetSample(dimensions.x, dimensions.y, SEED, height_map); + + double h = 20.0;//the range (-h -> +h) for the average offset + //for the new value in range of h + //side length is distance of a single square side + //or distance of diagonal in diamond + for (int sideLength = DATA_SIZE - 1; + //side length must be >= 2 so we always have + //a new value (if its 1 we overwrite existing values + //on the last iteration) + sideLength >= 2; + //each iteration we are looking at smaller squares + //diamonds, and we decrease the variation of the offset + sideLength /= 2, h /= 2.0) { + //half the length of the side of a square + //or distance from diamond center to one corner + //(just to make calcs below a little clearer) + int halfSide = sideLength / 2; + + //generate the new square values + for (int x = 0; x < DATA_SIZE - 1; x += sideLength) { + for (int y = 0; y < DATA_SIZE - 1; y += sideLength) { + //x, y is upper left corner of square + //calculate average of existing corners + double avg = Sample(x, y, height_map) + //top left + Sample(x + sideLength, y, height_map) +//top right + Sample(x, y + sideLength, height_map) + //lower left + Sample(x + sideLength, y + sideLength, height_map);//lower right + avg /= 4.0; + + //center is average plus random offset + SetSample(x + halfSide, y + halfSide, + //We calculate random value in range of 2h + //and then subtract h so the end value is + //in the range (-h, +h) + avg + (f_rand() * 2 * h) - h, height_map); + } + } - // check which direction we step in - face_mask.x = intersection_t.x <= std::min(intersection_t.y, intersection_t.z); - face_mask.y = intersection_t.y <= std::min(intersection_t.z, intersection_t.x); - face_mask.z = intersection_t.z <= std::min(intersection_t.x, intersection_t.y); + //generate the diamond values + //since the diamonds are staggered we only move x + //by half side + //NOTE: if the data shouldn't wrap then x < DATA_SIZE + //to generate the far edge values + for (int x = 0; x < DATA_SIZE - 1; x += halfSide) { + //and y is x offset by half a side, but moved by + //the full side length + //NOTE: if the data shouldn't wrap then y < DATA_SIZE + //to generate the far edge values + for (int y = (x + halfSide) % sideLength; y < DATA_SIZE - 1; y += sideLength) { + //x, y is center of diamond + //note we must use mod and add DATA_SIZE for subtraction + //so that we can wrap around the array to find the corners + double avg = + Sample((x - halfSide + DATA_SIZE) % DATA_SIZE, y, height_map) + //left of center + Sample((x + halfSide) % DATA_SIZE, y, height_map) + //right of center + Sample(x, (y + halfSide) % DATA_SIZE, height_map) + //below center + Sample(x, (y - halfSide + DATA_SIZE) % DATA_SIZE, height_map); //above center + avg /= 4.0; + + //new value = average plus random offset + //We calculate random value in range of 2h + //and then subtract h so the end value is + //in the range (-h, +h) + avg = avg + (f_rand() * 2 * h) - h; + //update value for center of diamond + SetSample(x, y, avg, height_map); + + //wrap values on the edges, remove + //this and adjust loop condition above + //for non-wrapping values. + if (x == 0) SetSample(DATA_SIZE - 1, y, avg, height_map); + if (y == 0) SetSample(x, DATA_SIZE - 1, avg, height_map); + } + } + } - // Increment the selected directions intersection, abs the face_mask to stay within the algo constraints - intersection_t.x += delta_t.x * fabs(face_mask.x); - intersection_t.y += delta_t.y * fabs(face_mask.y); - intersection_t.z += delta_t.z * fabs(face_mask.z); + sf::Uint8* pixels = new sf::Uint8[dimensions.x * dimensions.z * 4]; - // step the voxel direction - voxel.x += voxel_step.x * face_mask.x * jump_power; - voxel.y += voxel_step.y * face_mask.y * jump_power; - voxel.z += voxel_step.z * face_mask.z * jump_power; + for (int x = 0; x < dimensions.x; x++) { + for (int z = 0; z < dimensions.z; z++) { - uint8_t prev_val = traversal_state.idx_stack[traversal_state.scale]; - uint8_t this_face_mask = 0; + sf::Uint8 height = static_cast(std::min(std::max(height_map[x + z * dimensions.x], 0.0), (double)dimensions.z)); - // Check the voxel face that we traversed - // and increment the idx in the idx stack - if (face_mask.x) { - this_face_mask = Octree::idx_set_x_mask; - } - else if (face_mask.y) { - this_face_mask = Octree::idx_set_y_mask; - } - else if (face_mask.z) { - this_face_mask = Octree::idx_set_z_mask; - } + pixels[x + z * dimensions.x * 4 + 0] = height; + pixels[x + z * dimensions.x * 4 + 1] = height; + pixels[x + z * dimensions.x * 4 + 2] = height; + pixels[x + z * dimensions.x * 4 + 3] = sf::Uint8(255); - traversal_state.idx_stack[traversal_state.scale] ^= this_face_mask; - int mask_index = traversal_state.idx_stack[traversal_state.scale]; - - // Check to see if the idx increased or decreased - // If it decreased - // Pop up the stack until the oct that the idx flip is valid and we landed on a valid oct - while (traversal_state.idx_stack[traversal_state.scale] < prev_val || - !((traversal_state.parent_stack[traversal_state.parent_stack_position] >> 16) & Octree::mask_8[mask_index]) - ) { - - jump_power *= 2; - - // Keep track of the 0th edge of out current oct - traversal_state.oct_pos.x = floor(voxel.x / 2) * jump_power; - traversal_state.oct_pos.y = floor(voxel.x / 2) * jump_power; - traversal_state.oct_pos.z = floor(voxel.x / 2) * jump_power; - - // Clear and pop the idx stack - traversal_state.idx_stack[traversal_state.scale] = 0; - traversal_state.scale--; - - // Update the prev_val for our new idx - prev_val = traversal_state.idx_stack[traversal_state.scale]; - - // Clear and pop the parent stack, maybe off by one error? - traversal_state.parent_stack[traversal_state.parent_stack_position] = 0; - traversal_state.parent_stack_position--; - - // Set the current CD to the one on top of the stack - traversal_state.current_descriptor = - traversal_state.parent_stack[traversal_state.parent_stack_position]; - - // Apply the face mask to the new idx for the while check - traversal_state.idx_stack[traversal_state.scale] ^= this_face_mask; - mask_index = traversal_state.idx_stack[traversal_state.scale]; } - - - // Check to see if we are on a valid oct - //if ((traversal_state.parent_stack[traversal_state.parent_stack_position] >> 16) & Octree::mask_8[mask_index]) { - - // // Check to see if it is a leaf - // if ((traversal_state.parent_stack[traversal_state.parent_stack_position] >> 24) & Octree::mask_8[mask_index]) { + } - // // If it is, then we cannot traverse further as CP's won't have been generated - // state.found = 1; - // return state; - // } - //} - // Check to see if we are on top of a valid branch - // Traverse down to the lowest valid oct that the ray is within + sf::Image bitmap_img; + bitmap_img.create(dimensions.x, dimensions.z, pixels); - // When we pass a split, then that means that we traversed SCALE number of voxels in that direction + return bitmap_img; +} - // while the bit is valid and we are not bottomed out - // get the cp of the valid branch - // - // - // - // +double Map::Sample(int x, int y, double *height_map) { + return height_map[(x & (dimensions.x - 1)) + (y & (dimensions.y - 1)) * dimensions.x]; +} +void Map::SetSample(int x, int y, double value, double *height_map) { + height_map[(x & (dimensions.x - 1)) + (y & (dimensions.y - 1)) * dimensions.x] = value; +} - - - - if (voxel.x >= map_dim->x || voxel.y >= map_dim->y || voxel.z >= map_dim->z) { - return travel_path; - } - if (voxel.x < 0 || voxel.y < 0 || voxel.z < 0) { - return travel_path; - } +void Map::SampleSquare(int x, int y, int size, double value, double *height_map) { + int hs = size / 2; - // If we hit a voxel - //voxel_data = map[voxel.x + (*map_dim).x * (voxel.y + (*map_dim).z * (voxel.z))]; -// voxel_data = getVoxel(voxel); - travel_path.push_back(std::make_tuple(voxel, voxel_data)); + double a = Sample(x - hs, y - hs, height_map); + double b = Sample(x + hs, y - hs, height_map); + double c = Sample(x - hs, y + hs, height_map); + double d = Sample(x + hs, y + hs, height_map); - if (voxel_data != 0) - return travel_path; + SetSample(x, y, ((a + b + c + d) / 4.0) + value, height_map); +} +void Map::SampleDiamond(int x, int y, int size, double value, double *height_map) { + int hs = size / 2; - } while (++dist < 700.0f); + double a = Sample(x - hs, y, height_map); + double b = Sample(x + hs, y, height_map); + double c = Sample(x, y - hs, height_map); + double d = Sample(x, y + hs, height_map); - return travel_path; -} \ No newline at end of file + SetSample(x, y, ((a + b + c + d) / 4.0) + value, height_map); +} diff --git a/src/map/Octree.cpp b/src/map/Octree.cpp index c67b7f1..5bfbf8b 100644 --- a/src/map/Octree.cpp +++ b/src/map/Octree.cpp @@ -360,6 +360,221 @@ unsigned int Octree::getDimensions() { return oct_dimensions; } + +std::vector> Octree::CastRayOctree( + Octree *octree, + sf::Vector3i* map_dim, + sf::Vector2f* cam_dir, + sf::Vector3f* cam_pos +) { + + // Setup the voxel coords from the camera origin + sf::Vector3i voxel(0, 0, 0); + + // THIS DOES NOT HAVE TO RETURN TRUE ON FOUND + // This function when passed an "air" voxel will return as far down + // the IDX stack as it could go. We use this oct-level to determine + // our first position and jump. Updating it as we go + OctState traversal_state = octree->GetVoxel(voxel); + + std::vector> travel_path; + + sf::Vector3f ray_dir(1, 0, 0); + + // Pitch + ray_dir = sf::Vector3f( + ray_dir.z * sin((*cam_dir).x) + ray_dir.x * cos((*cam_dir).x), + ray_dir.y, + ray_dir.z * cos((*cam_dir).x) - ray_dir.x * sin((*cam_dir).x) + ); + + // Yaw + ray_dir = sf::Vector3f( + ray_dir.x * cos((*cam_dir).y) - ray_dir.y * sin((*cam_dir).y), + ray_dir.x * sin((*cam_dir).y) + ray_dir.y * cos((*cam_dir).y), + ray_dir.z + ); + + // correct for the base ray pointing to (1, 0, 0) as (0, 0). Should equal (1.57, 0) + ray_dir = sf::Vector3f( + static_cast(ray_dir.z * sin(-1.57) + ray_dir.x * cos(-1.57)), + static_cast(ray_dir.y), + static_cast(ray_dir.z * cos(-1.57) - ray_dir.x * sin(-1.57)) + ); + + + // Setup the voxel step based on what direction the ray is pointing + sf::Vector3i voxel_step(1, 1, 1); + + voxel_step.x *= (ray_dir.x > 0) - (ray_dir.x < 0); + voxel_step.y *= (ray_dir.y > 0) - (ray_dir.y < 0); + voxel_step.z *= (ray_dir.z > 0) - (ray_dir.z < 0); + + // set the jump multiplier based on the traversal state vs the log base 2 of the maps dimensions + int jump_power = log2(map_dim->x) - traversal_state.scale; + + + // Delta T is the units a ray must travel along an axis in order to + // traverse an integer split + sf::Vector3f delta_t( + fabs(1.0f / ray_dir.x), + fabs(1.0f / ray_dir.y), + fabs(1.0f / ray_dir.z) + ); + + delta_t *= static_cast(jump_power); + + // TODO: start here + // Whats the issue? + // Using traversal_scale + // set intersection t to the current hierarchy level each time we change levels + // and use that to step + + + // Intersection T is the collection of the next intersection points + // for all 3 axis XYZ. We take the full positive cardinality when + // subtracting the floor, so we must transfer the sign over from + // the voxel step + sf::Vector3f intersection_t( + delta_t.x * (cam_pos->y - floor(cam_pos->x)) * voxel_step.x, + delta_t.y * (cam_pos->x - floor(cam_pos->y)) * voxel_step.y, + delta_t.z * (cam_pos->z - floor(cam_pos->z)) * voxel_step.z + ); + + // When we transfer the sign over, we get the correct direction of + // the offset, but we merely transposed over the value instead of mirroring + // it over the axis like we want. So here, isless returns a boolean if intersection_t + // is less than 0 which dictates whether or not we subtract the delta which in effect + // mirrors the offset + intersection_t.x -= delta_t.x * (std::isless(intersection_t.x, 0.0f)); + intersection_t.y -= delta_t.y * (std::isless(intersection_t.y, 0.0f)); + intersection_t.z -= delta_t.z * (std::isless(intersection_t.z, 0.0f)); + + int dist = 0; + sf::Vector3i face_mask(0, 0, 0); + int voxel_data = 0; + + // Andrew Woo's raycasting algo + do { + + // check which direction we step in + face_mask.x = intersection_t.x <= std::min(intersection_t.y, intersection_t.z); + face_mask.y = intersection_t.y <= std::min(intersection_t.z, intersection_t.x); + face_mask.z = intersection_t.z <= std::min(intersection_t.x, intersection_t.y); + + // Increment the selected directions intersection, abs the face_mask to stay within the algo constraints + intersection_t.x += delta_t.x * fabs(face_mask.x); + intersection_t.y += delta_t.y * fabs(face_mask.y); + intersection_t.z += delta_t.z * fabs(face_mask.z); + + // step the voxel direction + voxel.x += voxel_step.x * face_mask.x * jump_power; + voxel.y += voxel_step.y * face_mask.y * jump_power; + voxel.z += voxel_step.z * face_mask.z * jump_power; + + uint8_t prev_val = traversal_state.idx_stack[traversal_state.scale]; + uint8_t this_face_mask = 0; + + // Check the voxel face that we traversed + // and increment the idx in the idx stack + if (face_mask.x) { + this_face_mask = Octree::idx_set_x_mask; + } + else if (face_mask.y) { + this_face_mask = Octree::idx_set_y_mask; + } + else if (face_mask.z) { + this_face_mask = Octree::idx_set_z_mask; + } + + traversal_state.idx_stack[traversal_state.scale] ^= this_face_mask; + int mask_index = traversal_state.idx_stack[traversal_state.scale]; + + // Check to see if the idx increased or decreased + // If it decreased + // Pop up the stack until the oct that the idx flip is valid and we landed on a valid oct + while (traversal_state.idx_stack[traversal_state.scale] < prev_val || + !((traversal_state.parent_stack[traversal_state.parent_stack_position] >> 16) & Octree::mask_8[mask_index]) + ) { + + jump_power *= 2; + + // Keep track of the 0th edge of out current oct + traversal_state.oct_pos.x = floor(voxel.x / 2) * jump_power; + traversal_state.oct_pos.y = floor(voxel.x / 2) * jump_power; + traversal_state.oct_pos.z = floor(voxel.x / 2) * jump_power; + + // Clear and pop the idx stack + traversal_state.idx_stack[traversal_state.scale] = 0; + traversal_state.scale--; + + // Update the prev_val for our new idx + prev_val = traversal_state.idx_stack[traversal_state.scale]; + + // Clear and pop the parent stack, maybe off by one error? + traversal_state.parent_stack[traversal_state.parent_stack_position] = 0; + traversal_state.parent_stack_position--; + + // Set the current CD to the one on top of the stack + traversal_state.current_descriptor = + traversal_state.parent_stack[traversal_state.parent_stack_position]; + + // Apply the face mask to the new idx for the while check + traversal_state.idx_stack[traversal_state.scale] ^= this_face_mask; + mask_index = traversal_state.idx_stack[traversal_state.scale]; + } + + + // Check to see if we are on a valid oct + //if ((traversal_state.parent_stack[traversal_state.parent_stack_position] >> 16) & Octree::mask_8[mask_index]) { + + // // Check to see if it is a leaf + // if ((traversal_state.parent_stack[traversal_state.parent_stack_position] >> 24) & Octree::mask_8[mask_index]) { + + // // If it is, then we cannot traverse further as CP's won't have been generated + // state.found = 1; + // return state; + // } + //} + // Check to see if we are on top of a valid branch + // Traverse down to the lowest valid oct that the ray is within + + // When we pass a split, then that means that we traversed SCALE number of voxels in that direction + + + // while the bit is valid and we are not bottomed out + // get the cp of the valid branch + // + // + // + // + + + + + + + if (voxel.x >= map_dim->x || voxel.y >= map_dim->y || voxel.z >= map_dim->z) { + return travel_path; + } + if (voxel.x < 0 || voxel.y < 0 || voxel.z < 0) { + return travel_path; + } + + // If we hit a voxel + //voxel_data = map[voxel.x + (*map_dim).x * (voxel.y + (*map_dim).z * (voxel.z))]; + // voxel_data = getVoxel(voxel); + travel_path.push_back(std::make_tuple(voxel, voxel_data)); + + if (voxel_data != 0) + return travel_path; + + + } while (++dist < 700.0f); + + return travel_path; +} + const uint8_t Octree::mask_8[8] = { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 diff --git a/src/map/Old_Map.cpp b/src/map/Old_Map.cpp deleted file mode 100644 index a021f3c..0000000 --- a/src/map/Old_Map.cpp +++ /dev/null @@ -1,397 +0,0 @@ -#include -#include -#include -#include "util.hpp" -#include -#include - -Old_Map::Old_Map(sf::Vector3i dim) { - dimensions = dim; -} - - -Old_Map::~Old_Map() { -} - -void generate_at(int x, int y, std::vector> *grid) { - - size_t x_bound = grid->size(); - size_t y_bound = grid->at(0).size(); - - // N S E W - std::vector t = { 1, 2, 3, 4 }; - std::random_shuffle(t.begin(), t.end()); - - while (t.size() > 0) { - - switch (t.back()) { - - // 20 lines to hard code, a headache to do it cleverly - case 1: { - if (y + 1 < y_bound && grid->at(x).at(y + 1) == 0) { - grid->at(x).at(y) = 1; - grid->at(x).at(y + 1) = 2; - generate_at(x, y + 1, grid); - } - break; - } - case 2: { - if (y - 1 >= 0 && grid->at(x).at(y - 1) == 0) { - grid->at(x).at(y) = 2; - grid->at(x).at(y - 1) = 1; - generate_at(x, y - 1, grid); - } - break; - } - case 3: { - if (x + 1 < x_bound && grid->at(x+1).at(y) == 0) { - grid->at(x).at(y) = 3; - grid->at(x + 1).at(y) = 4; - generate_at(x + 1, y, grid); - } - break; - } - case 4: { - if (x - 1 >= 0 && grid->at(x-1).at(y) == 0) { - grid->at(x).at(y) = 4; - grid->at(x - 1).at(y) = 3; - generate_at(x - 1, y, grid); - } - break; - } - } - - t.pop_back(); - } -} - -std::vector> generate_maze(sf::Vector2i dimensions, sf::Vector2i start_point) { - - std::vector> grid(dimensions.x, std::vector(dimensions.y, 0)); - - generate_at(start_point.x, start_point.y, &grid); - - return grid; -} - - -void Old_Map::generate_terrain() { - std::mt19937 gen; - std::uniform_real_distribution dis(-1.0, 1.0); - auto f_rand = std::bind(dis, std::ref(gen)); - - voxel_data = new char[dimensions.x * dimensions.y * dimensions.z]; - height_map = new double[dimensions.x * dimensions.y]; - - for (int i = 0; i < dimensions.x * dimensions.y * dimensions.z; i++) { - voxel_data[i] = 0; - } - - //set_voxel(sf::Vector3i(63, 63, 63), 1); - - - for (int i = 0; i < dimensions.x * dimensions.y; i++) { - height_map[i] = 0; - } - - //size of grid to generate, note this must be a - //value 2^n+1 - int DATA_SIZE = dimensions.x + 1; - //an initial seed value for the corners of the data - //srand(f_rand()); - double SEED = rand() % 10 + 55; - - //seed the data - set_sample(0, 0, SEED); - set_sample(0, dimensions.y, SEED); - set_sample(dimensions.x, 0, SEED); - set_sample(dimensions.x, dimensions.y, SEED); - - double h = 20.0;//the range (-h -> +h) for the average offset - //for the new value in range of h - //side length is distance of a single square side - //or distance of diagonal in diamond - for (int sideLength = DATA_SIZE - 1; - //side length must be >= 2 so we always have - //a new value (if its 1 we overwrite existing values - //on the last iteration) - sideLength >= 2; - //each iteration we are looking at smaller squares - //diamonds, and we decrease the variation of the offset - sideLength /= 2, h /= 2.0) { - //half the length of the side of a square - //or distance from diamond center to one corner - //(just to make calcs below a little clearer) - int halfSide = sideLength / 2; - - //generate the new square values - for (int x = 0; x < DATA_SIZE - 1; x += sideLength) { - for (int y = 0; y < DATA_SIZE - 1; y += sideLength) { - //x, y is upper left corner of square - //calculate average of existing corners - double avg = sample(x, y) + //top left - sample(x + sideLength, y) +//top right - sample(x, y + sideLength) + //lower left - sample(x + sideLength, y + sideLength);//lower right - avg /= 4.0; - - //center is average plus random offset - set_sample(x + halfSide, y + halfSide, - //We calculate random value in range of 2h - //and then subtract h so the end value is - //in the range (-h, +h) - avg + (f_rand() * 2 * h) - h); - } - } - - //generate the diamond values - //since the diamonds are staggered we only move x - //by half side - //NOTE: if the data shouldn't wrap then x < DATA_SIZE - //to generate the far edge values - for (int x = 0; x < DATA_SIZE - 1; x += halfSide) { - //and y is x offset by half a side, but moved by - //the full side length - //NOTE: if the data shouldn't wrap then y < DATA_SIZE - //to generate the far edge values - for (int y = (x + halfSide) % sideLength; y < DATA_SIZE - 1; y += sideLength) { - //x, y is center of diamond - //note we must use mod and add DATA_SIZE for subtraction - //so that we can wrap around the array to find the corners - double avg = - sample((x - halfSide + DATA_SIZE) % DATA_SIZE, y) + //left of center - sample((x + halfSide) % DATA_SIZE, y) + //right of center - sample(x, (y + halfSide) % DATA_SIZE) + //below center - sample(x, (y - halfSide + DATA_SIZE) % DATA_SIZE); //above center - avg /= 4.0; - - //new value = average plus random offset - //We calculate random value in range of 2h - //and then subtract h so the end value is - //in the range (-h, +h) - avg = avg + (f_rand() * 2 * h) - h; - //update value for center of diamond - set_sample(x, y, avg); - - //wrap values on the edges, remove - //this and adjust loop condition above - //for non-wrapping values. - if (x == 0) set_sample(DATA_SIZE - 1, y, avg); - if (y == 0) set_sample(x, DATA_SIZE - 1, avg); - } - } - } - - //for (int x = 100; x < 150; x += 10) { - // for (int y = 100; y < 150; y += 10) { - // for (int z = 0; z < 10; z += 1) { - // - // voxel_data[x + dimensions.x * (y + dimensions.z * z)] = 6; - - // } - // } - //} - - - - for (int x = 0; x < dimensions.x; x++) { - for (int y = 0; y < dimensions.y; y++) { - - if (height_map[x + y * dimensions.x] > 0) { - - int z = static_cast(height_map[x + y * dimensions.x]); - - while (z > 0 && z < dimensions.z) { - voxel_data[x + dimensions.x * (y + dimensions.z * z)] = 5; - z--; - } - } - - } - } - - - for (int x = dimensions.x / 2; x < dimensions.x / 2 + dimensions.x / 64; x++) { - for (int y = dimensions.x / 2; y < dimensions.y / 2 + dimensions.x / 64; y++) { - for (int z = 2; z < 7; z++) { - - voxel_data[x + dimensions.x * (y + dimensions.z * z)] = 6; - } - } - } - - for (int x = dimensions.x / 2 - 3; x < dimensions.x / 2 + dimensions.x / 64 + 3; x++) { - for (int y = dimensions.x / 2 - 3; y < dimensions.y / 2 + dimensions.x / 64 + 3; y++) { - for (int z = 0; z < 1; z++) { - - voxel_data[x + dimensions.x * (y + dimensions.z * z)] = 5; - } - } - } - - - for (int x = 140; x < 145; x++) { - for (int y = 155; y < 160; y++) { - for (int z = 30; z < 35; z++) { - voxel_data[x + dimensions.x * (y + dimensions.z * z)] = 6; - } - } - } - - for (int x = 0; x < dimensions.x; x++) { - for (int y = 0; y < dimensions.y; y++) { - // for (int z = 0; z < dimensions.z; z++) { - //if (rand() % 1000 < 1) - voxel_data[x + dimensions.x * (y + dimensions.z * 1)] = 6; - // } - } - } - - //for (int x = 30; x < 60; x++) { - // //for (int y = 0; y < dimensions.y; y++) { - // for (int z = 10; z < 25; z++) { - // voxel_data[x + dimensions.x * (50 + dimensions.z * z)] = 6; - // } - // //} - //} - - // Hand code in some constructions - - std::vector> maze = - generate_maze(sf::Vector2i(8, 8), sf::Vector2i(0, 0)); - - for (int x = 0; x < maze.size(); x++) { - for (int y = 0; y < maze.at(0).size(); y++) { - - switch(maze.at(x).at(y)) { - - case 1: { // North - voxel_data[x * 3 + 1 + dimensions.x * (y * 3 + dimensions.z * 1)] = 6; - voxel_data[x * 3 + 1 + dimensions.x * (y * 3 + 1 + dimensions.z * 1)] = 6; - voxel_data[x * 3 + 1 + dimensions.x * (y * 3 + 2 + dimensions.z * 1)] = 5; - //voxel_data[x * 3 + dimensions.x * (y * 3 + 2 + dimensions.z * 1)] = 6; - //voxel_data[x * 3 + 2 + dimensions.x * (y * 3 + 2 + dimensions.z * 1)] = 6; - break; - } - case 2: { // South - voxel_data[x * 3 + 1 + dimensions.x * (y * 3 + dimensions.z * 1)] = 5; - voxel_data[x * 3 + 1 + dimensions.x * (y * 3 + 1 + dimensions.z * 1)] = 6; - voxel_data[x * 3 + 1 + dimensions.x * (y * 3 + 2 + dimensions.z * 1)] = 6; - //voxel_data[x * 3 + dimensions.x * (y * 3 + dimensions.z * 1)] = 6; - //voxel_data[x * 3 + 2 + dimensions.x * (y * 3 + dimensions.z * 1)] = 6; - break; - } - case 3: { // East - voxel_data[x * 3 + dimensions.x * (y * 3 + 1 + dimensions.z * 1)] = 6; - voxel_data[x * 3 + 1 + dimensions.x * (y * 3 + 1 + dimensions.z * 1)] = 6; - voxel_data[x * 3 + 2 + dimensions.x * (y * 3 + 1 + dimensions.z * 1)] = 5; - //voxel_data[x * 3 + 2 + dimensions.x * (y * 3 + dimensions.z * 1)] = 6; - //voxel_data[x * 3 + 2 + dimensions.x * (y * 3 + 2 + dimensions.z * 1)] = 6; - break; - } - case 4: { // West - voxel_data[x * 3 + dimensions.x * (y * 3 + 1 + dimensions.z * 1)] = 5; - voxel_data[x * 3 + 1 + dimensions.x * (y * 3 + 1 + dimensions.z * 1)] = 6; - voxel_data[x * 3 + 2 + dimensions.x * (y * 3 + 1 + dimensions.z * 1)] = 6; - //voxel_data[x * 3 + dimensions.x * (y * 3 + dimensions.z * 1)] = 6; - //voxel_data[x * 3 + dimensions.x * (y * 3 + 2 + dimensions.z * 1)] = 6; - break; - } - - } - - - } - } - - - //for (int x = 0; x < dimensions.x; x++) { - // for (int y = 0; y < dimensions.y; y++) { - // voxel_data[x + dimensions.x * (y + dimensions.z * 1)] = 6; - // } - //} - - set_voxel(sf::Vector3i(45, 70, 6), 6); - set_voxel(sf::Vector3i(47, 70, 6), 6); - set_voxel(sf::Vector3i(100, 100, 50), 1); - -} - - -void Old_Map::set_voxel(sf::Vector3i position, int val) { - voxel_data[position.x + dimensions.x * (position.y + dimensions.z * position.z)] = val; -} - -sf::Vector3i Old_Map::getDimensions() { - return dimensions; -} - -char* Old_Map::get_voxel_data() { - return voxel_data; -} - -double Old_Map::sample(int x, int y) { - return height_map[(x & (dimensions.x - 1)) + (y & (dimensions.y - 1)) * dimensions.x]; -} - -void Old_Map::set_sample(int x, int y, double value) { - height_map[(x & (dimensions.x - 1)) + (y & (dimensions.y - 1)) * dimensions.x] = value; -} - -void Old_Map::sample_square(int x, int y, int size, double value) { - int hs = size / 2; - - // a b - // - // x - // - // c d - - double a = sample(x - hs, y - hs); - double b = sample(x + hs, y - hs); - double c = sample(x - hs, y + hs); - double d = sample(x + hs, y + hs); - - set_sample(x, y, ((a + b + c + d) / 4.0) + value); - -} - -void Old_Map::sample_diamond(int x, int y, int size, double value) { - int hs = size / 2; - - // c - // - //a x b - // - // d - - double a = sample(x - hs, y); - double b = sample(x + hs, y); - double c = sample(x, y - hs); - double d = sample(x, y + hs); - - set_sample(x, y, ((a + b + c + d) / 4.0) + value); -} - -void Old_Map::diamond_square(int stepsize, double scale) { - - std::mt19937 generator; - std::uniform_real_distribution uniform_distribution(-1.0, 1.0); - auto f_rand = std::bind(uniform_distribution, std::ref(generator)); - - int halfstep = stepsize / 2; - - for (int y = halfstep; y < dimensions.y + halfstep; y += stepsize) { - for (int x = halfstep; x < dimensions.x + halfstep; x += stepsize) { - sample_square(x, y, stepsize, f_rand() * scale); - } - } - - for (int y = 0; y < dimensions.y; y += stepsize) { - for (int x = 0; x < dimensions.x; x += stepsize) { - sample_diamond(x + halfstep, y, stepsize, f_rand() * scale); - sample_diamond(x, y + halfstep, stepsize, f_rand() * scale); - } - } - -}