Fix sphere winding and viewport middle-pan input
This commit is contained in:
@@ -78,9 +78,9 @@ inline void RenderViewportInteractionSurface(
|
||||
result.itemMin = ImGui::GetItemRectMin();
|
||||
result.itemMax = ImGui::GetItemRectMax();
|
||||
result.hovered = ImGui::IsItemHovered();
|
||||
result.clickedLeft = ImGui::IsItemClicked(ImGuiMouseButton_Left);
|
||||
result.clickedRight = ImGui::IsItemClicked(ImGuiMouseButton_Right);
|
||||
result.clickedMiddle = ImGui::IsItemClicked(ImGuiMouseButton_Middle);
|
||||
result.clickedLeft = result.hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Left, false);
|
||||
result.clickedRight = result.hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Right, false);
|
||||
result.clickedMiddle = result.hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Middle, false);
|
||||
}
|
||||
|
||||
inline ViewportPanelContentResult RenderViewportPanelContent(
|
||||
|
||||
@@ -865,7 +865,10 @@ LoadResult CreateBuiltinMeshResource(const Containers::String& path) {
|
||||
return LoadResult(Containers::String("Unsupported builtin mesh: ") + path);
|
||||
}
|
||||
|
||||
// The UV sphere generator already emits triangles in the runtime's front-face convention.
|
||||
if (primitiveType != BuiltinPrimitiveType::Sphere) {
|
||||
FlipTriangleWinding(buffers);
|
||||
}
|
||||
|
||||
Mesh* mesh = BuildMeshResource(path, GetBuiltinPrimitiveDisplayName(primitiveType), std::move(buffers));
|
||||
if (mesh == nullptr) {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <XCEngine/Core/Asset/AssetDatabase.h>
|
||||
#include <XCEngine/Core/Asset/ResourceManager.h>
|
||||
#include <XCEngine/Core/Math/Vector3.h>
|
||||
#include <XCEngine/Resources/BuiltinResources.h>
|
||||
#include <XCEngine/Resources/Material/MaterialLoader.h>
|
||||
#include <XCEngine/Resources/Mesh/MeshLoader.h>
|
||||
#include <XCEngine/Resources/Mesh/MeshImportSettings.h>
|
||||
@@ -23,6 +25,16 @@ std::string GetMeshFixturePath(const char* fileName) {
|
||||
return (std::filesystem::path(XCENGINE_TEST_FIXTURES_DIR) / "Resources" / "Mesh" / fileName).string();
|
||||
}
|
||||
|
||||
XCEngine::Core::uint32 ReadMeshIndex(const Mesh& mesh, XCEngine::Core::uint32 index) {
|
||||
if (mesh.IsUse32BitIndex()) {
|
||||
const auto* indices = static_cast<const XCEngine::Core::uint32*>(mesh.GetIndexData());
|
||||
return indices[index];
|
||||
}
|
||||
|
||||
const auto* indices = static_cast<const XCEngine::Core::uint16*>(mesh.GetIndexData());
|
||||
return static_cast<XCEngine::Core::uint32>(indices[index]);
|
||||
}
|
||||
|
||||
XCEngine::Core::uint32 GetFirstSectionMaterialIndex(const Mesh& mesh) {
|
||||
if (mesh.GetSections().Empty()) {
|
||||
return 0;
|
||||
@@ -142,6 +154,41 @@ TEST(MeshLoader, LoadValidObjMesh) {
|
||||
delete mesh;
|
||||
}
|
||||
|
||||
TEST(MeshLoader, BuiltinSphereUsesFrontFacingWindingForOutwardNormals) {
|
||||
LoadResult result = CreateBuiltinMeshResource(GetBuiltinPrimitiveMeshPath(BuiltinPrimitiveType::Sphere));
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_NE(result.resource, nullptr);
|
||||
|
||||
auto* mesh = static_cast<Mesh*>(result.resource);
|
||||
const auto* vertices = static_cast<const StaticMeshVertex*>(mesh->GetVertexData());
|
||||
ASSERT_NE(vertices, nullptr);
|
||||
ASSERT_GE(mesh->GetIndexCount(), 3u);
|
||||
|
||||
bool foundNonDegenerateTriangle = false;
|
||||
for (XCEngine::Core::uint32 index = 0; index + 2 < mesh->GetIndexCount(); index += 3) {
|
||||
const XCEngine::Core::uint32 i0 = ReadMeshIndex(*mesh, index + 0);
|
||||
const XCEngine::Core::uint32 i1 = ReadMeshIndex(*mesh, index + 1);
|
||||
const XCEngine::Core::uint32 i2 = ReadMeshIndex(*mesh, index + 2);
|
||||
|
||||
const XCEngine::Math::Vector3 edge01 = vertices[i1].position - vertices[i0].position;
|
||||
const XCEngine::Math::Vector3 edge02 = vertices[i2].position - vertices[i0].position;
|
||||
const XCEngine::Math::Vector3 geometricNormal =
|
||||
XCEngine::Math::Vector3::Cross(edge01, edge02);
|
||||
if (geometricNormal.SqrMagnitude() <= XCEngine::Math::EPSILON) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const XCEngine::Math::Vector3 averagedVertexNormal =
|
||||
(vertices[i0].normal + vertices[i1].normal + vertices[i2].normal).Normalized();
|
||||
EXPECT_LT(XCEngine::Math::Vector3::Dot(geometricNormal, averagedVertexNormal), 0.0f);
|
||||
foundNonDegenerateTriangle = true;
|
||||
break;
|
||||
}
|
||||
|
||||
EXPECT_TRUE(foundNonDegenerateTriangle);
|
||||
delete mesh;
|
||||
}
|
||||
|
||||
TEST(MeshLoader, GeneratesNormalsAndTangentsWhenRequested) {
|
||||
MeshLoader loader;
|
||||
MeshImportSettings settings;
|
||||
|
||||
@@ -13,6 +13,8 @@ using XCEngine::Editor::SceneViewportNavigationState;
|
||||
using XCEngine::Editor::SceneViewportToolMode;
|
||||
using XCEngine::Editor::SceneViewportToolShortcutRequest;
|
||||
using XCEngine::Editor::UpdateSceneViewportNavigationState;
|
||||
using XCEngine::UI::UIPoint;
|
||||
using XCEngine::UI::UISize;
|
||||
|
||||
TEST(SceneViewportNavigationTest, ToolShortcutActionIgnoresShortcutsDuringTextInputOrDrag) {
|
||||
SceneViewportToolShortcutRequest request = {};
|
||||
@@ -73,6 +75,19 @@ TEST(SceneViewportNavigationTest, NavigationUpdateBeginsLookAndPanDrags) {
|
||||
EXPECT_TRUE(panUpdate.beginLeftPanDrag);
|
||||
EXPECT_TRUE(panUpdate.state.panDragging);
|
||||
EXPECT_EQ(panUpdate.state.panDragButton, ImGuiMouseButton_Left);
|
||||
|
||||
SceneViewportNavigationRequest middlePanRequest = {};
|
||||
middlePanRequest.hasInteractiveViewport = true;
|
||||
middlePanRequest.viewportHovered = true;
|
||||
middlePanRequest.clickedMiddle = true;
|
||||
middlePanRequest.middleMouseDown = true;
|
||||
const auto middlePanUpdate = UpdateSceneViewportNavigationState(middlePanRequest);
|
||||
EXPECT_FALSE(middlePanUpdate.beginLookDrag);
|
||||
EXPECT_TRUE(middlePanUpdate.beginPanDrag);
|
||||
EXPECT_FALSE(middlePanUpdate.beginLeftPanDrag);
|
||||
EXPECT_TRUE(middlePanUpdate.beginMiddlePanDrag);
|
||||
EXPECT_TRUE(middlePanUpdate.state.panDragging);
|
||||
EXPECT_EQ(middlePanUpdate.state.panDragButton, ImGuiMouseButton_Middle);
|
||||
}
|
||||
|
||||
TEST(SceneViewportNavigationTest, NavigationUpdateEndsDragsWhenButtonsRelease) {
|
||||
@@ -105,7 +120,7 @@ TEST(SceneViewportNavigationTest, CaptureFlagsTrackNavigationAndActiveGizmos) {
|
||||
|
||||
TEST(SceneViewportNavigationTest, BuildInputRoutesWheelFocusMovementAndMouseDelta) {
|
||||
SceneViewportInputBuildRequest request = {};
|
||||
request.viewportSize = ImVec2(640.0f, 360.0f);
|
||||
request.viewportSize = UISize(640.0f, 360.0f);
|
||||
request.viewportHovered = true;
|
||||
request.viewportFocused = true;
|
||||
request.mouseWheel = 2.0f;
|
||||
@@ -117,10 +132,10 @@ TEST(SceneViewportNavigationTest, BuildInputRoutesWheelFocusMovementAndMouseDelt
|
||||
|
||||
request = {};
|
||||
request.state.lookDragging = true;
|
||||
request.viewportSize = ImVec2(640.0f, 360.0f);
|
||||
request.viewportSize = UISize(640.0f, 360.0f);
|
||||
request.viewportHovered = true;
|
||||
request.mouseWheel = 1.5f;
|
||||
request.mouseDelta = ImVec2(5.0f, -3.0f);
|
||||
request.mouseDelta = UIPoint(5.0f, -3.0f);
|
||||
request.fastMove = true;
|
||||
request.focusSelectionKeyPressed = true;
|
||||
request.moveForwardKeyDown = true;
|
||||
|
||||
Reference in New Issue
Block a user