2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
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.
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.
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
22 #if !defined(INCLUDED_PATCH_H)
23 #define INCLUDED_PATCH_H
26 /// \brief The patch primitive.
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.
39 #include "renderable.h"
41 #include "selectable.h"
43 #include "debugging/debugging.h"
47 #include "math/frustum.h"
48 #include "string/string.h"
49 #include "stream/stringstream.h"
50 #include "stream/textstream.h"
51 #include "xml/xmlelement.h"
53 #include "transformlib.h"
54 #include "instancelib.h"
55 #include "selectionlib.h"
56 #include "traverselib.h"
59 #include "shaderlib.h"
60 #include "generic/callback.h"
61 #include "signal/signalfwd.h"
62 #include "texturelib.h"
64 #include "dragplanes.h"
72 extern int g_PatchSubdivideThreshold;
75 #define MIN_PATCH_WIDTH 3
76 #define MIN_PATCH_HEIGHT 3
78 extern std::size_t MAX_PATCH_WIDTH;
79 extern std::size_t MAX_PATCH_HEIGHT;
81 #define MAX_PATCH_ROWCTRL (((MAX_PATCH_WIDTH-1)-1)/2)
82 #define MAX_PATCH_COLCTRL (((MAX_PATCH_HEIGHT-1)-1)/2)
118 const std::size_t BEZIERCURVETREE_MAX_INDEX = 1 << ((sizeof(std::size_t) * 8) - 1);
120 struct BezierCurveTree
123 BezierCurveTree* left;
124 BezierCurveTree* right;
127 inline bool BezierCurveTree_isLeaf(const BezierCurveTree* node)
129 return node->left == 0 && node->right == 0;
132 void BezierCurveTree_Delete(BezierCurveTree *pCurve);
135 inline VertexPointer vertexpointer_arbitrarymeshvertex(const ArbitraryMeshVertex* array)
137 return VertexPointer(VertexPointer::pointer(&array->vertex), sizeof(ArbitraryMeshVertex));
140 typedef PatchControl* PatchControlIter;
141 typedef const PatchControl* PatchControlConstIter;
143 inline void copy_ctrl(PatchControlIter ctrl, PatchControlConstIter begin, PatchControlConstIter end)
145 std::copy(begin, end, ctrl);
148 const Colour4b colour_corner(0, 255, 0, 255);
149 const Colour4b colour_inside(255, 0, 255, 255);
156 virtual bool filter(const Patch& patch) const = 0;
159 bool patch_filtered(Patch& patch);
160 void add_patch_filter(PatchFilter& filter, int mask, bool invert = false);
162 void Patch_addTextureChangedCallback(const SignalHandler& handler);
163 void Patch_textureChanged();
165 inline void BezierCurveTreeArray_deleteAll(Array<BezierCurveTree*>& curveTrees)
167 for(Array<BezierCurveTree*>::iterator i = curveTrees.begin(); i != curveTrees.end(); ++i)
169 BezierCurveTree_Delete(*i);
173 inline void PatchControlArray_invert(Array<PatchControl>& ctrl, std::size_t width, std::size_t height)
175 Array<PatchControl> tmp(width);
177 PatchControlIter from = ctrl.data() + (width * (height - 1));
178 PatchControlIter to = ctrl.data();
179 for(std::size_t h = 0; h != ((height - 1) >> 1); ++h, to += width, from -= width)
181 copy_ctrl(tmp.data(), to, to + width);
182 copy_ctrl(to, from, from + width);
183 copy_ctrl(from, tmp.data(), tmp.data() + width);
187 class PatchTesselation
191 : m_numStrips(0), m_lenStrips(0), m_nArrayWidth(0), m_nArrayHeight(0)
194 Array<ArbitraryMeshVertex> m_vertices;
195 Array<RenderIndex> m_indices;
196 std::size_t m_numStrips;
197 std::size_t m_lenStrips;
199 Array<std::size_t> m_arrayWidth;
200 std::size_t m_nArrayWidth;
201 Array<std::size_t> m_arrayHeight;
202 std::size_t m_nArrayHeight;
204 Array<BezierCurveTree*> m_curveTreeU;
205 Array<BezierCurveTree*> m_curveTreeV;
208 class RenderablePatchWireframe : public OpenGLRenderable
210 PatchTesselation& m_tess;
212 RenderablePatchWireframe(PatchTesselation& tess) : m_tess(tess)
215 void render(RenderStateFlags state) const
219 glVertexPointer(3, GL_FLOAT, 0, 0);
220 glDrawArrays(GL_TRIANGLE_FAN, 0, 0);
224 glVertexPointer(3, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->vertex);
225 for(std::size_t i = 0; i <= m_tess.m_curveTreeV.size(); ++i)
227 glDrawArrays(GL_LINE_STRIP, GLint(n), GLsizei(m_tess.m_nArrayWidth));
229 if(i == m_tess.m_curveTreeV.size()) break;
231 if(!BezierCurveTree_isLeaf(m_tess.m_curveTreeV[i]))
232 glDrawArrays(GL_LINE_STRIP, GLint(m_tess.m_curveTreeV[i]->index), GLsizei(m_tess.m_nArrayWidth));
234 n += (m_tess.m_arrayHeight[i]*m_tess.m_nArrayWidth);
240 const ArbitraryMeshVertex* p = m_tess.m_vertices.data();
241 std::size_t n = m_tess.m_nArrayWidth * sizeof(ArbitraryMeshVertex);
242 for(std::size_t i = 0; i <= m_tess.m_curveTreeU.size(); ++i)
244 glVertexPointer(3, GL_FLOAT, GLsizei(n), &p->vertex);
245 glDrawArrays(GL_LINE_STRIP, 0, GLsizei(m_tess.m_nArrayHeight));
247 if(i == m_tess.m_curveTreeU.size()) break;
249 if(!BezierCurveTree_isLeaf(m_tess.m_curveTreeU[i]))
251 glVertexPointer(3, GL_FLOAT, GLsizei(n), &(m_tess.m_vertices.data() + (m_tess.m_curveTreeU[i]->index))->vertex);
252 glDrawArrays(GL_LINE_STRIP, 0, GLsizei(m_tess.m_nArrayHeight));
255 p += m_tess.m_arrayWidth[i];
261 class RenderablePatchFixedWireframe : public OpenGLRenderable
263 PatchTesselation& m_tess;
265 RenderablePatchFixedWireframe(PatchTesselation& tess) : m_tess(tess)
268 void render(RenderStateFlags state) const
270 glVertexPointer(3, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->vertex);
271 const RenderIndex* strip_indices = m_tess.m_indices.data();
272 for(std::size_t i = 0; i<m_tess.m_numStrips; i++, strip_indices += m_tess.m_lenStrips)
274 glDrawElements(GL_QUAD_STRIP, GLsizei(m_tess.m_lenStrips), RenderIndexTypeID, strip_indices);
279 class RenderablePatchSolid : public OpenGLRenderable
281 PatchTesselation& m_tess;
283 RenderablePatchSolid(PatchTesselation& tess) : m_tess(tess)
286 void RenderNormals() const;
287 void render(RenderStateFlags state) const
290 if((state & RENDER_FILL) == 0)
292 RenderablePatchWireframe(m_tess).render(state);
297 if((state & RENDER_BUMP) != 0)
299 if(GlobalShaderCache().useShaderLanguage())
301 glNormalPointer(GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->normal);
302 glVertexAttribPointerARB(c_attr_TexCoord0, 2, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->texcoord);
303 glVertexAttribPointerARB(c_attr_Tangent, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->tangent);
304 glVertexAttribPointerARB(c_attr_Binormal, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->bitangent);
308 glVertexAttribPointerARB(11, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->normal);
309 glVertexAttribPointerARB(8, 2, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->texcoord);
310 glVertexAttribPointerARB(9, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->tangent);
311 glVertexAttribPointerARB(10, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->bitangent);
316 glNormalPointer(GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->normal);
317 glTexCoordPointer(2, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->texcoord);
319 glVertexPointer(3, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->vertex);
320 const RenderIndex* strip_indices = m_tess.m_indices.data();
321 for(std::size_t i = 0; i<m_tess.m_numStrips; i++, strip_indices += m_tess.m_lenStrips)
323 glDrawElements(GL_QUAD_STRIP, GLsizei(m_tess.m_lenStrips), RenderIndexTypeID, strip_indices);
333 // parametric surface defined by quadratic bezier control curves
337 public TransformNode,
355 xml_state_t(EState state)
362 const char* content() const
364 return m_content.c_str();
366 std::size_t write(const char* buffer, std::size_t length)
368 return m_content.write(buffer, length);
372 StringOutputStream m_content;
375 std::vector<xml_state_t> m_xml_state;
377 typedef Array<PatchControl> PatchControlArray;
379 class SavedState : public UndoMemento
385 const PatchControlArray& ctrl,
388 std::size_t subdivisions_x,
389 std::size_t subdivisions_y
395 m_patchDef3(patchDef3),
396 m_subdivisions_x(subdivisions_x),
397 m_subdivisions_y(subdivisions_y)
406 std::size_t m_width, m_height;
407 CopiedString m_shader;
408 PatchControlArray m_ctrl;
410 std::size_t m_subdivisions_x;
411 std::size_t m_subdivisions_y;
418 virtual void allocate(std::size_t size) = 0;
422 typedef UniqueSet<Observer*> Observers;
423 Observers m_observers;
427 AABB m_aabb_local; // local bbox
429 CopiedString m_shader;
433 std::size_t m_height;
436 std::size_t m_subdivisions_x;
437 std::size_t m_subdivisions_y;
440 UndoObserver* m_undoable_observer;
443 // dynamically allocated array of control points, size is m_width*m_height
444 PatchControlArray m_ctrl;
445 PatchControlArray m_ctrlTransformed;
447 PatchTesselation m_tess;
448 RenderablePatchSolid m_render_solid;
449 RenderablePatchWireframe m_render_wireframe;
450 RenderablePatchFixedWireframe m_render_wireframe_fixed;
452 static Shader* m_state_ctrl;
453 static Shader* m_state_lattice;
454 VertexBuffer<PointVertex> m_ctrl_vertices;
455 RenderableVertexBuffer m_render_ctrl;
456 IndexBuffer m_lattice_indices;
457 RenderableIndexBuffer m_render_lattice;
461 bool m_transformChanged;
462 Callback m_evaluateTransform;
463 Callback m_boundsChanged;
468 m_width = m_height = 0;
471 m_subdivisions_x = 0;
472 m_subdivisions_y = 0;
477 m_xml_state.push_back(xml_state_t::eDefault);
481 Callback m_lightsChanged;
483 static int m_CycleCapIndex;// = 0;
484 static EPatchType m_type;
486 STRING_CONSTANT(Name, "Patch");
488 Patch(scene::Node& node, const Callback& evaluateTransform, const Callback& boundsChanged) :
490 m_shader(texdef_name_default()),
492 m_undoable_observer(0),
494 m_render_solid(m_tess),
495 m_render_wireframe(m_tess),
496 m_render_wireframe_fixed(m_tess),
497 m_render_ctrl(GL_POINTS, m_ctrl_vertices),
498 m_render_lattice(GL_LINES, m_lattice_indices, m_ctrl_vertices),
499 m_transformChanged(false),
500 m_evaluateTransform(evaluateTransform),
501 m_boundsChanged(boundsChanged)
505 Patch(const Patch& other, scene::Node& node, const Callback& evaluateTransform, const Callback& boundsChanged) :
507 m_shader(texdef_name_default()),
509 m_undoable_observer(0),
511 m_render_solid(m_tess),
512 m_render_wireframe(m_tess),
513 m_render_wireframe_fixed(m_tess),
514 m_render_ctrl(GL_POINTS, m_ctrl_vertices),
515 m_render_lattice(GL_LINES, m_lattice_indices, m_ctrl_vertices),
516 m_transformChanged(false),
517 m_evaluateTransform(evaluateTransform),
518 m_boundsChanged(boundsChanged)
522 m_patchDef3 = other.m_patchDef3;
523 m_subdivisions_x = other.m_subdivisions_x;
524 m_subdivisions_y = other.m_subdivisions_y;
525 setDims(other.m_width, other.m_height);
526 copy_ctrl(m_ctrl.data(), other.m_ctrl.data(), other.m_ctrl.data()+(m_width*m_height));
527 SetShader(other.m_shader.c_str());
528 controlPointsChanged();
531 Patch(const Patch& other) :
534 TransformNode(other),
542 m_undoable_observer(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)
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();
566 BezierCurveTreeArray_deleteAll(m_tess.m_curveTreeU);
567 BezierCurveTreeArray_deleteAll(m_tess.m_curveTreeV);
571 ASSERT_MESSAGE(m_observers.empty(), "Patch::~Patch: observers still attached");
574 InstanceCounter m_instanceCounter;
575 void instanceAttach(const scene::Path& path)
577 if(++m_instanceCounter.m_count == 1)
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);
586 ASSERT_MESSAGE(path_find_mapfile(path.begin(), path.end()) == m_map, "node is instanced across more than one file");
589 void instanceDetach(const scene::Path& path)
591 if(--m_instanceCounter.m_count == 0)
594 m_undoable_observer = 0;
595 GlobalUndoSystem().release(this);
596 GlobalFilterSystem().unregisterFilterable(*this);
597 m_state->decrementUsed();
601 const char* name() const
605 void attach(const NameCallback& callback)
608 void detach(const NameCallback& callback)
612 void attach(Observer* observer)
614 observer->allocate(m_width * m_height);
616 m_observers.insert(observer);
618 void detach(Observer* observer)
620 m_observers.erase(observer);
623 void updateFiltered()
627 if(patch_filtered(*this))
629 m_node->enable(scene::Node::eFiltered);
633 m_node->disable(scene::Node::eFiltered);
638 void onAllocate(std::size_t size)
640 for(Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i)
642 (*i)->allocate(size);
646 const Matrix4& localToParent() const
648 return g_matrix4_identity;
650 const AABB& localAABB() const
654 VolumeIntersectionValue intersectVolume(const VolumeTest& test, const Matrix4& localToWorld) const
656 return test.TestAABB(m_aabb_local, localToWorld);
658 void render_solid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
660 renderer.SetState(m_state, Renderer::eFullMaterials);
661 renderer.addRenderable(m_render_solid, localToWorld);
663 void render_wireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
665 renderer.SetState(m_state, Renderer::eFullMaterials);
668 renderer.addRenderable(m_render_wireframe_fixed, localToWorld);
672 renderer.addRenderable(m_render_wireframe, localToWorld);
676 void render_component(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
678 renderer.SetState(m_state_lattice, Renderer::eWireframeOnly);
679 renderer.SetState(m_state_lattice, Renderer::eFullMaterials);
680 renderer.addRenderable(m_render_lattice, localToWorld);
682 renderer.SetState(m_state_ctrl, Renderer::eWireframeOnly);
683 renderer.SetState(m_state_ctrl, Renderer::eFullMaterials);
684 renderer.addRenderable(m_render_ctrl, localToWorld);
686 void testSelect(Selector& selector, SelectionTest& test)
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++)
692 test.TestQuadStrip(vertexpointer_arbitrarymeshvertex(m_tess.m_vertices.data()), IndexPointer(pIndex, m_tess.m_lenStrips), best);
693 pIndex += m_tess.m_lenStrips;
697 selector.addIntersection(best);
700 void transform(const Matrix4& matrix)
702 for(PatchControlIter i = m_ctrlTransformed.data(); i != m_ctrlTransformed.data() + m_ctrlTransformed.size(); ++i)
704 matrix4_transform_point(matrix, (*i).m_vertex);
707 if(matrix4_handedness(matrix) == MATRIX4_LEFTHANDED)
709 PatchControlArray_invert(m_ctrlTransformed, m_width, m_height);
713 void transformChanged()
715 m_transformChanged = true;
719 typedef MemberCaller<Patch, &Patch::transformChanged> TransformChangedCaller;
721 void evaluateTransform()
723 if(m_transformChanged)
725 m_transformChanged = false;
727 m_evaluateTransform();
731 void revertTransform()
733 m_ctrlTransformed = m_ctrl;
735 void freezeTransform()
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());
743 void controlPointsChanged()
749 bool isValid() const;
751 void snapto(float snap)
755 for(PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i)
757 vector3_snap((*i).m_vertex, snap);
760 controlPointsChanged();
766 void RenderDebug(RenderStateFlags state) const;
767 void RenderNormals(RenderStateFlags state) const;
769 void pushElement(const XMLElement& element)
771 switch(m_xml_state.back().state())
773 case xml_state_t::eDefault:
774 ASSERT_MESSAGE(string_equal(element.name(), "patch"), "parse error");
775 m_xml_state.push_back(xml_state_t::ePatch);
777 case xml_state_t::ePatch:
778 if(string_equal(element.name(), "matrix"))
780 setDims(atoi(element.attribute("width")), atoi(element.attribute("height")));
781 m_xml_state.push_back(xml_state_t::eMatrix);
783 else if(string_equal(element.name(), "shader"))
785 m_xml_state.push_back(xml_state_t::eShader);
789 ERROR_MESSAGE("parse error");
793 void popElement(const char* name)
795 switch(m_xml_state.back().state())
797 case xml_state_t::eDefault:
798 ERROR_MESSAGE("parse error");
800 case xml_state_t::ePatch:
802 case xml_state_t::eMatrix:
804 StringTokeniser content(m_xml_state.back().content());
806 for(PatchControlIter i = m_ctrl.data(), end = m_ctrl.data() + m_ctrl.size(); i != end; ++i)
808 (*i).m_vertex[0] = string_read_float(content.getToken());
809 (*i).m_vertex[1] = string_read_float(content.getToken());
810 (*i).m_vertex[2] = string_read_float(content.getToken());
811 (*i).m_texcoord[0] = string_read_float(content.getToken());
812 (*i).m_texcoord[1] = string_read_float(content.getToken());
814 controlPointsChanged();
817 case xml_state_t::eShader:
819 SetShader(m_xml_state.back().content());
823 ERROR_MESSAGE("parse error");
826 ASSERT_MESSAGE(!m_xml_state.empty(), "popping empty stack");
827 m_xml_state.pop_back();
829 std::size_t write(const char* buffer, std::size_t length)
831 switch(m_xml_state.back().state())
833 case xml_state_t::eDefault:
835 case xml_state_t::ePatch:
837 case xml_state_t::eMatrix:
838 case xml_state_t::eShader:
839 return m_xml_state.back().write(buffer, length);
842 ERROR_MESSAGE("parse error");
847 void exportXML(XMLImporter& importer)
849 StaticElement patchElement("patch");
850 importer.pushElement(patchElement);
853 const StaticElement element("shader");
854 importer.pushElement(element);
855 importer.write(m_shader.c_str(), strlen(m_shader.c_str()));
856 importer.popElement(element.name());
860 char width[16], height[16];
861 sprintf(width, "%u", Unsigned(m_width));
862 sprintf(height, "%u", Unsigned(m_height));
863 StaticElement element("matrix");
864 element.insertAttribute("width", width);
865 element.insertAttribute("height", height);
867 importer.pushElement(element);
869 for(PatchControlIter i = m_ctrl.data(), end = m_ctrl.data() + m_ctrl.size(); i != end; ++i)
871 importer << (*i).m_vertex[0]
872 << ' ' << (*i).m_vertex[1]
873 << ' ' << (*i).m_vertex[2]
874 << ' ' << (*i).m_texcoord[0]
875 << ' ' << (*i).m_texcoord[1];
878 importer.popElement(element.name());
881 importer.popElement(patchElement.name());
884 void UpdateCachedData();
886 const char *GetShader() const
888 return m_shader.c_str();
890 void SetShader(const char* name)
892 ASSERT_NOTNULL(name);
894 if(shader_equal(m_shader.c_str(), name))
899 if(m_instanceCounter.m_count != 0)
901 m_state->decrementUsed();
906 if(m_instanceCounter.m_count != 0)
908 m_state->incrementUsed();
912 Patch_textureChanged();
914 int getShaderFlags() const
918 return m_state->getFlags();
923 typedef PatchControl* iterator;
924 typedef const PatchControl* const_iterator;
928 return m_ctrl.data();
930 const_iterator begin() const
932 return m_ctrl.data();
936 return m_ctrl.data() + m_ctrl.size();
938 const_iterator end() const
940 return m_ctrl.data() + m_ctrl.size();
943 PatchControlArray& getControlPoints()
947 PatchControlArray& getControlPointsTransformed()
949 return m_ctrlTransformed;
952 void setDims (std::size_t w, std::size_t h);
953 std::size_t getWidth() const
957 std::size_t getHeight() const
961 PatchControl& ctrlAt(std::size_t row, std::size_t col)
963 return m_ctrl[row*m_width+col];
965 const PatchControl& ctrlAt(std::size_t row, std::size_t col) const
967 return m_ctrl[row*m_width+col];
970 void ConstructPrefab(const AABB& aabb, EPatchPrefab eType, int axis, std::size_t width = 3, std::size_t height = 3);
971 void constructPlane(const AABB& aabb, int axis, std::size_t width, std::size_t height);
973 void TransposeMatrix();
974 void Redisperse(EMatrixMajor mt);
975 void InsertRemove(bool bInsert, bool bColumn, bool bFirst);
976 Patch* MakeCap(Patch* patch, EPatchCap eType, EMatrixMajor mt, bool bFirst);
977 void ConstructSeam(EPatchCap eType, Vector3* p, std::size_t width);
979 void FlipTexture(int nAxis);
980 void TranslateTexture(float s, float t);
981 void ScaleTexture(float s, float t);
982 void RotateTexture(float angle);
983 void SetTextureRepeat(float s, float t); // call with s=1 t=1 for FIT
985 void NaturalTexture();
986 void ProjectTexture(int nAxis);
994 if(m_undoable_observer != 0)
996 m_undoable_observer->save(this);
1000 UndoMemento* exportState() const
1002 return new SavedState(m_width, m_height, m_ctrl, m_shader.c_str(), m_patchDef3, m_subdivisions_x, m_subdivisions_y);
1004 void importState(const UndoMemento* state)
1008 const SavedState& other = *(static_cast<const SavedState*>(state));
1010 // begin duplicate of SavedState copy constructor, needs refactoring
1014 m_width = other.m_width;
1015 m_height = other.m_height;
1016 SetShader(other.m_shader.c_str());
1017 m_ctrl = other.m_ctrl;
1018 onAllocate(m_ctrl.size());
1019 m_patchDef3 = other.m_patchDef3;
1020 m_subdivisions_x = other.m_subdivisions_x;
1021 m_subdivisions_y = other.m_subdivisions_y;
1024 // end duplicate code
1026 Patch_textureChanged();
1028 controlPointsChanged();
1031 static void constructStatic(EPatchType type)
1033 Patch::m_type = type;
1034 Patch::m_state_ctrl = GlobalShaderCache().capture("$POINT");
1035 Patch::m_state_lattice = GlobalShaderCache().capture("$LATTICE");
1038 static void destroyStatic()
1040 GlobalShaderCache().release("$LATTICE");
1041 GlobalShaderCache().release("$POINT");
1044 void captureShader()
1046 m_state = GlobalShaderCache().capture(m_shader.c_str());
1049 void releaseShader()
1051 GlobalShaderCache().release(m_shader.c_str());
1056 if(!shader_valid(GetShader()))
1058 globalErrorStream() << "patch has invalid texture name: '" << GetShader() << "'\n";
1062 void InsertPoints(EMatrixMajor mt, bool bFirst);
1063 void RemovePoints(EMatrixMajor mt, bool bFirst);
1065 void AccumulateBBox();
1067 void TesselateSubMatrixFixed(ArbitraryMeshVertex* vertices, std::size_t strideX, std::size_t strideY, unsigned int nFlagsX, unsigned int nFlagsY, PatchControl* subMatrix[3][3]);
1069 // uses binary trees representing bezier curves to recursively tesselate a bezier sub-patch
1070 void TesselateSubMatrix( const BezierCurveTree *BX, const BezierCurveTree *BY,
1071 std::size_t offStartX, std::size_t offStartY,
1072 std::size_t offEndX, std::size_t offEndY,
1073 std::size_t nFlagsX, std::size_t nFlagsY,
1074 Vector3& left, Vector3& mid, Vector3& right,
1075 Vector2& texLeft, Vector2& texMid, Vector2& texRight,
1078 // tesselates the entire surface
1079 void BuildTesselationCurves(EMatrixMajor major);
1080 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);
1081 void BuildVertexArray();
1084 inline bool Patch_importHeader(Patch& patch, Tokeniser& tokeniser)
1086 tokeniser.nextLine();
1087 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "{"));
1091 inline bool Patch_importShader(Patch& patch, Tokeniser& tokeniser)
1093 // parse shader name
1094 tokeniser.nextLine();
1095 const char* texture = tokeniser.getToken();
1098 Tokeniser_unexpectedError(tokeniser, texture, "#texture-name");
1101 if(string_equal(texture, "NULL"))
1103 patch.SetShader(texdef_name_default());
1107 StringOutputStream shader(string_length(GlobalTexturePrefix_get()) + string_length(texture));
1108 shader << GlobalTexturePrefix_get() << texture;
1109 patch.SetShader(shader.c_str());
1114 inline bool PatchDoom3_importShader(Patch& patch, Tokeniser& tokeniser)
1116 // parse shader name
1117 tokeniser.nextLine();
1118 const char *shader = tokeniser.getToken();
1121 Tokeniser_unexpectedError(tokeniser, shader, "#shader-name");
1124 if(string_equal(shader, "_emptyname"))
1126 shader = texdef_name_default();
1128 patch.SetShader(shader);
1132 inline bool Patch_importParams(Patch& patch, Tokeniser& tokeniser)
1134 tokeniser.nextLine();
1135 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
1137 // parse matrix dimensions
1140 RETURN_FALSE_IF_FAIL(Tokeniser_getSize(tokeniser, c));
1141 RETURN_FALSE_IF_FAIL(Tokeniser_getSize(tokeniser, r));
1143 patch.setDims(c, r);
1146 if(patch.m_patchDef3)
1148 RETURN_FALSE_IF_FAIL(Tokeniser_getSize(tokeniser, patch.m_subdivisions_x));
1149 RETURN_FALSE_IF_FAIL(Tokeniser_getSize(tokeniser, patch.m_subdivisions_y));
1152 // ignore contents/flags/value
1154 RETURN_FALSE_IF_FAIL(Tokeniser_getInteger(tokeniser, tmp));
1155 RETURN_FALSE_IF_FAIL(Tokeniser_getInteger(tokeniser, tmp));
1156 RETURN_FALSE_IF_FAIL(Tokeniser_getInteger(tokeniser, tmp));
1158 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
1162 inline bool Patch_importMatrix(Patch& patch, Tokeniser& tokeniser)
1165 tokeniser.nextLine();
1166 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
1168 for(std::size_t c=0; c<patch.getWidth(); c++)
1170 tokeniser.nextLine();
1171 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
1172 for(std::size_t r=0; r<patch.getHeight(); r++)
1174 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
1176 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r,c).m_vertex[0]));
1177 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r,c).m_vertex[1]));
1178 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r,c).m_vertex[2]));
1179 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r,c).m_texcoord[0]));
1180 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r,c).m_texcoord[1]));
1182 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
1184 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
1187 tokeniser.nextLine();
1188 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
1192 inline bool Patch_importFooter(Patch& patch, Tokeniser& tokeniser)
1194 patch.controlPointsChanged();
1196 tokeniser.nextLine();
1197 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "}"));
1199 tokeniser.nextLine();
1200 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "}"));
1204 class PatchTokenImporter : public MapImporter
1208 PatchTokenImporter(Patch& patch) : m_patch(patch)
1211 bool importTokens(Tokeniser& tokeniser)
1213 RETURN_FALSE_IF_FAIL(Patch_importHeader(m_patch, tokeniser));
1214 RETURN_FALSE_IF_FAIL(Patch_importShader(m_patch, tokeniser));
1215 RETURN_FALSE_IF_FAIL(Patch_importParams(m_patch, tokeniser));
1216 RETURN_FALSE_IF_FAIL(Patch_importMatrix(m_patch, tokeniser));
1217 RETURN_FALSE_IF_FAIL(Patch_importFooter(m_patch, tokeniser));
1223 class PatchDoom3TokenImporter : public MapImporter
1227 PatchDoom3TokenImporter(Patch& patch) : m_patch(patch)
1230 bool importTokens(Tokeniser& tokeniser)
1232 RETURN_FALSE_IF_FAIL(Patch_importHeader(m_patch, tokeniser));
1233 RETURN_FALSE_IF_FAIL(PatchDoom3_importShader(m_patch, tokeniser));
1234 RETURN_FALSE_IF_FAIL(Patch_importParams(m_patch, tokeniser));
1235 RETURN_FALSE_IF_FAIL(Patch_importMatrix(m_patch, tokeniser));
1236 RETURN_FALSE_IF_FAIL(Patch_importFooter(m_patch, tokeniser));
1242 inline void Patch_exportHeader(const Patch& patch, TokenWriter& writer)
1244 writer.writeToken("{");
1246 writer.writeToken(patch.m_patchDef3 ? "patchDef3" : "patchDef2");
1248 writer.writeToken("{");
1252 inline void Patch_exportShader(const Patch& patch, TokenWriter& writer)
1254 // write shader name
1255 if(*(shader_get_textureName(patch.GetShader())) == '\0')
1257 writer.writeToken("NULL");
1261 writer.writeToken(shader_get_textureName(patch.GetShader()));
1266 inline void PatchDoom3_exportShader(const Patch& patch, TokenWriter& writer)
1268 // write shader name
1269 if(*(shader_get_textureName(patch.GetShader())) == '\0')
1271 writer.writeString("_emptyname");
1275 writer.writeString(patch.GetShader());
1280 inline void Patch_exportParams(const Patch& patch, TokenWriter& writer)
1282 // write matrix dimensions
1283 writer.writeToken("(");
1284 writer.writeUnsigned(patch.getWidth());
1285 writer.writeUnsigned(patch.getHeight());
1286 if(patch.m_patchDef3)
1288 writer.writeUnsigned(patch.m_subdivisions_x);
1289 writer.writeUnsigned(patch.m_subdivisions_y);
1291 writer.writeInteger(0);
1292 writer.writeInteger(0);
1293 writer.writeInteger(0);
1294 writer.writeToken(")");
1298 inline void Patch_exportMatrix(const Patch& patch, TokenWriter& writer)
1301 writer.writeToken("(");
1303 for(std::size_t c=0; c<patch.getWidth(); c++)
1305 writer.writeToken("(");
1306 for(std::size_t r=0; r<patch.getHeight(); r++)
1308 writer.writeToken("(");
1310 writer.writeFloat(patch.ctrlAt(r,c).m_vertex[0]);
1311 writer.writeFloat(patch.ctrlAt(r,c).m_vertex[1]);
1312 writer.writeFloat(patch.ctrlAt(r,c).m_vertex[2]);
1313 writer.writeFloat(patch.ctrlAt(r,c).m_texcoord[0]);
1314 writer.writeFloat(patch.ctrlAt(r,c).m_texcoord[1]);
1316 writer.writeToken(")");
1318 writer.writeToken(")");
1321 writer.writeToken(")");
1325 inline void Patch_exportFooter(const Patch& patch, TokenWriter& writer)
1327 writer.writeToken("}");
1329 writer.writeToken("}");
1333 class PatchTokenExporter : public MapExporter
1335 const Patch& m_patch;
1337 PatchTokenExporter(Patch& patch) : m_patch(patch)
1340 void exportTokens(TokenWriter& writer) const
1342 Patch_exportHeader(m_patch, writer);
1343 Patch_exportShader(m_patch, writer);
1344 Patch_exportParams(m_patch, writer);
1345 Patch_exportMatrix(m_patch, writer);
1346 Patch_exportFooter(m_patch, writer);
1350 class PatchDoom3TokenExporter : public MapExporter
1352 const Patch& m_patch;
1354 PatchDoom3TokenExporter(Patch& patch) : m_patch(patch)
1357 void exportTokens(TokenWriter& writer) const
1359 Patch_exportHeader(m_patch, writer);
1360 PatchDoom3_exportShader(m_patch, writer);
1361 Patch_exportParams(m_patch, writer);
1362 Patch_exportMatrix(m_patch, writer);
1363 Patch_exportFooter(m_patch, writer);
1367 class PatchControlInstance
1370 PatchControl* m_ctrl;
1371 ObservedSelectable m_selectable;
1373 PatchControlInstance(PatchControl* ctrl, const SelectionChangeCallback& observer)
1374 : m_ctrl(ctrl), m_selectable(observer)
1378 void testSelect(Selector& selector, SelectionTest& test)
1380 SelectionIntersection best;
1381 test.TestPoint(m_ctrl->m_vertex, best);
1384 Selector_add(selector, m_selectable, best);
1387 void snapto(float snap)
1389 vector3_snap(m_ctrl->m_vertex, snap);
1394 class PatchInstance :
1395 public Patch::Observer,
1396 public scene::Instance,
1399 public SelectionTestable,
1400 public ComponentSelectionTestable,
1401 public ComponentEditable,
1402 public ComponentSnappable,
1403 public PlaneSelectable,
1404 public LightCullable
1408 InstanceTypeCastTable m_casts;
1412 InstanceStaticCast<PatchInstance, Selectable>::install(m_casts);
1413 InstanceContainedCast<PatchInstance, Bounded>::install(m_casts);
1414 InstanceContainedCast<PatchInstance, Cullable>::install(m_casts);
1415 InstanceStaticCast<PatchInstance, Renderable>::install(m_casts);
1416 InstanceStaticCast<PatchInstance, SelectionTestable>::install(m_casts);
1417 InstanceStaticCast<PatchInstance, ComponentSelectionTestable>::install(m_casts);
1418 InstanceStaticCast<PatchInstance, ComponentEditable>::install(m_casts);
1419 InstanceStaticCast<PatchInstance, ComponentSnappable>::install(m_casts);
1420 InstanceStaticCast<PatchInstance, PlaneSelectable>::install(m_casts);
1421 InstanceIdentityCast<PatchInstance>::install(m_casts);
1422 InstanceContainedCast<PatchInstance, Transformable>::install(m_casts);
1424 InstanceTypeCastTable& get()
1432 typedef std::vector<PatchControlInstance> PatchControlInstances;
1433 PatchControlInstances m_ctrl_instances;
1435 ObservedSelectable m_selectable;
1437 DragPlanes m_dragPlanes;
1439 mutable RenderablePointVector m_render_selected;
1440 mutable AABB m_aabb_component;
1442 static Shader* m_state_selpoint;
1444 const LightList* m_lightList;
1446 TransformModifier m_transform;
1449 typedef LazyStatic<TypeCasts> StaticTypeCasts;
1451 void lightsChanged()
1453 m_lightList->lightsChanged();
1455 typedef MemberCaller<PatchInstance, &PatchInstance::lightsChanged> LightsChangedCaller;
1457 STRING_CONSTANT(Name, "PatchInstance");
1459 PatchInstance(const scene::Path& path, scene::Instance* parent, Patch& patch) :
1460 Instance(path, parent, this, StaticTypeCasts::instance().get()),
1462 m_selectable(SelectedChangedCaller(*this)),
1463 m_dragPlanes(SelectedChangedComponentCaller(*this)),
1464 m_render_selected(GL_POINTS),
1465 m_transform(Patch::TransformChangedCaller(m_patch), ApplyTransformCaller(*this))
1467 m_patch.instanceAttach(Instance::path());
1468 m_patch.attach(this);
1470 m_lightList = &GlobalShaderCache().attach(*this);
1471 m_patch.m_lightsChanged = LightsChangedCaller(*this);
1473 Instance::setTransformChangedCallback(LightsChangedCaller(*this));
1477 Instance::setTransformChangedCallback(Callback());
1479 m_patch.m_lightsChanged = Callback();
1480 GlobalShaderCache().detach(*this);
1482 m_patch.detach(this);
1483 m_patch.instanceDetach(Instance::path());
1486 void selectedChanged(const Selectable& selectable)
1488 GlobalSelectionSystem().getObserver(SelectionSystem::ePrimitive)(selectable);
1489 GlobalSelectionSystem().onSelectedChanged(*this, selectable);
1491 Instance::selectedChanged();
1493 typedef MemberCaller1<PatchInstance, const Selectable&, &PatchInstance::selectedChanged> SelectedChangedCaller;
1495 void selectedChangedComponent(const Selectable& selectable)
1497 GlobalSelectionSystem().getObserver(SelectionSystem::eComponent)(selectable);
1498 GlobalSelectionSystem().onComponentSelection(*this, selectable);
1500 typedef MemberCaller1<PatchInstance, const Selectable&, &PatchInstance::selectedChangedComponent> SelectedChangedComponentCaller;
1506 Bounded& get(NullType<Bounded>)
1510 Cullable& get(NullType<Cullable>)
1514 Transformable& get(NullType<Transformable>)
1519 static void constructStatic()
1521 m_state_selpoint = GlobalShaderCache().capture("$SELPOINT");
1524 static void destroyStatic()
1526 GlobalShaderCache().release("$SELPOINT");
1530 void allocate(std::size_t size)
1532 m_ctrl_instances.clear();
1533 m_ctrl_instances.reserve(size);
1534 for(Patch::iterator i = m_patch.begin(); i != m_patch.end(); ++i)
1536 m_ctrl_instances.push_back(PatchControlInstance(&(*i), SelectedChangedComponentCaller(*this)));
1540 void setSelected(bool select)
1542 m_selectable.setSelected(select);
1544 bool isSelected() const
1546 return m_selectable.isSelected();
1550 void update_selected() const
1552 m_render_selected.clear();
1553 Patch::iterator ctrl = m_patch.getControlPointsTransformed().begin();
1554 for(PatchControlInstances::const_iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i, ++ctrl)
1556 if((*i).m_selectable.isSelected())
1558 const Colour4b colour_selected(0, 0, 255, 255);
1559 m_render_selected.push_back(PointVertex(reinterpret_cast<Vertex3f&>((*ctrl).m_vertex), colour_selected));
1565 void render(Renderer& renderer, const VolumeTest& volume) const
1567 if(GlobalSelectionSystem().Mode() == SelectionSystem::eComponent
1568 && m_selectable.isSelected())
1570 renderer.Highlight(Renderer::eFace, false);
1572 m_patch.render(renderer, volume, localToWorld());
1574 if(GlobalSelectionSystem().ComponentMode() == SelectionSystem::eVertex)
1576 renderer.Highlight(Renderer::ePrimitive, false);
1578 m_patch.render_component(renderer, volume, localToWorld());
1580 renderComponentsSelected(renderer, volume);
1584 m_patch.render(renderer, volume, localToWorld());
1588 void renderSolid(Renderer& renderer, const VolumeTest& volume) const
1590 m_patch.evaluateTransform();
1591 renderer.setLights(*m_lightList);
1592 m_patch.render_solid(renderer, volume, localToWorld());
1594 renderComponentsSelected(renderer, volume);
1597 void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
1599 m_patch.evaluateTransform();
1600 m_patch.render_wireframe(renderer, volume, localToWorld());
1602 renderComponentsSelected(renderer, volume);
1605 void renderComponentsSelected(Renderer& renderer, const VolumeTest& volume) const
1607 m_patch.evaluateTransform();
1609 if(!m_render_selected.empty())
1611 renderer.Highlight(Renderer::ePrimitive, false);
1612 renderer.SetState(m_state_selpoint, Renderer::eWireframeOnly);
1613 renderer.SetState(m_state_selpoint, Renderer::eFullMaterials);
1614 renderer.addRenderable(m_render_selected, localToWorld());
1617 void renderComponents(Renderer& renderer, const VolumeTest& volume) const
1619 m_patch.evaluateTransform();
1620 if(GlobalSelectionSystem().ComponentMode() == SelectionSystem::eVertex)
1622 m_patch.render_component(renderer, volume, localToWorld());
1626 void testSelect(Selector& selector, SelectionTest& test)
1628 test.BeginMesh(localToWorld(), true);
1629 m_patch.testSelect(selector, test);
1632 void selectCtrl(bool select)
1634 for(PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1636 (*i).m_selectable.setSelected(select);
1639 bool isSelectedComponents() const
1641 for(PatchControlInstances::const_iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1643 if((*i).m_selectable.isSelected())
1650 void setSelectedComponents(bool select, SelectionSystem::EComponentMode mode)
1652 if(mode == SelectionSystem::eVertex)
1656 else if(mode == SelectionSystem::eFace)
1658 m_dragPlanes.setSelected(select);
1661 const AABB& getSelectedComponentsBounds() const
1663 m_aabb_component = AABB();
1665 for(PatchControlInstances::const_iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1667 if((*i).m_selectable.isSelected())
1669 aabb_extend_by_point_safe(m_aabb_component, (*i).m_ctrl->m_vertex);
1673 return m_aabb_component;
1676 void testSelectComponents(Selector& selector, SelectionTest& test, SelectionSystem::EComponentMode mode)
1678 test.BeginMesh(localToWorld());
1682 case SelectionSystem::eVertex:
1684 for(PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1686 (*i).testSelect(selector, test);
1695 bool selectedVertices()
1697 for(PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1699 if((*i).m_selectable.isSelected())
1707 void transformComponents(const Matrix4& matrix)
1709 if(selectedVertices())
1711 PatchControlIter ctrl = m_patch.getControlPointsTransformed().begin();
1712 for(PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i, ++ctrl)
1714 if((*i).m_selectable.isSelected())
1716 matrix4_transform_point(matrix, (*ctrl).m_vertex);
1719 m_patch.UpdateCachedData();
1722 if(m_dragPlanes.isSelected()) // this should only be true when the transform is a pure translation.
1724 m_patch.transform(m_dragPlanes.evaluateTransform(vector4_to_vector3(matrix.t())));
1729 void selectPlanes(Selector& selector, SelectionTest& test, const PlaneCallback& selectedPlaneCallback)
1731 test.BeginMesh(localToWorld());
1733 m_dragPlanes.selectPlanes(m_patch.localAABB(), selector, test, selectedPlaneCallback);
1735 void selectReversedPlanes(Selector& selector, const SelectedPlanes& selectedPlanes)
1737 m_dragPlanes.selectReversedPlanes(m_patch.localAABB(), selector, selectedPlanes);
1741 void snapComponents(float snap)
1743 if(selectedVertices())
1746 for(PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1748 if((*i).m_selectable.isSelected())
1753 m_patch.controlPointsChanged();
1757 void evaluateTransform()
1759 Matrix4 matrix(m_transform.calculateTransform());
1761 if(m_transform.getType() == TRANSFORM_PRIMITIVE)
1763 m_patch.transform(matrix);
1767 transformComponents(matrix);
1770 void applyTransform()
1772 m_patch.revertTransform();
1773 evaluateTransform();
1774 m_patch.freezeTransform();
1776 typedef MemberCaller<PatchInstance, &PatchInstance::applyTransform> ApplyTransformCaller;
1779 bool testLight(const RendererLight& light) const
1781 return light.testAABB(worldAABB());
1786 template<typename TokenImporter, typename TokenExporter>
1788 public scene::Node::Symbiot,
1789 public scene::Instantiable,
1790 public scene::Cloneable
1792 typedef PatchNode<TokenImporter, TokenExporter> Self;
1796 InstanceTypeCastTable m_casts;
1800 NodeStaticCast<PatchNode, scene::Instantiable>::install(m_casts);
1801 NodeStaticCast<PatchNode, scene::Cloneable>::install(m_casts);
1802 NodeContainedCast<PatchNode, Snappable>::install(m_casts);
1803 NodeContainedCast<PatchNode, TransformNode>::install(m_casts);
1804 NodeContainedCast<PatchNode, Patch>::install(m_casts);
1805 NodeContainedCast<PatchNode, XMLImporter>::install(m_casts);
1806 NodeContainedCast<PatchNode, XMLExporter>::install(m_casts);
1807 NodeContainedCast<PatchNode, MapImporter>::install(m_casts);
1808 NodeContainedCast<PatchNode, MapExporter>::install(m_casts);
1809 NodeContainedCast<PatchNode, Nameable>::install(m_casts);
1811 InstanceTypeCastTable& get()
1819 InstanceSet m_instances;
1821 TokenImporter m_importMap;
1822 TokenExporter m_exportMap;
1826 typedef LazyStatic<TypeCasts> StaticTypeCasts;
1828 Snappable& get(NullType<Snappable>)
1832 TransformNode& get(NullType<TransformNode>)
1836 Patch& get(NullType<Patch>)
1840 XMLImporter& get(NullType<XMLImporter>)
1844 XMLExporter& get(NullType<XMLExporter>)
1848 MapImporter& get(NullType<MapImporter>)
1852 MapExporter& get(NullType<MapExporter>)
1856 Nameable& get(NullType<Nameable>)
1861 PatchNode(bool patchDef3 = false) :
1862 m_node(this, this, StaticTypeCasts::instance().get()),
1863 m_patch(m_node, InstanceSetEvaluateTransform<PatchInstance>::Caller(m_instances), InstanceSet::BoundsChangedCaller(m_instances)),
1864 m_importMap(m_patch),
1865 m_exportMap(m_patch)
1867 m_patch.m_patchDef3 = patchDef3;
1869 PatchNode(const PatchNode& other) :
1870 scene::Node::Symbiot(other),
1871 scene::Instantiable(other),
1872 scene::Cloneable(other),
1873 m_node(this, this, StaticTypeCasts::instance().get()),
1874 m_patch(other.m_patch, m_node, InstanceSetEvaluateTransform<PatchInstance>::Caller(m_instances), InstanceSet::BoundsChangedCaller(m_instances)),
1875 m_importMap(m_patch),
1876 m_exportMap(m_patch)
1891 const Patch& get() const
1896 scene::Node& clone() const
1898 return (new PatchNode(*this))->node();
1901 scene::Instance* create(const scene::Path& path, scene::Instance* parent)
1903 return new PatchInstance(path, parent, m_patch);
1905 void forEachInstance(const scene::Instantiable::Visitor& visitor)
1907 m_instances.forEachInstance(visitor);
1909 void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
1911 m_instances.insert(observer, path, instance);
1913 scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
1915 return m_instances.erase(observer, path);
1921 typedef PatchNode<PatchTokenImporter, PatchTokenExporter> PatchNodeQuake3;
1922 typedef PatchNode<PatchDoom3TokenImporter, PatchDoom3TokenExporter> PatchNodeDoom3;
1924 inline Patch* Node_getPatch(scene::Node& node)
1926 return NodeTypeCast<Patch>::cast(node);
1929 inline PatchInstance* Instance_getPatch(scene::Instance& instance)
1931 return InstanceTypeCast<PatchInstance>::cast(instance);
1934 template<typename Functor>
1935 class PatchSelectedVisitor : public SelectionSystem::Visitor
1937 const Functor& m_functor;
1939 PatchSelectedVisitor(const Functor& functor) : m_functor(functor)
1942 void visit(scene::Instance& instance) const
1944 PatchInstance* patch = Instance_getPatch(instance);
1952 template<typename Functor>
1953 inline void Scene_forEachSelectedPatch(const Functor& functor)
1955 GlobalSelectionSystem().foreachSelected(PatchSelectedVisitor<Functor>(functor));
1959 template<typename Functor>
1960 class PatchVisibleSelectedVisitor : public SelectionSystem::Visitor
1962 const Functor& m_functor;
1964 PatchVisibleSelectedVisitor(const Functor& functor) : m_functor(functor)
1967 void visit(scene::Instance& instance) const
1969 PatchInstance* patch = Instance_getPatch(instance);
1971 && instance.path().top().get().visible())
1978 template<typename Functor>
1979 inline void Scene_forEachVisibleSelectedPatchInstance(const Functor& functor)
1981 GlobalSelectionSystem().foreachSelected(PatchVisibleSelectedVisitor<Functor>(functor));
1984 template<typename Functor>
1985 class PatchForEachWalker : public scene::Graph::Walker
1987 const Functor& m_functor;
1989 PatchForEachWalker(const Functor& functor) : m_functor(functor)
1992 bool pre(const scene::Path& path, scene::Instance& instance) const
1994 if(path.top().get().visible())
1996 Patch* patch = Node_getPatch(path.top());
2006 template<typename Functor>
2007 inline void Scene_forEachVisiblePatch(const Functor& functor)
2009 GlobalSceneGraph().traverse(PatchForEachWalker<Functor>(functor));
2012 template<typename Functor>
2013 class PatchForEachSelectedWalker : public scene::Graph::Walker
2015 const Functor& m_functor;
2017 PatchForEachSelectedWalker(const Functor& functor) : m_functor(functor)
2020 bool pre(const scene::Path& path, scene::Instance& instance) const
2022 if(path.top().get().visible())
2024 Patch* patch = Node_getPatch(path.top());
2026 && Instance_getSelectable(instance)->isSelected())
2035 template<typename Functor>
2036 inline void Scene_forEachVisibleSelectedPatch(const Functor& functor)
2038 GlobalSceneGraph().traverse(PatchForEachSelectedWalker<Functor>(functor));
2041 template<typename Functor>
2042 class PatchForEachInstanceWalker : public scene::Graph::Walker
2044 const Functor& m_functor;
2046 PatchForEachInstanceWalker(const Functor& functor) : m_functor(functor)
2049 bool pre(const scene::Path& path, scene::Instance& instance) const
2051 if(path.top().get().visible())
2053 PatchInstance* patch = Instance_getPatch(instance);
2063 template<typename Functor>
2064 inline void Scene_forEachVisiblePatchInstance(const Functor& functor)
2066 GlobalSceneGraph().traverse(PatchForEachInstanceWalker<Functor>(functor));