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"
48 #include "math/frustum.h"
49 #include "string/string.h"
50 #include "stream/stringstream.h"
51 #include "stream/textstream.h"
52 #include "xml/xmlelement.h"
54 #include "transformlib.h"
55 #include "instancelib.h"
56 #include "selectionlib.h"
57 #include "traverselib.h"
60 #include "shaderlib.h"
61 #include "generic/callback.h"
62 #include "signal/signalfwd.h"
63 #include "texturelib.h"
65 #include "dragplanes.h"
73 extern int g_PatchSubdivideThreshold;
76 #define MIN_PATCH_WIDTH 3
77 #define MIN_PATCH_HEIGHT 3
79 extern std::size_t MAX_PATCH_WIDTH;
80 extern std::size_t MAX_PATCH_HEIGHT;
82 #define MAX_PATCH_ROWCTRL (((MAX_PATCH_WIDTH-1)-1)/2)
83 #define MAX_PATCH_COLCTRL (((MAX_PATCH_HEIGHT-1)-1)/2)
122 const std::size_t BEZIERCURVETREE_MAX_INDEX = std::size_t(1) << (std::numeric_limits<std::size_t>::digits - 1);
124 struct BezierCurveTree
127 BezierCurveTree* left;
128 BezierCurveTree* right;
131 inline bool BezierCurveTree_isLeaf(const BezierCurveTree* node)
133 return node->left == 0 && node->right == 0;
136 void BezierCurveTree_Delete(BezierCurveTree *pCurve);
139 inline VertexPointer vertexpointer_arbitrarymeshvertex(const ArbitraryMeshVertex* array)
141 return VertexPointer(VertexPointer::pointer(&array->vertex), sizeof(ArbitraryMeshVertex));
144 typedef PatchControl* PatchControlIter;
145 typedef const PatchControl* PatchControlConstIter;
147 inline void copy_ctrl(PatchControlIter ctrl, PatchControlConstIter begin, PatchControlConstIter end)
149 std::copy(begin, end, ctrl);
152 const Colour4b colour_corner(0, 255, 0, 255);
153 const Colour4b colour_inside(255, 0, 255, 255);
160 virtual bool filter(const Patch& patch) const = 0;
163 bool patch_filtered(Patch& patch);
164 void add_patch_filter(PatchFilter& filter, int mask, bool invert = false);
166 void Patch_addTextureChangedCallback(const SignalHandler& handler);
167 void Patch_textureChanged();
169 inline void BezierCurveTreeArray_deleteAll(Array<BezierCurveTree*>& curveTrees)
171 for(Array<BezierCurveTree*>::iterator i = curveTrees.begin(); i != curveTrees.end(); ++i)
173 BezierCurveTree_Delete(*i);
177 inline void PatchControlArray_invert(Array<PatchControl>& ctrl, std::size_t width, std::size_t height)
179 Array<PatchControl> tmp(width);
181 PatchControlIter from = ctrl.data() + (width * (height - 1));
182 PatchControlIter to = ctrl.data();
183 for(std::size_t h = 0; h != ((height - 1) >> 1); ++h, to += width, from -= width)
185 copy_ctrl(tmp.data(), to, to + width);
186 copy_ctrl(to, from, from + width);
187 copy_ctrl(from, tmp.data(), tmp.data() + width);
191 class PatchTesselation
195 : m_numStrips(0), m_lenStrips(0), m_nArrayWidth(0), m_nArrayHeight(0)
198 Array<ArbitraryMeshVertex> m_vertices;
199 Array<RenderIndex> m_indices;
200 std::size_t m_numStrips;
201 std::size_t m_lenStrips;
203 Array<std::size_t> m_arrayWidth;
204 std::size_t m_nArrayWidth;
205 Array<std::size_t> m_arrayHeight;
206 std::size_t m_nArrayHeight;
208 Array<BezierCurveTree*> m_curveTreeU;
209 Array<BezierCurveTree*> m_curveTreeV;
212 class RenderablePatchWireframe : public OpenGLRenderable
214 PatchTesselation& m_tess;
216 RenderablePatchWireframe(PatchTesselation& tess) : m_tess(tess)
219 void render(RenderStateFlags state) const
223 glVertexPointer(3, GL_FLOAT, 0, 0);
224 glDrawArrays(GL_TRIANGLE_FAN, 0, 0);
228 glVertexPointer(3, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->vertex);
229 for(std::size_t i = 0; i <= m_tess.m_curveTreeV.size(); ++i)
231 glDrawArrays(GL_LINE_STRIP, GLint(n), GLsizei(m_tess.m_nArrayWidth));
233 if(i == m_tess.m_curveTreeV.size()) break;
235 if(!BezierCurveTree_isLeaf(m_tess.m_curveTreeV[i]))
236 glDrawArrays(GL_LINE_STRIP, GLint(m_tess.m_curveTreeV[i]->index), GLsizei(m_tess.m_nArrayWidth));
238 n += (m_tess.m_arrayHeight[i]*m_tess.m_nArrayWidth);
244 const ArbitraryMeshVertex* p = m_tess.m_vertices.data();
245 std::size_t n = m_tess.m_nArrayWidth * sizeof(ArbitraryMeshVertex);
246 for(std::size_t i = 0; i <= m_tess.m_curveTreeU.size(); ++i)
248 glVertexPointer(3, GL_FLOAT, GLsizei(n), &p->vertex);
249 glDrawArrays(GL_LINE_STRIP, 0, GLsizei(m_tess.m_nArrayHeight));
251 if(i == m_tess.m_curveTreeU.size()) break;
253 if(!BezierCurveTree_isLeaf(m_tess.m_curveTreeU[i]))
255 glVertexPointer(3, GL_FLOAT, GLsizei(n), &(m_tess.m_vertices.data() + (m_tess.m_curveTreeU[i]->index))->vertex);
256 glDrawArrays(GL_LINE_STRIP, 0, GLsizei(m_tess.m_nArrayHeight));
259 p += m_tess.m_arrayWidth[i];
265 class RenderablePatchFixedWireframe : public OpenGLRenderable
267 PatchTesselation& m_tess;
269 RenderablePatchFixedWireframe(PatchTesselation& tess) : m_tess(tess)
272 void render(RenderStateFlags state) const
274 glVertexPointer(3, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->vertex);
275 const RenderIndex* strip_indices = m_tess.m_indices.data();
276 for(std::size_t i = 0; i<m_tess.m_numStrips; i++, strip_indices += m_tess.m_lenStrips)
278 glDrawElements(GL_QUAD_STRIP, GLsizei(m_tess.m_lenStrips), RenderIndexTypeID, strip_indices);
283 class RenderablePatchSolid : public OpenGLRenderable
285 PatchTesselation& m_tess;
287 RenderablePatchSolid(PatchTesselation& tess) : m_tess(tess)
290 void RenderNormals() const;
291 void render(RenderStateFlags state) const
294 if((state & RENDER_FILL) == 0)
296 RenderablePatchWireframe(m_tess).render(state);
301 if((state & RENDER_BUMP) != 0)
303 if(GlobalShaderCache().useShaderLanguage())
305 glNormalPointer(GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->normal);
306 glVertexAttribPointerARB(c_attr_TexCoord0, 2, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->texcoord);
307 glVertexAttribPointerARB(c_attr_Tangent, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->tangent);
308 glVertexAttribPointerARB(c_attr_Binormal, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->bitangent);
312 glVertexAttribPointerARB(11, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->normal);
313 glVertexAttribPointerARB(8, 2, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->texcoord);
314 glVertexAttribPointerARB(9, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->tangent);
315 glVertexAttribPointerARB(10, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->bitangent);
320 glNormalPointer(GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->normal);
321 glTexCoordPointer(2, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->texcoord);
323 glVertexPointer(3, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->vertex);
324 const RenderIndex* strip_indices = m_tess.m_indices.data();
325 for(std::size_t i = 0; i<m_tess.m_numStrips; i++, strip_indices += m_tess.m_lenStrips)
327 glDrawElements(GL_QUAD_STRIP, GLsizei(m_tess.m_lenStrips), RenderIndexTypeID, strip_indices);
337 // parametric surface defined by quadratic bezier control curves
341 public TransformNode,
359 xml_state_t(EState state)
366 const char* content() const
368 return m_content.c_str();
370 std::size_t write(const char* buffer, std::size_t length)
372 return m_content.write(buffer, length);
376 StringOutputStream m_content;
379 std::vector<xml_state_t> m_xml_state;
381 typedef Array<PatchControl> PatchControlArray;
383 class SavedState : public UndoMemento
389 const PatchControlArray& ctrl,
392 std::size_t subdivisions_x,
393 std::size_t subdivisions_y
399 m_patchDef3(patchDef3),
400 m_subdivisions_x(subdivisions_x),
401 m_subdivisions_y(subdivisions_y)
410 std::size_t m_width, m_height;
411 CopiedString m_shader;
412 PatchControlArray m_ctrl;
414 std::size_t m_subdivisions_x;
415 std::size_t m_subdivisions_y;
422 virtual void allocate(std::size_t size) = 0;
426 typedef UniqueSet<Observer*> Observers;
427 Observers m_observers;
431 AABB m_aabb_local; // local bbox
433 CopiedString m_shader;
437 std::size_t m_height;
440 std::size_t m_subdivisions_x;
441 std::size_t m_subdivisions_y;
444 UndoObserver* m_undoable_observer;
447 // dynamically allocated array of control points, size is m_width*m_height
448 PatchControlArray m_ctrl;
449 PatchControlArray m_ctrlTransformed;
451 PatchTesselation m_tess;
452 RenderablePatchSolid m_render_solid;
453 RenderablePatchWireframe m_render_wireframe;
454 RenderablePatchFixedWireframe m_render_wireframe_fixed;
456 static Shader* m_state_ctrl;
457 static Shader* m_state_lattice;
458 VertexBuffer<PointVertex> m_ctrl_vertices;
459 RenderableVertexBuffer m_render_ctrl;
460 IndexBuffer m_lattice_indices;
461 RenderableIndexBuffer m_render_lattice;
465 bool m_transformChanged;
466 Callback m_evaluateTransform;
467 Callback m_boundsChanged;
472 m_width = m_height = 0;
475 m_subdivisions_x = 0;
476 m_subdivisions_y = 0;
481 m_xml_state.push_back(xml_state_t::eDefault);
485 Callback m_lightsChanged;
487 static int m_CycleCapIndex;// = 0;
488 static EPatchType m_type;
490 STRING_CONSTANT(Name, "Patch");
492 Patch(scene::Node& node, const Callback& evaluateTransform, const Callback& boundsChanged) :
494 m_shader(texdef_name_default()),
496 m_undoable_observer(0),
498 m_render_solid(m_tess),
499 m_render_wireframe(m_tess),
500 m_render_wireframe_fixed(m_tess),
501 m_render_ctrl(GL_POINTS, m_ctrl_vertices),
502 m_render_lattice(GL_LINES, m_lattice_indices, m_ctrl_vertices),
503 m_transformChanged(false),
504 m_evaluateTransform(evaluateTransform),
505 m_boundsChanged(boundsChanged)
509 Patch(const Patch& other, scene::Node& node, const Callback& evaluateTransform, const Callback& boundsChanged) :
511 m_shader(texdef_name_default()),
513 m_undoable_observer(0),
515 m_render_solid(m_tess),
516 m_render_wireframe(m_tess),
517 m_render_wireframe_fixed(m_tess),
518 m_render_ctrl(GL_POINTS, m_ctrl_vertices),
519 m_render_lattice(GL_LINES, m_lattice_indices, m_ctrl_vertices),
520 m_transformChanged(false),
521 m_evaluateTransform(evaluateTransform),
522 m_boundsChanged(boundsChanged)
526 m_patchDef3 = other.m_patchDef3;
527 m_subdivisions_x = other.m_subdivisions_x;
528 m_subdivisions_y = other.m_subdivisions_y;
529 setDims(other.m_width, other.m_height);
530 copy_ctrl(m_ctrl.data(), other.m_ctrl.data(), other.m_ctrl.data()+(m_width*m_height));
531 SetShader(other.m_shader.c_str());
532 controlPointsChanged();
535 Patch(const Patch& other) :
538 TransformNode(other),
546 m_undoable_observer(0),
548 m_render_solid(m_tess),
549 m_render_wireframe(m_tess),
550 m_render_wireframe_fixed(m_tess),
551 m_render_ctrl(GL_POINTS, m_ctrl_vertices),
552 m_render_lattice(GL_LINES, m_lattice_indices, m_ctrl_vertices),
553 m_transformChanged(false),
554 m_evaluateTransform(other.m_evaluateTransform),
555 m_boundsChanged(other.m_boundsChanged)
559 m_patchDef3 = other.m_patchDef3;
560 m_subdivisions_x = other.m_subdivisions_x;
561 m_subdivisions_y = other.m_subdivisions_y;
562 setDims(other.m_width, other.m_height);
563 copy_ctrl(m_ctrl.data(), other.m_ctrl.data(), other.m_ctrl.data()+(m_width*m_height));
564 SetShader(other.m_shader.c_str());
565 controlPointsChanged();
570 BezierCurveTreeArray_deleteAll(m_tess.m_curveTreeU);
571 BezierCurveTreeArray_deleteAll(m_tess.m_curveTreeV);
575 ASSERT_MESSAGE(m_observers.empty(), "Patch::~Patch: observers still attached");
578 InstanceCounter m_instanceCounter;
579 void instanceAttach(const scene::Path& path)
581 if(++m_instanceCounter.m_count == 1)
583 m_state->incrementUsed();
584 m_map = path_find_mapfile(path.begin(), path.end());
585 m_undoable_observer = GlobalUndoSystem().observer(this);
586 GlobalFilterSystem().registerFilterable(*this);
590 ASSERT_MESSAGE(path_find_mapfile(path.begin(), path.end()) == m_map, "node is instanced across more than one file");
593 void instanceDetach(const scene::Path& path)
595 if(--m_instanceCounter.m_count == 0)
598 m_undoable_observer = 0;
599 GlobalUndoSystem().release(this);
600 GlobalFilterSystem().unregisterFilterable(*this);
601 m_state->decrementUsed();
605 const char* name() const
609 void attach(const NameCallback& callback)
612 void detach(const NameCallback& callback)
616 void attach(Observer* observer)
618 observer->allocate(m_width * m_height);
620 m_observers.insert(observer);
622 void detach(Observer* observer)
624 m_observers.erase(observer);
627 void updateFiltered()
631 if(patch_filtered(*this))
633 m_node->enable(scene::Node::eFiltered);
637 m_node->disable(scene::Node::eFiltered);
642 void onAllocate(std::size_t size)
644 for(Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i)
646 (*i)->allocate(size);
650 const Matrix4& localToParent() const
652 return g_matrix4_identity;
654 const AABB& localAABB() const
658 VolumeIntersectionValue intersectVolume(const VolumeTest& test, const Matrix4& localToWorld) const
660 return test.TestAABB(m_aabb_local, localToWorld);
662 void render_solid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
664 renderer.SetState(m_state, Renderer::eFullMaterials);
665 renderer.addRenderable(m_render_solid, localToWorld);
667 void render_wireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
669 renderer.SetState(m_state, Renderer::eFullMaterials);
672 renderer.addRenderable(m_render_wireframe_fixed, localToWorld);
676 renderer.addRenderable(m_render_wireframe, localToWorld);
680 void render_component(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
682 renderer.SetState(m_state_lattice, Renderer::eWireframeOnly);
683 renderer.SetState(m_state_lattice, Renderer::eFullMaterials);
684 renderer.addRenderable(m_render_lattice, localToWorld);
686 renderer.SetState(m_state_ctrl, Renderer::eWireframeOnly);
687 renderer.SetState(m_state_ctrl, Renderer::eFullMaterials);
688 renderer.addRenderable(m_render_ctrl, localToWorld);
690 void testSelect(Selector& selector, SelectionTest& test)
692 SelectionIntersection best;
693 IndexPointer::index_type* pIndex = m_tess.m_indices.data();
694 for(std::size_t s=0; s<m_tess.m_numStrips; s++)
696 test.TestQuadStrip(vertexpointer_arbitrarymeshvertex(m_tess.m_vertices.data()), IndexPointer(pIndex, m_tess.m_lenStrips), best);
697 pIndex += m_tess.m_lenStrips;
701 selector.addIntersection(best);
704 void transform(const Matrix4& matrix)
706 for(PatchControlIter i = m_ctrlTransformed.data(); i != m_ctrlTransformed.data() + m_ctrlTransformed.size(); ++i)
708 matrix4_transform_point(matrix, (*i).m_vertex);
711 if(matrix4_handedness(matrix) == MATRIX4_LEFTHANDED)
713 PatchControlArray_invert(m_ctrlTransformed, m_width, m_height);
717 void transformChanged()
719 m_transformChanged = true;
723 typedef MemberCaller<Patch, &Patch::transformChanged> TransformChangedCaller;
725 void evaluateTransform()
727 if(m_transformChanged)
729 m_transformChanged = false;
731 m_evaluateTransform();
735 void revertTransform()
737 m_ctrlTransformed = m_ctrl;
739 void freezeTransform()
743 ASSERT_MESSAGE(m_ctrlTransformed.size() == m_ctrl.size(), "Patch::freeze: size mismatch");
744 std::copy(m_ctrlTransformed.begin(), m_ctrlTransformed.end(), m_ctrl.begin());
747 void controlPointsChanged()
753 bool isValid() const;
755 void snapto(float snap)
759 for(PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i)
761 vector3_snap((*i).m_vertex, snap);
764 controlPointsChanged();
770 void RenderDebug(RenderStateFlags state) const;
771 void RenderNormals(RenderStateFlags state) const;
773 void pushElement(const XMLElement& element)
775 switch(m_xml_state.back().state())
777 case xml_state_t::eDefault:
778 ASSERT_MESSAGE(string_equal(element.name(), "patch"), "parse error");
779 m_xml_state.push_back(xml_state_t::ePatch);
781 case xml_state_t::ePatch:
782 if(string_equal(element.name(), "matrix"))
784 setDims(atoi(element.attribute("width")), atoi(element.attribute("height")));
785 m_xml_state.push_back(xml_state_t::eMatrix);
787 else if(string_equal(element.name(), "shader"))
789 m_xml_state.push_back(xml_state_t::eShader);
793 ERROR_MESSAGE("parse error");
797 void popElement(const char* name)
799 switch(m_xml_state.back().state())
801 case xml_state_t::eDefault:
802 ERROR_MESSAGE("parse error");
804 case xml_state_t::ePatch:
806 case xml_state_t::eMatrix:
808 StringTokeniser content(m_xml_state.back().content());
810 for(PatchControlIter i = m_ctrl.data(), end = m_ctrl.data() + m_ctrl.size(); i != end; ++i)
812 (*i).m_vertex[0] = string_read_float(content.getToken());
813 (*i).m_vertex[1] = string_read_float(content.getToken());
814 (*i).m_vertex[2] = string_read_float(content.getToken());
815 (*i).m_texcoord[0] = string_read_float(content.getToken());
816 (*i).m_texcoord[1] = string_read_float(content.getToken());
818 controlPointsChanged();
821 case xml_state_t::eShader:
823 SetShader(m_xml_state.back().content());
827 ERROR_MESSAGE("parse error");
830 ASSERT_MESSAGE(!m_xml_state.empty(), "popping empty stack");
831 m_xml_state.pop_back();
833 std::size_t write(const char* buffer, std::size_t length)
835 switch(m_xml_state.back().state())
837 case xml_state_t::eDefault:
839 case xml_state_t::ePatch:
841 case xml_state_t::eMatrix:
842 case xml_state_t::eShader:
843 return m_xml_state.back().write(buffer, length);
846 ERROR_MESSAGE("parse error");
851 void exportXML(XMLImporter& importer)
853 StaticElement patchElement("patch");
854 importer.pushElement(patchElement);
857 const StaticElement element("shader");
858 importer.pushElement(element);
859 importer.write(m_shader.c_str(), strlen(m_shader.c_str()));
860 importer.popElement(element.name());
864 char width[16], height[16];
865 sprintf(width, "%u", Unsigned(m_width));
866 sprintf(height, "%u", Unsigned(m_height));
867 StaticElement element("matrix");
868 element.insertAttribute("width", width);
869 element.insertAttribute("height", height);
871 importer.pushElement(element);
873 for(PatchControlIter i = m_ctrl.data(), end = m_ctrl.data() + m_ctrl.size(); i != end; ++i)
875 importer << (*i).m_vertex[0]
876 << ' ' << (*i).m_vertex[1]
877 << ' ' << (*i).m_vertex[2]
878 << ' ' << (*i).m_texcoord[0]
879 << ' ' << (*i).m_texcoord[1];
882 importer.popElement(element.name());
885 importer.popElement(patchElement.name());
888 void UpdateCachedData();
890 const char *GetShader() const
892 return m_shader.c_str();
894 void SetShader(const char* name)
896 ASSERT_NOTNULL(name);
898 if(shader_equal(m_shader.c_str(), name))
903 if(m_instanceCounter.m_count != 0)
905 m_state->decrementUsed();
910 if(m_instanceCounter.m_count != 0)
912 m_state->incrementUsed();
916 Patch_textureChanged();
918 int getShaderFlags() const
922 return m_state->getFlags();
927 typedef PatchControl* iterator;
928 typedef const PatchControl* const_iterator;
932 return m_ctrl.data();
934 const_iterator begin() const
936 return m_ctrl.data();
940 return m_ctrl.data() + m_ctrl.size();
942 const_iterator end() const
944 return m_ctrl.data() + m_ctrl.size();
947 PatchControlArray& getControlPoints()
951 PatchControlArray& getControlPointsTransformed()
953 return m_ctrlTransformed;
956 void setDims (std::size_t w, std::size_t h);
957 std::size_t getWidth() const
961 std::size_t getHeight() const
965 PatchControl& ctrlAt(std::size_t row, std::size_t col)
967 return m_ctrl[row*m_width+col];
969 const PatchControl& ctrlAt(std::size_t row, std::size_t col) const
971 return m_ctrl[row*m_width+col];
974 void ConstructPrefab(const AABB& aabb, EPatchPrefab eType, int axis, std::size_t width = 3, std::size_t height = 3);
975 void constructPlane(const AABB& aabb, int axis, std::size_t width, std::size_t height);
977 void TransposeMatrix();
978 void Redisperse(EMatrixMajor mt);
979 void Smooth(EMatrixMajor mt);
980 void InsertRemove(bool bInsert, bool bColumn, bool bFirst);
981 Patch* MakeCap(Patch* patch, EPatchCap eType, EMatrixMajor mt, bool bFirst);
982 void ConstructSeam(EPatchCap eType, Vector3* p, std::size_t width);
984 void FlipTexture(int nAxis);
985 void TranslateTexture(float s, float t);
986 void ScaleTexture(float s, float t);
987 void RotateTexture(float angle);
988 void SetTextureRepeat(float s, float t); // call with s=1 t=1 for FIT
990 void NaturalTexture();
991 void ProjectTexture(int nAxis);
999 if(m_undoable_observer != 0)
1001 m_undoable_observer->save(this);
1005 UndoMemento* exportState() const
1007 return new SavedState(m_width, m_height, m_ctrl, m_shader.c_str(), m_patchDef3, m_subdivisions_x, m_subdivisions_y);
1009 void importState(const UndoMemento* state)
1013 const SavedState& other = *(static_cast<const SavedState*>(state));
1015 // begin duplicate of SavedState copy constructor, needs refactoring
1019 m_width = other.m_width;
1020 m_height = other.m_height;
1021 SetShader(other.m_shader.c_str());
1022 m_ctrl = other.m_ctrl;
1023 onAllocate(m_ctrl.size());
1024 m_patchDef3 = other.m_patchDef3;
1025 m_subdivisions_x = other.m_subdivisions_x;
1026 m_subdivisions_y = other.m_subdivisions_y;
1029 // end duplicate code
1031 Patch_textureChanged();
1033 controlPointsChanged();
1036 static void constructStatic(EPatchType type)
1038 Patch::m_type = type;
1039 Patch::m_state_ctrl = GlobalShaderCache().capture("$POINT");
1040 Patch::m_state_lattice = GlobalShaderCache().capture("$LATTICE");
1043 static void destroyStatic()
1045 GlobalShaderCache().release("$LATTICE");
1046 GlobalShaderCache().release("$POINT");
1049 void captureShader()
1051 m_state = GlobalShaderCache().capture(m_shader.c_str());
1054 void releaseShader()
1056 GlobalShaderCache().release(m_shader.c_str());
1061 if(!shader_valid(GetShader()))
1063 globalErrorStream() << "patch has invalid texture name: '" << GetShader() << "'\n";
1067 void InsertPoints(EMatrixMajor mt, bool bFirst);
1068 void RemovePoints(EMatrixMajor mt, bool bFirst);
1070 void AccumulateBBox();
1072 void TesselateSubMatrixFixed(ArbitraryMeshVertex* vertices, std::size_t strideX, std::size_t strideY, unsigned int nFlagsX, unsigned int nFlagsY, PatchControl* subMatrix[3][3]);
1074 // uses binary trees representing bezier curves to recursively tesselate a bezier sub-patch
1075 void TesselateSubMatrix( const BezierCurveTree *BX, const BezierCurveTree *BY,
1076 std::size_t offStartX, std::size_t offStartY,
1077 std::size_t offEndX, std::size_t offEndY,
1078 std::size_t nFlagsX, std::size_t nFlagsY,
1079 Vector3& left, Vector3& mid, Vector3& right,
1080 Vector2& texLeft, Vector2& texMid, Vector2& texRight,
1083 // tesselates the entire surface
1084 void BuildTesselationCurves(EMatrixMajor major);
1085 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);
1086 void BuildVertexArray();
1089 inline bool Patch_importHeader(Patch& patch, Tokeniser& tokeniser)
1091 tokeniser.nextLine();
1092 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "{"));
1096 inline bool Patch_importShader(Patch& patch, Tokeniser& tokeniser)
1098 // parse shader name
1099 tokeniser.nextLine();
1100 const char* texture = tokeniser.getToken();
1103 Tokeniser_unexpectedError(tokeniser, texture, "#texture-name");
1106 if(string_equal(texture, "NULL"))
1108 patch.SetShader(texdef_name_default());
1112 StringOutputStream shader(string_length(GlobalTexturePrefix_get()) + string_length(texture));
1113 shader << GlobalTexturePrefix_get() << texture;
1114 patch.SetShader(shader.c_str());
1119 inline bool PatchDoom3_importShader(Patch& patch, Tokeniser& tokeniser)
1121 // parse shader name
1122 tokeniser.nextLine();
1123 const char *shader = tokeniser.getToken();
1126 Tokeniser_unexpectedError(tokeniser, shader, "#shader-name");
1129 if(string_equal(shader, "_emptyname"))
1131 shader = texdef_name_default();
1133 patch.SetShader(shader);
1137 inline bool Patch_importParams(Patch& patch, Tokeniser& tokeniser)
1139 tokeniser.nextLine();
1140 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
1142 // parse matrix dimensions
1145 RETURN_FALSE_IF_FAIL(Tokeniser_getSize(tokeniser, c));
1146 RETURN_FALSE_IF_FAIL(Tokeniser_getSize(tokeniser, r));
1148 patch.setDims(c, r);
1151 if(patch.m_patchDef3)
1153 RETURN_FALSE_IF_FAIL(Tokeniser_getSize(tokeniser, patch.m_subdivisions_x));
1154 RETURN_FALSE_IF_FAIL(Tokeniser_getSize(tokeniser, patch.m_subdivisions_y));
1157 // ignore contents/flags/value
1159 RETURN_FALSE_IF_FAIL(Tokeniser_getInteger(tokeniser, tmp));
1160 RETURN_FALSE_IF_FAIL(Tokeniser_getInteger(tokeniser, tmp));
1161 RETURN_FALSE_IF_FAIL(Tokeniser_getInteger(tokeniser, tmp));
1163 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
1167 inline bool Patch_importMatrix(Patch& patch, Tokeniser& tokeniser)
1170 tokeniser.nextLine();
1171 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
1173 for(std::size_t c=0; c<patch.getWidth(); c++)
1175 tokeniser.nextLine();
1176 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
1177 for(std::size_t r=0; r<patch.getHeight(); r++)
1179 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
1181 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r,c).m_vertex[0]));
1182 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r,c).m_vertex[1]));
1183 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r,c).m_vertex[2]));
1184 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r,c).m_texcoord[0]));
1185 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r,c).m_texcoord[1]));
1187 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
1189 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
1192 tokeniser.nextLine();
1193 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
1197 inline bool Patch_importFooter(Patch& patch, Tokeniser& tokeniser)
1199 patch.controlPointsChanged();
1201 tokeniser.nextLine();
1202 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "}"));
1204 tokeniser.nextLine();
1205 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "}"));
1209 class PatchTokenImporter : public MapImporter
1213 PatchTokenImporter(Patch& patch) : m_patch(patch)
1216 bool importTokens(Tokeniser& tokeniser)
1218 RETURN_FALSE_IF_FAIL(Patch_importHeader(m_patch, tokeniser));
1219 RETURN_FALSE_IF_FAIL(Patch_importShader(m_patch, tokeniser));
1220 RETURN_FALSE_IF_FAIL(Patch_importParams(m_patch, tokeniser));
1221 RETURN_FALSE_IF_FAIL(Patch_importMatrix(m_patch, tokeniser));
1222 RETURN_FALSE_IF_FAIL(Patch_importFooter(m_patch, tokeniser));
1228 class PatchDoom3TokenImporter : public MapImporter
1232 PatchDoom3TokenImporter(Patch& patch) : m_patch(patch)
1235 bool importTokens(Tokeniser& tokeniser)
1237 RETURN_FALSE_IF_FAIL(Patch_importHeader(m_patch, tokeniser));
1238 RETURN_FALSE_IF_FAIL(PatchDoom3_importShader(m_patch, tokeniser));
1239 RETURN_FALSE_IF_FAIL(Patch_importParams(m_patch, tokeniser));
1240 RETURN_FALSE_IF_FAIL(Patch_importMatrix(m_patch, tokeniser));
1241 RETURN_FALSE_IF_FAIL(Patch_importFooter(m_patch, tokeniser));
1247 inline void Patch_exportHeader(const Patch& patch, TokenWriter& writer)
1249 writer.writeToken("{");
1251 writer.writeToken(patch.m_patchDef3 ? "patchDef3" : "patchDef2");
1253 writer.writeToken("{");
1257 inline void Patch_exportShader(const Patch& patch, TokenWriter& writer)
1259 // write shader name
1260 if(*(shader_get_textureName(patch.GetShader())) == '\0')
1262 writer.writeToken("NULL");
1266 writer.writeToken(shader_get_textureName(patch.GetShader()));
1271 inline void PatchDoom3_exportShader(const Patch& patch, TokenWriter& writer)
1273 // write shader name
1274 if(*(shader_get_textureName(patch.GetShader())) == '\0')
1276 writer.writeString("_emptyname");
1280 writer.writeString(patch.GetShader());
1285 inline void Patch_exportParams(const Patch& patch, TokenWriter& writer)
1287 // write matrix dimensions
1288 writer.writeToken("(");
1289 writer.writeUnsigned(patch.getWidth());
1290 writer.writeUnsigned(patch.getHeight());
1291 if(patch.m_patchDef3)
1293 writer.writeUnsigned(patch.m_subdivisions_x);
1294 writer.writeUnsigned(patch.m_subdivisions_y);
1296 writer.writeInteger(0);
1297 writer.writeInteger(0);
1298 writer.writeInteger(0);
1299 writer.writeToken(")");
1303 inline void Patch_exportMatrix(const Patch& patch, TokenWriter& writer)
1306 writer.writeToken("(");
1308 for(std::size_t c=0; c<patch.getWidth(); c++)
1310 writer.writeToken("(");
1311 for(std::size_t r=0; r<patch.getHeight(); r++)
1313 writer.writeToken("(");
1315 writer.writeFloat(patch.ctrlAt(r,c).m_vertex[0]);
1316 writer.writeFloat(patch.ctrlAt(r,c).m_vertex[1]);
1317 writer.writeFloat(patch.ctrlAt(r,c).m_vertex[2]);
1318 writer.writeFloat(patch.ctrlAt(r,c).m_texcoord[0]);
1319 writer.writeFloat(patch.ctrlAt(r,c).m_texcoord[1]);
1321 writer.writeToken(")");
1323 writer.writeToken(")");
1326 writer.writeToken(")");
1330 inline void Patch_exportFooter(const Patch& patch, TokenWriter& writer)
1332 writer.writeToken("}");
1334 writer.writeToken("}");
1338 class PatchTokenExporter : public MapExporter
1340 const Patch& m_patch;
1342 PatchTokenExporter(Patch& patch) : m_patch(patch)
1345 void exportTokens(TokenWriter& writer) const
1347 Patch_exportHeader(m_patch, writer);
1348 Patch_exportShader(m_patch, writer);
1349 Patch_exportParams(m_patch, writer);
1350 Patch_exportMatrix(m_patch, writer);
1351 Patch_exportFooter(m_patch, writer);
1355 class PatchDoom3TokenExporter : public MapExporter
1357 const Patch& m_patch;
1359 PatchDoom3TokenExporter(Patch& patch) : m_patch(patch)
1362 void exportTokens(TokenWriter& writer) const
1364 Patch_exportHeader(m_patch, writer);
1365 PatchDoom3_exportShader(m_patch, writer);
1366 Patch_exportParams(m_patch, writer);
1367 Patch_exportMatrix(m_patch, writer);
1368 Patch_exportFooter(m_patch, writer);
1372 class PatchControlInstance
1375 PatchControl* m_ctrl;
1376 ObservedSelectable m_selectable;
1378 PatchControlInstance(PatchControl* ctrl, const SelectionChangeCallback& observer)
1379 : m_ctrl(ctrl), m_selectable(observer)
1383 void testSelect(Selector& selector, SelectionTest& test)
1385 SelectionIntersection best;
1386 test.TestPoint(m_ctrl->m_vertex, best);
1389 Selector_add(selector, m_selectable, best);
1392 void snapto(float snap)
1394 vector3_snap(m_ctrl->m_vertex, snap);
1399 class PatchInstance :
1400 public Patch::Observer,
1401 public scene::Instance,
1404 public SelectionTestable,
1405 public ComponentSelectionTestable,
1406 public ComponentEditable,
1407 public ComponentSnappable,
1408 public PlaneSelectable,
1409 public LightCullable
1413 InstanceTypeCastTable m_casts;
1417 InstanceStaticCast<PatchInstance, Selectable>::install(m_casts);
1418 InstanceContainedCast<PatchInstance, Bounded>::install(m_casts);
1419 InstanceContainedCast<PatchInstance, Cullable>::install(m_casts);
1420 InstanceStaticCast<PatchInstance, Renderable>::install(m_casts);
1421 InstanceStaticCast<PatchInstance, SelectionTestable>::install(m_casts);
1422 InstanceStaticCast<PatchInstance, ComponentSelectionTestable>::install(m_casts);
1423 InstanceStaticCast<PatchInstance, ComponentEditable>::install(m_casts);
1424 InstanceStaticCast<PatchInstance, ComponentSnappable>::install(m_casts);
1425 InstanceStaticCast<PatchInstance, PlaneSelectable>::install(m_casts);
1426 InstanceIdentityCast<PatchInstance>::install(m_casts);
1427 InstanceContainedCast<PatchInstance, Transformable>::install(m_casts);
1429 InstanceTypeCastTable& get()
1437 typedef std::vector<PatchControlInstance> PatchControlInstances;
1438 PatchControlInstances m_ctrl_instances;
1440 ObservedSelectable m_selectable;
1442 DragPlanes m_dragPlanes;
1444 mutable RenderablePointVector m_render_selected;
1445 mutable AABB m_aabb_component;
1447 static Shader* m_state_selpoint;
1449 const LightList* m_lightList;
1451 TransformModifier m_transform;
1454 typedef LazyStatic<TypeCasts> StaticTypeCasts;
1456 void lightsChanged()
1458 m_lightList->lightsChanged();
1460 typedef MemberCaller<PatchInstance, &PatchInstance::lightsChanged> LightsChangedCaller;
1462 STRING_CONSTANT(Name, "PatchInstance");
1464 PatchInstance(const scene::Path& path, scene::Instance* parent, Patch& patch) :
1465 Instance(path, parent, this, StaticTypeCasts::instance().get()),
1467 m_selectable(SelectedChangedCaller(*this)),
1468 m_dragPlanes(SelectedChangedComponentCaller(*this)),
1469 m_render_selected(GL_POINTS),
1470 m_transform(Patch::TransformChangedCaller(m_patch), ApplyTransformCaller(*this))
1472 m_patch.instanceAttach(Instance::path());
1473 m_patch.attach(this);
1475 m_lightList = &GlobalShaderCache().attach(*this);
1476 m_patch.m_lightsChanged = LightsChangedCaller(*this);
1478 Instance::setTransformChangedCallback(LightsChangedCaller(*this));
1482 Instance::setTransformChangedCallback(Callback());
1484 m_patch.m_lightsChanged = Callback();
1485 GlobalShaderCache().detach(*this);
1487 m_patch.detach(this);
1488 m_patch.instanceDetach(Instance::path());
1491 void selectedChanged(const Selectable& selectable)
1493 GlobalSelectionSystem().getObserver(SelectionSystem::ePrimitive)(selectable);
1494 GlobalSelectionSystem().onSelectedChanged(*this, selectable);
1496 Instance::selectedChanged();
1498 typedef MemberCaller1<PatchInstance, const Selectable&, &PatchInstance::selectedChanged> SelectedChangedCaller;
1500 void selectedChangedComponent(const Selectable& selectable)
1502 GlobalSelectionSystem().getObserver(SelectionSystem::eComponent)(selectable);
1503 GlobalSelectionSystem().onComponentSelection(*this, selectable);
1505 typedef MemberCaller1<PatchInstance, const Selectable&, &PatchInstance::selectedChangedComponent> SelectedChangedComponentCaller;
1511 Bounded& get(NullType<Bounded>)
1515 Cullable& get(NullType<Cullable>)
1519 Transformable& get(NullType<Transformable>)
1524 static void constructStatic()
1526 m_state_selpoint = GlobalShaderCache().capture("$SELPOINT");
1529 static void destroyStatic()
1531 GlobalShaderCache().release("$SELPOINT");
1535 void allocate(std::size_t size)
1537 m_ctrl_instances.clear();
1538 m_ctrl_instances.reserve(size);
1539 for(Patch::iterator i = m_patch.begin(); i != m_patch.end(); ++i)
1541 m_ctrl_instances.push_back(PatchControlInstance(&(*i), SelectedChangedComponentCaller(*this)));
1545 void setSelected(bool select)
1547 m_selectable.setSelected(select);
1549 bool isSelected() const
1551 return m_selectable.isSelected();
1555 void update_selected() const
1557 m_render_selected.clear();
1558 Patch::iterator ctrl = m_patch.getControlPointsTransformed().begin();
1559 for(PatchControlInstances::const_iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i, ++ctrl)
1561 if((*i).m_selectable.isSelected())
1563 const Colour4b colour_selected(0, 0, 255, 255);
1564 m_render_selected.push_back(PointVertex(reinterpret_cast<Vertex3f&>((*ctrl).m_vertex), colour_selected));
1570 void render(Renderer& renderer, const VolumeTest& volume) const
1572 if(GlobalSelectionSystem().Mode() == SelectionSystem::eComponent
1573 && m_selectable.isSelected())
1575 renderer.Highlight(Renderer::eFace, false);
1577 m_patch.render(renderer, volume, localToWorld());
1579 if(GlobalSelectionSystem().ComponentMode() == SelectionSystem::eVertex)
1581 renderer.Highlight(Renderer::ePrimitive, false);
1583 m_patch.render_component(renderer, volume, localToWorld());
1585 renderComponentsSelected(renderer, volume);
1589 m_patch.render(renderer, volume, localToWorld());
1593 void renderSolid(Renderer& renderer, const VolumeTest& volume) const
1595 m_patch.evaluateTransform();
1596 renderer.setLights(*m_lightList);
1597 m_patch.render_solid(renderer, volume, localToWorld());
1599 renderComponentsSelected(renderer, volume);
1602 void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
1604 m_patch.evaluateTransform();
1605 m_patch.render_wireframe(renderer, volume, localToWorld());
1607 renderComponentsSelected(renderer, volume);
1610 void renderComponentsSelected(Renderer& renderer, const VolumeTest& volume) const
1612 m_patch.evaluateTransform();
1614 if(!m_render_selected.empty())
1616 renderer.Highlight(Renderer::ePrimitive, false);
1617 renderer.SetState(m_state_selpoint, Renderer::eWireframeOnly);
1618 renderer.SetState(m_state_selpoint, Renderer::eFullMaterials);
1619 renderer.addRenderable(m_render_selected, localToWorld());
1622 void renderComponents(Renderer& renderer, const VolumeTest& volume) const
1624 m_patch.evaluateTransform();
1625 if(GlobalSelectionSystem().ComponentMode() == SelectionSystem::eVertex)
1627 m_patch.render_component(renderer, volume, localToWorld());
1631 void testSelect(Selector& selector, SelectionTest& test)
1633 test.BeginMesh(localToWorld(), true);
1634 m_patch.testSelect(selector, test);
1637 void selectCtrl(bool select)
1639 for(PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1641 (*i).m_selectable.setSelected(select);
1644 bool isSelectedComponents() const
1646 for(PatchControlInstances::const_iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1648 if((*i).m_selectable.isSelected())
1655 void setSelectedComponents(bool select, SelectionSystem::EComponentMode mode)
1657 if(mode == SelectionSystem::eVertex)
1661 else if(mode == SelectionSystem::eFace)
1663 m_dragPlanes.setSelected(select);
1666 const AABB& getSelectedComponentsBounds() const
1668 m_aabb_component = AABB();
1670 for(PatchControlInstances::const_iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1672 if((*i).m_selectable.isSelected())
1674 aabb_extend_by_point_safe(m_aabb_component, (*i).m_ctrl->m_vertex);
1678 return m_aabb_component;
1681 void testSelectComponents(Selector& selector, SelectionTest& test, SelectionSystem::EComponentMode mode)
1683 test.BeginMesh(localToWorld());
1687 case SelectionSystem::eVertex:
1689 for(PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1691 (*i).testSelect(selector, test);
1700 bool selectedVertices()
1702 for(PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1704 if((*i).m_selectable.isSelected())
1712 void transformComponents(const Matrix4& matrix)
1714 if(selectedVertices())
1716 PatchControlIter ctrl = m_patch.getControlPointsTransformed().begin();
1717 for(PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i, ++ctrl)
1719 if((*i).m_selectable.isSelected())
1721 matrix4_transform_point(matrix, (*ctrl).m_vertex);
1724 m_patch.UpdateCachedData();
1727 if(m_dragPlanes.isSelected()) // this should only be true when the transform is a pure translation.
1729 m_patch.transform(m_dragPlanes.evaluateTransform(vector4_to_vector3(matrix.t())));
1734 void selectPlanes(Selector& selector, SelectionTest& test, const PlaneCallback& selectedPlaneCallback)
1736 test.BeginMesh(localToWorld());
1738 m_dragPlanes.selectPlanes(m_patch.localAABB(), selector, test, selectedPlaneCallback);
1740 void selectReversedPlanes(Selector& selector, const SelectedPlanes& selectedPlanes)
1742 m_dragPlanes.selectReversedPlanes(m_patch.localAABB(), selector, selectedPlanes);
1746 void snapComponents(float snap)
1748 if(selectedVertices())
1751 for(PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1753 if((*i).m_selectable.isSelected())
1758 m_patch.controlPointsChanged();
1762 void evaluateTransform()
1764 Matrix4 matrix(m_transform.calculateTransform());
1766 if(m_transform.getType() == TRANSFORM_PRIMITIVE)
1768 m_patch.transform(matrix);
1772 transformComponents(matrix);
1775 void applyTransform()
1777 m_patch.revertTransform();
1778 evaluateTransform();
1779 m_patch.freezeTransform();
1781 typedef MemberCaller<PatchInstance, &PatchInstance::applyTransform> ApplyTransformCaller;
1784 bool testLight(const RendererLight& light) const
1786 return light.testAABB(worldAABB());
1791 template<typename TokenImporter, typename TokenExporter>
1793 public scene::Node::Symbiot,
1794 public scene::Instantiable,
1795 public scene::Cloneable
1797 typedef PatchNode<TokenImporter, TokenExporter> Self;
1801 InstanceTypeCastTable m_casts;
1805 NodeStaticCast<PatchNode, scene::Instantiable>::install(m_casts);
1806 NodeStaticCast<PatchNode, scene::Cloneable>::install(m_casts);
1807 NodeContainedCast<PatchNode, Snappable>::install(m_casts);
1808 NodeContainedCast<PatchNode, TransformNode>::install(m_casts);
1809 NodeContainedCast<PatchNode, Patch>::install(m_casts);
1810 NodeContainedCast<PatchNode, XMLImporter>::install(m_casts);
1811 NodeContainedCast<PatchNode, XMLExporter>::install(m_casts);
1812 NodeContainedCast<PatchNode, MapImporter>::install(m_casts);
1813 NodeContainedCast<PatchNode, MapExporter>::install(m_casts);
1814 NodeContainedCast<PatchNode, Nameable>::install(m_casts);
1816 InstanceTypeCastTable& get()
1824 InstanceSet m_instances;
1826 TokenImporter m_importMap;
1827 TokenExporter m_exportMap;
1831 typedef LazyStatic<TypeCasts> StaticTypeCasts;
1833 Snappable& get(NullType<Snappable>)
1837 TransformNode& get(NullType<TransformNode>)
1841 Patch& get(NullType<Patch>)
1845 XMLImporter& get(NullType<XMLImporter>)
1849 XMLExporter& get(NullType<XMLExporter>)
1853 MapImporter& get(NullType<MapImporter>)
1857 MapExporter& get(NullType<MapExporter>)
1861 Nameable& get(NullType<Nameable>)
1866 PatchNode(bool patchDef3 = false) :
1867 m_node(this, this, StaticTypeCasts::instance().get()),
1868 m_patch(m_node, InstanceSetEvaluateTransform<PatchInstance>::Caller(m_instances), InstanceSet::BoundsChangedCaller(m_instances)),
1869 m_importMap(m_patch),
1870 m_exportMap(m_patch)
1872 m_patch.m_patchDef3 = patchDef3;
1874 PatchNode(const PatchNode& other) :
1875 scene::Node::Symbiot(other),
1876 scene::Instantiable(other),
1877 scene::Cloneable(other),
1878 m_node(this, this, StaticTypeCasts::instance().get()),
1879 m_patch(other.m_patch, m_node, InstanceSetEvaluateTransform<PatchInstance>::Caller(m_instances), InstanceSet::BoundsChangedCaller(m_instances)),
1880 m_importMap(m_patch),
1881 m_exportMap(m_patch)
1896 const Patch& get() const
1901 scene::Node& clone() const
1903 return (new PatchNode(*this))->node();
1906 scene::Instance* create(const scene::Path& path, scene::Instance* parent)
1908 return new PatchInstance(path, parent, m_patch);
1910 void forEachInstance(const scene::Instantiable::Visitor& visitor)
1912 m_instances.forEachInstance(visitor);
1914 void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
1916 m_instances.insert(observer, path, instance);
1918 scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
1920 return m_instances.erase(observer, path);
1926 typedef PatchNode<PatchTokenImporter, PatchTokenExporter> PatchNodeQuake3;
1927 typedef PatchNode<PatchDoom3TokenImporter, PatchDoom3TokenExporter> PatchNodeDoom3;
1929 inline Patch* Node_getPatch(scene::Node& node)
1931 return NodeTypeCast<Patch>::cast(node);
1934 inline PatchInstance* Instance_getPatch(scene::Instance& instance)
1936 return InstanceTypeCast<PatchInstance>::cast(instance);
1939 template<typename Functor>
1940 class PatchSelectedVisitor : public SelectionSystem::Visitor
1942 const Functor& m_functor;
1944 PatchSelectedVisitor(const Functor& functor) : m_functor(functor)
1947 void visit(scene::Instance& instance) const
1949 PatchInstance* patch = Instance_getPatch(instance);
1957 template<typename Functor>
1958 inline void Scene_forEachSelectedPatch(const Functor& functor)
1960 GlobalSelectionSystem().foreachSelected(PatchSelectedVisitor<Functor>(functor));
1964 template<typename Functor>
1965 class PatchVisibleSelectedVisitor : public SelectionSystem::Visitor
1967 const Functor& m_functor;
1969 PatchVisibleSelectedVisitor(const Functor& functor) : m_functor(functor)
1972 void visit(scene::Instance& instance) const
1974 PatchInstance* patch = Instance_getPatch(instance);
1976 && instance.path().top().get().visible())
1983 template<typename Functor>
1984 inline void Scene_forEachVisibleSelectedPatchInstance(const Functor& functor)
1986 GlobalSelectionSystem().foreachSelected(PatchVisibleSelectedVisitor<Functor>(functor));
1989 template<typename Functor>
1990 class PatchForEachWalker : public scene::Graph::Walker
1992 const Functor& m_functor;
1994 PatchForEachWalker(const Functor& functor) : m_functor(functor)
1997 bool pre(const scene::Path& path, scene::Instance& instance) const
1999 if(path.top().get().visible())
2001 Patch* patch = Node_getPatch(path.top());
2011 template<typename Functor>
2012 inline void Scene_forEachVisiblePatch(const Functor& functor)
2014 GlobalSceneGraph().traverse(PatchForEachWalker<Functor>(functor));
2017 template<typename Functor>
2018 class PatchForEachSelectedWalker : public scene::Graph::Walker
2020 const Functor& m_functor;
2022 PatchForEachSelectedWalker(const Functor& functor) : m_functor(functor)
2025 bool pre(const scene::Path& path, scene::Instance& instance) const
2027 if(path.top().get().visible())
2029 Patch* patch = Node_getPatch(path.top());
2031 && Instance_getSelectable(instance)->isSelected())
2040 template<typename Functor>
2041 inline void Scene_forEachVisibleSelectedPatch(const Functor& functor)
2043 GlobalSceneGraph().traverse(PatchForEachSelectedWalker<Functor>(functor));
2046 template<typename Functor>
2047 class PatchForEachInstanceWalker : public scene::Graph::Walker
2049 const Functor& m_functor;
2051 PatchForEachInstanceWalker(const Functor& functor) : m_functor(functor)
2054 bool pre(const scene::Path& path, scene::Instance& instance) const
2056 if(path.top().get().visible())
2058 PatchInstance* patch = Instance_getPatch(instance);
2068 template<typename Functor>
2069 inline void Scene_forEachVisiblePatchInstance(const Functor& functor)
2071 GlobalSceneGraph().traverse(PatchForEachInstanceWalker<Functor>(functor));