/
Patch.cpp
154 lines (111 loc) · 6.57 KB
/
Patch.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#include "RadiantTest.h"
#include "imap.h"
#include "ipatch.h"
#include "igrid.h"
#include "iselection.h"
#include "scenelib.h"
#include "algorithm/Primitives.h"
#include "algorithm/Scene.h"
#include "algorithm/View.h"
#include "render/View.h"
namespace test
{
using PatchTest = RadiantTest;
namespace
{
void selectSinglePatchVertexAt(const Vector3& position)
{
render::View orthoView(false);
// Construct an orthoview to test-select the patch vertex
algorithm::constructCenteredOrthoview(orthoView, position);
auto centeredTest = algorithm::constructOrthoviewSelectionTest(orthoView);
auto previousComponentCount = GlobalSelectionSystem().countSelectedComponents();
GlobalSelectionSystem().selectPoint(centeredTest, selection::SelectionSystem::eToggle, false);
EXPECT_EQ(GlobalSelectionSystem().countSelectedComponents(), previousComponentCount + 1)
<< "1 additional vertex component should be selected now";
}
}
// Checks that snapping a single selected patch vertex is working
TEST_F(PatchTest, SnapVertexToGrid)
{
auto worldspawn = GlobalMapModule().findOrInsertWorldspawn();
// Use some off-grid bounds to generate the patch
auto patchNode = algorithm::createPatchFromBounds(worldspawn, AABB({ 0,0,0 }, { 11.5, 13, 15 }));
Node_setSelected(patchNode, true);
GlobalGrid().setGridSize(GRID_4);
// Switch to vertex component mode and select a single patch vertex
GlobalSelectionSystem().setSelectionMode(selection::SelectionMode::Component);
GlobalSelectionSystem().SetComponentMode(selection::ComponentSelectionMode::Vertex);
// Pick a vertex from the patch
const auto& ctrl = Node_getIPatch(patchNode)->getTransformedCtrlAt(0, 2);
auto vertexAfterSnapping = ctrl.vertex.getSnapped(GlobalGrid().getGridSize());
EXPECT_FALSE(math::isNear(ctrl.vertex, vertexAfterSnapping, 0.01)) << "Vertex should be off-grid";
selectSinglePatchVertexAt(ctrl.vertex);
// Snap selection to grid
GlobalCommandSystem().executeCommand("SnapToGrid");
EXPECT_TRUE(math::isNear(ctrl.vertex, vertexAfterSnapping, 0.01)) << "Vertex should be snapped to grid now";
}
// Checks that snapping a single vertex to grid is undoable
TEST_F(PatchTest, VertexSnappingIsUndoable)
{
auto worldspawn = GlobalMapModule().findOrInsertWorldspawn();
// Use some off-grid bounds to generate the patch
auto patchNode = algorithm::createPatchFromBounds(worldspawn, AABB({ 0,0,0 }, { 11.5, 13, 15 }));
Node_setSelected(patchNode, true);
GlobalGrid().setGridSize(GRID_4);
// Switch to vertex component mode and select a single patch vertex
GlobalSelectionSystem().setSelectionMode(selection::SelectionMode::Component);
GlobalSelectionSystem().SetComponentMode(selection::ComponentSelectionMode::Vertex);
// Pick a vertex from the patch
const auto& ctrl = Node_getIPatch(patchNode)->getTransformedCtrlAt(0, 2);
auto vertexBeforeSnapping = ctrl.vertex;
auto vertexAfterSnapping = ctrl.vertex.getSnapped(GlobalGrid().getGridSize());
EXPECT_FALSE(math::isNear(ctrl.vertex, vertexAfterSnapping, 0.01)) << "Vertex should be off-grid";
selectSinglePatchVertexAt(ctrl.vertex);
// Snap selection to grid
GlobalCommandSystem().executeCommand("SnapToGrid");
EXPECT_TRUE(math::isNear(ctrl.vertex, vertexAfterSnapping, 0.01)) << "Vertex should be snapped to grid now";
GlobalCommandSystem().executeCommand("Undo");
EXPECT_TRUE(math::isNear(ctrl.vertex, vertexBeforeSnapping, 0.01)) << "Vertex should be reverted and off-grid again";
}
TEST_F(PatchTest, InvertedEndCapInheritsDef2)
{
auto worldspawn = GlobalMapModule().findOrInsertWorldspawn();
GlobalCommandSystem().execute("PatchEndCap");
auto endcap = algorithm::findFirstPatch(worldspawn, [](auto&) { return true; });
Node_setSelected(endcap, true);
EXPECT_FALSE(Node_getIPatch(endcap)->subdivisionsFixed()) << "End cap should not have fixed tesselation";
// Execute the create inverted end cap command, check the tesselation
GlobalCommandSystem().execute("CapSelectedPatches invertedendcap");
// Get the two end caps
auto invertedEndCap1 = algorithm::findFirstNode(worldspawn, [&](auto& patch) { return patch != endcap; });
auto invertedEndCap2 = algorithm::findFirstNode(worldspawn, [&](auto& patch) { return patch != endcap && patch != invertedEndCap1; });
EXPECT_TRUE(invertedEndCap1) << "Couldn't locate the first end cap";
EXPECT_TRUE(invertedEndCap2) << "Couldn't locate the second end cap";
EXPECT_FALSE(Node_getIPatch(invertedEndCap1)->subdivisionsFixed()) << "Inverted end caps should not have fixed tesselation";
EXPECT_FALSE(Node_getIPatch(invertedEndCap2)->subdivisionsFixed()) << "Inverted end caps should not have fixed tesselation";
}
TEST_F(PatchTest, InvertedEndCapInheritsDef3)
{
auto worldspawn = GlobalMapModule().findOrInsertWorldspawn();
GlobalCommandSystem().execute("PatchEndCap");
auto endcap = algorithm::findFirstPatch(worldspawn, [](auto&) { return true; });
Node_setSelected(endcap, true);
auto subdivisions = Subdivisions(4, 2);
Node_getIPatch(endcap)->setFixedSubdivisions(true, subdivisions);
EXPECT_TRUE(Node_getIPatch(endcap)->subdivisionsFixed()) << "End cap should have fixed tesselation now";
// Execute the create inverted end cap command, check the tesselation
GlobalCommandSystem().execute("CapSelectedPatches invertedendcap");
// Get the two end caps
auto invertedEndCap1 = algorithm::findFirstNode(worldspawn, [&](auto& patch) { return patch != endcap; });
auto invertedEndCap2 = algorithm::findFirstNode(worldspawn, [&](auto& patch) { return patch != endcap && patch != invertedEndCap1; });
EXPECT_TRUE(invertedEndCap1) << "Couldn't locate the first end cap";
EXPECT_TRUE(invertedEndCap2) << "Couldn't locate the second end cap";
EXPECT_TRUE(Node_getIPatch(invertedEndCap1)->subdivisionsFixed()) << "Inverted end cap 1 should have fixed tesselation now";
EXPECT_TRUE(Node_getIPatch(invertedEndCap2)->subdivisionsFixed()) << "Inverted end cap 2 should have fixed tesselation now";
EXPECT_EQ(Node_getIPatch(invertedEndCap1)->getSubdivisions().x(), subdivisions.x()) << "Inverted end cap 1 should have a 4x2 division";
EXPECT_EQ(Node_getIPatch(invertedEndCap1)->getSubdivisions().y(), subdivisions.y()) << "Inverted end cap 1 should have a 4x2 division";
EXPECT_EQ(Node_getIPatch(invertedEndCap2)->getSubdivisions().x(), subdivisions.x()) << "Inverted end cap 2 should have a 4x2 division";
EXPECT_EQ(Node_getIPatch(invertedEndCap2)->getSubdivisions().y(), subdivisions.y()) << "Inverted end cap 2 should have a 4x2 division";
}
}