diff --git a/engine/include/cubos/engine/gizmos/gizmos.hpp b/engine/include/cubos/engine/gizmos/gizmos.hpp index 6035940ea8..b995f5021f 100644 --- a/engine/include/cubos/engine/gizmos/gizmos.hpp +++ b/engine/include/cubos/engine/gizmos/gizmos.hpp @@ -68,6 +68,18 @@ namespace cubos::engine glm::vec3 secondBaseCenter, float secondBaseRadius, float lifespan = 0.0F, Space space = Space::World); + /// @brief Draws a ring gizmo. + /// @param id Identifier of the gizmo. + /// @param firstBasePosition Center of one of the bases. + /// @param secondBasePosition Center of the second base. + /// @param outerRadius Radius of one of the ring. + /// @param innerRadius Radius of the of the hole. + /// @param lifespan How long the line will be on screen for, in seconds. Defaults to 0, which means a single + /// frame. + /// @param space Space to draw the gizmo in. + void drawRing(const std::string& id, glm::vec3 firstBasePosition, glm::vec3 secondBasePosition, + float outerRadius, float innerRadius, float lifespan = 0.0F, Space space = Space::World); + /// @brief Draws an arrow gizmo. /// @param id Identifier of the gizmo. /// @param origin Point from which the arrow starts. diff --git a/engine/samples/gizmos/main.cpp b/engine/samples/gizmos/main.cpp index 2362b81f32..9b3467eb03 100644 --- a/engine/samples/gizmos/main.cpp +++ b/engine/samples/gizmos/main.cpp @@ -76,6 +76,11 @@ static void drawSystem(Gizmos& gizmos) gizmos.drawCutCone("cut cone", {0.7F, 0.7F, 0.7F}, 5.0F, {-3, -3, -3}, 3.0F, 0, Gizmos::Space::World); ///[Cut Cone] + + /// [Ring] + gizmos.color({0.5F, 0.2F, 1.0F}); + gizmos.drawRing("ring", {-2, -2, 2}, {-3, -3, 3}, 5, 4, 0, Gizmos::Space::World); + /// [Ring] } /// [System] diff --git a/engine/src/cubos/engine/gizmos/gizmos.cpp b/engine/src/cubos/engine/gizmos/gizmos.cpp index e15f6745ef..1061c3a487 100644 --- a/engine/src/cubos/engine/gizmos/gizmos.cpp +++ b/engine/src/cubos/engine/gizmos/gizmos.cpp @@ -9,6 +9,7 @@ #include "types/box.hpp" #include "types/cut_cone.hpp" #include "types/line.hpp" +#include "types/ring.hpp" using cubos::engine::DeltaTime; using cubos::engine::Gizmos; @@ -127,6 +128,14 @@ void Gizmos::drawCutCone(const std::string& id, glm::vec3 firstBaseCenter, float space); } +void Gizmos::drawRing(const std::string& id, glm::vec3 firstBasePosition, glm::vec3 secondBasePosition, + float outerRadius, float innerRadius, float lifespan, Space space) +{ + push(std::make_shared((uint32_t)mHasher(id), firstBasePosition, secondBasePosition, outerRadius, + innerRadius, mColor, lifespan), + space); +} + void Gizmos::drawArrow(const std::string& id, glm::vec3 origin, glm::vec3 direction, float girth, float width, float ratio, float lifespan, Space space) { diff --git a/engine/src/cubos/engine/gizmos/renderer.cpp b/engine/src/cubos/engine/gizmos/renderer.cpp index e043b02ee6..b253364aba 100644 --- a/engine/src/cubos/engine/gizmos/renderer.cpp +++ b/engine/src/cubos/engine/gizmos/renderer.cpp @@ -121,6 +121,7 @@ void GizmosRenderer::init(RenderDevice* currentRenderDevice, glm::ivec2 size) initLinePrimitive(); initBoxPrimitive(); initCutConePrimitive(); + initRingPrimitive(); } void GizmosRenderer::initLinePrimitive() @@ -237,3 +238,104 @@ void GizmosRenderer::initCutConePrimitive() cutConePrimitive.ib = renderDevice->createIndexBuffer(sizeof(indices), indices, IndexFormat::UInt, Usage::Static); } + +void GizmosRenderer::initRingPrimitive() +{ + ringPrimitive.vaDesc.elementCount = 1; + ringPrimitive.vaDesc.elements[0].name = "position"; + ringPrimitive.vaDesc.elements[0].type = Type::Float; + ringPrimitive.vaDesc.elements[0].size = 3; + ringPrimitive.vaDesc.elements[0].buffer.index = 0; + ringPrimitive.vaDesc.elements[0].buffer.offset = 0; + ringPrimitive.vaDesc.elements[0].buffer.stride = 3 * sizeof(float); + ringPrimitive.vaDesc.shaderPipeline = drawPipeline; + + float verts[RingSections * 12]; + + renderDevice->setShaderPipeline(drawPipeline); + ringPrimitive.vb = renderDevice->createVertexBuffer(sizeof(verts), verts, Usage::Dynamic); + ringPrimitive.vaDesc.buffers[0] = ringPrimitive.vb; + ringPrimitive.va = renderDevice->createVertexArray(ringPrimitive.vaDesc); + + unsigned int indices[3 * 8 * RingSections]; + + int iIndex = 0; + // Sides + for (unsigned int i = 0; i < (RingSections - 1) * 2; i += 2) + { + // TOP + indices[iIndex++] = i; + indices[iIndex++] = i + 1; + indices[iIndex++] = i + 3; + + indices[iIndex++] = i; + indices[iIndex++] = i + 3; + indices[iIndex++] = i + 2; + + // BOTTOM + indices[iIndex++] = i + (RingSections * 2); + indices[iIndex++] = i + (RingSections * 2) + 1; + indices[iIndex++] = i + (RingSections * 2) + 3; + + indices[iIndex++] = i + (RingSections * 2); + indices[iIndex++] = i + (RingSections * 2) + 3; + indices[iIndex++] = i + (RingSections * 2) + 2; + + // INNER + indices[iIndex++] = i + 1; + indices[iIndex++] = i + (RingSections * 2) + 1; + indices[iIndex++] = i + (RingSections * 2) + 3; + + indices[iIndex++] = i + 1; + indices[iIndex++] = i + (RingSections * 2) + 3; + indices[iIndex++] = i + 3; + + // OUTTER + indices[iIndex++] = i; + indices[iIndex++] = i + (RingSections * 2) + 2; + indices[iIndex++] = i + 2; + + indices[iIndex++] = i; + indices[iIndex++] = i + (RingSections * 2); + indices[iIndex++] = i + (RingSections * 2) + 2; + } + + // Last Side Faces + // TOP + indices[iIndex++] = ((RingSections - 1) * 2); + indices[iIndex++] = ((RingSections - 1) * 2) + 1; + indices[iIndex++] = 1; + + indices[iIndex++] = ((RingSections - 1) * 2); + indices[iIndex++] = 1; + indices[iIndex++] = 0; + + // BOTTOM + indices[iIndex++] = ((RingSections - 1) * 2) + (RingSections * 2); + indices[iIndex++] = ((RingSections - 1) * 2) + (RingSections * 2) + 1; + indices[iIndex++] = (RingSections * 2) + 1; + + indices[iIndex++] = ((RingSections - 1) * 2) + (RingSections * 2); + indices[iIndex++] = (RingSections * 2) + 1; + indices[iIndex++] = (RingSections * 2); + + // INNER + indices[iIndex++] = ((RingSections - 1) * 2) + 1; + indices[iIndex++] = ((RingSections - 1) * 2) + (RingSections * 2) + 1; + indices[iIndex++] = (RingSections * 2) + 1; + + indices[iIndex++] = ((RingSections - 1) * 2) + 1; + indices[iIndex++] = (RingSections * 2) + 1; + indices[iIndex++] = 1; + + // OUTTER + indices[iIndex++] = ((RingSections - 1) * 2); + indices[iIndex++] = (RingSections * 2); + indices[iIndex++] = 0; + + indices[iIndex++] = ((RingSections - 1) * 2); + indices[iIndex++] = ((RingSections - 1) * 2) + (RingSections * 2); + indices[iIndex++] = (RingSections * 2) + 0; + + ringPrimitive.ib = renderDevice->createIndexBuffer(sizeof(indices), indices, IndexFormat::UInt, Usage::Static); +} diff --git a/engine/src/cubos/engine/gizmos/renderer.hpp b/engine/src/cubos/engine/gizmos/renderer.hpp index 82c26aca88..139559b0fe 100644 --- a/engine/src/cubos/engine/gizmos/renderer.hpp +++ b/engine/src/cubos/engine/gizmos/renderer.hpp @@ -11,6 +11,7 @@ namespace cubos::engine { public: static constexpr int CutConeVertsPerBase = 16; ///< Number of vertexes in each face of a cut cone gizmo. + static constexpr int RingSections = 32; ///< Number of traversal sections (i.e. quads) in a ring gizmo. cubos::core::gl::ShaderPipeline drawPipeline; ///< Shader pipeline to be used when drawing gizmos. cubos::core::gl::ShaderPipeline idPipeline; ///< Shader pipeline to be used when drawing gizmos. @@ -28,6 +29,7 @@ namespace cubos::engine Primitive linePrimitive; ///< GL line information. Primitive boxPrimitive; ///< GL box information. Primitive cutConePrimitive; ///< GL cut cone information. + Primitive ringPrimitive; ///< GL ring information. glm::ivec2 textureSize; ///< Size of the id texture. cubos::core::gl::Texture2D idTexture; ///< Texture holding the ids of the gizmo that was drawn to each pixel. @@ -58,5 +60,6 @@ namespace cubos::engine void initLinePrimitive(); void initBoxPrimitive(); void initCutConePrimitive(); + void initRingPrimitive(); }; } // namespace cubos::engine diff --git a/engine/src/cubos/engine/gizmos/types/ring.hpp b/engine/src/cubos/engine/gizmos/types/ring.hpp new file mode 100644 index 0000000000..3caaa5ba13 --- /dev/null +++ b/engine/src/cubos/engine/gizmos/types/ring.hpp @@ -0,0 +1,111 @@ +#pragma once + +#include +#include + +#include + +#include "../renderer.hpp" + +namespace cubos::engine +{ + /// @brief A gizmo that is a ring. + class RingGizmo : public Gizmos::Gizmo + { + glm::vec3 mPointA; + glm::vec3 mPointB; + float mRadiusOuter; + float mRadiusInner; + + public: + /// @brief Constructs. + /// @param id Identifier of the gizmo. + /// @param firstBasePosition Center of one of the bases. + /// @param secondBasePosition Center of the second base. + /// @param outerRadius Radius of one of the ring. + /// @param innerRadius Radius of the of the hole. + /// @param color Color for the gizmo to be drawn in. + /// @param lifespan Time the gizmo will remain on screen, in seconds. + RingGizmo(uint32_t id, glm::vec3 firstBasePosition, glm::vec3 secondBasePosition, float outerRadius, + float innerRadius, const glm::vec3& color, float lifespan) + : Gizmos::Gizmo(id, color, lifespan) + , mPointA(firstBasePosition) + , mPointB(secondBasePosition) + , mRadiusOuter(outerRadius) + , mRadiusInner(innerRadius) + { + } + + /// @brief Draws the gizmo to screen. + /// @param renderer GizmosRenderer in use. + /// @param phase Current draw phase. + /// @param mvp Matrix containing projection and viewpoint transformations. + void draw(GizmosRenderer& renderer, DrawPhase phase, + const glm::mat<4, 4, float, glm::packed_highp>& mvp) override + { + auto* verts = static_cast(renderer.ringPrimitive.vb->map()); + + glm::vec3 n = glm::normalize(mPointB - mPointA); + glm::vec3 p; + if (n[0] != n[1]) + { + p = {n[1], -n[0], n[2]}; + } + else if (n[0] != n[2]) + { + p = {-n[2], n[1], n[0]}; + } + else + { + p = {n[0], -n[2], n[1]}; + } + + glm::vec3 pA = p * mRadiusOuter; + glm::vec3 pB = p * mRadiusInner; + + for (std::size_t i = 0; i < GizmosRenderer::RingSections; i++) + { + glm::vec3 vertOuter = + glm::rotate(pA, (float)i * glm::radians(360.0F / (float)GizmosRenderer::RingSections), n) + mPointA; + glm::vec3 vertInner = + glm::rotate(pB, (float)i * glm::radians(360.0F / (float)GizmosRenderer::RingSections), n) + mPointA; + verts[2 * i] = {vertOuter[0], vertOuter[1], vertOuter[2]}; + verts[(2 * i) + 1] = {vertInner[0], vertInner[1], vertInner[2]}; + } + + for (std::size_t i = 0; i < GizmosRenderer::RingSections; i++) + { + glm::vec3 vertOuter = + glm::rotate(pA, (float)i * glm::radians(360.0F / (float)GizmosRenderer::RingSections), n) + mPointB; + glm::vec3 vertInner = + glm::rotate(pB, (float)i * glm::radians(360.0F / (float)GizmosRenderer::RingSections), n) + mPointB; + verts[GizmosRenderer::RingSections * 2 + 2 * i] = {vertOuter[0], vertOuter[1], vertOuter[2]}; + verts[GizmosRenderer::RingSections * 2 + (2 * i) + 1] = {vertInner[0], vertInner[1], vertInner[2]}; + } + + renderer.ringPrimitive.vb->unmap(); + + renderer.renderDevice->setVertexArray(renderer.ringPrimitive.va); + renderer.renderDevice->setIndexBuffer(renderer.ringPrimitive.ib); + + auto mvpBuffer = + renderer.renderDevice->createConstantBuffer(sizeof(glm::mat4), &mvp, cubos::core::gl::Usage::Static); + + if (phase == DrawPhase::Color) + { + renderer.drawPipeline->getBindingPoint("MVP")->bind(mvpBuffer); + + renderer.drawPipeline->getBindingPoint("objColor")->setConstant(mColor); + } + else + { + renderer.idPipeline->getBindingPoint("MVP")->bind(mvpBuffer); + } + + renderer.renderDevice->setRasterState( + renderer.renderDevice->createRasterState(cubos::core::gl::RasterStateDesc{})); + renderer.renderDevice->drawTrianglesIndexed(0, + 24 * (std::size_t)cubos::engine::GizmosRenderer::RingSections); + } + }; +} // namespace cubos::engine