/
Patch.h
340 lines (255 loc) · 11.6 KB
/
Patch.h
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
#pragma once
#include <vector>
#include "transformlib.h"
#include "editable.h"
#include "iundo.h"
#include "irender.h"
#include "SurfaceShader.h"
#include "PatchConstants.h"
#include "PatchControl.h"
#include "PatchTesselation.h"
#include "PatchRenderables.h"
#include "brush/FacePlane.h"
#include "brush/Face.h"
#include <sigc++/signal.h>
class PatchNode;
class Ray;
/* greebo: The patch class itself, represented by control vertices. The basic rendering of the patch
* is handled here (unselected control points, tesselation lines, shader).
*
* This class also provides functions to export/import itself to XML.
*/
// parametric surface defined by quadratic bezier control curves
class Patch :
public IPatch,
public Bounded,
public Snappable,
public IUndoable
{
friend class PatchNode;
PatchNode& _node;
typedef std::set<IPatch::Observer*> Observers;
Observers _observers;
AABB _localAABB; // local bbox
// Patch dimensions
std::size_t _width;
std::size_t _height;
IUndoStateSaver* _undoStateSaver;
// dynamically allocated array of control points, size is _width*_height
PatchControlArray _ctrl; // the true control array
PatchControlArray _ctrlTransformed; // a temporary control array used during transformations, so that the
// changes can be reverted and overwritten by <_ctrl>
// The tesselation for this patch
PatchTesselation _mesh;
bool _transformChanged;
// TRUE if the patch tesselation needs an update
bool _tesselationChanged;
// The rendersystem we're attached to, to acquire materials
RenderSystemWeakPtr _renderSystem;
// Shader container, taking care of use count
SurfaceShader _shader;
// If true, this patch is using fixed subdivisions
bool _patchDef3;
// Fixed subdivision layout of this patch
Subdivisions _subDivisions;
// greebo: Initialises the patch member variables
void construct();
public:
// Constructor
Patch(PatchNode& node);
// Copy constructors (create this patch from another patch)
Patch(const Patch& other, PatchNode& node);
~Patch();
PatchNode& getPatchNode();
void attachObserver(Observer* observer) override;
void detachObserver(Observer* observer) override;
void connectUndoSystem(IUndoSystem& undoSystem);
void disconnectUndoSystem(IUndoSystem& undoSystem);
const AABB& localAABB() const override;
RenderSystemPtr getRenderSystem() const;
void setRenderSystem(const RenderSystemPtr& renderSystem);
// Implementation of the abstract method of SelectionTestable
// Called to test if the patch can be selected by the mouse pointer
void testSelect(Selector& selector, SelectionTest& test);
// Transform this patch as defined by the transformation matrix <matrix>
void transform(const Matrix4& matrix);
// Called by the PatchNode if the transformation gets changed
void transformChanged();
// Called to evaluate the transform
void evaluateTransform();
// Revert the changes, fall back to the saved state in <m_ctrl>
void revertTransform() override;
// Apply the transformed control array, save it into <m_ctrl> and overwrite the old values
void freezeTransform() override;
// callback for changed control points
void controlPointsChanged() override;
// Check if the patch has invalid control points or width/height are zero
bool isValid() const override;
// Check whether all control vertices are in the same 3D spot (with minimal tolerance)
bool isDegenerate() const override;
// Snaps the control points to the grid
void snapto(float snap) override;
// Gets the shader name or sets the shader to <name>
const std::string& getShader() const override;
void setShader(const std::string& name) override;
const SurfaceShader& getSurfaceShader() const;
SurfaceShader& getSurfaceShader();
// greebo: returns true if the patch's shader is visible, false otherwise
bool hasVisibleMaterial() const override;
float getTextureAspectRatio() const override;
// As the name states: get the shader flags of the m_state shader
int getShaderFlags() const;
// Const and non-const iterators
PatchControlIter begin() {
return _ctrl.begin();
}
PatchControlConstIter begin() const {
return _ctrl.begin();
}
PatchControlIter end() {
return _ctrl.end();
}
PatchControlConstIter end() const {
return _ctrl.end();
}
PatchTesselation& getTesselation();
PatchRenderIndices getRenderIndices() const override;
// Returns a copy of the tesselated geometry
PatchMesh getTesselatedPatchMesh() const override;
// Get the current control point array
PatchControlArray& getControlPoints();
const PatchControlArray& getControlPoints() const;
// Get the (temporary) transformed control point array, not the saved ones
PatchControlArray& getControlPointsTransformed();
const PatchControlArray& getControlPointsTransformed() const;
// Set the dimensions of this patch to width <w>, height <h>
void setDims(std::size_t w, std::size_t h) override;
// Get the patch dimensions
std::size_t getWidth() const override;
std::size_t getHeight() const override;
// Return a defined patch control vertex at <row>,<col>
PatchControl& ctrlAt(std::size_t row, std::size_t col) override;
// The same as above just for const
const PatchControl& ctrlAt(std::size_t row, std::size_t col) const override;
PatchControl& getTransformedCtrlAt(std::size_t row, std::size_t col) override;
/** greebo: Inserts two columns before and after the column with index <colIndex>.
* Throws an GenericPatchException if an error occurs.
*/
void insertColumns(std::size_t colIndex) override;
/** greebo: Inserts two rows before and after the row with index <rowIndex>.
* Throws an GenericPatchException if an error occurs.
*/
void insertRows(std::size_t rowIndex) override;
/** greebo: Removes columns or rows right before and after the col/row
* with the given index, reducing the according dimension by 2.
*/
void removePoints(bool columns, std::size_t index) override;
/** greebo: Appends two rows or columns at the beginning or the end.
*/
void appendPoints(bool columns, bool beginning) override;
void ConstructPrefab(const AABB& aabb, EPatchPrefab eType, OrthoOrientation viewType, std::size_t width = 3, std::size_t height = 3);
void constructPlane(const AABB& aabb, int axis, std::size_t width, std::size_t height);
void constructBevel(const AABB& aabb, OrthoOrientation viewType);
void constructEndcap(const AABB& aabb, OrthoOrientation viewType);
void invertMatrix() override;
void transposeMatrix() override;
void Redisperse(EMatrixMajor mt);
void redisperseRows() override;
void redisperseColumns() override;
void insertRemove(bool insert, bool column, bool first) override;
void constructCap(Patch& patch, patch::CapType capType, bool front) const;
void constructSeam(patch::CapType eType, std::vector<Vector3>& points, std::size_t width);
void flipTexture(int axis) override;
/** greebo: This translates the texture as much towards
* the origin as possible. The patch appearance stays unchanged.
*/
void normaliseTexture() override;
/** greebo: Translate all control vertices in texture space
* with the given translation vector (helper method, no undoSave() call)
*/
void translateTexCoords(const Vector2& translation);
// This is the same as above, but with undoSave() for use in command sequences
void translateTexture(float s, float t) override;
void scaleTexture(float s, float t) override;
void rotateTexture(float angle) override; // angle in degrees
void fitTexture(float repeatS, float repeatT) override; // call with s=1 t=1 for FIT
/* uses longest parallel chord to calculate texture coords for each row/col
* greebo: The default texture scale is used when applying "Natural" texturing.
* The applied texture is never stretched more than the default
* texture scale. So if the default texture scale is 0.5, the texture coordinates
* are set such that the scaling never exceeds this value.
*/
void scaleTextureNaturally() override;
// Aligns the patch texture along the given side/border - if possible
void alignTexture(AlignEdge type) override;
/* greebo: This basically projects all the patch vertices into the brush plane and
* transforms the projected coordinates into the texture plane space */
void pasteTextureProjected(const Face* face);
// This returns the PatchControl pointer that is closest to the given <point>
PatchControlIter getClosestPatchControlToPoint(const Vector3& point);
PatchControlIter getClosestPatchControlToFace(const Face* face);
PatchControlIter getClosestPatchControlToPatch(const Patch& patch);
// Returns the w,h coordinates within the PatchControlArray of the given <control>
Vector2 getPatchControlArrayIndices(const PatchControlIter& control);
/* This takes the texture from the given brush face and applies it to this patch.
* It determines the closest control vertex of this patch to the brush and
* tries to continue the texture seamlessly. The resulting texturing is undistorted.
* Might throw a cmd::ExecutionFailure if the patch is not suitable.
*/
void pasteTextureNatural(const Face* face);
/** greebo: Pastes the texture from the given sourcepatch
* trying to make the transition seamless.
*/
void pasteTextureNatural(Patch& sourcePatch);
void pasteTextureCoordinates(const Patch* otherPatch);
/** greebo: Tries to make the texture transition seamless (from
* the source patch to the this patch), leaving the sourcepatch
* intact.
*/
void stitchTextureFrom(Patch& sourcePatch);
/** greebo: Converts this patch as thickened counterpart of the given <sourcePatch>
* with the given <thickness> along the chosen <axis>
*
* @axis: 0 = x-axis, 1 = y-axis, 2 = z-axis, 3 = vertex normals
*/
void createThickenedOpposite(const Patch& sourcePatch, const float thickness, const int axis);
/** greebo: This creates on of the "wall" patches when thickening patches.
*
* @sourcePath, targetPatch: these are the top and bottom patches. The wall connects
* a distinct edge of these two, depending on the wallIndex.
*
* @wallIndex: 0..3 (cycle through them to create all four walls).
*/
void createThickenedWall(const Patch& sourcePatch, const Patch& targetPatch, const int wallIndex);
// called just before an action to save the undo state
void undoSave() override;
// Save the current patch state into a new UndoMemento instance (allocated on heap) and return it to the undo observer
IUndoMementoPtr exportState() const override;
// Revert the state of this patch to the one that has been saved in the UndoMemento
void importState(const IUndoMementoPtr& state) override;
/** greebo: Gets whether this patch is a patchDef3 (fixed tesselation)
*/
bool subdivisionsFixed() const override;
/** greebo: Returns the x,y subdivision values (for tesselation)
*/
const Subdivisions& getSubdivisions() const override;
/** greebo: Sets the subdivision of this patch
*
* @isFixed: TRUE, if this patch should be a patchDef3 (fixed tesselation)
* @divisions: a two-component vector containing the desired subdivisions
*/
void setFixedSubdivisions(bool isFixed, const Subdivisions& divisions) override;
// Calculate the intersection of the given ray with the full patch mesh,
// returns true on intersection and fills in the out variable
bool getIntersection(const Ray& ray, Vector3& intersection);
// Static signal holder, signal is emitted after any patch texture has changed
static sigc::signal<void>& signal_patchTextureChanged();
void updateTesselation(bool force = false) override;
void queueTesselationUpdate();
private:
// This notifies the surfaceinspector/patchinspector about the texture change
void textureChanged();
// greebo: checks, if the shader name is valid
void check_shader();
void updateAABB();
};