diff --git a/radiantcore/selection/textool/FaceNode.h b/radiantcore/selection/textool/FaceNode.h index 906e155bab..a13af230ad 100644 --- a/radiantcore/selection/textool/FaceNode.h +++ b/radiantcore/selection/textool/FaceNode.h @@ -74,7 +74,7 @@ class FaceNode : auto selectionCount = selectedIndices.size(); Vector3 vertices[3]; - Vector2 texcoords[2]; + Vector2 texcoords[3]; const auto& winding = _face.getWinding(); if (selectionCount >= 3) @@ -87,6 +87,23 @@ class FaceNode : texcoords[i] = _vertices[selectedIndices[i]].getTexcoord(); } + _face.setTexDefFromPoints(vertices, texcoords); + } + else if (selectionCount == 2) + { + // Calculate the center point of the selection and pick the vertex that is farthest from it + auto selectionBounds = getSelectedComponentBounds(); + auto farthestIndex = findIndexFarthestFrom({ selectionBounds.origin.x(), selectionBounds.origin.y() }); + + for (std::size_t i = 0; i < 2; ++i) + { + vertices[i] = _vertices[selectedIndices[i]].getVertex(); + texcoords[i] = _vertices[selectedIndices[i]].getTexcoord(); + } + + vertices[2] = _vertices[farthestIndex].getVertex(); + texcoords[2] = _vertices[farthestIndex].getTexcoord(); + _face.setTexDefFromPoints(vertices, texcoords); } } @@ -164,6 +181,31 @@ class FaceNode : renderComponents(); } } + +private: + // Locates the index of the unselected vertex that is farthest away from the given texcoord + std::size_t findIndexFarthestFrom(const Vector2& texcoord) + { + assert(!_vertices.empty()); + + std::size_t farthestIndex = 0; + double largestDistanceSquared = 0; + + for (std::size_t i = 0; i < _vertices.size(); ++i) + { + if (_vertices[i].isSelected()) continue; + + auto candidateDistanceSquared = (_vertices[i].getTexcoord() - texcoord).getLengthSquared(); + + if (candidateDistanceSquared > largestDistanceSquared) + { + farthestIndex = i; + largestDistanceSquared = candidateDistanceSquared; + } + } + + return farthestIndex; + } }; } diff --git a/test/TextureTool.cpp b/test/TextureTool.cpp index ed1725f4a9..864e946e36 100644 --- a/test/TextureTool.cpp +++ b/test/TextureTool.cpp @@ -1036,24 +1036,27 @@ TEST_F(TextureToolTest, DragManipulateSingleFaceVertex) // Dragging two selected vertices chooses the one vertex as anchor point which is farthest away from the clicked vertex TEST_F(TextureToolTest, DragManipulateTwoFaceVertices) { - // Vertices 0 and 2 are opposite of each other, but 0 takes the lead + // Vertices 0 and 2 are opposite of each other std::size_t firstVertex = 0; std::size_t secondVertex = 2; performFaceVertexManipulationTest(false, { firstVertex, secondVertex }, [&](IFace& face, const std::vector& oldTexcoords, const std::vector& changedTexcoords) { - // Find out which face vertex was the farthest away from the first one - int farthestIndex = 1; - double largestDistance = 0; - for (int i = 0; i < oldTexcoords.size(); ++i) + auto center = (changedTexcoords[firstVertex] + changedTexcoords[secondVertex]) * 0.5; + // Find out which face vertex was the farthest away from the bounds center of the selection + std::size_t farthestIndex = 0; + double largestDistanceSquared = 0; + + for (std::size_t i = 0; i < changedTexcoords.size(); ++i) { if (i == firstVertex || i == secondVertex) continue; - auto candidateDistance = (oldTexcoords[i] - oldTexcoords[firstVertex]).getLengthSquared(); - if (candidateDistance > largestDistance) + auto candidateDistanceSquared = (changedTexcoords[i] - center).getLengthSquared(); + + if (candidateDistanceSquared > largestDistanceSquared) { farthestIndex = i; - largestDistance = candidateDistance; + largestDistanceSquared = candidateDistanceSquared; } }