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