1 /*
2 Copyright (C) 2001-2006, William Joseph.
3 All Rights Reserved.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #if !defined(INCLUDED_PATCH_H)
23 #define INCLUDED_PATCH_H
24
25 /// \file
26 /// \brief The patch primitive.
27 ///
28 /// A 2-dimensional matrix of vertices that define a quadratic bezier surface.
29 /// The Boundary-Representation of this primitive is a triangle mesh.
30 /// The surface is recursively tesselated until the angle between each triangle
31 /// edge is smaller than a specified tolerance.
32
33
34 #include "nameable.h"
35 #include "ifilter.h"
36 #include "imap.h"
37 #include "cullable.h"
38 #include "renderable.h"
39 #include "editable.h"
40 #include "selectable.h"
41
42 #include "debugging/debugging.h"
43
44 #include <set>
45
46 #include "math/frustum.h"
47 #include "string/string.h"
48 #include "stream/stringstream.h"
49 #include "stream/textstream.h"
50 #include "xml/xmlelement.h"
51 #include "scenelib.h"
52 #include "transformlib.h"
53 #include "instancelib.h"
54 #include "selectionlib.h"
55 #include "traverselib.h"
56 #include "render.h"
57 #include "stringio.h"
58 #include "shaderlib.h"
59 #include "generic/callback.h"
60 #include "texturelib.h"
61 #include "xml/ixml.h"
62 #include "dragplanes.h"
63
64 enum EPatchType
65 {
66 ePatchTypeQuake3,
67 ePatchTypeDoom3,
68 };
69
70 extern int g_PatchSubdivideThreshold;
71
72
73 #define MIN_PATCH_WIDTH 3
74 #define MIN_PATCH_HEIGHT 3
75
76 extern std::size_t MAX_PATCH_WIDTH;
77 extern std::size_t MAX_PATCH_HEIGHT;
78
79 #define MAX_PATCH_ROWCTRL (((MAX_PATCH_WIDTH-1)-1)/2)
80 #define MAX_PATCH_COLCTRL (((MAX_PATCH_HEIGHT-1)-1)/2)
81
82 enum EPatchCap
83 {
84 eCapBevel,
85 eCapEndCap,
86 eCapIBevel,
87 eCapIEndCap,
88 eCapCylinder,
89 };
90
91 enum EPatchPrefab
92 {
93 ePlane,
94 eBevel,
95 eEndCap,
96 eCylinder,
97 eDenseCylinder,
98 eVeryDenseCylinder,
99 eSqCylinder,
100 eCone,
101 eSphere,
102 };
103
104 enum EMatrixMajor
105 {
106 ROW, COL,
107 };
108
109 struct BezierCurve
110 {
111 Vector3 crd;
112 Vector3 left;
113 Vector3 right;
114 };
115
116 const std::size_t BEZIERCURVETREE_MAX_INDEX = 1 << ((sizeof(std::size_t) * 8) - 1);
117
118 struct BezierCurveTree
119 {
120 std::size_t index;
121 BezierCurveTree* left;
122 BezierCurveTree* right;
123 };
124
BezierCurveTree_isLeaf(const BezierCurveTree * node)125 inline bool BezierCurveTree_isLeaf(const BezierCurveTree* node)
126 {
127 return node->left == 0 && node->right == 0;
128 }
129
130 void BezierCurveTree_Delete(BezierCurveTree *pCurve);
131
132
vertexpointer_arbitrarymeshvertex(const ArbitraryMeshVertex * array)133 inline VertexPointer vertexpointer_arbitrarymeshvertex(const ArbitraryMeshVertex* array)
134 {
135 return VertexPointer(VertexPointer::pointer(&array->vertex), sizeof(ArbitraryMeshVertex));
136 }
137
138 class PatchControl
139 {
140 public:
141 Vector3 m_vertex;
142 Vector2 m_texcoord;
143 };
144
145 typedef PatchControl* PatchControlIter;
146 typedef const PatchControl* PatchControlConstIter;
147
copy_ctrl(PatchControlIter ctrl,PatchControlConstIter begin,PatchControlConstIter end)148 inline void copy_ctrl(PatchControlIter ctrl, PatchControlConstIter begin, PatchControlConstIter end)
149 {
150 std::copy(begin, end, ctrl);
151 }
152
153 const Colour4b colour_corner(0, 255, 0, 255);
154 const Colour4b colour_inside(255, 0, 255, 255);
155
156 class Patch;
157
158 class PatchFilter
159 {
160 public:
161 virtual bool filter(const Patch& patch) const = 0;
162 };
163
164 bool patch_filtered(Patch& patch);
165 void add_patch_filter(PatchFilter& filter, int mask, bool invert = false);
166
167 void Patch_addTextureChangedCallback(const Callback& callback);
168 void Patch_textureChanged();
169
BezierCurveTreeArray_deleteAll(Array<BezierCurveTree * > & curveTrees)170 inline void BezierCurveTreeArray_deleteAll(Array<BezierCurveTree*>& curveTrees)
171 {
172 for(Array<BezierCurveTree*>::iterator i = curveTrees.begin(); i != curveTrees.end(); ++i)
173 {
174 BezierCurveTree_Delete(*i);
175 }
176 }
177
PatchControlArray_invert(Array<PatchControl> & ctrl,std::size_t width,std::size_t height)178 inline void PatchControlArray_invert(Array<PatchControl>& ctrl, std::size_t width, std::size_t height)
179 {
180 Array<PatchControl> tmp(width);
181
182 PatchControlIter from = ctrl.data() + (width * (height - 1));
183 PatchControlIter to = ctrl.data();
184 for(std::size_t h = 0; h != ((height - 1) >> 1); ++h, to += width, from -= width)
185 {
186 copy_ctrl(tmp.data(), to, to + width);
187 copy_ctrl(to, from, from + width);
188 copy_ctrl(from, tmp.data(), tmp.data() + width);
189 }
190 }
191
192 class PatchTesselation
193 {
194 public:
195 Array<ArbitraryMeshVertex> m_vertices;
196 Array<RenderIndex> m_indices;
197 std::size_t m_numStrips;
198 std::size_t m_lenStrips;
199
200 Array<std::size_t> m_arrayWidth;
201 std::size_t m_nArrayWidth;
202 Array<std::size_t> m_arrayHeight;
203 std::size_t m_nArrayHeight;
204
205 Array<BezierCurveTree*> m_curveTreeU;
206 Array<BezierCurveTree*> m_curveTreeV;
207 };
208
209 class RenderablePatchWireframe : public OpenGLRenderable
210 {
211 PatchTesselation& m_tess;
212 public:
RenderablePatchWireframe(PatchTesselation & tess)213 RenderablePatchWireframe(PatchTesselation& tess) : m_tess(tess)
214 {
215 }
render(RenderStateFlags state)216 void render(RenderStateFlags state) const
217 {
218 {
219 #if NV_DRIVER_BUG
220 glVertexPointer(3, GL_FLOAT, 0, 0);
221 glDrawArrays(GL_TRIANGLE_FAN, 0, 0);
222 #endif
223
224 std::size_t n = 0;
225 glVertexPointer(3, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->vertex);
226 for(std::size_t i = 0; i <= m_tess.m_curveTreeV.size(); ++i)
227 {
228 glDrawArrays(GL_LINE_STRIP, GLint(n), GLsizei(m_tess.m_nArrayWidth));
229
230 if(i == m_tess.m_curveTreeV.size()) break;
231
232 if(!BezierCurveTree_isLeaf(m_tess.m_curveTreeV[i]))
233 glDrawArrays(GL_LINE_STRIP, GLint(m_tess.m_curveTreeV[i]->index), GLsizei(m_tess.m_nArrayWidth));
234
235 n += (m_tess.m_arrayHeight[i]*m_tess.m_nArrayWidth);
236
237 }
238 }
239
240 {
241 const ArbitraryMeshVertex* p = m_tess.m_vertices.data();
242 std::size_t n = m_tess.m_nArrayWidth * sizeof(ArbitraryMeshVertex);
243 for(std::size_t i = 0; i <= m_tess.m_curveTreeU.size(); ++i)
244 {
245 glVertexPointer(3, GL_FLOAT, GLsizei(n), &p->vertex);
246 glDrawArrays(GL_LINE_STRIP, 0, GLsizei(m_tess.m_nArrayHeight));
247
248 if(i == m_tess.m_curveTreeU.size()) break;
249
250 if(!BezierCurveTree_isLeaf(m_tess.m_curveTreeU[i]))
251 {
252 glVertexPointer(3, GL_FLOAT, GLsizei(n), &(m_tess.m_vertices.data() + (m_tess.m_curveTreeU[i]->index))->vertex);
253 glDrawArrays(GL_LINE_STRIP, 0, GLsizei(m_tess.m_nArrayHeight));
254 }
255
256 p += m_tess.m_arrayWidth[i];
257 }
258 }
259 }
260 };
261
262 class RenderablePatchFixedWireframe : public OpenGLRenderable
263 {
264 PatchTesselation& m_tess;
265 public:
RenderablePatchFixedWireframe(PatchTesselation & tess)266 RenderablePatchFixedWireframe(PatchTesselation& tess) : m_tess(tess)
267 {
268 }
render(RenderStateFlags state)269 void render(RenderStateFlags state) const
270 {
271 glVertexPointer(3, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->vertex);
272 const RenderIndex* strip_indices = m_tess.m_indices.data();
273 for(std::size_t i = 0; i<m_tess.m_numStrips; i++, strip_indices += m_tess.m_lenStrips)
274 {
275 glDrawElements(GL_QUAD_STRIP, GLsizei(m_tess.m_lenStrips), RenderIndexTypeID, strip_indices);
276 }
277 }
278 };
279
280 class RenderablePatchSolid : public OpenGLRenderable
281 {
282 PatchTesselation& m_tess;
283 public:
RenderablePatchSolid(PatchTesselation & tess)284 RenderablePatchSolid(PatchTesselation& tess) : m_tess(tess)
285 {
286 }
287 void RenderNormals() const;
render(RenderStateFlags state)288 void render(RenderStateFlags state) const
289 {
290 #if 0
291 if((state & RENDER_FILL) == 0)
292 {
293 RenderablePatchWireframe(m_tess).render(state);
294 }
295 else
296 #endif
297 {
298 if((state & RENDER_BUMP) != 0)
299 {
300 if(GlobalShaderCache().useShaderLanguage())
301 {
302 glNormalPointer(GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->normal);
303 glVertexAttribPointerARB(c_attr_TexCoord0, 2, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->texcoord);
304 glVertexAttribPointerARB(c_attr_Tangent, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->tangent);
305 glVertexAttribPointerARB(c_attr_Binormal, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->bitangent);
306 }
307 else
308 {
309 glVertexAttribPointerARB(11, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->normal);
310 glVertexAttribPointerARB(8, 2, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->texcoord);
311 glVertexAttribPointerARB(9, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->tangent);
312 glVertexAttribPointerARB(10, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->bitangent);
313 }
314 }
315 else
316 {
317 glNormalPointer(GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->normal);
318 glTexCoordPointer(2, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->texcoord);
319 }
320 glVertexPointer(3, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->vertex);
321 const RenderIndex* strip_indices = m_tess.m_indices.data();
322 for(std::size_t i = 0; i<m_tess.m_numStrips; i++, strip_indices += m_tess.m_lenStrips)
323 {
324 glDrawElements(GL_QUAD_STRIP, GLsizei(m_tess.m_lenStrips), RenderIndexTypeID, strip_indices);
325 }
326 }
327
328 #if defined(_DEBUG)
329 RenderNormals();
330 #endif
331 }
332 };
333
334 // parametric surface defined by quadratic bezier control curves
335 class Patch :
336 public XMLImporter,
337 public XMLExporter,
338 public TransformNode,
339 public Bounded,
340 public Cullable,
341 public Snappable,
342 public Undoable,
343 public Filterable,
344 public Nameable
345 {
346 class xml_state_t
347 {
348 public:
349 enum EState
350 {
351 eDefault,
352 ePatch,
353 eMatrix,
354 eShader,
355 };
xml_state_t(EState state)356 xml_state_t(EState state)
357 : m_state(state)
358 {}
state()359 EState state() const
360 {
361 return m_state;
362 }
content()363 const char* content() const
364 {
365 return m_content.c_str();
366 }
write(const char * buffer,std::size_t length)367 std::size_t write(const char* buffer, std::size_t length)
368 {
369 return m_content.write(buffer, length);
370 }
371 private:
372 EState m_state;
373 StringOutputStream m_content;
374 };
375
376 std::vector<xml_state_t> m_xml_state;
377
378 typedef Array<PatchControl> PatchControlArray;
379
380 class SavedState : public UndoMemento
381 {
382 public:
SavedState(std::size_t width,std::size_t height,const PatchControlArray & ctrl,const char * shader,bool patchDef3,std::size_t subdivisions_x,std::size_t subdivisions_y)383 SavedState(
384 std::size_t width,
385 std::size_t height,
386 const PatchControlArray& ctrl,
387 const char* shader,
388 bool patchDef3,
389 std::size_t subdivisions_x,
390 std::size_t subdivisions_y
391 ) :
392 m_width(width),
393 m_height(height),
394 m_shader(shader),
395 m_ctrl(ctrl),
396 m_patchDef3(patchDef3),
397 m_subdivisions_x(subdivisions_x),
398 m_subdivisions_y(subdivisions_y)
399 {
400 }
401
release()402 void release()
403 {
404 delete this;
405 }
406
407 std::size_t m_width, m_height;
408 CopiedString m_shader;
409 PatchControlArray m_ctrl;
410 bool m_patchDef3;
411 std::size_t m_subdivisions_x;
412 std::size_t m_subdivisions_y;
413 };
414
415 public:
416 class Observer
417 {
418 public:
419 virtual void allocate(std::size_t size) = 0;
420 };
421
422 private:
423 typedef UniqueSet<Observer*> Observers;
424 Observers m_observers;
425
426 scene::Node* m_node;
427
428 AABB m_aabb_local; // local bbox
429
430 CopiedString m_shader;
431 Shader* m_state;
432
433 std::size_t m_width;
434 std::size_t m_height;
435 public:
436 bool m_patchDef3;
437 std::size_t m_subdivisions_x;
438 std::size_t m_subdivisions_y;
439 private:
440
441 UndoObserver* m_undoable_observer;
442 MapFile* m_map;
443
444 // dynamically allocated array of control points, size is m_width*m_height
445 PatchControlArray m_ctrl;
446 PatchControlArray m_ctrlTransformed;
447
448 PatchTesselation m_tess;
449 RenderablePatchSolid m_render_solid;
450 RenderablePatchWireframe m_render_wireframe;
451 RenderablePatchFixedWireframe m_render_wireframe_fixed;
452
453 static Shader* m_state_ctrl;
454 static Shader* m_state_lattice;
455 VertexBuffer<PointVertex> m_ctrl_vertices;
456 RenderableVertexBuffer m_render_ctrl;
457 IndexBuffer m_lattice_indices;
458 RenderableIndexBuffer m_render_lattice;
459
460 bool m_bOverlay;
461
462 bool m_transformChanged;
463 Callback m_evaluateTransform;
464 Callback m_boundsChanged;
465
construct()466 void construct()
467 {
468 m_bOverlay = false;
469 m_width = m_height = 0;
470
471 m_patchDef3 = false;
472 m_subdivisions_x = 0;
473 m_subdivisions_y = 0;
474
475 check_shader();
476 captureShader();
477
478 m_xml_state.push_back(xml_state_t::eDefault);
479 }
480
481 public:
482 Callback m_lightsChanged;
483
484 static int m_CycleCapIndex;// = 0;
485 static EPatchType m_type;
486
487 STRING_CONSTANT(Name, "Patch");
488
Patch(scene::Node & node,const Callback & evaluateTransform,const Callback & boundsChanged)489 Patch(scene::Node& node, const Callback& evaluateTransform, const Callback& boundsChanged) :
490 m_node(&node),
491 m_shader(texdef_name_default()),
492 m_state(0),
493 m_undoable_observer(0),
494 m_map(0),
495 m_render_solid(m_tess),
496 m_render_wireframe(m_tess),
497 m_render_wireframe_fixed(m_tess),
498 m_render_ctrl(GL_POINTS, m_ctrl_vertices),
499 m_render_lattice(GL_LINES, m_lattice_indices, m_ctrl_vertices),
500 m_transformChanged(false),
501 m_evaluateTransform(evaluateTransform),
502 m_boundsChanged(boundsChanged)
503 {
504 construct();
505 }
Patch(const Patch & other,scene::Node & node,const Callback & evaluateTransform,const Callback & boundsChanged)506 Patch(const Patch& other, scene::Node& node, const Callback& evaluateTransform, const Callback& boundsChanged) :
507 m_node(&node),
508 m_shader(texdef_name_default()),
509 m_state(0),
510 m_undoable_observer(0),
511 m_map(0),
512 m_render_solid(m_tess),
513 m_render_wireframe(m_tess),
514 m_render_wireframe_fixed(m_tess),
515 m_render_ctrl(GL_POINTS, m_ctrl_vertices),
516 m_render_lattice(GL_LINES, m_lattice_indices, m_ctrl_vertices),
517 m_transformChanged(false),
518 m_evaluateTransform(evaluateTransform),
519 m_boundsChanged(boundsChanged)
520 {
521 construct();
522
523 m_patchDef3 = other.m_patchDef3;
524 m_subdivisions_x = other.m_subdivisions_x;
525 m_subdivisions_y = other.m_subdivisions_y;
526 setDims(other.m_width, other.m_height);
527 copy_ctrl(m_ctrl.data(), other.m_ctrl.data(), other.m_ctrl.data()+(m_width*m_height));
528 SetShader(other.m_shader.c_str());
529 controlPointsChanged();
530 }
531
Patch(const Patch & other)532 Patch(const Patch& other) :
533 XMLImporter(other),
534 XMLExporter(other),
535 TransformNode(other),
536 Bounded(other),
537 Cullable(other),
538 Undoable(other),
539 Filterable(other),
540 Nameable(other),
541 m_state(0),
542 m_undoable_observer(0),
543 m_map(0),
544 m_render_solid(m_tess),
545 m_render_wireframe(m_tess),
546 m_render_wireframe_fixed(m_tess),
547 m_render_ctrl(GL_POINTS, m_ctrl_vertices),
548 m_render_lattice(GL_LINES, m_lattice_indices, m_ctrl_vertices),
549 m_transformChanged(false),
550 m_evaluateTransform(other.m_evaluateTransform),
551 m_boundsChanged(other.m_boundsChanged)
552 {
553 m_bOverlay = false;
554
555 m_patchDef3 = other.m_patchDef3;
556 m_subdivisions_x = other.m_subdivisions_x;
557 m_subdivisions_y = other.m_subdivisions_y;
558 setDims(other.m_width, other.m_height);
559 copy_ctrl(m_ctrl.data(), other.m_ctrl.data(), other.m_ctrl.data()+(m_width*m_height));
560 SetShader(other.m_shader.c_str());
561 controlPointsChanged();
562 }
563
~Patch()564 ~Patch()
565 {
566 BezierCurveTreeArray_deleteAll(m_tess.m_curveTreeU);
567 BezierCurveTreeArray_deleteAll(m_tess.m_curveTreeV);
568
569 releaseShader();
570
571 ASSERT_MESSAGE(m_observers.empty(), "Patch::~Patch: observers still attached");
572 }
573
574 InstanceCounter m_instanceCounter;
instanceAttach(const scene::Path & path)575 void instanceAttach(const scene::Path& path)
576 {
577 if(++m_instanceCounter.m_count == 1)
578 {
579 m_state->incrementUsed();
580 m_map = path_find_mapfile(path.begin(), path.end());
581 m_undoable_observer = GlobalUndoSystem().observer(this);
582 GlobalFilterSystem().registerFilterable(*this);
583 }
584 else
585 {
586 ASSERT_MESSAGE(path_find_mapfile(path.begin(), path.end()) == m_map, "node is instanced across more than one file");
587 }
588 }
instanceDetach(const scene::Path & path)589 void instanceDetach(const scene::Path& path)
590 {
591 if(--m_instanceCounter.m_count == 0)
592 {
593 m_map = 0;
594 m_undoable_observer = 0;
595 GlobalUndoSystem().release(this);
596 GlobalFilterSystem().unregisterFilterable(*this);
597 m_state->decrementUsed();
598 }
599 }
600
name()601 const char* name() const
602 {
603 return "patch";
604 }
attach(const NameCallback & callback)605 void attach(const NameCallback& callback)
606 {
607 }
detach(const NameCallback & callback)608 void detach(const NameCallback& callback)
609 {
610 }
611
attach(Observer * observer)612 void attach(Observer* observer)
613 {
614 observer->allocate(m_width * m_height);
615
616 m_observers.insert(observer);
617 }
detach(Observer * observer)618 void detach(Observer* observer)
619 {
620 m_observers.erase(observer);
621 }
622
updateFiltered()623 void updateFiltered()
624 {
625 if(m_node != 0)
626 {
627 if(patch_filtered(*this))
628 {
629 m_node->enable(scene::Node::eFiltered);
630 }
631 else
632 {
633 m_node->disable(scene::Node::eFiltered);
634 }
635 }
636 }
637
onAllocate(std::size_t size)638 void onAllocate(std::size_t size)
639 {
640 for(Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i)
641 {
642 (*i)->allocate(size);
643 }
644 }
645
localToParent()646 const Matrix4& localToParent() const
647 {
648 return g_matrix4_identity;
649 }
localAABB()650 const AABB& localAABB() const
651 {
652 return m_aabb_local;
653 }
intersectVolume(const VolumeTest & test,const Matrix4 & localToWorld)654 VolumeIntersectionValue intersectVolume(const VolumeTest& test, const Matrix4& localToWorld) const
655 {
656 return test.TestAABB(m_aabb_local, localToWorld);
657 }
render_solid(Renderer & renderer,const VolumeTest & volume,const Matrix4 & localToWorld)658 void render_solid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
659 {
660 renderer.SetState(m_state, Renderer::eFullMaterials);
661 renderer.addRenderable(m_render_solid, localToWorld);
662 }
render_wireframe(Renderer & renderer,const VolumeTest & volume,const Matrix4 & localToWorld)663 void render_wireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
664 {
665 renderer.SetState(m_state, Renderer::eFullMaterials);
666 if(m_patchDef3)
667 {
668 renderer.addRenderable(m_render_wireframe_fixed, localToWorld);
669 }
670 else
671 {
672 renderer.addRenderable(m_render_wireframe, localToWorld);
673 }
674 }
675
render_component(Renderer & renderer,const VolumeTest & volume,const Matrix4 & localToWorld)676 void render_component(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
677 {
678 renderer.SetState(m_state_lattice, Renderer::eWireframeOnly);
679 renderer.SetState(m_state_lattice, Renderer::eFullMaterials);
680 renderer.addRenderable(m_render_lattice, localToWorld);
681
682 renderer.SetState(m_state_ctrl, Renderer::eWireframeOnly);
683 renderer.SetState(m_state_ctrl, Renderer::eFullMaterials);
684 renderer.addRenderable(m_render_ctrl, localToWorld);
685 }
testSelect(Selector & selector,SelectionTest & test)686 void testSelect(Selector& selector, SelectionTest& test)
687 {
688 SelectionIntersection best;
689 IndexPointer::index_type* pIndex = m_tess.m_indices.data();
690 for(std::size_t s=0; s<m_tess.m_numStrips; s++)
691 {
692 test.TestQuadStrip(vertexpointer_arbitrarymeshvertex(m_tess.m_vertices.data()), IndexPointer(pIndex, m_tess.m_lenStrips), best);
693 pIndex += m_tess.m_lenStrips;
694 }
695 if(best.valid())
696 {
697 selector.addIntersection(best);
698 }
699 }
transform(const Matrix4 & matrix)700 void transform(const Matrix4& matrix)
701 {
702 for(PatchControlIter i = m_ctrlTransformed.data(); i != m_ctrlTransformed.data() + m_ctrlTransformed.size(); ++i)
703 {
704 matrix4_transform_point(matrix, (*i).m_vertex);
705 }
706
707 if(matrix4_handedness(matrix) == MATRIX4_LEFTHANDED)
708 {
709 PatchControlArray_invert(m_ctrlTransformed, m_width, m_height);
710 }
711 UpdateCachedData();
712 }
transformChanged()713 void transformChanged()
714 {
715 m_transformChanged = true;
716 m_lightsChanged();
717 SceneChangeNotify();
718 }
719 typedef MemberCaller<Patch, &Patch::transformChanged> TransformChangedCaller;
720
evaluateTransform()721 void evaluateTransform()
722 {
723 if(m_transformChanged)
724 {
725 m_transformChanged = false;
726 revertTransform();
727 m_evaluateTransform();
728 }
729 }
730
revertTransform()731 void revertTransform()
732 {
733 m_ctrlTransformed = m_ctrl;
734 }
freezeTransform()735 void freezeTransform()
736 {
737 undoSave();
738 evaluateTransform();
739 ASSERT_MESSAGE(m_ctrlTransformed.size() == m_ctrl.size(), "Patch::freeze: size mismatch");
740 std::copy(m_ctrlTransformed.begin(), m_ctrlTransformed.end(), m_ctrl.begin());
741 }
742
controlPointsChanged()743 void controlPointsChanged()
744 {
745 transformChanged();
746 evaluateTransform();
747 UpdateCachedData();
748 }
749
snapto(float snap)750 void snapto(float snap)
751 {
752 undoSave();
753
754 for(PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i)
755 {
756 vector3_snap((*i).m_vertex, snap);
757 }
758
759 controlPointsChanged();
760 }
761
762
763
764
765 void RenderDebug(RenderStateFlags state) const;
766 void RenderNormals(RenderStateFlags state) const;
767
pushElement(const XMLElement & element)768 void pushElement(const XMLElement& element)
769 {
770 switch(m_xml_state.back().state())
771 {
772 case xml_state_t::eDefault:
773 ASSERT_MESSAGE(string_equal(element.name(), "patch"), "parse error");
774 m_xml_state.push_back(xml_state_t::ePatch);
775 break;
776 case xml_state_t::ePatch:
777 if(string_equal(element.name(), "matrix"))
778 {
779 setDims(atoi(element.attribute("width")), atoi(element.attribute("height")));
780 m_xml_state.push_back(xml_state_t::eMatrix);
781 }
782 else if(string_equal(element.name(), "shader"))
783 {
784 m_xml_state.push_back(xml_state_t::eShader);
785 }
786 break;
787 default:
788 ERROR_MESSAGE("parse error");
789 }
790
791 }
popElement(const char * name)792 void popElement(const char* name)
793 {
794 switch(m_xml_state.back().state())
795 {
796 case xml_state_t::eDefault:
797 ERROR_MESSAGE("parse error");
798 break;
799 case xml_state_t::ePatch:
800 break;
801 case xml_state_t::eMatrix:
802 {
803 StringTokeniser content(m_xml_state.back().content());
804
805 for(PatchControlIter i = m_ctrl.data(), end = m_ctrl.data() + m_ctrl.size(); i != end; ++i)
806 {
807 (*i).m_vertex[0] = string_read_float(content.getToken());
808 (*i).m_vertex[1] = string_read_float(content.getToken());
809 (*i).m_vertex[2] = string_read_float(content.getToken());
810 (*i).m_texcoord[0] = string_read_float(content.getToken());
811 (*i).m_texcoord[1] = string_read_float(content.getToken());
812 }
813 controlPointsChanged();
814 }
815 break;
816 case xml_state_t::eShader:
817 {
818 SetShader(m_xml_state.back().content());
819 }
820 break;
821 default:
822 ERROR_MESSAGE("parse error");
823 }
824
825 ASSERT_MESSAGE(!m_xml_state.empty(), "popping empty stack");
826 m_xml_state.pop_back();
827 }
write(const char * buffer,std::size_t length)828 std::size_t write(const char* buffer, std::size_t length)
829 {
830 switch(m_xml_state.back().state())
831 {
832 case xml_state_t::eDefault:
833 break;
834 case xml_state_t::ePatch:
835 break;
836 case xml_state_t::eMatrix:
837 case xml_state_t::eShader:
838 return m_xml_state.back().write(buffer, length);
839 break;
840 default:
841 ERROR_MESSAGE("parse error");
842 }
843 return length;
844 }
845
exportXML(XMLImporter & importer)846 void exportXML(XMLImporter& importer)
847 {
848 StaticElement patchElement("patch");
849 importer.pushElement(patchElement);
850
851 {
852 const StaticElement element("shader");
853 importer.pushElement(element);
854 importer.write(m_shader.c_str(), strlen(m_shader.c_str()));
855 importer.popElement(element.name());
856 }
857
858 {
859 char width[16], height[16];
860 sprintf(width, "%u", Unsigned(m_width));
861 sprintf(height, "%u", Unsigned(m_height));
862 StaticElement element("matrix");
863 element.insertAttribute("width", width);
864 element.insertAttribute("height", height);
865
866 importer.pushElement(element);
867 {
868 for(PatchControlIter i = m_ctrl.data(), end = m_ctrl.data() + m_ctrl.size(); i != end; ++i)
869 {
870 importer << (*i).m_vertex[0]
871 << ' ' << (*i).m_vertex[1]
872 << ' ' << (*i).m_vertex[2]
873 << ' ' << (*i).m_texcoord[0]
874 << ' ' << (*i).m_texcoord[1];
875 }
876 }
877 importer.popElement(element.name());
878 }
879
880 importer.popElement(patchElement.name());
881 }
882
883 void UpdateCachedData();
884
GetShader()885 const char *GetShader() const
886 {
887 return m_shader.c_str();
888 }
SetShader(const char * name)889 void SetShader(const char* name)
890 {
891 ASSERT_NOTNULL(name);
892
893 if(shader_equal(m_shader.c_str(), name))
894 return;
895
896 undoSave();
897
898 if(m_instanceCounter.m_count != 0)
899 {
900 m_state->decrementUsed();
901 }
902 releaseShader();
903 m_shader = name;
904 captureShader();
905 if(m_instanceCounter.m_count != 0)
906 {
907 m_state->incrementUsed();
908 }
909
910 check_shader();
911 Patch_textureChanged();
912 }
getShaderFlags()913 int getShaderFlags() const
914 {
915 if(m_state != 0)
916 {
917 return m_state->getFlags();
918 }
919 return 0;
920 }
921
922 typedef PatchControl* iterator;
923 typedef const PatchControl* const_iterator;
924
begin()925 iterator begin()
926 {
927 return m_ctrl.data();
928 }
begin()929 const_iterator begin() const
930 {
931 return m_ctrl.data();
932 }
end()933 iterator end()
934 {
935 return m_ctrl.data() + m_ctrl.size();
936 }
end()937 const_iterator end() const
938 {
939 return m_ctrl.data() + m_ctrl.size();
940 }
941
getControlPointsTransformed()942 PatchControlArray& getControlPointsTransformed()
943 {
944 return m_ctrlTransformed;
945 }
946
947 void setDims (std::size_t w, std::size_t h);
getWidth()948 std::size_t getWidth() const
949 {
950 return m_width;
951 }
getHeight()952 std::size_t getHeight() const
953 {
954 return m_height;
955 }
ctrlAt(std::size_t row,std::size_t col)956 PatchControl& ctrlAt(std::size_t row, std::size_t col)
957 {
958 return m_ctrl[row*m_width+col];
959 }
ctrlAt(std::size_t row,std::size_t col)960 const PatchControl& ctrlAt(std::size_t row, std::size_t col) const
961 {
962 return m_ctrl[row*m_width+col];
963 }
964
965 void ConstructPrefab(const AABB& aabb, EPatchPrefab eType, int axis, std::size_t width = 3, std::size_t height = 3);
966 void constructPlane(const AABB& aabb, int axis, std::size_t width, std::size_t height);
967 void InvertMatrix();
968 void TransposeMatrix();
969 void Redisperse(EMatrixMajor mt);
970 void InsertRemove(bool bInsert, bool bColumn, bool bFirst);
971 Patch* MakeCap(Patch* patch, EPatchCap eType, EMatrixMajor mt, bool bFirst);
972 void ConstructSeam(EPatchCap eType, Vector3* p, std::size_t width);
973
974 void FlipTexture(int nAxis);
975 void TranslateTexture(float s, float t);
976 void ScaleTexture(float s, float t);
977 void RotateTexture(float angle);
978 void SetTextureRepeat(float s, float t); // call with s=1 t=1 for FIT
979 void CapTexture();
980 void NaturalTexture();
981 void ProjectTexture(int nAxis);
982
undoSave()983 void undoSave()
984 {
985 if(m_map != 0)
986 {
987 m_map->changed();
988 }
989 if(m_undoable_observer != 0)
990 {
991 m_undoable_observer->save(this);
992 }
993 }
994
exportState()995 UndoMemento* exportState() const
996 {
997 return new SavedState(m_width, m_height, m_ctrl, m_shader.c_str(), m_patchDef3, m_subdivisions_x, m_subdivisions_y);
998 }
importState(const UndoMemento * state)999 void importState(const UndoMemento* state)
1000 {
1001 undoSave();
1002
1003 const SavedState& other = *(static_cast<const SavedState*>(state));
1004
1005 // begin duplicate of SavedState copy constructor, needs refactoring
1006
1007 // copy construct
1008 {
1009 m_width = other.m_width;
1010 m_height = other.m_height;
1011 SetShader(other.m_shader.c_str());
1012 m_ctrl = other.m_ctrl;
1013 onAllocate(m_ctrl.size());
1014 m_patchDef3 = other.m_patchDef3;
1015 m_subdivisions_x = other.m_subdivisions_x;
1016 m_subdivisions_y = other.m_subdivisions_y;
1017 }
1018
1019 // end duplicate code
1020
1021 Patch_textureChanged();
1022
1023 controlPointsChanged();
1024 }
1025
constructStatic(EPatchType type)1026 static void constructStatic(EPatchType type)
1027 {
1028 Patch::m_type = type;
1029 Patch::m_state_ctrl = GlobalShaderCache().capture("$POINT");
1030 Patch::m_state_lattice = GlobalShaderCache().capture("$LATTICE");
1031 }
1032
destroyStatic()1033 static void destroyStatic()
1034 {
1035 GlobalShaderCache().release("$LATTICE");
1036 GlobalShaderCache().release("$POINT");
1037 }
1038 private:
captureShader()1039 void captureShader()
1040 {
1041 m_state = GlobalShaderCache().capture(m_shader.c_str());
1042 }
1043
releaseShader()1044 void releaseShader()
1045 {
1046 GlobalShaderCache().release(m_shader.c_str());
1047 }
1048
check_shader()1049 void check_shader()
1050 {
1051 if(!shader_valid(GetShader()))
1052 {
1053 globalErrorStream() << "patch has invalid texture name: '" << GetShader() << "'\n";
1054 }
1055 }
1056
1057 void InsertPoints(EMatrixMajor mt, bool bFirst);
1058 void RemovePoints(EMatrixMajor mt, bool bFirst);
1059
1060 void AccumulateBBox();
1061
1062 void TesselateSubMatrixFixed(ArbitraryMeshVertex* vertices, std::size_t strideX, std::size_t strideY, unsigned int nFlagsX, unsigned int nFlagsY, PatchControl* subMatrix[3][3]);
1063
1064 // uses binary trees representing bezier curves to recursively tesselate a bezier sub-patch
1065 void TesselateSubMatrix( const BezierCurveTree *BX, const BezierCurveTree *BY,
1066 std::size_t offStartX, std::size_t offStartY,
1067 std::size_t offEndX, std::size_t offEndY,
1068 std::size_t nFlagsX, std::size_t nFlagsY,
1069 Vector3& left, Vector3& mid, Vector3& right,
1070 Vector2& texLeft, Vector2& texMid, Vector2& texRight,
1071 bool bTranspose );
1072
1073 // tesselates the entire surface
1074 void BuildTesselationCurves(EMatrixMajor major);
1075 void accumulateVertexTangentSpace(std::size_t index, Vector3 tangentX[6], Vector3 tangentY[6], Vector2 tangentS[6], Vector2 tangentT[6], std::size_t index0, std::size_t index1);
1076 void BuildVertexArray();
1077 };
1078
Patch_importHeader(Patch & patch,Tokeniser & tokeniser)1079 inline bool Patch_importHeader(Patch& patch, Tokeniser& tokeniser)
1080 {
1081 tokeniser.nextLine();
1082 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "{"));
1083 return true;
1084 }
1085
Patch_importShader(Patch & patch,Tokeniser & tokeniser)1086 inline bool Patch_importShader(Patch& patch, Tokeniser& tokeniser)
1087 {
1088 // parse shader name
1089 tokeniser.nextLine();
1090 const char* texture = tokeniser.getToken();
1091 if(texture == 0)
1092 {
1093 Tokeniser_unexpectedError(tokeniser, texture, "#texture-name");
1094 return false;
1095 }
1096 if(string_equal(texture, "NULL"))
1097 {
1098 patch.SetShader(texdef_name_default());
1099 }
1100 else
1101 {
1102 StringOutputStream shader(string_length(GlobalTexturePrefix_get()) + string_length(texture));
1103 shader << GlobalTexturePrefix_get() << texture;
1104 patch.SetShader(shader.c_str());
1105 }
1106 return true;
1107 }
1108
PatchDoom3_importShader(Patch & patch,Tokeniser & tokeniser)1109 inline bool PatchDoom3_importShader(Patch& patch, Tokeniser& tokeniser)
1110 {
1111 // parse shader name
1112 tokeniser.nextLine();
1113 const char *shader = tokeniser.getToken();
1114 if(shader == 0)
1115 {
1116 Tokeniser_unexpectedError(tokeniser, shader, "#shader-name");
1117 return false;
1118 }
1119 if(string_equal(shader, "_emptyname"))
1120 {
1121 shader = texdef_name_default();
1122 }
1123 patch.SetShader(shader);
1124 return true;
1125 }
1126
Patch_importParams(Patch & patch,Tokeniser & tokeniser)1127 inline bool Patch_importParams(Patch& patch, Tokeniser& tokeniser)
1128 {
1129 tokeniser.nextLine();
1130 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
1131
1132 // parse matrix dimensions
1133 {
1134 std::size_t c, r;
1135 RETURN_FALSE_IF_FAIL(Tokeniser_getSize(tokeniser, c));
1136 RETURN_FALSE_IF_FAIL(Tokeniser_getSize(tokeniser, r));
1137
1138 patch.setDims(c, r);
1139 }
1140
1141 if(patch.m_patchDef3)
1142 {
1143 RETURN_FALSE_IF_FAIL(Tokeniser_getSize(tokeniser, patch.m_subdivisions_x));
1144 RETURN_FALSE_IF_FAIL(Tokeniser_getSize(tokeniser, patch.m_subdivisions_y));
1145 }
1146
1147 // ignore contents/flags/value
1148 int tmp;
1149 RETURN_FALSE_IF_FAIL(Tokeniser_getInteger(tokeniser, tmp));
1150 RETURN_FALSE_IF_FAIL(Tokeniser_getInteger(tokeniser, tmp));
1151 RETURN_FALSE_IF_FAIL(Tokeniser_getInteger(tokeniser, tmp));
1152
1153 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
1154 return true;
1155 }
1156
Patch_importMatrix(Patch & patch,Tokeniser & tokeniser)1157 inline bool Patch_importMatrix(Patch& patch, Tokeniser& tokeniser)
1158 {
1159 // parse matrix
1160 tokeniser.nextLine();
1161 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
1162 {
1163 for(std::size_t c=0; c<patch.getWidth(); c++)
1164 {
1165 tokeniser.nextLine();
1166 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
1167 for(std::size_t r=0; r<patch.getHeight(); r++)
1168 {
1169 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
1170
1171 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r,c).m_vertex[0]));
1172 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r,c).m_vertex[1]));
1173 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r,c).m_vertex[2]));
1174 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r,c).m_texcoord[0]));
1175 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r,c).m_texcoord[1]));
1176
1177 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
1178 }
1179 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
1180 }
1181 }
1182 tokeniser.nextLine();
1183 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
1184 return true;
1185 }
1186
Patch_importFooter(Patch & patch,Tokeniser & tokeniser)1187 inline bool Patch_importFooter(Patch& patch, Tokeniser& tokeniser)
1188 {
1189 patch.controlPointsChanged();
1190
1191 tokeniser.nextLine();
1192 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "}"));
1193
1194 tokeniser.nextLine();
1195 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "}"));
1196 return true;
1197 }
1198
1199 class PatchTokenImporter : public MapImporter
1200 {
1201 Patch& m_patch;
1202 public:
PatchTokenImporter(Patch & patch)1203 PatchTokenImporter(Patch& patch) : m_patch(patch)
1204 {
1205 }
importTokens(Tokeniser & tokeniser)1206 bool importTokens(Tokeniser& tokeniser)
1207 {
1208 RETURN_FALSE_IF_FAIL(Patch_importHeader(m_patch, tokeniser));
1209 RETURN_FALSE_IF_FAIL(Patch_importShader(m_patch, tokeniser));
1210 RETURN_FALSE_IF_FAIL(Patch_importParams(m_patch, tokeniser));
1211 RETURN_FALSE_IF_FAIL(Patch_importMatrix(m_patch, tokeniser));
1212 RETURN_FALSE_IF_FAIL(Patch_importFooter(m_patch, tokeniser));
1213
1214 return true;
1215 }
1216 };
1217
1218 class PatchDoom3TokenImporter : public MapImporter
1219 {
1220 Patch& m_patch;
1221 public:
PatchDoom3TokenImporter(Patch & patch)1222 PatchDoom3TokenImporter(Patch& patch) : m_patch(patch)
1223 {
1224 }
importTokens(Tokeniser & tokeniser)1225 bool importTokens(Tokeniser& tokeniser)
1226 {
1227 RETURN_FALSE_IF_FAIL(Patch_importHeader(m_patch, tokeniser));
1228 RETURN_FALSE_IF_FAIL(PatchDoom3_importShader(m_patch, tokeniser));
1229 RETURN_FALSE_IF_FAIL(Patch_importParams(m_patch, tokeniser));
1230 RETURN_FALSE_IF_FAIL(Patch_importMatrix(m_patch, tokeniser));
1231 RETURN_FALSE_IF_FAIL(Patch_importFooter(m_patch, tokeniser));
1232
1233 return true;
1234 }
1235 };
1236
Patch_exportHeader(const Patch & patch,TokenWriter & writer)1237 inline void Patch_exportHeader(const Patch& patch, TokenWriter& writer)
1238 {
1239 writer.writeToken("{");
1240 writer.nextLine();
1241 writer.writeToken(patch.m_patchDef3 ? "patchDef3" : "patchDef2");
1242 writer.nextLine();
1243 writer.writeToken("{");
1244 writer.nextLine();
1245 }
1246
Patch_exportShader(const Patch & patch,TokenWriter & writer)1247 inline void Patch_exportShader(const Patch& patch, TokenWriter& writer)
1248 {
1249 // write shader name
1250 if(*(shader_get_textureName(patch.GetShader())) == '\0')
1251 {
1252 writer.writeToken("NULL");
1253 }
1254 else
1255 {
1256 writer.writeToken(shader_get_textureName(patch.GetShader()));
1257 }
1258 writer.nextLine();
1259 }
1260
PatchDoom3_exportShader(const Patch & patch,TokenWriter & writer)1261 inline void PatchDoom3_exportShader(const Patch& patch, TokenWriter& writer)
1262 {
1263 // write shader name
1264 if(*(shader_get_textureName(patch.GetShader())) == '\0')
1265 {
1266 writer.writeString("_emptyname");
1267 }
1268 else
1269 {
1270 writer.writeString(patch.GetShader());
1271 }
1272 writer.nextLine();
1273 }
1274
Patch_exportParams(const Patch & patch,TokenWriter & writer)1275 inline void Patch_exportParams(const Patch& patch, TokenWriter& writer)
1276 {
1277 // write matrix dimensions
1278 writer.writeToken("(");
1279 writer.writeUnsigned(patch.getWidth());
1280 writer.writeUnsigned(patch.getHeight());
1281 if(patch.m_patchDef3)
1282 {
1283 writer.writeUnsigned(patch.m_subdivisions_x);
1284 writer.writeUnsigned(patch.m_subdivisions_y);
1285 }
1286 writer.writeInteger(0);
1287 writer.writeInteger(0);
1288 writer.writeInteger(0);
1289 writer.writeToken(")");
1290 writer.nextLine();
1291 }
1292
Patch_exportMatrix(const Patch & patch,TokenWriter & writer)1293 inline void Patch_exportMatrix(const Patch& patch, TokenWriter& writer)
1294 {
1295 // write matrix
1296 writer.writeToken("(");
1297 writer.nextLine();
1298 for(std::size_t c=0; c<patch.getWidth(); c++)
1299 {
1300 writer.writeToken("(");
1301 for(std::size_t r=0; r<patch.getHeight(); r++)
1302 {
1303 writer.writeToken("(");
1304
1305 writer.writeFloat(patch.ctrlAt(r,c).m_vertex[0]);
1306 writer.writeFloat(patch.ctrlAt(r,c).m_vertex[1]);
1307 writer.writeFloat(patch.ctrlAt(r,c).m_vertex[2]);
1308 writer.writeFloat(patch.ctrlAt(r,c).m_texcoord[0]);
1309 writer.writeFloat(patch.ctrlAt(r,c).m_texcoord[1]);
1310
1311 writer.writeToken(")");
1312 }
1313 writer.writeToken(")");
1314 writer.nextLine();
1315 }
1316 writer.writeToken(")");
1317 writer.nextLine();
1318 }
1319
Patch_exportFooter(const Patch & patch,TokenWriter & writer)1320 inline void Patch_exportFooter(const Patch& patch, TokenWriter& writer)
1321 {
1322 writer.writeToken("}");
1323 writer.nextLine();
1324 writer.writeToken("}");
1325 writer.nextLine();
1326 }
1327
1328 class PatchTokenExporter : public MapExporter
1329 {
1330 const Patch& m_patch;
1331 public:
PatchTokenExporter(Patch & patch)1332 PatchTokenExporter(Patch& patch) : m_patch(patch)
1333 {
1334 }
exportTokens(TokenWriter & writer)1335 void exportTokens(TokenWriter& writer) const
1336 {
1337 Patch_exportHeader(m_patch, writer);
1338 Patch_exportShader(m_patch, writer);
1339 Patch_exportParams(m_patch, writer);
1340 Patch_exportMatrix(m_patch, writer);
1341 Patch_exportFooter(m_patch, writer);
1342 }
1343 };
1344
1345 class PatchDoom3TokenExporter : public MapExporter
1346 {
1347 const Patch& m_patch;
1348 public:
PatchDoom3TokenExporter(Patch & patch)1349 PatchDoom3TokenExporter(Patch& patch) : m_patch(patch)
1350 {
1351 }
exportTokens(TokenWriter & writer)1352 void exportTokens(TokenWriter& writer) const
1353 {
1354 Patch_exportHeader(m_patch, writer);
1355 PatchDoom3_exportShader(m_patch, writer);
1356 Patch_exportParams(m_patch, writer);
1357 Patch_exportMatrix(m_patch, writer);
1358 Patch_exportFooter(m_patch, writer);
1359 }
1360 };
1361
1362 class PatchControlInstance
1363 {
1364 public:
1365 PatchControl* m_ctrl;
1366 ObservedSelectable m_selectable;
1367
PatchControlInstance(PatchControl * ctrl,const SelectionChangeCallback & observer)1368 PatchControlInstance(PatchControl* ctrl, const SelectionChangeCallback& observer)
1369 : m_ctrl(ctrl), m_selectable(observer)
1370 {
1371 }
1372
testSelect(Selector & selector,SelectionTest & test)1373 void testSelect(Selector& selector, SelectionTest& test)
1374 {
1375 SelectionIntersection best;
1376 test.TestPoint(m_ctrl->m_vertex, best);
1377 if(best.valid())
1378 {
1379 Selector_add(selector, m_selectable, best);
1380 }
1381 }
snapto(float snap)1382 void snapto(float snap)
1383 {
1384 vector3_snap(m_ctrl->m_vertex, snap);
1385 }
1386 };
1387
1388
1389 class PatchInstance :
1390 public Patch::Observer,
1391 public scene::Instance,
1392 public Selectable,
1393 public Renderable,
1394 public SelectionTestable,
1395 public ComponentSelectionTestable,
1396 public ComponentEditable,
1397 public ComponentSnappable,
1398 public PlaneSelectable,
1399 public LightCullable
1400 {
1401 class TypeCasts
1402 {
1403 InstanceTypeCastTable m_casts;
1404 public:
TypeCasts()1405 TypeCasts()
1406 {
1407 InstanceStaticCast<PatchInstance, Selectable>::install(m_casts);
1408 InstanceContainedCast<PatchInstance, Bounded>::install(m_casts);
1409 InstanceContainedCast<PatchInstance, Cullable>::install(m_casts);
1410 InstanceStaticCast<PatchInstance, Renderable>::install(m_casts);
1411 InstanceStaticCast<PatchInstance, SelectionTestable>::install(m_casts);
1412 InstanceStaticCast<PatchInstance, ComponentSelectionTestable>::install(m_casts);
1413 InstanceStaticCast<PatchInstance, ComponentEditable>::install(m_casts);
1414 InstanceStaticCast<PatchInstance, ComponentSnappable>::install(m_casts);
1415 InstanceStaticCast<PatchInstance, PlaneSelectable>::install(m_casts);
1416 InstanceIdentityCast<PatchInstance>::install(m_casts);
1417 InstanceContainedCast<PatchInstance, Transformable>::install(m_casts);
1418 }
get()1419 InstanceTypeCastTable& get()
1420 {
1421 return m_casts;
1422 }
1423 };
1424
1425
1426 Patch& m_patch;
1427 typedef std::vector<PatchControlInstance> PatchControlInstances;
1428 PatchControlInstances m_ctrl_instances;
1429
1430 ObservedSelectable m_selectable;
1431
1432 DragPlanes m_dragPlanes;
1433
1434 mutable RenderablePointVector m_render_selected;
1435 mutable AABB m_aabb_component;
1436
1437 static Shader* m_state_selpoint;
1438
1439 const LightList* m_lightList;
1440
1441 TransformModifier m_transform;
1442 public:
1443
1444 typedef LazyStatic<TypeCasts> StaticTypeCasts;
1445
lightsChanged()1446 void lightsChanged()
1447 {
1448 m_lightList->lightsChanged();
1449 }
1450 typedef MemberCaller<PatchInstance, &PatchInstance::lightsChanged> LightsChangedCaller;
1451
1452 STRING_CONSTANT(Name, "PatchInstance");
1453
PatchInstance(const scene::Path & path,scene::Instance * parent,Patch & patch)1454 PatchInstance(const scene::Path& path, scene::Instance* parent, Patch& patch) :
1455 Instance(path, parent, this, StaticTypeCasts::instance().get()),
1456 m_patch(patch),
1457 m_selectable(SelectedChangedCaller(*this)),
1458 m_dragPlanes(SelectedChangedComponentCaller(*this)),
1459 m_render_selected(GL_POINTS),
1460 m_transform(Patch::TransformChangedCaller(m_patch), ApplyTransformCaller(*this))
1461 {
1462 m_patch.instanceAttach(Instance::path());
1463 m_patch.attach(this);
1464
1465 m_lightList = &GlobalShaderCache().attach(*this);
1466 m_patch.m_lightsChanged = LightsChangedCaller(*this);
1467
1468 Instance::setTransformChangedCallback(LightsChangedCaller(*this));
1469 }
~PatchInstance()1470 ~PatchInstance()
1471 {
1472 Instance::setTransformChangedCallback(Callback());
1473
1474 m_patch.m_lightsChanged = Callback();
1475 GlobalShaderCache().detach(*this);
1476
1477 m_patch.detach(this);
1478 m_patch.instanceDetach(Instance::path());
1479 }
1480
selectedChanged(const Selectable & selectable)1481 void selectedChanged(const Selectable& selectable)
1482 {
1483 GlobalSelectionSystem().getObserver(SelectionSystem::ePrimitive)(selectable);
1484 GlobalSelectionSystem().onSelectedChanged(*this, selectable);
1485
1486 Instance::selectedChanged();
1487 }
1488 typedef MemberCaller1<PatchInstance, const Selectable&, &PatchInstance::selectedChanged> SelectedChangedCaller;
1489
selectedChangedComponent(const Selectable & selectable)1490 void selectedChangedComponent(const Selectable& selectable)
1491 {
1492 GlobalSelectionSystem().getObserver(SelectionSystem::eComponent)(selectable);
1493 GlobalSelectionSystem().onComponentSelection(*this, selectable);
1494 }
1495 typedef MemberCaller1<PatchInstance, const Selectable&, &PatchInstance::selectedChangedComponent> SelectedChangedComponentCaller;
1496
getPatch()1497 Patch& getPatch()
1498 {
1499 return m_patch;
1500 }
get(NullType<Bounded>)1501 Bounded& get(NullType<Bounded>)
1502 {
1503 return m_patch;
1504 }
get(NullType<Cullable>)1505 Cullable& get(NullType<Cullable>)
1506 {
1507 return m_patch;
1508 }
get(NullType<Transformable>)1509 Transformable& get(NullType<Transformable>)
1510 {
1511 return m_transform;
1512 }
1513
constructStatic()1514 static void constructStatic()
1515 {
1516 m_state_selpoint = GlobalShaderCache().capture("$SELPOINT");
1517 }
1518
destroyStatic()1519 static void destroyStatic()
1520 {
1521 GlobalShaderCache().release("$SELPOINT");
1522 }
1523
1524
allocate(std::size_t size)1525 void allocate(std::size_t size)
1526 {
1527 m_ctrl_instances.clear();
1528 m_ctrl_instances.reserve(size);
1529 for(Patch::iterator i = m_patch.begin(); i != m_patch.end(); ++i)
1530 {
1531 m_ctrl_instances.push_back(PatchControlInstance(&(*i), SelectedChangedComponentCaller(*this)));
1532 }
1533 }
1534
setSelected(bool select)1535 void setSelected(bool select)
1536 {
1537 m_selectable.setSelected(select);
1538 }
isSelected()1539 bool isSelected() const
1540 {
1541 return m_selectable.isSelected();
1542 }
1543
1544
update_selected()1545 void update_selected() const
1546 {
1547 m_render_selected.clear();
1548 Patch::iterator ctrl = m_patch.getControlPointsTransformed().begin();
1549 for(PatchControlInstances::const_iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i, ++ctrl)
1550 {
1551 if((*i).m_selectable.isSelected())
1552 {
1553 const Colour4b colour_selected(0, 0, 255, 255);
1554 m_render_selected.push_back(PointVertex(reinterpret_cast<Vertex3f&>((*ctrl).m_vertex), colour_selected));
1555 }
1556 }
1557 }
1558
1559 #if 0
1560 void render(Renderer& renderer, const VolumeTest& volume) const
1561 {
1562 if(GlobalSelectionSystem().Mode() == SelectionSystem::eComponent
1563 && m_selectable.isSelected())
1564 {
1565 renderer.Highlight(Renderer::eFace, false);
1566
1567 m_patch.render(renderer, volume, localToWorld());
1568
1569 if(GlobalSelectionSystem().ComponentMode() == SelectionSystem::eVertex)
1570 {
1571 renderer.Highlight(Renderer::ePrimitive, false);
1572
1573 m_patch.render_component(renderer, volume, localToWorld());
1574
1575 renderComponentsSelected(renderer, volume);
1576 }
1577 }
1578 else
1579 m_patch.render(renderer, volume, localToWorld());
1580 }
1581 #endif
1582
renderSolid(Renderer & renderer,const VolumeTest & volume)1583 void renderSolid(Renderer& renderer, const VolumeTest& volume) const
1584 {
1585 m_patch.evaluateTransform();
1586 renderer.setLights(*m_lightList);
1587 m_patch.render_solid(renderer, volume, localToWorld());
1588
1589 renderComponentsSelected(renderer, volume);
1590 }
1591
renderWireframe(Renderer & renderer,const VolumeTest & volume)1592 void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
1593 {
1594 m_patch.evaluateTransform();
1595 m_patch.render_wireframe(renderer, volume, localToWorld());
1596
1597 renderComponentsSelected(renderer, volume);
1598 }
1599
renderComponentsSelected(Renderer & renderer,const VolumeTest & volume)1600 void renderComponentsSelected(Renderer& renderer, const VolumeTest& volume) const
1601 {
1602 m_patch.evaluateTransform();
1603 update_selected();
1604 if(!m_render_selected.empty())
1605 {
1606 renderer.Highlight(Renderer::ePrimitive, false);
1607 renderer.SetState(m_state_selpoint, Renderer::eWireframeOnly);
1608 renderer.SetState(m_state_selpoint, Renderer::eFullMaterials);
1609 renderer.addRenderable(m_render_selected, localToWorld());
1610 }
1611 }
renderComponents(Renderer & renderer,const VolumeTest & volume)1612 void renderComponents(Renderer& renderer, const VolumeTest& volume) const
1613 {
1614 m_patch.evaluateTransform();
1615 if(GlobalSelectionSystem().ComponentMode() == SelectionSystem::eVertex)
1616 {
1617 m_patch.render_component(renderer, volume, localToWorld());
1618 }
1619 }
1620
testSelect(Selector & selector,SelectionTest & test)1621 void testSelect(Selector& selector, SelectionTest& test)
1622 {
1623 test.BeginMesh(localToWorld(), true);
1624 m_patch.testSelect(selector, test);
1625 }
1626
selectCtrl(bool select)1627 void selectCtrl(bool select)
1628 {
1629 for(PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1630 {
1631 (*i).m_selectable.setSelected(select);
1632 }
1633 }
isSelectedComponents()1634 bool isSelectedComponents() const
1635 {
1636 for(PatchControlInstances::const_iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1637 {
1638 if((*i).m_selectable.isSelected())
1639 {
1640 return true;
1641 }
1642 }
1643 return false;
1644 }
setSelectedComponents(bool select,SelectionSystem::EComponentMode mode)1645 void setSelectedComponents(bool select, SelectionSystem::EComponentMode mode)
1646 {
1647 if(mode == SelectionSystem::eVertex)
1648 {
1649 selectCtrl(select);
1650 }
1651 else if(mode == SelectionSystem::eFace)
1652 {
1653 m_dragPlanes.setSelected(select);
1654 }
1655 }
getSelectedComponentsBounds()1656 const AABB& getSelectedComponentsBounds() const
1657 {
1658 m_aabb_component = AABB();
1659
1660 for(PatchControlInstances::const_iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1661 {
1662 if((*i).m_selectable.isSelected())
1663 {
1664 aabb_extend_by_point_safe(m_aabb_component, (*i).m_ctrl->m_vertex);
1665 }
1666 }
1667
1668 return m_aabb_component;
1669 }
1670
testSelectComponents(Selector & selector,SelectionTest & test,SelectionSystem::EComponentMode mode)1671 void testSelectComponents(Selector& selector, SelectionTest& test, SelectionSystem::EComponentMode mode)
1672 {
1673 test.BeginMesh(localToWorld());
1674
1675 switch(mode)
1676 {
1677 case SelectionSystem::eVertex:
1678 {
1679 for(PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1680 {
1681 (*i).testSelect(selector, test);
1682 }
1683 }
1684 break;
1685 default:
1686 break;
1687 }
1688 }
1689
selectedVertices()1690 bool selectedVertices()
1691 {
1692 for(PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1693 {
1694 if((*i).m_selectable.isSelected())
1695 {
1696 return true;
1697 }
1698 }
1699 return false;
1700 }
1701
transformComponents(const Matrix4 & matrix)1702 void transformComponents(const Matrix4& matrix)
1703 {
1704 if(selectedVertices())
1705 {
1706 PatchControlIter ctrl = m_patch.getControlPointsTransformed().begin();
1707 for(PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i, ++ctrl)
1708 {
1709 if((*i).m_selectable.isSelected())
1710 {
1711 matrix4_transform_point(matrix, (*ctrl).m_vertex);
1712 }
1713 }
1714 m_patch.UpdateCachedData();
1715 }
1716
1717 if(m_dragPlanes.isSelected()) // this should only be true when the transform is a pure translation.
1718 {
1719 m_patch.transform(m_dragPlanes.evaluateTransform(matrix.t()));
1720 }
1721 }
1722
1723
selectPlanes(Selector & selector,SelectionTest & test,const PlaneCallback & selectedPlaneCallback)1724 void selectPlanes(Selector& selector, SelectionTest& test, const PlaneCallback& selectedPlaneCallback)
1725 {
1726 test.BeginMesh(localToWorld());
1727
1728 m_dragPlanes.selectPlanes(m_patch.localAABB(), selector, test, selectedPlaneCallback);
1729 }
selectReversedPlanes(Selector & selector,const SelectedPlanes & selectedPlanes)1730 void selectReversedPlanes(Selector& selector, const SelectedPlanes& selectedPlanes)
1731 {
1732 m_dragPlanes.selectReversedPlanes(m_patch.localAABB(), selector, selectedPlanes);
1733 }
1734
1735
snapComponents(float snap)1736 void snapComponents(float snap)
1737 {
1738 if(selectedVertices())
1739 {
1740 m_patch.undoSave();
1741 for(PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1742 {
1743 if((*i).m_selectable.isSelected())
1744 {
1745 (*i).snapto(snap);
1746 }
1747 }
1748 m_patch.controlPointsChanged();
1749 }
1750 }
1751
evaluateTransform()1752 void evaluateTransform()
1753 {
1754 Matrix4 matrix(m_transform.calculateTransform());
1755
1756 if(m_transform.getType() == TRANSFORM_PRIMITIVE)
1757 {
1758 m_patch.transform(matrix);
1759 }
1760 else
1761 {
1762 transformComponents(matrix);
1763 }
1764 }
applyTransform()1765 void applyTransform()
1766 {
1767 m_patch.revertTransform();
1768 evaluateTransform();
1769 m_patch.freezeTransform();
1770 }
1771 typedef MemberCaller<PatchInstance, &PatchInstance::applyTransform> ApplyTransformCaller;
1772
1773
testLight(const RendererLight & light)1774 bool testLight(const RendererLight& light) const
1775 {
1776 return light.testAABB(worldAABB());
1777 }
1778 };
1779
1780
1781 template<typename TokenImporter, typename TokenExporter>
1782 class PatchNode :
1783 public scene::Node::Symbiot,
1784 public scene::Instantiable,
1785 public scene::Cloneable
1786 {
1787 typedef PatchNode<TokenImporter, TokenExporter> Self;
1788
1789 class TypeCasts
1790 {
1791 InstanceTypeCastTable m_casts;
1792 public:
TypeCasts()1793 TypeCasts()
1794 {
1795 NodeStaticCast<PatchNode, scene::Instantiable>::install(m_casts);
1796 NodeStaticCast<PatchNode, scene::Cloneable>::install(m_casts);
1797 NodeContainedCast<PatchNode, Snappable>::install(m_casts);
1798 NodeContainedCast<PatchNode, TransformNode>::install(m_casts);
1799 NodeContainedCast<PatchNode, Patch>::install(m_casts);
1800 NodeContainedCast<PatchNode, XMLImporter>::install(m_casts);
1801 NodeContainedCast<PatchNode, XMLExporter>::install(m_casts);
1802 NodeContainedCast<PatchNode, MapImporter>::install(m_casts);
1803 NodeContainedCast<PatchNode, MapExporter>::install(m_casts);
1804 NodeContainedCast<PatchNode, Nameable>::install(m_casts);
1805 }
get()1806 InstanceTypeCastTable& get()
1807 {
1808 return m_casts;
1809 }
1810 };
1811
1812
1813 scene::Node m_node;
1814 InstanceSet m_instances;
1815 Patch m_patch;
1816 TokenImporter m_importMap;
1817 TokenExporter m_exportMap;
1818
1819 public:
1820
1821 typedef LazyStatic<TypeCasts> StaticTypeCasts;
1822
get(NullType<Snappable>)1823 Snappable& get(NullType<Snappable>)
1824 {
1825 return m_patch;
1826 }
get(NullType<TransformNode>)1827 TransformNode& get(NullType<TransformNode>)
1828 {
1829 return m_patch;
1830 }
get(NullType<Patch>)1831 Patch& get(NullType<Patch>)
1832 {
1833 return m_patch;
1834 }
get(NullType<XMLImporter>)1835 XMLImporter& get(NullType<XMLImporter>)
1836 {
1837 return m_patch;
1838 }
get(NullType<XMLExporter>)1839 XMLExporter& get(NullType<XMLExporter>)
1840 {
1841 return m_patch;
1842 }
get(NullType<MapImporter>)1843 MapImporter& get(NullType<MapImporter>)
1844 {
1845 return m_importMap;
1846 }
get(NullType<MapExporter>)1847 MapExporter& get(NullType<MapExporter>)
1848 {
1849 return m_exportMap;
1850 }
get(NullType<Nameable>)1851 Nameable& get(NullType<Nameable>)
1852 {
1853 return m_patch;
1854 }
1855
1856 PatchNode(bool patchDef3 = false) :
1857 m_node(this, this, StaticTypeCasts::instance().get()),
1858 m_patch(m_node, InstanceSetEvaluateTransform<PatchInstance>::Caller(m_instances), InstanceSet::BoundsChangedCaller(m_instances)),
1859 m_importMap(m_patch),
1860 m_exportMap(m_patch)
1861 {
1862 m_patch.m_patchDef3 = patchDef3;
1863 }
PatchNode(const PatchNode & other)1864 PatchNode(const PatchNode& other) :
1865 scene::Node::Symbiot(other),
1866 scene::Instantiable(other),
1867 scene::Cloneable(other),
1868 m_node(this, this, StaticTypeCasts::instance().get()),
1869 m_patch(other.m_patch, m_node, InstanceSetEvaluateTransform<PatchInstance>::Caller(m_instances), InstanceSet::BoundsChangedCaller(m_instances)),
1870 m_importMap(m_patch),
1871 m_exportMap(m_patch)
1872 {
1873 }
release()1874 void release()
1875 {
1876 delete this;
1877 }
node()1878 scene::Node& node()
1879 {
1880 return m_node;
1881 }
get()1882 Patch& get()
1883 {
1884 return m_patch;
1885 }
get()1886 const Patch& get() const
1887 {
1888 return m_patch;
1889 }
1890
clone()1891 scene::Node& clone() const
1892 {
1893 return (new PatchNode(*this))->node();
1894 }
1895
create(const scene::Path & path,scene::Instance * parent)1896 scene::Instance* create(const scene::Path& path, scene::Instance* parent)
1897 {
1898 return new PatchInstance(path, parent, m_patch);
1899 }
forEachInstance(const scene::Instantiable::Visitor & visitor)1900 void forEachInstance(const scene::Instantiable::Visitor& visitor)
1901 {
1902 m_instances.forEachInstance(visitor);
1903 }
insert(scene::Instantiable::Observer * observer,const scene::Path & path,scene::Instance * instance)1904 void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
1905 {
1906 m_instances.insert(observer, path, instance);
1907 }
erase(scene::Instantiable::Observer * observer,const scene::Path & path)1908 scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
1909 {
1910 return m_instances.erase(observer, path);
1911 }
1912 };
1913
1914
1915
1916 typedef PatchNode<PatchTokenImporter, PatchTokenExporter> PatchNodeQuake3;
1917 typedef PatchNode<PatchDoom3TokenImporter, PatchDoom3TokenExporter> PatchNodeDoom3;
1918
Node_getPatch(scene::Node & node)1919 inline Patch* Node_getPatch(scene::Node& node)
1920 {
1921 return NodeTypeCast<Patch>::cast(node);
1922 }
1923
Instance_getPatch(scene::Instance & instance)1924 inline PatchInstance* Instance_getPatch(scene::Instance& instance)
1925 {
1926 return InstanceTypeCast<PatchInstance>::cast(instance);
1927 }
1928
1929 template<typename Functor>
1930 class PatchSelectedVisitor : public SelectionSystem::Visitor
1931 {
1932 const Functor& m_functor;
1933 public:
PatchSelectedVisitor(const Functor & functor)1934 PatchSelectedVisitor(const Functor& functor) : m_functor(functor)
1935 {
1936 }
visit(scene::Instance & instance)1937 void visit(scene::Instance& instance) const
1938 {
1939 PatchInstance* patch = Instance_getPatch(instance);
1940 if(patch != 0)
1941 {
1942 m_functor(*patch);
1943 }
1944 }
1945 };
1946
1947 template<typename Functor>
Scene_forEachSelectedPatch(const Functor & functor)1948 inline void Scene_forEachSelectedPatch(const Functor& functor)
1949 {
1950 GlobalSelectionSystem().foreachSelected(PatchSelectedVisitor<Functor>(functor));
1951 }
1952
1953
1954 template<typename Functor>
1955 class PatchVisibleSelectedVisitor : public SelectionSystem::Visitor
1956 {
1957 const Functor& m_functor;
1958 public:
PatchVisibleSelectedVisitor(const Functor & functor)1959 PatchVisibleSelectedVisitor(const Functor& functor) : m_functor(functor)
1960 {
1961 }
visit(scene::Instance & instance)1962 void visit(scene::Instance& instance) const
1963 {
1964 PatchInstance* patch = Instance_getPatch(instance);
1965 if(patch != 0
1966 && instance.path().top().get().visible())
1967 {
1968 m_functor(*patch);
1969 }
1970 }
1971 };
1972
1973 template<typename Functor>
Scene_forEachVisibleSelectedPatchInstance(const Functor & functor)1974 inline void Scene_forEachVisibleSelectedPatchInstance(const Functor& functor)
1975 {
1976 GlobalSelectionSystem().foreachSelected(PatchVisibleSelectedVisitor<Functor>(functor));
1977 }
1978
1979 template<typename Functor>
1980 class PatchForEachWalker : public scene::Graph::Walker
1981 {
1982 const Functor& m_functor;
1983 public:
PatchForEachWalker(const Functor & functor)1984 PatchForEachWalker(const Functor& functor) : m_functor(functor)
1985 {
1986 }
pre(const scene::Path & path,scene::Instance & instance)1987 bool pre(const scene::Path& path, scene::Instance& instance) const
1988 {
1989 if(path.top().get().visible())
1990 {
1991 Patch* patch = Node_getPatch(path.top());
1992 if(patch != 0)
1993 {
1994 m_functor(*patch);
1995 }
1996 }
1997 return true;
1998 }
1999 };
2000
2001 template<typename Functor>
Scene_forEachVisiblePatch(const Functor & functor)2002 inline void Scene_forEachVisiblePatch(const Functor& functor)
2003 {
2004 GlobalSceneGraph().traverse(PatchForEachWalker<Functor>(functor));
2005 }
2006
2007 template<typename Functor>
2008 class PatchForEachSelectedWalker : public scene::Graph::Walker
2009 {
2010 const Functor& m_functor;
2011 public:
PatchForEachSelectedWalker(const Functor & functor)2012 PatchForEachSelectedWalker(const Functor& functor) : m_functor(functor)
2013 {
2014 }
pre(const scene::Path & path,scene::Instance & instance)2015 bool pre(const scene::Path& path, scene::Instance& instance) const
2016 {
2017 if(path.top().get().visible())
2018 {
2019 Patch* patch = Node_getPatch(path.top());
2020 if(patch != 0
2021 && Instance_getSelectable(instance)->isSelected())
2022 {
2023 m_functor(*patch);
2024 }
2025 }
2026 return true;
2027 }
2028 };
2029
2030 template<typename Functor>
Scene_forEachVisibleSelectedPatch(const Functor & functor)2031 inline void Scene_forEachVisibleSelectedPatch(const Functor& functor)
2032 {
2033 GlobalSceneGraph().traverse(PatchForEachSelectedWalker<Functor>(functor));
2034 }
2035
2036 template<typename Functor>
2037 class PatchForEachInstanceWalker : public scene::Graph::Walker
2038 {
2039 const Functor& m_functor;
2040 public:
PatchForEachInstanceWalker(const Functor & functor)2041 PatchForEachInstanceWalker(const Functor& functor) : m_functor(functor)
2042 {
2043 }
pre(const scene::Path & path,scene::Instance & instance)2044 bool pre(const scene::Path& path, scene::Instance& instance) const
2045 {
2046 if(path.top().get().visible())
2047 {
2048 PatchInstance* patch = Instance_getPatch(instance);
2049 if(patch != 0)
2050 {
2051 m_functor(*patch);
2052 }
2053 }
2054 return true;
2055 }
2056 };
2057
2058 template<typename Functor>
Scene_forEachVisiblePatchInstance(const Functor & functor)2059 inline void Scene_forEachVisiblePatchInstance(const Functor& functor)
2060 {
2061 GlobalSceneGraph().traverse(PatchForEachInstanceWalker<Functor>(functor));
2062 }
2063
2064 #endif
2065