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:
@@ -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;
|
||||||
|
|||||||
35
include/map/ArrayMap.h
Normal file
35
include/map/ArrayMap.h
Normal 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;
|
||||||
|
|
||||||
|
};
|
||||||
@@ -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,
|
|
||||||
sf::Vector3f* cam_pos
|
|
||||||
);
|
|
||||||
|
|
||||||
std::vector<std::tuple<sf::Vector3i, char>> CastRayCharArray(
|
// Return the voxels that a box intersects / contains
|
||||||
char *map,
|
std::vector<sf::Vector3i> BoxIntersection(sf::Vector3f origin, sf::Vector3f magnitude);
|
||||||
sf::Vector3i* map_dim,
|
|
||||||
sf::Vector2f* cam_dir,
|
// Return a normalized ray opposite of the intersected normals
|
||||||
sf::Vector3f* cam_pos
|
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 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;
|
||||||
|
|||||||
147
src/map/ArrayMap.cpp
Normal file
147
src/map/ArrayMap.cpp
Normal 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;
|
||||||
|
}
|
||||||
445
src/map/Map.cpp
445
src/map/Map.cpp
@@ -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
|
|
||||||
// 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;
|
sf::Vector3f Map::ShortRayIntersection(sf::Vector3f origin, sf::Vector3f magnitude) {
|
||||||
int mask_index = traversal_state.idx_stack[traversal_state.scale];
|
return sf::Vector3f(0,0,0);
|
||||||
|
}
|
||||||
|
|
||||||
// Check to see if the idx increased or decreased
|
void Map::ApplyHeightmap(sf::Image bitmap) {
|
||||||
// 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
|
sf::Image Map::GenerateHeightBitmap(sf::Vector3i dimensions) {
|
||||||
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
|
std::mt19937 gen;
|
||||||
traversal_state.idx_stack[traversal_state.scale] = 0;
|
std::uniform_real_distribution<double> dis(-1.0, 1.0);
|
||||||
traversal_state.scale--;
|
auto f_rand = std::bind(dis, std::ref(gen));
|
||||||
|
|
||||||
// Update the prev_val for our new idx
|
double* height_map = new double[dimensions.x * dimensions.y];
|
||||||
prev_val = traversal_state.idx_stack[traversal_state.scale];
|
for (int i = 0; i < dimensions.x * dimensions.y; i++) {
|
||||||
|
height_map[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Clear and pop the parent stack, maybe off by one error?
|
//size of grid to generate, note this must be a
|
||||||
traversal_state.parent_stack[traversal_state.parent_stack_position] = 0;
|
//value 2^n+1
|
||||||
traversal_state.parent_stack_position--;
|
int DATA_SIZE = dimensions.x + 1;
|
||||||
|
//an initial seed value for the corners of the data
|
||||||
|
//srand(f_rand());
|
||||||
|
double SEED = rand() % 10 + 55;
|
||||||
|
|
||||||
// Set the current CD to the one on top of the stack
|
//seed the data
|
||||||
traversal_state.current_descriptor =
|
SetSample(0, 0, SEED, height_map);
|
||||||
traversal_state.parent_stack[traversal_state.parent_stack_position];
|
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;
|
||||||
|
|
||||||
// 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
|
double Map::Sample(int x, int y, double *height_map) {
|
||||||
//if ((traversal_state.parent_stack[traversal_state.parent_stack_position] >> 16) & Octree::mask_8[mask_index]) {
|
return height_map[(x & (dimensions.x - 1)) + (y & (dimensions.y - 1)) * dimensions.x];
|
||||||
|
|
||||||
// // 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
|
void Map::SetSample(int x, int y, double value, double *height_map) {
|
||||||
//voxel_data = map[voxel.x + (*map_dim).x * (voxel.y + (*map_dim).z * (voxel.z))];
|
height_map[(x & (dimensions.x - 1)) + (y & (dimensions.y - 1)) * dimensions.x] = value;
|
||||||
// voxel_data = getVoxel(voxel);
|
}
|
||||||
travel_path.push_back(std::make_tuple(voxel, voxel_data));
|
|
||||||
|
void Map::SampleSquare(int x, int y, int size, double value, double *height_map) {
|
||||||
if (voxel_data != 0)
|
int hs = size / 2;
|
||||||
return travel_path;
|
|
||||||
|
double a = Sample(x - hs, y - hs, height_map);
|
||||||
|
double b = Sample(x + hs, y - hs, height_map);
|
||||||
} while (++dist < 700.0f);
|
double c = Sample(x - hs, y + hs, height_map);
|
||||||
|
double d = Sample(x + hs, y + hs, height_map);
|
||||||
return travel_path;
|
|
||||||
|
SetSample(x, y, ((a + b + c + d) / 4.0) + value, height_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Map::SampleDiamond(int x, int y, int size, double value, double *height_map) {
|
||||||
|
int hs = size / 2;
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user