From b08f50bcf22bd2c4172506e3d9dcc3921f3e6bf9 Mon Sep 17 00:00:00 2001 From: adafcaefc Date: Thu, 5 Dec 2024 18:46:47 +0700 Subject: [PATCH] spline save and load --- Geome3Dash/src/LevelDataManager.cpp | 20 +- Geome3Dash/src/LevelDataManager.h | 14 +- Geome3Dash/src/LevelEditorImGui.cpp | 734 +++++++++--------- Geome3Dash/src/engine/sus3d/Model.cpp | 8 +- .../src/game/editor/G3DCurveEditorLoader.cpp | 38 +- .../src/game/editor/G3DCurveEditorLoader.h | 8 +- .../src/game/editor/G3DCurveEditorPopup.cpp | 47 +- Geome3Dash/src/game/playing/G3DPlayLayer.cpp | 22 +- Geome3Dash/src/helper/spline/Curve.h | 24 +- Geome3Dash/src/helper/spline/Spline.cpp | 84 +- Geome3Dash/src/helper/spline/Spline.h | 19 +- Geome3Dash/src/hook/LevelEditorLayer.cpp | 2 +- 12 files changed, 515 insertions(+), 505 deletions(-) diff --git a/Geome3Dash/src/LevelDataManager.cpp b/Geome3Dash/src/LevelDataManager.cpp index 04933cca..1b174aed 100644 --- a/Geome3Dash/src/LevelDataManager.cpp +++ b/Geome3Dash/src/LevelDataManager.cpp @@ -94,6 +94,8 @@ namespace g3d nlohmann::json jsonData = data; std::string jsonMsg = jsonData.dump(); msgLevelEncode(layer, jsonMsg); + std::ofstream out("g3d.out.json"); + out << jsonMsg; } LevelData LevelData::getDefault() @@ -104,14 +106,16 @@ namespace g3d ld.z = 40; ld.yaw = -55; ld.pitch = -6; - ld.bezierMultiplier = 1.0 / 3.0; - ld.bezierCurve = - { - 0.167 * 6, 0.355 * 6, - 0.516 * 6, 0.124 * 6, - 0.121 * 6, 0.557 * 6, - 0.412 * 6, 0.352 * 6 - }; + //ld.bezierMultiplier = 1.0 / 3.0; + //ld.bezierCurve = + //{ + // 0.167 * 6, 0.355 * 6, + // 0.516 * 6, 0.124 * 6, + // 0.121 * 6, 0.557 * 6, + // 0.412 * 6, 0.352 * 6 + //}; + ld.spline = Spline(); + ld.spline.addSegment(Curve(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(2.0f, 0.0f, 0.0f), glm::vec3(3.0f, 0.0f, 0.0f))); return ld; } } \ No newline at end of file diff --git a/Geome3Dash/src/LevelDataManager.h b/Geome3Dash/src/LevelDataManager.h index 565ebfbc..0dba597c 100644 --- a/Geome3Dash/src/LevelDataManager.h +++ b/Geome3Dash/src/LevelDataManager.h @@ -3,9 +3,12 @@ #include "CameraAction.h" #include "helper/BezierHelper.h" +#include "helper/spline/Spline.h" #include +#include + #include #include @@ -25,16 +28,19 @@ namespace g3d struct LevelData { - CubicBezierLD bezierCurve; // Bezier values - double bezierMultiplier; // Path size + //CubicBezierLD bezierCurve; // Bezier values + //double bezierMultiplier; // Path size + //std::vector actions; // Camera actions + + double x, y, z; // Position double yaw, pitch; // Rotation bool lock; // Lock camera - std::vector actions; // Camera actions + Spline spline; // Spline path static LevelData getDefault(); - NLOHMANN_DEFINE_TYPE_INTRUSIVE(LevelData, bezierCurve, bezierMultiplier, x, y, z, yaw, pitch, lock, actions); + NLOHMANN_DEFINE_TYPE_INTRUSIVE(LevelData, spline, x, y, z, yaw, pitch, lock); }; void msgLevelEncode(GJBaseGameLayer* layer, const std::string& message); diff --git a/Geome3Dash/src/LevelEditorImGui.cpp b/Geome3Dash/src/LevelEditorImGui.cpp index 58407d11..25b78aed 100644 --- a/Geome3Dash/src/LevelEditorImGui.cpp +++ b/Geome3Dash/src/LevelEditorImGui.cpp @@ -1,9 +1,7 @@ #include "pch.h" #include "LevelEditorImGui.h" - #include "LevelDataManager.h" - #include "lib/imgui-cocos/imgui-cocos.hpp" namespace g3d @@ -15,421 +13,389 @@ namespace g3d } - ImVec2 computeBezierPoint(const CubicBezier& bezier, float t) - { - float u = 1.0f - t; - float tt = t * t; - float uu = u * u; - float uuu = uu * u; - float ttt = tt * t; + //ImVec2 computeBezierPoint(const CubicBezier& bezier, float t) + //{ + // float u = 1.0f - t; + // float tt = t * t; + // float uu = u * u; + // float uuu = uu * u; + // float ttt = tt * t; - float x = uuu * bezier.x0 + 3 * uu * t * bezier.cx1 + 3 * u * tt * bezier.cx2 + ttt * bezier.x1; - float y = uuu * bezier.y0 + 3 * uu * t * bezier.cy1 + 3 * u * tt * bezier.cy2 + ttt * bezier.y1; + // float x = uuu * bezier.x0 + 3 * uu * t * bezier.cx1 + 3 * u * tt * bezier.cx2 + ttt * bezier.x1; + // float y = uuu * bezier.y0 + 3 * uu * t * bezier.cy1 + 3 * u * tt * bezier.cy2 + ttt * bezier.y1; - return ImVec2(x, y); - } + // return ImVec2(x, y); + //} - void renderBezierEditor(CubicBezier& bezier) { - - static int selectedPoint = -1; // Index of the currently selected point - static bool isDragging = false; - ImGui::Begin("Bezier Curve Editor"); - - ImVec2 canvasSize = ImVec2(400, 400); - ImVec2 canvasPos = ImGui::GetCursorScreenPos(); - ImDrawList* drawList = ImGui::GetWindowDrawList(); - - drawList->AddRectFilled(canvasPos, ImVec2(canvasPos.x + canvasSize.x, canvasPos.y + canvasSize.y), IM_COL32(50, 50, 50, 255)); - drawList->AddRect(canvasPos, ImVec2(canvasPos.x + canvasSize.x, canvasPos.y + canvasSize.y), IM_COL32(255, 255, 255, 255)); - - ImVec2 offset = ImVec2(canvasPos.x + canvasSize.x * 0.1f, canvasPos.y + canvasSize.y * 0.1f); - float scale = canvasSize.x * 0.8f; - - const int segments = 100; - for (int i = 0; i < segments; ++i) - { - float t0 = static_cast(i) / segments; - float t1 = static_cast(i + 1) / segments; - ImVec2 p0 = computeBezierPoint(bezier, t0); - ImVec2 p1 = computeBezierPoint(bezier, t1); - - p0 = ImVec2(offset.x + p0.x * scale, offset.y + p0.y * scale); - p1 = ImVec2(offset.x + p1.x * scale, offset.y + p1.y * scale); - - drawList->AddLine(p0, p1, IM_COL32(200, 100, 100, 255), 2.0f); - } - - ImVec2 points[4] = - { - ImVec2(offset.x + bezier.x0 * scale, offset.y + bezier.y0 * scale), - ImVec2(offset.x + bezier.cx1 * scale, offset.y + bezier.cy1 * scale), - ImVec2(offset.x + bezier.cx2 * scale, offset.y + bezier.cy2 * scale), - ImVec2(offset.x + bezier.x1 * scale, offset.y + bezier.y1 * scale) - }; - - ImGui::PushClipRect(canvasPos, ImVec2(canvasPos.x + canvasSize.x, canvasPos.y + canvasSize.y), true); - - for (int i = 0; i < 4; ++i) - { - drawList->AddCircleFilled(points[i], 5.0f, IM_COL32(255, 255, 0, 255)); - - if (ImGui::IsMouseHoveringRect(canvasPos, ImVec2(canvasPos.x + canvasSize.x, canvasPos.y + canvasSize.y))) - { - ImVec2 mousePos = ImGui::GetMousePos(); - float distance = std::hypot(points[i].x - mousePos.x, points[i].y - mousePos.y); - - if (distance < 10.0f && ImGui::IsMouseClicked(0)) - { - selectedPoint = i; - isDragging = true; - ImGui::SetNextFrameWantCaptureMouse(true); - } - } - } - - if (isDragging && selectedPoint != -1) - { - if (ImGui::IsMouseDragging(0)) - { - ImVec2 mousePos = ImGui::GetMousePos(); - float normalizedX = (mousePos.x - offset.x) / scale; - float normalizedY = (mousePos.y - offset.y) / scale; - - switch (selectedPoint) - { - case 0: bezier.x0 = normalizedX; bezier.y0 = normalizedY; break; - case 1: bezier.cx1 = normalizedX; bezier.cy1 = normalizedY; break; - case 2: bezier.cx2 = normalizedX; bezier.cy2 = normalizedY; break; - case 3: bezier.x1 = normalizedX; bezier.y1 = normalizedY; break; - } - } - else if (ImGui::IsMouseReleased(0)) - { - isDragging = false; - selectedPoint = -1; - ImGui::SetNextFrameWantCaptureMouse(false); - } - } - - ImGui::PopClipRect(); - ImGui::End(); - } - - static LevelData currentLevelData; + //void renderBezierEditor(CubicBezier& bezier) { - void renderLevelDataEditor() - { - ImGui::Begin("Level Data Editor"); - - GJBaseGameLayer* layer = nullptr; - if (PlayLayer::get()) { layer = PlayLayer::get(); } - else if (LevelEditorLayer::get()) { layer = LevelEditorLayer::get(); } - if (layer) - { - try - { - if (ImGui::Button("Load Level Data")) { currentLevelData = getLevelData(layer); } - if (ImGui::Button("Save Level Data")) { setLevelData(layer, currentLevelData); } - } - catch (...) - { - - } - } - - if (ImGui::Button("Reset Data")) - { - currentLevelData = LevelData::getDefault(); - } - - ImGui::Separator(); - - // Edit Bezier curve fields - ImGui::Text("Bezier Curve:"); - ImGui::InputDouble("Start X", ¤tLevelData.bezierCurve.x0); - ImGui::InputDouble("Start Y", ¤tLevelData.bezierCurve.y0); - ImGui::InputDouble("Control 1 X", ¤tLevelData.bezierCurve.cx1); - ImGui::InputDouble("Control 1 Y", ¤tLevelData.bezierCurve.cy1); - ImGui::InputDouble("Control 2 X", ¤tLevelData.bezierCurve.cx2); - ImGui::InputDouble("Control 2 Y", ¤tLevelData.bezierCurve.cy2); - ImGui::InputDouble("End X", ¤tLevelData.bezierCurve.x1); - ImGui::InputDouble("End Y", ¤tLevelData.bezierCurve.y1); - ImGui::InputDouble("Bezier Multiplier", ¤tLevelData.bezierMultiplier); - - ImGui::Separator(); - - ImGui::Text("Position:"); - ImGui::InputDouble("X", ¤tLevelData.x); - ImGui::InputDouble("Y", ¤tLevelData.y); - ImGui::InputDouble("Z", ¤tLevelData.z); - - ImGui::Text("Rotation:"); - ImGui::InputDouble("Yaw", ¤tLevelData.yaw); - ImGui::InputDouble("Pitch", ¤tLevelData.pitch); - - ImGui::Checkbox("Lock Camera", ¤tLevelData.lock); - - ImGui::Separator(); - ImGui::Text("Camera Actions:"); - - for (size_t i = 0; i < currentLevelData.actions.size(); ++i) - { - ImGui::PushID(static_cast(i)); - ImGui::Text("Action %d:", static_cast(i + 1)); - CameraAction& action = currentLevelData.actions[i]; - - ImGui::InputDouble("X##Action", &action.x); - ImGui::InputDouble("Y##Action", &action.y); - ImGui::InputDouble("Z##Action", &action.z); - ImGui::InputDouble("Yaw##Action", &action.yaw); - ImGui::InputDouble("Pitch##Action", &action.pitch); - ImGui::InputDouble("Time##Action", &action.time); - ImGui::InputDouble("TriggerAt##Action", &action.triggerAt); - - if (ImGui::Button("Remove Action")) - { - currentLevelData.actions.erase(currentLevelData.actions.begin() + i); - ImGui::PopID(); - break; - } - - ImGui::Separator(); - ImGui::PopID(); - } - - if (ImGui::Button("Add Action")) { currentLevelData.actions.push_back({}); } - - ImGui::End(); - } + // static int selectedPoint = -1; // Index of the currently selected point + // static bool isDragging = false; + // ImGui::Begin("Bezier Curve Editor"); - bool isTabKeyPressed() - { - return (GetAsyncKeyState(VK_TAB) & 0x8000) != 0; - } + // ImVec2 canvasSize = ImVec2(400, 400); + // ImVec2 canvasPos = ImGui::GetCursorScreenPos(); + // ImDrawList* drawList = ImGui::GetWindowDrawList(); - // ------------ spline - - static inline float ImLengthSqr(const ImVec2& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y); } - static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); } - static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); } - static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } - static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } - static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } - static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); } - static inline ImVec2 operator-(const ImVec2& lhs) { return ImVec2(-lhs.x, -lhs.y); } - - struct ControlPoint { - float x, y; - }; - - // Globals - std::vector controlPoints; - int degree = 3; // Default spline degree - bool showControlPolygon = true; - int resolution = 100; // Number of points to evaluate on the spline - - ControlPoint DeBoor(int k, int degree, float t, const std::vector& knots, const std::vector& points) { - std::vector d = points; - - for (int r = 1; r <= degree; ++r) { - for (int j = k; j > k - r; --j) { - float denominator = knots[j + degree - r + 1] - knots[j]; - float alpha = denominator == 0.0f ? 0.0f : (t - knots[j]) / denominator; - - d[j].x = (1.0f - alpha) * d[j - 1].x + alpha * d[j].x; - d[j].y = (1.0f - alpha) * d[j - 1].y + alpha * d[j].y; - } - } - - return d[k]; - } + // drawList->AddRectFilled(canvasPos, ImVec2(canvasPos.x + canvasSize.x, canvasPos.y + canvasSize.y), IM_COL32(50, 50, 50, 255)); + // drawList->AddRect(canvasPos, ImVec2(canvasPos.x + canvasSize.x, canvasPos.y + canvasSize.y), IM_COL32(255, 255, 255, 255)); - std::vector GenerateUniformKnots(int n, int degree) { - int knotCount = n + degree + 2; - std::vector knots(knotCount); - - for (int i = 0; i < knotCount; ++i) { - if (i < degree) { - knots[i] = 0.0f; // Repeat start knots - } - else if (i > n) { - knots[i] = static_cast(n - degree + 1); // Repeat end knots - } - else { - knots[i] = static_cast(i - degree); - } - } - - return knots; - } + // ImVec2 offset = ImVec2(canvasPos.x + canvasSize.x * 0.1f, canvasPos.y + canvasSize.y * 0.1f); + // float scale = canvasSize.x * 0.8f; - std::vector ComputeBSpline(const std::vector& points, int degree, int resolution) { - std::vector result; - if (points.size() < degree + 1) return result; + // const int segments = 100; + // for (int i = 0; i < segments; ++i) + // { + // float t0 = static_cast(i) / segments; + // float t1 = static_cast(i + 1) / segments; + // ImVec2 p0 = computeBezierPoint(bezier, t0); + // ImVec2 p1 = computeBezierPoint(bezier, t1); - int n = points.size() - 1; - std::vector knots = GenerateUniformKnots(n, degree); + // p0 = ImVec2(offset.x + p0.x * scale, offset.y + p0.y * scale); + // p1 = ImVec2(offset.x + p1.x * scale, offset.y + p1.y * scale); - float step = (knots[n + 1] - knots[degree]) / static_cast(resolution - 1); - for (float t = knots[degree]; t <= knots[n + 1] + step / 2; t += step) { - // Clamp t to ensure it doesn't exceed the range - if (t > knots[n + 1]) t = knots[n + 1]; + // drawList->AddLine(p0, p1, IM_COL32(200, 100, 100, 255), 2.0f); + // } - // Find the knot span index k - int k = n; - for (int i = degree; i <= n; ++i) { - if (t >= knots[i] && t < knots[i + 1]) { - k = i; - break; - } - } + // ImVec2 points[4] = + // { + // ImVec2(offset.x + bezier.x0 * scale, offset.y + bezier.y0 * scale), + // ImVec2(offset.x + bezier.cx1 * scale, offset.y + bezier.cy1 * scale), + // ImVec2(offset.x + bezier.cx2 * scale, offset.y + bezier.cy2 * scale), + // ImVec2(offset.x + bezier.x1 * scale, offset.y + bezier.y1 * scale) + // }; - result.push_back(DeBoor(k, degree, t, knots, points)); - } + // ImGui::PushClipRect(canvasPos, ImVec2(canvasPos.x + canvasSize.x, canvasPos.y + canvasSize.y), true); - return result; - } + // for (int i = 0; i < 4; ++i) + // { + // drawList->AddCircleFilled(points[i], 5.0f, IM_COL32(255, 255, 0, 255)); + + // if (ImGui::IsMouseHoveringRect(canvasPos, ImVec2(canvasPos.x + canvasSize.x, canvasPos.y + canvasSize.y))) + // { + // ImVec2 mousePos = ImGui::GetMousePos(); + // float distance = std::hypot(points[i].x - mousePos.x, points[i].y - mousePos.y); - void RenderBSplineInCanvas( - const std::vector& controlPoints, - int degree, - int resolution, - const ImVec2& offset, - float scale, - ImDrawList* drawList - ) { - if (controlPoints.size() < degree + 1) return; + // if (distance < 10.0f && ImGui::IsMouseClicked(0)) + // { + // selectedPoint = i; + // isDragging = true; + // ImGui::SetNextFrameWantCaptureMouse(true); + // } + // } + // } - std::vector splinePoints = ComputeBSpline(controlPoints, degree, resolution); + // if (isDragging && selectedPoint != -1) + // { + // if (ImGui::IsMouseDragging(0)) + // { + // ImVec2 mousePos = ImGui::GetMousePos(); + // float normalizedX = (mousePos.x - offset.x) / scale; + // float normalizedY = (mousePos.y - offset.y) / scale; - for (size_t i = 0; i < splinePoints.size() - 1; ++i) { - ImVec2 p1 = ImVec2(offset.x + splinePoints[i].x * scale, offset.y + splinePoints[i].y * scale); - ImVec2 p2 = ImVec2(offset.x + splinePoints[i + 1].x * scale, offset.y + splinePoints[i + 1].y * scale); + // switch (selectedPoint) + // { + // case 0: bezier.x0 = normalizedX; bezier.y0 = normalizedY; break; + // case 1: bezier.cx1 = normalizedX; bezier.cy1 = normalizedY; break; + // case 2: bezier.cx2 = normalizedX; bezier.cy2 = normalizedY; break; + // case 3: bezier.x1 = normalizedX; bezier.y1 = normalizedY; break; + // } + // } + // else if (ImGui::IsMouseReleased(0)) + // { + // isDragging = false; + // selectedPoint = -1; + // ImGui::SetNextFrameWantCaptureMouse(false); + // } + // } - drawList->AddLine(p1, p2, IM_COL32(255, 100, 100, 255), 2.0f); // Red curve - } - } + // ImGui::PopClipRect(); + // ImGui::End(); + //} + // + //static LevelData currentLevelData; - void DrawBSplineEditorWithCanvas() { - static int selectedPoint = -1; // Index of the currently selected point - static bool isDragging = false; - ImGui::Begin("B-Spline Editor"); - - // Canvas setup - ImVec2 canvasSize = ImVec2(400, 400); - ImVec2 canvasPos = ImGui::GetCursorScreenPos(); - ImDrawList* drawList = ImGui::GetWindowDrawList(); - - // Draw canvas background and border - drawList->AddRectFilled(canvasPos, canvasPos + canvasSize, IM_COL32(50, 50, 50, 255)); // Dark background - drawList->AddRect(canvasPos, canvasPos + canvasSize, IM_COL32(255, 255, 255, 255)); // White border - - // Transformations for control points - float scale = canvasSize.x * 0.8f; - ImVec2 offset = ImVec2(canvasPos.x + canvasSize.x * 0.1f, canvasPos.y + canvasSize.y * 0.1f); - - // Draw control polygon - if (controlPoints.size() > 1) { - for (size_t i = 0; i < controlPoints.size() - 1; ++i) { - ImVec2 p1 = ImVec2(offset.x + controlPoints[i].x * scale, offset.y + controlPoints[i].y * scale); - ImVec2 p2 = ImVec2(offset.x + controlPoints[i + 1].x * scale, offset.y + controlPoints[i + 1].y * scale); - drawList->AddLine(p1, p2, IM_COL32(150, 150, 150, 255), 2.0f); // Grey line - } - } - - // Draw and handle control points - for (size_t i = 0; i < controlPoints.size(); ++i) { - ImVec2 pointPos = ImVec2(offset.x + controlPoints[i].x * scale, offset.y + controlPoints[i].y * scale); - - // Draw point - drawList->AddCircleFilled(pointPos, 5.0f, IM_COL32(255, 255, 0, 255)); // Yellow point - - // Check for mouse interaction - if (ImGui::IsMouseHoveringRect(canvasPos, canvasPos + canvasSize)) { - ImVec2 mousePos = ImGui::GetMousePos(); - float distance = std::hypot(pointPos.x - mousePos.x, pointPos.y - mousePos.y); - - // Handle selection - if (distance < 10.0f && ImGui::IsMouseClicked(0)) { - selectedPoint = i; - isDragging = true; - } - } - } - - // Handle dragging - if (isDragging && selectedPoint != -1) { - if (ImGui::IsMouseDragging(0)) { - ImVec2 mousePos = ImGui::GetMousePos(); - float normalizedX = (mousePos.x - offset.x) / scale; - float normalizedY = (mousePos.y - offset.y) / scale; - - // Clamp the point within canvas bounds - controlPoints[selectedPoint].x = std::clamp(normalizedX, 0.0f, 1.0f); - controlPoints[selectedPoint].y = std::clamp(normalizedY, 0.0f, 1.0f); - } - else if (ImGui::IsMouseReleased(0)) { - isDragging = false; - selectedPoint = -1; - } - } - - // Draw B-spline curve - RenderBSplineInCanvas(controlPoints, degree, resolution, offset, scale, drawList); - - ImGui::End(); - } + //void renderLevelDataEditor() + //{ + // ImGui::Begin("Level Data Editor"); + + // GJBaseGameLayer* layer = nullptr; + // if (PlayLayer::get()) { layer = PlayLayer::get(); } + // else if (LevelEditorLayer::get()) { layer = LevelEditorLayer::get(); } + // if (layer) + // { + // try + // { + // if (ImGui::Button("Load Level Data")) { currentLevelData = getLevelData(layer); } + // if (ImGui::Button("Save Level Data")) { setLevelData(layer, currentLevelData); } + // } + // catch (...) + // { + // } + // } - void DrawBSplineEditor() { - ImGui::Begin("B-Spline Editor"); + // if (ImGui::Button("Reset Data")) + // { + // currentLevelData = LevelData::getDefault(); + // } - // Spline Degree - ImGui::SliderInt("Spline Degree", °ree, 1, 5); + // ImGui::Separator(); - // Toggle Control Polygon Visibility - ImGui::Checkbox("Show Control Polygon", &showControlPolygon); + // // Edit Bezier curve fields + // ImGui::Text("Bezier Curve:"); + // ImGui::InputDouble("Start X", ¤tLevelData.bezierCurve.x0); + // ImGui::InputDouble("Start Y", ¤tLevelData.bezierCurve.y0); + // ImGui::InputDouble("Control 1 X", ¤tLevelData.bezierCurve.cx1); + // ImGui::InputDouble("Control 1 Y", ¤tLevelData.bezierCurve.cy1); + // ImGui::InputDouble("Control 2 X", ¤tLevelData.bezierCurve.cx2); + // ImGui::InputDouble("Control 2 Y", ¤tLevelData.bezierCurve.cy2); + // ImGui::InputDouble("End X", ¤tLevelData.bezierCurve.x1); + // ImGui::InputDouble("End Y", ¤tLevelData.bezierCurve.y1); + // ImGui::InputDouble("Bezier Multiplier", ¤tLevelData.bezierMultiplier); - // Resolution - ImGui::SliderInt("Curve Resolution", &resolution, 10, 500); + // ImGui::Separator(); - // Control Points - if (ImGui::Button("Add Control Point")) { - controlPoints.push_back({ 0.0f, 0.0f }); - } + // ImGui::Text("Position:"); + // ImGui::InputDouble("X", ¤tLevelData.x); + // ImGui::InputDouble("Y", ¤tLevelData.y); + // ImGui::InputDouble("Z", ¤tLevelData.z); - for (size_t i = 0; i < controlPoints.size(); ++i) { - ImGui::PushID(i); - ImGui::DragFloat2("Point", &controlPoints[i].x, 0.1f); - if (ImGui::Button("Remove")) { - controlPoints.erase(controlPoints.begin() + i); - ImGui::PopID(); - continue; - } - ImGui::PopID(); - } + // ImGui::Text("Rotation:"); + // ImGui::InputDouble("Yaw", ¤tLevelData.yaw); + // ImGui::InputDouble("Pitch", ¤tLevelData.pitch); + // ImGui::Checkbox("Lock Camera", ¤tLevelData.lock); - ImGui::End(); - } + // ImGui::Separator(); + // ImGui::Text("Camera Actions:"); + + // for (size_t i = 0; i < currentLevelData.actions.size(); ++i) + // { + // ImGui::PushID(static_cast(i)); + // ImGui::Text("Action %d:", static_cast(i + 1)); + // CameraAction& action = currentLevelData.actions[i]; + + // ImGui::InputDouble("X##Action", &action.x); + // ImGui::InputDouble("Y##Action", &action.y); + // ImGui::InputDouble("Z##Action", &action.z); + // ImGui::InputDouble("Yaw##Action", &action.yaw); + // ImGui::InputDouble("Pitch##Action", &action.pitch); + // ImGui::InputDouble("Time##Action", &action.time); + // ImGui::InputDouble("TriggerAt##Action", &action.triggerAt); + + // if (ImGui::Button("Remove Action")) + // { + // currentLevelData.actions.erase(currentLevelData.actions.begin() + i); + // ImGui::PopID(); + // break; + // } + + // ImGui::Separator(); + // ImGui::PopID(); + // } + + // if (ImGui::Button("Add Action")) { currentLevelData.actions.push_back({}); } + + // ImGui::End(); + //} + + //bool isTabKeyPressed() + //{ + // return (GetAsyncKeyState(VK_TAB) & 0x8000) != 0; + //} + + //// ------------ spline + + //static inline float ImLengthSqr(const ImVec2& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y); } + //static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); } + //static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); } + //static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } + //static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } + //static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } + //static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); } + //static inline ImVec2 operator-(const ImVec2& lhs) { return ImVec2(-lhs.x, -lhs.y); } + + //struct ControlPoint { + // float x, y; + //}; + + //// Globals + //std::vector controlPoints; + //int degree = 3; // Default spline degree + //bool showControlPolygon = true; + //int resolution = 100; // Number of points to evaluate on the spline + + //ControlPoint DeBoor(int k, int degree, float t, const std::vector& knots, const std::vector& points) { + // std::vector d = points; + // for (int r = 1; r <= degree; ++r) { + // for (int j = k; j > k - r; --j) { + // float denominator = knots[j + degree - r + 1] - knots[j]; + // float alpha = denominator == 0.0f ? 0.0f : (t - knots[j]) / denominator; + // d[j].x = (1.0f - alpha) * d[j - 1].x + alpha * d[j].x; + // d[j].y = (1.0f - alpha) * d[j - 1].y + alpha * d[j].y; + // } + // } + // return d[k]; + //} + + //std::vector GenerateUniformKnots(int n, int degree) { + // int knotCount = n + degree + 2; + // std::vector knots(knotCount); + // for (int i = 0; i < knotCount; ++i) { + // if (i < degree) { + // knots[i] = 0.0f; // Repeat start knots + // } + // else if (i > n) { + // knots[i] = static_cast(n - degree + 1); // Repeat end knots + // } + // else { + // knots[i] = static_cast(i - degree); + // } + // } + // return knots; + //} + + //std::vector ComputeBSpline(const std::vector& points, int degree, int resolution) { + // std::vector result; + // if (points.size() < degree + 1) return result; + // int n = points.size() - 1; + // std::vector knots = GenerateUniformKnots(n, degree); + // float step = (knots[n + 1] - knots[degree]) / static_cast(resolution - 1); + // for (float t = knots[degree]; t <= knots[n + 1] + step / 2; t += step) { + // // Clamp t to ensure it doesn't exceed the range + // if (t > knots[n + 1]) t = knots[n + 1]; + // // Find the knot span index k + // int k = n; + // for (int i = degree; i <= n; ++i) { + // if (t >= knots[i] && t < knots[i + 1]) { + // k = i; + // break; + // } + // } + // result.push_back(DeBoor(k, degree, t, knots, points)); + // } + // return result; + //} + + //void RenderBSplineInCanvas( + // const std::vector& controlPoints, + // int degree, + // int resolution, + // const ImVec2& offset, + // float scale, + // ImDrawList* drawList + //) { + // if (controlPoints.size() < degree + 1) return; + // std::vector splinePoints = ComputeBSpline(controlPoints, degree, resolution); + // for (size_t i = 0; i < splinePoints.size() - 1; ++i) { + // ImVec2 p1 = ImVec2(offset.x + splinePoints[i].x * scale, offset.y + splinePoints[i].y * scale); + // ImVec2 p2 = ImVec2(offset.x + splinePoints[i + 1].x * scale, offset.y + splinePoints[i + 1].y * scale); + // drawList->AddLine(p1, p2, IM_COL32(255, 100, 100, 255), 2.0f); // Red curve + // } + //} + + //void DrawBSplineEditorWithCanvas() { + // static int selectedPoint = -1; // Index of the currently selected point + // static bool isDragging = false; + // ImGui::Begin("B-Spline Editor"); + // // Canvas setup + // ImVec2 canvasSize = ImVec2(400, 400); + // ImVec2 canvasPos = ImGui::GetCursorScreenPos(); + // ImDrawList* drawList = ImGui::GetWindowDrawList(); + // // Draw canvas background and border + // drawList->AddRectFilled(canvasPos, canvasPos + canvasSize, IM_COL32(50, 50, 50, 255)); // Dark background + // drawList->AddRect(canvasPos, canvasPos + canvasSize, IM_COL32(255, 255, 255, 255)); // White border + // // Transformations for control points + // float scale = canvasSize.x * 0.8f; + // ImVec2 offset = ImVec2(canvasPos.x + canvasSize.x * 0.1f, canvasPos.y + canvasSize.y * 0.1f); + // // Draw control polygon + // if (controlPoints.size() > 1) { + // for (size_t i = 0; i < controlPoints.size() - 1; ++i) { + // ImVec2 p1 = ImVec2(offset.x + controlPoints[i].x * scale, offset.y + controlPoints[i].y * scale); + // ImVec2 p2 = ImVec2(offset.x + controlPoints[i + 1].x * scale, offset.y + controlPoints[i + 1].y * scale); + // drawList->AddLine(p1, p2, IM_COL32(150, 150, 150, 255), 2.0f); // Grey line + // } + // } + // // Draw and handle control points + // for (size_t i = 0; i < controlPoints.size(); ++i) { + // ImVec2 pointPos = ImVec2(offset.x + controlPoints[i].x * scale, offset.y + controlPoints[i].y * scale); + // // Draw point + // drawList->AddCircleFilled(pointPos, 5.0f, IM_COL32(255, 255, 0, 255)); // Yellow point + // // Check for mouse interaction + // if (ImGui::IsMouseHoveringRect(canvasPos, canvasPos + canvasSize)) { + // ImVec2 mousePos = ImGui::GetMousePos(); + // float distance = std::hypot(pointPos.x - mousePos.x, pointPos.y - mousePos.y); + // // Handle selection + // if (distance < 10.0f && ImGui::IsMouseClicked(0)) { + // selectedPoint = i; + // isDragging = true; + // } + // } + // } + // // Handle dragging + // if (isDragging && selectedPoint != -1) { + // if (ImGui::IsMouseDragging(0)) { + // ImVec2 mousePos = ImGui::GetMousePos(); + // float normalizedX = (mousePos.x - offset.x) / scale; + // float normalizedY = (mousePos.y - offset.y) / scale; + // // Clamp the point within canvas bounds + // controlPoints[selectedPoint].x = std::clamp(normalizedX, 0.0f, 1.0f); + // controlPoints[selectedPoint].y = std::clamp(normalizedY, 0.0f, 1.0f); + // } + // else if (ImGui::IsMouseReleased(0)) { + // isDragging = false; + // selectedPoint = -1; + // } + // } + // // Draw B-spline curve + // RenderBSplineInCanvas(controlPoints, degree, resolution, offset, scale, drawList); + // ImGui::End(); + //} + + + //void DrawBSplineEditor() { + // ImGui::Begin("B-Spline Editor"); + // // Spline Degree + // ImGui::SliderInt("Spline Degree", °ree, 1, 5); + // // Toggle Control Polygon Visibility + // ImGui::Checkbox("Show Control Polygon", &showControlPolygon); + // // Resolution + // ImGui::SliderInt("Curve Resolution", &resolution, 10, 500); + // // Control Points + // if (ImGui::Button("Add Control Point")) { + // controlPoints.push_back({ 0.0f, 0.0f }); + // } + // for (size_t i = 0; i < controlPoints.size(); ++i) { + // ImGui::PushID(i); + // ImGui::DragFloat2("Point", &controlPoints[i].x, 0.1f); + // if (ImGui::Button("Remove")) { + // controlPoints.erase(controlPoints.begin() + i); + // ImGui::PopID(); + // continue; + // } + // ImGui::PopID(); + // } + // ImGui::End(); + //} // -------------------- void renderImGui() { - static bool showEditorWindow = false; - static bool prevTabState = false; - bool currentTabState = isTabKeyPressed(); - if (currentTabState && !prevTabState) { showEditorWindow = !showEditorWindow; } - prevTabState = currentTabState; - if (showEditorWindow) - { - //renderBezierEditor(currentLevelData.bezierCurve); - //renderLevelDataEditor(); - //DrawBSplineEditor(); - //DrawBSplineEditorWithCanvas(); - } + //static bool showEditorWindow = false; + //static bool prevTabState = false; + //bool currentTabState = isTabKeyPressed(); + //if (currentTabState && !prevTabState) { showEditorWindow = !showEditorWindow; } + //prevTabState = currentTabState; + //if (showEditorWindow) + //{ + // //renderBezierEditor(currentLevelData.bezierCurve); + // //renderLevelDataEditor(); + // //DrawBSplineEditor(); + // //DrawBSplineEditorWithCanvas(); + //} } //class $modify(PlayLayer) diff --git a/Geome3Dash/src/engine/sus3d/Model.cpp b/Geome3Dash/src/engine/sus3d/Model.cpp index 3c158a95..e6c2b24a 100644 --- a/Geome3Dash/src/engine/sus3d/Model.cpp +++ b/Geome3Dash/src/engine/sus3d/Model.cpp @@ -26,12 +26,12 @@ namespace sus3d model = glm::translate(model, position); - if (rotation.x) - model = glm::rotate(model, glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f)); - if (rotation.y) - model = glm::rotate(model, glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f)); if (rotation.z) model = glm::rotate(model, glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f)); + if (rotation.y) + model = glm::rotate(model, glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f)); + if (rotation.x) + model = glm::rotate(model, glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f)); model = glm::scale(model, scale); diff --git a/Geome3Dash/src/game/editor/G3DCurveEditorLoader.cpp b/Geome3Dash/src/game/editor/G3DCurveEditorLoader.cpp index 1d538ff0..4f265bf5 100644 --- a/Geome3Dash/src/game/editor/G3DCurveEditorLoader.cpp +++ b/Geome3Dash/src/game/editor/G3DCurveEditorLoader.cpp @@ -13,6 +13,7 @@ #include "engine/sus3d/Shaders.h" #include "BlockModelStorage.h" +#include "LevelDataManager.h" namespace g3d { @@ -21,27 +22,19 @@ namespace g3d CCObject* obj; CCARRAY_FOREACH(lel->m_objects, obj) { - auto block = static_cast(obj); + auto block = dynamic_cast(obj); levelLength = std::max(block->getPositionX(), levelLength); } - lengthScaleFactor = spline->length(10000) / levelLength; + lengthScaleFactor = spline.length(10000) / levelLength; } - bool G3DCurveEditorLoader::init(LevelEditorLayer* lel, Spline* defaultSpline) { + bool G3DCurveEditorLoader::init(LevelEditorLayer* lel) { if (!CCNode::init()) return false; this->lel = lel; - if (defaultSpline) { - spline = defaultSpline; - } - else { - spline = new Spline(); - spline->addSegment(new Curve(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(2.0f, 0.0f, 0.0f), glm::vec3(3.0f, 0.0f, 0.0f))); - } - layer3d = G3DBaseNode::create(); layer3d->camera.setPosition(glm::vec3(0, 0, 15)); layer3d->light.setPosition(glm::vec3(0, 50, 1000)); @@ -54,29 +47,24 @@ namespace g3d pointModel = bms->getModel(bms->getBP() / "editor" / "model" / "sphere.obj"); - updateLevel(); - spline->updateParameterList(); - return true; } - - void G3DCurveEditorLoader::addSegment() { - auto p1 = spline->segments.back()->p2; - auto m1 = spline->segments.back()->p2 * 2.f - spline->segments.back()->m2; - auto m2 = spline->segments.back()->p2 * 2.f - spline->segments.back()->m1; - auto p2 = spline->segments.back()->p2 * 2.f - spline->segments.back()->p1; + auto p1 = spline.segments.back().p2; + auto m1 = spline.segments.back().p2 * 2.f - spline.segments.back().m2; + auto m2 = spline.segments.back().p2 * 2.f - spline.segments.back().m1; + auto p2 = spline.segments.back().p2 * 2.f - spline.segments.back().p1; - spline->addSegment(new Curve(p1, m1, m2, p2)); + spline.addSegment(Curve(p1, m1, m2, p2)); updateLevel(); } void G3DCurveEditorLoader::removeSegment() { - if (spline->segments.size() > 1) { - spline->removeLastSegment(); + if (spline.segments.size() > 1) { + spline.removeLastSegment(); updateLevel(); } } @@ -87,9 +75,9 @@ namespace g3d } - G3DCurveEditorLoader* G3DCurveEditorLoader::create(LevelEditorLayer* lel, Spline* defaultSpline) { + G3DCurveEditorLoader* G3DCurveEditorLoader::create(LevelEditorLayer* lel) { auto ret = new G3DCurveEditorLoader(); - if (ret && ret->init(lel, defaultSpline)) { + if (ret && ret->init(lel)) { ret->autorelease(); return ret; } diff --git a/Geome3Dash/src/game/editor/G3DCurveEditorLoader.h b/Geome3Dash/src/game/editor/G3DCurveEditorLoader.h index eb7c52a4..9f36ea6f 100644 --- a/Geome3Dash/src/game/editor/G3DCurveEditorLoader.h +++ b/Geome3Dash/src/game/editor/G3DCurveEditorLoader.h @@ -4,6 +4,8 @@ #include "delegate/CustomMouse.h" #include "delegate/CustomTouch.h" +#include "helper/spline/Spline.h" + namespace sus3d { class Model; @@ -24,7 +26,7 @@ namespace g3d float levelLength = 0; float lengthScaleFactor; - virtual bool init(LevelEditorLayer* lel, Spline* defaultSpline); + virtual bool init(LevelEditorLayer* lel); void updateLevel(); @@ -32,10 +34,10 @@ namespace g3d void removeSegment(); public: - Spline* spline; + Spline spline; void show(); - static G3DCurveEditorLoader* create(LevelEditorLayer* lel, Spline* defaultSpline = nullptr); + static G3DCurveEditorLoader* create(LevelEditorLayer* lel); friend class KeyframeEditorLayer; friend class G3DCurveEditorPopup; diff --git a/Geome3Dash/src/game/editor/G3DCurveEditorPopup.cpp b/Geome3Dash/src/game/editor/G3DCurveEditorPopup.cpp index 3cbcdf7d..2c3a9d4b 100644 --- a/Geome3Dash/src/game/editor/G3DCurveEditorPopup.cpp +++ b/Geome3Dash/src/game/editor/G3DCurveEditorPopup.cpp @@ -13,9 +13,11 @@ #include "engine/sus3d/Shaders.h" #include "BlockModelStorage.h" +#include "LevelDataManager.h" namespace g3d { + static LevelData currentLevelData = LevelData::getDefault(); void G3DCurveEditorPopup::onGLFWMouseCallBack(GLFWwindow* window, int button, int action, int mods) { if (!this->isVisible()) return; @@ -71,7 +73,7 @@ namespace g3d mesh->render(cel->layer3d->getObjectIDByMousePositionShader); }; - auto points = cel->spline->getAllPoints(); + auto points = cel->spline.getAllPoints(); for (int pointIndex = 0; pointIndex < points.size(); pointIndex++) { @@ -103,7 +105,7 @@ namespace g3d newPosition -= tangent * (deltaX * 0.01f); newPosition -= bionormal * (deltaY * 0.01f); - cel->spline->editPointSymmetricCenterFix(selected, newPosition); + cel->spline.editPointSymmetricCenterFix(selected, newPosition); } else if (isPressingControl) { @@ -160,11 +162,26 @@ namespace g3d } void G3DCurveEditorPopup::onClose(CCObject* obj) { + currentLevelData.spline = cel->spline; + setLevelData(LevelEditorLayer::get(), currentLevelData); this->setMouseEnabled(false); Popup::onClose(obj); } bool G3DCurveEditorPopup::setup(G3DCurveEditorLoader* cel) { + + currentLevelData = LevelData::getDefault(); + try { + currentLevelData = getLevelData(LevelEditorLayer::get()); + } + catch (...) { + + } + cel->spline = currentLevelData.spline; + cel->updateLevel(); + cel->spline.updateParameterList(); + + this->setMouseEnabled(true); this->cel = cel; @@ -222,30 +239,30 @@ namespace g3d void G3DCurveEditorPopup::draw() { if (!isRightClicking) { - cel->spline->updateParameterList(); + cel->spline.updateParameterList(); } auto shaderProgram = BlockModelStorage::get()->getBlockSP(); OpenGLStateHelper::saveState(); - for (auto segment : cel->spline->segments) { + for (auto segment : cel->spline.segments) { cel->pointModel->meshes[0]->setCustomKa(glm::vec3(1, 0, 0)); cel->pointModel->setScale(glm::vec3(0.07)); - cel->pointModel->setPosition(segment->p1); + cel->pointModel->setPosition(segment.p1); cel->pointModel->render(shaderProgram, cel->layer3d->camera.getViewMat(), cel->layer3d->light.getPosition(), cel->layer3d->light.getColor(), cel->layer3d->camera.getPosition(), cel->layer3d->camera.getProjectionMat()); - cel->pointModel->setPosition(segment->p2); + cel->pointModel->setPosition(segment.p2); cel->pointModel->render(shaderProgram, cel->layer3d->camera.getViewMat(), cel->layer3d->light.getPosition(), cel->layer3d->light.getColor(), cel->layer3d->camera.getPosition(), cel->layer3d->camera.getProjectionMat()); cel->pointModel->meshes[0]->setCustomKa(glm::vec3(0, 1, 0)); cel->pointModel->setScale(glm::vec3(0.05)); - cel->pointModel->setPosition(segment->m1); + cel->pointModel->setPosition(segment.m1); cel->pointModel->render(shaderProgram, cel->layer3d->camera.getViewMat(), cel->layer3d->light.getPosition(), cel->layer3d->light.getColor(), cel->layer3d->camera.getPosition(), cel->layer3d->camera.getProjectionMat()); - cel->pointModel->setPosition(segment->m2); + cel->pointModel->setPosition(segment.m2); cel->pointModel->render(shaderProgram, cel->layer3d->camera.getViewMat(), cel->layer3d->light.getPosition(), cel->layer3d->light.getColor(), cel->layer3d->camera.getPosition(), cel->layer3d->camera.getProjectionMat()); } for (float i = 0; i < 3; i += 0.005) { - cel->pointModel->setPosition(cel->spline->get(i)); + cel->pointModel->setPosition(cel->spline.get(i)); cel->pointModel->meshes[0]->setCustomKa(glm::vec3(0.5, 0.5, 0.5)); cel->pointModel->setScale(glm::vec3(0.001)); cel->pointModel->render(shaderProgram, cel->layer3d->camera.getViewMat(), cel->layer3d->light.getPosition(), cel->layer3d->light.getColor(), cel->layer3d->camera.getPosition(), cel->layer3d->camera.getProjectionMat()); @@ -253,26 +270,24 @@ namespace g3d CCObject* obj; - CCARRAY_FOREACH(cel->lel->m_objects, obj) { + CCARRAY_FOREACH(cel->lel->m_objects, obj) + { auto block = static_cast(obj); - auto data = cel->spline->findClosestByLength(block->getPositionX() * cel->lengthScaleFactor); + auto data = cel->spline.findClosestByLength(block->getPositionX() * cel->lengthScaleFactor); auto pos = data.value; - auto normal = glm::normalize(cel->spline->normal(data.t)); - auto tangent = glm::normalize(cel->spline->tangent(data.t)); + auto normal = glm::normalize(cel->spline.normal(data.t)); + auto tangent = glm::normalize(cel->spline.tangent(data.t)); glm::vec3 side(1.f, 0.f, 0.f); float normalDeltaAngle = glm::radians(block->getRotation()); glm::quat firstRotationQuat = glm::angleAxis(normalDeltaAngle, side); - - glm::vec3 binormal = glm::normalize(glm::cross(normal, tangent)); glm::vec3 adjustedNormal = glm::normalize(glm::cross(tangent, binormal)); - glm::mat3 rotationMatrix( binormal, adjustedNormal, diff --git a/Geome3Dash/src/game/playing/G3DPlayLayer.cpp b/Geome3Dash/src/game/playing/G3DPlayLayer.cpp index 046e3f09..7b2ccc58 100644 --- a/Geome3Dash/src/game/playing/G3DPlayLayer.cpp +++ b/Geome3Dash/src/game/playing/G3DPlayLayer.cpp @@ -43,17 +43,17 @@ namespace g3d playerCameraOffset = glm::vec3(data.x, data.y, data.z); playerCameraYawOffset = data.yaw; playerCameraPitchOffset = data.pitch; - bezier = data.bezierCurve; - constexpr double bezierM = 1000; - bezier.cx1 *= bezierM; - bezier.cx2 *= bezierM; - bezier.cy1 *= bezierM; - bezier.cy2 *= bezierM; - bezier.x0 *= bezierM; - bezier.x1 *= bezierM; - bezier.y0 *= bezierM; - bezier.y1 *= bezierM; - bezierSegmentMultiplier = 1.0 / data.bezierMultiplier; + //bezier = data.bezierCurve; + //constexpr double bezierM = 1000; + //bezier.cx1 *= bezierM; + //bezier.cx2 *= bezierM; + //bezier.cy1 *= bezierM; + //bezier.cy2 *= bezierM; + //bezier.x0 *= bezierM; + //bezier.x1 *= bezierM; + //bezier.y0 *= bezierM; + //bezier.y1 *= bezierM; + //bezierSegmentMultiplier = 1.0 / data.bezierMultiplier; bezierTr = new BezierGameObjectModelTransformer(bezier, bezierSegmentMultiplier, bezierSegmentCount); fadeTr = new FadeGameObjectModelTransformer(playLayer, 700, 400, ease::InOutSine::get(), glm::vec3(0, 0, 0)); diff --git a/Geome3Dash/src/helper/spline/Curve.h b/Geome3Dash/src/helper/spline/Curve.h index 422c305d..b3205d75 100644 --- a/Geome3Dash/src/helper/spline/Curve.h +++ b/Geome3Dash/src/helper/spline/Curve.h @@ -1,17 +1,39 @@ #pragma once +#include +#include + +namespace nlohmann { + template <> + struct adl_serializer { + static void to_json(json& j, const glm::vec3& vec) { + j = json{ {"x", vec.x}, {"y", vec.y}, {"z", vec.z} }; + } + + static void from_json(const json& j, glm::vec3& vec) { + j.at("x").get_to(vec.x); + j.at("y").get_to(vec.y); + j.at("z").get_to(vec.z); + } + }; +} + namespace g3d { - struct Curve { + struct Curve + { glm::vec3 p1; glm::vec3 m1; glm::vec3 m2; glm::vec3 p2; + NLOHMANN_DEFINE_TYPE_INTRUSIVE(Curve, p1, m1, p2, m2); + float p1NormalAngle = 0; float p2NormalAngle = 0; Curve(glm::vec3 p1, glm::vec3 m1, glm::vec3 m2, glm::vec3 p2); + Curve() {} glm::vec3 lerp(glm::vec3 p0, glm::vec3 p1, float t); diff --git a/Geome3Dash/src/helper/spline/Spline.cpp b/Geome3Dash/src/helper/spline/Spline.cpp index 8a40e559..b4b5eb52 100644 --- a/Geome3Dash/src/helper/spline/Spline.cpp +++ b/Geome3Dash/src/helper/spline/Spline.cpp @@ -38,58 +38,58 @@ namespace g3d std::vector ret; for (int i = 0; i < segments.size(); i++) { - ret.push_back(segments[i]->p1); - ret.push_back(segments[i]->m1); - ret.push_back(segments[i]->m2); + ret.push_back(segments[i].p1); + ret.push_back(segments[i].m1); + ret.push_back(segments[i].m2); } - ret.push_back(segments.back()->p2); + ret.push_back(segments.back().p2); return ret; } void Spline::editPointSymmetricCenterFix(int pointIndex, glm::vec3 position) { if (pointIndex == 0) { - auto deltaP1 = position - segments[0]->p1; - segments[0]->p1 = position; - segments[0]->m1 += deltaP1; + auto deltaP1 = position - segments[0].p1; + segments[0].p1 = position; + segments[0].m1 += deltaP1; parameterListShouldBeUpdated = true; return; } if (pointIndex == getPointsCount() - 1) { - auto deltaP1 = position - segments.back()->p2; - segments.back()->p2 = position; - segments.back()->m2 += deltaP1; + auto deltaP1 = position - segments.back().p2; + segments.back().p2 = position; + segments.back().m2 += deltaP1; parameterListShouldBeUpdated = true; return; } if (pointIndex == 1) { - segments[0]->m1 = position; + segments[0].m1 = position; parameterListShouldBeUpdated = true; return; } if (pointIndex == getPointsCount() - 2) { - segments.back()->m2 = position; + segments.back().m2 = position; parameterListShouldBeUpdated = true; return; } int segmentIndex = std::floor(pointIndex / 3); int offset = pointIndex % 3; - auto deltaP1 = position - segments[segmentIndex]->p1; + auto deltaP1 = position - segments[segmentIndex].p1; switch (offset) { case 0: - segments[segmentIndex]->p1 = position; - segments[segmentIndex - 1]->p2 = position; - segments[segmentIndex]->m1 += deltaP1; - segments[segmentIndex - 1]->m2 += deltaP1; + segments[segmentIndex].p1 = position; + segments[segmentIndex - 1].p2 = position; + segments[segmentIndex].m1 += deltaP1; + segments[segmentIndex - 1].m2 += deltaP1; break; case 1: - segments[segmentIndex]->m1 = position; - segments[segmentIndex - 1]->m2 = 2.f * segments[segmentIndex]->p1 - segments[segmentIndex]->m1; + segments[segmentIndex].m1 = position; + segments[segmentIndex - 1].m2 = 2.f * segments[segmentIndex].p1 - segments[segmentIndex].m1; break; case 2: - segments[segmentIndex]->m2 = position; - segments[segmentIndex + 1]->m1 = 2.f * segments[segmentIndex + 1]->p1 - segments[segmentIndex]->m2; + segments[segmentIndex].m2 = position; + segments[segmentIndex + 1].m1 = 2.f * segments[segmentIndex + 1].p1 - segments[segmentIndex].m2; break; } parameterListShouldBeUpdated = true; @@ -97,22 +97,22 @@ namespace g3d void Spline::editPointSymmetric(int pointIndex, glm::vec3 position) { if (pointIndex == 0) { - segments[0]->p1 = position; + segments[0].p1 = position; parameterListShouldBeUpdated = true; return; } if (pointIndex == getPointsCount() - 1) { - segments.back()->p2 = position; + segments.back().p2 = position; parameterListShouldBeUpdated = true; return; } if (pointIndex == 1) { - segments[0]->m1 = position; + segments[0].m1 = position; parameterListShouldBeUpdated = true; return; } if (pointIndex == getPointsCount() - 2) { - segments.back()->m2 = position; + segments.back().m2 = position; parameterListShouldBeUpdated = true; return; } @@ -121,16 +121,16 @@ namespace g3d int offset = pointIndex % 3; switch (offset) { case 0: - segments[segmentIndex]->p1 = position; - segments[segmentIndex - 1]->p2 = position; + segments[segmentIndex].p1 = position; + segments[segmentIndex - 1].p2 = position; break; case 1: - segments[segmentIndex]->m1 = position; - segments[segmentIndex - 1]->m2 = 2.f * segments[segmentIndex]->p1 - segments[segmentIndex]->m1; + segments[segmentIndex].m1 = position; + segments[segmentIndex - 1].m2 = 2.f * segments[segmentIndex].p1 - segments[segmentIndex].m1; break; case 2: - segments[segmentIndex]->m2 = position; - segments[segmentIndex + 1]->m1 = 2.f * segments[segmentIndex + 1]->p1 - segments[segmentIndex]->m2; + segments[segmentIndex].m2 = position; + segments[segmentIndex + 1].m1 = 2.f * segments[segmentIndex + 1].p1 - segments[segmentIndex].m2; break; } parameterListShouldBeUpdated = true; @@ -138,12 +138,12 @@ namespace g3d void Spline::editPoint(int pointIndex, glm::vec3 position) { if (pointIndex == 0) { - segments[0]->p1 = position; + segments[0].p1 = position; parameterListShouldBeUpdated = true; return; } if (pointIndex == getPointsCount() - 1) { - segments.back()->p2 = position; + segments.back().p2 = position; parameterListShouldBeUpdated = true; return; } @@ -152,20 +152,20 @@ namespace g3d int offset = pointIndex % 3; switch (offset) { case 0: - segments[segmentIndex]->p1 = position; - segments[segmentIndex - 1]->p2 = position; + segments[segmentIndex].p1 = position; + segments[segmentIndex - 1].p2 = position; break; case 1: - segments[segmentIndex]->m1 = position; + segments[segmentIndex].m1 = position; break; case 2: - segments[segmentIndex]->m2 = position; + segments[segmentIndex].m2 = position; break; } parameterListShouldBeUpdated = true; } - void Spline::addSegment(Curve* curve) { + void Spline::addSegment(const Curve& curve) { segments.push_back(curve); parameterListShouldBeUpdated = true; } @@ -179,7 +179,7 @@ namespace g3d float Spline::length(int stepsProCurve) { float totalLength = 0; for (int i = 0; i < segments.size(); i++) { - totalLength += segments[i]->length(stepsProCurve); + totalLength += segments[i].length(stepsProCurve); } return totalLength; @@ -208,7 +208,7 @@ namespace g3d size_t segmentIndex = static_cast(t); float localT = t - segmentIndex; - return segments[segmentIndex]->get(localT); + return segments[segmentIndex].get(localT); } glm::vec3 Spline::tangent(float t) { @@ -218,7 +218,7 @@ namespace g3d size_t segmentIndex = static_cast(t); float localT = t - segmentIndex; - return segments[segmentIndex]->tangent(localT); + return segments[segmentIndex].tangent(localT); } glm::vec3 Spline::normal(float t) { @@ -228,6 +228,6 @@ namespace g3d size_t segmentIndex = static_cast(t); float localT = t - segmentIndex; - return segments[segmentIndex]->normal(localT); + return segments[segmentIndex].normal(localT); } } \ No newline at end of file diff --git a/Geome3Dash/src/helper/spline/Spline.h b/Geome3Dash/src/helper/spline/Spline.h index 542aa596..2fd127a0 100644 --- a/Geome3Dash/src/helper/spline/Spline.h +++ b/Geome3Dash/src/helper/spline/Spline.h @@ -1,18 +1,23 @@ #pragma once +#include "Curve.h" + namespace g3d { - class Curve; - - struct Spline { - struct ParameterData { + struct Spline + { + struct ParameterData + { float t; glm::vec3 value; float l; ParameterData(float t, glm::vec3 value, float l) : t(t), value(value), l(l) {}; }; - std::vector segments; + std::vector segments; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(Spline, segments); + std::vector parameterList; bool parameterListShouldBeUpdated = true; @@ -26,7 +31,7 @@ namespace g3d void editPointSymmetric(int pointIndex, glm::vec3 position); void editPoint(int pointIndex, glm::vec3 position); - void addSegment(Curve* curve); + void addSegment(const Curve& curve); void removeLastSegment(); ParameterData findClosestByLength(float l); @@ -36,5 +41,7 @@ namespace g3d glm::vec3 normal(float t); float length(int stepsProCurve); + + Spline() {} }; } \ No newline at end of file diff --git a/Geome3Dash/src/hook/LevelEditorLayer.cpp b/Geome3Dash/src/hook/LevelEditorLayer.cpp index b85a59a2..cd8cc3fc 100644 --- a/Geome3Dash/src/hook/LevelEditorLayer.cpp +++ b/Geome3Dash/src/hook/LevelEditorLayer.cpp @@ -79,7 +79,7 @@ namespace g3d auto menu2 = CCMenuItemSpriteExtra::create(sprite2, this, menu_selector(LevelEditorLayerG3D::onSplineEditor)); addG3DMenu(1, "PATH", settingsButton, settingsMenu, menu2, sprite2); - m_fields->curveEditorLayer = G3DCurveEditorLoader::create(this, nullptr); + m_fields->curveEditorLayer = G3DCurveEditorLoader::create(this); this->addChild(m_fields->curveEditorLayer); return true;