/
ipatch.h
343 lines (269 loc) · 9.3 KB
/
ipatch.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
341
342
343
#pragma once
#include "imodule.h"
#include <stdexcept>
#include "inode.h"
#include "math/Vector2.h"
#include "math/Vector3.h"
#include "render/VertexNT.h"
// This is thrown by the internal patch routines
class GenericPatchException :
public std::runtime_error
{
public:
// Constructor
GenericPatchException(const std::string& what):
std::runtime_error(what)
{}
};
/* greebo: A PatchControl consists of a vertex and a set of texture coordinates.
* Multiple PatchControls form a PatchControlArray or (together with width and height) a PatchControlMatrix.
*/
struct PatchControl
{
Vector3 vertex; // The coordinates of the control point
Vector2 texcoord; // The texture coordinates of this point
};
/**
* A structure representing the fully tesselated patch
* Can be acquired through the IPatch interface for
* exporting the geometry to an external app.
*/
struct PatchMesh
{
std::size_t width; // width of this mesh
std::size_t height; // height of this mesh
/// Geometry with normals and texture coordinates
std::vector<VertexNT> vertices;
};
struct PatchRenderIndices
{
// The indices, arranged in the way it's expected by GL_QUAD_STRIPS
// The number of indices is (lenStrips*numStrips)
std::vector<unsigned int> indices;
// Strip index layout
std::size_t numStrips;
std::size_t lenStrips;
};
typedef BasicVector2<unsigned int> Subdivisions;
// The abstract base class for a Doom3-compatible patch
class IPatch
{
public:
// An observer can attach itself to a specific patch instance.
// to get notified about changes.
class Observer
{
public:
/**
* Is called when the dimensions and/or the
* values of one or more control points get altered.
*/
virtual void onPatchControlPointsChanged() = 0;
/**
* Is called when the patch shader is changed.
*/
virtual void onPatchTextureChanged() = 0;
/**
* Is called by the Patch destructor. After this call
* the observer is automatically detached.
*/
virtual void onPatchDestruction() = 0;
};
virtual void attachObserver(Observer* observer) = 0;
virtual void detachObserver(Observer* observer) = 0;
virtual ~IPatch() {}
// Resizes the patch to the given dimensions
virtual void setDims(std::size_t width, std::size_t height) = 0;
// Get the patch dimensions
virtual std::size_t getWidth() const = 0;
virtual std::size_t getHeight() const = 0;
// Return a defined patch control vertex at <row>,<col>
virtual PatchControl& ctrlAt(std::size_t row, std::size_t col) = 0;
virtual const PatchControl& ctrlAt(std::size_t row, std::size_t col) const = 0;
// Returns a copy of the fully tesselated patch geometry (slow!)
virtual PatchMesh getTesselatedPatchMesh() const = 0;
// Returns a copy of the render indices which can be passed to GL_QUAD_STRIPS (slow)
virtual PatchRenderIndices getRenderIndices() const = 0;
/**
* greebo: Inserts two columns before and after the column with index <colIndex>.
* Throws an GenericPatchException if an error occurs.
*/
virtual void insertColumns(std::size_t colIndex) = 0;
/**
* greebo: Inserts two rows before and after the row with index <rowIndex>.
* Throws an GenericPatchException if an error occurs.
*/
virtual void insertRows(std::size_t rowIndex) = 0;
/**
* greebo: Removes columns or rows right before and after the col/row
* with the given index, reducing the according dimension by 2.
*/
virtual void removePoints(bool columns, std::size_t index) = 0;
/**
* greebo: Appends two rows or columns at the beginning or the end.
*/
virtual void appendPoints(bool columns, bool beginning) = 0;
// Updates the patch tesselation matrix, call this everytime you're done with your PatchControl changes
virtual void controlPointsChanged() = 0;
// Check if the patch has invalid control points or width/height are zero
virtual bool isValid() const = 0;
// Check whether all control vertices are in the same 3D spot (with minimal tolerance)
virtual bool isDegenerate() const = 0;
// Shader handling
virtual const std::string& getShader() const = 0;
virtual void setShader(const std::string& name) = 0;
// greebo: returns true if the patch's shader is visible, false otherwise
virtual bool hasVisibleMaterial() const = 0;
// Returns the texture aspect ratio width/height
virtual float getTextureAspectRatio() const = 0;
/**
* greebo: Sets/gets whether this patch is a patchDef3 (fixed tesselation)
*/
virtual bool subdivisionsFixed() const = 0;
/** greebo: Returns the x,y subdivision values (for tesselation)
*/
virtual const Subdivisions& getSubdivisions() const = 0;
/** 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
*/
virtual void setFixedSubdivisions(bool isFixed, const Subdivisions& divisions) = 0;
virtual void undoSave() = 0;
// This translates the texture as much towards the origin in texture space as possible
// without changing its appearance.
virtual void normaliseTexture() = 0;
// Flips the control point matrix such that the patch is facing the opposite direction
virtual void invertMatrix() = 0;
/**
* greebo: This algorithm will transpose the patch matrix
* such that the actual control vertex contents remain the same
* but their indices in the patch matrix change.
* Rows become columns and vice versa.
*/
virtual void transposeMatrix() = 0;
// Tries to rearrange the row vertices to be spaced out more evenly
virtual void redisperseRows() = 0;
// Tries to rearrange the column vertices to be spaced out more evenly
virtual void redisperseColumns() = 0;
// Insert or remove columns or rows at the beginning or at the end
virtual void insertRemove(bool insert, bool column, bool first) = 0;
virtual void translateTexture(float s, float t) = 0;
// Rotates the texture of the patch by the given angle (in degrees)
virtual void rotateTexture(float angle) = 0;
// Scales the patch texture by the given factors (pass 1.05 for a +0.05 scale)
virtual void scaleTexture(float s, float t) = 0;
virtual void fitTexture(float repeatS, float repeatT) = 0;
// Flips the texture by the given flipAxis (0 == x-axis, 1 == y-axis)
virtual void flipTexture(int axis) = 0;
// Applies the "natural" scale to this patch
virtual void scaleTextureNaturally() = 0;
enum class AlignEdge
{
Top,
Bottom,
Left,
Right,
};
// Alligns the assigned texture at the given edge (if possible)
virtual void alignTexture(AlignEdge type) = 0;
// Reverts any transform that has been applied since the last time freezeTransform() was called
virtual void revertTransform() = 0;
// Returns the transformable control point (not the one returned by ctrlAt) - this one is
// part of the "transformed" working set of the patch which will either be saved on freezeTransform()
// or discarded on revertTransform().
virtual PatchControl& getTransformedCtrlAt(std::size_t row, std::size_t col) = 0;
// Promotes the current transformed state to the new base state
virtual void freezeTransform() = 0;
// Updates the patch tesselation based on the transformed set of control vertices
// Setting force to true will update the tesselation even if controlPointsChanged()
// hasn't been called in the meantime.
virtual void updateTesselation(bool force = false) = 0;
};
namespace patch
{
// The cap types for a patch
enum class CapType
{
Nocap, // "None" was already #defined somewhere
Bevel,
EndCap,
InvertedBevel,
InvertedEndCap,
Cylinder,
};
enum class PatchEditVertexType : std::size_t
{
Corners,
Inside,
NumberOfVertexTypes,
};
class IPatchSettings
{
public:
virtual ~IPatchSettings() {}
virtual const Vector3& getVertexColour(PatchEditVertexType type) const = 0;
virtual void setVertexColour(PatchEditVertexType type, const Vector3& value) = 0;
virtual sigc::signal<void>& signal_settingsChanged() = 0;
};
enum class PatchDefType
{
Def2,
Def3,
};
/**
* Patch management module interface.
*/
class IPatchModule :
public RegisterableModule
{
public:
virtual ~IPatchModule() {}
// Create a patch and return the sceneNode
virtual scene::INodePtr createPatch(PatchDefType type) = 0;
virtual IPatchSettings& getSettings() = 0;
};
}
class Patch;
class IPatchNode
{
public:
virtual ~IPatchNode() {}
/**
* greebo: Retrieves the actual patch from a PatchNode, only works from within the main module.
*/
virtual Patch& getPatchInternal() = 0;
// Get access to the patch interface
virtual IPatch& getPatch() = 0;
};
typedef std::shared_ptr<IPatchNode> IPatchNodePtr;
inline bool Node_isPatch(const scene::INodePtr& node)
{
return node->getNodeType() == scene::INode::Type::Patch;
//return std::dynamic_pointer_cast<IPatchNode>(node) != NULL;
}
inline IPatch* Node_getIPatch(const scene::INodePtr& node)
{
auto patchNode = std::dynamic_pointer_cast<IPatchNode>(node);
if (patchNode)
{
return &patchNode->getPatch();
}
return nullptr;
}
// Casts a node onto a patch
inline Patch* Node_getPatch(const scene::INodePtr& node)
{
auto patchNode = std::dynamic_pointer_cast<IPatchNode>(node);
if (patchNode)
{
return &patchNode->getPatchInternal();
}
return nullptr;
}
const char* const MODULE_PATCH = "PatchModule";
inline patch::IPatchModule& GlobalPatchModule()
{
static module::InstanceReference<patch::IPatchModule> _reference(MODULE_PATCH);
return _reference;
}