diff --git a/src/engine/editor/EditorMath.cpp b/src/engine/editor/EditorMath.cpp index 82de0e575..2173fa0ad 100644 --- a/src/engine/editor/EditorMath.cpp +++ b/src/engine/editor/EditorMath.cpp @@ -226,6 +226,43 @@ bool IntersectRayTriangle(const Ray& ray, const Triangle& tri, const FVector& ob return t > EPSILON; } +bool IntersectRaySphere(const Ray& ray, const FVector& sphereCenter, float radius, float& t) { + const float EPSILON = 1e-6f; + + // Vector from ray origin to sphere center + FVector oc = ray.Origin - sphereCenter; + + // Quadratic equation coefficients + float a = ray.Direction.Dot(ray.Direction); + float b = 2.0f * oc.Dot(ray.Direction); + float c = oc.Dot(oc) - (radius * radius); + + // Compute discriminant + float discriminant = (b * b) - (4 * a * c); + + // No intersection if discriminant is negative + if (discriminant < 0) { + return false; + } + + // Compute nearest intersection point + float sqrtD = sqrtf(discriminant); + float t0 = (-b - sqrtD) / (2.0f * a); + float t1 = (-b + sqrtD) / (2.0f * a); + + // Select the closest valid intersection + if (t0 > EPSILON) { + t = t0; + return true; + } else if (t1 > EPSILON) { + t = t1; + return true; + } + + return false; // Sphere is behind the ray origin +} + + bool FindClosestObject(const Ray& ray, const std::vector& objects, GameObject& outObject, float& outDistance) { float closestDist = std::numeric_limits::max(); bool found = false; diff --git a/src/engine/editor/EditorMath.h b/src/engine/editor/EditorMath.h index 8b2f54080..7aafd3f3a 100644 --- a/src/engine/editor/EditorMath.h +++ b/src/engine/editor/EditorMath.h @@ -49,6 +49,7 @@ void Copy(MtxF* src, MtxF* dest); void Clear(MtxF* mf); bool IntersectRayTriangle(const Ray& ray, const Triangle& tri, const FVector& objectPos, float& t); +bool IntersectRaySphere(const Ray& ray, const FVector& sphereCenter, float radius, float& t); diff --git a/src/engine/editor/Gizmo.cpp b/src/engine/editor/Gizmo.cpp index 06437ff89..b7e37cf1e 100644 --- a/src/engine/editor/Gizmo.cpp +++ b/src/engine/editor/Gizmo.cpp @@ -42,67 +42,15 @@ void Gizmo::Load() { } void Gizmo::Tick() { - if (!Enabled) { - return; - } - - switch(SelectedHandle) { - case GizmoHandle::X_Axis: - Gizmo::Translate(); - break; - case GizmoHandle::Y_Axis: - Gizmo::Translate(); - break; - case GizmoHandle::Z_Axis: - Gizmo::Translate(); - break; - } -} - -std::pair Gizmo::GetBoundingBox(GizmoHandle handle) { - FVector min = Pos + HandleOffsets[(int)handle] - FVector(HandleSize, HandleSize, HandleSize); - FVector max = Pos + HandleOffsets[(int)handle] + FVector(HandleSize, HandleSize, HandleSize); - return {min, max}; -} - -void Gizmo::StartManipulation(GizmoHandle handle) { - printf("HANDLE SELECTED %d\n", (s32)handle); - auto wnd = GameEngine::Instance->context->GetWindow(); - - if (wnd->GetMouseState(Ship::LUS_MOUSE_BTN_LEFT)) { - switch(handle) { - case GizmoHandle::None: - break; - case GizmoHandle::Center: - break; - case GizmoHandle::X_Axis: - break; - case GizmoHandle::Y_Axis: - break; - case GizmoHandle::Z_Axis: - break; - } + if (Enabled) { + Gizmo::Translate(); } } +// Makes the gizmo visible void Gizmo::Enable(GameObject* object, Ray ray) { static float length = 180.0f; // Default value - // static AActor* lastSelected = nullptr; - // if (object != lastSelected) { - // length = sqrt( - // pow(object->Pos[0] - cameras[0].pos[0], 2) + - // pow(object->Pos[1] - cameras[0].pos[1], 2) + - // pow(object->Pos[2] - cameras[0].pos[2], 2) - // ); - // lastSelected = object; - // } - - //_selected->Pos[0] = cameras[0].pos[0] + ray.x * length; - //object->Pos[1] = cameras[0].pos[1] + ray.y * length; - //_selected->Pos[2] = cameras[0].pos[2] + ray.z * length; - - _selected = object; _ray = ray.Direction; Pos = FVector( @@ -129,9 +77,14 @@ void Gizmo::Translate() { ); switch(SelectedHandle) { + case GizmoHandle::All_Axis: + _selected->Pos->x = (cameras[0].pos[0] + _ray.x * PickDistance) + _cursorOffset.x; + _selected->Pos->y = (cameras[0].pos[1] + _ray.y * PickDistance) + _cursorOffset.y; + _selected->Pos->z = (cameras[0].pos[2] + _ray.z * PickDistance) + _cursorOffset.z; + break; case GizmoHandle::X_Axis: _selected->Pos->x = (cameras[0].pos[0] + _ray.x * length) + _cursorOffset.x; - break; + break; case GizmoHandle::Y_Axis: _selected->Pos->y = (cameras[0].pos[1] + _ray.y * length) + _cursorOffset.y; break; diff --git a/src/engine/editor/Gizmo.h b/src/engine/editor/Gizmo.h index a65fb318b..f7d556f73 100644 --- a/src/engine/editor/Gizmo.h +++ b/src/engine/editor/Gizmo.h @@ -10,7 +10,7 @@ public: enum class GizmoHandle { None, - Center, + All_Axis, X_Axis, Y_Axis, Z_Axis @@ -22,14 +22,11 @@ public: void Draw(); void Load(); - void StartManipulation(GizmoHandle handle); void Enable(GameObject* object, Ray ray); void Translate(); void DrawHandles(); - std::pair GetBoundingBox(GizmoHandle handle); - bool Enabled; GizmoHandle SelectedHandle; @@ -38,7 +35,9 @@ public: GameObject BlueCollision; FVector Pos; // Global scene view - float _gizmoOffset = 5.0f; + float _gizmoOffset = 8.0f; + float AllAxisRadius = 4.0f; // Free move selection radius + float PickDistance; FVector _cursorOffset; FVector RedPos = {0, 0, -_gizmoOffset}; // Local model view FVector GreenPos = {-_gizmoOffset, 0, 0}; // Local model view @@ -46,12 +45,6 @@ public: float HandleSize = 2.0f; - FVector HandleOffsets[4] = { - {0, 0, 0}, // Center Button - {0, 0, -5}, // X-Axis (Red) - {0, 5, 0}, // Y-Axis (Green) - {-5, 0, 0} // Z-Axis (Blue) - }; FVector _ray; GameObject* _selected = nullptr; private: diff --git a/src/engine/editor/ObjectPicker.cpp b/src/engine/editor/ObjectPicker.cpp index c68af8509..fdd08089f 100644 --- a/src/engine/editor/ObjectPicker.cpp +++ b/src/engine/editor/ObjectPicker.cpp @@ -67,14 +67,22 @@ void ObjectPicker::DragHandle() { // Is the gizmo being dragged? if (eGizmo.Enabled) { + float t; + if (IntersectRaySphere(ray, eGizmo.Pos, eGizmo.AllAxisRadius, t)) { + eGizmo.SelectedHandle = Gizmo::GizmoHandle::All_Axis; + eGizmo._ray = ray.Direction; + FVector clickPosition = ray.Origin + ray.Direction * t; + eGizmo._cursorOffset = eGizmo.Pos - clickPosition; + eGizmo.PickDistance = t; + return; + } + for (auto tri = eGizmo.RedCollision.Triangles.begin(); tri < eGizmo.RedCollision.Triangles.end(); tri++) { float t; FVector pos = FVector(eGizmo.Pos.x, eGizmo.Pos.y, eGizmo.Pos.z - eGizmo._gizmoOffset); if (IntersectRayTriangle(ray, *tri, pos, t)) { - //eGizmo.StartManipulation(Gizmo::GizmoHandle::X_Axis); eGizmo.SelectedHandle = Gizmo::GizmoHandle::Z_Axis; eGizmo._ray = ray.Direction; - FVector clickPosition = ray.Origin + ray.Direction * t; eGizmo._cursorOffset = eGizmo.Pos - clickPosition; return; // Stop checking objects if we selected a Gizmo handle @@ -85,9 +93,10 @@ void ObjectPicker::DragHandle() { float t; FVector pos = FVector(eGizmo.Pos.x - eGizmo._gizmoOffset, eGizmo.Pos.y, eGizmo.Pos.z); if (IntersectRayTriangle(ray, *tri, pos, t)) { - //eGizmo.StartManipulation(Gizmo::GizmoHandle::Y_Axis); eGizmo.SelectedHandle = Gizmo::GizmoHandle::X_Axis; eGizmo._ray = ray.Direction; + FVector clickPosition = ray.Origin + ray.Direction * t; + eGizmo._cursorOffset = eGizmo.Pos - clickPosition; return; // Stop checking objects if we selected a Gizmo handle } } @@ -98,6 +107,8 @@ void ObjectPicker::DragHandle() { if (IntersectRayTriangle(ray, *tri, pos, t)) { eGizmo.SelectedHandle = Gizmo::GizmoHandle::Y_Axis; eGizmo._ray = ray.Direction; + FVector clickPosition = ray.Origin + ray.Direction * t; + eGizmo._cursorOffset = eGizmo.Pos - clickPosition; return; // Stop checking objects if we selected a Gizmo handle } }