From b82a828f46252d99954d2cedbcf89db1d9dd6622 Mon Sep 17 00:00:00 2001 From: RDW Date: Thu, 23 Nov 2023 18:27:07 +0100 Subject: [PATCH 1/2] Core: Add a setting for the camera target position Can't exactly adjust it for debugging while it's still hardcoded. --- Core/NativeClient/C_Camera.lua | 15 ++++++++++++- Core/NativeClient/Renderer.lua | 4 ++-- Tests/NativeClient/C_Camera.spec.lua | 32 ++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/Core/NativeClient/C_Camera.lua b/Core/NativeClient/C_Camera.lua index 9e4ec0f3..49997cfb 100644 --- a/Core/NativeClient/C_Camera.lua +++ b/Core/NativeClient/C_Camera.lua @@ -29,6 +29,7 @@ local C_Camera = { DEGREES_PER_ZOOM_LEVEL = 5, MIN_ORBIT_DISTANCE = 45, MAX_ORBIT_DISTANCE = 80, + targetWorldPosition = Vector3D(0, 0, 0), } function C_Camera.CreatePerspectiveProjection(verticalFieldOfViewInDegrees, aspectRatio, zNearDistance, zFarDistance) @@ -155,11 +156,13 @@ function C_Camera.StopAdjustingView() end function C_Camera.GetWorldPosition() - return C_Camera.ComputeOrbitPositionInLocalSpace( + local orbitPositionRelativeToTarget = C_Camera.ComputeOrbitPositionInLocalSpace( C_Camera.horizontalRotationAngleInDegrees, C_Camera.verticalRotationAngleInDegrees, C_Camera.orbitDistanceInWorldUnits ) + + return orbitPositionRelativeToTarget:Add(C_Camera.targetWorldPosition) end function C_Camera.GetHorizontalRotationAngle() @@ -209,4 +212,14 @@ function C_Camera.SetOrbitDistance(distance) C_Camera.orbitDistanceInWorldUnits = distance end +function C_Camera.GetTargetPosition() + return C_Camera.targetWorldPosition +end + +function C_Camera.SetTargetPosition(newPosition) + C_Camera.targetWorldPosition.x = newPosition.x + C_Camera.targetWorldPosition.y = newPosition.y + C_Camera.targetWorldPosition.z = newPosition.z +end + return C_Camera diff --git a/Core/NativeClient/Renderer.lua b/Core/NativeClient/Renderer.lua index bac595f7..5ca3e89d 100644 --- a/Core/NativeClient/Renderer.lua +++ b/Core/NativeClient/Renderer.lua @@ -321,10 +321,10 @@ function Renderer:UpdateUniformBuffer() local perSceneUniformData = self.perSceneUniformData local cameraWorldPosition = C_Camera.GetWorldPosition() - local targetWorldPosition = Vector3D(0, 0, 0) + local cameraTarget = C_Camera.GetTargetPosition() local upVectorHint = Vector3D(0, 1, 0) local perspective = C_Camera.GetPerspective() - perSceneUniformData.view = C_Camera.CreateOrbitalView(cameraWorldPosition, targetWorldPosition, upVectorHint) + perSceneUniformData.view = C_Camera.CreateOrbitalView(cameraWorldPosition, cameraTarget, upVectorHint) perSceneUniformData.perspectiveProjection = C_Camera.CreatePerspectiveProjection(perspective.fov, aspectRatio, perspective.nearZ, perspective.farZ) perSceneUniformData.time = ffi.new("float", currentTime) diff --git a/Tests/NativeClient/C_Camera.spec.lua b/Tests/NativeClient/C_Camera.spec.lua index ae550321..abb818ca 100644 --- a/Tests/NativeClient/C_Camera.spec.lua +++ b/Tests/NativeClient/C_Camera.spec.lua @@ -285,6 +285,38 @@ describe("C_Camera", function() C_Camera.ResetView() end) + + it("should take into account the camera's focus target", function() + local positionBefore = C_Camera.GetWorldPosition() + local targetPosition = Vector3D(1, 2, 3) + C_Camera.SetTargetPosition(targetPosition) + + local defaultCameraPosition = C_Camera.ComputeOrbitPositionInLocalSpace( + C_Camera.DEFAULT_HORIZONTAL_ROTATION, + C_Camera.DEFAULT_VERTICAL_ROTATION, + C_Camera.DEFAULT_ORBIT_DISTANCE + ) + + assertEquals(positionBefore.x, defaultCameraPosition.x) + assertEquals(positionBefore.y, defaultCameraPosition.y) + assertEquals(positionBefore.z, defaultCameraPosition.z) + + C_Camera.ApplyHorizontalRotation(90) + local newCameraPosition = C_Camera.ComputeOrbitPositionInLocalSpace( + C_Camera.DEFAULT_HORIZONTAL_ROTATION + 90, + C_Camera.DEFAULT_VERTICAL_ROTATION, + C_Camera.DEFAULT_ORBIT_DISTANCE + ) + newCameraPosition = newCameraPosition:Add(targetPosition) -- Local to world space + + local positionAfter = C_Camera.GetWorldPosition() + assertEquals(positionAfter.x, newCameraPosition.x) + assertEquals(positionAfter.y, newCameraPosition.y) + assertEquals(positionAfter.z, newCameraPosition.z) + + C_Camera.ResetView() + C_Camera.SetTargetPosition(Vector3D(0, 0, 0)) + end) end) describe("ApplyHorizontalRotation", function() From 5f0c05c6e05c9fa05b16ef9c2861774c6ab32db7 Mon Sep 17 00:00:00 2001 From: RDW Date: Thu, 23 Nov 2023 22:17:39 +0100 Subject: [PATCH 2/2] Core: Allow moving the camera target via arrow keys It's not as versatile as a full panning mode, but also much simpler. --- Core/NativeClient/C_Camera.lua | 1 + Core/NativeClient/NativeClient.lua | 35 ++++++++++- Tests/NativeClient/NativeClient.spec.lua | 76 ++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 1 deletion(-) diff --git a/Core/NativeClient/C_Camera.lua b/Core/NativeClient/C_Camera.lua index 49997cfb..301edfd3 100644 --- a/Core/NativeClient/C_Camera.lua +++ b/Core/NativeClient/C_Camera.lua @@ -30,6 +30,7 @@ local C_Camera = { MIN_ORBIT_DISTANCE = 45, MAX_ORBIT_DISTANCE = 80, targetWorldPosition = Vector3D(0, 0, 0), + TARGET_DEBUG_STEPSIZE_IN_WORLD_UNITS = 12, } function C_Camera.CreatePerspectiveProjection(verticalFieldOfViewInDegrees, aspectRatio, zNearDistance, zFarDistance) diff --git a/Core/NativeClient/NativeClient.lua b/Core/NativeClient/NativeClient.lua index 601d1cd5..be2c6714 100644 --- a/Core/NativeClient/NativeClient.lua +++ b/Core/NativeClient/NativeClient.lua @@ -1,3 +1,4 @@ +local bit = require("bit") local ffi = require("ffi") local glfw = require("glfw") local interop = require("interop") @@ -6,6 +7,7 @@ local uv = require("uv") local C_Camera = require("Core.NativeClient.C_Camera") local C_Cursor = require("Core.NativeClient.C_Cursor") local Renderer = require("Core.NativeClient.Renderer") +local Vector3D = require("Core.VectorMath.Vector3D") local Box = require("Core.NativeClient.DebugDraw.Box") local Cone = require("Core.NativeClient.DebugDraw.Cone") @@ -261,7 +263,38 @@ function NativeClient:SCROLL_STATUS_CHANGED(eventID, payload) end function NativeClient:KEYPRESS_STATUS_CHANGED(eventID, payload) - print("KEYPRESS_STATUS_CHANGED") + local GLFW_KEY_LEFT = glfw.bindings.glfw_find_constant("GLFW_KEY_LEFT") + local GLFW_KEY_RIGHT = glfw.bindings.glfw_find_constant("GLFW_KEY_RIGHT") + local GLFW_KEY_DOWN = glfw.bindings.glfw_find_constant("GLFW_KEY_DOWN") + local GLFW_KEY_UP = glfw.bindings.glfw_find_constant("GLFW_KEY_UP") + local GLFW_MOD_SHIFT = glfw.bindings.glfw_find_constant("GLFW_MOD_SHIFT") + local GLFW_PRESS = glfw.bindings.glfw_find_constant("GLFW_PRESS") + local wasKeyPressed = tonumber(payload.key_details.action) == GLFW_PRESS + if not wasKeyPressed then + return + end + + local isModifiedBySHIFT = bit.band(payload.key_details.mods, GLFW_MOD_SHIFT) == 1 + if not isModifiedBySHIFT then + return + end + + local wasLeftKey = payload.key_details.key == GLFW_KEY_LEFT + local wasRightKey = payload.key_details.key == GLFW_KEY_RIGHT + local wasUpKey = payload.key_details.key == GLFW_KEY_UP + local wasDownKey = payload.key_details.key == GLFW_KEY_DOWN + local movementDirectionX = wasLeftKey and -1 or 0 + movementDirectionX = wasRightKey and 1 or movementDirectionX + local movementDirectionZ = wasUpKey and 1 or 0 + movementDirectionZ = wasDownKey and -1 or movementDirectionZ + + local movementDistanceInWorldUnits = C_Camera.TARGET_DEBUG_STEPSIZE_IN_WORLD_UNITS + local translation = Vector3D( + movementDirectionX * movementDistanceInWorldUnits, + 0, + movementDirectionZ * movementDistanceInWorldUnits + ) + C_Camera.targetWorldPosition = C_Camera.targetWorldPosition:Add(translation) end function NativeClient:UNICODE_INPUT_RECEIVED(eventID, payload) diff --git a/Tests/NativeClient/NativeClient.spec.lua b/Tests/NativeClient/NativeClient.spec.lua index 0d9e606d..52887f5d 100644 --- a/Tests/NativeClient/NativeClient.spec.lua +++ b/Tests/NativeClient/NativeClient.spec.lua @@ -4,6 +4,7 @@ local glfw = require("glfw") local C_Camera = require("Core.NativeClient.C_Camera") local C_Cursor = require("Core.NativeClient.C_Cursor") local NativeClient = require("Core.NativeClient.NativeClient") +local Vector3D = require("Core.VectorMath.Vector3D") describe("NativeClient", function() describe("CURSOR_MOVED", function() @@ -479,4 +480,79 @@ describe("NativeClient", function() end ) end) + + describe("KEYPRESS_STATUS_CHANGED", function() + local originalCameraTarget = C_Camera.GetTargetPosition() + after(function() + C_Camera.SetTargetPosition(originalCameraTarget) + end) + + it("should adjust the camera target if SHIFT + LEFT was pressed", function() + local event = ffi.new("deferred_event_t") + event.key_details.key = glfw.bindings.glfw_find_constant("GLFW_KEY_LEFT") + event.key_details.action = glfw.bindings.glfw_find_constant("GLFW_PRESS") + event.key_details.mods = glfw.bindings.glfw_find_constant("GLFW_MOD_SHIFT") + + NativeClient:KEYPRESS_STATUS_CHANGED("KEYPRESS_STATUS_CHANGED", event) + + local newCameraTarget = C_Camera.GetTargetPosition() + local expectedTranslation = Vector3D(-C_Camera.TARGET_DEBUG_STEPSIZE_IN_WORLD_UNITS, 0, 0) + local expectedCameraTarget = originalCameraTarget:Add(expectedTranslation) + + assertEquals(newCameraTarget.x, expectedCameraTarget.x) + assertEquals(newCameraTarget.y, expectedCameraTarget.y) + assertEquals(newCameraTarget.z, expectedCameraTarget.z) + end) + + it("should adjust the camera target if SHIFT + RIGHT was pressed", function() + local event = ffi.new("deferred_event_t") + event.key_details.key = glfw.bindings.glfw_find_constant("GLFW_KEY_RIGHT") + event.key_details.action = glfw.bindings.glfw_find_constant("GLFW_PRESS") + event.key_details.mods = glfw.bindings.glfw_find_constant("GLFW_MOD_SHIFT") + + NativeClient:KEYPRESS_STATUS_CHANGED("KEYPRESS_STATUS_CHANGED", event) + + local newCameraTarget = C_Camera.GetTargetPosition() + local expectedTranslation = Vector3D(C_Camera.TARGET_DEBUG_STEPSIZE_IN_WORLD_UNITS, 0, 0) + local expectedCameraTarget = originalCameraTarget:Add(expectedTranslation) + + assertEquals(newCameraTarget.x, expectedCameraTarget.x) + assertEquals(newCameraTarget.y, expectedCameraTarget.y) + assertEquals(newCameraTarget.z, expectedCameraTarget.z) + end) + + it("should adjust the camera target if SHIFT + UP was pressed", function() + local event = ffi.new("deferred_event_t") + event.key_details.key = glfw.bindings.glfw_find_constant("GLFW_KEY_UP") + event.key_details.action = glfw.bindings.glfw_find_constant("GLFW_PRESS") + event.key_details.mods = glfw.bindings.glfw_find_constant("GLFW_MOD_SHIFT") + + NativeClient:KEYPRESS_STATUS_CHANGED("KEYPRESS_STATUS_CHANGED", event) + + local newCameraTarget = C_Camera.GetTargetPosition() + local expectedTranslation = Vector3D(0, 0, C_Camera.TARGET_DEBUG_STEPSIZE_IN_WORLD_UNITS) + local expectedCameraTarget = originalCameraTarget:Add(expectedTranslation) + + assertEquals(newCameraTarget.x, expectedCameraTarget.x) + assertEquals(newCameraTarget.y, expectedCameraTarget.y) + assertEquals(newCameraTarget.z, expectedCameraTarget.z) + end) + + it("should adjust the camera target if SHIFT + DOWN was pressed", function() + local event = ffi.new("deferred_event_t") + event.key_details.key = glfw.bindings.glfw_find_constant("GLFW_KEY_DOWN") + event.key_details.action = glfw.bindings.glfw_find_constant("GLFW_PRESS") + event.key_details.mods = glfw.bindings.glfw_find_constant("GLFW_MOD_SHIFT") + + NativeClient:KEYPRESS_STATUS_CHANGED("KEYPRESS_STATUS_CHANGED", event) + + local newCameraTarget = C_Camera.GetTargetPosition() + local expectedTranslation = Vector3D(0, 0, -C_Camera.TARGET_DEBUG_STEPSIZE_IN_WORLD_UNITS) + local expectedCameraTarget = originalCameraTarget:Add(expectedTranslation) + + assertEquals(newCameraTarget.x, expectedCameraTarget.x) + assertEquals(newCameraTarget.y, expectedCameraTarget.y) + assertEquals(newCameraTarget.z, expectedCameraTarget.z) + end) + end) end)