Render API
This commit is contained in:
parent
a3d9a157f3
commit
d95b9eefee
|
@ -27,9 +27,7 @@ void Client::run(server_handle* const localHandle) {
|
||||||
pipeline->LightInvDir = glm::normalize(glm::vec3(-.5f, 2, -2));
|
pipeline->LightInvDir = glm::normalize(glm::vec3(-.5f, 2, -2));
|
||||||
render::Renderer::Get()->loadUI(window);
|
render::Renderer::Get()->loadUI(window);
|
||||||
|
|
||||||
auto world = world::client::Load(options.connection, localHandle, options.world);
|
auto world = world::client::Load(options.connection, localHandle, options.world, options.contouring);
|
||||||
|
|
||||||
world->setContouring(contouring::load(options.contouring.idx, options.contouring.data));
|
|
||||||
state.contouring = world->getContouring();
|
state.contouring = world->getContouring();
|
||||||
|
|
||||||
//TODO: loop
|
//TODO: loop
|
||||||
|
@ -115,10 +113,8 @@ void Client::run(server_handle* const localHandle) {
|
||||||
if(actions && render::UI::Actions::Control) {
|
if(actions && render::UI::Actions::Control) {
|
||||||
player.setOptions(options.control);
|
player.setOptions(options.control);
|
||||||
}
|
}
|
||||||
if(actions && render::UI::Actions::ChangeContouring) {
|
if(actions && render::UI::Actions::FillMode) {
|
||||||
state.contouring = NULL;
|
//TODO: pipeline->setFillMode(options.renderer.wireframe);
|
||||||
world->setContouring(contouring::load(options.contouring.idx, options.contouring.data));
|
|
||||||
state.contouring = world->getContouring();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{ // Rendering
|
{ // Rendering
|
||||||
|
@ -134,10 +130,10 @@ void Client::run(server_handle* const localHandle) {
|
||||||
const auto offset = state.position.raw_as_long();
|
const auto offset = state.position.raw_as_long();
|
||||||
{ // Chunks
|
{ // Chunks
|
||||||
const auto pass = pipeline->beginWorldPass();
|
const auto pass = pipeline->beginWorldPass();
|
||||||
const auto draw = [&](glm::mat4 model, buffer::Abstract *const buffer, const contouring::Abstract::area_info &area, const voxel_pos &pos) {
|
const auto draw = [&](glm::mat4 model, render::LodModel *const buffer, const contouring::Abstract::area_info &area, const voxel_pos &pos) {
|
||||||
pipeline->setCurvature(glm::vec4(pos, std::get<1>(area)), std::get<2>(area));
|
pipeline->setCurvature(glm::vec4(pos, std::get<1>(area)), std::get<2>(area));
|
||||||
reports.models_count++;
|
reports.models_count++;
|
||||||
reports.tris_count += buffer->draw(pass(model));
|
reports.tris_count += pass(buffer, model);
|
||||||
};
|
};
|
||||||
if (options.culling > 0) {
|
if (options.culling > 0) {
|
||||||
std::vector<glm::vec3> occlusion;
|
std::vector<glm::vec3> occlusion;
|
||||||
|
@ -188,5 +184,5 @@ void Client::run(server_handle* const localHandle) {
|
||||||
render::Renderer::Unload();
|
render::Renderer::Unload();
|
||||||
window.destroy();
|
window.destroy();
|
||||||
|
|
||||||
contouring::save(options.contouring.idx, state.contouring, options.contouring.data);
|
options.contouring = state.contouring->getOptions();
|
||||||
}
|
}
|
|
@ -6,7 +6,7 @@
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include "world/Universe.hpp"
|
#include "world/Universe.hpp"
|
||||||
#include "render/Renderer.hpp"
|
#include "render/Renderer.hpp"
|
||||||
#include "contouring/index.hpp"
|
#include "contouring/Abstract.hpp"
|
||||||
#include "control/Camera.hpp"
|
#include "control/Camera.hpp"
|
||||||
|
|
||||||
namespace config::client {
|
namespace config::client {
|
||||||
|
@ -50,10 +50,7 @@ public:
|
||||||
renderer.voxel.curv_depth = config["render"]["curvature_depth"].value_or(renderer.voxel.curv_depth);
|
renderer.voxel.curv_depth = config["render"]["curvature_depth"].value_or(renderer.voxel.curv_depth);
|
||||||
culling = config["render"]["culling"].value_or(culling);
|
culling = config["render"]["culling"].value_or(culling);
|
||||||
|
|
||||||
contouring.idx = contouring::idxByName(config["contouring"]["mode"].value_or(std::string("")));
|
contouring = config["contouring"].value_or(std::string(""));
|
||||||
for(const auto& name: contouring::names) {
|
|
||||||
contouring.data.emplace(name, config["contouring"]["options"][name].value_or(std::string("")));
|
|
||||||
}
|
|
||||||
|
|
||||||
camera.far = config["camera"]["far"].value_or(camera.far);
|
camera.far = config["camera"]["far"].value_or(camera.far);
|
||||||
camera.near = config["camera"]["near"].value_or(camera.near);
|
camera.near = config["camera"]["near"].value_or(camera.near);
|
||||||
|
@ -120,14 +117,7 @@ public:
|
||||||
{"curvature_depth", renderer.voxel.curv_depth},
|
{"curvature_depth", renderer.voxel.curv_depth},
|
||||||
{"culling", culling}
|
{"culling", culling}
|
||||||
}));
|
}));
|
||||||
config.insert_or_assign("contouring", toml::table({
|
config.insert_or_assign("contouring", contouring);
|
||||||
{"mode", contouring::names[contouring.idx]},
|
|
||||||
{"options", toml::table()}
|
|
||||||
}));
|
|
||||||
for(const auto& [key, val]: contouring.data) {
|
|
||||||
if(!val.empty())
|
|
||||||
config["contouring"]["options"].as_table()->insert_or_assign(key, val);
|
|
||||||
}
|
|
||||||
config.insert_or_assign("camera", toml::table({
|
config.insert_or_assign("camera", toml::table({
|
||||||
{"far", camera.far},
|
{"far", camera.far},
|
||||||
{"near", camera.near},
|
{"near", camera.near},
|
||||||
|
@ -199,10 +189,7 @@ public:
|
||||||
render::renderOptions renderer;
|
render::renderOptions renderer;
|
||||||
int culling = 0;
|
int culling = 0;
|
||||||
|
|
||||||
struct {
|
std::string contouring;
|
||||||
int idx;
|
|
||||||
std::map<std::string, std::string> data;
|
|
||||||
} contouring;
|
|
||||||
|
|
||||||
Controllable::options control;
|
Controllable::options control;
|
||||||
Camera::options camera;
|
Camera::options camera;
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../render/gl/buffer/Abstract.hpp"
|
|
||||||
#include "../../core/world/forward.h"
|
#include "../../core/world/forward.h"
|
||||||
#include "../../core/geometry/Frustum.hpp"
|
#include "../../core/geometry/Frustum.hpp"
|
||||||
#include "../../core/geometry/Ray.hpp"
|
#include "../../core/geometry/Ray.hpp"
|
||||||
#include "../../core/geometry/Faces.hpp"
|
#include "../../core/geometry/Faces.hpp"
|
||||||
|
|
||||||
|
namespace render { class LodModel; }
|
||||||
/// Mesh creation (from world to render)
|
/// Mesh creation (from world to render)
|
||||||
namespace contouring {
|
namespace contouring {
|
||||||
/// Generating mesh from world data
|
/// Generating mesh from world data
|
||||||
|
@ -35,7 +35,7 @@ namespace contouring {
|
||||||
virtual size_t getQueueSize() = 0;
|
virtual size_t getQueueSize() = 0;
|
||||||
|
|
||||||
using area_info = std::tuple<area_pos, voxel_pos::value_type, float>;
|
using area_info = std::tuple<area_pos, voxel_pos::value_type, float>;
|
||||||
using draw_call = const std::function<void(glm::mat4, buffer::Abstract *const, const area_info&, const voxel_pos&)> &;
|
using draw_call = const std::function<void(glm::mat4, render::LodModel *const, const area_info&, const voxel_pos&)> &;
|
||||||
|
|
||||||
/// Get buffers in frustum with model matrices
|
/// Get buffers in frustum with model matrices
|
||||||
/// @note buffers invalidated after update
|
/// @note buffers invalidated after update
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Abstract.hpp"
|
|
||||||
|
|
||||||
namespace contouring {
|
|
||||||
/// Useless contouring
|
|
||||||
class Dummy: public Abstract {
|
|
||||||
public:
|
|
||||||
Dummy(): Abstract() { }
|
|
||||||
virtual ~Dummy() { }
|
|
||||||
|
|
||||||
void update(const voxel_pos &, const world::client::area_map &) override {}
|
|
||||||
void onUpdate(const area_<chunk_pos> &, const chunk_pos &, const world::ChunkContainer &, geometry::Faces) override {}
|
|
||||||
void onNotify(const area_<chunk_pos> &, const chunk_pos &, const world::ChunkContainer &) override {}
|
|
||||||
void onGui() override { }
|
|
||||||
std::string getOptions() const override { return ""; }
|
|
||||||
std::pair<float, float> getFarRange() const override { return std::make_pair(0, 0); }
|
|
||||||
size_t getQueueSize() override { return 0; }
|
|
||||||
void getModels(draw_call, const std::optional<geometry::Frustum> &, const glm::llvec3 &, int) override {}
|
|
||||||
void getModels(draw_call, const glm::ifvec3 &, float, const std::vector<glm::vec3> &, const glm::llvec3 &, int) override {}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -41,14 +41,15 @@ namespace contouring {
|
||||||
#if TRACY_ENABLE
|
#if TRACY_ENABLE
|
||||||
tracy::SetThreadName("Contouring");
|
tracy::SetThreadName("Contouring");
|
||||||
#endif
|
#endif
|
||||||
std::vector<buffer::VertexData> tmp;
|
std::vector<render::VertexData> tmp;
|
||||||
while (running) {
|
while (running) {
|
||||||
std::pair<area_<chunk_pos>, surrounding::corners> ctx;
|
std::pair<area_<chunk_pos>, surrounding::corners> ctx;
|
||||||
loadQueue.wait();
|
loadQueue.wait();
|
||||||
if (loadQueue.pop(ctx)) {
|
if (loadQueue.pop(ctx)) {
|
||||||
ZoneScopedN("ProcessContouring");
|
ZoneScopedN("ProcessContouring");
|
||||||
buffer::LodShortIndexed::LodData data;
|
render::LodModel::LodData data;
|
||||||
render(ctx.second, data, tmp);
|
render(ctx.second, data, tmp);
|
||||||
|
//TODO: direct upload with vulkan
|
||||||
loadedQueue.emplace(ctx.first, data);
|
loadedQueue.emplace(ctx.first, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,12 +122,12 @@ namespace contouring {
|
||||||
|
|
||||||
void FlatDualMC::update(const voxel_pos& pos, const world::client::area_map& areas) {
|
void FlatDualMC::update(const voxel_pos& pos, const world::client::area_map& areas) {
|
||||||
ZoneScopedN("Ct");
|
ZoneScopedN("Ct");
|
||||||
std::pair<area_<chunk_pos>, buffer::LodShortIndexed::LodData> out;
|
std::pair<area_<chunk_pos>, render::LodModel::LodData> out;
|
||||||
TracyPlot("CtLoad", static_cast<int64_t>(loadQueue.size()));
|
TracyPlot("CtLoad", static_cast<int64_t>(loadQueue.size()));
|
||||||
//MAYBE: clear out of range loadQueue.trim(keepDistance * keepDistance)
|
//MAYBE: clear out of range loadQueue.trim(keepDistance * keepDistance)
|
||||||
TracyPlot("CtLoaded", static_cast<int64_t>(loadedQueue.size()));
|
TracyPlot("CtLoaded", static_cast<int64_t>(loadedQueue.size()));
|
||||||
for(auto handle = loadedQueue.extractor(); handle.first(out);) {
|
for(auto handle = loadedQueue.extractor(); handle.first(out);) {
|
||||||
const auto buffer = out.second.first.empty() ? NULL : new buffer::LodShortIndexed(GL_TRIANGLES, out.second);
|
const auto buffer = out.second.first.empty() ? NULL : render::LodModel::Create(out.second).release();
|
||||||
auto &bfs = buffers[out.first.first].second; //NOTE: buffer.first uninitialized (will be set in clear())
|
auto &bfs = buffers[out.first.first].second; //NOTE: buffer.first uninitialized (will be set in clear())
|
||||||
if (const auto it = bfs.find(out.first.second); it != bfs.end()) {
|
if (const auto it = bfs.find(out.first.second); it != bfs.end()) {
|
||||||
if(it->second != NULL)
|
if(it->second != NULL)
|
||||||
|
@ -163,7 +164,7 @@ namespace contouring {
|
||||||
it = bfs.erase(it);
|
it = bfs.erase(it);
|
||||||
} else {
|
} else {
|
||||||
if(it->second != NULL) {
|
if(it->second != NULL) {
|
||||||
static_cast<buffer::LodShortIndexed*>(it->second)->setLevel(std::clamp<size_t>((1+lod_quality-distRatio)*levelMax*(1+lod_strength), 0, levelMax));
|
it->second->setLevel(std::clamp<size_t>((1+lod_quality-distRatio)*levelMax*(1+lod_strength), 0, levelMax));
|
||||||
buffer_count++;
|
buffer_count++;
|
||||||
}
|
}
|
||||||
++it;
|
++it;
|
||||||
|
@ -212,7 +213,7 @@ namespace contouring {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlatDualMC::render(const surrounding::corners &surrounding, buffer::LodShortIndexed::LodData &out, std::vector<buffer::VertexData> &tmp) const {
|
void FlatDualMC::render(const surrounding::corners &surrounding, render::LodModel::LodData &out, std::vector<render::VertexData> &tmp) const {
|
||||||
const int SIZE = CHUNK_LENGTH + 3;
|
const int SIZE = CHUNK_LENGTH + 3;
|
||||||
std::array<dualmc::DualMC<float>::Point, SIZE * SIZE * SIZE> grid;
|
std::array<dualmc::DualMC<float>::Point, SIZE * SIZE * SIZE> grid;
|
||||||
{
|
{
|
||||||
|
@ -255,7 +256,7 @@ namespace contouring {
|
||||||
tmp.reserve(dmc_vertices.size());
|
tmp.reserve(dmc_vertices.size());
|
||||||
constexpr auto HALF_MANTISSA = 10;
|
constexpr auto HALF_MANTISSA = 10;
|
||||||
std::transform(dmc_vertices.begin(), dmc_vertices.end(), std::back_inserter(tmp), [](const dualmc::Vertex &v) {
|
std::transform(dmc_vertices.begin(), dmc_vertices.end(), std::back_inserter(tmp), [](const dualmc::Vertex &v) {
|
||||||
return buffer::VertexData(glm::vec3(meshopt_quantizeFloat(v.x, HALF_MANTISSA),meshopt_quantizeFloat(v.y, HALF_MANTISSA),
|
return render::VertexData(glm::vec3(meshopt_quantizeFloat(v.x, HALF_MANTISSA),meshopt_quantizeFloat(v.y, HALF_MANTISSA),
|
||||||
meshopt_quantizeFloat(v.z, HALF_MANTISSA)), v.w, glm::vec3(0));
|
meshopt_quantizeFloat(v.z, HALF_MANTISSA)), v.w, glm::vec3(0));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -285,8 +286,8 @@ namespace contouring {
|
||||||
}
|
}
|
||||||
|
|
||||||
out.second = simplify_lod(data.indices, tmp, loadedLevels);
|
out.second = simplify_lod(data.indices, tmp, loadedLevels);
|
||||||
std::transform(tmp.begin(), tmp.end(), std::back_inserter(data.vertices), [](const buffer::VertexData &v) {
|
std::transform(tmp.begin(), tmp.end(), std::back_inserter(data.vertices), [](const render::VertexData &v) {
|
||||||
return buffer::PackedVertexData(meshopt_quantizeHalf(v.Position.x), meshopt_quantizeHalf(v.Position.y),
|
return render::PackedVertexData(meshopt_quantizeHalf(v.Position.x), meshopt_quantizeHalf(v.Position.y),
|
||||||
meshopt_quantizeHalf(v.Position.z), v.Material,
|
meshopt_quantizeHalf(v.Position.z), v.Material,
|
||||||
meshopt_quantizeHalf(v.Normal.x), meshopt_quantizeHalf(v.Normal.y),
|
meshopt_quantizeHalf(v.Normal.x), meshopt_quantizeHalf(v.Normal.y),
|
||||||
meshopt_quantizeHalf(v.Normal.z));
|
meshopt_quantizeHalf(v.Normal.z));
|
||||||
|
|
|
@ -5,14 +5,14 @@
|
||||||
|
|
||||||
#include "../../core/data/safe_queue.hpp"
|
#include "../../core/data/safe_queue.hpp"
|
||||||
#include "../../core/data/safe_priority_queue.hpp"
|
#include "../../core/data/safe_priority_queue.hpp"
|
||||||
#include "../render/gl/buffer/LodShortIndexed.hpp"
|
#include "../render/api/Models.hpp"
|
||||||
#include "../../core/data/math.hpp"
|
#include "../../core/data/math.hpp"
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
using namespace data;
|
using namespace data;
|
||||||
namespace contouring {
|
namespace contouring {
|
||||||
/// Dual Marching Cube 1:1 contouring
|
/// Dual Marching Cube 1:1 contouring
|
||||||
class FlatDualMC: public Abstract {
|
class FlatDualMC final: public Abstract {
|
||||||
public:
|
public:
|
||||||
FlatDualMC(const std::string&);
|
FlatDualMC(const std::string&);
|
||||||
virtual ~FlatDualMC();
|
virtual ~FlatDualMC();
|
||||||
|
@ -39,10 +39,11 @@ namespace contouring {
|
||||||
void getModels(draw_call draw, const glm::ifvec3 &from, float far, const std::vector<glm::vec3> &occlusion, const glm::llvec3 &offset, int density) override;
|
void getModels(draw_call draw, const glm::ifvec3 &from, float far, const std::vector<glm::vec3> &occlusion, const glm::llvec3 &offset, int density) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
robin_hood::unordered_map<area_id, robin_hood::pair<area_info, robin_hood::unordered_map<chunk_pos, buffer::Abstract *>>> buffers;
|
//FIXME: use unique_ptr
|
||||||
|
robin_hood::unordered_map<area_id, robin_hood::pair<area_info, robin_hood::unordered_map<chunk_pos, render::LodModel*>>> buffers;
|
||||||
|
|
||||||
safe_priority_queue_map<area_<chunk_pos>, surrounding::corners, int, area_hash> loadQueue;
|
safe_priority_queue_map<area_<chunk_pos>, surrounding::corners, int, area_hash> loadQueue;
|
||||||
safe_queue<std::pair<area_<chunk_pos>, buffer::LodShortIndexed::LodData>> loadedQueue;
|
safe_queue<std::pair<area_<chunk_pos>, render::LodModel::LodData>> loadedQueue;
|
||||||
|
|
||||||
bool running = true;
|
bool running = true;
|
||||||
std::vector<std::thread> workers;
|
std::vector<std::thread> workers;
|
||||||
|
@ -61,6 +62,6 @@ namespace contouring {
|
||||||
|
|
||||||
std::vector<std::pair<float, float>> loadedLevels;
|
std::vector<std::pair<float, float>> loadedLevels;
|
||||||
|
|
||||||
void render(const surrounding::corners &surrounding, buffer::LodShortIndexed::LodData& out, std::vector<buffer::VertexData>& tmp) const;
|
void render(const surrounding::corners &surrounding, render::LodModel::LodData& out, std::vector<render::VertexData>& tmp) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
|
||||||
#include <meshoptimizer.h>
|
|
||||||
#include "../data/geometry/Faces.hpp"
|
|
||||||
#include "../render/buffer/VertexData.hpp"
|
|
||||||
|
|
||||||
using namespace geometry;
|
|
||||||
namespace contouring::box {
|
|
||||||
static const auto BOX_FACES = 6;
|
|
||||||
|
|
||||||
static const std::vector<glm::vec3> g_quad_vertices = {
|
|
||||||
glm::vec3(0.5f, 0.5f, 0.5f), glm::vec3(0.5f, -0.5f, 0.5f), glm::vec3(0.5f, -0.5f, -0.5f),
|
|
||||||
glm::vec3(0.5f, -0.5f, -0.5f), glm::vec3(0.5f, 0.5f, -0.5f), glm::vec3(0.5f, 0.5f, 0.5f)};
|
|
||||||
|
|
||||||
static const glm::vec3 g_cube_normals[BOX_FACES] = {
|
|
||||||
glm::vec3(1, 0, 0), glm::vec3(-1, 0, 0), glm::vec3(0, 1, 0), glm::vec3(0, -1, 0), glm::vec3(0, 0, 1), glm::vec3(0, 0, -1)};
|
|
||||||
|
|
||||||
static const glm::mat4 g_cube_rotate[BOX_FACES] = {
|
|
||||||
glm::mat4(1),
|
|
||||||
glm::rotate<float>(glm::mat4(1), glm::pi<float>(), glm::vec3(0, 1, 0)),
|
|
||||||
glm::rotate<float>(glm::mat4(1), glm::half_pi<float>(), glm::vec3(0, 0, 1)),
|
|
||||||
glm::rotate<float>(glm::mat4(1), glm::half_pi<float>(), glm::vec3(0, 0, -1)),
|
|
||||||
glm::rotate<float>(glm::mat4(1), glm::half_pi<float>(), glm::vec3(0, -1, 0)),
|
|
||||||
glm::rotate<float>(glm::mat4(1), glm::half_pi<float>(), glm::vec3(0, 1, 0)),
|
|
||||||
};
|
|
||||||
|
|
||||||
static void addQuad(std::vector<buffer::PackedVertexData> & out, glm::vec3 position, ushort texture, Face face, glm::vec3 size) {
|
|
||||||
for (auto vertex : g_quad_vertices) {
|
|
||||||
const auto p = glm::vec3(g_cube_rotate[static_cast<int>(face)] * glm::vec4(vertex, 1)) * size + position;
|
|
||||||
out.emplace_back(meshopt_quantizeHalf(p.x), meshopt_quantizeHalf(p.y),
|
|
||||||
meshopt_quantizeHalf(p.z), texture,
|
|
||||||
meshopt_quantizeHalf(g_cube_normals[static_cast<int>(face)].x), meshopt_quantizeHalf(g_cube_normals[static_cast<int>(face)].y),
|
|
||||||
meshopt_quantizeHalf(g_cube_normals[static_cast<int>(face)].z));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void addCube(std::vector<buffer::PackedVertexData>& out, glm::vec3 position, uint texture, Faces faces = Faces::All, glm::vec3 size = glm::vec3(1)) {
|
|
||||||
if (faces && Faces::Right)
|
|
||||||
addQuad(out, position, texture, Face::Right, size);
|
|
||||||
|
|
||||||
if(faces && Faces::Left)
|
|
||||||
addQuad(out, position, texture, Face::Left, size);
|
|
||||||
|
|
||||||
if (faces && Faces::Up)
|
|
||||||
addQuad(out, position, texture, Face::Up, size);
|
|
||||||
|
|
||||||
if (faces && Faces::Down)
|
|
||||||
addQuad(out, position, texture, Face::Down, size);
|
|
||||||
|
|
||||||
if (faces && Faces::Forward)
|
|
||||||
addQuad(out, position, texture, Face::Forward, size);
|
|
||||||
|
|
||||||
if (faces && Faces::Backward)
|
|
||||||
addQuad(out, position, texture, Face::Backward, size);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
#include "index.hpp"
|
|
||||||
#include "Dummy.hpp"
|
|
||||||
#include "FlatDualMC.hpp"
|
|
||||||
|
|
||||||
namespace contouring {
|
|
||||||
int idxByName(const std::string& name) {
|
|
||||||
for (size_t i = 0; i < names.size(); i++) {
|
|
||||||
if(name == names[i])
|
|
||||||
return (int)i;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<Abstract> load(int idx, const std::map<std::string, std::string>& data) {
|
|
||||||
switch (idx) {
|
|
||||||
case 2:
|
|
||||||
return std::make_shared<Dummy>();
|
|
||||||
|
|
||||||
default:
|
|
||||||
return std::make_shared<FlatDualMC>(data.at(names[0]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void save(int idx, std::shared_ptr<Abstract>& ct, std::map<std::string, std::string>& data) {
|
|
||||||
data.insert_or_assign(names[idx], ct->getOptions());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Abstract.hpp"
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
namespace contouring {
|
|
||||||
static const std::array<std::string, 2> names = {"FlatDualMC", "Dummy"};
|
|
||||||
|
|
||||||
int idxByName(const std::string &name);
|
|
||||||
std::shared_ptr<Abstract> load(int idx, const std::map<std::string, std::string> &data);
|
|
||||||
void save(int idx, std::shared_ptr<Abstract> &ct, std::map<std::string, std::string> &data);
|
|
||||||
}
|
|
|
@ -1,23 +1,23 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <meshoptimizer.h>
|
#include <meshoptimizer.h>
|
||||||
|
|
||||||
inline void optimize_fetch(buffer::ShortIndexed::Data& out) {
|
inline void optimize_fetch(render::Model::Data& out) {
|
||||||
ZoneScopedN("Optimize");
|
ZoneScopedN("Optimize");
|
||||||
std::vector<unsigned int> remap(out.indices.size());
|
std::vector<unsigned int> remap(out.indices.size());
|
||||||
size_t vertex_count = meshopt_optimizeVertexFetch(out.vertices.data(), out.indices.data(), out.indices.size(), out.vertices.data(), out.vertices.size(), sizeof(buffer::PackedVertexData));
|
size_t vertex_count = meshopt_optimizeVertexFetch(out.vertices.data(), out.indices.data(), out.indices.size(), out.vertices.data(), out.vertices.size(), sizeof(render::PackedVertexData));
|
||||||
out.vertices.resize(vertex_count, buffer::PackedVertexData(0, 0, 0, 0, 0, 0, 0));
|
out.vertices.resize(vertex_count, render::PackedVertexData(0, 0, 0, 0, 0, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
//MAYBE: when networking meshopt_encodeVertexBuffer
|
//MAYBE: when networking meshopt_encodeVertexBuffer
|
||||||
|
|
||||||
template<typename I>
|
template<typename I>
|
||||||
inline void simplify_buffer(std::vector<I> &out, const std::vector<I> &indices, const std::vector<buffer::VertexData>& vertices, float threshold = .2f, float target_error = 1e-2f) {
|
inline void simplify_buffer(std::vector<I> &out, const std::vector<I> &indices, const std::vector<render::VertexData>& vertices, float threshold = .2f, float target_error = 1e-2f) {
|
||||||
out.resize(indices.size());
|
out.resize(indices.size());
|
||||||
out.resize(meshopt_simplify(out.data(), indices.data(), indices.size(), &vertices.front().Position.x, vertices.size(), sizeof(buffer::VertexData), indices.size() * threshold, target_error));
|
out.resize(meshopt_simplify(out.data(), indices.data(), indices.size(), &vertices.front().Position.x, vertices.size(), sizeof(render::VertexData), indices.size() * threshold, target_error));
|
||||||
}
|
}
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
template <typename I>
|
template <typename I>
|
||||||
inline std::vector<size_t> simplify_lod(std::vector<I> &indices, const std::vector<buffer::VertexData> &vertices, const std::vector<std::pair<float, float>> &levels)
|
inline std::vector<size_t> simplify_lod(std::vector<I> &indices, const std::vector<render::VertexData> &vertices, const std::vector<std::pair<float, float>> &levels)
|
||||||
{
|
{
|
||||||
ZoneScopedN("LOD");
|
ZoneScopedN("LOD");
|
||||||
typename std::vector<I> full(indices);
|
typename std::vector<I> full(indices);
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../../core/flags.hpp"
|
#include "../../core/flags.hpp"
|
||||||
#include "buffer/Abstract.hpp"
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -11,6 +10,8 @@
|
||||||
class Window;
|
class Window;
|
||||||
class Camera;
|
class Camera;
|
||||||
namespace render {
|
namespace render {
|
||||||
|
class Model;
|
||||||
|
class LodModel;
|
||||||
|
|
||||||
/// Pass options
|
/// Pass options
|
||||||
struct passOptions {
|
struct passOptions {
|
||||||
|
@ -63,9 +64,9 @@ public:
|
||||||
/// Start new frame and setup
|
/// Start new frame and setup
|
||||||
virtual void beginFrame() = 0;
|
virtual void beginFrame() = 0;
|
||||||
/// Get started world program
|
/// Get started world program
|
||||||
virtual std::function<buffer::params(glm::mat4)> beginWorldPass() = 0;
|
virtual std::function<size_t(render::LodModel *const, glm::mat4)> beginWorldPass() = 0;
|
||||||
/// Get started entity program
|
/// Get started entity program
|
||||||
virtual std::function<buffer::params(const std::vector<glm::mat4> &)> beginEntityPass() = 0;
|
virtual std::function<size_t(render::Model *const, const std::vector<glm::mat4> &)> beginEntityPass() = 0;
|
||||||
/// Draw cube indicator
|
/// Draw cube indicator
|
||||||
virtual size_t drawIndicatorCube(glm::mat4 model) = 0;
|
virtual size_t drawIndicatorCube(glm::mat4 model) = 0;
|
||||||
/// Apply postprocessing
|
/// Apply postprocessing
|
||||||
|
|
|
@ -102,8 +102,9 @@ UI::Actions UI::draw(config::client::options &options, state::state &state, cons
|
||||||
if (ImGui::ColorEdit3("Fog color", &options.renderer.clear_color[0])) {
|
if (ImGui::ColorEdit3("Fog color", &options.renderer.clear_color[0])) {
|
||||||
actions |= Actions::ClearColor;
|
actions |= Actions::ClearColor;
|
||||||
}
|
}
|
||||||
if (ImGui::Checkbox("Wireframe", &options.renderer.wireframe))
|
if (ImGui::Checkbox("Wireframe", &options.renderer.wireframe)) {
|
||||||
glPolygonMode(GL_FRONT_AND_BACK, options.renderer.wireframe ? GL_LINE : GL_FILL);
|
actions |= Actions::FillMode;
|
||||||
|
}
|
||||||
ImGui::Text("Textures '%s'", options.renderer.textures.c_str()); // MAYBE: select
|
ImGui::Text("Textures '%s'", options.renderer.textures.c_str()); // MAYBE: select
|
||||||
if (ImGui::SliderFloat("LOD", &options.renderer.mipMapLOD, -1, 1) |
|
if (ImGui::SliderFloat("LOD", &options.renderer.mipMapLOD, -1, 1) |
|
||||||
ImGui::SliderInt("Anisotropy", &options.renderer.anisotropy, 0, 8)) {
|
ImGui::SliderInt("Anisotropy", &options.renderer.anisotropy, 0, 8)) {
|
||||||
|
@ -130,23 +131,6 @@ UI::Actions UI::draw(config::client::options &options, state::state &state, cons
|
||||||
|
|
||||||
if (options.debugMenu.contouring) {
|
if (options.debugMenu.contouring) {
|
||||||
ImGui::Begin("Debug: Contouring", &options.debugMenu.contouring, ImGuiWindowFlags_AlwaysAutoResize);
|
ImGui::Begin("Debug: Contouring", &options.debugMenu.contouring, ImGuiWindowFlags_AlwaysAutoResize);
|
||||||
if (ImGui::BeginCombo("Contouring", contouring::names[options.contouring.idx].c_str())) {
|
|
||||||
for (size_t i = 0; i < contouring::names.size(); i++) {
|
|
||||||
const bool is_selected = (options.contouring.idx == (int)i);
|
|
||||||
if (ImGui::Selectable(contouring::names[i].c_str(), is_selected)) {
|
|
||||||
actions |= Actions::ChangeContouring;
|
|
||||||
contouring::save(options.contouring.idx, state.contouring, options.contouring.data);
|
|
||||||
options.contouring.idx = i;
|
|
||||||
}
|
|
||||||
if (is_selected)
|
|
||||||
ImGui::SetItemDefaultFocus();
|
|
||||||
}
|
|
||||||
ImGui::EndCombo();
|
|
||||||
}
|
|
||||||
if(ImGui::Button("Reload")) {
|
|
||||||
actions |= Actions::ChangeContouring;
|
|
||||||
contouring::save(options.contouring.idx, state.contouring, options.contouring.data);
|
|
||||||
}
|
|
||||||
ImGui::SliderInt("Culling", &options.culling, -1, 10, options.culling > 0 ? "Occlusion %d" : (options.culling < 0 ? "None" : "Frustum"));
|
ImGui::SliderInt("Culling", &options.culling, -1, 10, options.culling > 0 ? "Occlusion %d" : (options.culling < 0 ? "None" : "Frustum"));
|
||||||
state.contouring->onGui();
|
state.contouring->onGui();
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
|
@ -31,7 +31,7 @@ public:
|
||||||
World = 1 << 5,
|
World = 1 << 5,
|
||||||
Camera = 1 << 6,
|
Camera = 1 << 6,
|
||||||
Control = 1 << 7,
|
Control = 1 << 7,
|
||||||
ChangeContouring = 1 << 8,
|
FillMode = 1 << 8,
|
||||||
};
|
};
|
||||||
friend inline void operator|=(Actions& a, Actions b) {
|
friend inline void operator|=(Actions& a, Actions b) {
|
||||||
a = static_cast<Actions>(static_cast<int>(a) | static_cast<int>(b));
|
a = static_cast<Actions>(static_cast<int>(a) | static_cast<int>(b));
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include "Buffers.hpp"
|
||||||
|
|
||||||
|
using namespace render;
|
||||||
|
|
||||||
|
std::unique_ptr<WritableBuffer> (*WritableBuffer::createFunc)(size_t, Usage, const data_view) = nullptr;
|
||||||
|
std::unique_ptr<FastBuffer> (*FastBuffer::createFunc)(size_t, Usage, const data_view) = nullptr;
|
||||||
|
std::unique_ptr<ShortIndexedVertexBuffer> (*ShortIndexedVertexBuffer::createFunc)(const data_view, const data_view) = nullptr;
|
|
@ -0,0 +1,75 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
|
|
||||||
|
namespace render {
|
||||||
|
|
||||||
|
/// Abstract raw data buffer
|
||||||
|
class Buffer {
|
||||||
|
public:
|
||||||
|
virtual ~Buffer() { }
|
||||||
|
|
||||||
|
// NOTE: matches VkBufferUsageFlags
|
||||||
|
enum class Usage {
|
||||||
|
TRANSFER_SRC = 1,
|
||||||
|
TRANSFER_DST = 2,
|
||||||
|
UNIFORM = 16,
|
||||||
|
STORAGE = 32,
|
||||||
|
INDEX = 64,
|
||||||
|
VERTEX = 128
|
||||||
|
};
|
||||||
|
friend inline Usage operator|(Usage a, Usage b) {
|
||||||
|
return static_cast<Usage>(static_cast<int>(a) | static_cast<int>(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct requirement {
|
||||||
|
requirement(size_t size, Usage usage, const data_view view = data_view()):
|
||||||
|
size(size), usage(usage), view(view) { }
|
||||||
|
|
||||||
|
size_t size;
|
||||||
|
Usage usage;
|
||||||
|
data_view view;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Writable raw data buffer
|
||||||
|
class WritableBuffer: public Buffer {
|
||||||
|
public:
|
||||||
|
static _FORCE_INLINE_ std::unique_ptr<WritableBuffer> Create(size_t size, Usage usage = Usage::TRANSFER_SRC, const data_view write = data_view()) {
|
||||||
|
assert(createFunc != nullptr && "Uninitialized renderer");
|
||||||
|
return createFunc(size, usage, write);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void write(const data_view, size_t offset = 0) = 0;
|
||||||
|
virtual void read(data_ref, size_t offset = 0) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static std::unique_ptr<WritableBuffer> (*createFunc)(size_t, Usage, const data_view);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Fast raw data buffer
|
||||||
|
class FastBuffer: public Buffer {
|
||||||
|
public:
|
||||||
|
// NOTE: implementation may implicitly add Usage::TRANSFER_DST
|
||||||
|
static _FORCE_INLINE_ std::unique_ptr<FastBuffer> Create(size_t size, Usage usage, const data_view write = data_view()) {
|
||||||
|
assert(createFunc != nullptr && "Uninitialized renderer");
|
||||||
|
return createFunc(size, usage, write);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static std::unique_ptr<FastBuffer> (*createFunc)(size_t, Usage, const data_view);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Grouped vertex and u16 index buffers
|
||||||
|
/// NOTE: vertex structure is undefined
|
||||||
|
class ShortIndexedVertexBuffer: public Buffer {
|
||||||
|
public:
|
||||||
|
static _FORCE_INLINE_ std::unique_ptr<ShortIndexedVertexBuffer> Create(const data_view vertices, const data_view indices) {
|
||||||
|
assert(createFunc != nullptr && "Uninitialized renderer");
|
||||||
|
return createFunc(vertices, indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static std::unique_ptr<ShortIndexedVertexBuffer> (*createFunc)(const data_view, const data_view);
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
#include "Images.hpp"
|
||||||
|
|
||||||
|
using namespace render;
|
||||||
|
|
||||||
|
std::unique_ptr<Texture> (*Texture::loadFunc)(const std::string&, const sampling&) = nullptr;
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#define FOURCC_DXT1 0x31545844 // Equivalent to "DXT1" in ASCII
|
||||||
|
#define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII
|
||||||
|
#define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII
|
||||||
|
|
||||||
|
std::optional<Image::properties> Image::Read(const std::string& imagepath, std::vector<unsigned char>& data) {
|
||||||
|
|
||||||
|
unsigned char header[124];
|
||||||
|
properties info;
|
||||||
|
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
/* try to open the file */
|
||||||
|
fp = fopen(imagepath.c_str(), "rb");
|
||||||
|
if (fp == NULL){
|
||||||
|
printf("%s could not be opened.\n", imagepath.c_str()); getchar();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verify the type of file */
|
||||||
|
char filecode[4];
|
||||||
|
fread(filecode, 1, 4, fp);
|
||||||
|
if (strncmp(filecode, "DDS ", 4) != 0) {
|
||||||
|
fclose(fp);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the surface desc */
|
||||||
|
fread(&header, 124, 1, fp);
|
||||||
|
|
||||||
|
info.size.height = *(unsigned int*)&(header[8 ]);
|
||||||
|
info.size.width = *(unsigned int*)&(header[12]);
|
||||||
|
unsigned int linearSize = *(unsigned int*)&(header[16]);
|
||||||
|
info.mipMap = *(unsigned int*)&(header[24]);
|
||||||
|
unsigned int fourCC = *(unsigned int*)&(header[80]);
|
||||||
|
|
||||||
|
|
||||||
|
/* how big is it going to be including all mipmaps? */
|
||||||
|
unsigned int bufsize = info.mipMap > 1 ? linearSize * 2 : linearSize;
|
||||||
|
data.resize(bufsize);
|
||||||
|
fread(data.data(), 1, bufsize, fp);
|
||||||
|
/* close the file pointer */
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
switch(fourCC)
|
||||||
|
{
|
||||||
|
case FOURCC_DXT1:
|
||||||
|
info.format = Format::BC1;
|
||||||
|
break;
|
||||||
|
case FOURCC_DXT3:
|
||||||
|
info.format = Format::BC2;
|
||||||
|
break;
|
||||||
|
case FOURCC_DXT5:
|
||||||
|
info.format = Format::BC3;
|
||||||
|
break;
|
||||||
|
//MAYBE: VK_FORMAT_BC6H_SFLOAT_BLOCK
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace render {
|
||||||
|
|
||||||
|
/// Abstract raw image
|
||||||
|
class Image {
|
||||||
|
public:
|
||||||
|
virtual ~Image() { }
|
||||||
|
|
||||||
|
struct frame {
|
||||||
|
uint32_t height;
|
||||||
|
uint32_t width;
|
||||||
|
};
|
||||||
|
// NOTE: matches VkFormat
|
||||||
|
enum class Format {
|
||||||
|
/// DXT1 RGBA SRGB
|
||||||
|
BC1 = 134,
|
||||||
|
/// DXT3 RGBA SRGB
|
||||||
|
BC2 = 136,
|
||||||
|
/// DXT1 RGBA SRGB
|
||||||
|
BC3 = 138,
|
||||||
|
// MAYBE: BMP RGBA SRGB ??
|
||||||
|
// MAYBE: For HDR BC6H_SFLOAT = 144,
|
||||||
|
};
|
||||||
|
// NOTE: matches VkImageLayout
|
||||||
|
enum class Layout {
|
||||||
|
UNDEFINED = 0,
|
||||||
|
GENERAL = 1,
|
||||||
|
COLOR_ATTACHMENT = 2,
|
||||||
|
DEPTH_STENCIL_ATTACHMENT = 3,
|
||||||
|
DEPTH_STENCIL_READ_ONLY = 4,
|
||||||
|
SHADER_READ_ONLY = 5,
|
||||||
|
TRANSFER_SRC = 6,
|
||||||
|
TRANSFER_DST = 7,
|
||||||
|
PREINITIALIZED = 8,
|
||||||
|
DEPTH_READ_ONLY_STENCIL_ATTACHMENT = 1000117000,
|
||||||
|
DEPTH_ATTACHMENT_STENCIL_READ_ONLY = 1000117001,
|
||||||
|
DEPTH_ATTACHMENT = 1000241000,
|
||||||
|
DEPTH_READ_ONLY = 1000241001,
|
||||||
|
STENCIL_ATTACHMENT = 1000241002,
|
||||||
|
STENCIL_READ_ONLY = 1000241003
|
||||||
|
};
|
||||||
|
// NOTE: matches VkImageUsageFlags
|
||||||
|
enum class Usage {
|
||||||
|
TRANSFER_SRC = 0x00000001,
|
||||||
|
TRANSFER_DST = 0x00000002,
|
||||||
|
SAMPLED = 0x00000004,
|
||||||
|
STORAGE = 0x00000008,
|
||||||
|
COLOR_ATTACHMENT = 0x00000010,
|
||||||
|
DEPTH_STENCIL_ATTACHMENT = 0x00000020,
|
||||||
|
TRANSIENT_ATTACHMENT = 0x00000040,
|
||||||
|
INPUT_ATTACHMENT = 0x00000080,
|
||||||
|
};
|
||||||
|
friend inline Usage operator|(Usage a, Usage b) {
|
||||||
|
return static_cast<Usage>(static_cast<int>(a) | static_cast<int>(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct properties {
|
||||||
|
frame size;
|
||||||
|
uint32_t mipMap;
|
||||||
|
Format format;
|
||||||
|
};
|
||||||
|
struct requirement {
|
||||||
|
properties props;
|
||||||
|
Layout layout;
|
||||||
|
Usage usage;
|
||||||
|
bool linear = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::optional<properties> Read(const std::string&, std::vector<unsigned char>& data);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Const image (single texture2D) with sampler
|
||||||
|
class Texture: public Image {
|
||||||
|
public:
|
||||||
|
// NOTE: matches VkSamplerAddressMode
|
||||||
|
enum class Wrap {
|
||||||
|
REPEAT = 0,
|
||||||
|
MIRRORED_REPEAT = 1,
|
||||||
|
CLAMP_TO_EDGE = 2,
|
||||||
|
CLAMP_TO_BORDER = 3,
|
||||||
|
};
|
||||||
|
struct sampling {
|
||||||
|
bool magLinear = true;
|
||||||
|
bool minLinear = true;
|
||||||
|
Wrap wrap = Wrap::MIRRORED_REPEAT;
|
||||||
|
int anisotropy = 0;
|
||||||
|
//TODO: mipmap
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Only supports dds files
|
||||||
|
/// DXT1(BC1) DXT3(BC2) DXT5(BC3)
|
||||||
|
static _FORCE_INLINE_ std::unique_ptr<Texture> LoadFromFile(const std::string &path, const sampling &props) {
|
||||||
|
assert(loadFunc != nullptr && "Uninitialized renderer");
|
||||||
|
return loadFunc(path, props);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static std::unique_ptr<Texture> (*loadFunc)(const std::string&, const sampling&);
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
#include "Models.hpp"
|
||||||
|
#include <fstream>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
using namespace render;
|
||||||
|
|
||||||
|
std::unique_ptr<Model> (*Model::createFunc)(const Data&) = nullptr;
|
||||||
|
std::unique_ptr<LodModel> (*LodModel::createFunc)(const LodData&) = nullptr;
|
||||||
|
|
||||||
|
void indexVBO(const std::vector<PackedVertexData> &in_vertices, std::vector<glm::u16> &out_indices, std::vector<PackedVertexData> &out_vertices);
|
||||||
|
|
||||||
|
Model::Data::Data(const std::vector<PackedVertexData> &vs, const std::vector<glm::u16> &indices): indices(indices), vertices(vs) { }
|
||||||
|
Model::Data::Data(std::ifstream& in) {
|
||||||
|
{
|
||||||
|
size_t i_size;
|
||||||
|
in.read(reinterpret_cast<char *>(&i_size), sizeof(i_size));
|
||||||
|
indices.resize(i_size);
|
||||||
|
in.read(reinterpret_cast<char *>(indices.data()), sizeof(glm::u16) * i_size);
|
||||||
|
}
|
||||||
|
size_t v_size;
|
||||||
|
in.read(reinterpret_cast<char *>(&v_size), sizeof(v_size));
|
||||||
|
vertices.resize(v_size, PackedVertexData(0, 0, 0, 0, 0, 0, 0, 0));
|
||||||
|
in.read(reinterpret_cast<char *>(vertices.data()), sizeof(PackedVertexData) * v_size);
|
||||||
|
}
|
||||||
|
void Model::Data::serialize(std::ofstream& out) {
|
||||||
|
{
|
||||||
|
size_t i_size = indices.size();
|
||||||
|
out.write(reinterpret_cast<char *>(&i_size), sizeof(i_size));
|
||||||
|
out.write(reinterpret_cast<char *>(indices.data()), sizeof(glm::u16) * i_size);
|
||||||
|
}
|
||||||
|
size_t v_size = vertices.size();
|
||||||
|
out.write(reinterpret_cast<char *>(&v_size), sizeof(v_size));
|
||||||
|
out.write(reinterpret_cast<char *>(vertices.data()), sizeof(PackedVertexData) * v_size);
|
||||||
|
}
|
||||||
|
void Model::Data::index(const std::vector<PackedVertexData>& vs) {
|
||||||
|
indexVBO(vs, indices, vertices);
|
||||||
|
}
|
||||||
|
|
||||||
|
void indexVBO(const std::vector<PackedVertexData> &in_vertices, std::vector<glm::u16> &out_indices,
|
||||||
|
std::vector<PackedVertexData> &out_vertices)
|
||||||
|
{
|
||||||
|
std::map<PackedVertexData, glm::u16> VertexToOutIndex;
|
||||||
|
|
||||||
|
auto getSimilarVertexIndex_fast = [&] (const PackedVertexData &packed, glm::u16 &out) {
|
||||||
|
if (auto it = VertexToOutIndex.find(packed); it == VertexToOutIndex.end()) {
|
||||||
|
return false;
|
||||||
|
}else{
|
||||||
|
out = it->second;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
out_indices.reserve(in_vertices.size());
|
||||||
|
for (const auto& vertex: in_vertices) {
|
||||||
|
if (glm::u16 index; getSimilarVertexIndex_fast(vertex, index)) {
|
||||||
|
out_indices.push_back(index);
|
||||||
|
} else {
|
||||||
|
out_vertices.push_back(vertex);
|
||||||
|
out_indices.push_back(out_vertices.size() - 1);
|
||||||
|
VertexToOutIndex[vertex] = out_indices.back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
/**
|
||||||
|
* Application specific vertex objects.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <string.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <iosfwd>
|
||||||
|
|
||||||
|
namespace render {
|
||||||
|
|
||||||
|
/// Vertex properties
|
||||||
|
struct VertexData {
|
||||||
|
VertexData(const glm::vec3 &position, glm::u16 material, const glm::vec3 &normal):
|
||||||
|
Position(position), Material(material), Normal(normal) { }
|
||||||
|
glm::vec3 Position;
|
||||||
|
glm::u16 Material;
|
||||||
|
glm::vec3 Normal;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Quantized vertex properties
|
||||||
|
struct PackedVertexData {
|
||||||
|
PackedVertexData(glm::u16 x, glm::u16 y, glm::u16 z, glm::u16 mat, glm::u16 nx, glm::u16 ny, glm::u16 nz, glm::u16 nw = 0) {
|
||||||
|
PosMat[0] = x;
|
||||||
|
PosMat[1] = y;
|
||||||
|
PosMat[2] = z;
|
||||||
|
PosMat[3] = mat;
|
||||||
|
Nrm[0] = nx;
|
||||||
|
Nrm[1] = ny;
|
||||||
|
Nrm[2] = nz;
|
||||||
|
Nrm[3] = nw;
|
||||||
|
}
|
||||||
|
glm::u16 PosMat[4];
|
||||||
|
glm::u16 Nrm[4]; //NOTE: Triplanar does not handle 10_10_10_2_REV
|
||||||
|
bool operator<(const PackedVertexData that) const {
|
||||||
|
return memcmp((void *)this, (void *)&that, sizeof(PackedVertexData)) > 0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Color lines model
|
||||||
|
class Indicator {
|
||||||
|
public:
|
||||||
|
virtual ~Indicator() { }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// VertexData model with index
|
||||||
|
class Model {
|
||||||
|
public:
|
||||||
|
virtual ~Model() { }
|
||||||
|
|
||||||
|
/// Preindexed buffer data
|
||||||
|
struct Data {
|
||||||
|
std::vector<glm::u16> indices;
|
||||||
|
std::vector<PackedVertexData> vertices;
|
||||||
|
|
||||||
|
Data() { }
|
||||||
|
Data(const std::vector<PackedVertexData> &vertices, const std::vector<glm::u16> &indices);
|
||||||
|
Data(const std::vector<PackedVertexData> &vertices) { index(vertices); }
|
||||||
|
Data(std::ifstream &in);
|
||||||
|
|
||||||
|
void index(const std::vector<PackedVertexData> &vertices);
|
||||||
|
bool empty() const {
|
||||||
|
return indices.empty();
|
||||||
|
}
|
||||||
|
void clear() {
|
||||||
|
indices.clear();
|
||||||
|
vertices.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void serialize(std::ofstream &out);
|
||||||
|
};
|
||||||
|
|
||||||
|
static _FORCE_INLINE_ std::unique_ptr<Model> Create(const Data& data) {
|
||||||
|
assert(createFunc != nullptr && "Uninitialized renderer");
|
||||||
|
return createFunc(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static std::unique_ptr<Model> (*createFunc)(const Data&);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// VertexData model with Level Of Detail indices
|
||||||
|
class LodModel {
|
||||||
|
public:
|
||||||
|
virtual ~LodModel() { }
|
||||||
|
|
||||||
|
using LodData = std::pair<Model::Data, std::vector<size_t>>;
|
||||||
|
|
||||||
|
static _FORCE_INLINE_ std::unique_ptr<LodModel> Create(const LodData& data) {
|
||||||
|
assert(createFunc != nullptr && "Uninitialized renderer");
|
||||||
|
return createFunc(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void inline setLevel(size_t l) { level = l; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
size_t level = 0;
|
||||||
|
|
||||||
|
size_t indexSize;
|
||||||
|
std::vector<size_t> offsets;
|
||||||
|
constexpr inline size_t getOffset(size_t level) const {
|
||||||
|
return level <= 0 ? 0 : (level-1 < offsets.size() ? offsets[level-1] : indexSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<LodModel> (*createFunc)(const LodData&);
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../../../core/flags.hpp"
|
||||||
|
#include <memory>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace render {
|
||||||
|
|
||||||
|
struct data_view {
|
||||||
|
data_view() { }
|
||||||
|
data_view(const void *ptr, size_t size): ptr(ptr), size(size) { }
|
||||||
|
template <typename Container>
|
||||||
|
data_view(const Container &c): data_view(c.data(), c.size() * sizeof(typename Container::value_type)) {}
|
||||||
|
|
||||||
|
constexpr bool isUsable() const { return ptr != nullptr && size > 0; }
|
||||||
|
explicit operator bool() const { return isUsable(); }
|
||||||
|
|
||||||
|
const void *ptr = nullptr;
|
||||||
|
size_t size = 0;
|
||||||
|
};
|
||||||
|
struct data_ref {
|
||||||
|
data_ref() { }
|
||||||
|
data_ref(void *ptr, size_t size): ptr(ptr), size(size) { }
|
||||||
|
template<typename Container>
|
||||||
|
data_ref(Container &c):
|
||||||
|
data_ref(c.data(), c.size() * sizeof(typename Container::value_type)) {}
|
||||||
|
|
||||||
|
constexpr bool isUsable() const { return ptr != nullptr && size > 0; }
|
||||||
|
explicit operator bool() const { return isUsable(); }
|
||||||
|
|
||||||
|
void *ptr = nullptr;
|
||||||
|
size_t size = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,14 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <GL/gl3w.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
namespace buffer {
|
|
||||||
/// Draw options
|
|
||||||
struct params {
|
|
||||||
/// Bind only vertices positions
|
|
||||||
bool vertexOnly;
|
|
||||||
/// Draw instanced model
|
|
||||||
size_t instances = 1;
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -15,7 +15,7 @@ constexpr auto GL_MAJOR = 4;
|
||||||
constexpr auto GL_MINOR = 6;
|
constexpr auto GL_MINOR = 6;
|
||||||
|
|
||||||
Renderer::Renderer(const renderOptions& options):
|
Renderer::Renderer(const renderOptions& options):
|
||||||
IndicatorCubeBuffer(GL_LINES, 24, {
|
IndicatorCubeBuffer({
|
||||||
glm::vec3(0, 0, 0), glm::vec3(0, 0, 1),
|
glm::vec3(0, 0, 0), glm::vec3(0, 0, 1),
|
||||||
glm::vec3(0, 0, 1), glm::vec3(0, 1, 1),
|
glm::vec3(0, 0, 1), glm::vec3(0, 1, 1),
|
||||||
glm::vec3(0, 1, 1), glm::vec3(0, 1, 0),
|
glm::vec3(0, 1, 1), glm::vec3(0, 1, 0),
|
||||||
|
@ -101,6 +101,7 @@ bool Renderer::Load(Window& window, const renderOptions& opt) {
|
||||||
TracyGpuContext;
|
TracyGpuContext;
|
||||||
|
|
||||||
sInstance = new Renderer(opt);
|
sInstance = new Renderer(opt);
|
||||||
|
LodModel::MakeDefault();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,25 +115,28 @@ void Renderer::beginFrame() {
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::function<buffer::params(glm::mat4)> Renderer::beginWorldPass() {
|
std::function<size_t(render::LodModel *const, glm::mat4)> Renderer::beginWorldPass() {
|
||||||
WorldPass->useIt();
|
WorldPass->useIt();
|
||||||
WorldPass->start(this);
|
WorldPass->start(this);
|
||||||
return [&](glm::mat4 model) {
|
return [&](render::LodModel *const buf, glm::mat4 model) {
|
||||||
return WorldPass->setup(this, model);
|
WorldPass->setup(this, model);
|
||||||
|
return dynamic_cast<LodModel *const>(buf)->draw();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::function<buffer::params(const std::vector<glm::mat4> &)> Renderer::beginEntityPass() {
|
std::function<size_t(render::Model *const, const std::vector<glm::mat4> &)> Renderer::beginEntityPass() {
|
||||||
EntityPass->useIt();
|
EntityPass->useIt();
|
||||||
EntityPass->start(this);
|
EntityPass->start(this);
|
||||||
return [&](const std::vector<glm::mat4>& models) {
|
return [&](render::Model *const buf, const std::vector<glm::mat4> &models) {
|
||||||
return EntityPass->setup(this, models);
|
EntityPass->setup(this, models);
|
||||||
|
return dynamic_cast<Model *const>(buf)->drawInstanced(models.size());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Renderer::drawIndicatorCube(glm::mat4 model) {
|
size_t Renderer::drawIndicatorCube(glm::mat4 model) {
|
||||||
IndicatorPass->useIt();
|
IndicatorPass->useIt();
|
||||||
return IndicatorCubeBuffer.draw(IndicatorPass->setup(this, model));
|
IndicatorPass->setup(this, model);
|
||||||
|
return IndicatorCubeBuffer.draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::endPass() {
|
void Renderer::endPass() {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include "pass/EntityProgram.hpp"
|
#include "pass/EntityProgram.hpp"
|
||||||
#include "pass/SkyProgram.hpp"
|
#include "pass/SkyProgram.hpp"
|
||||||
#include "pass/ColorProgram.hpp"
|
#include "pass/ColorProgram.hpp"
|
||||||
#include "buffer/Colored.hpp"
|
#include "api/Models.hpp"
|
||||||
|
|
||||||
namespace render::gl {
|
namespace render::gl {
|
||||||
|
|
||||||
|
@ -41,8 +41,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void beginFrame() override;
|
void beginFrame() override;
|
||||||
std::function<buffer::params(glm::mat4)> beginWorldPass() override;
|
std::function<size_t(render::LodModel *const, glm::mat4)> beginWorldPass() override;
|
||||||
std::function<buffer::params(const std::vector<glm::mat4>&)> beginEntityPass() override;
|
std::function<size_t(render::Model *const, const std::vector<glm::mat4>&)> beginEntityPass() override;
|
||||||
size_t drawIndicatorCube(glm::mat4 model) override;
|
size_t drawIndicatorCube(glm::mat4 model) override;
|
||||||
void endPass() override;
|
void endPass() override;
|
||||||
void swapBuffer(Window&) override;
|
void swapBuffer(Window&) override;
|
||||||
|
@ -74,7 +74,7 @@ private:
|
||||||
std::unique_ptr<pass::EntityProgram> EntityPass;
|
std::unique_ptr<pass::EntityProgram> EntityPass;
|
||||||
std::unique_ptr<pass::SkyProgram> SkyPass;
|
std::unique_ptr<pass::SkyProgram> SkyPass;
|
||||||
std::unique_ptr<pass::ColorProgram> IndicatorPass;
|
std::unique_ptr<pass::ColorProgram> IndicatorPass;
|
||||||
buffer::Colored IndicatorCubeBuffer;
|
Indicator IndicatorCubeBuffer;
|
||||||
|
|
||||||
glm::mat4 ProjectionMatrix;
|
glm::mat4 ProjectionMatrix;
|
||||||
glm::mat4 ViewMatrix;
|
glm::mat4 ViewMatrix;
|
||||||
|
|
|
@ -0,0 +1,152 @@
|
||||||
|
#include "Models.hpp"
|
||||||
|
|
||||||
|
using namespace render::gl;
|
||||||
|
|
||||||
|
Shape::Shape(const std::vector<glm::vec3>& pos) {
|
||||||
|
size = pos.size();
|
||||||
|
glGenBuffers(1, &bufferId);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, bufferId);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, pos.size() * sizeof(glm::vec3), pos.data(), GL_STATIC_DRAW);
|
||||||
|
}
|
||||||
|
Shape::~Shape() {
|
||||||
|
glDeleteBuffers(1, &bufferId);
|
||||||
|
}
|
||||||
|
size_t Shape::draw() {
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, bufferId);
|
||||||
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0);
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, size);
|
||||||
|
glDisableVertexAttribArray(0);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
Indicator::Indicator(const std::vector<glm::vec3>& pos, const std::vector<glm::vec4>& col) {
|
||||||
|
assert(pos.size() == col.size());
|
||||||
|
size = pos.size();
|
||||||
|
glGenBuffers(1, &vertexBufferId);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, pos.size() * sizeof(glm::vec3), pos.data(), GL_STATIC_DRAW);
|
||||||
|
glGenBuffers(1, &colorBufferId);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, colorBufferId);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, col.size() * sizeof(glm::vec4), col.data(), GL_STATIC_DRAW);
|
||||||
|
}
|
||||||
|
Indicator::~Indicator() {
|
||||||
|
glDeleteBuffers(1, &colorBufferId);
|
||||||
|
glDeleteBuffers(1, &vertexBufferId);
|
||||||
|
}
|
||||||
|
void Indicator::enableAttribs() {
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId);
|
||||||
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0);
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, colorBufferId);
|
||||||
|
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void *)0);
|
||||||
|
}
|
||||||
|
void Indicator::disableAttribs() {
|
||||||
|
glDisableVertexAttribArray(0);
|
||||||
|
glDisableVertexAttribArray(1);
|
||||||
|
}
|
||||||
|
size_t Indicator::draw() {
|
||||||
|
enableAttribs();
|
||||||
|
glDrawArrays(GL_LINES, 0, size);
|
||||||
|
disableAttribs();
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
size_t Indicator::drawInstanced(size_t count) {
|
||||||
|
enableAttribs();
|
||||||
|
glDrawArraysInstanced(GL_LINES, 0, size, count);
|
||||||
|
disableAttribs();
|
||||||
|
return size * count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void enableAttribs() {
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glVertexAttribPointer(0, 3, GL_HALF_FLOAT, GL_FALSE, sizeof(render::PackedVertexData),
|
||||||
|
reinterpret_cast<void *>(offsetof(render::PackedVertexData, PosMat[0])));
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
glVertexAttribIPointer(1, 1, GL_UNSIGNED_SHORT, sizeof(render::PackedVertexData),
|
||||||
|
reinterpret_cast<void *>(offsetof(render::PackedVertexData, PosMat[3])));
|
||||||
|
glEnableVertexAttribArray(2);
|
||||||
|
glVertexAttribPointer(2, 3, GL_HALF_FLOAT, GL_FALSE, sizeof(render::PackedVertexData),
|
||||||
|
reinterpret_cast<void *>(offsetof(render::PackedVertexData, Nrm)));
|
||||||
|
}
|
||||||
|
void disableAttribs() {
|
||||||
|
glDisableVertexAttribArray(0);
|
||||||
|
glDisableVertexAttribArray(1);
|
||||||
|
glDisableVertexAttribArray(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Model::Model(const Data& data) {
|
||||||
|
indexSize = data.indices.size();
|
||||||
|
glGenBuffers(1, &vertexBufferId);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, data.vertices.size() * sizeof(render::PackedVertexData), data.vertices.data(), GL_STATIC_DRAW);
|
||||||
|
glGenBuffers(1, &indexBufferId);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, indexBufferId);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, data.indices.size() * sizeof(glm::u16), data.indices.data(), GL_STATIC_DRAW);
|
||||||
|
}
|
||||||
|
Model::~Model() {
|
||||||
|
glDeleteBuffers(1, &vertexBufferId);
|
||||||
|
glDeleteBuffers(1, &indexBufferId);
|
||||||
|
}
|
||||||
|
size_t Model::draw() {
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId);
|
||||||
|
enableAttribs();
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferId);
|
||||||
|
glDrawElements(GL_TRIANGLES, indexSize, GL_UNSIGNED_SHORT, (void *)0);
|
||||||
|
disableAttribs();
|
||||||
|
return indexSize;
|
||||||
|
}
|
||||||
|
size_t Model::drawInstanced(size_t count) {
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId);
|
||||||
|
enableAttribs();
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferId);
|
||||||
|
glDrawElementsInstanced(GL_TRIANGLES, indexSize, GL_UNSIGNED_SHORT, (void *)0, count);
|
||||||
|
disableAttribs();
|
||||||
|
return indexSize * count;
|
||||||
|
}
|
||||||
|
|
||||||
|
LodModel::LodModel(const LodData& data) {
|
||||||
|
indexSize = data.first.indices.size();
|
||||||
|
offsets = data.second;
|
||||||
|
glGenBuffers(1, &vertexBufferId);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, data.first.vertices.size() * sizeof(render::PackedVertexData), data.first.vertices.data(), GL_STATIC_DRAW);
|
||||||
|
glGenBuffers(1, &indexBufferId);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, indexBufferId);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, data.first.indices.size() * sizeof(glm::u16), data.first.indices.data(), GL_STATIC_DRAW);
|
||||||
|
}
|
||||||
|
LodModel::~LodModel() {
|
||||||
|
glDeleteBuffers(1, &vertexBufferId);
|
||||||
|
glDeleteBuffers(1, &indexBufferId);
|
||||||
|
}
|
||||||
|
size_t LodModel::draw() {
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId);
|
||||||
|
enableAttribs();
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferId);
|
||||||
|
const auto start = getOffset(level);
|
||||||
|
const auto end = getOffset(level+1);
|
||||||
|
const auto count = end - start;
|
||||||
|
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (void *)(start*sizeof(glm::u16)));
|
||||||
|
disableAttribs();
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
size_t LodModel::drawInstanced(size_t i) {
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId);
|
||||||
|
enableAttribs();
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferId);
|
||||||
|
const auto start = getOffset(level);
|
||||||
|
const auto end = getOffset(level+1);
|
||||||
|
const auto count = end - start;
|
||||||
|
glDrawElementsInstanced(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (void *)(start*sizeof(glm::u16)), i);
|
||||||
|
disableAttribs();
|
||||||
|
return i * count;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<render::LodModel> createLodModel(const LodModel::LodData& data) {
|
||||||
|
return std::make_unique<LodModel>(data);
|
||||||
|
}
|
||||||
|
void LodModel::MakeDefault() {
|
||||||
|
createFunc = createLodModel;
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../../api/Models.hpp"
|
||||||
|
#include <GL/gl3w.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
namespace render::gl {
|
||||||
|
|
||||||
|
/// Positions only buffer
|
||||||
|
class Shape final {
|
||||||
|
public:
|
||||||
|
Shape(const std::vector<glm::vec3>&);
|
||||||
|
~Shape();
|
||||||
|
|
||||||
|
size_t draw();
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t size;
|
||||||
|
GLuint bufferId;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Indicator final: public render::Indicator {
|
||||||
|
public:
|
||||||
|
Indicator(const std::vector<glm::vec3>&, const std::vector<glm::vec4>&);
|
||||||
|
~Indicator();
|
||||||
|
|
||||||
|
size_t draw();
|
||||||
|
size_t drawInstanced(size_t count);
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t size;
|
||||||
|
GLuint vertexBufferId;
|
||||||
|
GLuint colorBufferId;
|
||||||
|
|
||||||
|
void enableAttribs();
|
||||||
|
void disableAttribs();
|
||||||
|
};
|
||||||
|
|
||||||
|
class Model final: public render::Model {
|
||||||
|
public:
|
||||||
|
Model(const Data&);
|
||||||
|
~Model();
|
||||||
|
|
||||||
|
size_t draw();
|
||||||
|
size_t drawInstanced(size_t count);
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t indexSize;
|
||||||
|
GLuint vertexBufferId;
|
||||||
|
GLuint indexBufferId;
|
||||||
|
};
|
||||||
|
class LodModel final: public render::LodModel {
|
||||||
|
public:
|
||||||
|
LodModel(const LodData&);
|
||||||
|
~LodModel();
|
||||||
|
|
||||||
|
static void MakeDefault();
|
||||||
|
|
||||||
|
size_t draw();
|
||||||
|
size_t drawInstanced(size_t count);
|
||||||
|
|
||||||
|
private:
|
||||||
|
GLuint vertexBufferId;
|
||||||
|
GLuint indexBufferId;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,38 +0,0 @@
|
||||||
#include "Abstract.hpp"
|
|
||||||
|
|
||||||
using namespace buffer;
|
|
||||||
|
|
||||||
Abstract::Abstract(GLenum shape): Shape(shape) {
|
|
||||||
glGenBuffers(1, &VertexBufferID);
|
|
||||||
}
|
|
||||||
|
|
||||||
Abstract::~Abstract() {
|
|
||||||
glDeleteBuffers(1, &VertexBufferID);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Abstract::enableVertexAttrib() {
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID);
|
|
||||||
glVertexAttribPointer(
|
|
||||||
0, // attribute
|
|
||||||
3, // size
|
|
||||||
GL_FLOAT, // type
|
|
||||||
GL_FALSE, // normalized?
|
|
||||||
0, // stride
|
|
||||||
(void *)0 // array buffer offset
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void Abstract::enableAllAttribs() {
|
|
||||||
enableVertexAttrib();
|
|
||||||
}
|
|
||||||
void Abstract::disableVertexAttrib() {
|
|
||||||
glDisableVertexAttribArray(0);
|
|
||||||
}
|
|
||||||
void Abstract::disableAllAttribs() {
|
|
||||||
disableVertexAttrib();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Abstract::setVertices(const unsigned long size, const void *data) {
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "../../buffer/Abstract.hpp"
|
|
||||||
|
|
||||||
namespace buffer {
|
|
||||||
/// 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);
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
#include "Colored.hpp"
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
Colored::~Colored() {
|
|
||||||
glDeleteBuffers(1, &ColorBufferID);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint Colored::draw(params params) {
|
|
||||||
if (params.vertexOnly) {
|
|
||||||
enableVertexAttrib();
|
|
||||||
} else {
|
|
||||||
enableAllAttribs();
|
|
||||||
}
|
|
||||||
if (params.instances == 1) {
|
|
||||||
glDrawArrays(Shape, 0, ElementCount);
|
|
||||||
} else {
|
|
||||||
glDrawArraysInstanced(Shape, 0, ElementCount, params.instances);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params.vertexOnly) {
|
|
||||||
disableVertexAttrib();
|
|
||||||
} else {
|
|
||||||
disableAllAttribs();
|
|
||||||
}
|
|
||||||
return ElementCount * params.instances;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Colored::enableAllAttribs() {
|
|
||||||
enableVertexAttrib();
|
|
||||||
|
|
||||||
glEnableVertexAttribArray(1);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, ColorBufferID);
|
|
||||||
glVertexAttribPointer(
|
|
||||||
1, // attribute
|
|
||||||
4, // size
|
|
||||||
GL_FLOAT, // type
|
|
||||||
GL_FALSE, // normalized?
|
|
||||||
0, // stride
|
|
||||||
(void *)0 // array buffer offset
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void Colored::disableAllAttribs() {
|
|
||||||
glDisableVertexAttribArray(1);
|
|
||||||
|
|
||||||
disableVertexAttrib();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Colored::setColors(const unsigned long size, const void *data) {
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, ColorBufferID);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <GL/gl3w.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);
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
#include "LodShortIndexed.hpp"
|
|
||||||
|
|
||||||
using namespace buffer;
|
|
||||||
|
|
||||||
LodShortIndexed::LodShortIndexed(GLenum shape, const ShortIndexed::Data &data, const std::vector<size_t> &offsets): ShortIndexed(shape, data), offsets(offsets) { }
|
|
||||||
LodShortIndexed::LodShortIndexed(GLenum shape, const LodShortIndexed::LodData &data): ShortIndexed(shape, data.first), offsets(data.second) { }
|
|
||||||
LodShortIndexed::~LodShortIndexed() { }
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
uint LodShortIndexed::draw(buffer::params params) {
|
|
||||||
if(params.vertexOnly) {
|
|
||||||
enableVertexAttrib();
|
|
||||||
} else {
|
|
||||||
enableAllAttribs();
|
|
||||||
}
|
|
||||||
enableIndex();
|
|
||||||
const auto start = getOffset(level);
|
|
||||||
const auto end = getOffset(level+1);
|
|
||||||
const auto count = end - start;
|
|
||||||
if (params.instances == 1) {
|
|
||||||
glDrawElements(Shape, count, GL_UNSIGNED_SHORT, (void *)(start*sizeof(GLushort)));
|
|
||||||
} else {
|
|
||||||
glDrawElementsInstanced(Shape, count, GL_UNSIGNED_SHORT, (void *)(start*sizeof(GLushort)), params.instances);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(params.vertexOnly) {
|
|
||||||
disableVertexAttrib();
|
|
||||||
} else {
|
|
||||||
disableAllAttribs();
|
|
||||||
}
|
|
||||||
return count * params.instances;
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "ShortIndexed.hpp"
|
|
||||||
|
|
||||||
namespace buffer {
|
|
||||||
/// ShortIndexed with merge indices for LOD
|
|
||||||
class LodShortIndexed: public ShortIndexed {
|
|
||||||
public:
|
|
||||||
using LodData = std::pair<Data, std::vector<size_t>>;
|
|
||||||
|
|
||||||
LodShortIndexed(GLenum shape, const ShortIndexed::Data &data, const std::vector<size_t> &lod_offsets);
|
|
||||||
LodShortIndexed(GLenum shape, const LodShortIndexed::LodData &data);
|
|
||||||
virtual ~LodShortIndexed();
|
|
||||||
|
|
||||||
uint draw(params params) override;
|
|
||||||
|
|
||||||
void inline setLevel(size_t l) { level = l; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
size_t level = 0;
|
|
||||||
std::vector<size_t> offsets;
|
|
||||||
constexpr inline size_t getOffset(size_t level) const {
|
|
||||||
return level <= 0 ? 0 : (level-1 < offsets.size() ? offsets[level-1] : IndexSize);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,131 +0,0 @@
|
||||||
#include "ShortIndexed.hpp"
|
|
||||||
|
|
||||||
#include "vboindexer.hpp"
|
|
||||||
#include "../../../../core/utils/logger.hpp"
|
|
||||||
|
|
||||||
using namespace buffer;
|
|
||||||
|
|
||||||
ShortIndexed::Data::Data(const std::vector<PackedVertexData> &vs, const std::vector<GLushort> &indices): indices(indices), vertices(vs) { }
|
|
||||||
ShortIndexed::Data::Data(std::ifstream& in) {
|
|
||||||
{
|
|
||||||
size_t i_size;
|
|
||||||
in.read(reinterpret_cast<char *>(&i_size), sizeof(i_size));
|
|
||||||
indices.resize(i_size);
|
|
||||||
in.read(reinterpret_cast<char *>(indices.data()), sizeof(GLushort) * i_size);
|
|
||||||
}
|
|
||||||
size_t v_size;
|
|
||||||
in.read(reinterpret_cast<char *>(&v_size), sizeof(v_size));
|
|
||||||
vertices.resize(v_size, PackedVertexData(0, 0, 0, 0, 0, 0, 0, 0));
|
|
||||||
in.read(reinterpret_cast<char *>(vertices.data()), sizeof(buffer::PackedVertexData) * v_size);
|
|
||||||
}
|
|
||||||
void ShortIndexed::Data::serialize(std::ofstream& out) {
|
|
||||||
{
|
|
||||||
size_t i_size = indices.size();
|
|
||||||
out.write(reinterpret_cast<char *>(&i_size), sizeof(i_size));
|
|
||||||
out.write(reinterpret_cast<char *>(indices.data()), sizeof(GLushort) * i_size);
|
|
||||||
}
|
|
||||||
size_t v_size = vertices.size();
|
|
||||||
out.write(reinterpret_cast<char *>(&v_size), sizeof(v_size));
|
|
||||||
out.write(reinterpret_cast<char *>(vertices.data()), sizeof(buffer::PackedVertexData) * v_size);
|
|
||||||
}
|
|
||||||
void ShortIndexed::Data::index(const std::vector<PackedVertexData>& vs) {
|
|
||||||
indexVBO(vs, indices, vertices);
|
|
||||||
}
|
|
||||||
|
|
||||||
ShortIndexed::ShortIndexed(GLenum shape, const std::vector<PackedVertexData> &vertices): Abstract(shape) {
|
|
||||||
setData(ShortIndexed::Data(vertices));
|
|
||||||
}
|
|
||||||
ShortIndexed::ShortIndexed(GLenum shape, const std::vector<PackedVertexData> &vertices, const std::vector<GLushort>& indices): Abstract(shape) {
|
|
||||||
setData(ShortIndexed::Data(vertices, indices));
|
|
||||||
}
|
|
||||||
ShortIndexed::ShortIndexed(GLenum shape, const ShortIndexed::Data &data): Abstract(shape) {
|
|
||||||
setData(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
ShortIndexed::~ShortIndexed() {
|
|
||||||
glDeleteBuffers(1, &IndexBufferID);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShortIndexed::enableVertexAttrib() {
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID);
|
|
||||||
glVertexAttribPointer(
|
|
||||||
0, // attribute
|
|
||||||
3, // size
|
|
||||||
GL_HALF_FLOAT, // type
|
|
||||||
GL_FALSE, // normalized?
|
|
||||||
sizeof(PackedVertexData), // stride
|
|
||||||
reinterpret_cast<void *>(offsetof(PackedVertexData, PosMat[0])) // array buffer offset
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShortIndexed::enableAllAttribs() {
|
|
||||||
enableVertexAttrib();
|
|
||||||
|
|
||||||
glEnableVertexAttribArray(1);
|
|
||||||
glVertexAttribIPointer(
|
|
||||||
1, // attribute
|
|
||||||
1, // size
|
|
||||||
GL_UNSIGNED_SHORT, // type
|
|
||||||
sizeof(PackedVertexData), // stride
|
|
||||||
reinterpret_cast<void *>(offsetof(PackedVertexData, PosMat[3])) // array buffer offset
|
|
||||||
);
|
|
||||||
|
|
||||||
glEnableVertexAttribArray(2);
|
|
||||||
glVertexAttribPointer(
|
|
||||||
2, // attribute
|
|
||||||
3, // size
|
|
||||||
GL_HALF_FLOAT, // type
|
|
||||||
GL_FALSE, // normalized?
|
|
||||||
sizeof(PackedVertexData), // stride
|
|
||||||
reinterpret_cast<void *>(offsetof(PackedVertexData, Nrm)) // array buffer offset
|
|
||||||
);
|
|
||||||
}
|
|
||||||
void ShortIndexed::disableAllAttribs() {
|
|
||||||
glDisableVertexAttribArray(2);
|
|
||||||
glDisableVertexAttribArray(1);
|
|
||||||
disableVertexAttrib();
|
|
||||||
}
|
|
||||||
void ShortIndexed::enableIndex() {
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferID);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint ShortIndexed::draw(buffer::params params) {
|
|
||||||
if(IndexSize == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if(params.vertexOnly) {
|
|
||||||
enableVertexAttrib();
|
|
||||||
} else {
|
|
||||||
enableAllAttribs();
|
|
||||||
}
|
|
||||||
enableIndex();
|
|
||||||
if (params.instances == 1) {
|
|
||||||
glDrawElements(Shape, IndexSize, GL_UNSIGNED_SHORT, (void *)0);
|
|
||||||
} else {
|
|
||||||
glDrawElementsInstanced(Shape, IndexSize, GL_UNSIGNED_SHORT, (void *)0, params.instances);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(params.vertexOnly) {
|
|
||||||
disableVertexAttrib();
|
|
||||||
} else {
|
|
||||||
disableAllAttribs();
|
|
||||||
}
|
|
||||||
return IndexSize * params.instances;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShortIndexed::setData(const ShortIndexed::Data& data) {
|
|
||||||
glGenBuffers(1, &IndexBufferID);
|
|
||||||
|
|
||||||
IndexSize = data.indices.size();
|
|
||||||
if(IndexSize != data.indices.size()) {
|
|
||||||
LOG_E("ShortBuffer overflow: " << data.indices.size());
|
|
||||||
}
|
|
||||||
setIndicies(IndexSize * sizeof(GLushort), data.indices.data());
|
|
||||||
setVertices(data.vertices.size() * sizeof(PackedVertexData), data.vertices.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);
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <GL/gl3w.h>
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
#include <vector>
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
#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<PackedVertexData> vertices;
|
|
||||||
|
|
||||||
Data() { }
|
|
||||||
Data(const std::vector<PackedVertexData> &vertices, const std::vector<GLushort> &indices);
|
|
||||||
Data(const std::vector<PackedVertexData> &vertices) { index(vertices); }
|
|
||||||
Data(std::ifstream &in);
|
|
||||||
|
|
||||||
void index(const std::vector<PackedVertexData> &vertices);
|
|
||||||
bool empty() const {
|
|
||||||
return indices.empty();
|
|
||||||
}
|
|
||||||
void clear() {
|
|
||||||
indices.clear();
|
|
||||||
vertices.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void serialize(std::ofstream &out);
|
|
||||||
};
|
|
||||||
|
|
||||||
ShortIndexed(GLenum shape, const typename std::vector<PackedVertexData> &vertices);
|
|
||||||
ShortIndexed(GLenum shape, const typename std::vector<PackedVertexData> &vertices, const typename std::vector<GLushort> &indices);
|
|
||||||
ShortIndexed(GLenum shape, const typename ShortIndexed::Data &data);
|
|
||||||
virtual ~ShortIndexed();
|
|
||||||
|
|
||||||
uint draw(params params) override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void enableVertexAttrib();
|
|
||||||
void enableAllAttribs();
|
|
||||||
void disableAllAttribs();
|
|
||||||
void enableIndex();
|
|
||||||
GLushort IndexSize = 0;
|
|
||||||
private:
|
|
||||||
GLuint IndexBufferID;
|
|
||||||
|
|
||||||
void setData(const ShortIndexed::Data &data);
|
|
||||||
void setIndicies(const unsigned long size, const void *data);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
#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;
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <GL/gl3w.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;
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
#include <string.h> // for memcmp
|
|
||||||
#include <GL/gl3w.h>
|
|
||||||
|
|
||||||
namespace buffer {
|
|
||||||
/// Vertex properties
|
|
||||||
struct VertexData {
|
|
||||||
VertexData(const glm::vec3 &position, GLushort material, const glm::vec3 &normal):
|
|
||||||
Position(position), Material(material), Normal(normal) { }
|
|
||||||
glm::vec3 Position;
|
|
||||||
GLushort Material;
|
|
||||||
glm::vec3 Normal;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Quantized vertex properties
|
|
||||||
struct PackedVertexData {
|
|
||||||
PackedVertexData(GLushort x, GLushort y, GLushort z, GLushort mat, GLushort nx, GLushort ny, GLushort nz, GLushort nw = 0) {
|
|
||||||
PosMat[0] = x;
|
|
||||||
PosMat[1] = y;
|
|
||||||
PosMat[2] = z;
|
|
||||||
PosMat[3] = mat;
|
|
||||||
Nrm[0] = nx;
|
|
||||||
Nrm[1] = ny;
|
|
||||||
Nrm[2] = nz;
|
|
||||||
Nrm[3] = nw;
|
|
||||||
}
|
|
||||||
GLushort PosMat[4];
|
|
||||||
GLushort Nrm[4]; //NOTE: Triplanar does not handle 10_10_10_2_REV
|
|
||||||
bool operator<(const PackedVertexData that) const {
|
|
||||||
return memcmp((void *)this, (void *)&that, sizeof(PackedVertexData)) > 0;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
|
|
||||||
#include "vboindexer.hpp"
|
|
||||||
|
|
||||||
bool getSimilarVertexIndex_fast(
|
|
||||||
const buffer::PackedVertexData &packed,
|
|
||||||
std::map<buffer::PackedVertexData, GLushort> &VertexToOutIndex,
|
|
||||||
GLushort &result)
|
|
||||||
{
|
|
||||||
std::map<buffer::PackedVertexData, GLushort>::iterator it = VertexToOutIndex.find(packed);
|
|
||||||
if ( it == VertexToOutIndex.end() ){
|
|
||||||
return false;
|
|
||||||
}else{
|
|
||||||
result = it->second;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool getSimilarVertexIndex_fast(
|
|
||||||
const buffer::PackedVertexData &packed,
|
|
||||||
std::map<buffer::PackedVertexData, unsigned int> &VertexToOutIndex,
|
|
||||||
unsigned int &result)
|
|
||||||
{
|
|
||||||
std::map<buffer::PackedVertexData, unsigned int>::iterator it = VertexToOutIndex.find(packed);
|
|
||||||
if ( it == VertexToOutIndex.end() ){
|
|
||||||
return false;
|
|
||||||
}else{
|
|
||||||
result = it->second;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void indexVBO(
|
|
||||||
const std::vector<buffer::PackedVertexData> &in_vertices,
|
|
||||||
|
|
||||||
std::vector<GLushort> &out_indices,
|
|
||||||
std::vector<buffer::PackedVertexData> &out_vertices)
|
|
||||||
{
|
|
||||||
std::map<buffer::PackedVertexData, GLushort> VertexToOutIndex;
|
|
||||||
|
|
||||||
out_indices.reserve(in_vertices.size());
|
|
||||||
// For each input vertex
|
|
||||||
for (size_t i=0; i<in_vertices.size(); i++ ){
|
|
||||||
// Try to find a similar vertex in out_XXXX
|
|
||||||
GLushort index;
|
|
||||||
bool found = getSimilarVertexIndex_fast(in_vertices[i], VertexToOutIndex, index);
|
|
||||||
|
|
||||||
if ( found ){ // A similar vertex is already in the VBO, use it instead !
|
|
||||||
out_indices.push_back( index );
|
|
||||||
}else{ // If not, it needs to be added in the output data.
|
|
||||||
out_vertices.push_back(in_vertices[i]);
|
|
||||||
GLushort newindex = (GLushort)out_vertices.size() - 1;
|
|
||||||
out_indices.push_back( newindex );
|
|
||||||
VertexToOutIndex[ in_vertices[i] ] = newindex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
#ifndef VBOINDEXER_HPP
|
|
||||||
#define VBOINDEXER_HPP
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
#include "VertexData.hpp"
|
|
||||||
#include <GL/gl3w.h>
|
|
||||||
|
|
||||||
void indexVBO(
|
|
||||||
const std::vector<buffer::PackedVertexData> &in_vertices,
|
|
||||||
|
|
||||||
std::vector<GLushort> &out_indices,
|
|
||||||
std::vector<buffer::PackedVertexData> &out_vertices);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -20,10 +20,9 @@ ColorProgram::~ColorProgram() { }
|
||||||
std::string ColorProgram::getName() const {
|
std::string ColorProgram::getName() const {
|
||||||
return "Color";
|
return "Color";
|
||||||
}
|
}
|
||||||
buffer::params ColorProgram::setup(render::gl::Renderer *renderer, glm::mat4 modelMatrix) {
|
void ColorProgram::setup(render::gl::Renderer *renderer, glm::mat4 modelMatrix) {
|
||||||
const auto mvp = renderer->getProjectionMatrix() * renderer->getViewMatrix() * modelMatrix;
|
const auto mvp = renderer->getProjectionMatrix() * renderer->getViewMatrix() * modelMatrix;
|
||||||
setMVP(&mvp[0][0]);
|
setMVP(&mvp[0][0]);
|
||||||
return buffer::params{.vertexOnly = false};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ColorProgram::setMVP(const GLfloat *matrix) {
|
void ColorProgram::setMVP(const GLfloat *matrix) {
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace pass {
|
||||||
ColorProgram();
|
ColorProgram();
|
||||||
~ColorProgram();
|
~ColorProgram();
|
||||||
|
|
||||||
buffer::params setup(render::gl::Renderer *, glm::mat4 modelMatrix);
|
void setup(render::gl::Renderer *, glm::mat4 modelMatrix);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string getName() const override;
|
std::string getName() const override;
|
||||||
|
|
|
@ -17,11 +17,9 @@ EntityProgram::EntityProgram(const EntityProgram::options &opts) : VoxelProgram(
|
||||||
}
|
}
|
||||||
EntityProgram::~EntityProgram() { }
|
EntityProgram::~EntityProgram() { }
|
||||||
|
|
||||||
buffer::params EntityProgram::setup(render::gl::Renderer *renderer, const std::vector<glm::mat4>& modelsMatrices) {
|
void EntityProgram::setup(render::gl::Renderer *renderer, const std::vector<glm::mat4>& modelsMatrices) {
|
||||||
setModels(&modelsMatrices[0][0][0], modelsMatrices.size());
|
setModels(&modelsMatrices[0][0][0], modelsMatrices.size());
|
||||||
auto params = VoxelProgram::setup(renderer);
|
VoxelProgram::setup(renderer);
|
||||||
params.instances = modelsMatrices.size();
|
|
||||||
return params;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityProgram::setModels(const GLfloat *matrices, size_t count) {
|
void EntityProgram::setModels(const GLfloat *matrices, size_t count) {
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace pass {
|
||||||
|
|
||||||
static constexpr auto LOCATION = 6;
|
static constexpr auto LOCATION = 6;
|
||||||
|
|
||||||
buffer::params setup(render::gl::Renderer *, const std::vector<glm::mat4> &modelsMatrices);
|
void setup(render::gl::Renderer *, const std::vector<glm::mat4> &modelsMatrices);
|
||||||
void disable();
|
void disable();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
#include "Shader.hpp"
|
#include "Shader.hpp"
|
||||||
#include "../buffer/Abstract.hpp"
|
|
||||||
|
|
||||||
namespace render {
|
namespace render {
|
||||||
struct passOptions;
|
struct passOptions;
|
||||||
|
|
|
@ -4,50 +4,50 @@
|
||||||
|
|
||||||
using namespace pass;
|
using namespace pass;
|
||||||
|
|
||||||
const GLfloat g_cubemap_vertices[] = {
|
const std::vector<glm::vec3> g_cubemap_vertices = {
|
||||||
-1.0f, 1.0f, -1.0f,
|
{-1.0f, 1.0f, -1.0f},
|
||||||
-1.0f, -1.0f, -1.0f,
|
{-1.0f, -1.0f, -1.0f},
|
||||||
1.0f, -1.0f, -1.0f,
|
{ 1.0f, -1.0f, -1.0f},
|
||||||
1.0f, -1.0f, -1.0f,
|
{ 1.0f, -1.0f, -1.0f},
|
||||||
1.0f, 1.0f, -1.0f,
|
{ 1.0f, 1.0f, -1.0f},
|
||||||
-1.0f, 1.0f, -1.0f,
|
{-1.0f, 1.0f, -1.0f},
|
||||||
|
|
||||||
-1.0f, -1.0f, 1.0f,
|
{-1.0f, -1.0f, 1.0f},
|
||||||
-1.0f, -1.0f, -1.0f,
|
{-1.0f, -1.0f, -1.0f},
|
||||||
-1.0f, 1.0f, -1.0f,
|
{-1.0f, 1.0f, -1.0f},
|
||||||
-1.0f, 1.0f, -1.0f,
|
{-1.0f, 1.0f, -1.0f},
|
||||||
-1.0f, 1.0f, 1.0f,
|
{-1.0f, 1.0f, 1.0f},
|
||||||
-1.0f, -1.0f, 1.0f,
|
{-1.0f, -1.0f, 1.0f},
|
||||||
|
|
||||||
1.0f, -1.0f, -1.0f,
|
{ 1.0f, -1.0f, -1.0f},
|
||||||
1.0f, -1.0f, 1.0f,
|
{ 1.0f, -1.0f, 1.0f},
|
||||||
1.0f, 1.0f, 1.0f,
|
{ 1.0f, 1.0f, 1.0f},
|
||||||
1.0f, 1.0f, 1.0f,
|
{ 1.0f, 1.0f, 1.0f},
|
||||||
1.0f, 1.0f, -1.0f,
|
{ 1.0f, 1.0f, -1.0f},
|
||||||
1.0f, -1.0f, -1.0f,
|
{ 1.0f, -1.0f, -1.0f},
|
||||||
|
|
||||||
-1.0f, -1.0f, 1.0f,
|
{-1.0f, -1.0f, 1.0f},
|
||||||
-1.0f, 1.0f, 1.0f,
|
{-1.0f, 1.0f, 1.0f},
|
||||||
1.0f, 1.0f, 1.0f,
|
{ 1.0f, 1.0f, 1.0f},
|
||||||
1.0f, 1.0f, 1.0f,
|
{ 1.0f, 1.0f, 1.0f},
|
||||||
1.0f, -1.0f, 1.0f,
|
{ 1.0f, -1.0f, 1.0f},
|
||||||
-1.0f, -1.0f, 1.0f,
|
{-1.0f, -1.0f, 1.0f},
|
||||||
|
|
||||||
-1.0f, 1.0f, -1.0f,
|
{-1.0f, 1.0f, -1.0f},
|
||||||
1.0f, 1.0f, -1.0f,
|
{ 1.0f, 1.0f, -1.0f},
|
||||||
1.0f, 1.0f, 1.0f,
|
{ 1.0f, 1.0f, 1.0f},
|
||||||
1.0f, 1.0f, 1.0f,
|
{ 1.0f, 1.0f, 1.0f},
|
||||||
-1.0f, 1.0f, 1.0f,
|
{-1.0f, 1.0f, 1.0f},
|
||||||
-1.0f, 1.0f, -1.0f,
|
{-1.0f, 1.0f, -1.0f},
|
||||||
|
|
||||||
-1.0f, -1.0f, -1.0f,
|
{-1.0f, -1.0f, -1.0f},
|
||||||
-1.0f, -1.0f, 1.0f,
|
{-1.0f, -1.0f, 1.0f},
|
||||||
1.0f, -1.0f, -1.0f,
|
{ 1.0f, -1.0f, -1.0f},
|
||||||
1.0f, -1.0f, -1.0f,
|
{ 1.0f, -1.0f, -1.0f},
|
||||||
-1.0f, -1.0f, 1.0f,
|
{-1.0f, -1.0f, 1.0f},
|
||||||
1.0f, -1.0f, 1.0f
|
{ 1.0f, -1.0f, 1.0f}
|
||||||
};
|
};
|
||||||
SkyProgram::SkyProgram(): Program(), CubeBuffer(GL_TRIANGLES, 36, sizeof(g_cubemap_vertices), g_cubemap_vertices) {
|
SkyProgram::SkyProgram(): Program(), CubeBuffer(g_cubemap_vertices) {
|
||||||
|
|
||||||
std::vector<std::string> flags;
|
std::vector<std::string> flags;
|
||||||
std::vector<Shader*> shaders;
|
std::vector<Shader*> shaders;
|
||||||
|
@ -72,13 +72,10 @@ void SkyProgram::start(render::gl::Renderer *renderer) {
|
||||||
|
|
||||||
bindTexture(renderer->getSkyTexture());
|
bindTexture(renderer->getSkyTexture());
|
||||||
}
|
}
|
||||||
buffer::params SkyProgram::setup() {
|
|
||||||
return buffer::params{.vertexOnly = true};
|
|
||||||
}
|
|
||||||
void SkyProgram::draw(render::gl::Renderer *renderer) {
|
void SkyProgram::draw(render::gl::Renderer *renderer) {
|
||||||
useIt();
|
useIt();
|
||||||
start(renderer);
|
start(renderer);
|
||||||
CubeBuffer.draw(setup());
|
CubeBuffer.draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkyProgram::setView(const GLfloat *matrix) {
|
void SkyProgram::setView(const GLfloat *matrix) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Program.hpp"
|
#include "Program.hpp"
|
||||||
#include "../buffer/Vertex.hpp"
|
#include "../api/Models.hpp"
|
||||||
|
|
||||||
namespace pass {
|
namespace pass {
|
||||||
/// Skybox pass
|
/// Skybox pass
|
||||||
|
@ -11,7 +11,6 @@ namespace pass {
|
||||||
~SkyProgram();
|
~SkyProgram();
|
||||||
|
|
||||||
void start(render::gl::Renderer *);
|
void start(render::gl::Renderer *);
|
||||||
buffer::params setup();
|
|
||||||
|
|
||||||
/// Direct draw using internal buffer
|
/// Direct draw using internal buffer
|
||||||
void draw(render::gl::Renderer *);
|
void draw(render::gl::Renderer *);
|
||||||
|
@ -28,6 +27,6 @@ namespace pass {
|
||||||
GLuint ProjectionMatrixID;
|
GLuint ProjectionMatrixID;
|
||||||
GLuint TextureID;
|
GLuint TextureID;
|
||||||
|
|
||||||
buffer::Vertex CubeBuffer;
|
render::gl::Shape CubeBuffer;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,10 +62,9 @@ void VoxelProgram::start(render::gl::Renderer *renderer) {
|
||||||
setView(&renderer->getViewMatrix()[0][0]);
|
setView(&renderer->getViewMatrix()[0][0]);
|
||||||
setProj(&renderer->getProjectionMatrix()[0][0]);
|
setProj(&renderer->getProjectionMatrix()[0][0]);
|
||||||
}
|
}
|
||||||
buffer::params VoxelProgram::setup(render::gl::Renderer *renderer) {
|
void VoxelProgram::setup(render::gl::Renderer *renderer) {
|
||||||
setSphereProj(&renderer->getSphereProj()[0]);
|
setSphereProj(&renderer->getSphereProj()[0]);
|
||||||
setCurvature(renderer->getCurvature());
|
setCurvature(renderer->getCurvature());
|
||||||
return buffer::params{.vertexOnly = false};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelProgram::setProj(const GLfloat *matrix) {
|
void VoxelProgram::setProj(const GLfloat *matrix) {
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace pass {
|
||||||
void start(render::gl::Renderer *);
|
void start(render::gl::Renderer *);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
buffer::params setup(render::gl::Renderer *);
|
void setup(render::gl::Renderer *);
|
||||||
|
|
||||||
std::string getName() const override;
|
std::string getName() const override;
|
||||||
void setView(const GLfloat *matrix);
|
void setView(const GLfloat *matrix);
|
||||||
|
|
|
@ -11,9 +11,9 @@ WorldProgram::WorldProgram(const WorldProgram::options& opts): VoxelProgram(opts
|
||||||
|
|
||||||
WorldProgram::~WorldProgram() { }
|
WorldProgram::~WorldProgram() { }
|
||||||
|
|
||||||
buffer::params WorldProgram::setup(render::gl::Renderer *renderer, glm::mat4 modelMatrix) {
|
void WorldProgram::setup(render::gl::Renderer *renderer, glm::mat4 modelMatrix) {
|
||||||
setModel(&modelMatrix[0][0]);
|
setModel(&modelMatrix[0][0]);
|
||||||
return VoxelProgram::setup(renderer);
|
VoxelProgram::setup(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldProgram::setModel(const GLfloat *matrix) {
|
void WorldProgram::setModel(const GLfloat *matrix) {
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace pass {
|
||||||
WorldProgram(const options &opts);
|
WorldProgram(const options &opts);
|
||||||
~WorldProgram();
|
~WorldProgram();
|
||||||
|
|
||||||
buffer::params setup(render::gl::Renderer *, glm::mat4 modelMatrix);
|
void setup(render::gl::Renderer *, glm::mat4 modelMatrix);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setModel(const GLfloat *matrix);
|
void setModel(const GLfloat *matrix);
|
||||||
|
|
|
@ -7,12 +7,15 @@
|
||||||
|
|
||||||
using namespace render::vk;
|
using namespace render::vk;
|
||||||
|
|
||||||
constexpr auto HOST_EASILY_WRITABLE = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
Allocator* Allocator::sInstance = nullptr;
|
||||||
constexpr VkDeviceSize MIN_ALLOC_SIZE = 1 << 28;
|
|
||||||
const auto NO_DELETER = Allocator::MemoryDeleter(nullptr);
|
|
||||||
Allocator::memory_ptr Allocator::GetNull() { return Allocator::memory_ptr(nullptr, NO_DELETER); }
|
|
||||||
|
|
||||||
Allocator::Allocator(VkDevice device, const PhysicalDeviceInfo &info): physicalDevice(info.device), device(device) {
|
constexpr VkDeviceSize MIN_ALLOC_SIZE = 1 << 28;
|
||||||
|
const auto NO_DELETER = memory::Deleter(nullptr);
|
||||||
|
memory::ptr memory::GetNull() { return memory::ptr(nullptr, NO_DELETER); }
|
||||||
|
|
||||||
|
Allocator::Allocator(VkDevice device, const PhysicalDeviceInfo &info): physicalDevice(info.device),
|
||||||
|
capabilities({info.features.samplerAnisotropy == VK_TRUE}), device(device)
|
||||||
|
{
|
||||||
if(info.hasMemoryBudget()) {
|
if(info.hasMemoryBudget()) {
|
||||||
properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2;
|
properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2;
|
||||||
properties2.pNext = &budget;
|
properties2.pNext = &budget;
|
||||||
|
@ -83,166 +86,6 @@ void Allocator::setTracyZone(const char* name) {
|
||||||
(void)name;
|
(void)name;
|
||||||
}
|
}
|
||||||
|
|
||||||
Allocator::memory_ptr Allocator::createBuffer(const buffer_requirement& requirement, VkMemoryPropertyFlags properties, buffer_info& out) {
|
|
||||||
VkBufferCreateInfo bufferInfo{};
|
|
||||||
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
|
||||||
bufferInfo.size = requirement.size;
|
|
||||||
bufferInfo.usage = requirement.usage;
|
|
||||||
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
|
|
||||||
if (vkCreateBuffer(device, &bufferInfo, ALLOC, &out.buffer) != VK_SUCCESS) {
|
|
||||||
LOG_E("Failed to create buffer");
|
|
||||||
return GetNull();
|
|
||||||
}
|
|
||||||
out.offset = 0;
|
|
||||||
|
|
||||||
VkMemoryRequirements memRequirements;
|
|
||||||
vkGetBufferMemoryRequirements(device, out.buffer, &memRequirements);
|
|
||||||
|
|
||||||
auto memory = allocate(memRequirements, properties);
|
|
||||||
if (!memory || vkBindBufferMemory(device, out.buffer, memory->ref, memory->offset) != VK_SUCCESS) {
|
|
||||||
LOG_E("Failed to allocate buffer memory");
|
|
||||||
return GetNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requirement.size != 0 && requirement.data != nullptr) {
|
|
||||||
if (memory->ptr != nullptr) {
|
|
||||||
memory->write(requirement.data, requirement.data_size, requirement.data_offset);
|
|
||||||
} else {
|
|
||||||
Allocator::buffer_info stagingBuffer;
|
|
||||||
if(auto stagingMemory = createBuffer({requirement.size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT}, HOST_EASILY_WRITABLE, stagingBuffer)) {
|
|
||||||
stagingMemory->write(requirement.data, requirement.data_size, requirement.data_offset);
|
|
||||||
copyBuffer(stagingBuffer, out, requirement.size);
|
|
||||||
vkDestroyBuffer(device, stagingBuffer.buffer, ALLOC); //TODO: move to buffer destructor
|
|
||||||
} else {
|
|
||||||
FATAL("Cannot allocate staging memory");
|
|
||||||
return GetNull();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return memory;
|
|
||||||
}
|
|
||||||
Allocator::memory_ptr Allocator::createBuffers(const std::vector<buffer_requirement>& requirements, VkMemoryPropertyFlags properties, std::vector<buffer_info>& out) {
|
|
||||||
assert(!requirements.empty());
|
|
||||||
out.resize(requirements.size()+1);
|
|
||||||
|
|
||||||
// Create buffers
|
|
||||||
VkMemoryRequirements memRequirements = {0, 0, UINT32_MAX};
|
|
||||||
std::vector<VkDeviceSize> sizes;
|
|
||||||
sizes.resize(requirements.size());
|
|
||||||
for (size_t i = 0; i < requirements.size(); i++) {
|
|
||||||
VkBufferCreateInfo bufferInfo{};
|
|
||||||
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
|
||||||
bufferInfo.size = requirements[i].size;
|
|
||||||
bufferInfo.usage = requirements[i].usage;
|
|
||||||
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
|
|
||||||
if (vkCreateBuffer(device, &bufferInfo, ALLOC, &out[i].buffer) != VK_SUCCESS) {
|
|
||||||
LOG_E("Failed to create buffer");
|
|
||||||
return GetNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
VkMemoryRequirements individualMemRequirements;
|
|
||||||
vkGetBufferMemoryRequirements(device, out[i].buffer, &individualMemRequirements);
|
|
||||||
memRequirements.alignment = std::max(memRequirements.alignment, individualMemRequirements.alignment);
|
|
||||||
memRequirements.memoryTypeBits &= individualMemRequirements.memoryTypeBits;
|
|
||||||
sizes[i] = individualMemRequirements.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Align blocks
|
|
||||||
auto aligned = [&](VkDeviceSize offset) {
|
|
||||||
if (offset % memRequirements.alignment == 0)
|
|
||||||
return offset;
|
|
||||||
return offset + memRequirements.alignment - (offset % memRequirements.alignment);
|
|
||||||
};
|
|
||||||
out[0].offset = 0;
|
|
||||||
for (size_t i = 1; i < out.size(); i++) {
|
|
||||||
out[i].offset = aligned(out[i-1].offset + sizes[i-1]);
|
|
||||||
}
|
|
||||||
memRequirements.size = out.back().offset;
|
|
||||||
out.pop_back();
|
|
||||||
|
|
||||||
// Bind memory
|
|
||||||
auto memory = allocate(memRequirements, properties);
|
|
||||||
if (!memory) {
|
|
||||||
LOG_E("Failed to allocate buffers");
|
|
||||||
return GetNull();
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < requirements.size(); i++) {
|
|
||||||
if (vkBindBufferMemory(device, out[i].buffer, memory->ref, memory->offset + out[i].offset) != VK_SUCCESS) {
|
|
||||||
LOG_E("Failed to bind buffer");
|
|
||||||
return GetNull();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDeviceSize stagingSize = 0;
|
|
||||||
for (auto& requirement: requirements)
|
|
||||||
if (requirement.data != nullptr)
|
|
||||||
stagingSize = std::max(stagingSize, requirement.size);
|
|
||||||
|
|
||||||
// Copy datas
|
|
||||||
if (stagingSize != 0) {
|
|
||||||
if (memory->ptr != nullptr) {
|
|
||||||
for (size_t i = 0; i < requirements.size(); i++) {
|
|
||||||
if (requirements[i].data != nullptr && requirements[i].size != 0) {
|
|
||||||
assert(requirements[i].data_size + requirements[i].data_offset <= requirements[i].size);
|
|
||||||
memory->write(requirements[i].data, requirements[i].data_size, out[i].offset + requirements[i].data_offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Allocator::buffer_info stagingBuffer;
|
|
||||||
if(auto stagingMemory = createBuffer({stagingSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT}, HOST_EASILY_WRITABLE, stagingBuffer)) {
|
|
||||||
for (size_t i = 0; i < requirements.size(); i++) {
|
|
||||||
if (requirements[i].data != nullptr && requirements[i].size != 0) {
|
|
||||||
assert(requirements[i].data_size + requirements[i].data_offset <= requirements[i].size);
|
|
||||||
stagingMemory->write(requirements[i].data, requirements[i].data_size, requirements[i].data_offset);
|
|
||||||
copyBuffer(stagingBuffer, out[i], requirements[i].size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vkDestroyBuffer(device, stagingBuffer.buffer, ALLOC); //TODO: move to buffer destructor
|
|
||||||
} else {
|
|
||||||
FATAL("Cannot allocate staging memory");
|
|
||||||
return GetNull();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return memory;
|
|
||||||
}
|
|
||||||
Allocator::memory_ptr Allocator::createImage(const VkImageCreateInfo& info, VkMemoryPropertyFlags properties, image_info& out,
|
|
||||||
const void *data, VkDeviceSize data_size, VkDeviceSize data_offset, VkImageLayout finalLayout) {
|
|
||||||
|
|
||||||
if (vkCreateImage(device, &info, ALLOC, &out.image) != VK_SUCCESS) {
|
|
||||||
LOG_E("Failed to create image");
|
|
||||||
return GetNull();
|
|
||||||
}
|
|
||||||
out.offset = 0;
|
|
||||||
|
|
||||||
VkMemoryRequirements memRequirements;
|
|
||||||
vkGetImageMemoryRequirements(device, out.image, &memRequirements);
|
|
||||||
|
|
||||||
auto memory = allocate(memRequirements, properties, true);
|
|
||||||
if (!memory || vkBindImageMemory(device, out.image, memory->ref, memory->offset) != VK_SUCCESS) {
|
|
||||||
LOG_E("Failed to allocate image memory");
|
|
||||||
return GetNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data_size != 0 && data != nullptr) {
|
|
||||||
Allocator::buffer_info stagingBuffer;
|
|
||||||
if(auto stagingMemory = createBuffer({data_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT}, HOST_EASILY_WRITABLE, stagingBuffer)) {
|
|
||||||
stagingMemory->write(data, data_size, data_offset);
|
|
||||||
transitionImageLayout(out.image, info.format, info.initialLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
|
||||||
copyBufferToImage(stagingBuffer, out, info.extent.width, info.extent.height);
|
|
||||||
transitionImageLayout(out.image, info.format, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, finalLayout);
|
|
||||||
vkDestroyBuffer(device, stagingBuffer.buffer, ALLOC); //TODO: move to buffer destructor
|
|
||||||
} else {
|
|
||||||
FATAL("Cannot allocate staging memory");
|
|
||||||
return GetNull();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return memory;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Allocator::updateProperties() {
|
void Allocator::updateProperties() {
|
||||||
if (hasBudget()) {
|
if (hasBudget()) {
|
||||||
vkGetPhysicalDeviceMemoryProperties2(physicalDevice, &properties2);
|
vkGetPhysicalDeviceMemoryProperties2(physicalDevice, &properties2);
|
||||||
|
@ -256,7 +99,7 @@ void Allocator::updateProperties() {
|
||||||
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &properties);
|
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &properties);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Allocator::memory_ptr Allocator::allocate(VkMemoryRequirements requirements, VkMemoryPropertyFlags properties, bool optimalTiling) {
|
memory::ptr Allocator::allocate(VkMemoryRequirements requirements, VkMemoryPropertyFlags properties, bool optimalTiling) {
|
||||||
// Search in existing allocations
|
// Search in existing allocations
|
||||||
for (auto& alloc: allocations) {
|
for (auto& alloc: allocations) {
|
||||||
if ((requirements.memoryTypeBits & (1 << alloc->memoryType)) &&
|
if ((requirements.memoryTypeBits & (1 << alloc->memoryType)) &&
|
||||||
|
@ -272,7 +115,7 @@ Allocator::memory_ptr Allocator::allocate(VkMemoryRequirements requirements, VkM
|
||||||
auto it = alloc->areas.cbegin();
|
auto it = alloc->areas.cbegin();
|
||||||
auto done = [&] {
|
auto done = [&] {
|
||||||
alloc->areas.insert(it, {requirements.size, start});
|
alloc->areas.insert(it, {requirements.size, start});
|
||||||
return memory_ptr(new memory_area{alloc->memory, requirements.size, start, alloc->ptr != nullptr ? alloc->ptr + start : nullptr}, alloc->deleter);
|
return memory::ptr(new memory::area{alloc->memory, requirements.size, start, alloc->ptr != nullptr ? static_cast<uint8_t*>(alloc->ptr) + start : nullptr}, alloc->deleter);
|
||||||
};
|
};
|
||||||
while (it != alloc->areas.cend()) {
|
while (it != alloc->areas.cend()) {
|
||||||
if (it->offset - start > requirements.size) {
|
if (it->offset - start > requirements.size) {
|
||||||
|
@ -300,24 +143,24 @@ Allocator::memory_ptr Allocator::allocate(VkMemoryRequirements requirements, VkM
|
||||||
} else {
|
} else {
|
||||||
LOG_E("No suitable memory heap within memory budget");
|
LOG_E("No suitable memory heap within memory budget");
|
||||||
LOG_D(requirements.memoryTypeBits << ' ' << properties << ' ' << requirements.size);
|
LOG_D(requirements.memoryTypeBits << ' ' << properties << ' ' << requirements.size);
|
||||||
return GetNull();
|
return memory::GetNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDeviceMemory memory;
|
VkDeviceMemory memory;
|
||||||
if (vkAllocateMemory(device, &allocInfo, ALLOC, &memory) != VK_SUCCESS) {
|
if (vkAllocateMemory(device, &allocInfo, ALLOC, &memory) != VK_SUCCESS) {
|
||||||
LOG_E("Failed to allocate memory!");
|
LOG_E("Failed to allocate memory!");
|
||||||
return GetNull();
|
return memory::GetNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
void *ptr = nullptr;
|
void *ptr = nullptr;
|
||||||
if ((getProperties().memoryTypes[allocInfo.memoryTypeIndex].propertyFlags & HOST_EASILY_WRITABLE) == HOST_EASILY_WRITABLE) {
|
if ((getProperties().memoryTypes[allocInfo.memoryTypeIndex].propertyFlags & memory::HOST_EASILY_WRITABLE) == memory::HOST_EASILY_WRITABLE) {
|
||||||
vkMapMemory(device, memory, 0, VK_WHOLE_SIZE, 0, &ptr);
|
vkMapMemory(device, memory, 0, VK_WHOLE_SIZE, 0, &ptr);
|
||||||
}
|
} //TODO: allow flushable memory
|
||||||
|
|
||||||
auto allocation = allocations.emplace_back(new Allocation(device, memory, allocInfo.allocationSize, allocInfo.memoryTypeIndex, optimalTiling, ptr)).get();
|
auto allocation = allocations.emplace_back(new Allocation(device, memory, allocInfo.allocationSize, allocInfo.memoryTypeIndex, optimalTiling, ptr)).get();
|
||||||
allocation->areas.push_back({requirements.size, 0});
|
allocation->areas.push_back({requirements.size, 0});
|
||||||
|
|
||||||
return memory_ptr(new memory_area{memory, requirements.size, 0, ptr}, allocation->deleter);
|
return memory::ptr(new memory::area{memory, requirements.size, 0, ptr}, allocation->deleter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void beginCmd(VkCommandBuffer buffer) {
|
void beginCmd(VkCommandBuffer buffer) {
|
||||||
|
@ -340,16 +183,14 @@ void submitCmd(VkCommandBuffer buffer, VkQueue queue) {
|
||||||
vkQueueWaitIdle(queue); //MAYBE: use fences
|
vkQueueWaitIdle(queue); //MAYBE: use fences
|
||||||
vkResetCommandBuffer(buffer, 0);
|
vkResetCommandBuffer(buffer, 0);
|
||||||
}
|
}
|
||||||
void Allocator::copyBuffer(buffer_info src, buffer_info dst, VkDeviceSize size) {
|
void Allocator::copyBuffer(VkBuffer src, VkBuffer dst, VkDeviceSize size) {
|
||||||
//FIXME: assert no out of range
|
|
||||||
|
|
||||||
beginCmd(transferBuffer);
|
beginCmd(transferBuffer);
|
||||||
|
|
||||||
VkBufferCopy copyRegion{};
|
VkBufferCopy copyRegion{};
|
||||||
copyRegion.srcOffset = 0;
|
copyRegion.srcOffset = 0;
|
||||||
copyRegion.dstOffset = 0;
|
copyRegion.dstOffset = 0;
|
||||||
copyRegion.size = size;
|
copyRegion.size = size;
|
||||||
vkCmdCopyBuffer(transferBuffer, src.buffer, dst.buffer, 1, ©Region);
|
vkCmdCopyBuffer(transferBuffer, src, dst, 1, ©Region);
|
||||||
|
|
||||||
submitCmd(transferBuffer, transferQueue);
|
submitCmd(transferBuffer, transferQueue);
|
||||||
}
|
}
|
||||||
|
@ -394,11 +235,11 @@ void Allocator::transitionImageLayout(VkImage image, VkFormat format, VkImageLay
|
||||||
|
|
||||||
submitCmd(graphicsBuffer, graphicsQueue);
|
submitCmd(graphicsBuffer, graphicsQueue);
|
||||||
}
|
}
|
||||||
void Allocator::copyBufferToImage(buffer_info src, image_info dest, uint32_t width, uint32_t height) {
|
void Allocator::copyBufferToImage(VkBuffer src, VkImage dest, uint32_t width, uint32_t height) {
|
||||||
beginCmd(transferBuffer);
|
beginCmd(transferBuffer);
|
||||||
|
|
||||||
VkBufferImageCopy region{};
|
VkBufferImageCopy region{};
|
||||||
region.bufferOffset = src.offset;
|
region.bufferOffset = 0;
|
||||||
region.bufferRowLength = 0;
|
region.bufferRowLength = 0;
|
||||||
region.bufferImageHeight = 0;
|
region.bufferImageHeight = 0;
|
||||||
|
|
||||||
|
@ -410,7 +251,7 @@ void Allocator::copyBufferToImage(buffer_info src, image_info dest, uint32_t wid
|
||||||
region.imageOffset = {0, 0, 0};
|
region.imageOffset = {0, 0, 0};
|
||||||
region.imageExtent = {width, height, 1};
|
region.imageExtent = {width, height, 1};
|
||||||
|
|
||||||
vkCmdCopyBufferToImage(transferBuffer, src.buffer, dest.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
vkCmdCopyBufferToImage(transferBuffer, src, dest, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||||
|
|
||||||
submitCmd(transferBuffer, transferQueue);
|
submitCmd(transferBuffer, transferQueue);
|
||||||
}
|
}
|
||||||
|
@ -451,12 +292,16 @@ std::optional<uint32_t> Allocator::findMemory(uint32_t typeFilter, VkMemoryPrope
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Allocator::memory_area::write(const void* data, size_t data_size, size_t write_offset) {
|
void memory::area::write(const void* data, size_t data_size, size_t write_offset) {
|
||||||
assert(ptr != nullptr && size >= write_offset + data_size);
|
assert(ptr != nullptr && size >= write_offset + data_size);
|
||||||
memcpy(ptr + write_offset, data, data_size);
|
memcpy(static_cast<uint8_t*>(ptr) + write_offset, data, data_size);
|
||||||
|
}
|
||||||
|
void memory::area::read(void* data, size_t data_size, size_t read_offset) {
|
||||||
|
assert(ptr != nullptr && size >= read_offset + data_size);
|
||||||
|
memcpy(data, static_cast<uint8_t*>(ptr) + read_offset, data_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Allocator::MemoryDeleter::operator()(memory_area* area) {
|
void memory::Deleter::operator()(memory::area* area) {
|
||||||
assert(area != nullptr && "Deleting null area");
|
assert(area != nullptr && "Deleting null area");
|
||||||
if(owner != nullptr) {
|
if(owner != nullptr) {
|
||||||
for (auto it = owner->areas.begin(); it != owner->areas.end(); ++it) {
|
for (auto it = owner->areas.begin(); it != owner->areas.end(); ++it) {
|
||||||
|
@ -472,9 +317,9 @@ void Allocator::MemoryDeleter::operator()(memory_area* area) {
|
||||||
LOG_E("Allocation area not found");
|
LOG_E("Allocation area not found");
|
||||||
delete area;
|
delete area;
|
||||||
}
|
}
|
||||||
Allocator::Allocation::Allocation(VkDevice device, VkDeviceMemory memory, VkDeviceSize size, uint32_t memoryType, bool optimalTiling, void *ptr):
|
Allocation::Allocation(VkDevice device, VkDeviceMemory memory, VkDeviceSize size, uint32_t memoryType, bool optimalTiling, void *ptr):
|
||||||
device(device), memory(memory), size(size), memoryType(memoryType), optimalTiling(optimalTiling), ptr(ptr), deleter(this) { }
|
device(device), memory(memory), size(size), memoryType(memoryType), optimalTiling(optimalTiling), ptr(ptr), deleter(this) { }
|
||||||
Allocator::Allocation::~Allocation() {
|
Allocation::~Allocation() {
|
||||||
if(!areas.empty())
|
if(!areas.empty())
|
||||||
LOG_E("Freeing " << areas.size() << " floating buffers");
|
LOG_E("Freeing " << areas.size() << " floating buffers");
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "forward.hpp"
|
#include "forward.hpp"
|
||||||
|
#include "../../../core/flags.hpp"
|
||||||
|
#include "api/Memory.hpp"
|
||||||
|
#include <cassert>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace tracy {
|
namespace tracy {
|
||||||
class VkCtx;
|
class VkCtx;
|
||||||
|
@ -11,65 +13,47 @@ namespace tracy {
|
||||||
typedef tracy::VkCtx* TracyVkCtx;
|
typedef tracy::VkCtx* TracyVkCtx;
|
||||||
namespace render::vk {
|
namespace render::vk {
|
||||||
|
|
||||||
class Allocator {
|
struct Allocation {
|
||||||
private:
|
Allocation(VkDevice, VkDeviceMemory, VkDeviceSize, uint32_t, bool optimalTiling, void *ptr);
|
||||||
struct Allocation;
|
~Allocation();
|
||||||
|
|
||||||
|
const VkDevice device;
|
||||||
|
const VkDeviceMemory memory;
|
||||||
|
const VkDeviceSize size;
|
||||||
|
const uint32_t memoryType;
|
||||||
|
const bool optimalTiling;
|
||||||
|
void *const ptr = nullptr;
|
||||||
|
const memory::Deleter deleter;
|
||||||
|
|
||||||
|
struct area { VkDeviceSize size; VkDeviceSize offset; };
|
||||||
|
std::vector<area> areas;
|
||||||
|
};
|
||||||
|
class Allocator final {
|
||||||
public:
|
public:
|
||||||
Allocator(VkDevice, const PhysicalDeviceInfo&);
|
Allocator(VkDevice, const PhysicalDeviceInfo&);
|
||||||
~Allocator();
|
~Allocator();
|
||||||
|
|
||||||
struct memory_area {
|
memory::ptr allocate(VkMemoryRequirements, VkMemoryPropertyFlags, bool optimalTiling = false);
|
||||||
VkDeviceMemory ref;
|
bool deallocate(const memory::area&);
|
||||||
VkDeviceSize size;
|
|
||||||
VkDeviceSize offset;
|
|
||||||
void *ptr = nullptr;
|
|
||||||
|
|
||||||
void write(const void*, VkDeviceSize size, VkDeviceSize offset = 0);
|
void copyBuffer(VkBuffer src, VkBuffer dst, VkDeviceSize size);
|
||||||
void read(void*, VkDeviceSize size, VkDeviceSize offset = 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
class MemoryDeleter {
|
|
||||||
public:
|
|
||||||
MemoryDeleter(Allocation *owner): owner(owner) { }
|
|
||||||
void operator()(memory_area *);
|
|
||||||
private:
|
|
||||||
Allocation *owner;
|
|
||||||
};
|
|
||||||
|
|
||||||
using memory_ptr = std::unique_ptr<memory_area, MemoryDeleter>;
|
|
||||||
|
|
||||||
memory_ptr allocate(VkMemoryRequirements, VkMemoryPropertyFlags, bool optimalTiling = false);
|
|
||||||
bool deallocate(const memory_area&);
|
|
||||||
|
|
||||||
struct buffer_info {
|
|
||||||
VkBuffer buffer = nullptr;
|
|
||||||
VkDeviceSize offset = 0;
|
|
||||||
};
|
|
||||||
struct buffer_requirement {
|
|
||||||
VkDeviceSize size;
|
|
||||||
VkBufferUsageFlags usage;
|
|
||||||
const void *data = nullptr;
|
|
||||||
VkDeviceSize data_size = 0;
|
|
||||||
VkDeviceSize data_offset = 0;
|
|
||||||
};
|
|
||||||
memory_ptr createBuffer(const buffer_requirement&, VkMemoryPropertyFlags, buffer_info&);
|
|
||||||
memory_ptr createBuffers(const std::vector<buffer_requirement> &, VkMemoryPropertyFlags, std::vector<buffer_info> &);
|
|
||||||
|
|
||||||
struct image_info {
|
|
||||||
VkImage image = nullptr;
|
|
||||||
VkDeviceSize offset = 0;
|
|
||||||
};
|
|
||||||
memory_ptr createImage(const VkImageCreateInfo&, VkMemoryPropertyFlags, image_info&,
|
|
||||||
const void *data = nullptr, VkDeviceSize data_size = 0, VkDeviceSize data_offset = 0,
|
|
||||||
VkImageLayout finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
|
||||||
|
|
||||||
void copyBuffer(buffer_info srcBuffer, buffer_info dstBuffer, VkDeviceSize size);
|
|
||||||
void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout);
|
void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout);
|
||||||
void copyBufferToImage(buffer_info buffer, image_info image, uint32_t width, uint32_t height);
|
void copyBufferToImage(VkBuffer src, VkImage dst, uint32_t width, uint32_t height);
|
||||||
|
|
||||||
void setTracyZone(const char* name);
|
void setTracyZone(const char* name);
|
||||||
|
|
||||||
static memory_ptr GetNull();
|
struct Capabilities {
|
||||||
|
bool anisotropy;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr VkDevice getDevice() const { return device; }
|
||||||
|
constexpr Capabilities getCapabilities() const { return capabilities; }
|
||||||
|
|
||||||
|
static void MakeDefault(Allocator *ptr) { sInstance = ptr; }
|
||||||
|
static _FORCE_INLINE_ Allocator *GetDefault() {
|
||||||
|
assert(sInstance != nullptr && "No default allocator");
|
||||||
|
return sInstance;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::optional<uint32_t> findMemory(uint32_t, VkMemoryPropertyFlags, VkDeviceSize size = 0);
|
std::optional<uint32_t> findMemory(uint32_t, VkMemoryPropertyFlags, VkDeviceSize size = 0);
|
||||||
|
@ -77,23 +61,8 @@ private:
|
||||||
constexpr const VkPhysicalDeviceMemoryProperties &getProperties() const { return hasBudget() ? properties2.memoryProperties : properties; }
|
constexpr const VkPhysicalDeviceMemoryProperties &getProperties() const { return hasBudget() ? properties2.memoryProperties : properties; }
|
||||||
void updateProperties();
|
void updateProperties();
|
||||||
|
|
||||||
struct Allocation {
|
|
||||||
Allocation(VkDevice, VkDeviceMemory, VkDeviceSize, uint32_t, bool optimalTiling, void *ptr);
|
|
||||||
~Allocation();
|
|
||||||
|
|
||||||
const VkDevice device;
|
|
||||||
const VkDeviceMemory memory;
|
|
||||||
const VkDeviceSize size;
|
|
||||||
const uint32_t memoryType;
|
|
||||||
const bool optimalTiling;
|
|
||||||
void *const ptr = nullptr;
|
|
||||||
const MemoryDeleter deleter;
|
|
||||||
|
|
||||||
struct area { VkDeviceSize size; VkDeviceSize offset; };
|
|
||||||
std::vector<area> areas;
|
|
||||||
};
|
|
||||||
|
|
||||||
VkPhysicalDevice const physicalDevice;
|
VkPhysicalDevice const physicalDevice;
|
||||||
|
Capabilities const capabilities;
|
||||||
VkDevice const device;
|
VkDevice const device;
|
||||||
VkPhysicalDeviceMemoryProperties properties{};
|
VkPhysicalDeviceMemoryProperties properties{};
|
||||||
VkPhysicalDeviceMemoryProperties2 properties2{};
|
VkPhysicalDeviceMemoryProperties2 properties2{};
|
||||||
|
@ -108,5 +77,7 @@ private:
|
||||||
VkCommandBuffer graphicsBuffer;
|
VkCommandBuffer graphicsBuffer;
|
||||||
|
|
||||||
std::vector<std::unique_ptr<Allocation>> allocations;
|
std::vector<std::unique_ptr<Allocation>> allocations;
|
||||||
|
|
||||||
|
static Allocator *sInstance;
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -2,20 +2,15 @@
|
||||||
|
|
||||||
#include "PhysicalDeviceInfo.hpp"
|
#include "PhysicalDeviceInfo.hpp"
|
||||||
#include "Pipeline.hpp"
|
#include "Pipeline.hpp"
|
||||||
#include "../Renderer.hpp"
|
#include "Renderer.hpp"
|
||||||
#include "buffer/VertexData.hpp"
|
#include "buffer/VertexData.hpp"
|
||||||
#include "texture.hpp"
|
|
||||||
|
|
||||||
using namespace render::vk;
|
using namespace render::vk;
|
||||||
|
|
||||||
#define CONTENT_DIR "content/"
|
#define CONTENT_DIR "content/"
|
||||||
#define TEXTURES_DIR CONTENT_DIR "textures/"
|
#define TEXTURES_DIR CONTENT_DIR "textures/"
|
||||||
|
|
||||||
CommandCenter::CommandCenter(VkDevice device, Allocator& alloc, const std::vector<VkImageView> &views,
|
CommandCenter::CommandCenter(VkDevice device, const PhysicalDeviceInfo &info, const renderOptions &opt): device(device) {
|
||||||
const Pipeline& pipe, const PhysicalDeviceInfo &info, const renderOptions &opt): device(device),
|
|
||||||
indexedBufferMemory(Allocator::GetNull()), sampleImageMemory(Allocator::GetNull()),
|
|
||||||
uniformBuffersMemory(Allocator::GetNull())
|
|
||||||
{
|
|
||||||
{ // Graphics command pool
|
{ // Graphics command pool
|
||||||
vkGetDeviceQueue(device, info.queueIndices.graphicsFamily.value(), 0, &graphicsQueue);
|
vkGetDeviceQueue(device, info.queueIndices.graphicsFamily.value(), 0, &graphicsQueue);
|
||||||
VkCommandPoolCreateInfo poolInfo{};
|
VkCommandPoolCreateInfo poolInfo{};
|
||||||
|
@ -28,114 +23,26 @@ CommandCenter::CommandCenter(VkDevice device, Allocator& alloc, const std::vecto
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{ // Vertex buffers (const)
|
{ // Vertex buffers (const)
|
||||||
size_t vertexSize = sizeof(buffer::vk::vertices[0]) * buffer::vk::vertices.size();
|
modelBuffer = ShortIndexedVertexBuffer::Create(buffer::vk::vertices, buffer::vk::indices);
|
||||||
size_t indexSize = sizeof(buffer::vk::indices[0]) * buffer::vk::indices.size();
|
if (!modelBuffer) {
|
||||||
if(std::vector<Allocator::buffer_info> out; indexedBufferMemory = alloc.createBuffers({
|
|
||||||
{indexSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, buffer::vk::indices.data(), indexSize, 0},
|
|
||||||
{vertexSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, buffer::vk::vertices.data(), vertexSize, 0}
|
|
||||||
}, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, out)) {
|
|
||||||
indexBuffer = out[0];
|
|
||||||
vertexBuffer = out[1];
|
|
||||||
} else {
|
|
||||||
FATAL("Cannot create vertex buffer");
|
FATAL("Cannot create vertex buffer");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{ // Texture sampler (const)
|
{ // Texture sampler (const)
|
||||||
std::vector<unsigned char> data;
|
sampleTexture = Texture::LoadFromFile(TEXTURES_DIR "1024-realistic/terrain/Mapl.dds", {true, true, Texture::Wrap::MIRRORED_REPEAT, opt.anisotropy});
|
||||||
dds::header_info header;
|
if (!sampleTexture) {
|
||||||
if (dds::readDDS(TEXTURES_DIR "1024-realistic/terrain/Mapl.dds", data, header)) {
|
|
||||||
FATAL("Cannot read texture");
|
|
||||||
}
|
|
||||||
|
|
||||||
VkImageCreateInfo imageInfo{};
|
|
||||||
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
|
||||||
imageInfo.imageType = VK_IMAGE_TYPE_2D;
|
|
||||||
imageInfo.extent.width = header.width;
|
|
||||||
imageInfo.extent.height = header.height;
|
|
||||||
imageInfo.extent.depth = 1;
|
|
||||||
imageInfo.mipLevels = header.mipMapCount; //TODO:
|
|
||||||
imageInfo.arrayLayers = 1;
|
|
||||||
imageInfo.format = header.format;
|
|
||||||
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
||||||
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
||||||
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
|
||||||
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
||||||
imageInfo.flags = 0;
|
|
||||||
|
|
||||||
sampleImageMemory = alloc.createImage(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, sampleImage, data.data(), data.size());
|
|
||||||
if(!sampleImageMemory) {
|
|
||||||
FATAL("Cannot create texture image");
|
|
||||||
}
|
|
||||||
|
|
||||||
VkImageViewCreateInfo viewInfo{};
|
|
||||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
||||||
viewInfo.image = sampleImage.image;
|
|
||||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
||||||
viewInfo.format = header.format;
|
|
||||||
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
viewInfo.subresourceRange.baseMipLevel = 0;
|
|
||||||
viewInfo.subresourceRange.levelCount = 1;
|
|
||||||
viewInfo.subresourceRange.baseArrayLayer = 0;
|
|
||||||
viewInfo.subresourceRange.layerCount = 1;
|
|
||||||
if (vkCreateImageView(device, &viewInfo, nullptr, &sampleImageView) != VK_SUCCESS) {
|
|
||||||
FATAL("Failed to create texture image view!");
|
|
||||||
}
|
|
||||||
|
|
||||||
VkSamplerCreateInfo samplerInfo{};
|
|
||||||
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
|
||||||
samplerInfo.magFilter = VK_FILTER_LINEAR;
|
|
||||||
samplerInfo.minFilter = VK_FILTER_LINEAR;
|
|
||||||
|
|
||||||
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
||||||
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
||||||
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
||||||
|
|
||||||
if (info.features.samplerAnisotropy && opt.anisotropy > 0) {
|
|
||||||
samplerInfo.anisotropyEnable = VK_TRUE;
|
|
||||||
samplerInfo.maxAnisotropy = 1 << (opt.anisotropy-1);
|
|
||||||
} else {
|
|
||||||
samplerInfo.anisotropyEnable = VK_FALSE;
|
|
||||||
samplerInfo.maxAnisotropy = 1.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
|
|
||||||
samplerInfo.unnormalizedCoordinates = VK_FALSE;
|
|
||||||
|
|
||||||
samplerInfo.compareEnable = VK_FALSE;
|
|
||||||
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
|
|
||||||
|
|
||||||
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
|
||||||
samplerInfo.mipLodBias = 0.0f; //TODO:
|
|
||||||
samplerInfo.minLod = 0.0f;
|
|
||||||
samplerInfo.maxLod = 0.0f;
|
|
||||||
|
|
||||||
if (vkCreateSampler(device, &samplerInfo, nullptr, &sampleSampler) != VK_SUCCESS) {
|
|
||||||
FATAL("Failed to create texture sampler!");
|
FATAL("Failed to create texture sampler!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allocate(alloc, views, pipe, info.swapDetails.capabilities.currentExtent, opt);
|
|
||||||
}
|
}
|
||||||
CommandCenter::~CommandCenter() {
|
CommandCenter::~CommandCenter() {
|
||||||
if(!freed)
|
if(!freed)
|
||||||
free();
|
free();
|
||||||
|
|
||||||
vkDestroyBuffer(device, indexBuffer.buffer, ALLOC);
|
|
||||||
vkDestroyBuffer(device, vertexBuffer.buffer, ALLOC);
|
|
||||||
indexedBufferMemory.reset();
|
|
||||||
|
|
||||||
vkDestroySampler(device, sampleSampler, ALLOC);
|
|
||||||
vkDestroyImageView(device, sampleImageView, ALLOC);
|
|
||||||
vkDestroyImage(device, sampleImage.image, ALLOC);
|
|
||||||
sampleImageMemory.reset();
|
|
||||||
|
|
||||||
vkDestroyCommandPool(device, graphicsPool, ALLOC);
|
vkDestroyCommandPool(device, graphicsPool, ALLOC);
|
||||||
}
|
}
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
void CommandCenter::allocate(Allocator& alloc, const std::vector<VkImageView>& views, const Pipeline& pipe, VkExtent2D extent,
|
void CommandCenter::allocate(const std::vector<VkImageView>& views, const Pipeline& pipe, VkExtent2D extent, const renderOptions& opt) {
|
||||||
const renderOptions& opt)
|
|
||||||
{
|
|
||||||
assert(freed);
|
assert(freed);
|
||||||
|
|
||||||
framebuffers.resize(views.size());
|
framebuffers.resize(views.size());
|
||||||
|
@ -160,10 +67,10 @@ void CommandCenter::allocate(Allocator& alloc, const std::vector<VkImageView>& v
|
||||||
{ // Uniform buffers
|
{ // Uniform buffers
|
||||||
VkDeviceSize bufferSize = sizeof(buffer::vk::UniformBufferObject);
|
VkDeviceSize bufferSize = sizeof(buffer::vk::UniformBufferObject);
|
||||||
|
|
||||||
std::vector<Allocator::buffer_requirement> requirements;
|
std::vector<Buffer::requirement> requirements;
|
||||||
requirements.resize(framebuffers.size(), Allocator::buffer_requirement{bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT});
|
requirements.resize(framebuffers.size(), Buffer::requirement(bufferSize, Buffer::Usage::UNIFORM));
|
||||||
uniformBuffersMemory = alloc.createBuffers(requirements, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers);
|
uniformBuffers.allocate(requirements, true);
|
||||||
if (!uniformBuffersMemory) {
|
if (!uniformBuffers) {
|
||||||
FATAL("Failed to allocate UBO");
|
FATAL("Failed to allocate UBO");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,15 +107,10 @@ void CommandCenter::allocate(Allocator& alloc, const std::vector<VkImageView>& v
|
||||||
|
|
||||||
for (size_t i = 0; i < descriptorSets.size(); i++) {
|
for (size_t i = 0; i < descriptorSets.size(); i++) {
|
||||||
VkDescriptorBufferInfo bufferInfo{};
|
VkDescriptorBufferInfo bufferInfo{};
|
||||||
bufferInfo.buffer = uniformBuffers[i].buffer;
|
bufferInfo.buffer = uniformBuffers.at(i);
|
||||||
bufferInfo.offset = 0;
|
bufferInfo.offset = 0;
|
||||||
bufferInfo.range = sizeof(buffer::vk::UniformBufferObject);
|
bufferInfo.range = sizeof(buffer::vk::UniformBufferObject);
|
||||||
|
|
||||||
VkDescriptorImageInfo imageInfo{};
|
|
||||||
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
|
||||||
imageInfo.imageView = sampleImageView;
|
|
||||||
imageInfo.sampler = sampleSampler;
|
|
||||||
|
|
||||||
std::array<VkWriteDescriptorSet, 2> descriptorWrites{};
|
std::array<VkWriteDescriptorSet, 2> descriptorWrites{};
|
||||||
descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
descriptorWrites[0].dstSet = descriptorSets[i];
|
descriptorWrites[0].dstSet = descriptorSets[i];
|
||||||
|
@ -224,7 +126,7 @@ void CommandCenter::allocate(Allocator& alloc, const std::vector<VkImageView>& v
|
||||||
descriptorWrites[1].dstArrayElement = 0;
|
descriptorWrites[1].dstArrayElement = 0;
|
||||||
descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
descriptorWrites[1].descriptorCount = 1;
|
descriptorWrites[1].descriptorCount = 1;
|
||||||
descriptorWrites[1].pImageInfo = &imageInfo;
|
descriptorWrites[1].pImageInfo = &sampleTexture->getDescriptor();
|
||||||
|
|
||||||
vkUpdateDescriptorSets(device, descriptorWrites.size(), descriptorWrites.data(), 0, nullptr);
|
vkUpdateDescriptorSets(device, descriptorWrites.size(), descriptorWrites.data(), 0, nullptr);
|
||||||
}
|
}
|
||||||
|
@ -266,10 +168,10 @@ void CommandCenter::allocate(Allocator& alloc, const std::vector<VkImageView>& v
|
||||||
|
|
||||||
vkCmdBeginRenderPass(graphicsBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
vkCmdBeginRenderPass(graphicsBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
vkCmdBindPipeline(graphicsBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.getPipeline());
|
vkCmdBindPipeline(graphicsBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.getPipeline());
|
||||||
VkBuffer vertexBuffers[] = {vertexBuffer.buffer};
|
VkBuffer vertexBuffers[] = {modelBuffer->getVertex()};
|
||||||
VkDeviceSize offsets[] = {0};
|
VkDeviceSize offsets[] = {0};
|
||||||
vkCmdBindVertexBuffers(graphicsBuffers[i], 0, 1, vertexBuffers, offsets);
|
vkCmdBindVertexBuffers(graphicsBuffers[i], 0, 1, vertexBuffers, offsets);
|
||||||
vkCmdBindIndexBuffer(graphicsBuffers[i], indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT16);
|
vkCmdBindIndexBuffer(graphicsBuffers[i], modelBuffer->getIndex(), 0, VK_INDEX_TYPE_UINT16);
|
||||||
vkCmdBindDescriptorSets(graphicsBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.getLayout(), 0, 1, &descriptorSets[i], 0, nullptr);
|
vkCmdBindDescriptorSets(graphicsBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.getLayout(), 0, 1, &descriptorSets[i], 0, nullptr);
|
||||||
vkCmdDrawIndexed(graphicsBuffers[i], static_cast<uint32_t>(buffer::vk::indices.size()), 1, 0, 0, 0);
|
vkCmdDrawIndexed(graphicsBuffers[i], static_cast<uint32_t>(buffer::vk::indices.size()), 1, 0, 0, 0);
|
||||||
vkCmdEndRenderPass(graphicsBuffers[i]);
|
vkCmdEndRenderPass(graphicsBuffers[i]);
|
||||||
|
@ -290,12 +192,6 @@ void CommandCenter::free() {
|
||||||
|
|
||||||
vkDestroyDescriptorPool(device, descriptorPool, nullptr);
|
vkDestroyDescriptorPool(device, descriptorPool, nullptr);
|
||||||
|
|
||||||
for (size_t i = 0; i < uniformBuffers.size(); i++) {
|
|
||||||
vkDestroyBuffer(device, uniformBuffers[i].buffer, ALLOC);
|
|
||||||
}
|
|
||||||
uniformBuffersMemory.reset();
|
|
||||||
|
|
||||||
|
|
||||||
for (size_t i = 0; i < framebuffers.size(); i++) {
|
for (size_t i = 0; i < framebuffers.size(); i++) {
|
||||||
vkDestroyFramebuffer(device, framebuffers[i], nullptr);
|
vkDestroyFramebuffer(device, framebuffers[i], nullptr);
|
||||||
}
|
}
|
||||||
|
@ -315,8 +211,7 @@ void CommandCenter::updateUBO(uint32_t idx) {
|
||||||
ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f));
|
ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f));
|
||||||
ubo.view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f));
|
ubo.view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f));
|
||||||
ubo.proj = proj;
|
ubo.proj = proj;
|
||||||
|
uniformBuffers.write(idx, data_view(&ubo, sizeof(ubo)));
|
||||||
memcpy(uniformBuffersMemory->ptr + uniformBuffers[idx].offset, &ubo, sizeof(ubo));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandCenter::submitGraphics(uint32_t idx, VkSemaphore waitSemaphore, VkSemaphore signalSemaphore, VkFence submittedFence) {
|
void CommandCenter::submitGraphics(uint32_t idx, VkSemaphore waitSemaphore, VkSemaphore signalSemaphore, VkFence submittedFence) {
|
||||||
|
|
|
@ -2,22 +2,23 @@
|
||||||
|
|
||||||
#include "forward.hpp"
|
#include "forward.hpp"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "Allocator.hpp"
|
|
||||||
#include <glm/mat4x4.hpp>
|
#include <glm/mat4x4.hpp>
|
||||||
|
#include "api/Buffers.hpp"
|
||||||
|
#include "api/Images.hpp"
|
||||||
|
|
||||||
namespace render::vk {
|
namespace render::vk {
|
||||||
class SwapChain;
|
class SwapChain;
|
||||||
class Pipeline;
|
class Pipeline;
|
||||||
|
|
||||||
class CommandCenter {
|
class CommandCenter final {
|
||||||
public:
|
public:
|
||||||
CommandCenter(VkDevice, Allocator&, const std::vector<VkImageView>&, const Pipeline&, const PhysicalDeviceInfo&, const renderOptions&);
|
CommandCenter(VkDevice, const PhysicalDeviceInfo&, const renderOptions&);
|
||||||
~CommandCenter();
|
~CommandCenter();
|
||||||
|
|
||||||
void updateUBO(uint32_t idx);
|
void updateUBO(uint32_t idx);
|
||||||
void submitGraphics(uint32_t, VkSemaphore, VkSemaphore, VkFence);
|
void submitGraphics(uint32_t, VkSemaphore, VkSemaphore, VkFence);
|
||||||
|
|
||||||
void allocate(Allocator&, const std::vector<VkImageView> &, const Pipeline&, VkExtent2D, const renderOptions&);
|
void allocate(const std::vector<VkImageView>&, const Pipeline&, VkExtent2D, const renderOptions&);
|
||||||
void free();
|
void free();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -32,18 +33,12 @@ private:
|
||||||
VkDescriptorPool descriptorPool;
|
VkDescriptorPool descriptorPool;
|
||||||
std::vector<VkDescriptorSet> descriptorSets;
|
std::vector<VkDescriptorSet> descriptorSets;
|
||||||
|
|
||||||
Allocator::buffer_info vertexBuffer;
|
std::unique_ptr<ShortIndexedVertexBuffer> modelBuffer;
|
||||||
Allocator::buffer_info indexBuffer;
|
|
||||||
Allocator::memory_ptr indexedBufferMemory;
|
|
||||||
|
|
||||||
Allocator::image_info sampleImage;
|
std::unique_ptr<Texture> sampleTexture;
|
||||||
VkImageView sampleImageView;
|
|
||||||
VkSampler sampleSampler;
|
|
||||||
Allocator::memory_ptr sampleImageMemory;
|
|
||||||
|
|
||||||
glm::mat4 proj;
|
glm::mat4 proj;
|
||||||
std::vector<Allocator::buffer_info> uniformBuffers;
|
BufferGroup uniformBuffers;
|
||||||
Allocator::memory_ptr uniformBuffersMemory;
|
|
||||||
|
|
||||||
bool freed = true;
|
bool freed = true;
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
namespace render::vk {
|
namespace render::vk {
|
||||||
|
|
||||||
class Pipeline {
|
class Pipeline final {
|
||||||
public:
|
public:
|
||||||
Pipeline(VkDevice, const PhysicalDeviceInfo&, const renderOptions&);
|
Pipeline(VkDevice, const PhysicalDeviceInfo&, const renderOptions&);
|
||||||
~Pipeline();
|
~Pipeline();
|
||||||
|
|
|
@ -46,10 +46,12 @@ Renderer::Renderer(VkInstance instance, VkDevice device, const PhysicalDeviceInf
|
||||||
|
|
||||||
set_current_extent(physicalInfo->swapDetails.capabilities, physicalInfo->window);
|
set_current_extent(physicalInfo->swapDetails.capabilities, physicalInfo->window);
|
||||||
|
|
||||||
allocator = std::make_unique<Allocator>(device, *physicalInfo.get());
|
allocator = std::make_unique<Allocator>(device, getInfos());
|
||||||
swapChain = std::make_unique<SwapChain>(device, *physicalInfo.get());
|
Allocator::MakeDefault(allocator.get());
|
||||||
pipeline = std::make_unique<Pipeline>(device, *physicalInfo.get(), options);
|
swapChain = std::make_unique<SwapChain>(device, getInfos());
|
||||||
commandCenter = std::make_unique<CommandCenter>(device, *allocator.get(), swapChain->getImageViews(), *pipeline.get(), *physicalInfo.get(), options);
|
pipeline = std::make_unique<Pipeline>(device, getInfos(), options);
|
||||||
|
commandCenter = std::make_unique<CommandCenter>(device, getInfos(), options);
|
||||||
|
commandCenter->allocate(swapChain->getImageViews(), *pipeline.get(), getInfos().swapDetails.capabilities.currentExtent, options);
|
||||||
|
|
||||||
{
|
{
|
||||||
imageAvailableSemaphores.resize(opt.inFlightFrames);
|
imageAvailableSemaphores.resize(opt.inFlightFrames);
|
||||||
|
@ -101,9 +103,9 @@ void Renderer::recreateSwapChain() {
|
||||||
|
|
||||||
physicalInfo->swapDetails = SwapChainSupportDetails::Query(physicalInfo->device, physicalInfo->surface);
|
physicalInfo->swapDetails = SwapChainSupportDetails::Query(physicalInfo->device, physicalInfo->surface);
|
||||||
set_current_extent(physicalInfo->swapDetails.capabilities, physicalInfo->window);
|
set_current_extent(physicalInfo->swapDetails.capabilities, physicalInfo->window);
|
||||||
swapChain = std::make_unique<SwapChain>(device, *physicalInfo.get());
|
swapChain = std::make_unique<SwapChain>(device, getInfos());
|
||||||
pipeline = std::make_unique<Pipeline>(device, *physicalInfo.get(), options);
|
pipeline = std::make_unique<Pipeline>(device, getInfos(), options);
|
||||||
commandCenter->allocate(*allocator.get(), swapChain->getImageViews(), *pipeline.get(), physicalInfo->swapDetails.capabilities.currentExtent, options);
|
commandCenter->allocate(swapChain->getImageViews(), *pipeline.get(), getInfos().swapDetails.capabilities.currentExtent, options);
|
||||||
}
|
}
|
||||||
void Renderer::destroySwapChain() {
|
void Renderer::destroySwapChain() {
|
||||||
commandCenter->free();
|
commandCenter->free();
|
||||||
|
@ -124,11 +126,8 @@ void set_current_extent(VkSurfaceCapabilitiesKHR &capabilities, GLFWwindow* ptr)
|
||||||
std::max(capabilities.minImageExtent.width, std::min<uint32_t>(capabilities.maxImageExtent.width, windowSize.first)),
|
std::max(capabilities.minImageExtent.width, std::min<uint32_t>(capabilities.maxImageExtent.width, windowSize.first)),
|
||||||
std::max(capabilities.minImageExtent.height, std::min<uint32_t>(capabilities.maxImageExtent.height, windowSize.second))};
|
std::max(capabilities.minImageExtent.height, std::min<uint32_t>(capabilities.maxImageExtent.height, windowSize.second))};
|
||||||
};
|
};
|
||||||
VKAPI_ATTR VkBool32 VKAPI_CALL debugValidationCallback(
|
VKAPI_ATTR VkBool32 VKAPI_CALL debugValidationCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT,
|
||||||
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void*)
|
||||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
|
||||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
|
||||||
void* pUserData)
|
|
||||||
{
|
{
|
||||||
switch (messageSeverity) {
|
switch (messageSeverity) {
|
||||||
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
|
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
|
||||||
|
@ -414,7 +413,7 @@ void Renderer::beginFrame() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::function<buffer::params(glm::mat4)> Renderer::beginWorldPass() {
|
std::function<size_t(render::LodModel *const, glm::mat4)> Renderer::beginWorldPass() {
|
||||||
assert(currentImage < swapChain->getImageViews().size());
|
assert(currentImage < swapChain->getImageViews().size());
|
||||||
|
|
||||||
commandCenter->updateUBO(currentImage);
|
commandCenter->updateUBO(currentImage);
|
||||||
|
@ -422,16 +421,16 @@ std::function<buffer::params(glm::mat4)> Renderer::beginWorldPass() {
|
||||||
renderFinishedSemaphores[currentFrame], inFlightFences[currentFrame]);
|
renderFinishedSemaphores[currentFrame], inFlightFences[currentFrame]);
|
||||||
/*WorldPass->useIt();
|
/*WorldPass->useIt();
|
||||||
WorldPass->start(this);*/
|
WorldPass->start(this);*/
|
||||||
return [&](glm::mat4) {
|
return [&](render::LodModel *const, glm::mat4) {
|
||||||
return buffer::params{}; //WorldPass->setup(this, model);
|
return 0; //WorldPass->setup(this, model);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::function<buffer::params(const std::vector<glm::mat4> &)> Renderer::beginEntityPass() {
|
std::function<size_t(render::Model *const, const std::vector<glm::mat4> &)> Renderer::beginEntityPass() {
|
||||||
/*EntityPass->useIt();
|
/*EntityPass->useIt();
|
||||||
EntityPass->start(this);*/
|
EntityPass->start(this);*/
|
||||||
return [&](const std::vector<glm::mat4>&) {
|
return [&](render::Model *const, const std::vector<glm::mat4>&) {
|
||||||
return buffer::params{}; //EntityPass->setup(this, models);
|
return 0; //EntityPass->setup(this, models);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,8 @@ public:
|
||||||
static _FORCE_INLINE_ Renderer *Get() { return static_cast<Renderer*>(render::Renderer::Get()); }
|
static _FORCE_INLINE_ Renderer *Get() { return static_cast<Renderer*>(render::Renderer::Get()); }
|
||||||
|
|
||||||
void beginFrame() override;
|
void beginFrame() override;
|
||||||
std::function<buffer::params(glm::mat4)> beginWorldPass() override;
|
std::function<size_t(render::LodModel *const, glm::mat4)> beginWorldPass() override;
|
||||||
std::function<buffer::params(const std::vector<glm::mat4> &)> beginEntityPass() override;
|
std::function<size_t(render::Model *const, const std::vector<glm::mat4> &)> beginEntityPass() override;
|
||||||
size_t drawIndicatorCube(glm::mat4 model) override;
|
size_t drawIndicatorCube(glm::mat4 model) override;
|
||||||
void endPass() override;
|
void endPass() override;
|
||||||
void swapBuffer(Window&) override;
|
void swapBuffer(Window&) override;
|
||||||
|
@ -34,11 +34,15 @@ public:
|
||||||
void reloadShaders(const passOptions &) override;
|
void reloadShaders(const passOptions &) override;
|
||||||
void reloadTextures(const std::string &, float mipMapLOD, float anisotropy) override;
|
void reloadTextures(const std::string &, float mipMapLOD, float anisotropy) override;
|
||||||
|
|
||||||
|
Allocator* getAllocator() const { return allocator.get(); }
|
||||||
|
|
||||||
void setResized() { framebufferResized = true; }
|
void setResized() { framebufferResized = true; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Renderer(VkInstance, VkDevice, const PhysicalDeviceInfo &, const renderOptions &);
|
Renderer(VkInstance, VkDevice, const PhysicalDeviceInfo &, const renderOptions &);
|
||||||
|
|
||||||
|
const PhysicalDeviceInfo &getInfos() const { return *physicalInfo.get(); }
|
||||||
|
|
||||||
renderOptions options;
|
renderOptions options;
|
||||||
|
|
||||||
VkInstance instance;
|
VkInstance instance;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
namespace render::vk {
|
namespace render::vk {
|
||||||
|
|
||||||
class SwapChain {
|
class SwapChain final {
|
||||||
public:
|
public:
|
||||||
SwapChain(VkDevice, const PhysicalDeviceInfo &);
|
SwapChain(VkDevice, const PhysicalDeviceInfo &);
|
||||||
~SwapChain();
|
~SwapChain();
|
||||||
|
|
|
@ -0,0 +1,184 @@
|
||||||
|
#include "Buffers.hpp"
|
||||||
|
#include "../Allocator.hpp"
|
||||||
|
#include "../../../../core/utils/logger.hpp"
|
||||||
|
|
||||||
|
using namespace render::vk;
|
||||||
|
|
||||||
|
Buffer::~Buffer() {
|
||||||
|
vkDestroyBuffer(Allocator::GetDefault()->getDevice(), ref, ALLOC);
|
||||||
|
//NOTE: memory_ptr self destroy
|
||||||
|
}
|
||||||
|
|
||||||
|
memory::ptr createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, const render::data_view view, Buffer::info &out) {
|
||||||
|
auto alloc = Allocator::GetDefault();
|
||||||
|
auto device = alloc->getDevice();
|
||||||
|
|
||||||
|
VkBufferCreateInfo bufferInfo{};
|
||||||
|
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||||
|
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
bufferInfo.size = size;
|
||||||
|
bufferInfo.usage = usage;
|
||||||
|
if (view)
|
||||||
|
bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||||
|
|
||||||
|
if (vkCreateBuffer(device, &bufferInfo, ALLOC, &out.ref) != VK_SUCCESS) {
|
||||||
|
LOG_E("Failed to create buffer");
|
||||||
|
return memory::GetNull();
|
||||||
|
}
|
||||||
|
out.offset = 0;
|
||||||
|
|
||||||
|
VkMemoryRequirements memRequirements;
|
||||||
|
vkGetBufferMemoryRequirements(device, out.ref, &memRequirements);
|
||||||
|
|
||||||
|
auto memory = alloc->allocate(memRequirements, properties);
|
||||||
|
if (!memory || vkBindBufferMemory(device, out.ref, memory->ref, memory->offset) != VK_SUCCESS) {
|
||||||
|
LOG_E("Failed to allocate buffer memory");
|
||||||
|
return memory::GetNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (view) {
|
||||||
|
if (memory->ptr != nullptr) {
|
||||||
|
memory->write(view.ptr, view.size);
|
||||||
|
} else if(auto staging = WritableBuffer::Create(size)) {
|
||||||
|
staging->write(view, 0);
|
||||||
|
alloc->copyBuffer(staging->getRef(), out.ref, size);
|
||||||
|
} else {
|
||||||
|
FATAL("Cannot allocate staging memory");
|
||||||
|
return memory::GetNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
memory::ptr createBuffers(const std::vector<Buffer::requirement>& requirements, VkMemoryPropertyFlags properties, std::vector<Buffer::info>& out) {
|
||||||
|
assert(!requirements.empty());
|
||||||
|
out.resize(requirements.size()+1);
|
||||||
|
|
||||||
|
auto alloc = Allocator::GetDefault();
|
||||||
|
auto device = alloc->getDevice();
|
||||||
|
|
||||||
|
// Create buffers
|
||||||
|
VkMemoryRequirements memRequirements = {0, 0, UINT32_MAX};
|
||||||
|
std::vector<VkDeviceSize> sizes;
|
||||||
|
sizes.resize(requirements.size());
|
||||||
|
for (size_t i = 0; i < requirements.size(); i++) {
|
||||||
|
VkBufferCreateInfo bufferInfo{};
|
||||||
|
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||||
|
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
bufferInfo.size = requirements[i].size;
|
||||||
|
bufferInfo.usage = static_cast<VkBufferUsageFlags>(requirements[i].usage);
|
||||||
|
if (requirements[i].view)
|
||||||
|
bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||||
|
|
||||||
|
if (vkCreateBuffer(device, &bufferInfo, ALLOC, &out[i].ref) != VK_SUCCESS) {
|
||||||
|
LOG_E("Failed to create buffer");
|
||||||
|
return memory::GetNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
VkMemoryRequirements individualMemRequirements;
|
||||||
|
vkGetBufferMemoryRequirements(device, out[i].ref, &individualMemRequirements);
|
||||||
|
memRequirements.alignment = std::max(memRequirements.alignment, individualMemRequirements.alignment);
|
||||||
|
memRequirements.memoryTypeBits &= individualMemRequirements.memoryTypeBits;
|
||||||
|
sizes[i] = individualMemRequirements.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Align blocks
|
||||||
|
auto aligned = [&](VkDeviceSize offset) {
|
||||||
|
if (offset % memRequirements.alignment == 0)
|
||||||
|
return offset;
|
||||||
|
return offset + memRequirements.alignment - (offset % memRequirements.alignment);
|
||||||
|
};
|
||||||
|
out[0].offset = 0;
|
||||||
|
for (size_t i = 1; i < out.size(); i++) {
|
||||||
|
out[i].offset = aligned(out[i-1].offset + sizes[i-1]);
|
||||||
|
}
|
||||||
|
memRequirements.size = out.back().offset;
|
||||||
|
out.pop_back();
|
||||||
|
|
||||||
|
// Bind memory
|
||||||
|
auto memory = alloc->allocate(memRequirements, properties);
|
||||||
|
if (!memory) {
|
||||||
|
LOG_E("Failed to allocate buffers");
|
||||||
|
return memory::GetNull();
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < requirements.size(); i++) {
|
||||||
|
if (vkBindBufferMemory(device, out[i].ref, memory->ref, memory->offset + out[i].offset) != VK_SUCCESS) {
|
||||||
|
LOG_E("Failed to bind buffer");
|
||||||
|
return memory::GetNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDeviceSize stagingSize = 0;
|
||||||
|
for (auto& requirement: requirements)
|
||||||
|
if (requirement.view)
|
||||||
|
stagingSize = std::max(stagingSize, requirement.size);
|
||||||
|
|
||||||
|
// Copy views
|
||||||
|
// MAYBE: allow single copy
|
||||||
|
if (stagingSize != 0) {
|
||||||
|
if (memory->ptr != nullptr) {
|
||||||
|
for (size_t i = 0; i < requirements.size(); i++) {
|
||||||
|
if (requirements[i].view) {
|
||||||
|
assert(requirements[i].view.size <= requirements[i].size);
|
||||||
|
memory->write(requirements[i].view.ptr, requirements[i].view.size, out[i].offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(auto staging = WritableBuffer::Create(stagingSize)) {
|
||||||
|
for (size_t i = 0; i < requirements.size(); i++) {
|
||||||
|
if (requirements[i].view) {
|
||||||
|
assert(requirements[i].view.size <= requirements[i].size);
|
||||||
|
staging->write(requirements[i].view, 0);
|
||||||
|
alloc->copyBuffer(staging->getRef(), out[i].ref, requirements[i].size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
FATAL("Cannot allocate staging memory");
|
||||||
|
return memory::GetNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Buffer::MakeDefault() { }
|
||||||
|
|
||||||
|
std::unique_ptr<WritableBuffer> WritableBuffer::Create(size_t size, Usage usage, const data_view write) {
|
||||||
|
vk::Buffer::info tmp;
|
||||||
|
auto mem = createBuffer(size, static_cast<int>(usage), memory::HOST_EASILY_WRITABLE, write, tmp);
|
||||||
|
return std::unique_ptr<WritableBuffer>(new WritableBuffer(tmp.ref, std::move(mem), tmp.offset));
|
||||||
|
}
|
||||||
|
void WritableBuffer::write(const data_view view, size_t offset) {
|
||||||
|
memory->write(view.ptr, view.size, memOffset + offset);
|
||||||
|
}
|
||||||
|
void WritableBuffer::read(data_ref ref, size_t offset) {
|
||||||
|
memory->read(ref.ptr, ref.size, memOffset + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
ShortIndexedVertexBuffer::~ShortIndexedVertexBuffer() {
|
||||||
|
vkDestroyBuffer(Allocator::GetDefault()->getDevice(), vertex, ALLOC);
|
||||||
|
vkDestroyBuffer(Allocator::GetDefault()->getDevice(), index, ALLOC);
|
||||||
|
//NOTE: memory_ptr self destroy
|
||||||
|
}
|
||||||
|
std::unique_ptr<ShortIndexedVertexBuffer> ShortIndexedVertexBuffer::Create(const data_view vertices, const data_view indices) {
|
||||||
|
std::vector<vk::Buffer::info> tmp;
|
||||||
|
auto mem = createBuffers({{vertices.size, Usage::VERTEX, vertices}, {indices.size, Usage::INDEX, indices}}, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, tmp);
|
||||||
|
return std::unique_ptr<ShortIndexedVertexBuffer>(new ShortIndexedVertexBuffer(tmp.at(0).ref, tmp.at(1).ref, std::move(mem)));
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferGroup::~BufferGroup() {
|
||||||
|
free();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BufferGroup::allocate(const std::vector<Buffer::requirement> & reqs, bool writable) {
|
||||||
|
free();
|
||||||
|
memory = createBuffers(reqs, writable ? memory::HOST_EASILY_WRITABLE : (VkMemoryPropertyFlags)VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, refs);
|
||||||
|
}
|
||||||
|
void BufferGroup::free() {
|
||||||
|
for (const auto& buffer: refs) {
|
||||||
|
vkDestroyBuffer(Allocator::GetDefault()->getDevice(), buffer.ref, ALLOC);
|
||||||
|
}
|
||||||
|
refs.clear();
|
||||||
|
memory = memory::GetNull();
|
||||||
|
}
|
||||||
|
void BufferGroup::write(size_t i, const data_view view) {
|
||||||
|
memory->write(view.ptr, view.size, refs.at(i).offset);
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../../api/Buffers.hpp"
|
||||||
|
#include "Memory.hpp"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace render::vk {
|
||||||
|
|
||||||
|
/// Self-container Vulkan buffer
|
||||||
|
class Buffer: public render::Buffer {
|
||||||
|
public:
|
||||||
|
~Buffer();
|
||||||
|
|
||||||
|
VkBuffer getRef() const { return ref; }
|
||||||
|
|
||||||
|
static void MakeDefault();
|
||||||
|
|
||||||
|
struct info {
|
||||||
|
VkBuffer ref = nullptr;
|
||||||
|
VkDeviceSize offset = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Buffer(VkBuffer ref, memory::ptr mem):
|
||||||
|
ref(ref), memory(std::move(mem)) { }
|
||||||
|
VkBuffer ref;
|
||||||
|
memory::ptr memory;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Writable (aka Host visible) vulkan buffer
|
||||||
|
class WritableBuffer: public render::WritableBuffer, public Buffer {
|
||||||
|
public:
|
||||||
|
static std::unique_ptr<WritableBuffer> Create(size_t size, Usage usage = Usage::TRANSFER_SRC, const data_view write = data_view());
|
||||||
|
|
||||||
|
void write(const data_view, size_t offset) override;
|
||||||
|
void read(data_ref, size_t offset) override;
|
||||||
|
|
||||||
|
explicit operator bool() const { return ref && memory->ptr; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
WritableBuffer(VkBuffer ref, memory::ptr mem, VkDeviceSize memOffset = 0):
|
||||||
|
vk::Buffer(ref, std::move(mem)), memOffset(memOffset) { }
|
||||||
|
const VkDeviceSize memOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Fast (aka Device local local) vulkan buffer
|
||||||
|
class FastBuffer: public render::FastBuffer, public Buffer {
|
||||||
|
public:
|
||||||
|
|
||||||
|
protected:
|
||||||
|
FastBuffer(VkBuffer ref, memory::ptr mem):
|
||||||
|
vk::Buffer(ref, std::move(mem)) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
class ShortIndexedVertexBuffer: public render::ShortIndexedVertexBuffer {
|
||||||
|
public:
|
||||||
|
static std::unique_ptr<ShortIndexedVertexBuffer> Create(const data_view vertices, const data_view indices);
|
||||||
|
~ShortIndexedVertexBuffer();
|
||||||
|
|
||||||
|
VkBuffer getVertex() const { return vertex; }
|
||||||
|
VkBuffer getIndex() const { return index; }
|
||||||
|
|
||||||
|
explicit operator bool() const { return vertex && index; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ShortIndexedVertexBuffer(VkBuffer vertex, VkBuffer index, memory::ptr mem):
|
||||||
|
vertex(vertex), index(index), memory(std::move(mem)) { }
|
||||||
|
VkBuffer vertex;
|
||||||
|
VkBuffer index;
|
||||||
|
memory::ptr memory;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BufferGroup {
|
||||||
|
public:
|
||||||
|
BufferGroup(): memory(memory::GetNull()) { }
|
||||||
|
~BufferGroup();
|
||||||
|
|
||||||
|
void allocate(const std::vector<Buffer::requirement> &, bool writable);
|
||||||
|
VkBuffer at(size_t i) const { return refs.at(i).ref; }
|
||||||
|
/// Requires last allocate to be writable
|
||||||
|
void write(size_t, const data_view);
|
||||||
|
|
||||||
|
explicit operator bool() const { return memory && !refs.empty(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void free();
|
||||||
|
std::vector<Buffer::info> refs;
|
||||||
|
memory::ptr memory;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,139 @@
|
||||||
|
#include "Images.hpp"
|
||||||
|
#include "Buffers.hpp"
|
||||||
|
#include "../Allocator.hpp"
|
||||||
|
#include "../../../../core/utils/logger.hpp"
|
||||||
|
|
||||||
|
using namespace render::vk;
|
||||||
|
|
||||||
|
Image::~Image() {
|
||||||
|
vkDestroyImage(Allocator::GetDefault()->getDevice(), ref, ALLOC);
|
||||||
|
}
|
||||||
|
Texture::~Texture() {
|
||||||
|
vkDestroySampler(Allocator::GetDefault()->getDevice(), sampler, ALLOC);
|
||||||
|
vkDestroyImageView(Allocator::GetDefault()->getDevice(), view, ALLOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
memory::ptr createImage(const Image::requirement& req, VkMemoryPropertyFlags properties, const render::data_view view, Image::info& out) {
|
||||||
|
auto alloc = Allocator::GetDefault();
|
||||||
|
auto device = alloc->getDevice();
|
||||||
|
|
||||||
|
VkImageCreateInfo info{};
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||||
|
info.imageType = VK_IMAGE_TYPE_2D;
|
||||||
|
info.extent.width = req.props.size.width;
|
||||||
|
info.extent.height = req.props.size.height;
|
||||||
|
info.extent.depth = 1;
|
||||||
|
info.mipLevels = req.props.mipMap; //TODO:
|
||||||
|
info.arrayLayers = 1;
|
||||||
|
info.format = static_cast<VkFormat>(req.props.format);
|
||||||
|
info.tiling = req.linear ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
|
||||||
|
info.initialLayout = static_cast<VkImageLayout>(req.layout);
|
||||||
|
info.usage = static_cast<VkImageUsageFlags>(req.usage);
|
||||||
|
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
info.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
info.flags = 0;
|
||||||
|
if (view) {
|
||||||
|
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vkCreateImage(device, &info, ALLOC, &out.ref) != VK_SUCCESS) {
|
||||||
|
LOG_E("Failed to create image");
|
||||||
|
return memory::GetNull();
|
||||||
|
}
|
||||||
|
out.offset = 0;
|
||||||
|
|
||||||
|
VkMemoryRequirements memRequirements;
|
||||||
|
vkGetImageMemoryRequirements(device, out.ref, &memRequirements);
|
||||||
|
|
||||||
|
auto memory = alloc->allocate(memRequirements, properties, true);
|
||||||
|
if (!memory || vkBindImageMemory(device, out.ref, memory->ref, memory->offset) != VK_SUCCESS) {
|
||||||
|
LOG_E("Failed to allocate image memory");
|
||||||
|
return memory::GetNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (view) {
|
||||||
|
if(auto staging = WritableBuffer::Create(view.size)) {
|
||||||
|
staging->write(view, 0);
|
||||||
|
alloc->transitionImageLayout(out.ref, info.format, info.initialLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||||
|
alloc->copyBufferToImage(staging->getRef(), out.ref, info.extent.width, info.extent.height);
|
||||||
|
alloc->transitionImageLayout(out.ref, info.format, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, static_cast<VkImageLayout>(req.layout));
|
||||||
|
} else {
|
||||||
|
FATAL("Cannot allocate staging memory");
|
||||||
|
return memory::GetNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
//TODO: createImages
|
||||||
|
|
||||||
|
std::unique_ptr<Texture> Texture::LoadFromFile(const std::string& path, const sampling& props) {
|
||||||
|
auto device = Allocator::GetDefault()->getDevice();
|
||||||
|
|
||||||
|
std::vector<unsigned char> data;
|
||||||
|
auto header = [&] {
|
||||||
|
if (auto header = render::Image::Read(path, data)) {
|
||||||
|
return header.value();
|
||||||
|
}
|
||||||
|
FATAL("Cannot read texture");
|
||||||
|
}();
|
||||||
|
|
||||||
|
vk::Image::info img;
|
||||||
|
auto mem = createImage({header.size, header.mipMap, header.format, Layout::SHADER_READ_ONLY, Usage::SAMPLED, false},
|
||||||
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, data, img);
|
||||||
|
if(!mem) {
|
||||||
|
FATAL("Cannot create texture image");
|
||||||
|
}
|
||||||
|
|
||||||
|
VkImageViewCreateInfo viewInfo{};
|
||||||
|
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
|
viewInfo.image = img.ref;
|
||||||
|
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
|
viewInfo.format = static_cast<VkFormat>(header.format);
|
||||||
|
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
viewInfo.subresourceRange.baseMipLevel = 0;
|
||||||
|
viewInfo.subresourceRange.levelCount = 1;
|
||||||
|
viewInfo.subresourceRange.baseArrayLayer = 0;
|
||||||
|
viewInfo.subresourceRange.layerCount = 1;
|
||||||
|
|
||||||
|
VkImageView view;
|
||||||
|
if (vkCreateImageView(device, &viewInfo, ALLOC, &view) != VK_SUCCESS) {
|
||||||
|
FATAL("Failed to create texture image view!");
|
||||||
|
}
|
||||||
|
|
||||||
|
VkSamplerCreateInfo samplerInfo{};
|
||||||
|
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||||
|
samplerInfo.magFilter = props.magLinear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
|
||||||
|
samplerInfo.minFilter = props.minLinear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
|
||||||
|
|
||||||
|
const auto wrap = static_cast<VkSamplerAddressMode>(props.wrap);
|
||||||
|
samplerInfo.addressModeU = wrap;
|
||||||
|
samplerInfo.addressModeV = wrap;
|
||||||
|
samplerInfo.addressModeW = wrap;
|
||||||
|
|
||||||
|
if (Allocator::GetDefault()->getCapabilities().anisotropy && props.anisotropy > 0) {
|
||||||
|
samplerInfo.anisotropyEnable = VK_TRUE;
|
||||||
|
samplerInfo.maxAnisotropy = 1 << (props.anisotropy-1);
|
||||||
|
} else {
|
||||||
|
samplerInfo.anisotropyEnable = VK_FALSE;
|
||||||
|
samplerInfo.maxAnisotropy = 1.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
|
||||||
|
samplerInfo.unnormalizedCoordinates = VK_FALSE;
|
||||||
|
|
||||||
|
samplerInfo.compareEnable = VK_FALSE;
|
||||||
|
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||||
|
|
||||||
|
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||||
|
samplerInfo.mipLodBias = 0.0f; //TODO:
|
||||||
|
samplerInfo.minLod = 0.0f;
|
||||||
|
samplerInfo.maxLod = 0.0f;
|
||||||
|
|
||||||
|
VkSampler sampler;
|
||||||
|
if (vkCreateSampler(device, &samplerInfo, ALLOC, &sampler) != VK_SUCCESS) {
|
||||||
|
FATAL("Failed to create texture sampler!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::unique_ptr<Texture>(new Texture(sampler, view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, img.ref, std::move(mem)));
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../../api/Images.hpp"
|
||||||
|
#include "Memory.hpp"
|
||||||
|
|
||||||
|
namespace render::vk {
|
||||||
|
|
||||||
|
class Image: public render::Image {
|
||||||
|
public:
|
||||||
|
virtual ~Image();
|
||||||
|
|
||||||
|
static void MakeDefault();
|
||||||
|
|
||||||
|
struct info {
|
||||||
|
VkImage ref = nullptr;
|
||||||
|
VkDeviceSize offset = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Image(VkImage ref, memory::ptr mem):
|
||||||
|
ref(ref), memory(std::move(mem)) { }
|
||||||
|
VkImage ref;
|
||||||
|
memory::ptr memory;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Texture: public render::Texture, Image {
|
||||||
|
public:
|
||||||
|
~Texture();
|
||||||
|
|
||||||
|
const VkDescriptorImageInfo &getDescriptor() const { return descriptor; }
|
||||||
|
|
||||||
|
static std::unique_ptr<Texture> LoadFromFile(const std::string&, const sampling&);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Texture(VkSampler sampler, VkImageView view, VkImageLayout layout, VkImage ref, memory::ptr memory):
|
||||||
|
vk::Image(ref, std::move(memory)), sampler(sampler), view(view), descriptor({sampler, view, layout}) { }
|
||||||
|
VkSampler sampler;
|
||||||
|
VkImageView view;
|
||||||
|
const VkDescriptorImageInfo descriptor;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../forward.hpp"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace render::vk { struct Allocation; }
|
||||||
|
namespace render::vk::memory {
|
||||||
|
|
||||||
|
constexpr VkMemoryPropertyFlags HOST_EASILY_WRITABLE = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||||
|
struct area {
|
||||||
|
VkDeviceMemory ref;
|
||||||
|
VkDeviceSize size;
|
||||||
|
VkDeviceSize offset;
|
||||||
|
void *ptr = nullptr;
|
||||||
|
|
||||||
|
void write(const void*, VkDeviceSize size, VkDeviceSize offset = 0);
|
||||||
|
void read(void*, VkDeviceSize size, VkDeviceSize offset = 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Deleter {
|
||||||
|
public:
|
||||||
|
Deleter(Allocation *owner): owner(owner) { }
|
||||||
|
void operator()(area *);
|
||||||
|
private:
|
||||||
|
Allocation *owner;
|
||||||
|
};
|
||||||
|
|
||||||
|
using ptr = std::unique_ptr<area, Deleter>;
|
||||||
|
|
||||||
|
ptr GetNull();
|
||||||
|
|
||||||
|
}
|
|
@ -1,27 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <volk.h>
|
|
||||||
|
|
||||||
namespace buffer::vk {
|
|
||||||
|
|
||||||
class MemoryArea {
|
|
||||||
|
|
||||||
private:
|
|
||||||
VkDeviceMemory ref;
|
|
||||||
size_t size;
|
|
||||||
std::vector<>
|
|
||||||
};
|
|
||||||
class Buffer {
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::weak_ptr<>
|
|
||||||
VkBuffer ref;
|
|
||||||
|
|
||||||
size_t offset;
|
|
||||||
size_t size;
|
|
||||||
|
|
||||||
// Only is mappable
|
|
||||||
void* data = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
#include "texture.hpp"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <cassert>
|
|
||||||
#include <cmath>
|
|
||||||
#include <iostream>
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
#define FOURCC_DXT1 0x31545844 // Equivalent to "DXT1" in ASCII
|
|
||||||
#define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII
|
|
||||||
#define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII
|
|
||||||
|
|
||||||
VkResult render::vk::dds::readDDS(const std::string& imagepath, std::vector<unsigned char>& data, header_info& info) {
|
|
||||||
|
|
||||||
unsigned char header[124];
|
|
||||||
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
/* try to open the file */
|
|
||||||
fp = fopen(imagepath.c_str(), "rb");
|
|
||||||
if (fp == NULL){
|
|
||||||
printf("%s could not be opened.\n", imagepath.c_str()); getchar();
|
|
||||||
return VK_ERROR_INVALID_DEVICE_ADDRESS_EXT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* verify the type of file */
|
|
||||||
char filecode[4];
|
|
||||||
fread(filecode, 1, 4, fp);
|
|
||||||
if (strncmp(filecode, "DDS ", 4) != 0) {
|
|
||||||
fclose(fp);
|
|
||||||
return VK_ERROR_INVALID_DEVICE_ADDRESS_EXT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get the surface desc */
|
|
||||||
fread(&header, 124, 1, fp);
|
|
||||||
|
|
||||||
info.height = *(unsigned int*)&(header[8 ]);
|
|
||||||
info.width = *(unsigned int*)&(header[12]);
|
|
||||||
unsigned int linearSize = *(unsigned int*)&(header[16]);
|
|
||||||
info.mipMapCount = *(unsigned int*)&(header[24]);
|
|
||||||
unsigned int fourCC = *(unsigned int*)&(header[80]);
|
|
||||||
|
|
||||||
|
|
||||||
/* how big is it going to be including all mipmaps? */
|
|
||||||
unsigned int bufsize = info.mipMapCount > 1 ? linearSize * 2 : linearSize;
|
|
||||||
data.resize(bufsize);
|
|
||||||
fread(data.data(), 1, bufsize, fp);
|
|
||||||
/* close the file pointer */
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
switch(fourCC)
|
|
||||||
{
|
|
||||||
case FOURCC_DXT1:
|
|
||||||
info.format = VK_FORMAT_BC1_RGBA_SRGB_BLOCK;
|
|
||||||
break;
|
|
||||||
case FOURCC_DXT3:
|
|
||||||
info.format = VK_FORMAT_BC2_SRGB_BLOCK;
|
|
||||||
break;
|
|
||||||
case FOURCC_DXT5:
|
|
||||||
info.format = VK_FORMAT_BC3_SRGB_BLOCK;
|
|
||||||
break;
|
|
||||||
//MAYBE: VK_FORMAT_BC6H_SFLOAT_BLOCK
|
|
||||||
default:
|
|
||||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if FALSE
|
|
||||||
glTextureParameteri(textureID, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST);
|
|
||||||
glTextureParameteri(textureID, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST);
|
|
||||||
|
|
||||||
TODO: glGenerateTextureMipmap(textureID);
|
|
||||||
#endif
|
|
||||||
return VK_SUCCESS;
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <array>
|
|
||||||
#include <volk.h>
|
|
||||||
|
|
||||||
namespace render::vk::dds {
|
|
||||||
struct header_info {
|
|
||||||
unsigned int height;
|
|
||||||
unsigned int width;
|
|
||||||
unsigned int mipMapCount;
|
|
||||||
VkFormat format;
|
|
||||||
};
|
|
||||||
VkResult readDDS(const std::string& imagepath, std::vector<unsigned char>& data, header_info& info);
|
|
||||||
}
|
|
|
@ -10,7 +10,7 @@ struct state {
|
||||||
camera_pos position = camera_pos(voxel_pos(0), 1);
|
camera_pos position = camera_pos(voxel_pos(0), 1);
|
||||||
std::optional<world::Universe::ray_target> look_at = {};
|
std::optional<world::Universe::ray_target> look_at = {};
|
||||||
|
|
||||||
std::shared_ptr<contouring::Abstract> contouring;
|
contouring::Abstract* contouring;
|
||||||
|
|
||||||
std::array<char, 256> console_buffer;
|
std::array<char, 256> console_buffer;
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
using namespace world::client;
|
using namespace world::client;
|
||||||
|
|
||||||
DistantUniverse::DistantUniverse(const connection& ct, const options& opt): Universe(), peer(ct),
|
DistantUniverse::DistantUniverse(const connection& ct, const options& opt, const std::string& contouring): Universe(contouring), peer(ct),
|
||||||
loadDistance(opt.loadDistance), keepDistance(opt.keepDistance), serverDistance(0) { }
|
loadDistance(opt.loadDistance), keepDistance(opt.keepDistance), serverDistance(0) { }
|
||||||
DistantUniverse::~DistantUniverse() { }
|
DistantUniverse::~DistantUniverse() { }
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace world::client {
|
||||||
/// Whole universe container in network client
|
/// Whole universe container in network client
|
||||||
class DistantUniverse final: public Universe {
|
class DistantUniverse final: public Universe {
|
||||||
public:
|
public:
|
||||||
DistantUniverse(const connection&, const options &);
|
DistantUniverse(const connection&, const options &, const std::string&);
|
||||||
~DistantUniverse();
|
~DistantUniverse();
|
||||||
|
|
||||||
void update(voxel_pos, float) override;
|
void update(voxel_pos, float) override;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
using namespace world::client;
|
using namespace world::client;
|
||||||
|
|
||||||
LocalUniverse::LocalUniverse(server_handle *const handle): Universe(), handle(handle) {
|
LocalUniverse::LocalUniverse(server_handle *const handle, const std::string& contour): Universe(contour), handle(handle) {
|
||||||
assert(handle != nullptr);
|
assert(handle != nullptr);
|
||||||
for (auto i = 0; i < 500 && !handle->running; i++) {
|
for (auto i = 0; i < 500 && !handle->running; i++) {
|
||||||
LOG_D("Waiting local server startup");
|
LOG_D("Waiting local server startup");
|
||||||
|
@ -22,11 +22,6 @@ LocalUniverse::~LocalUniverse() {
|
||||||
handle->running = false;
|
handle->running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalUniverse::setContouring(const std::shared_ptr<contouring::Abstract>& ct) {
|
|
||||||
Universe::setContouring(ct);
|
|
||||||
last_chunk = chunk_pos(INT_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LocalUniverse::update(voxel_pos pos, float) {
|
void LocalUniverse::update(voxel_pos pos, float) {
|
||||||
const auto cur_chunk = glm::divide(pos);
|
const auto cur_chunk = glm::divide(pos);
|
||||||
const auto chunkChange = cur_chunk != last_chunk;
|
const auto chunkChange = cur_chunk != last_chunk;
|
||||||
|
|
|
@ -7,14 +7,12 @@ namespace world::client {
|
||||||
/// Whole universe container in client with in-memory server
|
/// Whole universe container in client with in-memory server
|
||||||
class LocalUniverse final: public Universe {
|
class LocalUniverse final: public Universe {
|
||||||
public:
|
public:
|
||||||
LocalUniverse(server_handle *const handle);
|
LocalUniverse(server_handle *const handle, const std::string& contouring);
|
||||||
~LocalUniverse();
|
~LocalUniverse();
|
||||||
|
|
||||||
void update(voxel_pos pos, float deltaTime) override;
|
void update(voxel_pos pos, float deltaTime) override;
|
||||||
void emit(const action::packet &) override;
|
void emit(const action::packet &) override;
|
||||||
|
|
||||||
void setContouring(const std::shared_ptr<contouring::Abstract> &ct) override;
|
|
||||||
|
|
||||||
ray_result raycast(const geometry::Ray &ray) const override;
|
ray_result raycast(const geometry::Ray &ray) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -1,16 +1,12 @@
|
||||||
#include "Universe.hpp"
|
#include "Universe.hpp"
|
||||||
|
|
||||||
#include "../contouring/Dummy.hpp"
|
#include "../contouring/FlatDualMC.hpp"
|
||||||
|
|
||||||
using namespace world::client;
|
using namespace world::client;
|
||||||
|
|
||||||
Universe::Universe(): world::Universe(), contouring(std::make_shared<contouring::Dummy>()) { }
|
Universe::Universe(const std::string& ct): world::Universe(), contouring(std::make_unique<contouring::FlatDualMC>(ct)) { }
|
||||||
Universe::~Universe() { }
|
Universe::~Universe() { }
|
||||||
|
|
||||||
void Universe::setContouring(const std::shared_ptr<contouring::Abstract>& ct) {
|
|
||||||
contouring = ct;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
void ServerUniverse::getEntitiesModels(const std::function<void(const std::vector<glm::mat4>&, buffer::Abstract *const)> &draw, const std::optional<geometry::Frustum> &frustum, const glm::llvec3 &offset, int density) {
|
void ServerUniverse::getEntitiesModels(const std::function<void(const std::vector<glm::mat4>&, buffer::Abstract *const)> &draw, const std::optional<geometry::Frustum> &frustum, const glm::llvec3 &offset, int density) {
|
||||||
std::vector<glm::mat4> mats;
|
std::vector<glm::mat4> mats;
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace world::client {
|
||||||
/// Whole universe container in abstract client
|
/// Whole universe container in abstract client
|
||||||
class Universe: public world::Universe {
|
class Universe: public world::Universe {
|
||||||
public:
|
public:
|
||||||
Universe();
|
Universe(const std::string& contouring);
|
||||||
virtual ~Universe();
|
virtual ~Universe();
|
||||||
|
|
||||||
struct connection: net::connection {
|
struct connection: net::connection {
|
||||||
|
@ -25,11 +25,9 @@ namespace world::client {
|
||||||
/// Send action to ServerUniverse
|
/// Send action to ServerUniverse
|
||||||
virtual void emit(const action::packet &) = 0;
|
virtual void emit(const action::packet &) = 0;
|
||||||
|
|
||||||
/// Change contouring worker
|
|
||||||
virtual void setContouring(const std::shared_ptr<contouring::Abstract> &ct);
|
|
||||||
/// Get current contouring worker
|
/// Get current contouring worker
|
||||||
std::shared_ptr<contouring::Abstract> getContouring() const {
|
contouring::Abstract* getContouring() const {
|
||||||
return contouring;
|
return contouring.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: move to ClientUniverse
|
//TODO: move to ClientUniverse
|
||||||
|
@ -37,6 +35,6 @@ namespace world::client {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Contouring worker
|
/// Contouring worker
|
||||||
std::shared_ptr<contouring::Abstract> contouring;
|
std::unique_ptr<contouring::Abstract> contouring;
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -6,13 +6,13 @@
|
||||||
#include "../../core/utils/logger.hpp"
|
#include "../../core/utils/logger.hpp"
|
||||||
|
|
||||||
namespace world::client {
|
namespace world::client {
|
||||||
std::unique_ptr<Universe> Load(const std::optional<Universe::connection>& ct, server_handle *const localHandle, const Universe::options &distOpts) {
|
std::unique_ptr<Universe> Load(const std::optional<Universe::connection>& ct, server_handle *const localHandle, const Universe::options &distOpts, const std::string& contouring) {
|
||||||
if(ct.has_value()) {
|
if(ct.has_value()) {
|
||||||
return std::make_unique<DistantUniverse>(ct.value(), distOpts);
|
return std::make_unique<DistantUniverse>(ct.value(), distOpts, contouring);
|
||||||
#ifndef STANDALONE
|
#ifndef STANDALONE
|
||||||
} else if(localHandle != nullptr) {
|
} else if(localHandle != nullptr) {
|
||||||
LOG_D("Using local universe");
|
LOG_D("Using local universe");
|
||||||
return std::make_unique<LocalUniverse>(localHandle);
|
return std::make_unique<LocalUniverse>(localHandle, contouring);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
FATAL("Must enable server.allow_local or define client.connection");
|
FATAL("Must enable server.allow_local or define client.connection");
|
||||||
|
|
|
@ -4,5 +4,5 @@
|
||||||
#include "../../core/server_handle.hpp"
|
#include "../../core/server_handle.hpp"
|
||||||
|
|
||||||
namespace world::client {
|
namespace world::client {
|
||||||
std::unique_ptr<Universe> Load(const std::optional<Universe::connection>& ct, server_handle *const localHandle, const Universe::options& distOpts);
|
std::unique_ptr<Universe> Load(const std::optional<Universe::connection>& ct, server_handle *const localHandle, const Universe::options& distOpts, const std::string& contouring);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ public:
|
||||||
|
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
server_handle *const getHandle() { return localHandle; }
|
server_handle *getHandle() { return localHandle; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
config::server::options& options;
|
config::server::options& options;
|
||||||
|
|
Loading…
Reference in New Issue