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

master
MitchellHansen 7 years ago
parent 242aaaa485
commit c35f867c76

@ -23,13 +23,14 @@
#include "util.hpp" #include "util.hpp"
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#include "map/Old_Map.h"
#include "CLCaster.h" #include "CLCaster.h"
#include "Camera.h" #include "Camera.h"
#include "Input.h" #include "Input.h"
#include "LightController.h" #include "LightController.h"
#include "LightHandle.h" #include "LightHandle.h"
#include "map/Map.h" #include "map/Map.h"
#include <chrono>
#include "imgui/imgui-SFML.h"
// Srsly people who macro error codes are the devil // Srsly people who macro error codes are the devil
#undef ERROR #undef ERROR
@ -41,9 +42,9 @@ public:
const int WINDOW_X = 1600; const int WINDOW_X = 1600;
const int WINDOW_Y = 900; const int WINDOW_Y = 900;
const int MAP_X = 256; const int MAP_X = 64;
const int MAP_Y = 256; const int MAP_Y = 64;
const int MAP_Z = 256; const int MAP_Z = 64;
Application(); Application();
~Application(); ~Application();
@ -62,8 +63,7 @@ private:
sf::Texture spritesheet; sf::Texture spritesheet;
std::shared_ptr<sf::RenderWindow> window; std::shared_ptr<sf::RenderWindow> window;
std::shared_ptr<Old_Map> map; std::shared_ptr<Map> map;
std::shared_ptr<Map> octree;
std::shared_ptr<Camera> camera; std::shared_ptr<Camera> camera;
std::shared_ptr<CLCaster> raycaster; std::shared_ptr<CLCaster> raycaster;
std::shared_ptr<LightHandle> light_handle; std::shared_ptr<LightHandle> light_handle;

@ -5,7 +5,6 @@
#include <map> #include <map>
#include <string.h> #include <string.h>
#include "LightController.h" #include "LightController.h"
#include "map/Old_Map.h"
#include "Camera.h" #include "Camera.h"
#include <GL/glew.h> #include <GL/glew.h>
#include <unordered_map> #include <unordered_map>
@ -115,11 +114,11 @@ public:
bool assign_lights(std::vector<PackedData> *data) ; bool assign_lights(std::vector<PackedData> *data) ;
// We take a ptr to the map and create the map, and map_dimensions buffer for the GPU // We take a ptr to the map and create the map, and map_dimensions buffer for the GPU
bool assign_map(std::shared_ptr<Old_Map> map); bool assign_map(std::shared_ptr<Map> map);
bool release_map(); bool release_map();
// We take a ptr to the map and create the map, and map_dimensions buffer for the GPU // We take a ptr to the map and create the map, and map_dimensions buffer for the GPU
bool assign_octree(std::shared_ptr<Map> octree); bool assign_octree(std::shared_ptr<Map> map);
bool release_octree(); bool release_octree();
// We take a ptr to the camera and create a camera direction and position buffer // We take a ptr to the camera and create a camera direction and position buffer
@ -287,8 +286,7 @@ private:
sf::Vector2i viewport_resolution; sf::Vector2i viewport_resolution;
std::shared_ptr<Camera> camera; std::shared_ptr<Camera> camera;
std::shared_ptr<Old_Map> map; std::shared_ptr<Map> map;
std::shared_ptr<Map> octree;
std::vector<PackedData> *lights; std::vector<PackedData> *lights;
int light_count = 0; int light_count = 0;

@ -48,7 +48,7 @@ public:
private: private:
float friction_coefficient = 0.1f; float friction_coefficient = 0.1f;
float default_impulse = 1.0f; float default_impulse = 0.3f;
// 3D vector // 3D vector
sf::Vector3f movement; sf::Vector3f movement;

@ -0,0 +1,35 @@
#pragma once
#include<SFML/Graphics.hpp>
#include <algorithm>
#include "util.hpp"
#include <random>
#include <functional>
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<std::tuple<sf::Vector3i, char>> ArrayMap::CastRayCharArray(
char* map,
sf::Vector3i* map_dim,
sf::Vector2f* cam_dir,
sf::Vector3f* cam_pos
);
private:
char *voxel_data;
sf::Vector3i dimensions;
};

@ -7,16 +7,35 @@
#include "util.hpp" #include "util.hpp"
#include "map/Octree.h" #include "map/Octree.h"
#include <time.h> #include <time.h>
#include "map/Old_Map.h" #include "map/ArrayMap.h"
#define _USE_MATH_DEFINES #define _USE_MATH_DEFINES
#include <math.h> #include <math.h>
// 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 { class Map {
public: public:
// Currently takes a // Currently takes a
Map(uint32_t dimensions, Old_Map* array_map); Map(uint32_t dimensions);
// Sets a voxel in the 3D char dataset // Sets a voxel in the 3D char dataset
void setVoxel(sf::Vector3i position, int val); void setVoxel(sf::Vector3i position, int val);
@ -24,37 +43,37 @@ public:
// Gets a voxel at the 3D position in the octree // Gets a voxel at the 3D position in the octree
char getVoxel(sf::Vector3i pos); char getVoxel(sf::Vector3i pos);
std::vector<std::tuple<sf::Vector3i, char>> CastRayOctree( // Return the position at which a generalized ray hits a voxel
Octree *octree, sf::Vector3f LongRayIntersection(sf::Vector3f origin, sf::Vector3f magnitude);
sf::Vector3i* map_dim,
sf::Vector2f* cam_dir, // Return the voxels that a box intersects / contains
sf::Vector3f* cam_pos std::vector<sf::Vector3i> 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);
std::vector<std::tuple<sf::Vector3i, char>> CastRayCharArray( sf::Image GenerateHeightBitmap(sf::Vector3i dimensions);
char *map,
sf::Vector3i* map_dim, void ApplyHeightmap(sf::Image bitmap);
sf::Vector2f* cam_dir,
sf::Vector3f* cam_pos
);
// Octree handles all basic octree operations // Octree handles all basic octree operations
Octree octree; Octree octree;
ArrayMap array_map;
private: private:
bool test_oct_arr_traversal(sf::Vector3i dimensions);
// ======= DEBUG =========== // ======= DEBUG ===========
int counter = 0; int counter = 0;
std::stringstream output_stream; std::stringstream output_stream;
// The 3D char dataset that is generated at runtime. This will be replaced by two different interactions. sf::Vector3i dimensions;
// 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;
// ========================= // =========================
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 // Might possibly use this struct for hashing XYZ chunk values into a dict for storage and loading

@ -91,6 +91,13 @@ public:
static const uint64_t contour_pointer_mask = 0xFFFFFF00000000; static const uint64_t contour_pointer_mask = 0xFFFFFF00000000;
static const uint64_t contour_mask = 0xFF00000000000000; static const uint64_t contour_mask = 0xFF00000000000000;
std::vector<std::tuple<sf::Vector3i, char>> Octree::CastRayOctree(
Octree *octree,
sf::Vector3i* map_dim,
sf::Vector2f* cam_dir,
sf::Vector3f* cam_pos
);
private: private:
unsigned int oct_dimensions = 1; unsigned int oct_dimensions = 1;

@ -1,42 +0,0 @@
#pragma once
#include <SFML/System/Vector3.hpp>
#include <SFML/System/Vector2.hpp>
#include <SFML/Graphics/Color.hpp>
#include <random>
#include <iostream>
#include <functional>
#include <cmath>
#define _USE_MATH_DEFINES
#include <math.h>
#include <deque>
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);
};

@ -1,9 +1,7 @@
#include "Application.h" #include "Application.h"
#include <chrono>
#include "imgui/imgui-SFML.h"
Application::Application() { Application::Application() {
//srand(time(nullptr));
window = std::make_shared<sf::RenderWindow>(sf::VideoMode(WINDOW_X, WINDOW_Y), "SFML"); window = std::make_shared<sf::RenderWindow>(sf::VideoMode(WINDOW_X, WINDOW_Y), "SFML");
window->setMouseCursorVisible(false); window->setMouseCursorVisible(false);
@ -28,23 +26,17 @@ bool Application::init_clcaster() {
if (!raycaster->init()) if (!raycaster->init())
abort(); abort();
// Create and generate the old 3d array style map map = std::make_shared<Map>(MAP_X);
map = std::make_shared<Old_Map>(sf::Vector3i(MAP_X, MAP_Y, MAP_Z)); sf::Image bitmap = map->GenerateHeightBitmap(sf::Vector3i(MAP_X, MAP_Y, MAP_Z));
map->generate_terrain(); map->ApplyHeightmap(bitmap);
// Send the data to the GPU raycaster->assign_octree(map);
raycaster->assign_map(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<Map>(256, map.get());
raycaster->assign_octree(octree);
// Create a new camera with (starting position, direction) // Create a new camera with (starting position, direction)
camera = std::make_shared<Camera>( camera = std::make_shared<Camera>(
sf::Vector3f(50, 50, 50), sf::Vector3f(50, 60, 10),
sf::Vector2f(1.5f, 0.0f), sf::Vector2f(1.5f, -2.0f),
window.get() window.get()
); );
@ -59,9 +51,9 @@ bool Application::init_clcaster() {
// Create a light prototype, send it to the controller, and get the handle back // Create a light prototype, send it to the controller, and get the handle back
LightPrototype prototype( 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::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); light_handle = light_controller->create_light(prototype);

@ -66,12 +66,12 @@ bool CLCaster::init() {
} }
bool CLCaster::assign_map(std::shared_ptr<Old_Map> map) { bool CLCaster::assign_map(std::shared_ptr<Map> map) {
this->map = 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; return false;
if (!create_buffer("map_dimensions", sizeof(int) * 3, &dimensions)) if (!create_buffer("map_dimensions", sizeof(int) * 3, &dimensions))
return false; return false;
@ -92,17 +92,17 @@ bool CLCaster::release_map() {
} }
bool CLCaster::assign_octree(std::shared_ptr<Map> octree) { bool CLCaster::assign_octree(std::shared_ptr<Map> 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; 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; 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; 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 false;
return true; return true;
@ -111,7 +111,7 @@ bool CLCaster::assign_octree(std::shared_ptr<Map> octree) {
bool CLCaster::release_octree() bool CLCaster::release_octree()
{ {
this->octree = nullptr; this->map = nullptr;
if (!release_buffer("octree_descriptor_buffer")) if (!release_buffer("octree_descriptor_buffer"))
return false; return false;

@ -9,13 +9,11 @@
Input::Input() : Input::Input() :
keyboard_flags(sf::Keyboard::Key::KeyCount, false), 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> sf_event_queue) {
break; 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: { case sf::Event::MouseWheelMoved: {
event_queue.emplace_back(std::make_unique<vr::MouseWheelScrolled>(vr::MouseWheelScrolled(sf::Mouse::VerticalWheel, sf_event.mouseWheelScroll.delta, sf_event.mouseWheelScroll.x, sf_event.mouseWheelScroll.y))); event_queue.emplace_back(std::make_unique<vr::MouseWheelScrolled>(vr::MouseWheelScrolled(sf::Mouse::VerticalWheel, sf_event.mouseWheelScroll.delta, sf_event.mouseWheelScroll.x, sf_event.mouseWheelScroll.y)));
break; break;

@ -0,0 +1,147 @@
#include <map/ArrayMap.h>
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<std::tuple<sf::Vector3i, char>> 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<std::tuple<sf::Vector3i, char>> 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<float>(ray_dir.z * sin(-1.57) + ray_dir.x * cos(-1.57)),
static_cast<float>(ray_dir.y),
static_cast<float>(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;
}

@ -2,104 +2,53 @@
#include "Logger.h" #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) if ((int)pow(2, (int)log2(dimensions)) != dimensions)
Logger::log("Map dimensions not an even exponent of 2", Logger::LogLevel::ERROR, __LINE__, __FILE__); 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); sf::Vector3i dim3(dimensions, dimensions, dimensions);
Logger::log("Generating Octree", Logger::LogLevel::INFO); 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); 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__); 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<std::tuple<sf::Vector3i, char>> list1 = CastRayCharArray(voxel_data, &dimensions, &cam_dir, &cam_pos);
//std::vector<std::tuple<sf::Vector3i, char>> 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) { 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){ 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; return octree.GetVoxel(pos).found;
} }
sf::Vector3f Map::LongRayIntersection(sf::Vector3f origin, sf::Vector3f magnitude) {
std::vector<std::tuple<sf::Vector3i, char>> Map::CastRayCharArray( sf::Vector3i voxel(origin);
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<std::tuple<sf::Vector3i, char>> travel_path; std::vector<std::tuple<sf::Vector3i, char>> travel_path;
sf::Vector3f ray_dir(1, 0, 0); sf::Vector3f ray_dir(1, 0, 0);
sf::Vector3i map_dim = array_map.getDimensions();
// Pitch // Pitch
ray_dir = sf::Vector3f( 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.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 // Yaw
ray_dir = sf::Vector3f( ray_dir = sf::Vector3f(
ray_dir.x * cos((*cam_dir).y) - ray_dir.y * sin((*cam_dir).y), ray_dir.x * cos(magnitude.y) - ray_dir.y * sin(magnitude.y),
ray_dir.x * sin((*cam_dir).y) + ray_dir.y * cos((*cam_dir).y), ray_dir.x * sin(magnitude.y) + ray_dir.y * cos(magnitude.y),
ray_dir.z ray_dir.z
); );
@ -131,9 +80,9 @@ std::vector<std::tuple<sf::Vector3i, char>> Map::CastRayCharArray(
// Intersection T is the collection of the next intersection points // Intersection T is the collection of the next intersection points
// for all 3 axis XYZ. // for all 3 axis XYZ.
sf::Vector3f intersection_t( sf::Vector3f intersection_t(
delta_t.x * (cam_pos->x - floor(cam_pos->x)) * voxel_step.x, delta_t.x * (origin.x - floor(origin.x)) * voxel_step.x,
delta_t.y * (cam_pos->y - floor(cam_pos->y)) * voxel_step.y, delta_t.y * (origin.y - floor(origin.y)) * voxel_step.y,
delta_t.z * (cam_pos->z - floor(cam_pos->z)) * voxel_step.z delta_t.z * (origin.z - floor(origin.z)) * voxel_step.z
); );
// for negative values, wrap around the delta_t // for negative values, wrap around the delta_t
@ -161,239 +110,185 @@ std::vector<std::tuple<sf::Vector3i, char>> Map::CastRayCharArray(
voxel.y += voxel_step.y * face_mask.y; voxel.y += voxel_step.y * face_mask.y;
voxel.z += voxel_step.z * face_mask.z; voxel.z += voxel_step.z * face_mask.z;
if (voxel.x >= map_dim->x || voxel.y >= map_dim->y || voxel.z >= map_dim->z) { if (voxel.x >= map_dim.x || voxel.y >= map_dim.y || voxel.z >= map_dim.z) {
return travel_path; return intersection_t;
} }
if (voxel.x < 0 || voxel.y < 0 || voxel.z < 0) { if (voxel.x < 0 || voxel.y < 0 || voxel.z < 0) {
return travel_path; return intersection_t;
} }
// If we hit a voxel // If we hit a voxel
voxel_data = map[voxel.x + (*map_dim).x * (voxel.y + (*map_dim).z * (voxel.z))]; voxel_data = array_map.getDataPtr()[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) if (voxel_data != 0)
return travel_path; return intersection_t;
} while (++dist < 700.0f); } while (++dist < 700.0f);
return travel_path; return intersection_t;
} }
class Octree; std::vector<sf::Vector3i> Map::BoxIntersection(sf::Vector3f origin, sf::Vector3f magnitude) {
return std::vector<sf::Vector3i>();
std::vector<std::tuple<sf::Vector3i, char>> 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<std::tuple<sf::Vector3i, char>> 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<float>(ray_dir.z * sin(-1.57) + ray_dir.x * cos(-1.57)),
static_cast<float>(ray_dir.y),
static_cast<float>(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<float>(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 sf::Vector3f Map::ShortRayIntersection(sf::Vector3f origin, sf::Vector3f magnitude) {
// for all 3 axis XYZ. We take the full positive cardinality when return sf::Vector3f(0,0,0);
// 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 void Map::ApplyHeightmap(sf::Image bitmap) {
// 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 sf::Image Map::GenerateHeightBitmap(sf::Vector3i dimensions) {
do {
// check which direction we step in std::mt19937 gen;
face_mask.x = intersection_t.x <= std::min(intersection_t.y, intersection_t.z); std::uniform_real_distribution<double> dis(-1.0, 1.0);
face_mask.y = intersection_t.y <= std::min(intersection_t.z, intersection_t.x); auto f_rand = std::bind(dis, std::ref(gen));
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 double* height_map = new double[dimensions.x * dimensions.y];
intersection_t.x += delta_t.x * fabs(face_mask.x); for (int i = 0; i < dimensions.x * dimensions.y; i++) {
intersection_t.y += delta_t.y * fabs(face_mask.y); height_map[i] = 0;
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]; //size of grid to generate, note this must be a
uint8_t this_face_mask = 0; //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 the voxel face that we traversed //generate the diamond values
// and increment the idx in the idx stack //since the diamonds are staggered we only move x
if (face_mask.x) { //by half side
this_face_mask = Octree::idx_set_x_mask; //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);
} }
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; sf::Uint8* pixels = new sf::Uint8[dimensions.x * dimensions.z * 4];
int mask_index = traversal_state.idx_stack[traversal_state.scale];
// Check to see if the idx increased or decreased for (int x = 0; x < dimensions.x; x++) {
// If it decreased for (int z = 0; z < dimensions.z; z++) {
// 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; sf::Uint8 height = static_cast<sf::Uint8>(std::min(std::max(height_map[x + z * dimensions.x], 0.0), (double)dimensions.z));
// Keep track of the 0th edge of out current oct pixels[x + z * dimensions.x * 4 + 0] = height;
traversal_state.oct_pos.x = floor(voxel.x / 2) * jump_power; pixels[x + z * dimensions.x * 4 + 1] = height;
traversal_state.oct_pos.y = floor(voxel.x / 2) * jump_power; pixels[x + z * dimensions.x * 4 + 2] = height;
traversal_state.oct_pos.z = floor(voxel.x / 2) * jump_power; pixels[x + z * dimensions.x * 4 + 3] = sf::Uint8(255);
// 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];
} }
sf::Image bitmap_img;
bitmap_img.create(dimensions.x, dimensions.z, pixels);
// Check to see if we are on a valid oct return bitmap_img;
//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
//
//
//
//
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;
}
void Map::SampleSquare(int x, int y, int size, double value, double *height_map) {
int hs = size / 2;
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.x >= map_dim->x || voxel.y >= map_dim->y || voxel.z >= map_dim->z) { SetSample(x, y, ((a + b + c + d) / 4.0) + value, height_map);
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;
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; SetSample(x, y, ((a + b + c + d) / 4.0) + value, height_map);
} }

@ -360,6 +360,221 @@ unsigned int Octree::getDimensions() {
return oct_dimensions; return oct_dimensions;
} }
std::vector<std::tuple<sf::Vector3i, char>> 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<std::tuple<sf::Vector3i, char>> 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<float>(ray_dir.z * sin(-1.57) + ray_dir.x * cos(-1.57)),
static_cast<float>(ray_dir.y),
static_cast<float>(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<float>(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] = { const uint8_t Octree::mask_8[8] = {
0x1, 0x2, 0x4, 0x8, 0x1, 0x2, 0x4, 0x8,
0x10, 0x20, 0x40, 0x80 0x10, 0x20, 0x40, 0x80

@ -1,397 +0,0 @@
#include <iostream>
#include <SFML/System/Vector3.hpp>
#include <SFML/System/Vector2.hpp>
#include "util.hpp"
#include <map/Old_Map.h>
#include <algorithm>
Old_Map::Old_Map(sf::Vector3i dim) {
dimensions = dim;
}
Old_Map::~Old_Map() {
}
void generate_at(int x, int y, std::vector<std::vector<int>> *grid) {
size_t x_bound = grid->size();
size_t y_bound = grid->at(0).size();
// N S E W
std::vector<int> 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<std::vector<int>> generate_maze(sf::Vector2i dimensions, sf::Vector2i start_point) {
std::vector<std::vector<int>> grid(dimensions.x, std::vector<int>(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<double> 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<int>(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<std::vector<int>> 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<double> 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);
}
}
}
Loading…
Cancel
Save