From 5fdff56f8f7dc71687d45dc9e1ae4b43ea682621 Mon Sep 17 00:00:00 2001 From: Shu Date: Fri, 23 Oct 2020 22:50:00 +0200 Subject: [PATCH] Raw sphere tool --- TODO.md | 5 +- resource/content/shaders/Color.fs | 2 +- resource/content/shaders/Color.fs.spv | 4 +- resource/content/shaders/Color.vs | 4 +- resource/content/shaders/Color.vs.spv | 4 +- resource/shaders-src/Color.frag | 2 +- resource/shaders-src/Color.vert | 4 +- src/client/Client.cpp | 12 +++-- src/client/config.hpp | 3 ++ src/client/render/Renderer.hpp | 5 +- src/client/render/UI.cpp | 1 + src/client/render/api/Models.cpp | 21 +++++++- src/client/render/api/Models.hpp | 8 +-- src/client/render/gl/Renderer.cpp | 12 +++-- src/client/render/gl/Renderer.hpp | 5 +- src/client/render/gl/api/Models.cpp | 16 +++--- src/client/render/gl/api/Models.hpp | 8 +-- src/client/render/gl/pass/ColorProgram.cpp | 7 ++- src/client/render/gl/pass/ColorProgram.hpp | 4 +- src/client/render/gl/pass/SkyProgram.cpp | 2 +- src/client/render/vk/CommandCenter.cpp | 15 +++--- src/client/render/vk/CommandCenter.hpp | 5 +- src/client/render/vk/Pipeline.cpp | 10 ++-- src/client/render/vk/Renderer.cpp | 9 ++-- src/client/render/vk/Renderer.hpp | 2 +- src/client/render/vk/api/Models.cpp | 4 +- src/client/render/vk/api/Models.hpp | 10 ++-- src/client/state.hpp | 1 + src/client/world/DistantUniverse.cpp | 4 +- src/core/net/data.hpp | 4 +- src/core/world/actions.hpp | 26 +++++++-- src/server/world/SharedUniverse.cpp | 11 ++-- src/server/world/Universe.cpp | 62 ++++++++++++++++++++-- src/server/world/Universe.hpp | 4 +- 34 files changed, 209 insertions(+), 87 deletions(-) diff --git a/TODO.md b/TODO.md index 3459500..a08ae1e 100644 --- a/TODO.md +++ b/TODO.md @@ -14,6 +14,7 @@ - [~] Authentication - [x] Compression - [ ] Encryption + - DTLS - [x] Embedded - [x] Standalone @@ -24,8 +25,10 @@ - [ ] Local prediction - [ ] Contouring service - [~] Edit - - [ ] More types + - [ ] Shape iterators + - Cube - Sphere + - [ ] More types - Anchor - Prevent suffocation - [ ] Local prediction diff --git a/resource/content/shaders/Color.fs b/resource/content/shaders/Color.fs index 892bfe0..bea0778 100644 --- a/resource/content/shaders/Color.fs +++ b/resource/content/shaders/Color.fs @@ -6,5 +6,5 @@ layout(location = 0) out vec4 color; in vec4 Color; void main(){ - color = vec4(Color.xyz, .5); + color = Color; } \ No newline at end of file diff --git a/resource/content/shaders/Color.fs.spv b/resource/content/shaders/Color.fs.spv index b148912..1a8f64c 100644 --- a/resource/content/shaders/Color.fs.spv +++ b/resource/content/shaders/Color.fs.spv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5311d6e728a8130264f2142f937cc4f893757bc5820bc3258c7b17b0b79f2e2f -size 632 +oid sha256:fbd3f1dc76303d181564dbf54fc1833c874c14d6a911009b2192349f70613af2 +size 480 diff --git a/resource/content/shaders/Color.vs b/resource/content/shaders/Color.vs index e61a295..9baca9f 100644 --- a/resource/content/shaders/Color.vs +++ b/resource/content/shaders/Color.vs @@ -2,14 +2,14 @@ layout(location = 0) in vec3 Position_modelspace; -layout(location = 1) in vec4 Color_model; uniform mat4 MVP; +uniform vec4 Col; out vec4 Color; void main(){ gl_Position = MVP * vec4(Position_modelspace, 1); - Color = Color_model; + Color = Col; } diff --git a/resource/content/shaders/Color.vs.spv b/resource/content/shaders/Color.vs.spv index 2ecbe89..2342974 100644 --- a/resource/content/shaders/Color.vs.spv +++ b/resource/content/shaders/Color.vs.spv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0a2efd883d46b6c0920c265a5f511795063285ae4ca95bc0d99423242e751413 -size 1744 +oid sha256:26a5bd8054a9172df79d6b18b899126f4c2ee2e3ddfb4b0d3ee776d5a5e375a8 +size 1752 diff --git a/resource/shaders-src/Color.frag b/resource/shaders-src/Color.frag index d53aeda..947706f 100644 --- a/resource/shaders-src/Color.frag +++ b/resource/shaders-src/Color.frag @@ -6,5 +6,5 @@ layout(location = 0) in vec4 Color; layout(location = 0) out vec4 color; void main(){ - color = vec4(Color.xyz, .5); + color = Color; } \ No newline at end of file diff --git a/resource/shaders-src/Color.vert b/resource/shaders-src/Color.vert index dd6f06b..68aab05 100644 --- a/resource/shaders-src/Color.vert +++ b/resource/shaders-src/Color.vert @@ -6,15 +6,15 @@ layout(binding = 0) uniform UniformBufferObject { } UBO; layout(push_constant) uniform PushConst { mat4 model; + vec4 color; } Push; layout(location = 0) in vec3 Position_modelspace; -layout(location = 1) in vec4 Color_model; layout(location = 0) out vec4 Color; void main(){ gl_Position = UBO.proj * UBO.view * Push.model * vec4(Position_modelspace, 1); - Color = Color_model; + Color = Push.color; } diff --git a/src/client/Client.cpp b/src/client/Client.cpp index ed93ac2..aa52f3a 100644 --- a/src/client/Client.cpp +++ b/src/client/Client.cpp @@ -66,6 +66,8 @@ void Client::run(server_handle* const localHandle) { const auto ray_result = world->raycast(camera.getRay() * options.voxel_density); if(auto target = std::get_if(&ray_result)) { state.look_at = *target; + const auto &tool = options.editor.tool; + state.can_fill = true; //FIXME: world->canFill(target->pos, tool.shape, tool.radius); } else { state.look_at = {}; } @@ -75,11 +77,11 @@ void Client::run(server_handle* const localHandle) { ZoneScopedN("Edit"); const auto &tool = options.editor.tool; if (inputs.isPressing(Mouse::Left)) - world->emit(world::action::FillCube( - state.look_at.value().pos, world::Voxel(world::materials::AIR, tool.emptyAir * world::Voxel::DENSITY_MAX), tool.radius)); + world->emit(world::action::FillShape( + 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)) - world->emit(world::action::FillCube( - 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, world::Voxel(tool.material, world::Voxel::DENSITY_MAX), tool.shape, tool.radius)); } if (inputs.isDown(Input::Throw)) { //FIXME: register entity type world->addEntity(entity_id(0), {state.position * options.voxel_density, glm::vec3(10, 0, 0)}); @@ -196,7 +198,7 @@ void Client::run(server_handle* const localHandle) { 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)); reports.models_count++; - reports.tris_count += pass(model); + reports.tris_count += pass(model, options.editor.tool.shape, state.can_fill ? glm::vec4(1, 1, 1, .5) : glm::vec4(1, 0, 0, .5)); } } pipeline->postProcess(); diff --git a/src/client/config.hpp b/src/client/config.hpp index dd84e7a..82943d8 100644 --- a/src/client/config.hpp +++ b/src/client/config.hpp @@ -79,6 +79,7 @@ public: } editor.visible = config["editor"]["visible"].value_or(editor.visible); + editor.tool.shape = static_cast(config["editor"]["tool"]["shape"].value_or(static_cast(editor.tool.shape))); 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.emptyAir = config["editor"]["tool"]["empty_air"].value_or(editor.tool.emptyAir); @@ -156,6 +157,7 @@ public: config.insert_or_assign("editor", toml::table({ {"visible", editor.visible}, {"tool", toml::table({ + {"shape", static_cast(editor.tool.shape)}, {"radius", editor.tool.radius}, {"material", editor.tool.material}, {"empty_air", editor.tool.emptyAir} @@ -205,6 +207,7 @@ public: struct { bool visible = false; struct { + world::action::Shape shape = world::action::Shape::Cube; int radius = 2; unsigned short material = 5; bool emptyAir = true; diff --git a/src/client/render/Renderer.hpp b/src/client/render/Renderer.hpp index fe3015f..532c973 100644 --- a/src/client/render/Renderer.hpp +++ b/src/client/render/Renderer.hpp @@ -1,6 +1,7 @@ #pragma once #include "../../core/flags.hpp" +#include "../../core/world/actions.hpp" #include #include #include @@ -73,8 +74,8 @@ public: virtual std::function beginWorldPass(bool solid) = 0; /// Get started entity program virtual std::function &)> beginEntityPass() = 0; - /// Draw cube indicator - virtual std::function beginIndicatorPass() = 0; + /// Draw line indicator (model, shape, color) + virtual std::function beginIndicatorPass() = 0; /// Apply postprocessing virtual void postProcess() = 0; /// Finalise frame diff --git a/src/client/render/UI.cpp b/src/client/render/UI.cpp index 10424e9..a57fdd0 100644 --- a/src/client/render/UI.cpp +++ b/src/client/render/UI.cpp @@ -227,6 +227,7 @@ UI::Actions UI::draw(config::client::options &options, state::state &state, cons ImGui::EndCombo(); } 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); if (ImGui::IsItemHovered()) ImGui::SetTooltip("Is cleaned area breathable"); diff --git a/src/client/render/api/Models.cpp b/src/client/render/api/Models.cpp index 6fb44bd..a96f7ba 100644 --- a/src/client/render/api/Models.cpp +++ b/src/client/render/api/Models.cpp @@ -15,10 +15,27 @@ const std::vector 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} }; -const std::pair, std::vector> Indicator::CUBE = {{ +const std::vector 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}, {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 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> 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} }}; diff --git a/src/client/render/api/Models.hpp b/src/client/render/api/Models.hpp index b701c9b..314e523 100644 --- a/src/client/render/api/Models.hpp +++ b/src/client/render/api/Models.hpp @@ -45,14 +45,16 @@ public: virtual ~Shape() { } static const std::vector SKY_CUBE; + static const std::vector LINE_CUBE; + static const std::vector LINE_SPHERE; }; /// Color lines model -class Indicator { +class ColoredShape { public: - virtual ~Indicator() { } + virtual ~ColoredShape() { } - static const std::pair, std::vector> CUBE; + static const std::pair, std::vector> LINE_CUBE; }; /// VertexData model with index diff --git a/src/client/render/gl/Renderer.cpp b/src/client/render/gl/Renderer.cpp index b21dc9e..2ad2816 100644 --- a/src/client/render/gl/Renderer.cpp +++ b/src/client/render/gl/Renderer.cpp @@ -18,7 +18,8 @@ constexpr auto GL_MINOR = 6; #define TEXTURES_DIR CONTENT_DIR "textures/" Renderer::Renderer(const renderOptions& options): - IndicatorCubeBuffer(Indicator::CUBE.first, Indicator::CUBE.second) { + IndicatorCubeBuffer(Shape::LINE_CUBE), IndicatorSphereBuffer(Shape::LINE_SPHERE) +{ glGenVertexArrays(1, &VertexArrayID); glBindVertexArray(VertexArrayID); @@ -122,11 +123,12 @@ std::function &)> Rend }; } -std::function Renderer::beginIndicatorPass() { +std::function Renderer::beginIndicatorPass() { IndicatorPass->useIt(); - return [&](glm::mat4 model) { - IndicatorPass->setup(this, model); - return IndicatorCubeBuffer.draw(); + return [&](glm::mat4 model, world::action::Shape shape, glm::vec4 color) { + IndicatorPass->setup(this, model, color); + return shape == world::action::Shape::Cube ? + IndicatorCubeBuffer.draw(GL_LINES) : IndicatorSphereBuffer.draw(GL_LINES); }; } diff --git a/src/client/render/gl/Renderer.hpp b/src/client/render/gl/Renderer.hpp index 2f65561..b499ea1 100644 --- a/src/client/render/gl/Renderer.hpp +++ b/src/client/render/gl/Renderer.hpp @@ -45,7 +45,7 @@ public: void beginFrame() override; std::function beginWorldPass(bool solid) override; std::function&)> beginEntityPass() override; - std::function beginIndicatorPass() override; + std::function beginIndicatorPass() override; void postProcess() override; void endFrame() override; void swapBuffer(Window&) override; @@ -72,7 +72,8 @@ private: std::unique_ptr EntityPass; std::unique_ptr SkyPass; std::unique_ptr IndicatorPass; - Indicator IndicatorCubeBuffer; + Shape IndicatorCubeBuffer; + Shape IndicatorSphereBuffer; glm::mat4 ProjectionMatrix; glm::mat4 ViewMatrix; diff --git a/src/client/render/gl/api/Models.cpp b/src/client/render/gl/api/Models.cpp index 94492a1..c39c1bd 100644 --- a/src/client/render/gl/api/Models.cpp +++ b/src/client/render/gl/api/Models.cpp @@ -11,16 +11,16 @@ Shape::Shape(const std::vector& pos) { Shape::~Shape() { glDeleteBuffers(1, &bufferId); } -size_t Shape::draw() { +size_t Shape::draw(GLenum format) { glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, bufferId); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0); - glDrawArrays(GL_TRIANGLES, 0, size); + glDrawArrays(format, 0, size); glDisableVertexAttribArray(0); return size; } -Indicator::Indicator(const std::vector& pos, const std::vector& col) { +ColoredShape::ColoredShape(const std::vector& pos, const std::vector& col) { assert(pos.size() == col.size()); size = pos.size(); glGenBuffers(1, &vertexBufferId); @@ -30,11 +30,11 @@ Indicator::Indicator(const std::vector& pos, const std::vector&); ~Shape(); - size_t draw(); + size_t draw(GLenum format); private: size_t size; GLuint bufferId; }; -class Indicator final: public render::Indicator { +class ColoredShape final: public render::ColoredShape { public: - Indicator(const std::vector&, const std::vector&); - ~Indicator(); + ColoredShape(const std::vector&, const std::vector&); + ~ColoredShape(); size_t draw(); size_t drawInstanced(size_t count); diff --git a/src/client/render/gl/pass/ColorProgram.cpp b/src/client/render/gl/pass/ColorProgram.cpp index 0d6dc4b..78eee13 100644 --- a/src/client/render/gl/pass/ColorProgram.cpp +++ b/src/client/render/gl/pass/ColorProgram.cpp @@ -13,6 +13,7 @@ ColorProgram::ColorProgram(): Program() { load(shaders); MVPMatrixID = glGetUniformLocation(ProgramID, "MVP"); + ColID = glGetUniformLocation(ProgramID, "Col"); } ColorProgram::~ColorProgram() { } @@ -20,11 +21,15 @@ ColorProgram::~ColorProgram() { } std::string ColorProgram::getName() const { 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; setMVP(&mvp[0][0]); + setCol(&color[0]); } void ColorProgram::setMVP(const GLfloat *matrix) { glUniformMatrix4fv(MVPMatrixID, 1, GL_FALSE, matrix); } +void ColorProgram::setCol(const GLfloat *color) { + glUniform4fv(ColID, 1, color); +} diff --git a/src/client/render/gl/pass/ColorProgram.hpp b/src/client/render/gl/pass/ColorProgram.hpp index d728e09..70470f7 100644 --- a/src/client/render/gl/pass/ColorProgram.hpp +++ b/src/client/render/gl/pass/ColorProgram.hpp @@ -9,13 +9,15 @@ namespace pass { ColorProgram(); ~ColorProgram(); - void setup(render::gl::Renderer *, glm::mat4 modelMatrix); + void setup(render::gl::Renderer *, glm::mat4 modelMatrix, glm::vec4 color); protected: std::string getName() const override; void setMVP(const GLfloat *matrix); + void setCol(const GLfloat *color); private: GLuint MVPMatrixID; + GLuint ColID; }; } diff --git a/src/client/render/gl/pass/SkyProgram.cpp b/src/client/render/gl/pass/SkyProgram.cpp index f87784e..6009ff3 100644 --- a/src/client/render/gl/pass/SkyProgram.cpp +++ b/src/client/render/gl/pass/SkyProgram.cpp @@ -32,7 +32,7 @@ void SkyProgram::start(render::gl::Renderer *renderer) { void SkyProgram::draw(render::gl::Renderer *renderer) { useIt(); start(renderer); - CubeBuffer.draw(); + CubeBuffer.draw(GL_TRIANGLES); } void SkyProgram::setView(const GLfloat *matrix) { diff --git a/src/client/render/vk/CommandCenter.cpp b/src/client/render/vk/CommandCenter.cpp index bfe5a82..bb793e7 100644 --- a/src/client/render/vk/CommandCenter.cpp +++ b/src/client/render/vk/CommandCenter.cpp @@ -23,8 +23,9 @@ CommandCenter::CommandCenter(VkDevice device, const PhysicalDeviceInfo &info, co } } - indicCubeBuffer = Indicator::Create(Indicator::CUBE.first, Indicator::CUBE.second); - if (!indicCubeBuffer) { + indicSphereBuffer = Shape::Create(Shape::LINE_SPHERE); + indicCubeBuffer = Shape::Create(Shape::LINE_CUBE); + if (!(indicCubeBuffer && indicSphereBuffer)) { 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); 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) { - ModelPush push{model}; +size_t CommandCenter::recordIndicator(uint32_t idx, const Subpass& indicPass, const ModelColorPush& push, bool isCube) { 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}; vkCmdBindVertexBuffers(graphicsBuffers[idx], 0, 1, vertexBuffers, offsets); - vkCmdDraw(graphicsBuffers[idx], indicCubeBuffer->size, 1, 0, 0); - return indicCubeBuffer->size; + vkCmdDraw(graphicsBuffers[idx], buffer->size, 1, 0, 0); + return buffer->size; } void CommandCenter::recordPostprocess(uint32_t idx, const Subpass& skyPass, bool skybox) { vkCmdNextSubpass(graphicsBuffers[idx], VK_SUBPASS_CONTENTS_INLINE); diff --git a/src/client/render/vk/CommandCenter.hpp b/src/client/render/vk/CommandCenter.hpp index b140ca6..efb22a0 100644 --- a/src/client/render/vk/CommandCenter.hpp +++ b/src/client/render/vk/CommandCenter.hpp @@ -29,7 +29,7 @@ public: void startEntityPass(uint32_t idx, const Subpass &entityPass); size_t recordModels(uint32_t idx, const Subpass &entityPass, const std::vector&, const Model *const); 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 recordUI(uint32_t idx, VkRenderPass uiPass, VkExtent2D, const std::function &); void submitGraphics(uint32_t, VkSemaphore, VkSemaphore, VkFence); @@ -66,7 +66,8 @@ private: std::unique_ptr voxelHOSAtlas; std::vector indicDescriptorSets; - std::unique_ptr indicCubeBuffer; + std::unique_ptr indicCubeBuffer; + std::unique_ptr indicSphereBuffer; std::vector skyDescriptorSets; std::unique_ptr skyboxTexture; diff --git a/src/client/render/vk/Pipeline.cpp b/src/client/render/vk/Pipeline.cpp index 6342c7a..1994baa 100644 --- a/src/client/render/vk/Pipeline.cpp +++ b/src/client/render/vk/Pipeline.cpp @@ -464,7 +464,7 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render { // Indicator pipeline VkPushConstantRange pushRange{}; pushRange.offset = 0; - pushRange.size = sizeof(ModelPush); + pushRange.size = sizeof(ModelColorPush); pushRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; setLayout(indicPass, {indicDescriptorSet}, {pushRange}); auto shaderStages = setShaders(indicPass, "Color"); @@ -476,12 +476,12 @@ Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render VkPipelineVertexInputStateCreateInfo vertexInputInfo{}; vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - auto bindingDescription = Indicator::getBindingDescription(); + auto bindingDescription = Shape::getBindingDescription(); vertexInputInfo.vertexBindingDescriptionCount = 1; vertexInputInfo.pVertexBindingDescriptions = &bindingDescription; - auto attributeDescriptions = Indicator::getAttributeDescription(); - vertexInputInfo.vertexAttributeDescriptionCount = attributeDescriptions.size(); - vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); + auto attributeDescription = Shape::getAttributeDescription(); + vertexInputInfo.vertexAttributeDescriptionCount = 1; + vertexInputInfo.pVertexAttributeDescriptions = &attributeDescription; VkGraphicsPipelineCreateInfo pipelineInfo{}; pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; diff --git a/src/client/render/vk/Renderer.cpp b/src/client/render/vk/Renderer.cpp index e28b2a8..ec46384 100644 --- a/src/client/render/vk/Renderer.cpp +++ b/src/client/render/vk/Renderer.cpp @@ -482,13 +482,16 @@ std::function &)> Rend return [](render::Model *const, const std::vector &) { return 0; }; } -std::function Renderer::beginIndicatorPass() { +std::function Renderer::beginIndicatorPass() { assert(currentImage < swapChain->getImageViews().size()); auto &pass = pipeline->getIndicPass(); commandCenter->startIndicPass(currentImage, pass); - return [&](glm::mat4 model) { - return commandCenter->recordIndicator(currentImage, pass, model); + return [&](glm::mat4 model, world::action::Shape shape, glm::vec4 color) { + ModelColorPush push{}; + push.model = model; + push.color = color; + return commandCenter->recordIndicator(currentImage, pass, push, shape == world::action::Shape::Cube); }; } diff --git a/src/client/render/vk/Renderer.hpp b/src/client/render/vk/Renderer.hpp index ae14b2b..23f8b83 100644 --- a/src/client/render/vk/Renderer.hpp +++ b/src/client/render/vk/Renderer.hpp @@ -23,7 +23,7 @@ public: void beginFrame() override; std::function beginWorldPass(bool solid) override; std::function &)> beginEntityPass() override; - std::function beginIndicatorPass() override; + std::function beginIndicatorPass() override; void postProcess() override; void recordUI(std::function); void endFrame() override; diff --git a/src/client/render/vk/api/Models.cpp b/src/client/render/vk/api/Models.cpp index 9b8911d..f7f231f 100644 --- a/src/client/render/vk/api/Models.cpp +++ b/src/client/render/vk/api/Models.cpp @@ -9,7 +9,7 @@ std::unique_ptr Shape::Create(const std::vector& vertices) { return std::unique_ptr(new Shape(tmp.ref, std::move(mem), vertices.size())); } -std::unique_ptr Indicator::Create(const std::vector& vert, const std::vector& cols) { +std::unique_ptr ColoredShape::Create(const std::vector& vert, const std::vector& cols) { assert(vert.size() == cols.size()); std::vector vertices; vertices.reserve(vert.size()); @@ -20,7 +20,7 @@ std::unique_ptr Indicator::Create(const std::vector& vert, vk::Buffer::info tmp; data_view view(vertices); auto mem = createBuffer(view.size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, view, tmp); - return std::unique_ptr(new Indicator(vertices.size(), tmp.ref, std::move(mem))); + return std::unique_ptr(new ColoredShape(vertices.size(), tmp.ref, std::move(mem))); } std::unique_ptr Model::Create(const Data& data) { diff --git a/src/client/render/vk/api/Models.hpp b/src/client/render/vk/api/Models.hpp index 25babbd..7bb99f8 100644 --- a/src/client/render/vk/api/Models.hpp +++ b/src/client/render/vk/api/Models.hpp @@ -33,11 +33,11 @@ protected: Buffer(ref, std::move(mem)), size(size) { } }; -class Indicator final: public render::Indicator, public Buffer { +class ColoredShape final: public render::ColoredShape, public Buffer { public: const size_t size; - static std::unique_ptr Create(const std::vector&, const std::vector&); + static std::unique_ptr Create(const std::vector&, const std::vector&); struct Vertex { alignas(16) glm::vec3 pos; @@ -65,7 +65,7 @@ public: } 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 { alignas(16) glm::mat4 model; }; +struct ModelColorPush { + alignas(16) glm::mat4 model; + alignas(16) glm::vec4 color; +}; struct CurvaturePush { alignas(16) glm::vec4 sphereProj; alignas(4) float curvature; diff --git a/src/client/state.hpp b/src/client/state.hpp index 71f7cce..6225879 100644 --- a/src/client/state.hpp +++ b/src/client/state.hpp @@ -9,6 +9,7 @@ struct state { bool capture_mouse = true; camera_pos position = camera_pos(voxel_pos(0), 1); std::optional look_at = {}; + bool can_fill = true; contouring::Abstract* contouring; diff --git a/src/client/world/DistantUniverse.cpp b/src/client/world/DistantUniverse.cpp index 422c59f..933c33e 100644 --- a/src/client/world/DistantUniverse.cpp +++ b/src/client/world/DistantUniverse.cpp @@ -258,8 +258,8 @@ void DistantUniverse::emit(const action::packet &action) { peer.send(net::client_packet_type::MOVE, move->pos, net::channel_type::NOTIFY); } else if(const auto message = std::get_if(&action)) { 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)) { - peer.send(net::client_packet_type::FILL_CUBE, *fillCube, net::channel_type::RELIABLE); + } else if(const auto fill = std::get_if(&action)) { + peer.send(net::client_packet_type::FILL_SHAPE, *fill, net::channel_type::RELIABLE); } else { LOG_W("Bad action " << action.index()); } diff --git a/src/core/net/data.hpp b/src/core/net/data.hpp index 0d6e172..eed31c4 100644 --- a/src/core/net/data.hpp +++ b/src/core/net/data.hpp @@ -66,8 +66,8 @@ enum class server_packet_type: enet_uint8 { }; enum class client_packet_type: enet_uint8 { /// Interact with voxels - /// actions::FillCube reliable - FILL_CUBE = 0, + /// actions::FillShape reliable + FILL_SHAPE = 0, /// Request missing chunks /// area_id, chunk_pos[] reliable diff --git a/src/core/world/actions.hpp b/src/core/world/actions.hpp index ec24050..45ccdee 100644 --- a/src/core/world/actions.hpp +++ b/src/core/world/actions.hpp @@ -17,10 +17,28 @@ struct Fill: part::Ping { const area_ pos; const Voxel val; }; -struct FillCube: Fill { - FillCube(const area_ &pos, const Voxel &val, int radius): Fill(pos, val), radius(radius) { } +enum class Shape : uint8_t { + Cube, + Sphere, + /*SmoothSphere, + CylinderX, + CylinderY, + CylinderZ, + ConePX, + ConeNX, + ConePY, + ConeNY, + ConePZ, + ConeNZ, + */ +}; +constexpr auto SHAPES = "Cube\0Sphere\0"; +struct FillShape: Fill { + FillShape(const area_ &pos, const Voxel &val, Shape shape, uint8_t radius): + Fill(pos, val), shape(shape), radius(radius) {} - const int radius; + const Shape shape; + const uint8_t radius; }; struct Move: part::Ping { Move(const voxel_pos& pos): pos(pos) { } @@ -33,5 +51,5 @@ struct Message: part::Ping { const std::string text; }; -using packet = std::variant; +using packet = std::variant; } \ No newline at end of file diff --git a/src/server/world/SharedUniverse.cpp b/src/server/world/SharedUniverse.cpp index bb31e64..e87b9a3 100644 --- a/src/server/world/SharedUniverse.cpp +++ b/src/server/world/SharedUniverse.cpp @@ -6,7 +6,7 @@ using namespace world::server; SharedUniverse::SharedUniverse(const options &o, server_handle *const localHandle): Universe(o), localHandle(localHandle) { // Local player [[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); localHandle->teleport = spawnPoint; movedPlayers.insert(id); @@ -14,10 +14,11 @@ SharedUniverse::SharedUniverse(const options &o, server_handle *const localHandl localHandle->areas = (world::client::area_map*)(&areas); //WONT FIX: templated area localHandle->entities = &entities; localHandle->emit = std::function([&](const world::action::packet &packet) { - if(const auto fill = std::get_if(&packet)) { - this->set(fill->pos, fill->val); - } else if(const auto fillCube = std::get_if(&packet)) { - this->setCube(fillCube->pos, fillCube->val, fillCube->radius); + if(const auto fill = std::get_if(&packet)) { + if (fill->shape == world::action::Shape::Cube) + this->setCube(fill->pos, fill->val, fill->radius); + else + this->setSphere(fill->pos, fill->val, fill->radius); } else if(const auto message = std::get_if(&packet)) { this->broadcastMessage("Player" + std::to_string(id.index) + ": " + message->text); } else if(const auto move = std::get_if(&packet)) { diff --git a/src/server/world/Universe.cpp b/src/server/world/Universe.cpp index 12ffb8b..1d1e0bd 100644 --- a/src/server/world/Universe.cpp +++ b/src/server/world/Universe.cpp @@ -391,7 +391,7 @@ void Universe::pullNetwork() { [&](peer_t *peer, salt_t salt) { ZoneScopedN("Connect"); 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; const salt_t rnd = std::rand(); @@ -451,12 +451,15 @@ void Universe::pullNetwork() { } break; } - case client_packet_type::FILL_CUBE: { - if(const auto fill = PacketReader(packet).read()) { + case client_packet_type::FILL_SHAPE: { + if(const auto fill = PacketReader(packet).read()) { //TODO: check ray //TODO: check entities //TODO: handle inventory - setCube(fill->pos, fill->val, fill->radius); + if (fill->shape == world::action::Shape::Cube) + setCube(fill->pos, fill->val, fill->radius); + else + setSphere(fill->pos, fill->val, fill->radius); } else { LOG_T("Bad fill"); } @@ -527,7 +530,7 @@ void Universe::broadcastMessage(const std::string& text) { 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, const world::ChunkContainer &) {} void Universe::setOptions(const Universe::options& options) { @@ -594,6 +597,55 @@ world::ItemList Universe::setCube(const area_& pos, const Voxel& val, } return list; } +world::ItemList Universe::setSphere(const area_& pos, const Voxel& val, int radius) { + ZoneScopedN("FillSphere"); + ItemList list; + if(const auto it = areas.find(pos.first); it != areas.end()) { + robin_hood::unordered_map> edits; + auto &chunks = it->second->setChunks(); + for (int z = -radius; z <= radius; z++) { + for (int y = -radius; y <= radius; y++) { + for (int x = -radius; x <= radius; x++) { + const auto offset = voxel_pos(x, y, z); + //FIXME: refactor with voxel_pos iterator + if (glm::length2(offset) > glm::pow2(radius)) + continue; + + //TODO: list.pop(val) + const auto split = glm::splitIdx(pos.second + offset); + if(chunks.inRange(split.first)) + if(const auto chunk = it->second->setChunks().findInRange(split.first)) { + auto ck = std::dynamic_pointer_cast(chunk.value()); + auto prev = ck->get(split.second); + if(prev.value != val.value) { + //TODO: apply break table + //TODO: inventory + const auto delay = glm::length2(offset) / radius * .05f; + edits[split.first].push_back(Chunk::Edit{split.second, val, delay}); + ck->replace(split.second, val, delay); + } + } + }}} + ZoneScopedN("Packet"); + size_t size = sizeof(area_id); + for(const auto& part: edits) { + size += sizeof(chunk_pos); + size += sizeof(chunk_voxel_idx); + size += sizeof(Chunk::Edit) * part.second.size(); + } + auto packet = net::Server::makePacket(net::server_packet_type::EDITS, NULL, size, 0); + packet.write(pos.first); + for(const auto& part: edits) { + packet.write(part.first); + packet.write(part.second.size()); + packet.write(part.second.data(), part.second.size() * sizeof(Chunk::Edit)); + } + + assert(packet.isFull()); + host.broadcast(packet.get(), net::channel_type::NOTIFY); + } + return list; +} bool Universe::collide_end(const glm::ifvec3 &pos, const glm::vec3 &vel, int density, float radius) const { return std::holds_alternative(raycast(geometry::Ray((pos + vel) * density, vel, radius))); diff --git a/src/server/world/Universe.hpp b/src/server/world/Universe.hpp index f6258ad..6c8a36a 100644 --- a/src/server/world/Universe.hpp +++ b/src/server/world/Universe.hpp @@ -44,6 +44,9 @@ namespace world::server { /// Set cube of voxel with pos as center /// MAYBE: allow set multi area ItemList setCube(const area_ &pos, const Voxel &val, int radius); + /// Set sphere of voxel with pos as center + /// MAYBE: allow set multi area + ItemList setSphere(const area_ &pos, const Voxel &val, int radius); /// Instante entity entity_instance_id addEntity(entity_id type, const Entity::Instance &instance); @@ -76,7 +79,6 @@ namespace world::server { virtual std::shared_ptr createChunk(const chunk_pos &pos, const std::unique_ptr &rnd) const; virtual std::shared_ptr createChunk(std::istream &str) const; - virtual void updateChunk(area_map::iterator&, world::ChunkContainer::iterator&, chunk_pos, float deltaTime); virtual void loadChunk(area_, chunk_pos, const world::ChunkContainer &);