From 4ed1f1a6fe98da9aca55b8544da7305d81980724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= <49535803+damacaa@users.noreply.github.com> Date: Fri, 20 Jun 2025 18:48:31 +0200 Subject: [PATCH 1/9] [WIP] Testing combination idea --- include/weird-engine/Scene.h | 6 +- src/weird-engine/Scene.cpp | 70 +++++++++++-------- src/weird-physics/Simulation2D.cpp | 12 +++- src/weird-renderer/shaders/raymarching2d.frag | 4 +- 4 files changed, 55 insertions(+), 37 deletions(-) diff --git a/include/weird-engine/Scene.h b/include/weird-engine/Scene.h index 0a33040..ff7e90c 100644 --- a/include/weird-engine/Scene.h +++ b/include/weird-engine/Scene.h @@ -27,10 +27,10 @@ namespace WeirdEngine void get2DShapesData(WeirdRenderer::Dot2D*& data, uint32_t& size); - Scene(const Scene&) = default; // Deleted copy constructor + Scene(const Scene&) = default; // Deleted copy constructor Scene& operator=(const Scene&) = default; // Deleted copy assignment operator - Scene(Scene&&) = default; // Defaulted move constructor - Scene& operator=(Scene&&) = default; // Defaulted move assignment operator + Scene(Scene&&) = default; // Defaulted move constructor + Scene& operator=(Scene&&) = default; // Defaulted move assignment operator WeirdRenderer::Camera& getCamera(); std::vector& getLigths(); diff --git a/src/weird-engine/Scene.cpp b/src/weird-engine/Scene.cpp index 3f75385..89b80f1 100644 --- a/src/weird-engine/Scene.cpp +++ b/src/weird-engine/Scene.cpp @@ -13,7 +13,7 @@ namespace WeirdEngine void Scene::handleCollision(CollisionEvent &event, void *userData) { // Unsafe cast! Prone to error. - Scene* self = static_cast(userData); + Scene *self = static_cast(userData); self->onCollision(event); } @@ -21,7 +21,7 @@ namespace WeirdEngine vec3 g_cameraPosition(0, 1, 20); Scene::Scene() - : m_simulation2D(MAX_ENTITIES), m_sdfRenderSystem(m_ecs), m_sdfRenderSystem2D(m_ecs), m_renderSystem(m_ecs), m_instancedRenderSystem(m_ecs), m_rbPhysicsSystem2D(m_ecs), m_physicsInteractionSystem(m_ecs), m_playerMovementSystem(m_ecs), m_cameraSystem(m_ecs), m_runSimulationInThread(true) + : m_simulation2D(MAX_ENTITIES), m_sdfRenderSystem(m_ecs), m_sdfRenderSystem2D(m_ecs), m_renderSystem(m_ecs), m_instancedRenderSystem(m_ecs), m_rbPhysicsSystem2D(m_ecs), m_physicsInteractionSystem(m_ecs), m_playerMovementSystem(m_ecs), m_cameraSystem(m_ecs), m_runSimulationInThread(true) { // Custom component managers @@ -67,12 +67,12 @@ namespace WeirdEngine case WeirdEngine::Scene::RenderMode::RayMarching3D: case WeirdEngine::Scene::RenderMode::RayMarchingBoth: { - FlyMovement& fly = m_ecs.addComponent(m_mainCamera); + FlyMovement &fly = m_ecs.addComponent(m_mainCamera); break; } case WeirdEngine::Scene::RenderMode::RayMarching2D: { - FlyMovement2D& fly = m_ecs.addComponent(m_mainCamera); + FlyMovement2D &fly = m_ecs.addComponent(m_mainCamera); // fly.targetPosition = g_cameraPosition; break; } @@ -83,9 +83,9 @@ namespace WeirdEngine } // TODO: pass render target instead of shader. Shaders should be accessed in a different way, through the resource manager - void Scene::renderModels(WeirdRenderer::RenderTarget& renderTarget, WeirdRenderer::Shader& shader, WeirdRenderer::Shader& instancingShader) + void Scene::renderModels(WeirdRenderer::RenderTarget &renderTarget, WeirdRenderer::Shader &shader, WeirdRenderer::Shader &instancingShader) { - WeirdRenderer::Camera& camera = m_ecs.getComponent(m_mainCamera).camera; + WeirdRenderer::Camera &camera = m_ecs.getComponent(m_mainCamera).camera; m_renderSystem.render(m_ecs, m_resourceManager, shader, camera, m_lights); onRender(renderTarget); @@ -93,7 +93,7 @@ namespace WeirdEngine // m_instancedRenderSystem.render(m_ecs, m_resourceManager, instancingShader, camera, m_lights); } - void replaceSubstring(std::string& str, const std::string& from, const std::string& to) + void replaceSubstring(std::string &str, const std::string &from, const std::string &to) { size_t start_pos = str.find(from); if (start_pos != std::string::npos) @@ -102,7 +102,7 @@ namespace WeirdEngine } } - void Scene::updateCustomShapesShader(WeirdRenderer::Shader& shader) + void Scene::updateCustomShapesShader(WeirdRenderer::Shader &shader) { if (!m_sdfRenderSystem2D.shaderNeedsUpdate()) { @@ -124,7 +124,7 @@ namespace WeirdEngine for (size_t i = 0; i < componentArray->getSize(); i++) { - auto& shape = componentArray->getDataAtIdx(i); + auto &shape = componentArray->getDataAtIdx(i); oss << "{"; @@ -151,11 +151,19 @@ namespace WeirdEngine oss << "dist = dist > 0 ? dist : 0.1 * dist;" << std::endl; - oss << "d = min(d, dist);\n"; + if (i == componentArray->getSize() - 1) + { + oss << "d = max(d, -dist);\n"; + } + else + { + oss << "d = min(d, dist);\n"; + } + // oss << "col = d == (dist) ? getMaterial(p," << (i % 12) + 4 << ") : col;\n"; oss << "col = d == (dist) ? getMaterial(p," << 3 << ") : col;\n"; oss << "}\n" - << std::endl; + << std::endl; } std::string replacement = oss.str(); @@ -170,14 +178,14 @@ namespace WeirdEngine shader.setFragmentCode(str); } - void Scene::updateRayMarchingShader(WeirdRenderer::Shader& shader) + void Scene::updateRayMarchingShader(WeirdRenderer::Shader &shader) { m_sdfRenderSystem2D.updatePalette(shader); updateCustomShapesShader(shader); } - void Scene::get2DShapesData(WeirdRenderer::Dot2D*& data, uint32_t& size) + void Scene::get2DShapesData(WeirdRenderer::Dot2D *&data, uint32_t &size) { m_sdfRenderSystem2D.fillDataBuffer(data, size); } @@ -207,12 +215,12 @@ namespace WeirdEngine m_ecs.freeRemovedComponents(); } - WeirdRenderer::Camera& Scene::getCamera() + WeirdRenderer::Camera &Scene::getCamera() { return m_ecs.getComponent(m_mainCamera).camera; } - std::vector& Scene::getLigths() + std::vector &Scene::getLigths() { return m_lights; } @@ -222,7 +230,7 @@ namespace WeirdEngine return m_simulation2D.getSimulationTime(); } - void Scene::fillShapeDataBuffer(WeirdRenderer::Dot2D*& data, uint32_t& size) + void Scene::fillShapeDataBuffer(WeirdRenderer::Dot2D *&data, uint32_t &size) { m_sdfRenderSystem2D.fillDataBuffer(data, size); } @@ -232,10 +240,10 @@ namespace WeirdEngine return m_renderMode; } - Entity Scene::addShape(int shapeId, float* variables) + Entity Scene::addShape(int shapeId, float *variables) { Entity entity = m_ecs.createEntity(); - CustomShape& shape = m_ecs.addComponent(entity); + CustomShape &shape = m_ecs.addComponent(entity); shape.m_distanceFieldId = shapeId; std::copy(variables, variables + 8, shape.m_parameters); @@ -244,10 +252,10 @@ namespace WeirdEngine return entity; } - Entity Scene::addScreenSpaceShape(int shapeId, float* variables) + Entity Scene::addScreenSpaceShape(int shapeId, float *variables) { Entity entity = m_ecs.createEntity(); - CustomShape& shape = m_ecs.addComponent(entity); + CustomShape &shape = m_ecs.addComponent(entity); shape.m_screenSpace = true; shape.m_distanceFieldId = shapeId; std::copy(variables, variables + 8, shape.m_parameters); @@ -259,15 +267,15 @@ namespace WeirdEngine void Scene::lookAt(Entity entity) { - FlyMovement2D& fly = m_ecs.getComponent(m_mainCamera); - Transform& target = m_ecs.getComponent(entity); + FlyMovement2D &fly = m_ecs.getComponent(m_mainCamera); + Transform &target = m_ecs.getComponent(entity); float oldZ = fly.targetPosition.z; fly.targetPosition = target.position; fly.targetPosition.z = oldZ; }; - void Scene::loadScene(std::string& sceneFileContent) + void Scene::loadScene(std::string &sceneFileContent) { // json scene = json::parse(sceneFileContent); @@ -279,11 +287,11 @@ namespace WeirdEngine // Create camera object m_mainCamera = m_ecs.createEntity(); - Transform& t = m_ecs.addComponent(m_mainCamera); + Transform &t = m_ecs.addComponent(m_mainCamera); t.position = g_cameraPosition; t.rotation = vec3(0, 0, -1.0f); - ECS::Camera& c = m_ecs.addComponent(m_mainCamera); + ECS::Camera &c = m_ecs.addComponent(m_mainCamera); // Add a light WeirdRenderer::Light light; @@ -418,7 +426,7 @@ namespace WeirdEngine constexpr int INVALID_INDEX = -1; - void Scene::print(const std::string& text) + void Scene::print(const std::string &text) { float offset = 0; for (auto i : text) @@ -433,10 +441,10 @@ namespace WeirdEngine float y = vec2.y; Entity entity = m_ecs.createEntity(); - Transform& t = m_ecs.addComponent(entity); + Transform &t = m_ecs.addComponent(entity); t.position = vec3(x, y, -10.0f); - SDFRenderer& sdfRenderer = m_ecs.addComponent(entity); + SDFRenderer &sdfRenderer = m_ecs.addComponent(entity); sdfRenderer.materialId = 4 + idx % 12; } @@ -444,10 +452,10 @@ namespace WeirdEngine } } - void Scene::loadFont(const char* imagePath, int charWidth, int charHeight, const char* characters) + void Scene::loadFont(const char *imagePath, int charWidth, int charHeight, const char *characters) { // Set all to INVALID_INDEX initially - for (int& val : m_CharLookUpTable) + for (int &val : m_CharLookUpTable) { val = INVALID_INDEX; } @@ -464,7 +472,7 @@ namespace WeirdEngine // Load the image int width, height, channels; - unsigned char* img = wstbi_load(imagePath, &width, &height, &channels, 0); + unsigned char *img = wstbi_load(imagePath, &width, &height, &channels, 0); if (img == nullptr) { diff --git a/src/weird-physics/Simulation2D.cpp b/src/weird-physics/Simulation2D.cpp index 179d399..45184e5 100644 --- a/src/weird-physics/Simulation2D.cpp +++ b/src/weird-physics/Simulation2D.cpp @@ -337,8 +337,9 @@ namespace WeirdEngine { float d = 1.0f; - for (DistanceFieldObject2D& obj : m_objects) + for (int i = 0; i < m_objects.size(); i++) { + DistanceFieldObject2D& obj = m_objects[i]; if (obj.distanceFieldId >= m_sdfs->size()) { continue; @@ -352,7 +353,14 @@ namespace WeirdEngine float dist = (*m_sdfs)[obj.distanceFieldId]->getValue(); - d = std::min(d, dist); + if (i == m_objects.size() - 1) // Last object + { + d = std::max(d, -dist); + } + else + { + d = std::min(d, dist); + } } return d; diff --git a/src/weird-renderer/shaders/raymarching2d.frag b/src/weird-renderer/shaders/raymarching2d.frag index 273ab75..cf39efc 100644 --- a/src/weird-renderer/shaders/raymarching2d.frag +++ b/src/weird-renderer/shaders/raymarching2d.frag @@ -152,6 +152,8 @@ vec4 getColor(vec2 p, vec2 uv) bool bestIsScreenSpace = false; + /*ADD_SHAPES_HERE*/ + for (int i = 0; i < u_loadedObjects - (2 * u_customShapeCount); i++) { vec4 positionSizeMaterial = texelFetch(t_shapeBuffer, i); @@ -193,7 +195,7 @@ vec4 getColor(vec2 p, vec2 uv) if(bestIsScreenSpace) return vec4(col, d); - /*ADD_SHAPES_HERE*/ + // Repetition // float scale = 1.0 / 10.0; From 9f10c6d111b63969f02298f73a2d9d3087259fe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= <49535803+damacaa@users.noreply.github.com> Date: Fri, 20 Jun 2025 19:20:46 +0200 Subject: [PATCH 2/9] [WIP] Working implementation of combination selection --- include/weird-engine/Scene.h | 2 +- .../weird-engine/ecs/Components/CustomShape.h | 1 + include/weird-physics/Simulation2D.h | 3 ++- src/weird-engine/Scene.cpp | 16 ++++++++++----- src/weird-physics/Simulation2D.cpp | 20 +++++++++++++------ 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/include/weird-engine/Scene.h b/include/weird-engine/Scene.h index ff7e90c..c31efb2 100644 --- a/include/weird-engine/Scene.h +++ b/include/weird-engine/Scene.h @@ -64,7 +64,7 @@ namespace WeirdEngine std::vector> m_sdfs; - Entity addShape(int shapeId, float* variables); + Entity addShape(int shapeId, float* variables, int combination = 0); Entity addScreenSpaceShape(int shapeId, float* variables); void lookAt(Entity entity); diff --git a/include/weird-engine/ecs/Components/CustomShape.h b/include/weird-engine/ecs/Components/CustomShape.h index 2c86495..86a4f87 100644 --- a/include/weird-engine/ecs/Components/CustomShape.h +++ b/include/weird-engine/ecs/Components/CustomShape.h @@ -9,6 +9,7 @@ namespace WeirdEngine public: uint16_t m_distanceFieldId; + uint16_t m_combinationdId; float m_parameters[8]; bool m_isDirty; bool m_screenSpace; diff --git a/include/weird-physics/Simulation2D.h b/include/weird-physics/Simulation2D.h index 879f91e..4a67167 100644 --- a/include/weird-physics/Simulation2D.h +++ b/include/weird-physics/Simulation2D.h @@ -256,9 +256,10 @@ namespace WeirdEngine { Entity owner; uint16_t distanceFieldId; + uint16_t combinationId; float parameters[11]; - DistanceFieldObject2D(Entity owner, uint16_t id, float* params) : distanceFieldId(id), owner(owner) + DistanceFieldObject2D(Entity owner, uint16_t id, uint16_t combinationId, float* params) : distanceFieldId(id), combinationId(combinationId), owner(owner) { std::copy(params, params + 8, parameters); // Copy params into parameters } diff --git a/src/weird-engine/Scene.cpp b/src/weird-engine/Scene.cpp index 89b80f1..0d1ce94 100644 --- a/src/weird-engine/Scene.cpp +++ b/src/weird-engine/Scene.cpp @@ -151,13 +151,18 @@ namespace WeirdEngine oss << "dist = dist > 0 ? dist : 0.1 * dist;" << std::endl; - if (i == componentArray->getSize() - 1) + switch (shape.m_combinationdId) { + case 0: { + oss << "d = min(d, dist);\n"; + break; + } + case 1: { oss << "d = max(d, -dist);\n"; + break; } - else - { - oss << "d = min(d, dist);\n"; + default: + break; } // oss << "col = d == (dist) ? getMaterial(p," << (i % 12) + 4 << ") : col;\n"; @@ -240,11 +245,12 @@ namespace WeirdEngine return m_renderMode; } - Entity Scene::addShape(int shapeId, float *variables) + Entity Scene::addShape(int shapeId, float* variables, int combination) { Entity entity = m_ecs.createEntity(); CustomShape &shape = m_ecs.addComponent(entity); shape.m_distanceFieldId = shapeId; + shape.m_combinationdId = combination; std::copy(variables, variables + 8, shape.m_parameters); // CustomShape shape(shapeId, variables); // check old constructor for references diff --git a/src/weird-physics/Simulation2D.cpp b/src/weird-physics/Simulation2D.cpp index 45184e5..734e5ff 100644 --- a/src/weird-physics/Simulation2D.cpp +++ b/src/weird-physics/Simulation2D.cpp @@ -336,6 +336,7 @@ namespace WeirdEngine float Simulation2D::map(vec2 p) { float d = 1.0f; + float distances[2]; for (int i = 0; i < m_objects.size(); i++) { @@ -349,17 +350,24 @@ namespace WeirdEngine obj.parameters[9] = p.x; obj.parameters[10] = p.y; + // Distance (*m_sdfs)[obj.distanceFieldId]->propagateValues(obj.parameters); float dist = (*m_sdfs)[obj.distanceFieldId]->getValue(); - if (i == m_objects.size() - 1) // Last object + // Combination + switch (obj.combinationId) { + case 0: { + d = std::min(d, dist); + break; + } + case 1: { d = std::max(d, -dist); + break; } - else - { - d = std::min(d, dist); + default: + break; } } @@ -460,7 +468,7 @@ namespace WeirdEngine m_forces[col.B] += m_mass[col.B] * penalty; // Notify collision callback - if (m_collisionCallback) + if (m_collisionCallback) { CollisionEvent event{ col.A, col.B }; m_collisionCallback(event, m_callbackUserData); @@ -817,7 +825,7 @@ namespace WeirdEngine if (shape.m_screenSpace) return; - DistanceFieldObject2D sdf(shape.Owner, shape.m_distanceFieldId, shape.m_parameters); + DistanceFieldObject2D sdf(shape.Owner, shape.m_distanceFieldId, shape.m_combinationdId, shape.m_parameters); // Check if the key exists auto it = m_entityToObjectsIdx.find(shape.Owner); From 5983a935c1da9751138221fc36e5bba39f83528c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= <49535803+damacaa@users.noreply.github.com> Date: Sat, 21 Jun 2025 17:31:46 +0200 Subject: [PATCH 3/9] Combination grops and can disable collisions --- include/weird-engine/Scene.h | 2 +- .../weird-engine/ecs/Components/CustomShape.h | 2 + .../ecs/Systems/SDFRenderSystem2D.h | 2 +- src/weird-engine/Scene.cpp | 77 ++++++++++++++++--- src/weird-physics/Simulation2D.cpp | 2 +- 5 files changed, 70 insertions(+), 15 deletions(-) diff --git a/include/weird-engine/Scene.h b/include/weird-engine/Scene.h index c31efb2..8dbda0c 100644 --- a/include/weird-engine/Scene.h +++ b/include/weird-engine/Scene.h @@ -64,7 +64,7 @@ namespace WeirdEngine std::vector> m_sdfs; - Entity addShape(int shapeId, float* variables, int combination = 0); + Entity addShape(int shapeId, float* variables, int combination = 0, bool hasCollision = true, int group = 0); Entity addScreenSpaceShape(int shapeId, float* variables); void lookAt(Entity entity); diff --git a/include/weird-engine/ecs/Components/CustomShape.h b/include/weird-engine/ecs/Components/CustomShape.h index 86a4f87..4858f83 100644 --- a/include/weird-engine/ecs/Components/CustomShape.h +++ b/include/weird-engine/ecs/Components/CustomShape.h @@ -13,6 +13,8 @@ namespace WeirdEngine float m_parameters[8]; bool m_isDirty; bool m_screenSpace; + bool m_hasCollision; + uint16_t m_groupId; CustomShape() : m_distanceFieldId(0), m_isDirty(true), m_screenSpace(false) { diff --git a/include/weird-engine/ecs/Systems/SDFRenderSystem2D.h b/include/weird-engine/ecs/Systems/SDFRenderSystem2D.h index 969e0f2..cc344c8 100644 --- a/include/weird-engine/ecs/Systems/SDFRenderSystem2D.h +++ b/include/weird-engine/ecs/Systems/SDFRenderSystem2D.h @@ -98,7 +98,7 @@ namespace WeirdEngine return closestIndex; } - bool shaderNeedsUpdate() const + bool& shaderNeedsUpdate() { return m_customShapesNeedUpdate; } diff --git a/src/weird-engine/Scene.cpp b/src/weird-engine/Scene.cpp index 0d1ce94..a8d47fb 100644 --- a/src/weird-engine/Scene.cpp +++ b/src/weird-engine/Scene.cpp @@ -104,35 +104,57 @@ namespace WeirdEngine void Scene::updateCustomShapesShader(WeirdRenderer::Shader &shader) { + auto sdfBalls = m_ecs.getComponentManager()->getComponentArray(); + int32_t atomCount = sdfBalls->getSize(); + auto componentArray = m_ecs.getComponentManager()->getComponentArray(); + shader.setUniform("u_customShapeCount", componentArray->getSize()); + if (!m_sdfRenderSystem2D.shaderNeedsUpdate()) { return; } + m_sdfRenderSystem2D.shaderNeedsUpdate() = false; + std::string str = shader.getFragmentCode(); std::string toReplace("/*ADD_SHAPES_HERE*/"); std::ostringstream oss; - auto atomArray = m_ecs.getComponentManager()->getComponentArray(); - int32_t atomCount = atomArray->getSize(); - auto componentArray = m_ecs.getComponentManager()->getComponentArray(); - shader.setUniform("u_customShapeCount", componentArray->getSize()); - oss << "int dataOffset = u_loadedObjects - (2 * u_customShapeCount);"; + + oss << "///////////////////////////////////////////\n"; + + oss << "int dataOffset = u_loadedObjects - (2 * u_customShapeCount);\n"; + + int currentGroup = -1; + for (size_t i = 0; i < componentArray->getSize(); i++) { auto &shape = componentArray->getDataAtIdx(i); - oss << "{"; + int group = shape.m_groupId; + + if(group != currentGroup) + { + if(currentGroup != -1) + { + oss << "d = min(d" << currentGroup << ", d);\n"; + } + + oss << "float d" << group << "= 10000;\n"; + currentGroup = group; + } + + oss << "{\n"; oss << "int idx = dataOffset + " << 2 * i << ";\n"; // Fetch parameters - oss << "vec4 parameters0 = texelFetch(t_shapeBuffer, idx);"; - oss << "vec4 parameters1 = texelFetch(t_shapeBuffer, idx + 1);"; + oss << "vec4 parameters0 = texelFetch(t_shapeBuffer, idx);\n"; + oss << "vec4 parameters1 = texelFetch(t_shapeBuffer, idx + 1);\n"; auto fragmentCode = m_sdfs[shape.m_distanceFieldId]->print(); @@ -154,25 +176,47 @@ namespace WeirdEngine switch (shape.m_combinationdId) { case 0: { - oss << "d = min(d, dist);\n"; + oss << "d" << group << " = min(d" << group << ", dist);\n"; break; } case 1: { - oss << "d = max(d, -dist);\n"; + oss << "d" << group << " = max(d" << group << ", -dist);\n"; break; } default: break; } + /*switch (shape.m_combinationdId) + { + case 0: { + oss << "d = min(d, dist);\n"; + break; + } + case 1: { + oss << "d = max(d, -dist);\n"; + break; + } + default: + break; + }*/ + + + // oss << "col = d == (dist) ? getMaterial(p," << (i % 12) + 4 << ") : col;\n"; - oss << "col = d == (dist) ? getMaterial(p," << 3 << ") : col;\n"; + oss << "col = d" << currentGroup << " == (dist) ? getMaterial(p," << 3 << ") : col;\n"; oss << "}\n" << std::endl; } + // oss << "d" << currentGroup << " = d" << currentGroup << " > 0 ? d" << currentGroup << " : 0.1 * d" << currentGroup << ";" << std::endl; + + oss << "d = min(d" << currentGroup << ", d);\n"; + std::string replacement = oss.str(); + std::cout << replacement << std::endl; + size_t pos = str.find(toReplace); if (pos != std::string::npos) { // Check if the substring was found @@ -197,6 +241,11 @@ namespace WeirdEngine void Scene::update(double delta, double time) { + if (Input::GetKeyDown((Input::V))) + { + m_sdfRenderSystem2D.shaderNeedsUpdate() = true; + } + // Update systems if (m_debugFly) { @@ -245,16 +294,20 @@ namespace WeirdEngine return m_renderMode; } - Entity Scene::addShape(int shapeId, float* variables, int combination) + Entity Scene::addShape(int shapeId, float* variables, int combination, bool hasCollision, int group) { Entity entity = m_ecs.createEntity(); CustomShape &shape = m_ecs.addComponent(entity); shape.m_distanceFieldId = shapeId; shape.m_combinationdId = combination; + shape.m_hasCollision = hasCollision; + shape.m_groupId = group; std::copy(variables, variables + 8, shape.m_parameters); // CustomShape shape(shapeId, variables); // check old constructor for references + m_sdfRenderSystem2D.shaderNeedsUpdate() = true; + return entity; } diff --git a/src/weird-physics/Simulation2D.cpp b/src/weird-physics/Simulation2D.cpp index 734e5ff..286eb2c 100644 --- a/src/weird-physics/Simulation2D.cpp +++ b/src/weird-physics/Simulation2D.cpp @@ -822,7 +822,7 @@ namespace WeirdEngine void Simulation2D::updateShape(CustomShape& shape) { - if (shape.m_screenSpace) + if (shape.m_screenSpace || !shape.m_hasCollision) return; DistanceFieldObject2D sdf(shape.Owner, shape.m_distanceFieldId, shape.m_combinationdId, shape.m_parameters); From 4a916404660391d056da485c51b034e496a66bfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= <49535803+damacaa@users.noreply.github.com> Date: Sat, 21 Jun 2025 21:55:13 +0200 Subject: [PATCH 4/9] Physics combinations --- include/weird-engine/Scene.h | 3 +- .../weird-engine/ecs/Components/CustomShape.h | 9 +- include/weird-physics/Simulation2D.h | 3 +- src/weird-engine/Scene.cpp | 87 +++++++---------- src/weird-physics/Simulation2D.cpp | 21 +++- src/weird-renderer/shaders/raymarching2d.frag | 95 ++++++++----------- 6 files changed, 106 insertions(+), 112 deletions(-) diff --git a/include/weird-engine/Scene.h b/include/weird-engine/Scene.h index 8dbda0c..637d3ee 100644 --- a/include/weird-engine/Scene.h +++ b/include/weird-engine/Scene.h @@ -64,8 +64,7 @@ namespace WeirdEngine std::vector> m_sdfs; - Entity addShape(int shapeId, float* variables, int combination = 0, bool hasCollision = true, int group = 0); - Entity addScreenSpaceShape(int shapeId, float* variables); + Entity addShape(ShapeId shapeId, float* variables, int combination = 0, bool hasCollision = true, int group = 0); void lookAt(Entity entity); diff --git a/include/weird-engine/ecs/Components/CustomShape.h b/include/weird-engine/ecs/Components/CustomShape.h index 4858f83..9537670 100644 --- a/include/weird-engine/ecs/Components/CustomShape.h +++ b/include/weird-engine/ecs/Components/CustomShape.h @@ -4,10 +4,13 @@ namespace WeirdEngine { + using ShapeId = std::uint16_t; + struct CustomShape : public Component { public: + uint16_t m_distanceFieldId; uint16_t m_combinationdId; float m_parameters[8]; @@ -25,5 +28,9 @@ namespace WeirdEngine std::copy(params, params + 8, m_parameters); } + static constexpr ShapeId CIRCLE = 2; + static constexpr ShapeId BOX = 3; + static constexpr ShapeId SINE = 0; + static constexpr ShapeId STAR = 1; }; -} \ No newline at end of file +} diff --git a/include/weird-physics/Simulation2D.h b/include/weird-physics/Simulation2D.h index 4a67167..6ea91f0 100644 --- a/include/weird-physics/Simulation2D.h +++ b/include/weird-physics/Simulation2D.h @@ -257,9 +257,10 @@ namespace WeirdEngine Entity owner; uint16_t distanceFieldId; uint16_t combinationId; + uint16_t groupId; float parameters[11]; - DistanceFieldObject2D(Entity owner, uint16_t id, uint16_t combinationId, float* params) : distanceFieldId(id), combinationId(combinationId), owner(owner) + DistanceFieldObject2D(Entity owner, uint16_t id, uint16_t combinationId, uint16_t groupId, float* params) : distanceFieldId(id), combinationId(combinationId), groupId(groupId), owner(owner) { std::copy(params, params + 8, parameters); // Copy params into parameters } diff --git a/src/weird-engine/Scene.cpp b/src/weird-engine/Scene.cpp index a8d47fb..915ba2e 100644 --- a/src/weird-engine/Scene.cpp +++ b/src/weird-engine/Scene.cpp @@ -23,7 +23,6 @@ namespace WeirdEngine Scene::Scene() : m_simulation2D(MAX_ENTITIES), m_sdfRenderSystem(m_ecs), m_sdfRenderSystem2D(m_ecs), m_renderSystem(m_ecs), m_instancedRenderSystem(m_ecs), m_rbPhysicsSystem2D(m_ecs), m_physicsInteractionSystem(m_ecs), m_playerMovementSystem(m_ecs), m_cameraSystem(m_ecs), m_runSimulationInThread(true) { - // Custom component managers std::shared_ptr rbManager = std::make_shared(m_simulation2D); m_ecs.registerComponent(rbManager); @@ -105,7 +104,7 @@ namespace WeirdEngine void Scene::updateCustomShapesShader(WeirdRenderer::Shader &shader) { auto sdfBalls = m_ecs.getComponentManager()->getComponentArray(); - int32_t atomCount = sdfBalls->getSize(); + int32_t ballsCount = sdfBalls->getSize(); auto componentArray = m_ecs.getComponentManager()->getComponentArray(); shader.setUniform("u_customShapeCount", componentArray->getSize()); @@ -129,101 +128,100 @@ namespace WeirdEngine oss << "int dataOffset = u_loadedObjects - (2 * u_customShapeCount);\n"; int currentGroup = -1; - + std::string groupDistanceVariable; for (size_t i = 0; i < componentArray->getSize(); i++) { + // Get shape auto &shape = componentArray->getDataAtIdx(i); + // Get group int group = shape.m_groupId; + // Start new group if necessary if(group != currentGroup) { + // If this is not the first group, combine current group distance with global minDistance if(currentGroup != -1) { - oss << "d = min(d" << currentGroup << ", d);\n"; + oss << "minDist = min("<< groupDistanceVariable <<", minDist);\n"; } - oss << "float d" << group << "= 10000;\n"; + // Next group currentGroup = group; + groupDistanceVariable = "d" + std::to_string(currentGroup); + + // Initialize distance with big value + oss << "float " << groupDistanceVariable << "= 10000;\n"; } + // Start shape oss << "{\n"; + // Calculate data position in array oss << "int idx = dataOffset + " << 2 * i << ";\n"; // Fetch parameters oss << "vec4 parameters0 = texelFetch(t_shapeBuffer, idx);\n"; oss << "vec4 parameters1 = texelFetch(t_shapeBuffer, idx + 1);\n"; + // Get distance function auto fragmentCode = m_sdfs[shape.m_distanceFieldId]->print(); + // Use screen space coords (DEPRECATED) if (shape.m_screenSpace) { replaceSubstring(fragmentCode, "var9", "var11"); replaceSubstring(fragmentCode, "var10", "var12"); } + // Shape distance calculation oss << "float dist = " << fragmentCode << ";" << std::endl; - /*if (shape.m_screenSpace) - { - oss << "dist = dist * u_uiScale;" << std::endl; - }*/ - - oss << "dist = dist > 0 ? dist : 0.1 * dist;" << std::endl; + // Combine shape distance switch (shape.m_combinationdId) { - case 0: { - oss << "d" << group << " = min(d" << group << ", dist);\n"; + case 0: + { + // Scale negative distances + oss << "dist = dist > 0 ? dist : 0.1 * dist;" << std::endl; + oss << groupDistanceVariable << " = min(" << groupDistanceVariable << ", dist);\n"; + oss << "col = " << groupDistanceVariable << " == (dist) ? getMaterial(p," << 3 << ") : col;\n"; break; } - case 1: { - oss << "d" << group << " = max(d" << group << ", -dist);\n"; + case 1: + { + oss << groupDistanceVariable << " = max(" << groupDistanceVariable << ", -dist);\n"; break; } default: break; } - /*switch (shape.m_combinationdId) - { - case 0: { - oss << "d = min(d, dist);\n"; - break; - } - case 1: { - oss << "d = max(d, -dist);\n"; - break; - } - default: - break; - }*/ - - - - // oss << "col = d == (dist) ? getMaterial(p," << (i % 12) + 4 << ") : col;\n"; - oss << "col = d" << currentGroup << " == (dist) ? getMaterial(p," << 3 << ") : col;\n"; oss << "}\n" << std::endl; } - // oss << "d" << currentGroup << " = d" << currentGroup << " > 0 ? d" << currentGroup << " : 0.1 * d" << currentGroup << ";" << std::endl; - - oss << "d = min(d" << currentGroup << ", d);\n"; + // Combine last group + oss << "minDist = min(" << groupDistanceVariable << ", minDist);\n"; + // Get string std::string replacement = oss.str(); + // Print std::cout << replacement << std::endl; + // Replace in shader source code size_t pos = str.find(toReplace); + // Check if the substring was found if (pos != std::string::npos) - { // Check if the substring was found + { // Replace the substring str.replace(pos, toReplace.length(), replacement); } + // Set new source code and recompile shader shader.setFragmentCode(str); } @@ -294,7 +292,7 @@ namespace WeirdEngine return m_renderMode; } - Entity Scene::addShape(int shapeId, float* variables, int combination, bool hasCollision, int group) + Entity Scene::addShape(ShapeId shapeId, float* variables, int combination, bool hasCollision, int group) { Entity entity = m_ecs.createEntity(); CustomShape &shape = m_ecs.addComponent(entity); @@ -311,19 +309,6 @@ namespace WeirdEngine return entity; } - Entity Scene::addScreenSpaceShape(int shapeId, float *variables) - { - Entity entity = m_ecs.createEntity(); - CustomShape &shape = m_ecs.addComponent(entity); - shape.m_screenSpace = true; - shape.m_distanceFieldId = shapeId; - std::copy(variables, variables + 8, shape.m_parameters); - - // CustomShape shape(shapeId, variables); // check old constructor for references - - return entity; - } - void Scene::lookAt(Entity entity) { FlyMovement2D &fly = m_ecs.getComponent(m_mainCamera); diff --git a/src/weird-physics/Simulation2D.cpp b/src/weird-physics/Simulation2D.cpp index 286eb2c..a5410b0 100644 --- a/src/weird-physics/Simulation2D.cpp +++ b/src/weird-physics/Simulation2D.cpp @@ -336,10 +336,14 @@ namespace WeirdEngine float Simulation2D::map(vec2 p) { float d = 1.0f; - float distances[2]; + float currentGroupMinDistance = 1.0f; + + auto currentGroup = 0; for (int i = 0; i < m_objects.size(); i++) { + + DistanceFieldObject2D& obj = m_objects[i]; if (obj.distanceFieldId >= m_sdfs->size()) { @@ -350,6 +354,13 @@ namespace WeirdEngine obj.parameters[9] = p.x; obj.parameters[10] = p.y; + if (obj.groupId != currentGroup) + { + currentGroup = obj.groupId; + d = std::min(d, currentGroupMinDistance); + currentGroupMinDistance = 100000.0f; + } + // Distance (*m_sdfs)[obj.distanceFieldId]->propagateValues(obj.parameters); @@ -359,11 +370,11 @@ namespace WeirdEngine switch (obj.combinationId) { case 0: { - d = std::min(d, dist); + currentGroupMinDistance = std::min(currentGroupMinDistance, dist); break; } case 1: { - d = std::max(d, -dist); + currentGroupMinDistance = std::max(currentGroupMinDistance, -dist); break; } default: @@ -371,6 +382,8 @@ namespace WeirdEngine } } + d = std::min(d, currentGroupMinDistance); + return d; } @@ -825,7 +838,7 @@ namespace WeirdEngine if (shape.m_screenSpace || !shape.m_hasCollision) return; - DistanceFieldObject2D sdf(shape.Owner, shape.m_distanceFieldId, shape.m_combinationdId, shape.m_parameters); + DistanceFieldObject2D sdf(shape.Owner, shape.m_distanceFieldId, shape.m_combinationdId, shape.m_groupId, shape.m_parameters); // Check if the key exists auto it = m_entityToObjectsIdx.find(shape.Owner); diff --git a/src/weird-renderer/shaders/raymarching2d.frag b/src/weird-renderer/shaders/raymarching2d.frag index cf39efc..9a4eb52 100644 --- a/src/weird-renderer/shaders/raymarching2d.frag +++ b/src/weird-renderer/shaders/raymarching2d.frag @@ -140,77 +140,66 @@ vec3 getMaterial(vec2 p, int materialId) vec4 getColor(vec2 p, vec2 uv) { - float d = 100000.0; + float minDist = 100000.0; - vec3 col = vec3(0.0); - float minZ = 1000.0f; + vec3 col = vec3(0.0); + float minZ = 1000.0f; - float zoom = -u_camMatrix[3].z; + float zoom = -u_camMatrix[3].z; - float aspectRatio = u_resolution.x / u_resolution.y; - vec2 zoomVec = vec2((zoom * aspectRatio) - 1.0, zoom); + float aspectRatio = u_resolution.x / u_resolution.y; + vec2 zoomVec = vec2((zoom * aspectRatio) - 1.0, zoom); - bool bestIsScreenSpace = false; + bool bestIsScreenSpace = false; - /*ADD_SHAPES_HERE*/ + /*ADD_SHAPES_HERE*/ - for (int i = 0; i < u_loadedObjects - (2 * u_customShapeCount); i++) - { - vec4 positionSizeMaterial = texelFetch(t_shapeBuffer, i); - int materialId = int(positionSizeMaterial.w); - // vec4 extraParameters = texelFetch(t_shapeBuffer, (2 * i) + 1); + if(minDist < EPSILON) + { + return vec4(col, minDist); + } - float z = positionSizeMaterial.z; - bool screenSpace = z < 0.0f; + for (int i = 0; i < u_loadedObjects - (2 * u_customShapeCount); i++) + { + vec4 positionSizeMaterial = texelFetch(t_shapeBuffer, i); + int materialId = int(positionSizeMaterial.w); + // vec4 extraParameters = texelFetch(t_shapeBuffer, (2 * i) + 1); - + float z = positionSizeMaterial.z; - float objectDist = shape_circle((screenSpace ? u_uiScale * uv : p) - positionSizeMaterial.xy); + float objectDist = shape_circle(p - positionSizeMaterial.xy); - if(z < minZ) - { + #if BLEND_SHAPES -#if BLEND_SHAPES + minDist = fOpUnionSoft(objectDist, minDist, u_k); + float delta = 1 - (max(u_k - abs(objectDist - minDist), 0.0) / u_k); // After new d is calculated + col = mix(getMaterial(p, materialId), col, delta); - d = fOpUnionSoft(objectDist, d, u_k); - float delta = 1 - (max(u_k - abs(objectDist - d), 0.0) / u_k); // After new d is calculated - col = mix(getMaterial(p, materialId), col, delta); + #else -#else + if(objectDist < minDist) + { + minDist = objectDist; + col = getMaterial(positionSizeMaterial.xy, materialId); + minZ = z; - d = min(d, objectDist); + if(minDist < EPSILON) + { + break; + } + } - if(objectDist < 0) - { - col = getMaterial(positionSizeMaterial.xy, materialId); - minZ = z; - bestIsScreenSpace = screenSpace; - } - -#endif - - } - } - - if(bestIsScreenSpace) - return vec4(col, d); - - + #endif - // Repetition - // float scale = 1.0 / 10.0; - // vec2 pp = p + 5.0; - // vec2 roundPos = ((scale * pp) - round(scale * pp)) * 10.0; - // roundPos.x += cos(u_time + round(0.1 * pp.x)); - // roundPos.y += sin(u_time + round(0.1 * pp.x)); + } - // Set bacu_kground color - // vec3 bacu_kground = mix(u_staticColors[2], u_staticColors[3], mod(floor(.1 * p.x) + floor(.1 * p.y), 2.0)); - float pixel = 0.2 / u_resolution.y; - vec3 bacu_kground = mix(u_staticColors[3], u_staticColors[2], min(fract(0.1 * p.x), fract(0.1 * p.y)) > pixel * zoom ? 1.0 : 0.0); - col = d > 0.0 ? bacu_kground : col; + // Set bacu_kground color + // vec3 bacu_kground = mix(u_staticColors[2], u_staticColors[3], mod(floor(.1 * p.x) + floor(.1 * p.y), 2.0)); + float pixel = 0.2 / u_resolution.y; + vec3 background = mix(u_staticColors[3], u_staticColors[2], min(fract(0.1 * p.x), fract(0.1 * p.y)) > pixel * zoom ? 1.0 : 0.0); + col = minDist > 0.0 ? background : col; - return vec4(col, d); + return vec4(col, minDist); } void main() From bf9cffcdeff0ef961d85caa20e4618d9304b8a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= <49535803+damacaa@users.noreply.github.com> Date: Sat, 21 Jun 2025 21:37:58 +0200 Subject: [PATCH 5/9] Colors? --- src/weird-engine/Scene.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/weird-engine/Scene.cpp b/src/weird-engine/Scene.cpp index 915ba2e..7fcd6b4 100644 --- a/src/weird-engine/Scene.cpp +++ b/src/weird-engine/Scene.cpp @@ -144,7 +144,8 @@ namespace WeirdEngine // If this is not the first group, combine current group distance with global minDistance if(currentGroup != -1) { - oss << "minDist = min("<< groupDistanceVariable <<", minDist);\n"; + oss << "if(minDist >"<< groupDistanceVariable <<"){ minDist = "<< groupDistanceVariable <<";\n"; + oss << "col = getMaterial(p," << (4 + currentGroup) % 16 << ");}\n"; } // Next group @@ -187,7 +188,7 @@ namespace WeirdEngine // Scale negative distances oss << "dist = dist > 0 ? dist : 0.1 * dist;" << std::endl; oss << groupDistanceVariable << " = min(" << groupDistanceVariable << ", dist);\n"; - oss << "col = " << groupDistanceVariable << " == (dist) ? getMaterial(p," << 3 << ") : col;\n"; + // oss << "col = " << groupDistanceVariable << " == (dist) ? getMaterial(p," << (3 + currentGroup) % 16 << ") : col;\n"; break; } case 1: @@ -204,7 +205,8 @@ namespace WeirdEngine } // Combine last group - oss << "minDist = min(" << groupDistanceVariable << ", minDist);\n"; + oss << "if(minDist >"<< groupDistanceVariable <<"){ minDist = "<< groupDistanceVariable <<";\n"; + oss << "col = getMaterial(p," << (4 + currentGroup) % 16 << ");}\n"; // Get string std::string replacement = oss.str(); From 97b7aa9cfd21a511c14dc640cbc845e4b30e6b5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= <49535803+damacaa@users.noreply.github.com> Date: Tue, 24 Jun 2025 22:40:02 +0200 Subject: [PATCH 6/9] [WIP] Group 5 has global effect combinations --- src/weird-engine/Scene.cpp | 38 +++++++++++++++++------------- src/weird-physics/Simulation2D.cpp | 31 +++++++++++++++--------- 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/src/weird-engine/Scene.cpp b/src/weird-engine/Scene.cpp index 7fcd6b4..fa44453 100644 --- a/src/weird-engine/Scene.cpp +++ b/src/weird-engine/Scene.cpp @@ -176,32 +176,36 @@ namespace WeirdEngine replaceSubstring(fragmentCode, "var10", "var12"); } + bool globalEffect = group == 5; + // Shape distance calculation oss << "float dist = " << fragmentCode << ";" << std::endl; + // Apply globalEffect logic + oss << "float currentMinDistance = " << (globalEffect ? "minDist" : groupDistanceVariable) << ";" << std::endl; // Combine shape distance switch (shape.m_combinationdId) { - case 0: - { - // Scale negative distances - oss << "dist = dist > 0 ? dist : 0.1 * dist;" << std::endl; - oss << groupDistanceVariable << " = min(" << groupDistanceVariable << ", dist);\n"; - // oss << "col = " << groupDistanceVariable << " == (dist) ? getMaterial(p," << (3 + currentGroup) % 16 << ") : col;\n"; - break; - } - case 1: - { - oss << groupDistanceVariable << " = max(" << groupDistanceVariable << ", -dist);\n"; - break; - } - default: - break; + case 0: + { + // Scale negative distances + oss << "dist = dist > 0 ? dist : 0.1 * dist;" << std::endl; + oss << "currentMinDistance = min(currentMinDistance, dist);\n"; + break; + } + case 1: + { + oss << "currentMinDistance = max(currentMinDistance, -dist);\n"; + break; + } + default: + break; } - oss << "}\n" - << std::endl; + // Assign back to the correct target + oss << (globalEffect ? "minDist" : groupDistanceVariable) << " = currentMinDistance;\n"; + oss << "}\n\n"; } // Combine last group diff --git a/src/weird-physics/Simulation2D.cpp b/src/weird-physics/Simulation2D.cpp index a5410b0..3d60988 100644 --- a/src/weird-physics/Simulation2D.cpp +++ b/src/weird-physics/Simulation2D.cpp @@ -366,19 +366,28 @@ namespace WeirdEngine float dist = (*m_sdfs)[obj.distanceFieldId]->getValue(); + bool globalEffect = obj.groupId == 5; + + float currentMinDistance = globalEffect ? d : currentGroupMinDistance; + // Combination - switch (obj.combinationId) - { - case 0: { - currentGroupMinDistance = std::min(currentGroupMinDistance, dist); - break; - } - case 1: { - currentGroupMinDistance = std::max(currentGroupMinDistance, -dist); - break; + switch (obj.combinationId) { + case 0: { + currentMinDistance = std::min(currentMinDistance, dist); + break; + } + case 1: { + currentMinDistance = std::max(currentMinDistance, -dist); + break; + } + default: + break; } - default: - break; + + if (globalEffect) { + d = currentMinDistance; + } else { + currentGroupMinDistance = currentMinDistance; } } From fbb8c4302fe318bef7b65ef213679f32b89c2295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= <49535803+damacaa@users.noreply.github.com> Date: Fri, 27 Jun 2025 11:08:38 +0200 Subject: [PATCH 7/9] Fixed error when there are 0 shapes --- src/weird-engine/Scene.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/weird-engine/Scene.cpp b/src/weird-engine/Scene.cpp index fa44453..75a0e7a 100644 --- a/src/weird-engine/Scene.cpp +++ b/src/weird-engine/Scene.cpp @@ -209,8 +209,13 @@ namespace WeirdEngine } // Combine last group - oss << "if(minDist >"<< groupDistanceVariable <<"){ minDist = "<< groupDistanceVariable <<";\n"; - oss << "col = getMaterial(p," << (4 + currentGroup) % 16 << ");}\n"; + if (componentArray->getSize() > 0) + { + oss << "if(minDist >" << groupDistanceVariable << "){ minDist = " << groupDistanceVariable << ";\n"; + oss << "col = getMaterial(p," << (4 + currentGroup) % 16 << ");}\n"; + } + + // oss << "minDist -= 1.5;\n"; // Get string std::string replacement = oss.str(); From a46b1c472c1f8275383c1ba2188e184173c1e04d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= <49535803+damacaa@users.noreply.github.com> Date: Sun, 6 Jul 2025 22:30:40 +0200 Subject: [PATCH 8/9] CombinationType and API improvements --- include/weird-engine/Scene.h | 2 +- .../weird-engine/ecs/Components/CustomShape.h | 14 ++++++++-- include/weird-physics/Simulation2D.h | 4 +-- src/weird-engine/Scene.cpp | 26 +++++++++++++------ src/weird-physics/Simulation2D.cpp | 16 +++++++++--- 5 files changed, 45 insertions(+), 17 deletions(-) diff --git a/include/weird-engine/Scene.h b/include/weird-engine/Scene.h index 637d3ee..941b16b 100644 --- a/include/weird-engine/Scene.h +++ b/include/weird-engine/Scene.h @@ -64,7 +64,7 @@ namespace WeirdEngine std::vector> m_sdfs; - Entity addShape(ShapeId shapeId, float* variables, int combination = 0, bool hasCollision = true, int group = 0); + Entity addShape(ShapeId shapeId, float* variables, CombinationType combination = CombinationType::Addition, bool hasCollision = true, int group = 0); void lookAt(Entity entity); diff --git a/include/weird-engine/ecs/Components/CustomShape.h b/include/weird-engine/ecs/Components/CustomShape.h index 9537670..48f3d2e 100644 --- a/include/weird-engine/ecs/Components/CustomShape.h +++ b/include/weird-engine/ecs/Components/CustomShape.h @@ -6,13 +6,20 @@ namespace WeirdEngine { using ShapeId = std::uint16_t; + enum class CombinationType : uint16_t + { + Addition, + Subtraction, + Intersection, + SmoothAddition + }; + struct CustomShape : public Component { public: - uint16_t m_distanceFieldId; - uint16_t m_combinationdId; + CombinationType m_combination; float m_parameters[8]; bool m_isDirty; bool m_screenSpace; @@ -32,5 +39,8 @@ namespace WeirdEngine static constexpr ShapeId BOX = 3; static constexpr ShapeId SINE = 0; static constexpr ShapeId STAR = 1; + + static constexpr uint16_t GLOBAL_GROUP = std::numeric_limits::max(); + }; } diff --git a/include/weird-physics/Simulation2D.h b/include/weird-physics/Simulation2D.h index 6ea91f0..2ad4a87 100644 --- a/include/weird-physics/Simulation2D.h +++ b/include/weird-physics/Simulation2D.h @@ -256,11 +256,11 @@ namespace WeirdEngine { Entity owner; uint16_t distanceFieldId; - uint16_t combinationId; + CombinationType combinationId; uint16_t groupId; float parameters[11]; - DistanceFieldObject2D(Entity owner, uint16_t id, uint16_t combinationId, uint16_t groupId, float* params) : distanceFieldId(id), combinationId(combinationId), groupId(groupId), owner(owner) + DistanceFieldObject2D(Entity owner, uint16_t id, CombinationType combinationId, uint16_t groupId, float* params) : distanceFieldId(id), combinationId(combinationId), groupId(groupId), owner(owner) { std::copy(params, params + 8, parameters); // Copy params into parameters } diff --git a/src/weird-engine/Scene.cpp b/src/weird-engine/Scene.cpp index 75a0e7a..fdd7128 100644 --- a/src/weird-engine/Scene.cpp +++ b/src/weird-engine/Scene.cpp @@ -145,7 +145,7 @@ namespace WeirdEngine if(currentGroup != -1) { oss << "if(minDist >"<< groupDistanceVariable <<"){ minDist = "<< groupDistanceVariable <<";\n"; - oss << "col = getMaterial(p," << (4 + currentGroup) % 16 << ");}\n"; + oss << "col = getMaterial(p," << 3 << ");}\n"; } // Next group @@ -176,7 +176,7 @@ namespace WeirdEngine replaceSubstring(fragmentCode, "var10", "var12"); } - bool globalEffect = group == 5; + bool globalEffect = group == CustomShape::GLOBAL_GROUP; // Shape distance calculation oss << "float dist = " << fragmentCode << ";" << std::endl; @@ -185,20 +185,30 @@ namespace WeirdEngine oss << "float currentMinDistance = " << (globalEffect ? "minDist" : groupDistanceVariable) << ";" << std::endl; // Combine shape distance - switch (shape.m_combinationdId) + switch (shape.m_combination) { - case 0: + case CombinationType::Addition: { // Scale negative distances oss << "dist = dist > 0 ? dist : 0.1 * dist;" << std::endl; oss << "currentMinDistance = min(currentMinDistance, dist);\n"; break; } - case 1: + case CombinationType::Subtraction: { oss << "currentMinDistance = max(currentMinDistance, -dist);\n"; break; } + case CombinationType::Intersection: + { + oss << "currentMinDistance = max(currentMinDistance, dist);\n"; + break; + } + case CombinationType::SmoothAddition: + { + + break; + } default: break; } @@ -212,7 +222,7 @@ namespace WeirdEngine if (componentArray->getSize() > 0) { oss << "if(minDist >" << groupDistanceVariable << "){ minDist = " << groupDistanceVariable << ";\n"; - oss << "col = getMaterial(p," << (4 + currentGroup) % 16 << ");}\n"; + oss << "col = getMaterial(p," << 3 << ");}\n"; } // oss << "minDist -= 1.5;\n"; @@ -303,12 +313,12 @@ namespace WeirdEngine return m_renderMode; } - Entity Scene::addShape(ShapeId shapeId, float* variables, int combination, bool hasCollision, int group) + Entity Scene::addShape(ShapeId shapeId, float* variables, CombinationType combination, bool hasCollision, int group) { Entity entity = m_ecs.createEntity(); CustomShape &shape = m_ecs.addComponent(entity); shape.m_distanceFieldId = shapeId; - shape.m_combinationdId = combination; + shape.m_combination = combination; shape.m_hasCollision = hasCollision; shape.m_groupId = group; std::copy(variables, variables + 8, shape.m_parameters); diff --git a/src/weird-physics/Simulation2D.cpp b/src/weird-physics/Simulation2D.cpp index 3d60988..7f4c437 100644 --- a/src/weird-physics/Simulation2D.cpp +++ b/src/weird-physics/Simulation2D.cpp @@ -366,20 +366,28 @@ namespace WeirdEngine float dist = (*m_sdfs)[obj.distanceFieldId]->getValue(); - bool globalEffect = obj.groupId == 5; + bool globalEffect = obj.groupId == CustomShape::GLOBAL_GROUP; float currentMinDistance = globalEffect ? d : currentGroupMinDistance; // Combination switch (obj.combinationId) { - case 0: { + case CombinationType::Addition: { currentMinDistance = std::min(currentMinDistance, dist); break; } - case 1: { + case CombinationType::Subtraction: { currentMinDistance = std::max(currentMinDistance, -dist); break; } + case CombinationType::Intersection: { + currentMinDistance = std::max(currentMinDistance, dist); + break; + } + case CombinationType::SmoothAddition: { + + break; + } default: break; } @@ -847,7 +855,7 @@ namespace WeirdEngine if (shape.m_screenSpace || !shape.m_hasCollision) return; - DistanceFieldObject2D sdf(shape.Owner, shape.m_distanceFieldId, shape.m_combinationdId, shape.m_groupId, shape.m_parameters); + DistanceFieldObject2D sdf(shape.Owner, shape.m_distanceFieldId, shape.m_combination, shape.m_groupId, shape.m_parameters); // Check if the key exists auto it = m_entityToObjectsIdx.find(shape.Owner); From eccbbd93e5d84d01f5c00789340d3801602a0e77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= <49535803+damacaa@users.noreply.github.com> Date: Sun, 6 Jul 2025 22:53:02 +0200 Subject: [PATCH 9/9] Smooth addition --- src/weird-engine/Scene.cpp | 2 +- src/weird-physics/Simulation2D.cpp | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/weird-engine/Scene.cpp b/src/weird-engine/Scene.cpp index fdd7128..27a553d 100644 --- a/src/weird-engine/Scene.cpp +++ b/src/weird-engine/Scene.cpp @@ -206,7 +206,7 @@ namespace WeirdEngine } case CombinationType::SmoothAddition: { - + oss << "currentMinDistance = fOpUnionSoft(currentMinDistance, dist, 1.0);\n"; break; } default: diff --git a/src/weird-physics/Simulation2D.cpp b/src/weird-physics/Simulation2D.cpp index 7f4c437..5c1178c 100644 --- a/src/weird-physics/Simulation2D.cpp +++ b/src/weird-physics/Simulation2D.cpp @@ -333,6 +333,12 @@ namespace WeirdEngine } } + static float fOpUnionSoft(float a, float b, float r) + { + float e = std::max(r - std::abs(a - b), 0.0f); + return std::min(a, b) - e * e * 0.25 / r; + } + float Simulation2D::map(vec2 p) { float d = 1.0f; @@ -385,7 +391,7 @@ namespace WeirdEngine break; } case CombinationType::SmoothAddition: { - + currentMinDistance = fOpUnionSoft(currentMinDistance, dist, 1.0f); break; } default: