1
0
Fork 0

Compare commits

...

3 Commits

Author SHA1 Message Date
May B. 3666fc2ed8 Edit shape iterators 2020-10-25 13:33:03 +01:00
May B. ec467ca037 Prevent suffocation 2020-10-25 13:32:59 +01:00
May B. 5fdff56f8f Raw sphere tool 2020-10-25 13:32:42 +01:00
45 changed files with 395 additions and 144 deletions

View File

@ -90,6 +90,7 @@ cmake <options> ..
``` ```
CMake options: `-DKEY=VAL` CMake options: `-DKEY=VAL`
Key | Usage | Default Key | Usage | Default
--- | --- | --- --- | --- | ---
SIMD_LEVEL | SIMD processor acceleration (sse2, sse4.1, avx2, avx512f) | `avx2` SIMD_LEVEL | SIMD processor acceleration (sse2, sse4.1, avx2, avx512f) | `avx2`
@ -144,6 +145,7 @@ Distributed under the MIT License. See [LICENSE](LICENSE) for more information.
<!-- CONTACT --> <!-- CONTACT -->
## Contact ## Contact
Maelys Bois - [/me](https://git.wadza.fr/me) - me@wadza.fr Shu - [/me](https://git.wadza.fr/me) - me@wadza.fr
Project Link: [https://git.wadza.fr/me/univerxel](https://git.wadza.fr/me/univerxel) Public releases: [https://framagit.org/univerxel/univerxel](https://framagit.org/univerxel/univerxel)
Working repo: [https://git.wadza.fr/me/univerxel](https://git.wadza.fr/me/univerxel)

19
TODO.md
View File

@ -14,6 +14,7 @@
- [~] Authentication - [~] Authentication
- [x] Compression - [x] Compression
- [ ] Encryption - [ ] Encryption
- DTLS
- [x] Embedded - [x] Embedded
- [x] Standalone - [x] Standalone
@ -24,20 +25,24 @@
- [ ] Local prediction - [ ] Local prediction
- [ ] Contouring service - [ ] Contouring service
- [~] Edit - [~] Edit
- [ ] More types - [x] Shape iterators
- Sphere - [ ] More shapes
- Anchor - [ ] Anchor
- Prevent suffocation - [x] Prevent suffocation
- [ ] Local prediction - [ ] Local prediction
- [~] Occlusion Culling - [~] Occlusion Culling
- [ ] Iterator ray - [ ] Iterator ray
- [ ] Cast from chunk center - [ ] Cast from chunk center
- [x] Transparency - [x] Transparency
- [~] Entities - [~] Entities
- Get models - [ ] Collide
- [ ] Get models
## Hello universe ## Hello universe
- [ ] CI build
- CMake package
- GitLab / Drone pipeline
- [ ] Universe - [ ] Universe
- [ ] Galaxy - [ ] Galaxy
- [ ] Rotation - [ ] Rotation
@ -53,7 +58,8 @@
- https://imgur.com/kM8b5Zq - https://imgur.com/kM8b5Zq
- https://imgur.com/a/bh2iy - https://imgur.com/a/bh2iy
- https://speciesdevblog.files.wordpress.com/2012/11/biomemap.png - https://speciesdevblog.files.wordpress.com/2012/11/biomemap.png
- Curvature - [ ] Planet scale LOD
- [~] Curvature
- [~] CubeSphere - [~] CubeSphere
- [ ] Area corrected CubeSphere - [ ] Area corrected CubeSphere
- [ ] Corrected Normals - [ ] Corrected Normals
@ -64,6 +70,7 @@
## Hello industry ## Hello industry
- [ ] Multiblock - [ ] Multiblock
- [ ] Inventory
## Hello darkness ## Hello darkness

View File

@ -6,5 +6,5 @@ layout(location = 0) out vec4 color;
in vec4 Color; in vec4 Color;
void main(){ void main(){
color = vec4(Color.xyz, .5); color = Color;
} }

BIN
resource/content/shaders/Color.fs.spv (Stored with Git LFS)

Binary file not shown.

View File

@ -2,14 +2,14 @@
layout(location = 0) in vec3 Position_modelspace; layout(location = 0) in vec3 Position_modelspace;
layout(location = 1) in vec4 Color_model;
uniform mat4 MVP; uniform mat4 MVP;
uniform vec4 Col;
out vec4 Color; out vec4 Color;
void main(){ void main(){
gl_Position = MVP * vec4(Position_modelspace, 1); gl_Position = MVP * vec4(Position_modelspace, 1);
Color = Color_model; Color = Col;
} }

BIN
resource/content/shaders/Color.vs.spv (Stored with Git LFS)

Binary file not shown.

View File

@ -6,5 +6,5 @@ layout(location = 0) in vec4 Color;
layout(location = 0) out vec4 color; layout(location = 0) out vec4 color;
void main(){ void main(){
color = vec4(Color.xyz, .5); color = Color;
} }

View File

@ -6,15 +6,15 @@ layout(binding = 0) uniform UniformBufferObject {
} UBO; } UBO;
layout(push_constant) uniform PushConst { layout(push_constant) uniform PushConst {
mat4 model; mat4 model;
vec4 color;
} Push; } Push;
layout(location = 0) in vec3 Position_modelspace; layout(location = 0) in vec3 Position_modelspace;
layout(location = 1) in vec4 Color_model;
layout(location = 0) out vec4 Color; layout(location = 0) out vec4 Color;
void main(){ void main(){
gl_Position = UBO.proj * UBO.view * Push.model * vec4(Position_modelspace, 1); gl_Position = UBO.proj * UBO.view * Push.model * vec4(Position_modelspace, 1);
Color = Color_model; Color = Push.color;
} }

View File

@ -66,6 +66,8 @@ void Client::run(server_handle* const localHandle) {
const auto ray_result = world->raycast(camera.getRay() * options.voxel_density); const auto ray_result = world->raycast(camera.getRay() * options.voxel_density);
if(auto target = std::get_if<world::Universe::ray_target>(&ray_result)) { if(auto target = std::get_if<world::Universe::ray_target>(&ray_result)) {
state.look_at = *target; state.look_at = *target;
const auto &tool = options.editor.tool;
state.can_fill = world->isAreaFree(target->pos, world::action::ToGeometry(tool.shape), tool.radius);
} else { } else {
state.look_at = {}; state.look_at = {};
} }
@ -75,11 +77,12 @@ void Client::run(server_handle* const localHandle) {
ZoneScopedN("Edit"); ZoneScopedN("Edit");
const auto &tool = options.editor.tool; const auto &tool = options.editor.tool;
if (inputs.isPressing(Mouse::Left)) if (inputs.isPressing(Mouse::Left))
world->emit(world::action::FillCube( world->emit(world::action::FillShape(
state.look_at.value().pos, world::Voxel(world::materials::AIR, tool.emptyAir * world::Voxel::DENSITY_MAX), tool.radius)); state.look_at.value().pos, world::Voxel(world::materials::AIR, tool.emptyAir * world::Voxel::DENSITY_MAX), tool.shape, tool.radius));
else if (inputs.isPressing(Mouse::Right)) else if (const auto voxel = world::Voxel(tool.material, world::Voxel::DENSITY_MAX);
world->emit(world::action::FillCube( inputs.isPressing(Mouse::Right) && (state.can_fill || !voxel.is_solid()))
state.look_at.value().pos, world::Voxel(tool.material, world::Voxel::DENSITY_MAX), tool.radius)); world->emit(world::action::FillShape(
state.look_at.value().pos, voxel, tool.shape, tool.radius));
} }
if (inputs.isDown(Input::Throw)) { if (inputs.isDown(Input::Throw)) {
//FIXME: register entity type world->addEntity(entity_id(0), {state.position * options.voxel_density, glm::vec3(10, 0, 0)}); //FIXME: register entity type world->addEntity(entity_id(0), {state.position * options.voxel_density, glm::vec3(10, 0, 0)});
@ -195,8 +198,9 @@ void Client::run(server_handle* const localHandle) {
const auto pass = pipeline->beginIndicatorPass(); const auto pass = pipeline->beginIndicatorPass();
if(state.look_at.has_value()) { // Indicator if(state.look_at.has_value()) { // Indicator
const auto model = glm::scale(glm::translate(glm::scale(glm::mat4(1), 1.f / glm::vec3(options.voxel_density)), glm::vec3(state.look_at.value().pos.second + state.look_at.value().offset - offset * glm::llvec3(options.voxel_density)) - glm::vec3(.5 + options.editor.tool.radius)), glm::vec3(1 + options.editor.tool.radius * 2)); const auto model = glm::scale(glm::translate(glm::scale(glm::mat4(1), 1.f / glm::vec3(options.voxel_density)), glm::vec3(state.look_at.value().pos.second + state.look_at.value().offset - offset * glm::llvec3(options.voxel_density)) - glm::vec3(.5 + options.editor.tool.radius)), glm::vec3(1 + options.editor.tool.radius * 2));
const auto color = state.can_fill ? glm::vec4(1, 1, 1, .5) : (world::materials::solidity[options.editor.tool.material] ? glm::vec4(1, 0, 0, .5) : glm::vec4(1, .5, 0, .5));
reports.models_count++; reports.models_count++;
reports.tris_count += pass(model); reports.tris_count += pass(model, options.editor.tool.shape, color);
} }
} }
pipeline->postProcess(); pipeline->postProcess();

View File

@ -79,6 +79,7 @@ public:
} }
editor.visible = config["editor"]["visible"].value_or(editor.visible); editor.visible = config["editor"]["visible"].value_or(editor.visible);
editor.tool.shape = static_cast<world::action::Shape>(config["editor"]["tool"]["shape"].value_or(static_cast<int>(editor.tool.shape)));
editor.tool.radius = config["editor"]["tool"]["radius"].value_or(editor.tool.radius); editor.tool.radius = config["editor"]["tool"]["radius"].value_or(editor.tool.radius);
editor.tool.material = config["editor"]["tool"]["material"].value_or(editor.tool.material); editor.tool.material = config["editor"]["tool"]["material"].value_or(editor.tool.material);
editor.tool.emptyAir = config["editor"]["tool"]["empty_air"].value_or(editor.tool.emptyAir); editor.tool.emptyAir = config["editor"]["tool"]["empty_air"].value_or(editor.tool.emptyAir);
@ -156,6 +157,7 @@ public:
config.insert_or_assign("editor", toml::table({ config.insert_or_assign("editor", toml::table({
{"visible", editor.visible}, {"visible", editor.visible},
{"tool", toml::table({ {"tool", toml::table({
{"shape", static_cast<int>(editor.tool.shape)},
{"radius", editor.tool.radius}, {"radius", editor.tool.radius},
{"material", editor.tool.material}, {"material", editor.tool.material},
{"empty_air", editor.tool.emptyAir} {"empty_air", editor.tool.emptyAir}
@ -205,6 +207,7 @@ public:
struct { struct {
bool visible = false; bool visible = false;
struct { struct {
world::action::Shape shape = world::action::Shape::Cube;
int radius = 2; int radius = 2;
unsigned short material = 5; unsigned short material = 5;
bool emptyAir = true; bool emptyAir = true;

View File

@ -253,6 +253,16 @@ namespace contouring {
} }
ImGui::Columns(1); ImGui::Columns(1);
} }
if (ImGui::Button("Flush buffers")) {
//TODO: prefer unique_ptr
for(auto& buffer: buffers) {
for(auto& val: buffer.second.second) {
delete val.second.first;
delete val.second.second;
}
}
buffers.clear();
}
} }
void FlatDualMC::render(const surrounding::corners &surrounding, render::LodModel::LodData &out, std::vector<render::VertexData> &tmp, Layer layer) const { void FlatDualMC::render(const surrounding::corners &surrounding, render::LodModel::LodData &out, std::vector<render::VertexData> &tmp, Layer layer) const {

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "../../core/flags.hpp" #include "../../core/flags.hpp"
#include "../../core/world/actions.hpp"
#include <cassert> #include <cassert>
#include <memory> #include <memory>
#include <string> #include <string>
@ -73,8 +74,8 @@ public:
virtual std::function<size_t(render::LodModel *const, glm::mat4, glm::vec4, float)> beginWorldPass(bool solid) = 0; virtual std::function<size_t(render::LodModel *const, glm::mat4, glm::vec4, float)> beginWorldPass(bool solid) = 0;
/// Get started entity program /// Get started entity program
virtual std::function<size_t(render::Model *const, 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 line indicator (model, shape, color)
virtual std::function<size_t(glm::mat4)> beginIndicatorPass() = 0; virtual std::function<size_t(glm::mat4, world::action::Shape, glm::vec4)> beginIndicatorPass() = 0;
/// Apply postprocessing /// Apply postprocessing
virtual void postProcess() = 0; virtual void postProcess() = 0;
/// Finalise frame /// Finalise frame

View File

@ -227,6 +227,7 @@ UI::Actions UI::draw(config::client::options &options, state::state &state, cons
ImGui::EndCombo(); ImGui::EndCombo();
} }
ImGui::SliderInt("Radius", &options.editor.tool.radius, 0, 10); ImGui::SliderInt("Radius", &options.editor.tool.radius, 0, 10);
ImGui::Combo("Shape", (int*)&options.editor.tool.shape, world::action::SHAPES);
ImGui::Checkbox("Empty air", &options.editor.tool.emptyAir); ImGui::Checkbox("Empty air", &options.editor.tool.emptyAir);
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
ImGui::SetTooltip("Is cleaned area breathable"); ImGui::SetTooltip("Is cleaned area breathable");

View File

@ -15,10 +15,27 @@ const std::vector<glm::vec3> Shape::SKY_CUBE = {
{-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}
}; };
const std::pair<std::vector<glm::vec3>, std::vector<glm::vec4>> Indicator::CUBE = {{ const std::vector<glm::vec3> Shape::LINE_CUBE = {
{0, 0, 0}, {0, 0, 1}, {0, 0, 1}, {0, 1, 1}, {0, 1, 1}, {0, 1, 0}, {0, 1, 0}, {0, 0, 0}, {1, 0, 0}, {1, 0, 1}, {1, 0, 1}, {1, 1, 1}, {0, 0, 0}, {0, 0, 1}, {0, 0, 1}, {0, 1, 1}, {0, 1, 1}, {0, 1, 0}, {0, 1, 0}, {0, 0, 0}, {1, 0, 0}, {1, 0, 1}, {1, 0, 1}, {1, 1, 1},
{1, 1, 1}, {1, 1, 0}, {1, 1, 0}, {1, 0, 0}, {0, 0, 0}, {1, 0, 0}, {0, 0, 1}, {1, 0, 1}, {0, 1, 1}, {1, 1, 1}, {0, 1, 0}, {1, 1, 0} {1, 1, 1}, {1, 1, 0}, {1, 1, 0}, {1, 0, 0}, {0, 0, 0}, {1, 0, 0}, {0, 0, 1}, {1, 0, 1}, {0, 1, 1}, {1, 1, 1}, {0, 1, 0}, {1, 1, 0}
}, { };
constexpr auto SINPIOVER4 = 0.853553391f;
const std::vector<glm::vec3> Shape::LINE_SPHERE = {
{1, .5f, .5f}, {SINPIOVER4, SINPIOVER4, .5f}, {SINPIOVER4, SINPIOVER4, .5f}, {.5f, 1, .5f},
{.5f, 1, .5f}, {1-SINPIOVER4, SINPIOVER4, .5f}, {1-SINPIOVER4, SINPIOVER4, .5f}, {0, .5f, .5f},
{1, .5f, .5f}, {SINPIOVER4, 1-SINPIOVER4, .5f}, {SINPIOVER4, 1-SINPIOVER4, .5f}, {.5f, 0, .5f},
{.5f, 0, .5f}, {1-SINPIOVER4, 1-SINPIOVER4, .5f}, {1-SINPIOVER4, 1-SINPIOVER4, .5f}, {0, .5f, .5f},
{1, .5f, .5f}, {SINPIOVER4, .5f, SINPIOVER4}, {SINPIOVER4, .5f, SINPIOVER4}, {.5f, .5f, 1},
{.5f, .5f, 1}, {1-SINPIOVER4, .5f, SINPIOVER4}, {1-SINPIOVER4, .5f, SINPIOVER4}, {0, .5f, .5f},
{1, .5f, .5f}, {SINPIOVER4, .5f, 1-SINPIOVER4}, {SINPIOVER4, .5f, 1-SINPIOVER4}, {.5f, .5f, 0},
{.5f, .5f, 0}, {1-SINPIOVER4, .5f, 1-SINPIOVER4}, {1-SINPIOVER4, .5f, 1-SINPIOVER4}, {0, .5f, .5f},
{.5f, 1, .5f}, {.5f, SINPIOVER4, SINPIOVER4}, {.5f, SINPIOVER4, SINPIOVER4}, {.5f, .5f, 1},
{.5f, .5f, 1}, {.5f, 1-SINPIOVER4, SINPIOVER4}, {.5f, 1-SINPIOVER4, SINPIOVER4}, {.5f, 0, .5f},
{.5f, 1, .5f}, {.5f, SINPIOVER4, 1-SINPIOVER4}, {.5f, SINPIOVER4, 1-SINPIOVER4}, {.5f, .5f, 0},
{.5f, .5f, 0}, {.5f, 1-SINPIOVER4, 1-SINPIOVER4}, {.5f, 1-SINPIOVER4, 1-SINPIOVER4}, {.5f, 0, .5f}
};
const std::pair<std::vector<glm::vec3>, std::vector<glm::vec4>> ColoredShape::LINE_CUBE = {Shape::LINE_CUBE,
{
{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1},
{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1} {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}
}}; }};

View File

@ -45,14 +45,16 @@ public:
virtual ~Shape() { } virtual ~Shape() { }
static const std::vector<glm::vec3> SKY_CUBE; static const std::vector<glm::vec3> SKY_CUBE;
static const std::vector<glm::vec3> LINE_CUBE;
static const std::vector<glm::vec3> LINE_SPHERE;
}; };
/// Color lines model /// Color lines model
class Indicator { class ColoredShape {
public: public:
virtual ~Indicator() { } virtual ~ColoredShape() { }
static const std::pair<std::vector<glm::vec3>, std::vector<glm::vec4>> CUBE; static const std::pair<std::vector<glm::vec3>, std::vector<glm::vec4>> LINE_CUBE;
}; };
/// VertexData model with index /// VertexData model with index

View File

@ -18,7 +18,8 @@ constexpr auto GL_MINOR = 6;
#define TEXTURES_DIR CONTENT_DIR "textures/" #define TEXTURES_DIR CONTENT_DIR "textures/"
Renderer::Renderer(const renderOptions& options): Renderer::Renderer(const renderOptions& options):
IndicatorCubeBuffer(Indicator::CUBE.first, Indicator::CUBE.second) { IndicatorCubeBuffer(Shape::LINE_CUBE), IndicatorSphereBuffer(Shape::LINE_SPHERE)
{
glGenVertexArrays(1, &VertexArrayID); glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID); glBindVertexArray(VertexArrayID);
@ -122,11 +123,12 @@ std::function<size_t(render::Model *const, const std::vector<glm::mat4> &)> Rend
}; };
} }
std::function<size_t(glm::mat4)> Renderer::beginIndicatorPass() { std::function<size_t(glm::mat4, world::action::Shape, glm::vec4)> Renderer::beginIndicatorPass() {
IndicatorPass->useIt(); IndicatorPass->useIt();
return [&](glm::mat4 model) { return [&](glm::mat4 model, world::action::Shape shape, glm::vec4 color) {
IndicatorPass->setup(this, model); IndicatorPass->setup(this, model, color);
return IndicatorCubeBuffer.draw(); return shape == world::action::Shape::Cube ?
IndicatorCubeBuffer.draw(GL_LINES) : IndicatorSphereBuffer.draw(GL_LINES);
}; };
} }

View File

@ -45,7 +45,7 @@ public:
void beginFrame() override; void beginFrame() override;
std::function<size_t(render::LodModel *const, glm::mat4, glm::vec4, float)> beginWorldPass(bool solid) override; std::function<size_t(render::LodModel *const, glm::mat4, glm::vec4, float)> beginWorldPass(bool solid) override;
std::function<size_t(render::Model *const, const std::vector<glm::mat4>&)> beginEntityPass() override; std::function<size_t(render::Model *const, const std::vector<glm::mat4>&)> beginEntityPass() override;
std::function<size_t(glm::mat4)> beginIndicatorPass() override; std::function<size_t(glm::mat4, world::action::Shape, glm::vec4)> beginIndicatorPass() override;
void postProcess() override; void postProcess() override;
void endFrame() override; void endFrame() override;
void swapBuffer(Window&) override; void swapBuffer(Window&) override;
@ -72,7 +72,8 @@ 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;
Indicator IndicatorCubeBuffer; Shape IndicatorCubeBuffer;
Shape IndicatorSphereBuffer;
glm::mat4 ProjectionMatrix; glm::mat4 ProjectionMatrix;
glm::mat4 ViewMatrix; glm::mat4 ViewMatrix;

View File

@ -11,16 +11,16 @@ Shape::Shape(const std::vector<glm::vec3>& pos) {
Shape::~Shape() { Shape::~Shape() {
glDeleteBuffers(1, &bufferId); glDeleteBuffers(1, &bufferId);
} }
size_t Shape::draw() { size_t Shape::draw(GLenum format) {
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, bufferId); glBindBuffer(GL_ARRAY_BUFFER, bufferId);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0);
glDrawArrays(GL_TRIANGLES, 0, size); glDrawArrays(format, 0, size);
glDisableVertexAttribArray(0); glDisableVertexAttribArray(0);
return size; return size;
} }
Indicator::Indicator(const std::vector<glm::vec3>& pos, const std::vector<glm::vec4>& col) { ColoredShape::ColoredShape(const std::vector<glm::vec3>& pos, const std::vector<glm::vec4>& col) {
assert(pos.size() == col.size()); assert(pos.size() == col.size());
size = pos.size(); size = pos.size();
glGenBuffers(1, &vertexBufferId); glGenBuffers(1, &vertexBufferId);
@ -30,11 +30,11 @@ Indicator::Indicator(const std::vector<glm::vec3>& pos, const std::vector<glm::v
glBindBuffer(GL_ARRAY_BUFFER, colorBufferId); glBindBuffer(GL_ARRAY_BUFFER, colorBufferId);
glBufferData(GL_ARRAY_BUFFER, col.size() * sizeof(glm::vec4), col.data(), GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, col.size() * sizeof(glm::vec4), col.data(), GL_STATIC_DRAW);
} }
Indicator::~Indicator() { ColoredShape::~ColoredShape() {
glDeleteBuffers(1, &colorBufferId); glDeleteBuffers(1, &colorBufferId);
glDeleteBuffers(1, &vertexBufferId); glDeleteBuffers(1, &vertexBufferId);
} }
void Indicator::enableAttribs() { void ColoredShape::enableAttribs() {
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId); glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0);
@ -43,17 +43,17 @@ void Indicator::enableAttribs() {
glBindBuffer(GL_ARRAY_BUFFER, colorBufferId); glBindBuffer(GL_ARRAY_BUFFER, colorBufferId);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void *)0); glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void *)0);
} }
void Indicator::disableAttribs() { void ColoredShape::disableAttribs() {
glDisableVertexAttribArray(0); glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1); glDisableVertexAttribArray(1);
} }
size_t Indicator::draw() { size_t ColoredShape::draw() {
enableAttribs(); enableAttribs();
glDrawArrays(GL_LINES, 0, size); glDrawArrays(GL_LINES, 0, size);
disableAttribs(); disableAttribs();
return size; return size;
} }
size_t Indicator::drawInstanced(size_t count) { size_t ColoredShape::drawInstanced(size_t count) {
enableAttribs(); enableAttribs();
glDrawArraysInstanced(GL_LINES, 0, size, count); glDrawArraysInstanced(GL_LINES, 0, size, count);
disableAttribs(); disableAttribs();

View File

@ -13,17 +13,17 @@ public:
Shape(const std::vector<glm::vec3>&); Shape(const std::vector<glm::vec3>&);
~Shape(); ~Shape();
size_t draw(); size_t draw(GLenum format);
private: private:
size_t size; size_t size;
GLuint bufferId; GLuint bufferId;
}; };
class Indicator final: public render::Indicator { class ColoredShape final: public render::ColoredShape {
public: public:
Indicator(const std::vector<glm::vec3>&, const std::vector<glm::vec4>&); ColoredShape(const std::vector<glm::vec3>&, const std::vector<glm::vec4>&);
~Indicator(); ~ColoredShape();
size_t draw(); size_t draw();
size_t drawInstanced(size_t count); size_t drawInstanced(size_t count);

View File

@ -13,6 +13,7 @@ ColorProgram::ColorProgram(): Program() {
load(shaders); load(shaders);
MVPMatrixID = glGetUniformLocation(ProgramID, "MVP"); MVPMatrixID = glGetUniformLocation(ProgramID, "MVP");
ColID = glGetUniformLocation(ProgramID, "Col");
} }
ColorProgram::~ColorProgram() { } ColorProgram::~ColorProgram() { }
@ -20,11 +21,15 @@ ColorProgram::~ColorProgram() { }
std::string ColorProgram::getName() const { std::string ColorProgram::getName() const {
return "Color"; return "Color";
} }
void ColorProgram::setup(render::gl::Renderer *renderer, glm::mat4 modelMatrix) { void ColorProgram::setup(render::gl::Renderer *renderer, glm::mat4 modelMatrix, glm::vec4 color) {
const auto mvp = renderer->getProjectionMatrix() * renderer->getViewMatrix() * modelMatrix; const auto mvp = renderer->getProjectionMatrix() * renderer->getViewMatrix() * modelMatrix;
setMVP(&mvp[0][0]); setMVP(&mvp[0][0]);
setCol(&color[0]);
} }
void ColorProgram::setMVP(const GLfloat *matrix) { void ColorProgram::setMVP(const GLfloat *matrix) {
glUniformMatrix4fv(MVPMatrixID, 1, GL_FALSE, matrix); glUniformMatrix4fv(MVPMatrixID, 1, GL_FALSE, matrix);
} }
void ColorProgram::setCol(const GLfloat *color) {
glUniform4fv(ColID, 1, color);
}

View File

@ -9,13 +9,15 @@ namespace pass {
ColorProgram(); ColorProgram();
~ColorProgram(); ~ColorProgram();
void setup(render::gl::Renderer *, glm::mat4 modelMatrix); void setup(render::gl::Renderer *, glm::mat4 modelMatrix, glm::vec4 color);
protected: protected:
std::string getName() const override; std::string getName() const override;
void setMVP(const GLfloat *matrix); void setMVP(const GLfloat *matrix);
void setCol(const GLfloat *color);
private: private:
GLuint MVPMatrixID; GLuint MVPMatrixID;
GLuint ColID;
}; };
} }

View File

@ -32,7 +32,7 @@ void SkyProgram::start(render::gl::Renderer *renderer) {
void SkyProgram::draw(render::gl::Renderer *renderer) { void SkyProgram::draw(render::gl::Renderer *renderer) {
useIt(); useIt();
start(renderer); start(renderer);
CubeBuffer.draw(); CubeBuffer.draw(GL_TRIANGLES);
} }
void SkyProgram::setView(const GLfloat *matrix) { void SkyProgram::setView(const GLfloat *matrix) {

View File

@ -23,8 +23,9 @@ CommandCenter::CommandCenter(VkDevice device, const PhysicalDeviceInfo &info, co
} }
} }
indicCubeBuffer = Indicator::Create(Indicator::CUBE.first, Indicator::CUBE.second); indicSphereBuffer = Shape::Create(Shape::LINE_SPHERE);
if (!indicCubeBuffer) { indicCubeBuffer = Shape::Create(Shape::LINE_CUBE);
if (!(indicCubeBuffer && indicSphereBuffer)) {
FATAL("Failed to create vertex buffer!"); FATAL("Failed to create vertex buffer!");
} }
@ -337,15 +338,15 @@ void CommandCenter::startIndicPass(uint32_t idx, const Subpass& indicPass) {
vkCmdBindPipeline(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, indicPass.pipeline); vkCmdBindPipeline(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, indicPass.pipeline);
vkCmdBindDescriptorSets(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, indicPass.layout, 0, 1, &indicDescriptorSets[idx], 0, nullptr); vkCmdBindDescriptorSets(graphicsBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, indicPass.layout, 0, 1, &indicDescriptorSets[idx], 0, nullptr);
} }
size_t CommandCenter::recordIndicator(uint32_t idx, const Subpass& indicPass, glm::mat4 model) { size_t CommandCenter::recordIndicator(uint32_t idx, const Subpass& indicPass, const ModelColorPush& push, bool isCube) {
ModelPush push{model};
vkCmdPushConstants(graphicsBuffers[idx], indicPass.layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(push), &push); vkCmdPushConstants(graphicsBuffers[idx], indicPass.layout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(push), &push);
VkBuffer vertexBuffers[] = {indicCubeBuffer->getRef()}; const auto buffer = isCube ? indicCubeBuffer.get() : indicSphereBuffer.get();
VkBuffer vertexBuffers[] = {buffer->getRef()};
VkDeviceSize offsets[] = {0}; VkDeviceSize offsets[] = {0};
vkCmdBindVertexBuffers(graphicsBuffers[idx], 0, 1, vertexBuffers, offsets); vkCmdBindVertexBuffers(graphicsBuffers[idx], 0, 1, vertexBuffers, offsets);
vkCmdDraw(graphicsBuffers[idx], indicCubeBuffer->size, 1, 0, 0); vkCmdDraw(graphicsBuffers[idx], buffer->size, 1, 0, 0);
return indicCubeBuffer->size; return buffer->size;
} }
void CommandCenter::recordPostprocess(uint32_t idx, const Subpass& skyPass, bool skybox) { void CommandCenter::recordPostprocess(uint32_t idx, const Subpass& skyPass, bool skybox) {
vkCmdNextSubpass(graphicsBuffers[idx], VK_SUBPASS_CONTENTS_INLINE); vkCmdNextSubpass(graphicsBuffers[idx], VK_SUBPASS_CONTENTS_INLINE);

View File

@ -29,7 +29,7 @@ public:
void startEntityPass(uint32_t idx, const Subpass &entityPass); void startEntityPass(uint32_t idx, const Subpass &entityPass);
size_t recordModels(uint32_t idx, const Subpass &entityPass, const std::vector<glm::mat4>&, const Model *const); size_t recordModels(uint32_t idx, const Subpass &entityPass, const std::vector<glm::mat4>&, const Model *const);
void startIndicPass(uint32_t idx, const Subpass&); void startIndicPass(uint32_t idx, const Subpass&);
size_t recordIndicator(uint32_t idx, const Subpass&, glm::mat4 model); size_t recordIndicator(uint32_t idx, const Subpass&, const ModelColorPush&, bool isCube);
void recordPostprocess(uint32_t idx, const Subpass&, bool skybox); void recordPostprocess(uint32_t idx, const Subpass&, bool skybox);
void recordUI(uint32_t idx, VkRenderPass uiPass, VkExtent2D, const std::function<void(VkCommandBuffer)> &); void recordUI(uint32_t idx, VkRenderPass uiPass, VkExtent2D, const std::function<void(VkCommandBuffer)> &);
void submitGraphics(uint32_t, VkSemaphore, VkSemaphore, VkFence); void submitGraphics(uint32_t, VkSemaphore, VkSemaphore, VkFence);
@ -66,7 +66,8 @@ private:
std::unique_ptr<TextureArray> voxelHOSAtlas; std::unique_ptr<TextureArray> voxelHOSAtlas;
std::vector<VkDescriptorSet> indicDescriptorSets; std::vector<VkDescriptorSet> indicDescriptorSets;
std::unique_ptr<Indicator> indicCubeBuffer; std::unique_ptr<Shape> indicCubeBuffer;
std::unique_ptr<Shape> indicSphereBuffer;
std::vector<VkDescriptorSet> skyDescriptorSets; std::vector<VkDescriptorSet> skyDescriptorSets;
std::unique_ptr<TextureCube> skyboxTexture; std::unique_ptr<TextureCube> skyboxTexture;

View File

@ -464,7 +464,7 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render
{ // Indicator pipeline { // Indicator pipeline
VkPushConstantRange pushRange{}; VkPushConstantRange pushRange{};
pushRange.offset = 0; pushRange.offset = 0;
pushRange.size = sizeof(ModelPush); pushRange.size = sizeof(ModelColorPush);
pushRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; pushRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
setLayout(indicPass, {indicDescriptorSet}, {pushRange}); setLayout(indicPass, {indicDescriptorSet}, {pushRange});
auto shaderStages = setShaders(indicPass, "Color"); auto shaderStages = setShaders(indicPass, "Color");
@ -476,12 +476,12 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render
VkPipelineVertexInputStateCreateInfo vertexInputInfo{}; VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
auto bindingDescription = Indicator::getBindingDescription(); auto bindingDescription = Shape::getBindingDescription();
vertexInputInfo.vertexBindingDescriptionCount = 1; vertexInputInfo.vertexBindingDescriptionCount = 1;
vertexInputInfo.pVertexBindingDescriptions = &bindingDescription; vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
auto attributeDescriptions = Indicator::getAttributeDescription(); auto attributeDescription = Shape::getAttributeDescription();
vertexInputInfo.vertexAttributeDescriptionCount = attributeDescriptions.size(); vertexInputInfo.vertexAttributeDescriptionCount = 1;
vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); vertexInputInfo.pVertexAttributeDescriptions = &attributeDescription;
VkGraphicsPipelineCreateInfo pipelineInfo{}; VkGraphicsPipelineCreateInfo pipelineInfo{};
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;

View File

@ -482,13 +482,16 @@ std::function<size_t(render::Model *const, const std::vector<glm::mat4> &)> Rend
return [](render::Model *const, const std::vector<glm::mat4> &) { return 0; }; return [](render::Model *const, const std::vector<glm::mat4> &) { return 0; };
} }
std::function<size_t(glm::mat4)> Renderer::beginIndicatorPass() { std::function<size_t(glm::mat4, world::action::Shape, glm::vec4)> Renderer::beginIndicatorPass() {
assert(currentImage < swapChain->getImageViews().size()); assert(currentImage < swapChain->getImageViews().size());
auto &pass = pipeline->getIndicPass(); auto &pass = pipeline->getIndicPass();
commandCenter->startIndicPass(currentImage, pass); commandCenter->startIndicPass(currentImage, pass);
return [&](glm::mat4 model) { return [&](glm::mat4 model, world::action::Shape shape, glm::vec4 color) {
return commandCenter->recordIndicator(currentImage, pass, model); ModelColorPush push{};
push.model = model;
push.color = color;
return commandCenter->recordIndicator(currentImage, pass, push, shape == world::action::Shape::Cube);
}; };
} }

View File

@ -23,7 +23,7 @@ public:
void beginFrame() override; void beginFrame() override;
std::function<size_t(render::LodModel *const, glm::mat4, glm::vec4, float)> beginWorldPass(bool solid) override; std::function<size_t(render::LodModel *const, glm::mat4, glm::vec4, float)> beginWorldPass(bool solid) override;
std::function<size_t(render::Model *const, const std::vector<glm::mat4> &)> beginEntityPass() override; std::function<size_t(render::Model *const, const std::vector<glm::mat4> &)> beginEntityPass() override;
std::function<size_t(glm::mat4)> beginIndicatorPass() override; std::function<size_t(glm::mat4, world::action::Shape, glm::vec4)> beginIndicatorPass() override;
void postProcess() override; void postProcess() override;
void recordUI(std::function<void(VkCommandBuffer)>); void recordUI(std::function<void(VkCommandBuffer)>);
void endFrame() override; void endFrame() override;

View File

@ -9,7 +9,7 @@ std::unique_ptr<Shape> Shape::Create(const std::vector<glm::vec3>& vertices) {
return std::unique_ptr<Shape>(new Shape(tmp.ref, std::move(mem), vertices.size())); return std::unique_ptr<Shape>(new Shape(tmp.ref, std::move(mem), vertices.size()));
} }
std::unique_ptr<Indicator> Indicator::Create(const std::vector<glm::vec3>& vert, const std::vector<glm::vec4>& cols) { std::unique_ptr<ColoredShape> ColoredShape::Create(const std::vector<glm::vec3>& vert, const std::vector<glm::vec4>& cols) {
assert(vert.size() == cols.size()); assert(vert.size() == cols.size());
std::vector<Vertex> vertices; std::vector<Vertex> vertices;
vertices.reserve(vert.size()); vertices.reserve(vert.size());
@ -20,7 +20,7 @@ std::unique_ptr<Indicator> Indicator::Create(const std::vector<glm::vec3>& vert,
vk::Buffer::info tmp; vk::Buffer::info tmp;
data_view view(vertices); data_view view(vertices);
auto mem = createBuffer(view.size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, view, tmp); auto mem = createBuffer(view.size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, view, tmp);
return std::unique_ptr<Indicator>(new Indicator(vertices.size(), tmp.ref, std::move(mem))); return std::unique_ptr<ColoredShape>(new ColoredShape(vertices.size(), tmp.ref, std::move(mem)));
} }
std::unique_ptr<Model> Model::Create(const Data& data) { std::unique_ptr<Model> Model::Create(const Data& data) {

View File

@ -33,11 +33,11 @@ protected:
Buffer(ref, std::move(mem)), size(size) { } Buffer(ref, std::move(mem)), size(size) { }
}; };
class Indicator final: public render::Indicator, public Buffer { class ColoredShape final: public render::ColoredShape, public Buffer {
public: public:
const size_t size; const size_t size;
static std::unique_ptr<Indicator> Create(const std::vector<glm::vec3>&, const std::vector<glm::vec4>&); static std::unique_ptr<ColoredShape> Create(const std::vector<glm::vec3>&, const std::vector<glm::vec4>&);
struct Vertex { struct Vertex {
alignas(16) glm::vec3 pos; alignas(16) glm::vec3 pos;
@ -65,7 +65,7 @@ public:
} }
protected: protected:
Indicator(size_t size, VkBuffer ref, memory::ptr mem): Buffer(ref, std::move(mem)), size(size) {} ColoredShape(size_t size, VkBuffer ref, memory::ptr mem): Buffer(ref, std::move(mem)), size(size) {}
}; };
@ -162,6 +162,10 @@ struct VoxelUBO {
struct ModelPush { struct ModelPush {
alignas(16) glm::mat4 model; alignas(16) glm::mat4 model;
}; };
struct ModelColorPush {
alignas(16) glm::mat4 model;
alignas(16) glm::vec4 color;
};
struct CurvaturePush { struct CurvaturePush {
alignas(16) glm::vec4 sphereProj; alignas(16) glm::vec4 sphereProj;
alignas(4) float curvature; alignas(4) float curvature;

View File

@ -9,6 +9,7 @@ struct state {
bool capture_mouse = true; bool capture_mouse = true;
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 = {};
bool can_fill = true;
contouring::Abstract* contouring; contouring::Abstract* contouring;

View File

@ -258,8 +258,8 @@ void DistantUniverse::emit(const action::packet &action) {
peer.send(net::client_packet_type::MOVE, move->pos, net::channel_type::NOTIFY); peer.send(net::client_packet_type::MOVE, move->pos, net::channel_type::NOTIFY);
} else if(const auto message = std::get_if<action::Message>(&action)) { } else if(const auto message = std::get_if<action::Message>(&action)) {
peer.send(net::client_packet_type::MESSAGE, message->text.data(), message->text.size(), net::channel_type::RELIABLE); peer.send(net::client_packet_type::MESSAGE, message->text.data(), message->text.size(), net::channel_type::RELIABLE);
} else if(const auto fillCube = std::get_if<action::FillCube>(&action)) { } else if(const auto fill = std::get_if<action::FillShape>(&action)) {
peer.send(net::client_packet_type::FILL_CUBE, *fillCube, net::channel_type::RELIABLE); peer.send(net::client_packet_type::FILL_SHAPE, *fill, net::channel_type::RELIABLE);
} else { } else {
LOG_W("Bad action " << action.index()); LOG_W("Bad action " << action.index());
} }
@ -269,6 +269,18 @@ Universe::ray_result DistantUniverse::raycast(const geometry::Ray &ray) const {
return Raycast(ray, areas); return Raycast(ray, areas);
} }
bool DistantUniverse::isAreaFree(const area_<voxel_pos> &pos, const geometry::Shape shape, const uint16_t radius) const {
if (const auto it = areas.find(pos.first); it != areas.end()) {
const auto center = pos.second + it->second->getOffset().as_voxel();
return !entities.contains([&](size_t, const Entity &entity) {
return entity.instances.contains([&](size_t, const Universe::Entity::Instance &inst) {
return geometry::InShape(shape, center, radius, inst.pos.as_voxel(), entity.size);
});
});
} else
return false;
}
void DistantUniverse::getEntitiesModels(const std::function<void(size_t, const std::vector<glm::mat4>&)>& call, void DistantUniverse::getEntitiesModels(const std::function<void(size_t, const std::vector<glm::mat4>&)>& call,
const std::optional<geometry::Frustum>& frustum, const glm::llvec3& offset, int density) const std::optional<geometry::Frustum>& frustum, const glm::llvec3& offset, int density)
{ {

View File

@ -18,6 +18,8 @@ namespace world::client {
ray_result raycast(const geometry::Ray &) const override; ray_result raycast(const geometry::Ray &) const override;
bool isAreaFree(const area_<voxel_pos> &pos, geometry::Shape shape, uint16_t radius) const override;
void getEntitiesModels(const std::function<void(size_t, const std::vector<glm::mat4>&)>&, void getEntitiesModels(const std::function<void(size_t, const std::vector<glm::mat4>&)>&,
const std::optional<geometry::Frustum>& frustum, const glm::llvec3& offset, int density) override; const std::optional<geometry::Frustum>& frustum, const glm::llvec3& offset, int density) override;

View File

@ -55,6 +55,17 @@ void LocalUniverse::emit(const action::packet &packet) {
Universe::ray_result LocalUniverse::raycast(const geometry::Ray& ray) const { Universe::ray_result LocalUniverse::raycast(const geometry::Ray& ray) const {
return handle->raycast(ray); return handle->raycast(ray);
} }
bool LocalUniverse::isAreaFree(const area_<voxel_pos> &pos, const geometry::Shape shape, const uint16_t radius) const {
if (const auto it = handle->areas->find(pos.first); it != handle->areas->end()) {
const auto center = pos.second + it->second->getOffset().as_voxel();
return !handle->entities->contains([&](entity_id, const Entity &entity) {
return entity.instances.contains([&](entity_id, const Entity::Instance &inst) {
return geometry::InShape(shape, center, radius, inst.pos.as_voxel(), entity.size);
});
});
} else
return false;
}
void LocalUniverse::getEntitiesModels(const std::function<void(size_t, const std::vector<glm::mat4>&)>& call, void LocalUniverse::getEntitiesModels(const std::function<void(size_t, const std::vector<glm::mat4>&)>& call,
const std::optional<geometry::Frustum>& frustum, const glm::llvec3& offset, int density) const std::optional<geometry::Frustum>& frustum, const glm::llvec3& offset, int density)

View File

@ -15,6 +15,8 @@ namespace world::client {
ray_result raycast(const geometry::Ray &ray) const override; ray_result raycast(const geometry::Ray &ray) const override;
bool isAreaFree(const area_<voxel_pos> &pos, geometry::Shape shape, uint16_t radius) const override;
void getEntitiesModels(const std::function<void(size_t, const std::vector<glm::mat4>&)>&, void getEntitiesModels(const std::function<void(size_t, const std::vector<glm::mat4>&)>&,
const std::optional<geometry::Frustum>& frustum, const glm::llvec3& offset, int density) override; const std::optional<geometry::Frustum>& frustum, const glm::llvec3& offset, int density) override;

View File

@ -264,6 +264,16 @@ namespace data::generational {
} }
} }
template<typename predicate>
bool contains(predicate fn) const {
for (size_t i = 0; i < this->size(); i++) {
if(this->at(i).has_value() && fn(i, this->at(i).value())) {
return true;
}
}
return false;
}
size_t count() const { size_t count() const {
return std::count_if(this->begin(), this->end(), return std::count_if(this->begin(), this->end(),
[](const std::optional<T> &e) { return e.has_value(); }); [](const std::optional<T> &e) { return e.has_value(); });

View File

@ -0,0 +1,28 @@
#pragma once
#include "../flags.hpp"
#include "../data/math.hpp"
#include "IBox.hpp"
namespace geometry {
enum class Shape {
Cube,
Sphere
};
static _FORCE_INLINE_ bool InShape(Shape shape, glm::llvec3 center, int radius, glm::llvec3 pos, glm::vec3 size) {
switch (shape) {
case Shape::Cube:
return IBox::fromCenter(center, radius).contains(
IBox::fromMin(pos, size)) != IBox::ContainmentType::Disjoint;
case Shape::Sphere:
return glm::length2(center - pos) < glm::pow2(radius + (int)size.x);
default:
return false;
}
}
};

View File

@ -1,27 +0,0 @@
#pragma once
#include <glm/glm.hpp>
#include <vector>
/// Interger sphere fill
struct SphereIterator {
SphereIterator(const glm::ivec3 &center, int radius): center(center), radius(radius) { }
glm::ivec3 center;
int radius;
void vector(std::vector<glm::ivec3>& out) {
int top = center.y - radius, bottom = center.y + radius;
for (int y = top; y <= bottom; y++) {
int dy = y - center.y, dxz = floor(sqrt(radius * radius - dy * dy));
int minx = center.x - dxz, maxx = center.x + dxz;
int minz = center.z - dxz, maxz = center.z + dxz;
out.reserve(out.size() + dxz * dxz);
for (int z = minz; z <= maxz; z++) {
for (int x = minx; x <= maxx; x++) {
out.emplace_back(x, y, z);
}}
}
}
};

View File

@ -66,8 +66,8 @@ enum class server_packet_type: enet_uint8 {
}; };
enum class client_packet_type: enet_uint8 { enum class client_packet_type: enet_uint8 {
/// Interact with voxels /// Interact with voxels
/// actions::FillCube reliable /// actions::FillShape reliable
FILL_CUBE = 0, FILL_SHAPE = 0,
/// Request missing chunks /// Request missing chunks
/// area_id, chunk_pos[] reliable /// area_id, chunk_pos[] reliable

View File

@ -5,6 +5,7 @@
#include "Voxel.hpp" #include "Voxel.hpp"
#include "position.h" #include "position.h"
#include "../geometry/Ray.hpp" #include "../geometry/Ray.hpp"
#include "../geometry/Shapes.hpp"
namespace world { namespace world {
/// Whole abstract universe container /// Whole abstract universe container
@ -43,6 +44,10 @@ namespace world {
/// @note ray in world scale /// @note ray in world scale
virtual ray_result raycast(const geometry::Ray &ray) const = 0; virtual ray_result raycast(const geometry::Ray &ray) const = 0;
/// Check for entity in shape
/// MAYBE: multiarea
virtual bool isAreaFree(const area_<voxel_pos> &pos, geometry::Shape shape, uint16_t radius) const = 0;
/// Check for collision on movement /// Check for collision on movement
bool collide(const glm::ifvec3 &pos, const glm::vec3 &vel, int density, float radius = 0) const; bool collide(const glm::ifvec3 &pos, const glm::vec3 &vel, int density, float radius = 0) const;
/// Move with collision check /// Move with collision check

View File

@ -3,6 +3,8 @@
#include "forward.h" #include "forward.h"
#include "Voxel.hpp" #include "Voxel.hpp"
#include <variant> #include <variant>
#include "../flags.hpp"
#include "../geometry/Shapes.hpp"
/// Client action on world /// Client action on world
namespace world::action { namespace world::action {
@ -17,10 +19,38 @@ struct Fill: part::Ping {
const area_<voxel_pos> pos; const area_<voxel_pos> pos;
const Voxel val; const Voxel val;
}; };
struct FillCube: Fill {
FillCube(const area_<voxel_pos> &pos, const Voxel &val, int radius): Fill(pos, val), radius(radius) { }
const int radius; enum class Shape: uint8_t {
Cube,
RawSphere,
/*SmoothSphere,
CylinderX,
CylinderY,
CylinderZ,
ConePX,
ConeNX,
ConePY,
ConeNY,
ConePZ,
ConeNZ,
*/
};
constexpr auto SHAPES = "Cube\0RawSphere\0";
static _FORCE_INLINE_ geometry::Shape ToGeometry(Shape shape) {
switch (shape) {
case Shape::RawSphere:
return geometry::Shape::Sphere;
default:
return geometry::Shape::Cube;
}
}
struct FillShape: Fill {
FillShape(const area_<voxel_pos> &pos, const Voxel &val, Shape shape, uint8_t radius):
Fill(pos, val), shape(shape), radius(radius) {}
const Shape shape;
const uint8_t radius;
}; };
struct Move: part::Ping { struct Move: part::Ping {
Move(const voxel_pos& pos): pos(pos) { } Move(const voxel_pos& pos): pos(pos) { }
@ -33,5 +63,5 @@ struct Message: part::Ping {
const std::string text; const std::string text;
}; };
using packet = std::variant<Move, Message, Fill, FillCube>; using packet = std::variant<Move, Message, Fill, FillShape>;
} }

View File

@ -0,0 +1,59 @@
#include "iterators.hpp"
using namespace world::iterator;
std::unique_ptr<Abstract> world::iterator::Get(world::action::Shape shape, uint16_t radius) {
switch (shape) {
case world::action::Shape::Cube:
return std::make_unique<Cube>(radius);
case world::action::Shape::RawSphere:
return std::make_unique<RawSphere>(radius);
default:
return std::unique_ptr<Abstract>(nullptr);
}
}
bool Cube::next(pair& out) {
if (pos.z > radius)
return false;
out.first = pos;
out.second = 1;
// MAYBE: use linear idx to make branch less
if (pos.x < radius) {
pos.x++;
} else {
pos.x = -radius;
if (pos.y < radius) {
pos.y++;
} else {
pos.y = -radius;
pos.z++;
}
}
return true;
}
bool RawSphere::next(pair& out) {
if (pos.x > radius)
return false;
out.first = pos;
out.second = 1;
if (pos.z < dz) {
pos.z++;
} else {
if (pos.y < dy) {
pos.y++;
} else {
pos.x++;
dy = floor(sqrt(radius * radius - pos.x * pos.x));
pos.y = -dy;
}
dz = floor(sqrt(dy * dy - pos.y * pos.y));
pos.z = -dz;
}
return true;
}

View File

@ -0,0 +1,45 @@
#pragma once
#include "position.h"
#include "actions.hpp"
namespace world::iterator {
using pair = std::pair<glm::ivec3, float>;
class Abstract {
public:
virtual bool next(pair&) = 0;
protected:
static constexpr uint32_t Diam(uint16_t radius) { return radius * 2 + 1; }
};
/// From -radius to radius
std::unique_ptr<Abstract> Get(action::Shape, uint16_t radius);
class Cube final: public Abstract {
public:
bool next(pair&) override;
Cube(uint16_t radius): radius(radius), pos(-radius, -radius, -radius) { }
private:
const uint16_t radius;
glm::ivec3 pos;
};
/// Interger sphere
class RawSphere final: public Abstract {
public:
bool next(pair&) override;
RawSphere(uint16_t radius): radius(radius), pos(-radius, 0, 0), dy(0), dz(0) { }
private:
const uint16_t radius;
glm::ivec3 pos;
int dy;
int dz;
};
}

View File

@ -6,7 +6,7 @@ using namespace world::server;
SharedUniverse::SharedUniverse(const options &o, server_handle *const localHandle): Universe(o), localHandle(localHandle) { SharedUniverse::SharedUniverse(const options &o, server_handle *const localHandle): Universe(o), localHandle(localHandle) {
// Local player // Local player
[[maybe_unused]] [[maybe_unused]]
const auto id = entities.at(PLAYER_ENTITY_ID).instances.emplace(Entity::Instance{spawnPoint}); const auto id = entities.at(PLAYER_ENTITY_ID).instances.emplace(Entity::Instance{spawnPoint, glm::vec3(0)});
assert(id == PLAYER_ENTITY_ID); assert(id == PLAYER_ENTITY_ID);
localHandle->teleport = spawnPoint; localHandle->teleport = spawnPoint;
movedPlayers.insert(id); movedPlayers.insert(id);
@ -14,10 +14,9 @@ SharedUniverse::SharedUniverse(const options &o, server_handle *const localHandl
localHandle->areas = (world::client::area_map*)(&areas); //WONT FIX: templated area localHandle->areas = (world::client::area_map*)(&areas); //WONT FIX: templated area
localHandle->entities = &entities; localHandle->entities = &entities;
localHandle->emit = std::function([&](const world::action::packet &packet) { localHandle->emit = std::function([&](const world::action::packet &packet) {
if(const auto fill = std::get_if<world::action::Fill>(&packet)) { if(const auto fill = std::get_if<world::action::FillShape>(&packet)) {
this->set(fill->pos, fill->val); //NOTE: LocalUniverse had already check for entities
} else if(const auto fillCube = std::get_if<world::action::FillCube>(&packet)) { this->set(fill->pos, fill->radius, fill->shape, fill->val);
this->setCube(fillCube->pos, fillCube->val, fillCube->radius);
} else if(const auto message = std::get_if<world::action::Message>(&packet)) { } else if(const auto message = std::get_if<world::action::Message>(&packet)) {
this->broadcastMessage("Player" + std::to_string(id.index) + ": " + message->text); this->broadcastMessage("Player" + std::to_string(id.index) + ": " + message->text);
} else if(const auto move = std::get_if<world::action::Move>(&packet)) { } else if(const auto move = std::get_if<world::action::Move>(&packet)) {

View File

@ -7,6 +7,7 @@
#include "Chunk.hpp" #include "Chunk.hpp"
#include "../../core/world/raycast.hpp" #include "../../core/world/raycast.hpp"
#include "../../core/world/iterators.hpp"
#include "../../core/world/actions.hpp" #include "../../core/world/actions.hpp"
#include "../../core/net/PacketView.hpp" #include "../../core/net/PacketView.hpp"
@ -391,7 +392,7 @@ void Universe::pullNetwork() {
[&](peer_t *peer, salt_t salt) { [&](peer_t *peer, salt_t salt) {
ZoneScopedN("Connect"); ZoneScopedN("Connect");
LOG_I("Client connect from " << peer->address); LOG_I("Client connect from " << peer->address);
net_client* client = new net_client(salt, entities.at(PLAYER_ENTITY_ID).instances.emplace(Entity::Instance{spawnPoint})); net_client* client = new net_client(salt, entities.at(PLAYER_ENTITY_ID).instances.emplace(Entity::Instance{spawnPoint, glm::vec3(0)}));
peer->data = client; peer->data = client;
const salt_t rnd = std::rand(); const salt_t rnd = std::rand();
@ -451,12 +452,15 @@ void Universe::pullNetwork() {
} }
break; break;
} }
case client_packet_type::FILL_CUBE: { case client_packet_type::FILL_SHAPE: {
if(const auto fill = PacketReader(packet).read<world::action::FillCube>()) { if(const auto fill = PacketReader(packet).read<world::action::FillShape>()) {
//TODO: check ray //TODO: check ray
//TODO: check entities if (fill->val.is_solid() && !isAreaFree(fill->pos, world::action::ToGeometry(fill->shape), fill->radius)) {
LOG_T("Entity in solid fill area");
break;
}
set(fill->pos, fill->radius, fill->shape, fill->val);
//TODO: handle inventory //TODO: handle inventory
setCube(fill->pos, fill->val, fill->radius);
} else { } else {
LOG_T("Bad fill"); LOG_T("Bad fill");
} }
@ -527,7 +531,7 @@ void Universe::broadcastMessage(const std::string& text) {
host.broadcast(net::server_packet_type::MESSAGE, text.data(), text.size(), net::channel_type::RELIABLE); host.broadcast(net::server_packet_type::MESSAGE, text.data(), text.size(), net::channel_type::RELIABLE);
} }
void Universe::updateChunk(area_map::iterator &, world::ChunkContainer::iterator &, chunk_pos, float deltaTime) {} void Universe::updateChunk(area_map::iterator &, world::ChunkContainer::iterator &, chunk_pos, float /*deltaTime*/) {}
void Universe::loadChunk(area_<chunk_pos>, chunk_pos, const world::ChunkContainer &) {} void Universe::loadChunk(area_<chunk_pos>, chunk_pos, const world::ChunkContainer &) {}
void Universe::setOptions(const Universe::options& options) { void Universe::setOptions(const Universe::options& options) {
@ -539,30 +543,32 @@ Universe::ray_result Universe::raycast(const geometry::Ray &ray) const {
return Raycast(ray, areas); return Raycast(ray, areas);
} }
std::optional<world::Item> Universe::set(const area_<voxel_pos>& pos, const Voxel& val) { bool Universe::isAreaFree(const area_<voxel_pos> &pos, const geometry::Shape shape, const uint16_t radius) const {
if(const auto it = areas.find(pos.first); it != areas.end()) { if (const auto it = areas.find(pos.first); it != areas.end()) {
auto &chunks = it->second->setChunks(); const auto center = pos.second + it->second->getOffset().as_voxel();
const auto split = glm::splitIdx(pos.second); return !entities.contains([&](entity_id, const Entity &entity) {
if(chunks.inRange(split.first)) return entity.instances.contains([&](entity_id, const Entity::Instance &inst) {
if(const auto chunk = chunks.findInRange(split.first)) return geometry::InShape(shape, center, radius, inst.pos.as_voxel(), entity.size);
return {std::dynamic_pointer_cast<Chunk>(chunk.value())->replace(split.second, val)}; });
} });
return {}; } else
return false;
} }
world::ItemList Universe::setCube(const area_<voxel_pos>& pos, const Voxel& val, int radius) {
world::ItemList Universe::set(const area_<voxel_pos>& pos, int radius, action::Shape shape, const Voxel& val) {
ZoneScopedN("Fill"); ZoneScopedN("Fill");
ItemList list; ItemList list;
if(const auto it = areas.find(pos.first); it != areas.end()) { if(const auto it = areas.find(pos.first); it != areas.end()) {
robin_hood::unordered_map<chunk_pos, std::vector<Chunk::Edit>> edits; robin_hood::unordered_map<chunk_pos, std::vector<Chunk::Edit>> edits;
auto &chunks = it->second->setChunks(); auto &chunks = it->second->setChunks();
for (int z = -radius; z <= radius; z++) { auto iterator = world::iterator::Get(shape, radius);
for (int y = -radius; y <= radius; y++) { world::iterator::pair point;
for (int x = -radius; x <= radius; x++) { while (iterator->next(point)) {
//TODO: list.pop(val) const voxel_pos offset = point.first;
const auto offset = voxel_pos(x, y, z);
const auto split = glm::splitIdx(pos.second + offset); const auto split = glm::splitIdx(pos.second + offset);
if(chunks.inRange(split.first)) if(chunks.inRange(split.first)) {
if(const auto chunk = it->second->setChunks().findInRange(split.first)) { if(const auto chunk = it->second->setChunks().findInRange(split.first)) {
//TODO: use ratio in point.second
auto ck = std::dynamic_pointer_cast<Chunk>(chunk.value()); auto ck = std::dynamic_pointer_cast<Chunk>(chunk.value());
auto prev = ck->get(split.second); auto prev = ck->get(split.second);
if(prev.value != val.value) { if(prev.value != val.value) {
@ -573,7 +579,9 @@ world::ItemList Universe::setCube(const area_<voxel_pos>& pos, const Voxel& val,
ck->replace(split.second, val, delay); ck->replace(split.second, val, delay);
} }
} }
}}} }
}
ZoneScopedN("Packet"); ZoneScopedN("Packet");
size_t size = sizeof(area_id); size_t size = sizeof(area_id);
for(const auto& part: edits) { for(const auto& part: edits) {

View File

@ -3,6 +3,7 @@
#include <string> #include <string>
#include <thread> #include <thread>
#include "../../core/world/Universe.hpp" #include "../../core/world/Universe.hpp"
#include "../../core/world/actions.hpp"
#include "../../core/data/math.hpp" #include "../../core/data/math.hpp"
#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"
@ -39,11 +40,9 @@ namespace world::server {
/// Apply new options /// Apply new options
void setOptions(const options &); void setOptions(const options &);
/// Set voxel at pos /// Set volume of voxel with pos as center
std::optional<Item> set(const area_<voxel_pos> &pos, const Voxel &val);
/// Set cube of voxel with pos as center
/// MAYBE: allow set multi area /// MAYBE: allow set multi area
ItemList setCube(const area_<voxel_pos> &pos, const Voxel &val, int radius); ItemList set(const area_<voxel_pos> &pos, int radius, action::Shape shape, const Voxel &val);
/// Instante entity /// Instante entity
entity_instance_id addEntity(entity_id type, const Entity::Instance &instance); entity_instance_id addEntity(entity_id type, const Entity::Instance &instance);
@ -56,6 +55,8 @@ namespace world::server {
/// @note ray in world scale /// @note ray in world scale
ray_result raycast(const geometry::Ray &ray) const override; ray_result raycast(const geometry::Ray &ray) const override;
bool isAreaFree(const area_<voxel_pos> &pos, geometry::Shape shape, uint16_t radius) const override;
/// Check for collision on destination /// Check for collision on destination
bool collide_end(const glm::ifvec3 &pos, const glm::vec3 &vel, int density, float radius) const; bool collide_end(const glm::ifvec3 &pos, const glm::vec3 &vel, int density, float radius) const;
/// Check for collision at position /// Check for collision at position
@ -76,7 +77,6 @@ namespace world::server {
virtual std::shared_ptr<Chunk> createChunk(const chunk_pos &pos, const std::unique_ptr<generator::Abstract> &rnd) const; virtual std::shared_ptr<Chunk> createChunk(const chunk_pos &pos, const std::unique_ptr<generator::Abstract> &rnd) const;
virtual std::shared_ptr<Chunk> createChunk(std::istream &str) const; virtual std::shared_ptr<Chunk> createChunk(std::istream &str) const;
virtual void updateChunk(area_map::iterator&, world::ChunkContainer::iterator&, chunk_pos, float deltaTime); virtual void updateChunk(area_map::iterator&, world::ChunkContainer::iterator&, chunk_pos, float deltaTime);
virtual void loadChunk(area_<chunk_pos>, chunk_pos, const world::ChunkContainer &); virtual void loadChunk(area_<chunk_pos>, chunk_pos, const world::ChunkContainer &);