Skip to content

Commit

Permalink
#5746: Grid-snapping implemented for faces and face vertices
Browse files Browse the repository at this point in the history
  • Loading branch information
codereader committed Sep 26, 2021
1 parent 842f207 commit 1f817f3
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 115 deletions.
200 changes: 102 additions & 98 deletions radiantcore/selection/textool/FaceNode.h
Expand Up @@ -56,90 +56,10 @@ class FaceNode :

void transformComponents(const Matrix3& transform) override
{
std::vector<std::size_t> selectedIndices;

// We need to remember the old texture coordinates to determine the fixed points
std::vector<Vector2> unchangedTexcoords;
AABB selectionBounds;

// Manipulate every selected vertex using the given transform
for (std::size_t i = 0; i < _vertices.size(); ++i)
{
auto& vertex = _vertices[i];

unchangedTexcoords.push_back(vertex.getTexcoord());

if (!vertex.isSelected()) continue;

selectionBounds.includePoint({ vertex.getTexcoord().x(), vertex.getTexcoord().y(), 0 });
selectedIndices.push_back(i);

// Apply the transform to the selected texcoord
vertex.getTexcoord() = transform * vertex.getTexcoord();
}

if (selectedIndices.empty()) return; // nothing happened

// Now we need to pick three vertices to calculate the tex def from
// we have certain options, depending on the number of selected vertices
auto selectionCount = selectedIndices.size();

Vector3 vertices[3];
Vector2 texcoords[3];
const auto& winding = _face.getWinding();

if (selectionCount >= 3)
{
// Manipulating 3+ vertices means that the whole face is transformed
// the same way. We can pick any of the three selected vertices.
for (std::size_t i = 0; i < 3; ++i)
{
vertices[i] = _vertices[selectedIndices[i]].getVertex();
texcoords[i] = _vertices[selectedIndices[i]].getTexcoord();
}

_face.setTexDefFromPoints(vertices, texcoords);
}
else if (selectionCount == 2)
transformSelectedAndRecalculateTexDef([&](Vector2& selectedTexcoord)
{
// Calculate the center point of the selection and pick the vertex that is farthest from it
auto farthestIndex = findIndexFarthestFrom(
{ selectionBounds.origin.x(), selectionBounds.origin.y() },
unchangedTexcoords, selectedIndices);

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);
}
else // selectionCount == 1
{
assert(selectionCount == 1);
std::vector<std::size_t> fixedVerts{ selectedIndices[0] };

auto secondIndex = findIndexFarthestFrom(unchangedTexcoords[selectedIndices[0]],
unchangedTexcoords, fixedVerts);
fixedVerts.push_back(secondIndex);

// Now we've got two vertices, calculate the center and take the farthest of that one
auto center = (unchangedTexcoords[secondIndex] + unchangedTexcoords[selectedIndices[0]]) * 0.5;
auto thirdIndex = findIndexFarthestFrom(center, unchangedTexcoords, fixedVerts);
fixedVerts.push_back(thirdIndex);

for (std::size_t i = 0; i < 3; ++i)
{
vertices[i] = _vertices[fixedVerts[i]].getVertex();
texcoords[i] = _vertices[fixedVerts[i]].getTexcoord();
}

_face.setTexDefFromPoints(vertices, texcoords);
}
selectedTexcoord = transform * selectedTexcoord;
});
}

void commitTransformation() override
Expand Down Expand Up @@ -241,37 +161,121 @@ class FaceNode :

void snapto(float snap) override
{
#if 0
for (const auto& vertex : _face.getWinding())
{
_bounds.includePoint({ vertex.texcoord.x(), vertex.texcoord.y(), 0 });
}

for (auto& vertex : _vertices)
{
auto& texcoord = vertex.getTexcoord();
texcoord.x() = float_snapped(texcoord.x(), snap);
texcoord.y() = float_snapped(texcoord.y(), snap);
}
#endif

// Take three vertices and calculate a new tex def
Vector3 vertices[3];
Vector2 texcoords[3];

for (std::size_t i = 0; i < 3; ++i)
{
vertices[i] = _vertices[i].getVertex();
texcoords[i] = _vertices[i].getTexcoord();
}

_face.setTexDefFromPoints(vertices, texcoords);
}

void snapComponents(float snap) override
{
#if 0
for (auto& vertex : _vertices)
transformSelectedAndRecalculateTexDef([&](Vector2& selectedTexcoord)
{
// Snap the selection to the grid
selectedTexcoord.x() = float_snapped(selectedTexcoord.x(), snap);
selectedTexcoord.y() = float_snapped(selectedTexcoord.y(), snap);
});
}

private:
void transformSelectedAndRecalculateTexDef(const std::function<void(Vector2&)>& transform)
{
std::vector<std::size_t> selectedIndices;

// We need to remember the old texture coordinates to determine the fixed points
std::vector<Vector2> unchangedTexcoords;
AABB selectionBounds;

// Manipulate every selected vertex using the given transform
for (std::size_t i = 0; i < _vertices.size(); ++i)
{
auto& vertex = _vertices[i];

unchangedTexcoords.push_back(vertex.getTexcoord());

if (!vertex.isSelected()) continue;

selectionBounds.includePoint({ vertex.getTexcoord().x(), vertex.getTexcoord().y(), 0 });
selectedIndices.push_back(i);

// Apply the transform to the selected texcoord
transform(vertex.getTexcoord());
}

if (selectedIndices.empty()) return; // nothing happened

// Now we need to pick three vertices to calculate the tex def from
// we have certain options, depending on the number of selected vertices
auto selectionCount = selectedIndices.size();

Vector3 vertices[3];
Vector2 texcoords[3];
const auto& winding = _face.getWinding();

if (selectionCount >= 3)
{
if (vertex.isSelected())
// Manipulating 3+ vertices means that the whole face is transformed
// the same way. We can pick any of the three selected vertices.
for (std::size_t i = 0; i < 3; ++i)
{
vertices[i] = _vertices[selectedIndices[i]].getVertex();
texcoords[i] = _vertices[selectedIndices[i]].getTexcoord();
}
}
else if (selectionCount == 2)
{
// Calculate the center point of the selection and pick the vertex that is farthest from it
auto farthestIndex = findIndexFarthestFrom(
{ selectionBounds.origin.x(), selectionBounds.origin.y() },
unchangedTexcoords, selectedIndices);

for (std::size_t i = 0; i < 2; ++i)
{
auto& texcoord = vertex.getTexcoord();
texcoord.x() = float_snapped(texcoord.x(), snap);
texcoord.y() = float_snapped(texcoord.y(), snap);
vertices[i] = _vertices[selectedIndices[i]].getVertex();
texcoords[i] = _vertices[selectedIndices[i]].getTexcoord();
}

vertices[2] = _vertices[farthestIndex].getVertex();
texcoords[2] = _vertices[farthestIndex].getTexcoord();
}
#endif
else // selectionCount == 1
{
assert(selectionCount == 1);
std::vector<std::size_t> fixedVerts{ selectedIndices[0] };

auto secondIndex = findIndexFarthestFrom(unchangedTexcoords[selectedIndices[0]],
unchangedTexcoords, fixedVerts);
fixedVerts.push_back(secondIndex);

// Now we've got two vertices, calculate the center and take the farthest of that one
auto center = (unchangedTexcoords[secondIndex] + unchangedTexcoords[selectedIndices[0]]) * 0.5;
auto thirdIndex = findIndexFarthestFrom(center, unchangedTexcoords, fixedVerts);
fixedVerts.push_back(thirdIndex);

for (std::size_t i = 0; i < 3; ++i)
{
vertices[i] = _vertices[fixedVerts[i]].getVertex();
texcoords[i] = _vertices[fixedVerts[i]].getTexcoord();
}
}

_face.setTexDefFromPoints(vertices, texcoords);
}

private:
// Locates the index of the vertex that is farthest away from the given texcoord
// the indices contained in exludedIndices are not returned
static std::size_t findIndexFarthestFrom(const Vector2& texcoord,
Expand Down
29 changes: 12 additions & 17 deletions test/TextureTool.cpp
Expand Up @@ -1572,6 +1572,13 @@ TEST_F(TextureToolTest, SnapFaceToGrid)
auto faceUp = algorithm::findBrushFaceWithNormal(Node_getIBrush(brush), Vector3(0, 0, 1));
auto faceRight = algorithm::findBrushFaceWithNormal(Node_getIBrush(brush), Vector3(1, 0, 0));

// Assume some non-grid snapped texcoords on both faces
faceUp->fitTexture(1, 1);
faceUp->shiftTexdef(0.133f, 0.111f);

faceRight->fitTexture(1, 1);
faceRight->shiftTexdef(0.133f, 0.111f);

EXPECT_EQ(getAllSelectedTextoolNodes().size(), 0) << "No item should be selected";

// Get the texture space bounds of this face
Expand All @@ -1588,13 +1595,6 @@ TEST_F(TextureToolTest, SnapFaceToGrid)
GlobalGrid().setGridSize(GRID_8);
auto gridSize = GlobalGrid().getGridSize(grid::Space::Texture);

// Assume some non-grid snapped texcoords on both faces
faceUp->fitTexture(1, 1);
faceUp->shiftTexdef(0.133f, 0.111f);

faceRight->fitTexture(1, 1);
faceRight->shiftTexdef(0.133f, 0.111f);

assumeFaceVerticesGridSnapped(*faceUp, false);
assumeFaceVerticesGridSnapped(*faceRight, false);

Expand All @@ -1614,13 +1614,13 @@ TEST_F(TextureToolTest, SnapFaceVerticesToGrid)
auto brush = setupBrushNodeForTextureTool();
auto faceUp = algorithm::findBrushFaceWithNormal(Node_getIBrush(brush), Vector3(0, 0, 1));

faceUp->fitTexture(1, 1);
faceUp->shiftTexdef(0.133f, 0.111f);

// Get the texture space bounds of this face
auto bounds = getTextureSpaceBounds(*faceUp);
bounds.extents *= 1.2f;

faceUp->fitTexture(1, 1);
faceUp->shiftTexdef(0.133f, 0.111f);

render::TextureToolView view;
view.constructFromTextureSpaceBounds(bounds, TEXTOOL_WIDTH, TEXTOOL_HEIGHT);

Expand All @@ -1629,7 +1629,7 @@ TEST_F(TextureToolTest, SnapFaceVerticesToGrid)

// Get the texcoords of the first vertex
auto firstIndex = 0;
auto secondIndex = 0;
auto secondIndex = 1;

auto firstVertex = faceUp->getWinding()[firstIndex].texcoord;
auto secondVertex = faceUp->getWinding()[secondIndex].texcoord;
Expand All @@ -1652,17 +1652,12 @@ TEST_F(TextureToolTest, SnapFaceVerticesToGrid)
{
const auto& vertex = faceUp->getWinding()[i];

// Only the two selected ones should have been grid-aligned
// At least the the two selected ones should have been grid-aligned, the rest is not checked
if (i == firstIndex || i == secondIndex)
{
EXPECT_EQ(vertex.texcoord.x(), float_snapped(vertex.texcoord.x(), gridSize)) << "U should be grid-snapped";
EXPECT_EQ(vertex.texcoord.y(), float_snapped(vertex.texcoord.y(), gridSize)) << "V should be grid-snapped";
}
else
{
EXPECT_NE(vertex.texcoord.x(), float_snapped(vertex.texcoord.x(), gridSize)) << "U should not be grid-snapped";
EXPECT_NE(vertex.texcoord.y(), float_snapped(vertex.texcoord.y(), gridSize)) << "V should not be grid-snapped";
}
}
}

Expand Down

0 comments on commit 1f817f3

Please sign in to comment.