Skip to content

Commit

Permalink
Merge pull request #28 from LimpingPebble/feat/debug-shape
Browse files Browse the repository at this point in the history
Feat/debug shape
  • Loading branch information
amasson42 authored Oct 20, 2024
2 parents a7d7c55 + 6646b2e commit 546197d
Show file tree
Hide file tree
Showing 9 changed files with 416 additions and 20 deletions.
4 changes: 2 additions & 2 deletions Engine/Core/include/Core/Assets/Bundle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ class Bundle : public Object {
const std::string &reducedPath = reducePath(filepath);
auto it = _resources.find(reducedPath);
if (it != _resources.end()) {
return std::dynamic_pointer_cast<ResourceType>(it->second);
return std::static_pointer_cast<ResourceType>(it->second);
}
auto thisBundle = std::dynamic_pointer_cast<Bundle>(shared_from_this());
auto thisBundle = std::static_pointer_cast<Bundle>(shared_from_this());
auto resource = std::make_shared<ResourceType>(thisBundle, reducedPath, std::forward<Args>(args)...);
_resources[reducedPath] = resource;
return resource;
Expand Down
2 changes: 1 addition & 1 deletion Engine/Core/src/Core/Image/ImageSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Size ImageSource::getSize() const {
void ImageSource::loadData(bool force) {
if (force || _loadedImage == nullptr) {
_loadedImage = std::make_shared<ImageData>(getFullPath(), _channels);
_loadedImage->_source = std::dynamic_pointer_cast<ImageSource>(shared_from_this());
_loadedImage->_source = std::static_pointer_cast<ImageSource>(shared_from_this());
_channels = _loadedImage->getChannels();
_size = _loadedImage->getSize();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
namespace Stone::Render::Vulkan {

void VulkanRenderer::updateDataForWorld(const std::shared_ptr<Scene::WorldNode> &world) {
RendererObjectManager manager(std::dynamic_pointer_cast<VulkanRenderer>(shared_from_this()));
RendererObjectManager manager(std::static_pointer_cast<VulkanRenderer>(shared_from_this()));
world->traverseTopDown([&manager](const std::shared_ptr<Scene::Node> &node) {
auto renderElement = std::dynamic_pointer_cast<Scene::IRenderable>(node);
if (renderElement && renderElement->isDirty()) {
Expand Down
68 changes: 64 additions & 4 deletions Engine/Scene/include/Scene/Geometry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,83 @@
#pragma once

#include <glm/glm.hpp>
#include <vector>

namespace Stone::Scene {

struct Plane {
glm::vec3 normal;
float distance;
glm::vec3 normal = glm::vec3(0.0f, 1.0f, 0.0f);
float distance = 0.0f;

Plane() = default;

Plane(const glm::vec3 &n, float d) : normal(n), distance(d) {
}
};

struct Sphere {
glm::vec3 center;
float radius;
glm::vec3 center = glm::vec3(0.0f);
float radius = 1.0f;

Sphere() = default;

Sphere(const glm::vec3 &c, float r) : center(c), radius(r) {
}
};

struct Box {
glm::vec3 min = glm::vec3(-0.5f);
glm::vec3 max = glm::vec3(0.5f);

Box() = default;

Box(const glm::vec3 &min, const glm::vec3 &max) : min(min), max(max) {
}
};

struct Line {
glm::vec3 origin = glm::vec3(0.0f);
glm::vec3 direction = glm::vec3(0.0f, 0.0f, 1.0f);

Line() = default;

Line(const glm::vec3 &o, const glm::vec3 &d) : origin(o), direction(d) {
}
};

struct Cone {
glm::vec3 origin = glm::vec3(0.0f);
glm::vec3 direction = glm::vec3(0.0f, 0.0f, 1.0f);
float angle = M_PI_4;
float length = 1.0f;

Cone() = default;

Cone(const glm::vec3 &o, const glm::vec3 &d, float a, float l) : origin(o), direction(d), angle(a), length(l) {
}
};

struct Frustum {
Plane planes[6] = {Plane(), Plane(), Plane(), Plane(), Plane(), Plane()};

Frustum() = default;

Frustum(const Plane &p0, const Plane &p1, const Plane &p2, const Plane &p3, const Plane &p4, const Plane &p5) {
planes[0] = p0;
planes[1] = p1;
planes[2] = p2;
planes[3] = p3;
planes[4] = p4;
planes[5] = p5;
}
};

std::pair<std::vector<uint32_t>, std::vector<glm::vec3>> generateGeometryMesh(const Plane &plane, float size = 1.0f);
std::pair<std::vector<uint32_t>, std::vector<glm::vec3>> generateGeometryMesh(const Sphere &sphere, int rings = 16);
std::pair<std::vector<uint32_t>, std::vector<glm::vec3>> generateGeometryMesh(const Box &box);
std::pair<std::vector<uint32_t>, std::vector<glm::vec3>> generateGeometryMesh(const Line &line);
std::pair<std::vector<uint32_t>, std::vector<glm::vec3>> generateGeometryMesh(const Cone &cone, int segments = 16);
std::pair<std::vector<uint32_t>, std::vector<glm::vec3>> generateGeometryMesh(const Frustum &frustum);


} // namespace Stone::Scene
134 changes: 134 additions & 0 deletions Engine/Scene/include/Scene/Node/WireframeShape.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// Copyright 2024 Stone-Engine

#pragma once

#include "Scene/Geometry.hpp"
#include "Scene/Node/RenderableNode.hpp"

namespace Stone::Scene {

/**
* @class WireframeShape
* @brief Represents a wireframe shape that can be rendered in a scene.
*
* The WireframeShape class is a subclass of RenderableNode and provides functionality for creating and manipulating
* wireframe shapes. Wireframe shapes are represented by a collection of vertices and can be rendered as lines or dots.
* The color, line thickness, and lifespan of the wireframe shape can be customized.
*/
class WireframeShape : public RenderableNode {
STONE_NODE(WireframeShape);

public:
/**
* @brief Constructs a WireframeShape object.
*
* @param name The name of the WireframeShape (optional).
*/
explicit WireframeShape(const std::string &name = "debug_shape");
/**
* @brief Constructs a new WireframeShape by copying another WireframeShape object.
*
* @param other The WireframeShape object to be copied.
*/
WireframeShape(const WireframeShape &other) = default;

/**
* @brief Destructor for the WireframeShape class.
*/
~WireframeShape() override = default;

/**
* Writes the wireframe shape to the output stream.
*
* @param stream The output stream to write to.
* @param closing_bracer Flag indicating whether to write a closing bracer.
* @return The output stream after writing the wireframe shape.
*/
std::ostream &writeToStream(std::ostream &stream, bool closing_bracer) const override;

/**
* @brief Retrieves the color
*
* @return The color of the wireframe shape as a glm::vec3.
*/
[[nodiscard]] glm::vec3 getColor() const;
/**
* Sets the color of the wireframe shape.
*
* @param color The color to set, specified as a glm::vec3.
*/
void setColor(const glm::vec3 &color);

/**
* @brief Retrieves the thickness of the wireframe shape.
*
* @return The thickness of the wireframe shape.
*/
[[nodiscard]] float getThickness() const;
/**
* @brief Sets the thickness of the wireframe shape.
*
* @param thickness The thickness of the wireframe shape.
*/
void setThickness(float thickness);

/**
* @brief Retrieves the points of the wireframe shape.
*
* @return A constant reference to a vector of vectors of glm::vec3 representing the points of the wireframe shape.
*/
[[nodiscard]] const std::vector<std::vector<glm::vec3>> &getPoints() const;
/**
* @brief Returns a reference to the vector of vector of glm::vec3 points.
*
* @return std::vector<std::vector<glm::vec3>>& A reference to the vector of vector of glm::vec3 points.
*/
std::vector<std::vector<glm::vec3>> &pointsRef();

/**
* @brief Checks if the wireframe shape should be drawn as a line.
*
* @return true if the wireframe shape should be drawn as a line, false otherwise.
*/
[[nodiscard]] bool isDrawLine() const;
/**
* @brief Sets whether to draw the wireframe shape as a line.
*
* @param drawLine True to draw the wireframe shape as a line, false otherwise.
*/
void setDrawLine(bool drawLine);

/**
* @brief Creates a new instance of WireframeShape with the specified shape and arguments.
*
* @tparam ShapeType The type of shape to generate.
* @tparam Args The types of arguments to pass to the shape generator.
* @param shape The shape to generate.
* @param args The arguments to pass to the shape generator.
* @return A shared pointer to the newly created WireframeShape.
*/
template <typename ShapeType, typename... Args>
static std::shared_ptr<WireframeShape> create(const ShapeType &shape, Args &&...args) {
auto wireframeShape = std::make_shared<WireframeShape>();

auto [indices, vertices] = generateGeometryMesh(shape, std::forward<Args>(args)...);

auto &points = wireframeShape->pointsRef().emplace_back();
points.reserve(indices.size());
for (auto &index : indices) {
points.push_back(vertices[index]);
}

return wireframeShape;
}

protected:
glm::vec3 _color; /** The color of the debug shape. */
float _thickness; /** The line thickness of the debug shape. */

std::vector<std::vector<glm::vec3>> _points; /** The vertices of the debug shape. */

bool _drawLine; /** Whether to draw the debug shape as a line or as dots. */
};

} // namespace Stone::Scene
138 changes: 138 additions & 0 deletions Engine/Scene/src/Scene/Geometry.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// Copyright 2024 Stone-Engine

#include "Scene/Geometry.hpp"

namespace Stone::Scene {

std::pair<std::vector<uint32_t>, std::vector<glm::vec3>> generateGeometryMesh(const Plane &plane, float size) {
std::vector<uint32_t> indices = {0, 1, 2, 0, 2, 3};
std::vector<glm::vec3> vertices = {
plane.normal * size + glm::vec3(0.0f, 0.0f, plane.distance),
plane.normal * size + glm::vec3(size, 0.0f, plane.distance),
plane.normal * size + glm::vec3(size, size, plane.distance),
plane.normal * size + glm::vec3(0.0f, size, plane.distance),
};
return {indices, vertices};
}

std::pair<std::vector<uint32_t>, std::vector<glm::vec3>> generateGeometryMesh(const Sphere &sphere, int rings) {
std::vector<uint32_t> indices;
std::vector<glm::vec3> vertices;

const float phiStep = M_PIf32 / (float)rings;
const float thetaStep = 2 * M_PIf32 / (float)rings;

for (int i = 0; i <= rings; i++) {
const float phi = (float)i * phiStep;
for (int j = 0; j <= rings; j++) {
const float theta = (float)j * thetaStep;

const float x = sphere.radius * std::sin(phi) * std::cos(theta);
const float y = sphere.radius * std::cos(phi);
const float z = sphere.radius * std::sin(phi) * std::sin(theta);

vertices.push_back(sphere.center + glm::vec3(x, y, z));
}
}

for (int i = 0; i < rings; i++) {
for (int j = 0; j < rings; j++) {
const int i0 = i * (rings + 1) + j;
const int i1 = i0 + 1;
const int i2 = i0 + rings + 1;
const int i3 = i2 + 1;

indices.push_back(i0);
indices.push_back(i1);
indices.push_back(i2);

indices.push_back(i2);
indices.push_back(i1);
indices.push_back(i3);
}
}

return {indices, vertices};
}

std::pair<std::vector<uint32_t>, std::vector<glm::vec3>> generateGeometryMesh(const Box &box) {
std::vector<uint32_t> indices = {
0, 1, 2, 2, 3, 0, // Front
4, 5, 6, 6, 7, 4, // Back
0, 4, 7, 7, 3, 0, // Left
1, 5, 6, 6, 2, 1, // Right
0, 1, 5, 5, 4, 0, // Top
3, 2, 6, 6, 7, 3, // Bottom
};
std::vector<glm::vec3> vertices = {
box.min,
glm::vec3(box.max.x, box.min.y, box.min.z),
glm::vec3(box.max.x, box.max.y, box.min.z),
glm::vec3(box.min.x, box.max.y, box.min.z),
glm::vec3(box.min.x, box.min.y, box.max.z),
glm::vec3(box.max.x, box.min.y, box.max.z),
box.max,
glm::vec3(box.min.x, box.max.y, box.max.z),
};
return {indices, vertices};
}

std::pair<std::vector<uint32_t>, std::vector<glm::vec3>> generateGeometryMesh(const Line &line) {
std::vector<uint32_t> indices = {0, 1};
std::vector<glm::vec3> vertices = {line.origin, line.origin + line.direction};
return {indices, vertices};
}

std::pair<std::vector<uint32_t>, std::vector<glm::vec3>> generateGeometryMesh(const Cone &cone, int segments) {
std::vector<uint32_t> indices;
std::vector<glm::vec3> vertices;

const float angleStep = cone.angle / (float)segments;
const float halfLength = cone.length / 2.0f;

for (int i = 0; i <= segments; i++) {
const float angle = (float)i * angleStep;
const float x = cone.length * std::cos(angle);
const float y = cone.length * std::sin(angle);

vertices.push_back(cone.origin + glm::vec3(x, y, -halfLength));
vertices.push_back(cone.origin + glm::vec3(x, y, halfLength));
}

for (int i = 0; i < segments; i++) {
const int i0 = i * 2;
const int i1 = i0 + 1;
const int i2 = i0 + 2;
const int i3 = i2 + 1;

indices.push_back(i0);
indices.push_back(i1);
indices.push_back(i2);

indices.push_back(i2);
indices.push_back(i1);
indices.push_back(i3);
}

return {indices, vertices};
}

std::pair<std::vector<uint32_t>, std::vector<glm::vec3>> generateGeometryMesh(const Frustum &frustum) {
std::vector<uint32_t> indices;
std::vector<glm::vec3> vertices;

for (auto plane : frustum.planes) {
auto [planeIndices, planeVertices] = generateGeometryMesh(plane, 1.0f);
const auto offset = static_cast<uint32_t>(vertices.size());
for (const auto &index : planeIndices) {
indices.push_back(index + offset);
}
for (const auto &vertex : planeVertices) {
vertices.push_back(vertex);
}
}

return {indices, vertices};
}

} // namespace Stone::Scene
Loading

0 comments on commit 546197d

Please sign in to comment.