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

This commit is contained in:
MitchellHansen
2017-10-17 23:59:15 -07:00
parent 242aaaa485
commit c35f867c76
14 changed files with 638 additions and 771 deletions

View File

@@ -23,13 +23,14 @@
#include "util.hpp"
#include <SFML/Graphics.hpp>
#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 <chrono>
#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<sf::RenderWindow> window;
std::shared_ptr<Old_Map> map;
std::shared_ptr<Map> octree;
std::shared_ptr<Map> map;
std::shared_ptr<Camera> camera;
std::shared_ptr<CLCaster> raycaster;
std::shared_ptr<LightHandle> light_handle;

View File

@@ -5,7 +5,6 @@
#include <map>
#include <string.h>
#include "LightController.h"
#include "map/Old_Map.h"
#include "Camera.h"
#include <GL/glew.h>
#include <unordered_map>
@@ -115,11 +114,11 @@ public:
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
bool assign_map(std::shared_ptr<Old_Map> map);
bool assign_map(std::shared_ptr<Map> 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<Map> octree);
bool assign_octree(std::shared_ptr<Map> 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> camera;
std::shared_ptr<Old_Map> map;
std::shared_ptr<Map> octree;
std::shared_ptr<Map> map;
std::vector<PackedData> *lights;
int light_count = 0;

View File

@@ -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;

35
include/map/ArrayMap.h Normal file
View File

@@ -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;
};

View File

@@ -7,16 +7,35 @@
#include "util.hpp"
#include "map/Octree.h"
#include <time.h>
#include "map/Old_Map.h"
#include "map/ArrayMap.h"
#define _USE_MATH_DEFINES
#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 {
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<std::tuple<sf::Vector3i, char>> CastRayOctree(
Octree *octree,
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);
std::vector<std::tuple<sf::Vector3i, char>> CastRayCharArray(
char *map,
sf::Vector3i* map_dim,
sf::Vector2f* cam_dir,
sf::Vector3f* cam_pos
);
// Return the voxels that a box intersects / contains
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);
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

View File

@@ -91,6 +91,13 @@ public:
static const uint64_t contour_pointer_mask = 0xFFFFFF00000000;
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:
unsigned int oct_dimensions = 1;

View File

@@ -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);
};

View File

@@ -1,9 +1,7 @@
#include "Application.h"
#include <chrono>
#include "imgui/imgui-SFML.h"
Application::Application() {
//srand(time(nullptr));
window = std::make_shared<sf::RenderWindow>(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<Old_Map>(sf::Vector3i(MAP_X, MAP_Y, MAP_Z));
map->generate_terrain();
map = std::make_shared<Map>(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<Map>(256, map.get());
raycaster->assign_octree(octree);
// Create a new camera with (starting position, direction)
camera = std::make_shared<Camera>(
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);

View File

@@ -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;
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<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;
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<Map> octree) {
bool CLCaster::release_octree()
{
this->octree = nullptr;
this->map = nullptr;
if (!release_buffer("octree_descriptor_buffer"))
return false;

View File

@@ -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> 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>(vr::MouseWheelScrolled(sf::Mouse::VerticalWheel, sf_event.mouseWheelScroll.delta, sf_event.mouseWheelScroll.x, sf_event.mouseWheelScroll.y)));
break;

147
src/map/ArrayMap.cpp Normal file
View File

@@ -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;
}

View File

@@ -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<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) {
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;
}
sf::Vector3f Map::LongRayIntersection(sf::Vector3f origin, sf::Vector3f magnitude) {
std::vector<std::tuple<sf::Vector3i, char>> 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::Vector3i voxel(origin);
std::vector<std::tuple<sf::Vector3i, char>> 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<std::tuple<sf::Vector3i, char>> 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<std::tuple<sf::Vector3i, char>> 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<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
// 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;
std::vector<sf::Vector3i> Map::BoxIntersection(sf::Vector3f origin, sf::Vector3f magnitude) {
return std::vector<sf::Vector3i>();
}
sf::Vector3f Map::ShortRayIntersection(sf::Vector3f origin, sf::Vector3f magnitude) {
return sf::Vector3f(0,0,0);
}
void Map::ApplyHeightmap(sf::Image bitmap) {
}
sf::Image Map::GenerateHeightBitmap(sf::Vector3i dimensions) {
std::mt19937 gen;
std::uniform_real_distribution<double> dis(-1.0, 1.0);
auto f_rand = std::bind(dis, std::ref(gen));
double* height_map = new double[dimensions.x * dimensions.y];
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
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);
}
}
//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);
}
}
}
sf::Uint8* pixels = new sf::Uint8[dimensions.x * dimensions.z * 4];
for (int x = 0; x < dimensions.x; x++) {
for (int z = 0; z < dimensions.z; z++) {
sf::Uint8 height = static_cast<sf::Uint8>(std::min(std::max(height_map[x + z * dimensions.x], 0.0), (double)dimensions.z));
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);
}
}
sf::Image bitmap_img;
bitmap_img.create(dimensions.x, dimensions.z, pixels);
return bitmap_img;
}
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);
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;
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);
SetSample(x, y, ((a + b + c + d) / 4.0) + value, height_map);
}

View File

@@ -360,6 +360,221 @@ unsigned int Octree::getDimensions() {
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] = {
0x1, 0x2, 0x4, 0x8,
0x10, 0x20, 0x40, 0x80

View File

@@ -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);
}
}
}