1
0
Fork 0

Doc and refactor

This commit is contained in:
May B. 2020-07-25 18:45:03 +02:00
parent 5a0c87cd7a
commit 978334c659
69 changed files with 1297 additions and 1183 deletions

View File

@ -32,7 +32,7 @@ DOXYFILE_ENCODING = UTF-8
# title of most generated pages and in a few other places.
# The default value is: My Project.
PROJECT_NAME = Atomic
PROJECT_NAME = Univerxel
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
# could be handy for archiving the generated documentation or if some version
@ -461,7 +461,7 @@ LOOKUP_CACHE_SIZE = 0
# normally produced when WARNINGS is set to YES.
# The default value is: NO.
EXTRACT_ALL = YES
EXTRACT_ALL = NO
# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
# be included in the documentation.
@ -823,7 +823,7 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT = /home/sheychen/Develop/Current/Atomic/src
INPUT = ../src
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@ -2354,7 +2354,7 @@ UML_LOOK = YES
# Minimum value: 0, maximum value: 100, default value: 10.
# This tag requires that the tag HAVE_DOT is set to YES.
UML_LIMIT_NUM_FIELDS = 10
UML_LIMIT_NUM_FIELDS = 20
# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
# collaboration graphs will show the relations between templates and their
@ -2362,7 +2362,7 @@ UML_LIMIT_NUM_FIELDS = 10
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
TEMPLATE_RELATIONS = YES
TEMPLATE_RELATIONS = NO
# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
# YES then doxygen will generate a graph for each documented file showing the

View File

@ -1,6 +1,6 @@
# Univerxel <!-- omit in toc -->
Work in progress galaxy down to atom (mostly centimeter) Voxel game
Work in progress galaxy down to atom (mostly centimeter) voxel game
## Table of Contents <!-- omit in toc -->
@ -90,7 +90,7 @@ See [Features](TODO.md)
<!-- LICENSE -->
## License
Distributed under the MIT License. See (LICENSE)[LICENSE] for more information.
Distributed under the MIT License. See [LICENSE](LICENSE) for more information.
@ -99,4 +99,4 @@ Distributed under the MIT License. See (LICENSE)[LICENSE] for more information.
Maelys Bois - [/me](https://git.wadza.fr/me) - me@wadza.fr
Project Link: [https://git.wadza.fr/me/atomic](https://git.wadza.fr/me/atomic)
Project Link: [https://git.wadza.fr/me/univerxel](https://git.wadza.fr/me/univerxel)

View File

@ -1,15 +1,17 @@
#pragma once
#include "../data/glm.hpp"
#include "../render/buffer/Buffer.hpp"
#include "../render/buffer/Abstract.hpp"
#include "../data/geometry/Frustum.hpp"
#include "../data/geometry/Faces.hpp"
#include <memory>
#include <toml.h>
#include <robin_hood.h>
class World;
class Chunk;
namespace world {
class Chunk;
}
/// Mesh creation
namespace contouring {
/// Generating mesh from world data
class Abstract {
@ -22,10 +24,10 @@ namespace contouring {
virtual void update(const camera_pos &pos) = 0;
/// Chunk data change
virtual void onUpdate(const chunk_pos &pos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>>& data, Faces neighbors) = 0;
virtual void onUpdate(const chunk_pos &pos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<world::Chunk>>& data, geometry::Faces neighbors) = 0;
/// Chunk existante ping
/// @note notify for chunks entering view while moving
virtual void onNotify(const chunk_pos &pos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &data) = 0;
virtual void onNotify(const chunk_pos &pos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<world::Chunk>> &data) = 0;
/// Display ImGui config
virtual void onGui() = 0;
/// Get options
@ -33,6 +35,6 @@ namespace contouring {
/// Get buffers in frustum with model matrices
/// @note buffers invalidated after update
virtual void getModels(std::vector<std::pair<glm::mat4, Buffer *const>> &buffers, const std::optional<Frustum>& frustum, float scale) = 0;
virtual void getModels(std::vector<std::pair<glm::mat4, buffer::Abstract *const>> &buffers, const std::optional<geometry::Frustum>& frustum, float scale) = 0;
};
}

View File

@ -38,10 +38,10 @@ namespace contouring {
ImGui::SliderInt("Keep Distance", &keepDistance, loadDistance+1, 21);
}
void AbstractFlat::getModels(std::vector<std::pair<glm::mat4, Buffer *const>> &out, const std::optional<Frustum> &frustum, float scale) {
void AbstractFlat::getModels(std::vector<std::pair<glm::mat4, buffer::Abstract *const>> &out, const std::optional<geometry::Frustum> &frustum, float scale) {
const auto scaling = glm::scale(glm::mat4(1), glm::vec3(scale));
for (const auto [pos, buffer] : buffers) {
if (buffer != NULL && (!frustum.has_value() || frustum.value().contains(Box::fromMin(scale * glm::vec3(pos) * glm::vec3(CHUNK_LENGTH), scale * glm::vec3(CHUNK_LENGTH)))))
if (buffer != NULL && (!frustum.has_value() || frustum.value().contains(geometry::Box::fromMin(scale * glm::vec3(pos) * glm::vec3(CHUNK_LENGTH), scale * glm::vec3(CHUNK_LENGTH)))))
out.push_back({glm::translate(scaling, glm::vec3(pos) * glm::vec3(CHUNK_LENGTH)), buffer});
}
}

View File

@ -2,8 +2,6 @@
#include "Abstract.hpp"
class World;
class Chunk;
namespace contouring {
/// Generating mesh for chunks 1:1
class AbstractFlat: public Abstract {
@ -21,7 +19,7 @@ namespace contouring {
/// Get buffers in frustum with model matrices
/// @note buffers invalidated after update
void getModels(std::vector<std::pair<glm::mat4, Buffer *const>> &out, const std::optional<Frustum> &frustum, float scale) override;
void getModels(std::vector<std::pair<glm::mat4, buffer::Abstract *const>> &out, const std::optional<geometry::Frustum> &frustum, float scale) override;
protected:
bool inline inLoadRange(const chunk_pos& point) const {
@ -31,7 +29,7 @@ namespace contouring {
return glm::length2(center - point) <= keepDistance * keepDistance;
}
robin_hood::unordered_map<chunk_pos, Buffer *> buffers;
robin_hood::unordered_map<chunk_pos, buffer::Abstract *> buffers;
chunk_pos center = chunk_pos(INT_MAX);
int loadDistance = 3;

View File

@ -2,8 +2,6 @@
#include "Abstract.hpp"
class World;
class Chunk;
namespace contouring {
/// Useless contouring
class Dummy: public Abstract {
@ -12,10 +10,10 @@ namespace contouring {
virtual ~Dummy() { }
void update(const camera_pos &) override { }
void onUpdate(const chunk_pos &, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &, Faces) override {}
void onNotify(const chunk_pos &, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &) override { }
void onUpdate(const chunk_pos &, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<world::Chunk>> &, geometry::Faces) override {}
void onNotify(const chunk_pos &, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<world::Chunk>> &) override { }
void onGui() override { }
std::string getOptions() override { return ""; }
void getModels(std::vector<std::pair<glm::mat4, Buffer *const>> &, const std::optional<Frustum>&, float) override { }
void getModels(std::vector<std::pair<glm::mat4, buffer::Abstract *const>> &, const std::optional<geometry::Frustum>&, float) override { }
};
}

View File

@ -19,7 +19,7 @@ namespace contouring {
loadQueue.wait();
if (loadQueue.pop(ctx)) {
rmt_ScopedCPUSample(ProcessContouring, 0);
ShortIndexedBuffer::Data data;
buffer::ShortIndexed::Data data;
render(ctx.second, data);
loadedQueue.push({ctx.first, data});
}
@ -48,7 +48,7 @@ namespace contouring {
return ss.str();
}
void FlatDualMC::enqueue(const chunk_pos &pos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &data) {
void FlatDualMC::enqueue(const chunk_pos &pos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<world::Chunk>> &data) {
rmt_ScopedCPUSample(EnqueueContouring, RMTSF_Aggregate);
const auto dist2 = glm::length2(pos - center);
if (dist2 <= loadDistance * loadDistance) {
@ -59,16 +59,16 @@ namespace contouring {
}
}
void FlatDualMC::onUpdate(const chunk_pos &pos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &data, Faces neighbors) {
void FlatDualMC::onUpdate(const chunk_pos &pos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<world::Chunk>> &data, geometry::Faces neighbors) {
enqueue(pos, data);
if (neighbors && (Faces::Left | Faces::Down | Faces::Backward)) {
if (neighbors && (geometry::Faces::Left | geometry::Faces::Down | geometry::Faces::Backward)) {
for (size_t i = 1; i < 8; i++) {
enqueue(pos - surrounding::g_corner_offsets[i], data);
}
}
}
void FlatDualMC::onNotify(const chunk_pos &pos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &data) {
void FlatDualMC::onNotify(const chunk_pos &pos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<world::Chunk>> &data) {
if (buffers.find(pos) == buffers.end()) {
enqueue(pos, data);
}
@ -76,12 +76,12 @@ namespace contouring {
void FlatDualMC::update(const camera_pos& pos) {
AbstractFlat::update(pos);
std::pair<chunk_pos, ShortIndexedBuffer::Data> out;
std::pair<chunk_pos, buffer::ShortIndexed::Data> out;
reports.load.push(loadQueue.size());
//MAYBE: clear out of range loadQueue.trim(keepDistance * keepDistance)
reports.loaded.push(loadedQueue.size());
while(loadedQueue.pop(out)) {
const auto buffer = new ShortIndexedBuffer(GL_TRIANGLES, out.second);
const auto buffer = new buffer::ShortIndexed(GL_TRIANGLES, out.second);
const auto it = buffers.find(out.first);
if (it != buffers.end()) {
if(it->second != NULL)
@ -106,7 +106,7 @@ namespace contouring {
ImGui::Checkbox("Manifold", &manifold);
}
void FlatDualMC::render(const surrounding::corners &surrounding, ShortIndexedBuffer::Data &out) const {
void FlatDualMC::render(const surrounding::corners &surrounding, buffer::ShortIndexed::Data &out) const {
const int SIZE = CHUNK_LENGTH + 3;
std::vector<dualmc::DualMC<float>::Point> grid;
grid.reserve(SIZE * SIZE * SIZE);
@ -116,7 +116,7 @@ namespace contouring {
for (int x = 0; x < SIZE; x++) {
const auto chunk = surrounding[(z >= CHUNK_LENGTH) + (y >= CHUNK_LENGTH)*2 + (x >= CHUNK_LENGTH)*4];
// MAYBE: area copy
const auto voxel = chunk->get(Chunk::getIdx(x % CHUNK_LENGTH, y % CHUNK_LENGTH, z % CHUNK_LENGTH));
const auto voxel = chunk->getAt(chunk_voxel_pos(x % CHUNK_LENGTH, y % CHUNK_LENGTH, z % CHUNK_LENGTH));
grid.push_back({voxel.Density * 1.f / UCHAR_MAX, voxel.Material});
}}}
}
@ -125,7 +125,7 @@ namespace contouring {
std::vector<dualmc::Tri> dmc_tris;
dualmc::DualMC<float> builder;
builder.buildTris(&grid.front(), SIZE, SIZE, SIZE, iso, materials::roughness.cbegin(), manifold, dmc_vertices, dmc_tris);
builder.buildTris(&grid.front(), SIZE, SIZE, SIZE, iso, world::materials::roughness.cbegin(), manifold, dmc_vertices, dmc_tris);
out.vertices.reserve(dmc_vertices.size());
out.materials.reserve(dmc_vertices.size());

View File

@ -6,12 +6,14 @@
#include "../data/safe_queue.hpp"
#include "../data/safe_priority_queue.hpp"
#include "../data/circular_buffer.hpp"
#include "../render/buffer/ShortIndexedBuffer.hpp"
#include "../render/buffer/ShortIndexed.hpp"
#include <thread>
#define REPORT_BUFFER_SIZE 128
using namespace data;
namespace contouring {
/// Dual Marching Cube 1:1 contouring
class FlatDualMC: public AbstractFlat {
public:
FlatDualMC(const std::string&);
@ -24,14 +26,14 @@ namespace contouring {
std::string getOptions() override;
/// Chunk data change
void onUpdate(const chunk_pos &, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &, Faces) override;
void onUpdate(const chunk_pos &, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<world::Chunk>> &, geometry::Faces) override;
/// Chunk existante ping
/// @note notify for chunks entering view while moving
void onNotify(const chunk_pos &, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &) override;
void onNotify(const chunk_pos &, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<world::Chunk>> &) override;
protected:
safe_priority_queue_map<chunk_pos, surrounding::corners, int> loadQueue;
safe_queue<std::pair<chunk_pos, ShortIndexedBuffer::Data>> loadedQueue;
safe_queue<std::pair<chunk_pos, buffer::ShortIndexed::Data>> loadedQueue;
struct report {
circular_buffer<float> count = circular_buffer<float>(REPORT_BUFFER_SIZE, 0); // MAYBE: store int
@ -42,11 +44,11 @@ namespace contouring {
bool running = true;
std::vector<std::thread> workers;
void enqueue(const chunk_pos &, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &);
void enqueue(const chunk_pos &, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<world::Chunk>> &);
float iso = .1f;
bool manifold = true;
void render(const surrounding::corners &surrounding, ShortIndexedBuffer::Data& out) const;
void render(const surrounding::corners &surrounding, buffer::ShortIndexed::Data& out) const;
};
}

View File

@ -5,6 +5,7 @@
#include <Remotery.h>
#include <imgui.h>
using namespace geometry;
namespace contouring {
FlatSurroundingBox::FlatSurroundingBox(const std::string &opt) : AbstractFlat(opt) {
for (size_t i = 1; i <= 4; i++) {
@ -14,11 +15,11 @@ namespace contouring {
loadQueue.wait();
if (loadQueue.pop(ctx)) {
rmt_ScopedCPUSample(ProcessContouring, 0);
std::vector<VertexData> vertices;
std::vector<buffer::VertexData> vertices;
render(ctx.second, vertices);
{
rmt_ScopedCPUSample(Index, 0);
loadedQueue.push({ctx.first, ShortIndexedBuffer::Data(vertices)});
loadedQueue.push({ctx.first, buffer::ShortIndexed::Data(vertices)});
}
}
}
@ -35,7 +36,7 @@ namespace contouring {
}
}
void FlatSurroundingBox::enqueue(const chunk_pos &pos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &data) {
void FlatSurroundingBox::enqueue(const chunk_pos &pos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<world::Chunk>> &data) {
rmt_ScopedCPUSample(EnqueueContouring, RMTSF_Aggregate);
const auto dist2 = glm::length2(pos - center);
if (dist2 <= loadDistance * loadDistance) {
@ -46,7 +47,7 @@ namespace contouring {
}
}
void FlatSurroundingBox::onUpdate(const chunk_pos &pos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &data, Faces neighbors) {
void FlatSurroundingBox::onUpdate(const chunk_pos &pos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<world::Chunk>> &data, Faces neighbors) {
enqueue(pos, data);
if (neighbors && Faces::Right)
enqueue(pos + g_face_offsets[static_cast<int>(Face::Right)], data);
@ -67,7 +68,7 @@ namespace contouring {
enqueue(pos + g_face_offsets[static_cast<int>(Face::Backward)], data);
}
void FlatSurroundingBox::onNotify(const chunk_pos &pos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &data) {
void FlatSurroundingBox::onNotify(const chunk_pos &pos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<world::Chunk>> &data) {
if (buffers.find(pos) == buffers.end()) {
enqueue(pos, data);
}
@ -75,12 +76,12 @@ namespace contouring {
void FlatSurroundingBox::update(const camera_pos& pos) {
AbstractFlat::update(pos);
std::pair<chunk_pos, ShortIndexedBuffer::Data> out;
std::pair<chunk_pos, buffer::ShortIndexed::Data> out;
reports.load.push(loadQueue.size());
//MAYBE: clear out of range loadQueue.trim(keepDistance * keepDistance)
reports.loaded.push(loadedQueue.size());
while(loadedQueue.pop(out)) {
const auto buffer = new ShortIndexedBuffer(GL_TRIANGLES, out.second);
const auto buffer = new buffer::ShortIndexed(GL_TRIANGLES, out.second);
const auto it = buffers.find(out.first);
if (it != buffers.end()) {
if(it->second != NULL)
@ -103,22 +104,22 @@ namespace contouring {
}
bool FlatSurroundingBox::isTransparent(const surrounding::faces &surrounding, const std::pair<ushort, ushort> &idx) {
return surrounding[idx.first]->begin()[idx.second].Density < UCHAR_MAX; // MAYBE: materials::transparent
return surrounding[idx.first]->get(idx.second).Density < UCHAR_MAX; // MAYBE: materials::transparent
}
void FlatSurroundingBox::render(const surrounding::faces &surrounding, std::vector<VertexData> &vertices) {
const auto voxels = surrounding[surrounding::CENTER]->begin();
void FlatSurroundingBox::render(const surrounding::faces &surrounding, std::vector<buffer::VertexData> &vertices) {
const auto center = surrounding[surrounding::CENTER];
vertices.clear();
for (ushort i = 0; i < CHUNK_SIZE; i++) {
if (voxels[i].Density > 0) {
Faces faces = voxels[i].Density < UCHAR_MAX ? Faces::All :
if (center->get(i).Density > 0) {
Faces faces = center->get(i).Density < UCHAR_MAX ? Faces::All :
(isTransparent(surrounding, surrounding::getNeighborIdx(i, Face::Right)) & Faces::Right) |
(isTransparent(surrounding, surrounding::getNeighborIdx(i, Face::Left)) & Faces::Left) |
(isTransparent(surrounding, surrounding::getNeighborIdx(i, Face::Up)) & Faces::Up) |
(isTransparent(surrounding, surrounding::getNeighborIdx(i, Face::Down)) & Faces::Down) |
(isTransparent(surrounding, surrounding::getNeighborIdx(i, Face::Forward)) & Faces::Forward) |
(isTransparent(surrounding, surrounding::getNeighborIdx(i, Face::Backward)) & Faces::Backward);
box::addCube(vertices, Chunk::getPosition(i), voxels[i].Material, faces, glm::vec3(voxels[i].Density * 1.f / UCHAR_MAX));
box::addCube(vertices, world::Chunk::getPosition(i), center->get(i).Material, faces, glm::vec3(center->get(i).Density * 1.f / UCHAR_MAX));
}
}
}

View File

@ -6,12 +6,14 @@
#include "../data/safe_queue.hpp"
#include "../data/safe_priority_queue.hpp"
#include "../data/circular_buffer.hpp"
#include "../render/buffer/ShortIndexedBuffer.hpp"
#include "../render/buffer/ShortIndexed.hpp"
#include <thread>
#define REPORT_BUFFER_SIZE 128
using namespace data;
namespace contouring {
/// Stupid cubes 1:1 contouring
class FlatSurroundingBox: public AbstractFlat {
public:
FlatSurroundingBox(const std::string&);
@ -22,14 +24,14 @@ namespace contouring {
void onGui() override;
/// Chunk data change
void onUpdate(const chunk_pos &, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &, Faces) override;
void onUpdate(const chunk_pos &, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<world::Chunk>> &, geometry::Faces) override;
/// Chunk existante ping
/// @note notify for chunks entering view while moving
void onNotify(const chunk_pos &, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &) override;
void onNotify(const chunk_pos &, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<world::Chunk>> &) override;
protected:
safe_priority_queue_map<chunk_pos, surrounding::faces, int> loadQueue;
safe_queue<std::pair<chunk_pos, ShortIndexedBuffer::Data>> loadedQueue;
safe_queue<std::pair<chunk_pos, buffer::ShortIndexed::Data>> loadedQueue;
struct report {
circular_buffer<float> count = circular_buffer<float>(REPORT_BUFFER_SIZE, 0); // MAYBE: store int
@ -40,10 +42,10 @@ namespace contouring {
bool running = true;
std::vector<std::thread> workers;
void enqueue(const chunk_pos &, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &);
void enqueue(const chunk_pos &, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<world::Chunk>> &);
private:
static inline bool isTransparent(const surrounding::faces &surrounding, const std::pair<ushort, ushort> &idx);
static void render(const surrounding::faces &surrounding, std::vector<VertexData> &vertices);
static void render(const surrounding::faces &surrounding, std::vector<buffer::VertexData> &vertices);
};
}
} // namespace contouring

View File

@ -5,6 +5,7 @@
#include "../data/geometry/Faces.hpp"
#include "../render/buffer/VertexData.hpp"
using namespace geometry;
namespace contouring::box {
static const auto BOX_FACES = 6;
@ -24,13 +25,13 @@ namespace contouring::box {
glm::rotate<float>(glm::mat4(1), glm::half_pi<float>(), glm::vec3(0, 1, 0)),
};
static void addQuad(std::vector<VertexData> & out, glm::vec3 position, ushort material, Face face, glm::vec3 size) {
static void addQuad(std::vector<buffer::VertexData> & out, glm::vec3 position, ushort material, Face face, glm::vec3 size) {
for (auto vertex : g_quad_vertices) {
out.push_back(VertexData{glm::vec3(g_cube_rotate[static_cast<int>(face)] * glm::vec4(vertex, 1)) * size + position, material, g_cube_normals[static_cast<int>(face)]});
out.push_back(buffer::VertexData{glm::vec3(g_cube_rotate[static_cast<int>(face)] * glm::vec4(vertex, 1)) * size + position, material, g_cube_normals[static_cast<int>(face)]});
}
}
static void addCube(std::vector<VertexData>& out, glm::vec3 position, uint material, Faces faces = Faces::All, glm::vec3 size = glm::vec3(1)) {
static void addCube(std::vector<buffer::VertexData>& out, glm::vec3 position, uint material, Faces faces = Faces::All, glm::vec3 size = glm::vec3(1)) {
if (faces && Faces::Right)
addQuad(out, position, material, Face::Right, size);

View File

@ -2,8 +2,9 @@
#include "../world/Chunk.hpp"
using namespace geometry;
namespace contouring::surrounding {
bool load(faces &out, const chunk_pos &chunkPos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &chunks) {
bool load(faces &out, const chunk_pos &chunkPos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<world::Chunk>> &chunks) {
{
const auto it = chunks.find(chunkPos);
if (it == chunks.end())
@ -58,7 +59,7 @@ namespace contouring::surrounding {
}
}
bool load(corners &out, const chunk_pos &chunkPos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &chunks) {
bool load(corners &out, const chunk_pos &chunkPos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<world::Chunk>> &chunks) {
for (size_t i = 0; i < 8; i++) {
const auto it = chunks.find(chunkPos + g_corner_offsets[i]);
if (it == chunks.end())

View File

@ -4,16 +4,18 @@
#include <memory>
#include <robin_hood.h>
class Chunk;
namespace world {
class Chunk;
}
namespace contouring::surrounding {
const auto CENTER = 6;
typedef std::array<std::shared_ptr<const Chunk>, CENTER+1> faces;
typedef std::array<std::shared_ptr<const world::Chunk>, CENTER+1> faces;
bool load(faces &out, const chunk_pos &chunkPos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &chunks);
bool load(faces &out, const chunk_pos &chunkPos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<world::Chunk>> &chunks);
std::pair<ushort, ushort> getNeighborIdx(ushort idx, Face face);
std::pair<ushort, ushort> getNeighborIdx(ushort idx, geometry::Face face);
typedef std::array<std::shared_ptr<const Chunk>, 8> corners;
typedef std::array<std::shared_ptr<const world::Chunk>, 8> corners;
const glm::ivec3 g_corner_offsets[8] = {
glm::ivec3(0, 0, 0),
glm::ivec3(0, 0, 1),
@ -25,5 +27,5 @@ namespace contouring::surrounding {
glm::ivec3(1, 1, 1),
};
bool load(corners &out, const chunk_pos &chunkPos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> &chunks);
bool load(corners &out, const chunk_pos &chunkPos, const robin_hood::unordered_map<chunk_pos, std::shared_ptr<world::Chunk>> &chunks);
}

View File

@ -34,8 +34,8 @@ public:
}
glm::vec3 getDirection() const { return glm::vec3(cos(VerticalAngle) * sin(HorizontalAngle), sin(VerticalAngle), cos(VerticalAngle) * cos(HorizontalAngle)); }
inline Frustum getFrustum() const { return Frustum(ViewMatrix, ProjectionMatrix); }
inline Ray getRay() const { return Ray(Position, getDirection(), o.far); }
inline geometry::Frustum getFrustum() const { return geometry::Frustum(ViewMatrix, ProjectionMatrix); }
inline geometry::Ray getRay() const { return geometry::Ray(Position, getDirection(), o.far); }
glm::mat4 getViewMatrix() const { return ViewMatrix; }
glm::mat4 getProjectionMatrix() const { return ProjectionMatrix; }

View File

@ -1,25 +1,28 @@
#pragma once
#include <memory>
/// Looping array
template <class T>
struct circular_buffer {
circular_buffer(size_t size): size(size), buffer(std::unique_ptr<T[]>(new T[size])) { }
circular_buffer(size_t size, const T& zero): circular_buffer(size) {
for (size_t i = 0; i < size; i++) {
buffer[i] = zero;
/// Generic containers
namespace data {
/// Looping array
template <class T>
struct circular_buffer {
circular_buffer(size_t size): size(size), buffer(std::unique_ptr<T[]>(new T[size])) { }
circular_buffer(size_t size, const T& zero): circular_buffer(size) {
for (size_t i = 0; i < size; i++) {
buffer[i] = zero;
}
}
}
size_t last = 0;
size_t size;
std::unique_ptr<T[]> buffer;
size_t last = 0;
size_t size;
std::unique_ptr<T[]> buffer;
void push(T in) {
last = (last + 1) % size;
buffer[last] = in;
}
T current() const {
return buffer[last];
}
};
void push(T in) {
last = (last + 1) % size;
buffer[last] = in;
}
T current() const {
return buffer[last];
}
};
}

View File

@ -3,40 +3,42 @@
#include <glm/glm.hpp>
#include <iostream>
/// Axis Aligned Floating Box
struct Box {
enum class ContainmentType {
Disjoint = false, Intersects, Contains
namespace geometry {
/// Axis Aligned Floating Box
struct Box {
enum class ContainmentType {
Disjoint = false, Intersects, Contains
};
Box(glm::vec3 min, glm::vec3 max): Min(min), Max(max) {
assert(("Min > Max", max.x >= min.x && max.y >= min.y && max.z >= min.z));
}
inline static Box fromCenter(glm::vec3 center, float radius) { return Box(center - radius, center + radius); }
inline static Box fromMin(glm::vec3 min, glm::vec3 size) { return Box(min, min + size); }
glm::vec3 Min;
glm::vec3 Max;
ContainmentType contains(const Box& box) const {
//test if all corner is in the same side of a face by just checking min and max
if (box.Max.x < Min.x
|| box.Min.x > Max.x
|| box.Max.y < Min.y
|| box.Min.y > Max.y
|| box.Max.z < Min.z
|| box.Min.z > Max.z)
return ContainmentType::Disjoint;
if (box.Min.x >= Min.x
&& box.Max.x <= Max.x
&& box.Min.y >= Min.y
&& box.Max.y <= Max.y
&& box.Min.z >= Min.z
&& box.Max.z <= Max.z)
return ContainmentType::Contains;
return ContainmentType::Intersects;
}
};
Box(glm::vec3 min, glm::vec3 max): Min(min), Max(max) {
assert(("Min > Max", max.x >= min.x && max.y >= min.y && max.z >= min.z));
}
inline static Box fromCenter(glm::vec3 center, float radius) { return Box(center - radius, center + radius); }
inline static Box fromMin(glm::vec3 min, glm::vec3 size) { return Box(min, min + size); }
glm::vec3 Min;
glm::vec3 Max;
ContainmentType contains(const Box& box) const {
//test if all corner is in the same side of a face by just checking min and max
if (box.Max.x < Min.x
|| box.Min.x > Max.x
|| box.Max.y < Min.y
|| box.Min.y > Max.y
|| box.Max.z < Min.z
|| box.Min.z > Max.z)
return ContainmentType::Disjoint;
if (box.Min.x >= Min.x
&& box.Max.x <= Max.x
&& box.Min.y >= Min.y
&& box.Max.y <= Max.y
&& box.Min.z >= Min.z
&& box.Max.z <= Max.z)
return ContainmentType::Contains;
return ContainmentType::Intersects;
}
};
}

View File

@ -2,34 +2,37 @@
#include "../glm.hpp"
enum class Face {
Right, Left, Up, Down, Forward, Backward
};
const glm::ivec3 g_face_offsets[6] = {
glm::ivec3(1,0,0), glm::ivec3(-1,0,0),
glm::ivec3(0,1,0), glm::ivec3(0,-1,0),
glm::ivec3(0,0,1), glm::ivec3(0,0,-1),
};
/// Math utils
namespace geometry {
enum class Face {
Right, Left, Up, Down, Forward, Backward
};
const glm::ivec3 g_face_offsets[6] = {
glm::ivec3(1,0,0), glm::ivec3(-1,0,0),
glm::ivec3(0,1,0), glm::ivec3(0,-1,0),
glm::ivec3(0,0,1), glm::ivec3(0,0,-1),
};
enum class Faces {
None = 0,
Right = 1,
Left = 2,
Up = 4,
Down = 8,
Forward = 16,
Backward = 32,
All = 63
};
inline Faces operator|(Faces a, Faces b) {
return static_cast<Faces>(static_cast<int>(a) | static_cast<int>(b));
}
inline Faces operator&(Faces a, Faces b) {
return static_cast<Faces>(static_cast<int>(a) & static_cast<int>(b));
}
inline Faces operator&(bool a, Faces b) {
return (a ? Faces::All : Faces::None) & b;
}
inline bool operator&&(Faces a, Faces b) {
return static_cast<int>(a) & static_cast<int>(b);
enum class Faces {
None = 0,
Right = 1,
Left = 2,
Up = 4,
Down = 8,
Forward = 16,
Backward = 32,
All = 63
};
inline Faces operator|(Faces a, Faces b) {
return static_cast<Faces>(static_cast<int>(a) | static_cast<int>(b));
}
inline Faces operator&(Faces a, Faces b) {
return static_cast<Faces>(static_cast<int>(a) & static_cast<int>(b));
}
inline Faces operator&(bool a, Faces b) {
return (a ? Faces::All : Faces::None) & b;
}
inline bool operator&&(Faces a, Faces b) {
return static_cast<int>(a) & static_cast<int>(b);
}
}

View File

@ -2,82 +2,84 @@
#include "Box.hpp"
/// Bounding frustum
struct Frustum {
glm::vec4 planes[6];
namespace geometry {
/// Bounding frustum
struct Frustum {
glm::vec4 planes[6];
enum FrustumSide
{
RIGHT = 0, // The RIGHT side of the frustum
LEFT = 1, // The LEFT side of the frustum
BOTTOM = 2, // The BOTTOM side of the frustum
TOP = 3, // The TOP side of the frustum
BACK = 4, // The BACK side of the frustum
FRONT = 5 // The FRONT side of the frustum
};
enum FrustumSide
{
RIGHT = 0, // The RIGHT side of the frustum
LEFT = 1, // The LEFT side of the frustum
BOTTOM = 2, // The BOTTOM side of the frustum
TOP = 3, // The TOP side of the frustum
BACK = 4, // The BACK side of the frustum
FRONT = 5 // The FRONT side of the frustum
};
void normalize(glm::vec4 &plane) {
plane /= (float)sqrt(plane.x * plane.x + plane.y * plane.y + plane.z * plane.z);
}
Frustum(const glm::mat4& view_matrix, const glm::mat4& proj_matrix) {
const float *proj = &proj_matrix[0][0];
const float *modl = &view_matrix[0][0];
float clip[16]; //clipping planes
clip[0] = modl[0] * proj[0] + modl[1] * proj[4] + modl[2] * proj[8] + modl[3] * proj[12];
clip[1] = modl[0] * proj[1] + modl[1] * proj[5] + modl[2] * proj[9] + modl[3] * proj[13];
clip[2] = modl[0] * proj[2] + modl[1] * proj[6] + modl[2] * proj[10] + modl[3] * proj[14];
clip[3] = modl[0] * proj[3] + modl[1] * proj[7] + modl[2] * proj[11] + modl[3] * proj[15];
clip[4] = modl[4] * proj[0] + modl[5] * proj[4] + modl[6] * proj[8] + modl[7] * proj[12];
clip[5] = modl[4] * proj[1] + modl[5] * proj[5] + modl[6] * proj[9] + modl[7] * proj[13];
clip[6] = modl[4] * proj[2] + modl[5] * proj[6] + modl[6] * proj[10] + modl[7] * proj[14];
clip[7] = modl[4] * proj[3] + modl[5] * proj[7] + modl[6] * proj[11] + modl[7] * proj[15];
clip[8] = modl[8] * proj[0] + modl[9] * proj[4] + modl[10] * proj[8] + modl[11] * proj[12];
clip[9] = modl[8] * proj[1] + modl[9] * proj[5] + modl[10] * proj[9] + modl[11] * proj[13];
clip[10] = modl[8] * proj[2] + modl[9] * proj[6] + modl[10] * proj[10] + modl[11] * proj[14];
clip[11] = modl[8] * proj[3] + modl[9] * proj[7] + modl[10] * proj[11] + modl[11] * proj[15];
clip[12] = modl[12] * proj[0] + modl[13] * proj[4] + modl[14] * proj[8] + modl[15] * proj[12];
clip[13] = modl[12] * proj[1] + modl[13] * proj[5] + modl[14] * proj[9] + modl[15] * proj[13];
clip[14] = modl[12] * proj[2] + modl[13] * proj[6] + modl[14] * proj[10] + modl[15] * proj[14];
clip[15] = modl[12] * proj[3] + modl[13] * proj[7] + modl[14] * proj[11] + modl[15] * proj[15];
planes[RIGHT] = glm::vec4(clip[3] - clip[0], clip[7] - clip[4], clip[11] - clip[8], clip[15] - clip[12]);
normalize(planes[RIGHT]);
planes[LEFT] = glm::vec4(clip[3] + clip[0], clip[7] + clip[4], clip[11] + clip[8], clip[15] + clip[12]);
normalize(planes[LEFT]);
planes[BOTTOM] = glm::vec4(clip[3] + clip[1], clip[7] + clip[5], clip[11] + clip[9], clip[15] + clip[13]);
normalize(planes[BOTTOM]);
planes[TOP] = glm::vec4(clip[3] - clip[1], clip[7] - clip[5], clip[11] - clip[9], clip[15] - clip[13]);
normalize(planes[TOP]);
planes[BACK] = glm::vec4(clip[3] - clip[2], clip[7] - clip[6], clip[11] - clip[10], clip[15] - clip[14]);
normalize(planes[BACK]);
planes[FRONT] = glm::vec4(clip[3] + clip[2], clip[7] + clip[6], clip[11] + clip[10], clip[15] + clip[14]);
normalize(planes[FRONT]);
}
/// Check if box is contained
inline bool contains(const Box &box) const {
bool inside = true;
//test all 6 frustum planes
for (int i = 0; i<6; i++) {
//pick closest point to plane and check if it behind the plane
//if yes - object outside frustum
float d = std::max(box.Min.x * planes[i].x, box.Max.x * planes[i].x)
+ std::max(box.Min.y * planes[i].y, box.Max.y * planes[i].y)
+ std::max(box.Min.z * planes[i].z, box.Max.z * planes[i].z)
+ planes[i].w;
inside &= d > 0;
//return false; //with flag works faster
void normalize(glm::vec4 &plane) {
plane /= (float)sqrt(plane.x * plane.x + plane.y * plane.y + plane.z * plane.z);
}
return inside;
}
};
Frustum(const glm::mat4& view_matrix, const glm::mat4& proj_matrix) {
const float *proj = &proj_matrix[0][0];
const float *modl = &view_matrix[0][0];
float clip[16]; //clipping planes
clip[0] = modl[0] * proj[0] + modl[1] * proj[4] + modl[2] * proj[8] + modl[3] * proj[12];
clip[1] = modl[0] * proj[1] + modl[1] * proj[5] + modl[2] * proj[9] + modl[3] * proj[13];
clip[2] = modl[0] * proj[2] + modl[1] * proj[6] + modl[2] * proj[10] + modl[3] * proj[14];
clip[3] = modl[0] * proj[3] + modl[1] * proj[7] + modl[2] * proj[11] + modl[3] * proj[15];
clip[4] = modl[4] * proj[0] + modl[5] * proj[4] + modl[6] * proj[8] + modl[7] * proj[12];
clip[5] = modl[4] * proj[1] + modl[5] * proj[5] + modl[6] * proj[9] + modl[7] * proj[13];
clip[6] = modl[4] * proj[2] + modl[5] * proj[6] + modl[6] * proj[10] + modl[7] * proj[14];
clip[7] = modl[4] * proj[3] + modl[5] * proj[7] + modl[6] * proj[11] + modl[7] * proj[15];
clip[8] = modl[8] * proj[0] + modl[9] * proj[4] + modl[10] * proj[8] + modl[11] * proj[12];
clip[9] = modl[8] * proj[1] + modl[9] * proj[5] + modl[10] * proj[9] + modl[11] * proj[13];
clip[10] = modl[8] * proj[2] + modl[9] * proj[6] + modl[10] * proj[10] + modl[11] * proj[14];
clip[11] = modl[8] * proj[3] + modl[9] * proj[7] + modl[10] * proj[11] + modl[11] * proj[15];
clip[12] = modl[12] * proj[0] + modl[13] * proj[4] + modl[14] * proj[8] + modl[15] * proj[12];
clip[13] = modl[12] * proj[1] + modl[13] * proj[5] + modl[14] * proj[9] + modl[15] * proj[13];
clip[14] = modl[12] * proj[2] + modl[13] * proj[6] + modl[14] * proj[10] + modl[15] * proj[14];
clip[15] = modl[12] * proj[3] + modl[13] * proj[7] + modl[14] * proj[11] + modl[15] * proj[15];
planes[RIGHT] = glm::vec4(clip[3] - clip[0], clip[7] - clip[4], clip[11] - clip[8], clip[15] - clip[12]);
normalize(planes[RIGHT]);
planes[LEFT] = glm::vec4(clip[3] + clip[0], clip[7] + clip[4], clip[11] + clip[8], clip[15] + clip[12]);
normalize(planes[LEFT]);
planes[BOTTOM] = glm::vec4(clip[3] + clip[1], clip[7] + clip[5], clip[11] + clip[9], clip[15] + clip[13]);
normalize(planes[BOTTOM]);
planes[TOP] = glm::vec4(clip[3] - clip[1], clip[7] - clip[5], clip[11] - clip[9], clip[15] - clip[13]);
normalize(planes[TOP]);
planes[BACK] = glm::vec4(clip[3] - clip[2], clip[7] - clip[6], clip[11] - clip[10], clip[15] - clip[14]);
normalize(planes[BACK]);
planes[FRONT] = glm::vec4(clip[3] + clip[2], clip[7] + clip[6], clip[11] + clip[10], clip[15] + clip[14]);
normalize(planes[FRONT]);
}
/// Check if box is contained
inline bool contains(const Box &box) const {
bool inside = true;
//test all 6 frustum planes
for (int i = 0; i<6; i++) {
//pick closest point to plane and check if it behind the plane
//if yes - object outside frustum
float d = std::max(box.Min.x * planes[i].x, box.Max.x * planes[i].x)
+ std::max(box.Min.y * planes[i].y, box.Max.y * planes[i].y)
+ std::max(box.Min.z * planes[i].z, box.Max.z * planes[i].z)
+ planes[i].w;
inside &= d > 0;
//return false; //with flag works faster
}
return inside;
}
};
}

View File

@ -3,83 +3,85 @@
#include "Box.hpp"
#include "../glm.hpp"
/// Raycast with distance
struct Ray {
glm::vec3 from;
glm::vec3 dir;
float dist;
namespace geometry {
/// Raycast with distance
struct Ray {
glm::vec3 from;
glm::vec3 dir;
float dist;
// MAYBE: Ray(const glm::mat4& view_matrix) { }
Ray(const glm::vec3& from, const glm::vec3& dir, float dist): from(from), dir(glm::normalize(dir)), dist(dist) { }
// MAYBE: Ray(const glm::mat4& view_matrix) { }
Ray(const glm::vec3& from, const glm::vec3& dir, float dist): from(from), dir(glm::normalize(dir)), dist(dist) { }
inline Ray operator/(float scale) const noexcept {
return Ray(from / scale, dir, dist / scale);
}
/// Get path points in integer grid
/// @note not precise enough
inline void grid(std::vector<voxel_pos>& points) const {
voxel_pos current = from + glm::vec3(.5f);
voxel_pos d = dir * dist;
voxel_pos inc = voxel_pos((d.x < 0) ? -1 : 1, (d.y < 0) ? -1 : 1, (d.z < 0) ? -1 : 1);
voxel_pos size = glm::abs(d);
voxel_pos delta = size << 1ll;
if ((size.x >= size.y) && (size.x >= size.z)) {
int err_1 = delta.y - size.x;
int err_2 = delta.z - size.x;
points.reserve(size.x + 1);
for (int i = 0; i < size.x; i++) {
points.push_back(current);
if (err_1 > 0) {
current.y += inc.y;
err_1 -= delta.x;
}
if (err_2 > 0) {
current.z += inc.z;
err_2 -= delta.x;
}
err_1 += delta.y;
err_2 += delta.z;
current.x += inc.x;
}
} else if ((size.y >= size.x) && (size.y >= size.z)) {
int err_1 = delta.x - size.y;
int err_2 = delta.z - size.y;
points.reserve(size.y + 1);
for (int i = 0; i < size.y; i++) {
points.push_back(current);
if (err_1 > 0) {
current.x += inc.x;
err_1 -= delta.y;
}
if (err_2 > 0) {
current.z += inc.z;
err_2 -= delta.y;
}
err_1 += delta.x;
err_2 += delta.z;
current.y += inc.y;
}
} else {
int err_1 = delta.y - size.z;
int err_2 = delta.x - size.z;
points.reserve(size.z + 1);
for (int i = 0; i < size.z; i++) {
points.push_back(current);
if (err_1 > 0) {
current.y += inc.y;
err_1 -= delta.z;
}
if (err_2 > 0) {
current.x += inc.x;
err_2 -= delta.z;
}
err_1 += delta.y;
err_2 += delta.x;
current.z += inc.z;
}
inline Ray operator/(float scale) const noexcept {
return Ray(from / scale, dir, dist / scale);
}
points.push_back(current);
}
};
/// Get path points in integer grid
/// @note not precise enough
inline void grid(std::vector<voxel_pos>& points) const {
voxel_pos current = from + glm::vec3(.5f);
voxel_pos d = dir * dist;
voxel_pos inc = voxel_pos((d.x < 0) ? -1 : 1, (d.y < 0) ? -1 : 1, (d.z < 0) ? -1 : 1);
voxel_pos size = glm::abs(d);
voxel_pos delta = size << 1ll;
if ((size.x >= size.y) && (size.x >= size.z)) {
int err_1 = delta.y - size.x;
int err_2 = delta.z - size.x;
points.reserve(size.x + 1);
for (int i = 0; i < size.x; i++) {
points.push_back(current);
if (err_1 > 0) {
current.y += inc.y;
err_1 -= delta.x;
}
if (err_2 > 0) {
current.z += inc.z;
err_2 -= delta.x;
}
err_1 += delta.y;
err_2 += delta.z;
current.x += inc.x;
}
} else if ((size.y >= size.x) && (size.y >= size.z)) {
int err_1 = delta.x - size.y;
int err_2 = delta.z - size.y;
points.reserve(size.y + 1);
for (int i = 0; i < size.y; i++) {
points.push_back(current);
if (err_1 > 0) {
current.x += inc.x;
err_1 -= delta.y;
}
if (err_2 > 0) {
current.z += inc.z;
err_2 -= delta.y;
}
err_1 += delta.x;
err_2 += delta.z;
current.y += inc.y;
}
} else {
int err_1 = delta.y - size.z;
int err_2 = delta.x - size.z;
points.reserve(size.z + 1);
for (int i = 0; i < size.z; i++) {
points.push_back(current);
if (err_1 > 0) {
current.y += inc.y;
err_1 -= delta.z;
}
if (err_2 > 0) {
current.x += inc.x;
err_2 -= delta.z;
}
err_1 += delta.y;
err_2 += delta.x;
current.z += inc.z;
}
}
points.push_back(current);
}
};
}

View File

@ -8,126 +8,128 @@
#include <condition_variable>
#include <algorithm>
/// Thread safe queue with unique keys updating priority and value
template <class K, class V, class W>
class safe_priority_queue_map {
private:
static bool cmpByWeight(const std::pair<K, W> &a, const std::pair<K, W> &b) {
return a.second < b.second;
}
namespace data {
/// Thread safe queue with unique keys updating priority and value
template <class K, class V, class W>
class safe_priority_queue_map {
private:
static bool cmpByWeight(const std::pair<K, W> &a, const std::pair<K, W> &b) {
return a.second < b.second;
}
std::vector<std::pair<K, W>> heap;
robin_hood::unordered_map<K, V> map;
std::mutex mutex;
std::condition_variable cv;
std::vector<std::pair<K, W>> heap;
robin_hood::unordered_map<K, V> map;
std::mutex mutex;
std::condition_variable cv;
public:
void push(const K& key, const V& val, const W& weight) {
std::unique_lock<std::mutex> lock(mutex);
heap.push_back({key, weight});
std::push_heap(heap.begin(), heap.end(), cmpByWeight);
map.insert_or_assign(key, val);
cv.notify_one();
}
public:
void push(const K& key, const V& val, const W& weight) {
std::unique_lock<std::mutex> lock(mutex);
heap.push_back({key, weight});
std::push_heap(heap.begin(), heap.end(), cmpByWeight);
map.insert_or_assign(key, val);
cv.notify_one();
}
bool pop(std::pair<K, V>& out) {
std::unique_lock<std::mutex> lock(mutex);
if (heap.empty())
return false;
bool pop(std::pair<K, V>& out) {
std::unique_lock<std::mutex> lock(mutex);
if (heap.empty())
return false;
std::pop_heap(heap.begin(), heap.end(), cmpByWeight);
const auto priority = heap.back();
heap.pop_back();
std::pop_heap(heap.begin(), heap.end(), cmpByWeight);
const auto priority = heap.back();
heap.pop_back();
const auto it = map.find(priority.first);
if(it == map.end())
return false;
const auto it = map.find(priority.first);
if(it == map.end())
return false;
out = std::make_pair(it->first, it->second);
map.erase(it);
return true;
}
out = std::make_pair(it->first, it->second);
map.erase(it);
return true;
}
bool empty() {
std::unique_lock<std::mutex> lock(mutex);
return heap.empty();
}
bool empty() {
std::unique_lock<std::mutex> lock(mutex);
return heap.empty();
}
size_t size() {
std::unique_lock<std::mutex> lock(mutex);
return map.size();
}
size_t size() {
std::unique_lock<std::mutex> lock(mutex);
return map.size();
}
void notify() {
cv.notify_all();
}
void notify() {
cv.notify_all();
}
void wait() {
std::unique_lock<std::mutex> lock(mutex);
if (heap.empty())
cv.wait(lock);
}
void wait() {
std::unique_lock<std::mutex> lock(mutex);
if (heap.empty())
cv.wait(lock);
}
};
};
/// Thread safe queue with unique keys updating priority
template <class K, class W>
class safe_priority_queue {
private:
static bool cmpByWeight(const std::pair<K, W> &a, const std::pair<K, W> &b) {
return a.second < b.second;
}
/// Thread safe queue with unique keys updating priority
template <class K, class W>
class safe_priority_queue {
private:
static bool cmpByWeight(const std::pair<K, W> &a, const std::pair<K, W> &b) {
return a.second < b.second;
}
std::vector<std::pair<K, W>> heap;
robin_hood::unordered_set<K> set;
std::mutex mutex;
std::condition_variable cv;
std::vector<std::pair<K, W>> heap;
robin_hood::unordered_set<K> set;
std::mutex mutex;
std::condition_variable cv;
public:
void push(const K& key, const W& weight) {
std::unique_lock<std::mutex> lock(mutex);
heap.push_back({key, weight});
std::push_heap(heap.begin(), heap.end(), cmpByWeight);
set.insert(key);
cv.notify_one();
}
public:
void push(const K& key, const W& weight) {
std::unique_lock<std::mutex> lock(mutex);
heap.push_back({key, weight});
std::push_heap(heap.begin(), heap.end(), cmpByWeight);
set.insert(key);
cv.notify_one();
}
bool pop(K& out) {
std::unique_lock<std::mutex> lock(mutex);
if (heap.empty())
return false;
bool pop(K& out) {
std::unique_lock<std::mutex> lock(mutex);
if (heap.empty())
return false;
std::pop_heap(heap.begin(), heap.end(), cmpByWeight);
const auto priority = heap.back();
heap.pop_back();
std::pop_heap(heap.begin(), heap.end(), cmpByWeight);
const auto priority = heap.back();
heap.pop_back();
const auto it = set.find(priority.first);
if(it == set.end())
return false;
const auto it = set.find(priority.first);
if(it == set.end())
return false;
out = *it;
set.erase(it);
return true;
}
out = *it;
set.erase(it);
return true;
}
bool empty() {
std::unique_lock<std::mutex> lock(mutex);
return heap.empty();
}
bool empty() {
std::unique_lock<std::mutex> lock(mutex);
return heap.empty();
}
size_t size() {
std::unique_lock<std::mutex> lock(mutex);
return set.size();
}
size_t size() {
std::unique_lock<std::mutex> lock(mutex);
return set.size();
}
void notify() {
cv.notify_all();
}
void notify() {
cv.notify_all();
}
void wait() {
std::unique_lock<std::mutex> lock(mutex);
if (heap.empty())
cv.wait(lock);
}
void wait() {
std::unique_lock<std::mutex> lock(mutex);
if (heap.empty())
cv.wait(lock);
}
};
};
}

View File

@ -4,49 +4,51 @@
#include <mutex>
#include <condition_variable>
/// Thread safe queue
template <class T>
class safe_queue {
private:
std::queue<T> queue;
std::mutex mutex;
std::condition_variable cv;
namespace data {
/// Thread safe queue
template <class T>
class safe_queue {
private:
std::queue<T> queue;
std::mutex mutex;
std::condition_variable cv;
public:
void push(const T& in) {
std::unique_lock<std::mutex> lock(mutex);
queue.push(in);
cv.notify_one();
}
public:
void push(const T& in) {
std::unique_lock<std::mutex> lock(mutex);
queue.push(in);
cv.notify_one();
}
bool pop(T& out) {
std::unique_lock<std::mutex> lock(mutex);
if (queue.empty())
return false;
bool pop(T& out) {
std::unique_lock<std::mutex> lock(mutex);
if (queue.empty())
return false;
out = queue.front();
queue.pop();
return true;
}
out = queue.front();
queue.pop();
return true;
}
bool empty() {
std::unique_lock<std::mutex> lock(mutex);
return queue.empty();
}
bool empty() {
std::unique_lock<std::mutex> lock(mutex);
return queue.empty();
}
size_t size() {
std::unique_lock<std::mutex> lock(mutex);
return queue.size();
}
size_t size() {
std::unique_lock<std::mutex> lock(mutex);
return queue.size();
}
void notify() {
cv.notify_all();
}
void notify() {
cv.notify_all();
}
void wait() {
std::unique_lock<std::mutex> lock(mutex);
if(queue.empty())
cv.wait(lock);
}
void wait() {
std::unique_lock<std::mutex> lock(mutex);
if(queue.empty())
cv.wait(lock);
}
};
};
}

View File

@ -5,69 +5,71 @@
#include <mutex>
#include <condition_variable>
/// Thread safe queue discarding duplicate values
template <class T>
class safe_unique_queue {
private:
std::queue<T> queue;
std::unordered_set<T> set;
std::mutex mutex;
std::condition_variable cv;
namespace data {
/// Thread safe queue discarding duplicate values
template <class T>
class safe_unique_queue {
private:
std::queue<T> queue;
std::unordered_set<T> set;
std::mutex mutex;
std::condition_variable cv;
public:
bool push(const T& in) {
std::unique_lock<std::mutex> lock(mutex);
if(set.insert(in).second) {
queue.push(in);
cv.notify_one();
public:
bool push(const T& in) {
std::unique_lock<std::mutex> lock(mutex);
if(set.insert(in).second) {
queue.push(in);
cv.notify_one();
return true;
}
return false;
}
bool pop(T& out) {
std::unique_lock<std::mutex> lock(mutex);
if (queue.empty())
return false;
out = queue.front();
set.erase(out);
queue.pop();
return true;
}
return false;
}
bool pop(T& out) {
std::unique_lock<std::mutex> lock(mutex);
if (queue.empty())
return false;
bool take(T& out) {
std::unique_lock<std::mutex> lock(mutex);
if (queue.empty())
return false;
out = queue.front();
set.erase(out);
queue.pop();
return true;
}
out = queue.front();
queue.pop();
return true;
}
bool take(T& out) {
std::unique_lock<std::mutex> lock(mutex);
if (queue.empty())
return false;
void release(const T& taken) {
std::unique_lock<std::mutex> lock(mutex);
set.erase(taken);
}
out = queue.front();
queue.pop();
return true;
}
bool empty() {
std::unique_lock<std::mutex> lock(mutex);
return queue.empty();
}
void release(const T& taken) {
std::unique_lock<std::mutex> lock(mutex);
set.erase(taken);
}
size_t size() {
std::unique_lock<std::mutex> lock(mutex);
return set.size();
}
bool empty() {
std::unique_lock<std::mutex> lock(mutex);
return queue.empty();
}
void notify() {
cv.notify_all();
}
size_t size() {
std::unique_lock<std::mutex> lock(mutex);
return set.size();
}
void notify() {
cv.notify_all();
}
void wait() {
std::unique_lock<std::mutex> lock(mutex);
if(queue.empty())
cv.wait(lock);
}
};
void wait() {
std::unique_lock<std::mutex> lock(mutex);
if(queue.empty())
cv.wait(lock);
}
};
}

View File

@ -1,39 +1,38 @@
#ifndef UNIQUE_QUEUE_HPP
#define UNIQUE_QUEUE_HPP
#pragma once
#include <queue>
#include <unordered_set>
#include <cassert>
/// Queue discarding duplicate values
/// @note not thread safe
template <class T>
struct unique_queue {
std::queue<T> queue;
std::unordered_set<T> set;
namespace data {
/// Queue discarding duplicate values
/// @note not thread safe
template <class T>
struct unique_queue {
std::queue<T> queue;
std::unordered_set<T> set;
bool push(T in) {
if(set.insert(in).second) {
queue.push(in);
return true;
bool push(T in) {
if(set.insert(in).second) {
queue.push(in);
return true;
}
return false;
}
return false;
}
T pop() {
const auto out = queue.front();
set.erase(out);
queue.pop();
return out;
}
T pop() {
const auto out = queue.front();
set.erase(out);
queue.pop();
return out;
}
bool empty() const {
return queue.empty();
}
bool empty() const {
return queue.empty();
}
size_t size() const {
return queue.size();
}
};
#endif
size_t size() const {
return queue.size();
}
};
}

View File

@ -19,10 +19,10 @@
#include "render/Renderer.hpp"
#include "render/pass/ColorProgram.hpp"
#include "render/buffer/ColorBuffer.hpp"
#include "world/World.hpp"
#include "render/buffer/Colored.hpp"
#include "world/Universe.hpp"
#include "data/state.h"
#include "state.h"
#include <Remotery.h>
@ -46,10 +46,10 @@ int main(int, char *[]){
renderer->LightInvDir = glm::vec3(-0.5f, 2, -2);
UI::setup(window);
GLuint aimTexture = Program::loadTexture("ui/Aim", false);
GLuint aimTexture = pass::Program::loadTexture("ui/Aim", false);
ColorProgram *lookProgram = new ColorProgram();
ColorBuffer lookBuffer(GL_LINES, 24, {
pass::ColorProgram *lookProgram = new pass::ColorProgram();
buffer::Colored lookBuffer(GL_LINES, 24, {
glm::vec3(0, 0, 0), glm::vec3(0, 0, 1),
glm::vec3(0, 0, 1), glm::vec3(0, 1, 1),
glm::vec3(0, 1, 1), glm::vec3(0, 1, 0),
@ -84,7 +84,7 @@ int main(int, char *[]){
std::cout << "Profiling !" << std::endl;
#endif
World world = World(options.world);
world::Universe world = world::Universe(options.world);
world.setContouring(contouring::load(options.contouring_idx, options.contouring_data));
state.contouring = world.getContouring();
@ -103,9 +103,9 @@ int main(int, char *[]){
state.look_at = world.raycast(camera.getRay() / options.voxel_size);
if (state.capture_mouse && state.look_at.has_value()) {
if (inputs.isPressing(Mouse::Left))
world.setCube(state.look_at.value().first, Voxel{0, 0}, options.tool.radius);
world.setCube(state.look_at.value().first, world::Voxel{0, 0}, options.tool.radius);
else if (inputs.isPressing(Mouse::Right))
world.setCube(state.look_at.value().first, Voxel{UCHAR_MAX, options.tool.material}, options.tool.radius);
world.setCube(state.look_at.value().first, world::Voxel{UCHAR_MAX, options.tool.material}, options.tool.radius);
}
world.update(state.position / options.voxel_size, reports.world);
inputs.saveKeys();
@ -157,8 +157,8 @@ int main(int, char *[]){
auto pass = renderer->getPass();
pass.start();
std::vector<std::pair<glm::mat4, Buffer *const>> models;
std::optional<Frustum> frustum;
std::vector<std::pair<glm::mat4, buffer::Abstract *const>> models;
std::optional<geometry::Frustum> frustum;
if(options.culling) {
frustum = {camera.getFrustum()};
}

View File

@ -7,8 +7,8 @@ Renderer::Renderer(const Renderer::options& options) {
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
MainPass = new MainProgram(options.main);
SkyPass = new SkyProgram();
MainPass = new pass::MainProgram(options.main);
SkyPass = new pass::SkyProgram();
SkyEnable = options.skybox;
FogColor = glm::vec3(options.clear_color.x, options.clear_color.y, options.clear_color.z);
@ -22,9 +22,9 @@ Renderer::~Renderer() {
glDeleteVertexArrays(1, &VertexArrayID);
}
PassContext Renderer::getPass() {
pass::Context Renderer::getPass() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
return PassContext(this, MainPass);
return pass::Context(this, MainPass);
}
void Renderer::postProcess() {
if(SkyEnable) {
@ -32,9 +32,9 @@ void Renderer::postProcess() {
}
}
void Renderer::reloadShaders(const MainProgram::options& options) {
void Renderer::reloadShaders(const pass::MainProgram::options& options) {
delete MainPass;
MainPass = new MainProgram(options);
MainPass = new pass::MainProgram(options);
}
void Renderer::reloadTextures(const std::string& texturePath, float mipMapLOD) {
unloadTextures();
@ -48,14 +48,14 @@ void Renderer::unloadTextures() {
}
void Renderer::loadTextures(const std::string& texturePath, float mipMapLOD) {
std::vector<std::string> terrainTextures;
for(const auto texture: materials::textures) {
for(const auto texture: world::materials::textures) {
terrainTextures.push_back(texturePath + "/terrain/" + texture);
}
TextureAtlas = Program::loadTextureArray(terrainTextures, "", mipMapLOD);
NormalAtlas = Program::loadTextureArray(terrainTextures, ".nrm", mipMapLOD);
HOSAtlas = Program::loadTextureArray(terrainTextures, ".hos", mipMapLOD);
TextureAtlas = pass::Program::loadTextureArray(terrainTextures, "", mipMapLOD);
NormalAtlas = pass::Program::loadTextureArray(terrainTextures, ".nrm", mipMapLOD);
HOSAtlas = pass::Program::loadTextureArray(terrainTextures, ".hos", mipMapLOD);
Skybox = Program::loadTextureCube(texturePath + "/sky/Space_tray");
Skybox = pass::Program::loadTextureCube(texturePath + "/sky/Space_tray");
}
void Renderer::lookFrom(const Camera& camera) {

View File

@ -4,18 +4,25 @@
#include <imgui.h>
#include "pass/MainProgram.hpp"
#include "pass/SkyProgram.hpp"
#include "pass/PassContext.hpp"
#include "pass/Context.hpp"
class Camera;
/// Handle rendering passes and params
class Renderer {
public:
/// Rendering options
struct options {
MainProgram::options main;
/// Main pass
pass::MainProgram::options main;
/// Display skybox
bool skybox = false;
/// Display only wires
bool wireframe = false;
/// Texture pack name
std::string textures = "1024-realistic";
/// Textures quality
float mipMapLOD = -.5;
/// Depth color
ImVec4 clear_color;
};
@ -52,18 +59,21 @@ public:
return Skybox;
}
PassContext getPass();
/// Get main pass with context
pass::Context getPass();
/// Apply postprocessing
void postProcess();
/// Apply camera matrices
void lookFrom(const Camera&);
void reloadShaders(const MainProgram::options&);
void reloadShaders(const pass::MainProgram::options &);
void reloadTextures(const std::string &, float mipMapLOD = 0);
private:
GLuint VertexArrayID;
MainProgram *MainPass;
SkyProgram *SkyPass;
pass::MainProgram *MainPass;
pass::SkyProgram *SkyPass;
glm::mat4 ProjectionMatrix;
glm::mat4 ViewMatrix;

View File

@ -160,16 +160,16 @@ UI::Actions UI::draw(options &options, state &state, const reports &reports, GLu
if (options.editor_show) {
ImGui::Begin("Editor", &options.editor_show, ImGuiWindowFlags_AlwaysAutoResize);
if (state.look_at.has_value()) {
ImGui::Text("Look at: (%lld, %lld, %lld) (%s, %.1f)", state.look_at.value().first.x, state.look_at.value().first.y, state.look_at.value().first.z, materials::textures[state.look_at.value().second.Material].c_str(), state.look_at.value().second.Density * 1. / UCHAR_MAX);
ImGui::Text("Look at: (%lld, %lld, %lld) (%s, %.1f)", state.look_at.value().first.x, state.look_at.value().first.y, state.look_at.value().first.z, world::materials::textures[state.look_at.value().second.Material].c_str(), state.look_at.value().second.Density * 1. / UCHAR_MAX);
ImGui::Text("(%.3f, %.3f, %.3f)", state.look_at.value().first.x * options.voxel_size, state.look_at.value().first.y * options.voxel_size, state.look_at.value().first.z * options.voxel_size);
} else {
ImGui::Text("Look at: none");
}
ImGui::Separator();
if (ImGui::BeginCombo("Material", materials::textures[options.tool.material].c_str())) {
for (size_t i = 0; i < materials::textures.size(); i++) {
if (ImGui::BeginCombo("Material", world::materials::textures[options.tool.material].c_str())) {
for (size_t i = 0; i < world::materials::textures.size(); i++) {
const bool is_selected = (options.tool.material == i);
if (ImGui::Selectable(materials::textures[i].c_str(), is_selected))
if (ImGui::Selectable(world::materials::textures[i].c_str(), is_selected))
options.tool.material = i;
if (is_selected)
ImGui::SetItemDefaultFocus();

View File

@ -3,9 +3,10 @@
#include "imgui.h"
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "../data/state.h"
#include "../state.h"
namespace UI {
/// Retro actions to state
enum class Actions {
None = 0,
FPS = 1 << 0,
@ -24,10 +25,15 @@ namespace UI {
return static_cast<int>(a) & static_cast<int>(b);
}
/// Prepare UI
void setup(GLFWwindow*);
/// Release UI
void unload();
/// Compute UI
Actions draw(options&, state&, const reports&, GLuint aim);
/// Is UI in focus
bool isFocus();
/// Display UI
void render();
};

View File

@ -1,14 +1,16 @@
#include "Buffer.hpp"
#include "Abstract.hpp"
Buffer::Buffer(GLenum shape): Shape(shape) {
using namespace buffer;
Abstract::Abstract(GLenum shape): Shape(shape) {
glGenBuffers(1, &VertexBufferID);
}
Buffer::~Buffer() {
Abstract::~Abstract() {
glDeleteBuffers(1, &VertexBufferID);
}
void Buffer::enableVertexAttrib() {
void Abstract::enableVertexAttrib() {
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID);
glVertexAttribPointer(
@ -20,17 +22,17 @@ void Buffer::enableVertexAttrib() {
(void *)0 // array buffer offset
);
}
void Buffer::enableAllAttribs() {
void Abstract::enableAllAttribs() {
enableVertexAttrib();
}
void Buffer::disableVertexAttrib() {
void Abstract::disableVertexAttrib() {
glDisableVertexAttribArray(0);
}
void Buffer::disableAllAttribs() {
void Abstract::disableAllAttribs() {
disableVertexAttrib();
}
void Buffer::setVertices(const unsigned long size, const void *data) {
void Abstract::setVertices(const unsigned long size, const void *data) {
glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID);
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
}

View File

@ -0,0 +1,34 @@
#pragma once
#include <GL/glew.h>
#include <sys/types.h>
namespace buffer {
/// Draw options
struct params {
/// Bind only vertices positions
bool vertexOnly;
};
/// Abstract OpenGL Buffer
class Abstract {
public:
Abstract(GLenum shape);
virtual ~Abstract();
/// Bind and draw buffer
virtual uint draw(params params) = 0;
protected:
GLenum Shape;
GLuint VertexBufferID;
void enableVertexAttrib();
void disableVertexAttrib();
void enableAllAttribs();
void disableAllAttribs();
void setVertices(const unsigned long size, const void *data);
};
}

View File

@ -1,29 +0,0 @@
#pragma once
#include <GL/glew.h>
#include <sys/types.h>
/// Abstract OpenGL Buffer
class Buffer {
public:
Buffer(GLenum shape);
virtual ~Buffer();
struct params {
bool vertexOnly;
};
virtual uint draw(params params) = 0;
protected:
GLenum Shape;
GLuint VertexBufferID;
void enableVertexAttrib();
void disableVertexAttrib();
void enableAllAttribs();
void disableAllAttribs();
void setVertices(const unsigned long size, const void *data);
};

View File

@ -1,26 +0,0 @@
#pragma once
#include <GL/glew.h>
#include <vector>
#include <glm/glm.hpp>
#include "Buffer.hpp"
/// OpenGL VertexBuffer with Colors
class ColorBuffer: public Buffer {
public:
ColorBuffer(GLenum shape, const unsigned long count, const std::vector<glm::vec3> &vertices, const std::vector<glm::vec4> &colors);
virtual ~ColorBuffer();
void enableAllAttribs();
void disableAllAttribs();
uint draw(params params) override;
private:
unsigned long ElementCount;
GLuint ColorBufferID;
void setColors(const unsigned long size, const void *data);
};

View File

@ -1,16 +1,18 @@
#include "ColorBuffer.hpp"
#include "Colored.hpp"
ColorBuffer::ColorBuffer(GLenum shape, const unsigned long count, const std::vector<glm::vec3> &vertices, const std::vector<glm::vec4> &colors): Buffer(shape) {
using namespace buffer;
Colored::Colored(GLenum shape, const unsigned long count, const std::vector<glm::vec3> &vertices, const std::vector<glm::vec4> &colors): Abstract(shape) {
glGenBuffers(1, &ColorBufferID);
setVertices(vertices.size() * sizeof(glm::vec3), &vertices[0]);
setColors(colors.size() * sizeof(glm::vec4), &colors[0]);
ElementCount = count;
}
ColorBuffer::~ColorBuffer() {
Colored::~Colored() {
glDeleteBuffers(1, &ColorBufferID);
}
uint ColorBuffer::draw(params params) {
uint Colored::draw(params params) {
if (params.vertexOnly) {
enableVertexAttrib();
} else {
@ -26,7 +28,7 @@ uint ColorBuffer::draw(params params) {
return ElementCount;
}
void ColorBuffer::enableAllAttribs() {
void Colored::enableAllAttribs() {
enableVertexAttrib();
glEnableVertexAttribArray(1);
@ -40,13 +42,13 @@ void ColorBuffer::enableAllAttribs() {
(void *)0 // array buffer offset
);
}
void ColorBuffer::disableAllAttribs() {
void Colored::disableAllAttribs() {
glDisableVertexAttribArray(1);
disableVertexAttrib();
}
void ColorBuffer::setColors(const unsigned long size, const void *data) {
void Colored::setColors(const unsigned long size, const void *data) {
glBindBuffer(GL_ARRAY_BUFFER, ColorBufferID);
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
}

View File

@ -0,0 +1,28 @@
#pragma once
#include <GL/glew.h>
#include <vector>
#include <glm/glm.hpp>
#include "Abstract.hpp"
namespace buffer {
/// OpenGL VertexBuffer with Colors
class Colored: public Abstract {
public:
Colored(GLenum shape, const unsigned long count, const std::vector<glm::vec3> &vertices, const std::vector<glm::vec4> &colors);
virtual ~Colored();
void enableAllAttribs();
void disableAllAttribs();
uint draw(params params) override;
private:
unsigned long ElementCount;
GLuint ColorBufferID;
void setColors(const unsigned long size, const void *data);
};
}

View File

@ -1,8 +1,10 @@
#include "ShortIndexedBuffer.hpp"
#include "ShortIndexed.hpp"
#include "vboindexer.hpp"
ShortIndexedBuffer::Data::Data(const std::vector<VertexData> &vs, const std::vector<GLushort> &indices): indices(indices) {
using namespace buffer;
ShortIndexed::Data::Data(const std::vector<VertexData> &vs, const std::vector<GLushort> &indices): indices(indices) {
vertices.reserve(vs.size());
materials.reserve(vs.size());
normals.reserve(vs.size());
@ -12,27 +14,27 @@ ShortIndexedBuffer::Data::Data(const std::vector<VertexData> &vs, const std::vec
normals.push_back(vertex.Normal);
}
}
void ShortIndexedBuffer::Data::index(const std::vector<VertexData>& vs) {
void ShortIndexed::Data::index(const std::vector<VertexData>& vs) {
indexVBO(vs, indices, vertices, materials, normals);
}
ShortIndexedBuffer::ShortIndexedBuffer(GLenum shape, const std::vector<VertexData> &vertices): Buffer(shape) {
setData(ShortIndexedBuffer::Data(vertices));
ShortIndexed::ShortIndexed(GLenum shape, const std::vector<VertexData> &vertices): Abstract(shape) {
setData(ShortIndexed::Data(vertices));
}
ShortIndexedBuffer::ShortIndexedBuffer(GLenum shape, const std::vector<VertexData> &vertices, const std::vector<GLushort>& indices): Buffer(shape) {
setData(ShortIndexedBuffer::Data(vertices, indices));
ShortIndexed::ShortIndexed(GLenum shape, const std::vector<VertexData> &vertices, const std::vector<GLushort>& indices): Abstract(shape) {
setData(ShortIndexed::Data(vertices, indices));
}
ShortIndexedBuffer::ShortIndexedBuffer(GLenum shape, const ShortIndexedBuffer::Data &data): Buffer(shape) {
ShortIndexed::ShortIndexed(GLenum shape, const ShortIndexed::Data &data): Abstract(shape) {
setData(data);
}
ShortIndexedBuffer::~ShortIndexedBuffer() {
ShortIndexed::~ShortIndexed() {
glDeleteBuffers(1, &NormalBufferID);
glDeleteBuffers(1, &MaterialBufferID);
glDeleteBuffers(1, &IndexBufferID);
}
void ShortIndexedBuffer::enableAllAttribs() {
void ShortIndexed::enableAllAttribs() {
enableVertexAttrib();
glEnableVertexAttribArray(1);
@ -56,16 +58,16 @@ void ShortIndexedBuffer::enableAllAttribs() {
(void *)0 // array buffer offset
);
}
void ShortIndexedBuffer::disableAllAttribs() {
void ShortIndexed::disableAllAttribs() {
glDisableVertexAttribArray(2);
glDisableVertexAttribArray(1);
disableVertexAttrib();
}
void ShortIndexedBuffer::enableIndex() {
void ShortIndexed::enableIndex() {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferID);
}
uint ShortIndexedBuffer::draw(Buffer::params params) {
uint ShortIndexed::draw(buffer::params params) {
if(IndexSize == 0)
return 0;
@ -86,7 +88,7 @@ uint ShortIndexedBuffer::draw(Buffer::params params) {
}
#include <iostream>
void ShortIndexedBuffer::setData(const ShortIndexedBuffer::Data& data) {
void ShortIndexed::setData(const ShortIndexed::Data& data) {
glGenBuffers(1, &IndexBufferID);
glGenBuffers(1, &MaterialBufferID);
glGenBuffers(1, &NormalBufferID);
@ -101,15 +103,15 @@ void ShortIndexedBuffer::setData(const ShortIndexedBuffer::Data& data) {
setNormals(data.normals.size() * sizeof(glm::vec3), &data.normals[0]);
}
void ShortIndexedBuffer::setIndicies(const unsigned long size, const void *data) {
void ShortIndexed::setIndicies(const unsigned long size, const void *data) {
glBindBuffer(GL_ARRAY_BUFFER, IndexBufferID);
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
}
void ShortIndexedBuffer::setMaterials(const unsigned long size, const void *data) {
void ShortIndexed::setMaterials(const unsigned long size, const void *data) {
glBindBuffer(GL_ARRAY_BUFFER, MaterialBufferID);
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
}
void ShortIndexedBuffer::setNormals(const unsigned long size, const void *data) {
void ShortIndexed::setNormals(const unsigned long size, const void *data) {
glBindBuffer(GL_ARRAY_BUFFER, NormalBufferID);
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
}

View File

@ -0,0 +1,62 @@
#pragma once
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <vector>
#include "Abstract.hpp"
#include "VertexData.hpp"
namespace buffer {
/// OpenGL VertexBuffer with IndexBuffer
class ShortIndexed: public Abstract {
public:
/// Preindexed buffer data
struct Data {
std::vector<GLushort> indices;
std::vector<glm::vec3> vertices;
std::vector<GLushort> materials;
std::vector<glm::vec3> normals;
Data() { }
Data(const std::vector<VertexData> &vertices, const std::vector<GLushort> &indices);
Data(const std::vector<VertexData> &vertices) { index(vertices); }
void index(const std::vector<VertexData> &vertices);
bool empty() const {
return indices.empty();
}
void clear() {
indices.clear();
vertices.clear();
materials.clear();
normals.clear();
}
};
ShortIndexed(GLenum shape, const typename std::vector<VertexData> &vertices);
ShortIndexed(GLenum shape, const typename std::vector<VertexData> &vertices, const typename std::vector<GLushort> &indices);
ShortIndexed(GLenum shape, const typename ShortIndexed::Data &data);
virtual ~ShortIndexed();
void enableAllAttribs();
void disableAllAttribs();
void enableIndex();
uint draw(params params) override;
private:
GLuint IndexBufferID;
GLushort IndexSize = 0;
GLuint MaterialBufferID;
GLuint NormalBufferID;
void setData(const ShortIndexed::Data &data);
void setIndicies(const unsigned long size, const void *data);
void setMaterials(const unsigned long size, const void *data);
void setNormals(const unsigned long size, const void *data);
};
}

View File

@ -1,59 +0,0 @@
#pragma once
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <vector>
#include "Buffer.hpp"
#include "VertexData.hpp"
/// OpenGL VertexBuffer with IndexBuffer
class ShortIndexedBuffer: public Buffer {
public:
struct Data {
std::vector<GLushort> indices;
std::vector<glm::vec3> vertices;
std::vector<GLushort> materials;
std::vector<glm::vec3> normals;
Data() { }
Data(const std::vector<VertexData> &vertices, const std::vector<GLushort> &indices);
Data(const std::vector<VertexData> &vertices) { index(vertices); }
void index(const std::vector<VertexData> &vertices);
bool empty() const {
return indices.empty();
}
void clear() {
indices.clear();
vertices.clear();
materials.clear();
normals.clear();
}
};
ShortIndexedBuffer(GLenum shape, const typename std::vector<VertexData> &vertices);
ShortIndexedBuffer(GLenum shape, const typename std::vector<VertexData> &vertices, const typename std::vector<GLushort> &indices);
ShortIndexedBuffer(GLenum shape, const typename ShortIndexedBuffer::Data &data);
virtual ~ShortIndexedBuffer();
void enableAllAttribs();
void disableAllAttribs();
void enableIndex();
uint draw(Buffer::params params) override;
private:
GLuint IndexBufferID;
GLushort IndexSize = 0;
GLuint MaterialBufferID;
GLuint NormalBufferID;
void setData(const ShortIndexedBuffer::Data &data);
void setIndicies(const unsigned long size, const void *data);
void setMaterials(const unsigned long size, const void *data);
void setNormals(const unsigned long size, const void *data);
};

View File

@ -0,0 +1,15 @@
#include "Vertex.hpp"
using namespace buffer;
Vertex::Vertex(GLenum shape, const unsigned long count, const unsigned long size, const void *data): Abstract(shape) {
setVertices(size, data);
ElementCount = count;
}
uint Vertex::draw(params) {
enableAllAttribs();
glDrawArrays(Shape, 0, ElementCount);
disableAllAttribs();
return ElementCount;
}

View File

@ -0,0 +1,18 @@
#pragma once
#include <GL/glew.h>
#include "Abstract.hpp"
/// OpenGL VertexBuffer
namespace buffer {
class Vertex: public Abstract {
public:
Vertex(GLenum shape, const unsigned long count, const unsigned long size, const void *data);
uint draw(params) override;
private:
unsigned long ElementCount;
};
}

View File

@ -1,13 +0,0 @@
#include "VertexBuffer.hpp"
VertexBuffer::VertexBuffer(GLenum shape, const unsigned long count, const unsigned long size, const void *data): Buffer(shape) {
setVertices(size, data);
ElementCount = count;
}
uint VertexBuffer::draw(params) {
enableAllAttribs();
glDrawArrays(Shape, 0, ElementCount);
disableAllAttribs();
return ElementCount;
}

View File

@ -1,16 +0,0 @@
#pragma once
#include <GL/glew.h>
#include "Buffer.hpp"
/// OpenGL VertexBuffer
class VertexBuffer: public Buffer {
public:
VertexBuffer(GLenum shape, const unsigned long count, const unsigned long size, const void *data);
uint draw(params) override;
private:
unsigned long ElementCount;
};

View File

@ -1,18 +1,17 @@
#ifndef VERTEX_DATA_HPP
#define VERTEX_DATA_HPP
#pragma once
#include <glm/glm.hpp>
#include <string.h> // for memcmp
#include <GL/glew.h>
/// Vertex properties
struct VertexData {
glm::vec3 Position;
GLushort Material;
glm::vec3 Normal;
bool operator<(const VertexData that) const {
return memcmp((void *)this, (void *)&that, sizeof(VertexData)) > 0;
namespace buffer {
/// Vertex properties
struct VertexData {
glm::vec3 Position;
GLushort Material;
glm::vec3 Normal;
bool operator<(const VertexData that) const {
return memcmp((void *)this, (void *)&that, sizeof(VertexData)) > 0;
};
};
};
#endif
}

View File

@ -6,11 +6,11 @@
#include "vboindexer.hpp"
bool getSimilarVertexIndex_fast(
const VertexData &packed,
std::map<VertexData, GLushort> &VertexToOutIndex,
const buffer::VertexData &packed,
std::map<buffer::VertexData, GLushort> &VertexToOutIndex,
GLushort &result)
{
std::map<VertexData, GLushort>::iterator it = VertexToOutIndex.find(packed);
std::map<buffer::VertexData, GLushort>::iterator it = VertexToOutIndex.find(packed);
if ( it == VertexToOutIndex.end() ){
return false;
}else{
@ -19,11 +19,11 @@ bool getSimilarVertexIndex_fast(
}
}
bool getSimilarVertexIndex_fast(
const VertexData &packed,
std::map<VertexData, unsigned int> &VertexToOutIndex,
const buffer::VertexData &packed,
std::map<buffer::VertexData, unsigned int> &VertexToOutIndex,
unsigned int &result)
{
std::map<VertexData, unsigned int>::iterator it = VertexToOutIndex.find(packed);
std::map<buffer::VertexData, unsigned int>::iterator it = VertexToOutIndex.find(packed);
if ( it == VertexToOutIndex.end() ){
return false;
}else{
@ -43,13 +43,13 @@ void indexVBO(
std::vector<GLushort> &out_materials,
std::vector<glm::vec3> &out_normals)
{
std::map<VertexData,unsigned int> VertexToOutIndex;
std::map<buffer::VertexData,unsigned int> VertexToOutIndex;
out_indices.reserve(in_vertices.size());
// For each input vertex
for (unsigned int i = 0; i < in_vertices.size(); i++) {
VertexData packed = {in_vertices[i], in_materials[i], in_normals[i]};
buffer::VertexData packed = {in_vertices[i], in_materials[i], in_normals[i]};
// Try to find a similar vertex in out_XXXX
unsigned int index;
@ -68,14 +68,14 @@ void indexVBO(
}
}
void indexVBO(
const std::vector<VertexData> &in_vertices,
const std::vector<buffer::VertexData> &in_vertices,
std::vector<GLushort> &out_indices,
std::vector<glm::vec3> &out_vertices,
std::vector<GLushort> &out_materials,
std::vector<glm::vec3> &out_normals)
{
std::map<VertexData, GLushort> VertexToOutIndex;
std::map<buffer::VertexData, GLushort> VertexToOutIndex;
out_indices.reserve(in_vertices.size());
// For each input vertex
@ -95,44 +95,4 @@ void indexVBO(
VertexToOutIndex[ in_vertices[i] ] = newindex;
}
}
}
/*
void indexVBO_TBN(
std::vector<glm::vec3> & in_vertices,
std::vector<glm::vec2> & in_uvs,
std::vector<glm::vec3> & in_normals,
std::vector<glm::vec3> & in_tangents,
std::vector<glm::vec3> & in_bitangents,
std::vector<unsigned int> & out_indices,
std::vector<glm::vec3> & out_vertices,
std::vector<glm::vec2> & out_uvs,
std::vector<glm::vec3> & out_normals,
std::vector<glm::vec3> & out_tangents,
std::vector<glm::vec3> & out_bitangents
){
// For each input vertex
for ( unsigned int i=0; i<in_vertices.size(); i++ ){
// Try to find a similar vertex in out_XXXX
unsigned int index;
bool found = getSimilarVertexIndex(in_vertices[i], in_uvs[i], in_normals[i], out_vertices, out_uvs, out_normals, index);
if ( found ){ // A similar vertex is already in the VBO, use it instead !
out_indices.push_back( index );
// Average the tangents and the bitangents
out_tangents[index] += in_tangents[i];
out_bitangents[index] += in_bitangents[i];
}else{ // If not, it needs to be added in the output data.
out_vertices.push_back( in_vertices[i]);
out_uvs .push_back( in_uvs[i]);
out_normals .push_back( in_normals[i]);
out_tangents .push_back( in_tangents[i]);
out_bitangents .push_back( in_bitangents[i]);
out_indices .push_back( (unsigned int)out_vertices.size() - 1 );
}
}
}
*/
}

View File

@ -17,7 +17,7 @@ void indexVBO(
std::vector<glm::vec3> &out_normals);
void indexVBO(
const std::vector<VertexData> &in_vertices,
const std::vector<buffer::VertexData> &in_vertices,
std::vector<GLushort> &out_indices,
std::vector<glm::vec3> &out_vertices,

View File

@ -2,6 +2,8 @@
#include "../Renderer.hpp"
using namespace pass;
ColorProgram::ColorProgram(): Program() {
std::vector<std::string> flags;
@ -18,11 +20,11 @@ ColorProgram::~ColorProgram() { }
std::string ColorProgram::getName() const {
return "Color";
}
void ColorProgram::start(Renderer *renderer) { }
Buffer::params ColorProgram::setup(Renderer *renderer, glm::mat4 modelMatrix) {
void ColorProgram::start(Renderer *) { }
buffer::params ColorProgram::setup(Renderer *renderer, glm::mat4 modelMatrix) {
const auto mvp = renderer->getProjectionMatrix() * renderer->getViewMatrix() * modelMatrix;
setMVP(&mvp[0][0]);
return Buffer::params{.vertexOnly = false};
return buffer::params{.vertexOnly = false};
}
void ColorProgram::setMVP(const GLfloat *matrix) {

View File

@ -2,18 +2,20 @@
#include "Program.hpp"
/// Final pass
class ColorProgram: public Program {
public:
ColorProgram();
~ColorProgram();
namespace pass {
/// Solid colors pass
class ColorProgram: public Program {
public:
ColorProgram();
~ColorProgram();
std::string getName() const override;
void start(Renderer *) override;
Buffer::params setup(Renderer *, glm::mat4 modelMatrix) override;
std::string getName() const override;
void start(Renderer *) override;
buffer::params setup(Renderer *, glm::mat4 modelMatrix) override;
void setMVP(const GLfloat *matrix);
void setMVP(const GLfloat *matrix);
private:
GLuint MVPMatrixID;
};
private:
GLuint MVPMatrixID;
};
}

View File

@ -0,0 +1,15 @@
#include "Context.hpp"
#include "../Renderer.hpp"
using namespace pass;
Context::Context(Renderer* Renderer, Program *Program):
renderer(Renderer), program(Program) { }
void Context::start() {
program->useIt();
program->start(renderer);
}
buffer::params Context::setup(glm::mat4 modelMatrix) {
return program->setup(renderer, modelMatrix);
}

View File

@ -0,0 +1,23 @@
#pragma once
#include "../buffer/Abstract.hpp"
#include <glm/glm.hpp>
class Renderer;
namespace pass {
class Program;
/// Program execution container
struct Context {
public:
Context(Renderer *Renderer, Program *Program);
/// Prepare for multiple draw
void start();
/// Prepare for specific draw
buffer::params setup(glm::mat4 modelMatrix);
private:
Renderer *renderer;
Program *program;
};
}

View File

@ -2,6 +2,8 @@
#include "../Renderer.hpp"
using namespace pass;
MainProgram::MainProgram(const MainProgram::options& opts): Program() {
std::vector<std::string> flags;
@ -47,12 +49,12 @@ void MainProgram::start(Renderer *renderer) {
setLightInvDir(&renderer->LightInvDir[0]);
setFog(&renderer->FogColor[0], renderer->FogDepth);
}
Buffer::params MainProgram::setup(Renderer *renderer, glm::mat4 modelMatrix) {
buffer::params MainProgram::setup(Renderer *renderer, glm::mat4 modelMatrix) {
setModel(&modelMatrix[0][0]);
setView(&renderer->getViewMatrix()[0][0]);
const auto mvp = renderer->getProjectionMatrix() * renderer->getViewMatrix() * modelMatrix;
setMVP(&mvp[0][0]);
return Buffer::params{.vertexOnly = false};
return buffer::params{.vertexOnly = false};
}
void MainProgram::setMVP(const GLfloat *matrix) {

View File

@ -2,44 +2,51 @@
#include "Program.hpp"
/// Final pass
class MainProgram: public Program {
public:
struct options {
bool pbr = true;
bool triplanar = false;
bool blend = true;
bool fog = true;
namespace pass {
/// World voxels pass
class MainProgram: public Program {
public:
/// Pass options
struct options {
/// Apply light properties
bool pbr = true;
/// Triplanar texture mapping
bool triplanar = false;
/// Blend voxel with mixed materials
bool blend = true;
/// Depth fog
bool fog = true;
};
MainProgram(const options &opts);
~MainProgram();
std::string getName() const override;
void start(Renderer *) override;
buffer::params setup(Renderer *, glm::mat4 modelMatrix) override;
void setMVP(const GLfloat *matrix);
void setModel(const GLfloat *matrix);
void setView(const GLfloat *matrix);
void bindTexture(const GLuint textureID);
void bindNormal(const GLuint textureID);
void bindHOS(const GLuint textureID);
void setLightInvDir(const GLfloat *pos);
void setFog(const GLfloat *color, GLfloat depth);
private:
GLuint MVPMatrixID;
GLuint ModelMatrixID;
GLuint ViewMatrixID;
GLuint TextureID;
GLuint NormalID;
GLuint HOSID;
GLuint LightInvDirID;
GLuint FogDepthID;
GLuint FogColorID;
};
MainProgram(const options &opts);
~MainProgram();
std::string getName() const override;
void start(Renderer *) override;
Buffer::params setup(Renderer *, glm::mat4 modelMatrix) override;
void setMVP(const GLfloat *matrix);
void setModel(const GLfloat *matrix);
void setView(const GLfloat *matrix);
void bindTexture(const GLuint textureID);
void bindNormal(const GLuint textureID);
void bindHOS(const GLuint textureID);
void setLightInvDir(const GLfloat *pos);
void setFog(const GLfloat *color, GLfloat depth);
private:
GLuint MVPMatrixID;
GLuint ModelMatrixID;
GLuint ViewMatrixID;
GLuint TextureID;
GLuint NormalID;
GLuint HOSID;
GLuint LightInvDirID;
GLuint FogDepthID;
GLuint FogColorID;
};
}

View File

@ -1,13 +0,0 @@
#include "PassContext.hpp"
#include "../Renderer.hpp"
PassContext::PassContext(Renderer* Renderer, Program *Program):
renderer(Renderer), program(Program) { }
void PassContext::start() {
program->useIt();
program->start(renderer);
}
Buffer::params PassContext::setup(glm::mat4 modelMatrix) {
return program->setup(renderer, modelMatrix);
}

View File

@ -1,19 +0,0 @@
#pragma once
#include "../buffer/Buffer.hpp"
#include <glm/glm.hpp>
class Renderer;
class Program;
/// Program execution container
struct PassContext {
public:
PassContext(Renderer *Renderer, Program *Program);
void start();
Buffer::params setup(glm::mat4 modelMatrix);
private:
Renderer *renderer;
Program *program;
};

View File

@ -8,6 +8,8 @@
#define SHADER_DIR CONTENT_DIR "shaders/"
#define TEXTURES_DIR CONTENT_DIR "textures/"
using namespace pass;
void Program::load(const std::vector<Shader*>& shaders) {
ProgramID = glCreateProgram();

View File

@ -6,27 +6,33 @@
#include <glm/glm.hpp>
#include "Shader.hpp"
#include "../buffer/Buffer.hpp"
#include "../buffer/Abstract.hpp"
class Renderer;
/// OpenGL shaders pipeline
class Program {
public:
virtual ~Program();
/// OpenGL programs
namespace pass {
/// OpenGL shaders pipeline
class Program {
public:
virtual ~Program();
void useIt();
virtual std::string getName() const = 0;
/// Bind program
void useIt();
virtual std::string getName() const = 0;
virtual void start(Renderer*) = 0;
virtual Buffer::params setup(Renderer*, glm::mat4 modelMatrix) = 0;
/// Prepare for multiple draw
virtual void start(Renderer*) = 0;
/// Prepare for specific draw
virtual buffer::params setup(Renderer*, glm::mat4 modelMatrix) = 0;
static GLuint loadTexture(const std::string &name, bool linear = true);
static GLuint loadRawTexture(const std::string &name);
static GLuint loadTextureArray(const std::vector<std::string> &names, const std::string &suffix = "", float mipMapLOD = 0);
static GLuint loadTextureCube(const std::string &name);
static GLuint loadTexture(const std::string &name, bool linear = true);
static GLuint loadRawTexture(const std::string &name);
static GLuint loadTextureArray(const std::vector<std::string> &names, const std::string &suffix = "", float mipMapLOD = 0);
static GLuint loadTextureCube(const std::string &name);
protected:
void load(const std::vector<Shader *> &shaders);
virtual Shader *loadShader(GLenum type, const std::vector<std::string> &flags = {});
GLuint ProgramID;
};
protected:
void load(const std::vector<Shader *> &shaders);
virtual Shader *loadShader(GLenum type, const std::vector<std::string> &flags = {});
GLuint ProgramID;
};
}

View File

@ -5,6 +5,8 @@
#include <fstream>
#include <sstream>
using namespace pass;
Shader::Shader(GLenum type, const std::string& file_path, const std::vector<std::string>& flags) {
ShaderID = glCreateShader(type);

View File

@ -4,32 +4,34 @@
#include <vector>
#include <GL/glew.h>
/// OpenGL shader
class Shader {
public:
Shader(GLenum type, const std::string &file_path, const std::vector<std::string> &flags = {});
~Shader();
namespace pass {
/// OpenGL shader
class Shader {
public:
Shader(GLenum type, const std::string &file_path, const std::vector<std::string> &flags = {});
~Shader();
GLuint getId() const {
return ShaderID;
}
static std::string getExt(GLenum type) {
switch (type) {
case GL_VERTEX_SHADER:
return "vs";
case GL_GEOMETRY_SHADER:
return "gs";
case GL_FRAGMENT_SHADER:
return "fs";
default:
return "??";
GLuint getId() const {
return ShaderID;
}
}
private:
GLuint ShaderID;
};
static std::string getExt(GLenum type) {
switch (type) {
case GL_VERTEX_SHADER:
return "vs";
case GL_GEOMETRY_SHADER:
return "gs";
case GL_FRAGMENT_SHADER:
return "fs";
default:
return "??";
}
}
private:
GLuint ShaderID;
};
}

View File

@ -2,6 +2,8 @@
#include "../Renderer.hpp"
using namespace pass;
const GLfloat g_cubemap_vertices[] = {
-1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
@ -70,8 +72,8 @@ void SkyProgram::start(Renderer *renderer) {
bindTexture(renderer->getSkyTexture());
}
Buffer::params SkyProgram::setup(Renderer *, glm::mat4) {
return Buffer::params{.vertexOnly = true};
buffer::params SkyProgram::setup(Renderer *, glm::mat4) {
return buffer::params{.vertexOnly = true};
}
void SkyProgram::draw(Renderer *renderer) {
useIt();

View File

@ -1,29 +1,32 @@
#pragma once
#include "Program.hpp"
#include "../buffer/VertexBuffer.hpp"
#include "../buffer/Vertex.hpp"
/// Skybox pass
class SkyProgram: public Program {
public:
SkyProgram();
~SkyProgram();
namespace pass {
/// Skybox pass
class SkyProgram: public Program {
public:
SkyProgram();
~SkyProgram();
std::string getName() const override;
void start(Renderer *) override;
Buffer::params setup(Renderer *, glm::mat4 modelMatrix) override;
std::string getName() const override;
void start(Renderer *) override;
buffer::params setup(Renderer *, glm::mat4 modelMatrix) override;
void draw(Renderer *);
/// Direct draw using internal buffer
void draw(Renderer *);
void setView(const GLfloat *matrix);
void setProjection(const GLfloat *matrix);
void setView(const GLfloat *matrix);
void setProjection(const GLfloat *matrix);
void bindTexture(const GLuint textureID);
void bindTexture(const GLuint textureID);
private:
GLuint ViewMatrixID;
GLuint ProjectionMatrixID;
GLuint TextureID;
private:
GLuint ViewMatrixID;
GLuint ProjectionMatrixID;
GLuint TextureID;
VertexBuffer CubeBuffer;
};
buffer::Vertex CubeBuffer;
};
}

View File

@ -1,5 +1,7 @@
#include "UIProgram.hpp"
using namespace pass;
UIProgram::UIProgram() : Program() {
std::vector<Shader*> shaders;
shaders.push_back(loadShader(GL_VERTEX_SHADER));

View File

@ -2,16 +2,18 @@
#include "Program.hpp"
/// Basic final pass
class UIProgram: public Program {
public:
UIProgram();
~UIProgram();
namespace pass {
/// To screen texture pass
class UIProgram: public Program {
public:
UIProgram();
~UIProgram();
std::string getName() const override;
std::string getName() const override;
void bindTexture(GLuint textureID);
void bindTexture(GLuint textureID);
private:
GLuint TextureID;
};
private:
GLuint TextureID;
};
}

View File

@ -9,12 +9,12 @@
#include <fstream>
#include <filesystem>
#include <optional>
#include "glm.hpp"
#include "circular_buffer.hpp"
#include "../render/Renderer.hpp"
#include "../world/World.hpp"
#include "../control/Camera.hpp"
#include "../contouring/index.hpp"
#include "data/glm.hpp"
#include "data/circular_buffer.hpp"
#include "render/Renderer.hpp"
#include "world/Universe.hpp"
#include "control/Camera.hpp"
#include "contouring/index.hpp"
inline ImColor fromHex(const std::string& str) {
int rgb[3] = {UCHAR_MAX};
@ -30,6 +30,7 @@ inline std::string toHexa(const ImVec4& rgba) {
/// Savable game options
struct options {
const char *PATH = "config.toml";
/// Load from PATH
options() {
auto config = std::filesystem::exists(PATH) ? toml::parse_file(PATH) : toml::table();
target_fps = config["window"]["fps"].value_or(60);
@ -76,6 +77,7 @@ struct options {
tool.material = config["editor"]["tool"]["material"].value_or<int>(tool.material);
tool.radius = config["editor"]["tool"]["radius"].value_or(tool.radius);
}
/// Write to PATH
void save() {
auto config = toml::table();
config.insert_or_assign("window", toml::table({
@ -149,7 +151,7 @@ struct options {
Renderer::options renderer;
bool show_debug_world;
World::options world;
world::Universe::options world;
float voxel_size;
bool show_debug_contouring;
@ -163,7 +165,7 @@ struct options {
bool editor_show;
struct tool {
int radius = 2;
unsigned long long material = 2;
unsigned short material = 2;
} tool;
bool overlay_show;
@ -177,7 +179,7 @@ struct options {
struct state {
bool capture_mouse = true;
camera_pos position;
std::optional<std::pair<voxel_pos, Voxel>> look_at = {};
std::optional<std::pair<voxel_pos, world::Voxel>> look_at = {};
std::shared_ptr<contouring::Abstract> contouring;
@ -195,5 +197,5 @@ struct reports {
circular_buffer<float> swap = circular_buffer<float>(REPORT_BUFFER_SIZE, 0);
circular_buffer<float> wait = circular_buffer<float>(REPORT_BUFFER_SIZE, 0);
} main;
World::report world;
world::Universe::report world;
};

View File

@ -3,6 +3,8 @@
#include <FastNoiseSIMD.h>
#include "materials.hpp"
using namespace world;
#define DENSITY 0.f
#define GRANULARITY 30.f
@ -28,6 +30,17 @@ std::optional<Faces> Chunk::update() {
}
}
void Chunk::set(ushort idx, const Voxel& val) {
voxels[idx] = val;
invalidate(
((!getNeighborIdx(idx, Face::Up).has_value()) & Faces::Up) |
((!getNeighborIdx(idx, Face::Down).has_value()) & Faces::Down) |
((!getNeighborIdx(idx, Face::Left).has_value()) & Faces::Left) |
((!getNeighborIdx(idx, Face::Right).has_value()) & Faces::Right) |
((!getNeighborIdx(idx, Face::Forward).has_value()) & Faces::Forward) |
((!getNeighborIdx(idx, Face::Backward).has_value()) & Faces::Backward));
}
std::optional<ushort> Chunk::getNeighborIdx(ushort idx, Face face) {
switch (face) {
case Face::Forward:

View File

@ -4,72 +4,70 @@
#include "Voxel.hpp"
#include "../data/geometry/Faces.hpp"
/// Chunk length
#define CHUNK_LENGTH 32
#define CHUNK_LENGTH2 (CHUNK_LENGTH * CHUNK_LENGTH)
#define CHUNK_SIZE (CHUNK_LENGTH2 * CHUNK_LENGTH)
/// World part as linear 3d voxel array
struct Chunk {
public:
Chunk(const chunk_pos& pos, Generator& rnd);
~Chunk();
namespace world {
using namespace geometry;
/// World part as linear 3d voxel array
struct Chunk {
public:
Chunk(const chunk_pos& pos, Generator& rnd);
~Chunk();
/// Update voxels
/// @return if modified neightbors to update
std::optional<Faces> update();
/// Update voxels
/// @return if modified neighbors to update
std::optional<Faces> update();
const Voxel* begin() const {
return voxels.begin();
}
inline void invalidate(Faces faces) {
upToDate = false;
toUpdate = toUpdate | faces;
modified = true;
}
inline const Voxel& get(ushort idx) const {
return voxels[idx];
}
const Voxel& getAt(const chunk_voxel_pos& pos) const {
return get(getIdx(pos));
}
void set(ushort idx, const Voxel& val) {
voxels[idx] = val;
invalidate(
((!getNeighborIdx(idx, Face::Up).has_value()) & Faces::Up) |
((!getNeighborIdx(idx, Face::Down).has_value()) & Faces::Down) |
((!getNeighborIdx(idx, Face::Left).has_value()) & Faces::Left) |
((!getNeighborIdx(idx, Face::Right).has_value()) & Faces::Right) |
((!getNeighborIdx(idx, Face::Forward).has_value()) & Faces::Forward) |
((!getNeighborIdx(idx, Face::Backward).has_value()) & Faces::Backward));
}
void setAt(const chunk_voxel_pos& pos, const Voxel& val) {
set(getIdx(pos), val);
}
Item breakAt(const chunk_voxel_pos& pos, const Voxel& val) {
const auto idx = getIdx(pos);
const auto res = voxels[idx];
set(idx, val);
return Item{res.Density, res.Material};
}
// Notify for render
inline void invalidate(Faces faces) {
upToDate = false;
toUpdate = toUpdate | faces;
modified = true;
}
// Get voxel from index
inline const Voxel& get(ushort idx) const {
return voxels[idx];
}
// Get voxel from position
inline const Voxel& getAt(const chunk_voxel_pos& pos) const {
return get(getIdx(pos));
}
// Set voxel from index
void set(ushort idx, const Voxel& val);
// Set voxel from position
void setAt(const chunk_voxel_pos& pos, const Voxel& val) {
set(getIdx(pos), val);
}
// Break voxel
Item breakAt(const chunk_voxel_pos& pos, const Voxel& val) {
const auto idx = getIdx(pos);
const auto res = voxels[idx];
set(idx, val);
return Item{res.Density, res.Material};
}
static inline chunk_voxel_pos getPosition(ushort idx) {
return chunk_voxel_pos(idx / CHUNK_LENGTH2, (idx / CHUNK_LENGTH) % CHUNK_LENGTH, idx % CHUNK_LENGTH);
}
static inline ushort getIdx(chunk_voxel_pos pos) {
return getIdx(pos.x, pos.y, pos.z);
}
static inline ushort getIdx(uint x, uint y, uint z) {
return (x * CHUNK_LENGTH + y) * CHUNK_LENGTH + z;
}
static std::optional<ushort> getNeighborIdx(ushort idx, Face dir);
static inline chunk_voxel_pos getPosition(ushort idx) {
return chunk_voxel_pos(idx / CHUNK_LENGTH2, (idx / CHUNK_LENGTH) % CHUNK_LENGTH, idx % CHUNK_LENGTH);
}
static inline ushort getIdx(chunk_voxel_pos pos) {
return getIdx(pos.x, pos.y, pos.z);
}
static inline ushort getIdx(uint x, uint y, uint z) {
return (x * CHUNK_LENGTH + y) * CHUNK_LENGTH + z;
}
static std::optional<ushort> getNeighborIdx(ushort idx, Face dir);
private:
/// Chunk data
std::array<Voxel, CHUNK_SIZE> voxels;
/// Require update
bool upToDate = true;
/// Neighbors to update
Faces toUpdate = Faces::None;
/// Modified by player
bool modified = false;
};
private:
/// Chunk data
std::array<Voxel, CHUNK_SIZE> voxels;
/// Require update
bool upToDate = true;
/// Neighbors to update
Faces toUpdate = Faces::None;
/// Modified by player
bool modified = false;
};
}

View File

@ -4,33 +4,38 @@
#include <tuple>
#include "../data/glm.hpp"
class Generator {
public:
Generator(int seed = 42) {
densityNoise = FastNoiseSIMD::NewFastNoiseSIMD(seed);
materialNoise = FastNoiseSIMD::NewFastNoiseSIMD(seed * 5);
materialNoise->SetNoiseType(FastNoiseSIMD::Cellular); // NOTE: probably heavy
materialNoise->SetCellularReturnType(FastNoiseSIMD::CellValue);
materialNoise->SetCellularDistanceFunction(FastNoiseSIMD::Natural);
materialNoise->SetFrequency(.1);
}
~Generator() {
delete densityNoise;
delete materialNoise;
}
namespace world {
/// Noise generator
class Generator {
public:
Generator(int seed = 42) {
densityNoise = FastNoiseSIMD::NewFastNoiseSIMD(seed);
materialNoise = FastNoiseSIMD::NewFastNoiseSIMD(seed * 5);
materialNoise->SetNoiseType(FastNoiseSIMD::Cellular); // NOTE: probably heavy
materialNoise->SetCellularReturnType(FastNoiseSIMD::CellValue);
materialNoise->SetCellularDistanceFunction(FastNoiseSIMD::Natural);
materialNoise->SetFrequency(.1);
}
~Generator() {
delete densityNoise;
delete materialNoise;
}
inline std::pair<float*, float*> getChunk(const chunk_pos& pos, int size) {
return {
densityNoise->GetNoiseSet(pos.x * size, pos.y * size, pos.z * size, size, size, size),
materialNoise->GetNoiseSet(pos.x * size, pos.y * size, pos.z * size, size, size, size),
};
}
inline void freeChunk(std::pair<float*, float*>& set) {
FastNoiseSIMD::FreeNoiseSet(set.first);
FastNoiseSIMD::FreeNoiseSet(set.second);
}
/// Get block of given size with index pos.
/// @note owning pointers, @see FastNoiseSIMD::FreeNoiseSet
inline std::pair<float*, float*> getChunk(const chunk_pos& pos, int size) {
return {
densityNoise->GetNoiseSet(pos.x * size, pos.y * size, pos.z * size, size, size, size),
materialNoise->GetNoiseSet(pos.x * size, pos.y * size, pos.z * size, size, size, size),
};
}
inline void freeChunk(std::pair<float*, float*>& set) {
FastNoiseSIMD::FreeNoiseSet(set.first);
FastNoiseSIMD::FreeNoiseSet(set.second);
}
private:
FastNoiseSIMD *densityNoise;
FastNoiseSIMD *materialNoise;
};
private:
FastNoiseSIMD *densityNoise;
FastNoiseSIMD *materialNoise;
};
}

View File

@ -1,16 +1,18 @@
#include "World.hpp"
#include "Universe.hpp"
#include "../contouring/Dummy.hpp"
#include <Remotery.h>
World::World(const World::options &options): loadPool(2), contouring(std::make_shared<contouring::Dummy>()) {
using namespace world;
Universe::Universe(const Universe::options &options): loadPool(2), contouring(std::make_shared<contouring::Dummy>()) {
setOptions(options);
}
World::~World() {
Universe::~Universe() {
contouring = NULL;
}
World::LoadPool::LoadPool(size_t count) {
Universe::LoadPool::LoadPool(size_t count) {
for (size_t i = 0; i < count; i++) {
workers.push_back(std::thread([&] {
while (running) {
@ -24,7 +26,7 @@ World::LoadPool::LoadPool(size_t count) {
}));
}
}
World::LoadPool::~LoadPool() {
Universe::LoadPool::~LoadPool() {
running = false;
loadQueue.notify();
@ -33,15 +35,15 @@ World::LoadPool::~LoadPool() {
worker.join();
}
}
inline void World::LoadPool::push(const chunk_pos &pos, int weight) { loadQueue.push(pos, weight); }
inline bool World::LoadPool::pop(robin_hood::pair<chunk_pos, std::shared_ptr<Chunk>> &out) { return loadedQueue.pop(out); }
inline size_t World::LoadPool::size() { return loadQueue.size(); }
inline void Universe::LoadPool::push(const chunk_pos &pos, int weight) { loadQueue.push(pos, weight); }
inline bool Universe::LoadPool::pop(robin_hood::pair<chunk_pos, std::shared_ptr<Chunk>> &out) { return loadedQueue.pop(out); }
inline size_t Universe::LoadPool::size() { return loadQueue.size(); }
void World::update(const camera_pos& pos, World::report& rep) {
void Universe::update(const camera_pos& pos, Universe::report& rep) {
const chunk_pos newPos = glm::divide(pos, chunk_voxel_pos(CHUNK_LENGTH));
const auto chunkChange = newPos != last_pos;
last_pos = newPos;
rmt_ScopedCPUSample(World, 0);
rmt_ScopedCPUSample(Universe, 0);
// Update alive chunks
{
@ -104,17 +106,17 @@ void World::update(const camera_pos& pos, World::report& rep) {
}
rep.chunk_count.push(chunks.size());
}
void World::setOptions(const World::options& options) {
void Universe::setOptions(const Universe::options& options) {
loadDistance = options.loadDistance;
keepDistance = options.keepDistance;
}
void World::setContouring(std::shared_ptr<contouring::Abstract> ct) {
void Universe::setContouring(std::shared_ptr<contouring::Abstract> ct) {
contouring = ct;
last_pos = chunk_pos(INT_MAX); // trigger chunkChange on next update
}
std::optional<std::pair<voxel_pos, Voxel>> World::raycast(const Ray &ray) const {
std::optional<std::pair<voxel_pos, Voxel>> Universe::raycast(const Ray &ray) const {
std::vector<voxel_pos> points;
ray.grid(points);
std::shared_ptr<Chunk> chunk = NULL;
@ -136,7 +138,7 @@ std::optional<std::pair<voxel_pos, Voxel>> World::raycast(const Ray &ray) const
return {};
}
std::optional<Item> World::set(const voxel_pos& pos, const Voxel& val) {
std::optional<Item> Universe::set(const voxel_pos& pos, const Voxel& val) {
const auto chunkPos = glm::divide(pos, glm::ivec3(CHUNK_LENGTH));
if(const auto& chunk = at(chunkPos)) {
return {chunk.value()->breakAt(glm::modulo(pos, glm::ivec3(CHUNK_LENGTH)), val)};
@ -144,7 +146,7 @@ std::optional<Item> World::set(const voxel_pos& pos, const Voxel& val) {
return {};
}
}
ItemList World::setCube(const voxel_pos& pos, const Voxel& val, int radius) {
ItemList Universe::setCube(const voxel_pos& pos, const Voxel& val, int radius) {
ItemList list;
for (int z = -radius; z <= radius; z++) {
for (int y = -radius; y <= radius; y++) {

104
src/world/Universe.hpp Normal file
View File

@ -0,0 +1,104 @@
#pragma once
#include <memory>
#include <thread>
#include "../data/unique_queue.hpp"
#include "../data/safe_queue.hpp"
#include "../data/safe_priority_queue.hpp"
#include "../data/circular_buffer.hpp"
#include "Chunk.hpp"
#include "../data/geometry/Ray.hpp"
#define REPORT_BUFFER_SIZE 128
namespace contouring {
class Abstract;
};
using namespace data;
/// Universe data
namespace world {
/// Whole universe container
class Universe {
public:
/// Distance management
struct options {
/// Radius in chunks to load if missing
int loadDistance = 5;
/// Radius in chunks to keep in memory
int keepDistance = 6;
};
/// Reports to UI
struct report {
/// Chunks in memory
circular_buffer<float> chunk_count = circular_buffer<float>(REPORT_BUFFER_SIZE, 0); // MAYBE: store int
/// Loaded chunks
circular_buffer<float> chunk_load = circular_buffer<float>(REPORT_BUFFER_SIZE, 0);
/// Saved chunks
circular_buffer<float> chunk_unload = circular_buffer<float>(REPORT_BUFFER_SIZE, 0);
};
Universe(const options&);
~Universe();
/// Update physics and contouring
void update(const camera_pos& pos, report& rep);
/// Apply new options
void setOptions(const options &);
/// Get nearest voxel colliding ray
/// @note ray in world scale
std::optional<std::pair<voxel_pos, Voxel>> raycast(const geometry::Ray &ray) const;
/// Set voxel at pos
std::optional<Item> set(const voxel_pos &pos, const Voxel &val);
/// Set cube of voxel with pos as center
ItemList setCube(const voxel_pos &pos, const Voxel &val, int radius);
/// Change contouring worker
void setContouring(std::shared_ptr<contouring::Abstract>);
/// Get current contouring worker
std::shared_ptr<contouring::Abstract> getContouring() const {
return contouring;
}
private:
chunk_pos last_pos = chunk_pos(INT_MAX);
/// Data
robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> chunks;
std::optional<std::shared_ptr<Chunk>> at(const chunk_pos& pos) const {
const auto it = chunks.find(pos);
if(it == chunks.end())
return {};
return {it->second};
}
/// Generating worker pool
class LoadPool {
public:
LoadPool(size_t size);
~LoadPool();
Generator generator;
inline void push(const chunk_pos &pos, int weight);
inline bool pop(robin_hood::pair<chunk_pos, std::shared_ptr<Chunk>> &out);
inline size_t size();
private:
std::vector<std::thread> workers;
bool running = true;
safe_priority_queue<chunk_pos, int> loadQueue;
safe_queue<robin_hood::pair<chunk_pos, std::shared_ptr<Chunk>>> loadedQueue;
};
LoadPool loadPool;
unique_queue<chunk_pos> unloadQueue;
int loadDistance;
int keepDistance;
/// Contouring worker
std::shared_ptr<contouring::Abstract> contouring;
};
}

View File

@ -2,18 +2,29 @@
#include <map>
struct Voxel {
unsigned char Density;
unsigned short Material;
};
struct Item {
unsigned long long Count;
unsigned short Material;
};
struct ItemList: std::map<unsigned short, unsigned long long> {
void add(const std::optional<Item>& item) {
if(item) {
(*this)[item.value().Material] += item.value().Count;
namespace world {
/// Universe unit
struct Voxel {
/// Quantity of material
unsigned char Density;
/// Material type
/// @see world::materials
unsigned short Material;
};
/// Stock of material
struct Item {
/// Quantity of material
unsigned long long Count;
/// Material type
/// @see world::materials
unsigned short Material;
};
/// List of materials
struct ItemList: std::map<unsigned short, unsigned long long> {
void add(const std::optional<Item>& item) {
if(item) {
(*this)[item.value().Material] += item.value().Count;
}
}
}
};
};
}

View File

@ -1,84 +0,0 @@
#pragma once
#include <memory>
#include <thread>
#include "../data/unique_queue.hpp"
#include "../data/safe_queue.hpp"
#include "../data/safe_priority_queue.hpp"
#include "../data/circular_buffer.hpp"
#include "Chunk.hpp"
#include "../data/geometry/Ray.hpp"
#define REPORT_BUFFER_SIZE 128
namespace contouring {
class Abstract;
};
class World {
public:
struct options {
int loadDistance = 5;
int keepDistance = 6;
};
struct report {
circular_buffer<float> chunk_count = circular_buffer<float>(REPORT_BUFFER_SIZE, 0); // MAYBE: store int
circular_buffer<float> chunk_load = circular_buffer<float>(REPORT_BUFFER_SIZE, 0);
circular_buffer<float> chunk_unload = circular_buffer<float>(REPORT_BUFFER_SIZE, 0);
};
World(const options&);
~World();
void update(const camera_pos& pos, report& rep);
void setOptions(const options &);
std::optional<std::shared_ptr<Chunk>> at(const chunk_pos& pos) const {
const auto it = chunks.find(pos);
if(it == chunks.end())
return {};
return {it->second};
}
std::optional<std::pair<voxel_pos, Voxel>> raycast(const Ray &ray) const;
std::optional<Item> set(const voxel_pos &pos, const Voxel &val);
ItemList setCube(const voxel_pos &pos, const Voxel &val, int radius);
/// Change contouring worker
void setContouring(std::shared_ptr<contouring::Abstract>);
/// Get current contouring worker
std::shared_ptr<contouring::Abstract> getContouring() const {
return contouring;
}
private:
chunk_pos last_pos = chunk_pos(INT_MAX);
robin_hood::unordered_map<chunk_pos, std::shared_ptr<Chunk>> chunks;
/// Generating worker pool
class LoadPool {
public:
LoadPool(size_t size);
~LoadPool();
Generator generator;
inline void push(const chunk_pos &pos, int weight);
inline bool pop(robin_hood::pair<chunk_pos, std::shared_ptr<Chunk>> &out);
inline size_t size();
private:
std::vector<std::thread> workers;
bool running = true;
safe_priority_queue<chunk_pos, int> loadQueue;
safe_queue<robin_hood::pair<chunk_pos, std::shared_ptr<Chunk>>> loadedQueue;
};
LoadPool loadPool;
unique_queue<chunk_pos> unloadQueue;
int loadDistance;
int keepDistance;
/// Contouring worker
std::shared_ptr<contouring::Abstract> contouring;
};

View File

@ -3,8 +3,12 @@
#include <array>
#include <string>
namespace materials {
namespace world::materials {
/// Materials count
static const auto count = 9;
/// Materials textures
static const std::array<std::string, count> textures = {{"Air", "Sand", "Dirt", "Stone_path", "Mapl", "Seaside_rock", "Stone_wall", "Rough_rock", "Alien"}};
/// Materials roughness.
/// -1: slope, 0: normal, 1: cube
static const std::array<float, count> roughness = {{0, 0, 0, 0, 0, 0, 0, -1, .8}};
}