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),
541 m_undoable_observer(0),
543 m_render_solid(m_tess),
544 m_render_wireframe(m_tess),
545 m_render_wireframe_fixed(m_tess),
546 m_render_ctrl(GL_POINTS, m_ctrl_vertices),
547 m_render_lattice(GL_LINES, m_lattice_indices, m_ctrl_vertices),
548 m_transformChanged(false),
549 m_evaluateTransform(other.m_evaluateTransform),
550 m_boundsChanged(other.m_boundsChanged)
554 m_patchDef3 = other.m_patchDef3;
555 m_subdivisions_x = other.m_subdivisions_x;
556 m_subdivisions_y = other.m_subdivisions_y;
557 setDims(other.m_width, other.m_height);
558 copy_ctrl(m_ctrl.data(), other.m_ctrl.data(), other.m_ctrl.data()+(m_width*m_height));
559 SetShader(other.m_shader.c_str());
560 controlPointsChanged();
565 BezierCurveTreeArray_deleteAll(m_tess.m_curveTreeU);
566 BezierCurveTreeArray_deleteAll(m_tess.m_curveTreeV);
570 ASSERT_MESSAGE(m_observers.empty(), "Patch::~Patch: observers still attached");
573 InstanceCounter m_instanceCounter;
574 void instanceAttach(const scene::Path& path)
576 if(++m_instanceCounter.m_count == 1)
578 m_state->incrementUsed();
579 m_map = path_find_mapfile(path.begin(), path.end());
580 m_undoable_observer = GlobalUndoSystem().observer(this);
581 GlobalFilterSystem().registerFilterable(*this);
585 ASSERT_MESSAGE(path_find_mapfile(path.begin(), path.end()) == m_map, "node is instanced across more than one file");
588 void instanceDetach(const scene::Path& path)
590 if(--m_instanceCounter.m_count == 0)
593 m_undoable_observer = 0;
594 GlobalUndoSystem().release(this);
595 GlobalFilterSystem().unregisterFilterable(*this);
596 m_state->decrementUsed();
600 const char* name() const
604 void attach(const NameCallback& callback)
607 void detach(const NameCallback& callback)
611 void attach(Observer* observer)
613 observer->allocate(m_width * m_height);
615 m_observers.insert(observer);
617 void detach(Observer* observer)
619 m_observers.erase(observer);
622 void updateFiltered()
626 if(patch_filtered(*this))
628 m_node->enable(scene::Node::eFiltered);
632 m_node->disable(scene::Node::eFiltered);
637 void onAllocate(std::size_t size)
639 for(Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i)
641 (*i)->allocate(size);
645 const Matrix4& localToParent() const
647 return g_matrix4_identity;
649 const AABB& localAABB() const
653 VolumeIntersectionValue intersectVolume(const VolumeTest& test, const Matrix4& localToWorld) const
655 return test.TestAABB(m_aabb_local, localToWorld);
657 void render_solid(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
659 renderer.SetState(m_state, Renderer::eFullMaterials);
660 renderer.addRenderable(m_render_solid, localToWorld);
662 void render_wireframe(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
664 renderer.SetState(m_state, Renderer::eFullMaterials);
667 renderer.addRenderable(m_render_wireframe_fixed, localToWorld);
671 renderer.addRenderable(m_render_wireframe, localToWorld);
675 void render_component(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
677 renderer.SetState(m_state_lattice, Renderer::eWireframeOnly);
678 renderer.SetState(m_state_lattice, Renderer::eFullMaterials);
679 renderer.addRenderable(m_render_lattice, localToWorld);
681 renderer.SetState(m_state_ctrl, Renderer::eWireframeOnly);
682 renderer.SetState(m_state_ctrl, Renderer::eFullMaterials);
683 renderer.addRenderable(m_render_ctrl, localToWorld);
685 void testSelect(Selector& selector, SelectionTest& test)
687 SelectionIntersection best;
688 IndexPointer::index_type* pIndex = m_tess.m_indices.data();
689 for(std::size_t s=0; s<m_tess.m_numStrips; s++)
691 test.TestQuadStrip(vertexpointer_arbitrarymeshvertex(m_tess.m_vertices.data()), IndexPointer(pIndex, m_tess.m_lenStrips), best);
692 pIndex += m_tess.m_lenStrips;
696 selector.addIntersection(best);
699 void transform(const Matrix4& matrix)
701 for(PatchControlIter i = m_ctrlTransformed.data(); i != m_ctrlTransformed.data() + m_ctrlTransformed.size(); ++i)
703 matrix4_transform_point(matrix, (*i).m_vertex);
706 if(matrix4_handedness(matrix) == MATRIX4_LEFTHANDED)
708 PatchControlArray_invert(m_ctrlTransformed, m_width, m_height);
712 void transformChanged()
714 m_transformChanged = true;
718 typedef MemberCaller<Patch, &Patch::transformChanged> TransformChangedCaller;
720 void evaluateTransform()
722 if(m_transformChanged)
724 m_transformChanged = false;
726 m_evaluateTransform();
730 void revertTransform()
732 m_ctrlTransformed = m_ctrl;
734 void freezeTransform()
738 ASSERT_MESSAGE(m_ctrlTransformed.size() == m_ctrl.size(), "Patch::freeze: size mismatch");
739 std::copy(m_ctrlTransformed.begin(), m_ctrlTransformed.end(), m_ctrl.begin());
742 void controlPointsChanged()
748 bool isValid() const;
750 void snapto(float snap)
754 for(PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i)
756 vector3_snap((*i).m_vertex, snap);
759 controlPointsChanged();
765 void RenderDebug(RenderStateFlags state) const;
766 void RenderNormals(RenderStateFlags state) const;
768 void pushElement(const XMLElement& element)
770 switch(m_xml_state.back().state())
772 case xml_state_t::eDefault:
773 ASSERT_MESSAGE(string_equal(element.name(), "patch"), "parse error");
774 m_xml_state.push_back(xml_state_t::ePatch);
776 case xml_state_t::ePatch:
777 if(string_equal(element.name(), "matrix"))
779 setDims(atoi(element.attribute("width")), atoi(element.attribute("height")));
780 m_xml_state.push_back(xml_state_t::eMatrix);
782 else if(string_equal(element.name(), "shader"))
784 m_xml_state.push_back(xml_state_t::eShader);
788 ERROR_MESSAGE("parse error");
792 void popElement(const char* name)
794 switch(m_xml_state.back().state())
796 case xml_state_t::eDefault:
797 ERROR_MESSAGE("parse error");
799 case xml_state_t::ePatch:
801 case xml_state_t::eMatrix:
803 StringTokeniser content(m_xml_state.back().content());
805 for(PatchControlIter i = m_ctrl.data(), end = m_ctrl.data() + m_ctrl.size(); i != end; ++i)
807 (*i).m_vertex[0] = string_read_float(content.getToken());
808 (*i).m_vertex[1] = string_read_float(content.getToken());
809 (*i).m_vertex[2] = string_read_float(content.getToken());
810 (*i).m_texcoord[0] = string_read_float(content.getToken());
811 (*i).m_texcoord[1] = string_read_float(content.getToken());
813 controlPointsChanged();
816 case xml_state_t::eShader:
818 SetShader(m_xml_state.back().content());
822 ERROR_MESSAGE("parse error");
825 ASSERT_MESSAGE(!m_xml_state.empty(), "popping empty stack");
826 m_xml_state.pop_back();
828 std::size_t write(const char* buffer, std::size_t length)
830 switch(m_xml_state.back().state())
832 case xml_state_t::eDefault:
834 case xml_state_t::ePatch:
836 case xml_state_t::eMatrix:
837 case xml_state_t::eShader:
838 return m_xml_state.back().write(buffer, length);
841 ERROR_MESSAGE("parse error");
846 void exportXML(XMLImporter& importer)
848 StaticElement patchElement("patch");
849 importer.pushElement(patchElement);
852 const StaticElement element("shader");
853 importer.pushElement(element);
854 importer.write(m_shader.c_str(), strlen(m_shader.c_str()));
855 importer.popElement(element.name());
859 char width[16], height[16];
860 sprintf(width, "%u", Unsigned(m_width));
861 sprintf(height, "%u", Unsigned(m_height));
862 StaticElement element("matrix");
863 element.insertAttribute("width", width);
864 element.insertAttribute("height", height);
866 importer.pushElement(element);
868 for(PatchControlIter i = m_ctrl.data(), end = m_ctrl.data() + m_ctrl.size(); i != end; ++i)
870 importer << (*i).m_vertex[0]
871 << ' ' << (*i).m_vertex[1]
872 << ' ' << (*i).m_vertex[2]
873 << ' ' << (*i).m_texcoord[0]
874 << ' ' << (*i).m_texcoord[1];
877 importer.popElement(element.name());
880 importer.popElement(patchElement.name());
883 void UpdateCachedData();
885 const char *GetShader() const
887 return m_shader.c_str();
889 void SetShader(const char* name)
891 ASSERT_NOTNULL(name);
893 if(shader_equal(m_shader.c_str(), name))
898 if(m_instanceCounter.m_count != 0)
900 m_state->decrementUsed();
905 if(m_instanceCounter.m_count != 0)
907 m_state->incrementUsed();
911 Patch_textureChanged();
913 int getShaderFlags() const
917 return m_state->getFlags();
922 typedef PatchControl* iterator;
923 typedef const PatchControl* const_iterator;
927 return m_ctrl.data();
929 const_iterator begin() const
931 return m_ctrl.data();
935 return m_ctrl.data() + m_ctrl.size();
937 const_iterator end() const
939 return m_ctrl.data() + m_ctrl.size();
942 PatchControlArray& getControlPoints()
946 PatchControlArray& getControlPointsTransformed()
948 return m_ctrlTransformed;
951 void setDims (std::size_t w, std::size_t h);
952 std::size_t getWidth() const
956 std::size_t getHeight() const
960 PatchControl& ctrlAt(std::size_t row, std::size_t col)
962 return m_ctrl[row*m_width+col];
964 const PatchControl& ctrlAt(std::size_t row, std::size_t col) const
966 return m_ctrl[row*m_width+col];
969 void ConstructPrefab(const AABB& aabb, EPatchPrefab eType, int axis, std::size_t width = 3, std::size_t height = 3);
970 void constructPlane(const AABB& aabb, int axis, std::size_t width, std::size_t height);
972 void TransposeMatrix();
973 void Redisperse(EMatrixMajor mt);
974 void InsertRemove(bool bInsert, bool bColumn, bool bFirst);
975 Patch* MakeCap(Patch* patch, EPatchCap eType, EMatrixMajor mt, bool bFirst);
976 void ConstructSeam(EPatchCap eType, Vector3* p, std::size_t width);
978 void FlipTexture(int nAxis);
979 void TranslateTexture(float s, float t);
980 void ScaleTexture(float s, float t);
981 void RotateTexture(float angle);
982 void SetTextureRepeat(float s, float t); // call with s=1 t=1 for FIT
984 void NaturalTexture();
985 void ProjectTexture(int nAxis);
993 if(m_undoable_observer != 0)
995 m_undoable_observer->save(this);
999 UndoMemento* exportState() const
1001 return new SavedState(m_width, m_height, m_ctrl, m_shader.c_str(), m_patchDef3, m_subdivisions_x, m_subdivisions_y);
1003 void importState(const UndoMemento* state)
1007 const SavedState& other = *(static_cast<const SavedState*>(state));
1009 // begin duplicate of SavedState copy constructor, needs refactoring
1013 m_width = other.m_width;
1014 m_height = other.m_height;
1015 SetShader(other.m_shader.c_str());
1016 m_ctrl = other.m_ctrl;
1017 onAllocate(m_ctrl.size());
1018 m_patchDef3 = other.m_patchDef3;
1019 m_subdivisions_x = other.m_subdivisions_x;
1020 m_subdivisions_y = other.m_subdivisions_y;
1023 // end duplicate code
1025 Patch_textureChanged();
1027 controlPointsChanged();
1030 static void constructStatic(EPatchType type)
1032 Patch::m_type = type;
1033 Patch::m_state_ctrl = GlobalShaderCache().capture("$POINT");
1034 Patch::m_state_lattice = GlobalShaderCache().capture("$LATTICE");
1037 static void destroyStatic()
1039 GlobalShaderCache().release("$LATTICE");
1040 GlobalShaderCache().release("$POINT");
1043 void captureShader()
1045 m_state = GlobalShaderCache().capture(m_shader.c_str());
1048 void releaseShader()
1050 GlobalShaderCache().release(m_shader.c_str());
1055 if(!shader_valid(GetShader()))
1057 globalErrorStream() << "patch has invalid texture name: '" << GetShader() << "'\n";
1061 void InsertPoints(EMatrixMajor mt, bool bFirst);
1062 void RemovePoints(EMatrixMajor mt, bool bFirst);
1064 void AccumulateBBox();
1066 void TesselateSubMatrixFixed(ArbitraryMeshVertex* vertices, std::size_t strideX, std::size_t strideY, unsigned int nFlagsX, unsigned int nFlagsY, PatchControl* subMatrix[3][3]);
1068 // uses binary trees representing bezier curves to recursively tesselate a bezier sub-patch
1069 void TesselateSubMatrix( const BezierCurveTree *BX, const BezierCurveTree *BY,
1070 std::size_t offStartX, std::size_t offStartY,
1071 std::size_t offEndX, std::size_t offEndY,
1072 std::size_t nFlagsX, std::size_t nFlagsY,
1073 Vector3& left, Vector3& mid, Vector3& right,
1074 Vector2& texLeft, Vector2& texMid, Vector2& texRight,
1077 // tesselates the entire surface
1078 void BuildTesselationCurves(EMatrixMajor major);
1079 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);
1080 void BuildVertexArray();
1083 inline bool Patch_importHeader(Patch& patch, Tokeniser& tokeniser)
1085 tokeniser.nextLine();
1086 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "{"));
1090 inline bool Patch_importShader(Patch& patch, Tokeniser& tokeniser)
1092 // parse shader name
1093 tokeniser.nextLine();
1094 const char* texture = tokeniser.getToken();
1097 Tokeniser_unexpectedError(tokeniser, texture, "#texture-name");
1100 if(string_equal(texture, "NULL"))
1102 patch.SetShader(texdef_name_default());
1106 StringOutputStream shader(string_length(GlobalTexturePrefix_get()) + string_length(texture));
1107 shader << GlobalTexturePrefix_get() << texture;
1108 patch.SetShader(shader.c_str());
1113 inline bool PatchDoom3_importShader(Patch& patch, Tokeniser& tokeniser)
1115 // parse shader name
1116 tokeniser.nextLine();
1117 const char *shader = tokeniser.getToken();
1120 Tokeniser_unexpectedError(tokeniser, shader, "#shader-name");
1123 if(string_equal(shader, "_emptyname"))
1125 shader = texdef_name_default();
1127 patch.SetShader(shader);
1131 inline bool Patch_importParams(Patch& patch, Tokeniser& tokeniser)
1133 tokeniser.nextLine();
1134 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
1136 // parse matrix dimensions
1139 RETURN_FALSE_IF_FAIL(Tokeniser_getSize(tokeniser, c));
1140 RETURN_FALSE_IF_FAIL(Tokeniser_getSize(tokeniser, r));
1142 patch.setDims(c, r);
1145 if(patch.m_patchDef3)
1147 RETURN_FALSE_IF_FAIL(Tokeniser_getSize(tokeniser, patch.m_subdivisions_x));
1148 RETURN_FALSE_IF_FAIL(Tokeniser_getSize(tokeniser, patch.m_subdivisions_y));
1151 // ignore contents/flags/value
1153 RETURN_FALSE_IF_FAIL(Tokeniser_getInteger(tokeniser, tmp));
1154 RETURN_FALSE_IF_FAIL(Tokeniser_getInteger(tokeniser, tmp));
1155 RETURN_FALSE_IF_FAIL(Tokeniser_getInteger(tokeniser, tmp));
1157 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
1161 inline bool Patch_importMatrix(Patch& patch, Tokeniser& tokeniser)
1164 tokeniser.nextLine();
1165 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
1167 for(std::size_t c=0; c<patch.getWidth(); c++)
1169 tokeniser.nextLine();
1170 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
1171 for(std::size_t r=0; r<patch.getHeight(); r++)
1173 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
1175 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r,c).m_vertex[0]));
1176 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r,c).m_vertex[1]));
1177 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r,c).m_vertex[2]));
1178 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r,c).m_texcoord[0]));
1179 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r,c).m_texcoord[1]));
1181 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
1183 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
1186 tokeniser.nextLine();
1187 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
1191 inline bool Patch_importFooter(Patch& patch, Tokeniser& tokeniser)
1193 patch.controlPointsChanged();
1195 tokeniser.nextLine();
1196 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "}"));
1198 tokeniser.nextLine();
1199 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "}"));
1203 class PatchTokenImporter : public MapImporter
1207 PatchTokenImporter(Patch& patch) : m_patch(patch)
1210 bool importTokens(Tokeniser& tokeniser)
1212 RETURN_FALSE_IF_FAIL(Patch_importHeader(m_patch, tokeniser));
1213 RETURN_FALSE_IF_FAIL(Patch_importShader(m_patch, tokeniser));
1214 RETURN_FALSE_IF_FAIL(Patch_importParams(m_patch, tokeniser));
1215 RETURN_FALSE_IF_FAIL(Patch_importMatrix(m_patch, tokeniser));
1216 RETURN_FALSE_IF_FAIL(Patch_importFooter(m_patch, tokeniser));
1222 class PatchDoom3TokenImporter : public MapImporter
1226 PatchDoom3TokenImporter(Patch& patch) : m_patch(patch)
1229 bool importTokens(Tokeniser& tokeniser)
1231 RETURN_FALSE_IF_FAIL(Patch_importHeader(m_patch, tokeniser));
1232 RETURN_FALSE_IF_FAIL(PatchDoom3_importShader(m_patch, tokeniser));
1233 RETURN_FALSE_IF_FAIL(Patch_importParams(m_patch, tokeniser));
1234 RETURN_FALSE_IF_FAIL(Patch_importMatrix(m_patch, tokeniser));
1235 RETURN_FALSE_IF_FAIL(Patch_importFooter(m_patch, tokeniser));
1241 inline void Patch_exportHeader(const Patch& patch, TokenWriter& writer)
1243 writer.writeToken("{");
1245 writer.writeToken(patch.m_patchDef3 ? "patchDef3" : "patchDef2");
1247 writer.writeToken("{");
1251 inline void Patch_exportShader(const Patch& patch, TokenWriter& writer)
1253 // write shader name
1254 if(*(shader_get_textureName(patch.GetShader())) == '\0')
1256 writer.writeToken("NULL");
1260 writer.writeToken(shader_get_textureName(patch.GetShader()));
1265 inline void PatchDoom3_exportShader(const Patch& patch, TokenWriter& writer)
1267 // write shader name
1268 if(*(shader_get_textureName(patch.GetShader())) == '\0')
1270 writer.writeString("_emptyname");
1274 writer.writeString(patch.GetShader());
1279 inline void Patch_exportParams(const Patch& patch, TokenWriter& writer)
1281 // write matrix dimensions
1282 writer.writeToken("(");
1283 writer.writeUnsigned(patch.getWidth());
1284 writer.writeUnsigned(patch.getHeight());
1285 if(patch.m_patchDef3)
1287 writer.writeUnsigned(patch.m_subdivisions_x);
1288 writer.writeUnsigned(patch.m_subdivisions_y);
1290 writer.writeInteger(0);
1291 writer.writeInteger(0);
1292 writer.writeInteger(0);
1293 writer.writeToken(")");
1297 inline void Patch_exportMatrix(const Patch& patch, TokenWriter& writer)
1300 writer.writeToken("(");
1302 for(std::size_t c=0; c<patch.getWidth(); c++)
1304 writer.writeToken("(");
1305 for(std::size_t r=0; r<patch.getHeight(); r++)
1307 writer.writeToken("(");
1309 writer.writeFloat(patch.ctrlAt(r,c).m_vertex[0]);
1310 writer.writeFloat(patch.ctrlAt(r,c).m_vertex[1]);
1311 writer.writeFloat(patch.ctrlAt(r,c).m_vertex[2]);
1312 writer.writeFloat(patch.ctrlAt(r,c).m_texcoord[0]);
1313 writer.writeFloat(patch.ctrlAt(r,c).m_texcoord[1]);
1315 writer.writeToken(")");
1317 writer.writeToken(")");
1320 writer.writeToken(")");
1324 inline void Patch_exportFooter(const Patch& patch, TokenWriter& writer)
1326 writer.writeToken("}");
1328 writer.writeToken("}");
1332 class PatchTokenExporter : public MapExporter
1334 const Patch& m_patch;
1336 PatchTokenExporter(Patch& patch) : m_patch(patch)
1339 void exportTokens(TokenWriter& writer) const
1341 Patch_exportHeader(m_patch, writer);
1342 Patch_exportShader(m_patch, writer);
1343 Patch_exportParams(m_patch, writer);
1344 Patch_exportMatrix(m_patch, writer);
1345 Patch_exportFooter(m_patch, writer);
1349 class PatchDoom3TokenExporter : public MapExporter
1351 const Patch& m_patch;
1353 PatchDoom3TokenExporter(Patch& patch) : m_patch(patch)
1356 void exportTokens(TokenWriter& writer) const
1358 Patch_exportHeader(m_patch, writer);
1359 PatchDoom3_exportShader(m_patch, writer);
1360 Patch_exportParams(m_patch, writer);
1361 Patch_exportMatrix(m_patch, writer);
1362 Patch_exportFooter(m_patch, writer);
1366 class PatchControlInstance
1369 PatchControl* m_ctrl;
1370 ObservedSelectable m_selectable;
1372 PatchControlInstance(PatchControl* ctrl, const SelectionChangeCallback& observer)
1373 : m_ctrl(ctrl), m_selectable(observer)
1377 void testSelect(Selector& selector, SelectionTest& test)
1379 SelectionIntersection best;
1380 test.TestPoint(m_ctrl->m_vertex, best);
1383 Selector_add(selector, m_selectable, best);
1386 void snapto(float snap)
1388 vector3_snap(m_ctrl->m_vertex, snap);
1393 class PatchInstance :
1394 public Patch::Observer,
1395 public scene::Instance,
1398 public SelectionTestable,
1399 public ComponentSelectionTestable,
1400 public ComponentEditable,
1401 public ComponentSnappable,
1402 public PlaneSelectable,
1403 public LightCullable
1407 InstanceTypeCastTable m_casts;
1411 InstanceStaticCast<PatchInstance, Selectable>::install(m_casts);
1412 InstanceContainedCast<PatchInstance, Bounded>::install(m_casts);
1413 InstanceContainedCast<PatchInstance, Cullable>::install(m_casts);
1414 InstanceStaticCast<PatchInstance, Renderable>::install(m_casts);
1415 InstanceStaticCast<PatchInstance, SelectionTestable>::install(m_casts);
1416 InstanceStaticCast<PatchInstance, ComponentSelectionTestable>::install(m_casts);
1417 InstanceStaticCast<PatchInstance, ComponentEditable>::install(m_casts);
1418 InstanceStaticCast<PatchInstance, ComponentSnappable>::install(m_casts);
1419 InstanceStaticCast<PatchInstance, PlaneSelectable>::install(m_casts);
1420 InstanceIdentityCast<PatchInstance>::install(m_casts);
1421 InstanceContainedCast<PatchInstance, Transformable>::install(m_casts);
1423 InstanceTypeCastTable& get()
1431 typedef std::vector<PatchControlInstance> PatchControlInstances;
1432 PatchControlInstances m_ctrl_instances;
1434 ObservedSelectable m_selectable;
1436 DragPlanes m_dragPlanes;
1438 mutable RenderablePointVector m_render_selected;
1439 mutable AABB m_aabb_component;
1441 static Shader* m_state_selpoint;
1443 const LightList* m_lightList;
1445 TransformModifier m_transform;
1448 typedef LazyStatic<TypeCasts> StaticTypeCasts;
1450 void lightsChanged()
1452 m_lightList->lightsChanged();
1454 typedef MemberCaller<PatchInstance, &PatchInstance::lightsChanged> LightsChangedCaller;
1456 STRING_CONSTANT(Name, "PatchInstance");
1458 PatchInstance(const scene::Path& path, scene::Instance* parent, Patch& patch) :
1459 Instance(path, parent, this, StaticTypeCasts::instance().get()),
1461 m_selectable(SelectedChangedCaller(*this)),
1462 m_dragPlanes(SelectedChangedComponentCaller(*this)),
1463 m_render_selected(GL_POINTS),
1464 m_transform(Patch::TransformChangedCaller(m_patch), ApplyTransformCaller(*this))
1466 m_patch.instanceAttach(Instance::path());
1467 m_patch.attach(this);
1469 m_lightList = &GlobalShaderCache().attach(*this);
1470 m_patch.m_lightsChanged = LightsChangedCaller(*this);
1472 Instance::setTransformChangedCallback(LightsChangedCaller(*this));
1476 Instance::setTransformChangedCallback(Callback());
1478 m_patch.m_lightsChanged = Callback();
1479 GlobalShaderCache().detach(*this);
1481 m_patch.detach(this);
1482 m_patch.instanceDetach(Instance::path());
1485 void selectedChanged(const Selectable& selectable)
1487 GlobalSelectionSystem().getObserver(SelectionSystem::ePrimitive)(selectable);
1488 GlobalSelectionSystem().onSelectedChanged(*this, selectable);
1490 Instance::selectedChanged();
1492 typedef MemberCaller1<PatchInstance, const Selectable&, &PatchInstance::selectedChanged> SelectedChangedCaller;
1494 void selectedChangedComponent(const Selectable& selectable)
1496 GlobalSelectionSystem().getObserver(SelectionSystem::eComponent)(selectable);
1497 GlobalSelectionSystem().onComponentSelection(*this, selectable);
1499 typedef MemberCaller1<PatchInstance, const Selectable&, &PatchInstance::selectedChangedComponent> SelectedChangedComponentCaller;
1505 Bounded& get(NullType<Bounded>)
1509 Cullable& get(NullType<Cullable>)
1513 Transformable& get(NullType<Transformable>)
1518 static void constructStatic()
1520 m_state_selpoint = GlobalShaderCache().capture("$SELPOINT");
1523 static void destroyStatic()
1525 GlobalShaderCache().release("$SELPOINT");
1529 void allocate(std::size_t size)
1531 m_ctrl_instances.clear();
1532 m_ctrl_instances.reserve(size);
1533 for(Patch::iterator i = m_patch.begin(); i != m_patch.end(); ++i)
1535 m_ctrl_instances.push_back(PatchControlInstance(&(*i), SelectedChangedComponentCaller(*this)));
1539 void setSelected(bool select)
1541 m_selectable.setSelected(select);
1543 bool isSelected() const
1545 return m_selectable.isSelected();
1549 void update_selected() const
1551 m_render_selected.clear();
1552 Patch::iterator ctrl = m_patch.getControlPointsTransformed().begin();
1553 for(PatchControlInstances::const_iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i, ++ctrl)
1555 if((*i).m_selectable.isSelected())
1557 const Colour4b colour_selected(0, 0, 255, 255);
1558 m_render_selected.push_back(PointVertex(reinterpret_cast<Vertex3f&>((*ctrl).m_vertex), colour_selected));
1564 void render(Renderer& renderer, const VolumeTest& volume) const
1566 if(GlobalSelectionSystem().Mode() == SelectionSystem::eComponent
1567 && m_selectable.isSelected())
1569 renderer.Highlight(Renderer::eFace, false);
1571 m_patch.render(renderer, volume, localToWorld());
1573 if(GlobalSelectionSystem().ComponentMode() == SelectionSystem::eVertex)
1575 renderer.Highlight(Renderer::ePrimitive, false);
1577 m_patch.render_component(renderer, volume, localToWorld());
1579 renderComponentsSelected(renderer, volume);
1583 m_patch.render(renderer, volume, localToWorld());
1587 void renderSolid(Renderer& renderer, const VolumeTest& volume) const
1589 m_patch.evaluateTransform();
1590 renderer.setLights(*m_lightList);
1591 m_patch.render_solid(renderer, volume, localToWorld());
1593 renderComponentsSelected(renderer, volume);
1596 void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
1598 m_patch.evaluateTransform();
1599 m_patch.render_wireframe(renderer, volume, localToWorld());
1601 renderComponentsSelected(renderer, volume);
1604 void renderComponentsSelected(Renderer& renderer, const VolumeTest& volume) const
1606 m_patch.evaluateTransform();
1608 if(!m_render_selected.empty())
1610 renderer.Highlight(Renderer::ePrimitive, false);
1611 renderer.SetState(m_state_selpoint, Renderer::eWireframeOnly);
1612 renderer.SetState(m_state_selpoint, Renderer::eFullMaterials);
1613 renderer.addRenderable(m_render_selected, localToWorld());
1616 void renderComponents(Renderer& renderer, const VolumeTest& volume) const
1618 m_patch.evaluateTransform();
1619 if(GlobalSelectionSystem().ComponentMode() == SelectionSystem::eVertex)
1621 m_patch.render_component(renderer, volume, localToWorld());
1625 void testSelect(Selector& selector, SelectionTest& test)
1627 test.BeginMesh(localToWorld(), true);
1628 m_patch.testSelect(selector, test);
1631 void selectCtrl(bool select)
1633 for(PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1635 (*i).m_selectable.setSelected(select);
1638 bool isSelectedComponents() const
1640 for(PatchControlInstances::const_iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1642 if((*i).m_selectable.isSelected())
1649 void setSelectedComponents(bool select, SelectionSystem::EComponentMode mode)
1651 if(mode == SelectionSystem::eVertex)
1655 else if(mode == SelectionSystem::eFace)
1657 m_dragPlanes.setSelected(select);
1660 const AABB& getSelectedComponentsBounds() const
1662 m_aabb_component = AABB();
1664 for(PatchControlInstances::const_iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1666 if((*i).m_selectable.isSelected())
1668 aabb_extend_by_point_safe(m_aabb_component, (*i).m_ctrl->m_vertex);
1672 return m_aabb_component;
1675 void testSelectComponents(Selector& selector, SelectionTest& test, SelectionSystem::EComponentMode mode)
1677 test.BeginMesh(localToWorld());
1681 case SelectionSystem::eVertex:
1683 for(PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1685 (*i).testSelect(selector, test);
1694 bool selectedVertices()
1696 for(PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1698 if((*i).m_selectable.isSelected())
1706 void transformComponents(const Matrix4& matrix)
1708 if(selectedVertices())
1710 PatchControlIter ctrl = m_patch.getControlPointsTransformed().begin();
1711 for(PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i, ++ctrl)
1713 if((*i).m_selectable.isSelected())
1715 matrix4_transform_point(matrix, (*ctrl).m_vertex);
1718 m_patch.UpdateCachedData();
1721 if(m_dragPlanes.isSelected()) // this should only be true when the transform is a pure translation.
1723 m_patch.transform(m_dragPlanes.evaluateTransform(vector4_to_vector3(matrix.t())));
1728 void selectPlanes(Selector& selector, SelectionTest& test, const PlaneCallback& selectedPlaneCallback)
1730 test.BeginMesh(localToWorld());
1732 m_dragPlanes.selectPlanes(m_patch.localAABB(), selector, test, selectedPlaneCallback);
1734 void selectReversedPlanes(Selector& selector, const SelectedPlanes& selectedPlanes)
1736 m_dragPlanes.selectReversedPlanes(m_patch.localAABB(), selector, selectedPlanes);
1740 void snapComponents(float snap)
1742 if(selectedVertices())
1745 for(PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i)
1747 if((*i).m_selectable.isSelected())
1752 m_patch.controlPointsChanged();
1756 void evaluateTransform()
1758 Matrix4 matrix(m_transform.calculateTransform());
1760 if(m_transform.getType() == TRANSFORM_PRIMITIVE)
1762 m_patch.transform(matrix);
1766 transformComponents(matrix);
1769 void applyTransform()
1771 m_patch.revertTransform();
1772 evaluateTransform();
1773 m_patch.freezeTransform();
1775 typedef MemberCaller<PatchInstance, &PatchInstance::applyTransform> ApplyTransformCaller;
1778 bool testLight(const RendererLight& light) const
1780 return light.testAABB(worldAABB());
1785 template<typename TokenImporter, typename TokenExporter>
1787 public scene::Node::Symbiot,
1788 public scene::Instantiable,
1789 public scene::Cloneable
1791 typedef PatchNode<TokenImporter, TokenExporter> Self;
1795 InstanceTypeCastTable m_casts;
1799 NodeStaticCast<PatchNode, scene::Instantiable>::install(m_casts);
1800 NodeStaticCast<PatchNode, scene::Cloneable>::install(m_casts);
1801 NodeContainedCast<PatchNode, Snappable>::install(m_casts);
1802 NodeContainedCast<PatchNode, TransformNode>::install(m_casts);
1803 NodeContainedCast<PatchNode, Patch>::install(m_casts);
1804 NodeContainedCast<PatchNode, XMLImporter>::install(m_casts);
1805 NodeContainedCast<PatchNode, XMLExporter>::install(m_casts);
1806 NodeContainedCast<PatchNode, MapImporter>::install(m_casts);
1807 NodeContainedCast<PatchNode, MapExporter>::install(m_casts);
1808 NodeContainedCast<PatchNode, Nameable>::install(m_casts);
1810 InstanceTypeCastTable& get()
1818 InstanceSet m_instances;
1820 TokenImporter m_importMap;
1821 TokenExporter m_exportMap;
1825 typedef LazyStatic<TypeCasts> StaticTypeCasts;
1827 Snappable& get(NullType<Snappable>)
1831 TransformNode& get(NullType<TransformNode>)
1835 Patch& get(NullType<Patch>)
1839 XMLImporter& get(NullType<XMLImporter>)
1843 XMLExporter& get(NullType<XMLExporter>)
1847 MapImporter& get(NullType<MapImporter>)
1851 MapExporter& get(NullType<MapExporter>)
1855 Nameable& get(NullType<Nameable>)
1860 PatchNode(bool patchDef3 = false) :
1861 m_node(this, this, StaticTypeCasts::instance().get()),
1862 m_patch(m_node, InstanceSetEvaluateTransform<PatchInstance>::Caller(m_instances), InstanceSet::BoundsChangedCaller(m_instances)),
1863 m_importMap(m_patch),
1864 m_exportMap(m_patch)
1866 m_patch.m_patchDef3 = patchDef3;
1868 PatchNode(const PatchNode& other) :
1869 scene::Node::Symbiot(other),
1870 scene::Instantiable(other),
1871 scene::Cloneable(other),
1872 m_node(this, this, StaticTypeCasts::instance().get()),
1873 m_patch(other.m_patch, m_node, InstanceSetEvaluateTransform<PatchInstance>::Caller(m_instances), InstanceSet::BoundsChangedCaller(m_instances)),
1874 m_importMap(m_patch),
1875 m_exportMap(m_patch)
1890 const Patch& get() const
1895 scene::Node& clone() const
1897 return (new PatchNode(*this))->node();
1900 scene::Instance* create(const scene::Path& path, scene::Instance* parent)
1902 return new PatchInstance(path, parent, m_patch);
1904 void forEachInstance(const scene::Instantiable::Visitor& visitor)
1906 m_instances.forEachInstance(visitor);
1908 void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
1910 m_instances.insert(observer, path, instance);
1912 scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
1914 return m_instances.erase(observer, path);
1920 typedef PatchNode<PatchTokenImporter, PatchTokenExporter> PatchNodeQuake3;
1921 typedef PatchNode<PatchDoom3TokenImporter, PatchDoom3TokenExporter> PatchNodeDoom3;
1923 inline Patch* Node_getPatch(scene::Node& node)
1925 return NodeTypeCast<Patch>::cast(node);
1928 inline PatchInstance* Instance_getPatch(scene::Instance& instance)
1930 return InstanceTypeCast<PatchInstance>::cast(instance);
1933 template<typename Functor>
1934 class PatchSelectedVisitor : public SelectionSystem::Visitor
1936 const Functor& m_functor;
1938 PatchSelectedVisitor(const Functor& functor) : m_functor(functor)
1941 void visit(scene::Instance& instance) const
1943 PatchInstance* patch = Instance_getPatch(instance);
1951 template<typename Functor>
1952 inline void Scene_forEachSelectedPatch(const Functor& functor)
1954 GlobalSelectionSystem().foreachSelected(PatchSelectedVisitor<Functor>(functor));
1958 template<typename Functor>
1959 class PatchVisibleSelectedVisitor : public SelectionSystem::Visitor
1961 const Functor& m_functor;
1963 PatchVisibleSelectedVisitor(const Functor& functor) : m_functor(functor)
1966 void visit(scene::Instance& instance) const
1968 PatchInstance* patch = Instance_getPatch(instance);
1970 && instance.path().top().get().visible())
1977 template<typename Functor>
1978 inline void Scene_forEachVisibleSelectedPatchInstance(const Functor& functor)
1980 GlobalSelectionSystem().foreachSelected(PatchVisibleSelectedVisitor<Functor>(functor));
1983 template<typename Functor>
1984 class PatchForEachWalker : public scene::Graph::Walker
1986 const Functor& m_functor;
1988 PatchForEachWalker(const Functor& functor) : m_functor(functor)
1991 bool pre(const scene::Path& path, scene::Instance& instance) const
1993 if(path.top().get().visible())
1995 Patch* patch = Node_getPatch(path.top());
2005 template<typename Functor>
2006 inline void Scene_forEachVisiblePatch(const Functor& functor)
2008 GlobalSceneGraph().traverse(PatchForEachWalker<Functor>(functor));
2011 template<typename Functor>
2012 class PatchForEachSelectedWalker : public scene::Graph::Walker
2014 const Functor& m_functor;
2016 PatchForEachSelectedWalker(const Functor& functor) : m_functor(functor)
2019 bool pre(const scene::Path& path, scene::Instance& instance) const
2021 if(path.top().get().visible())
2023 Patch* patch = Node_getPatch(path.top());
2025 && Instance_getSelectable(instance)->isSelected())
2034 template<typename Functor>
2035 inline void Scene_forEachVisibleSelectedPatch(const Functor& functor)
2037 GlobalSceneGraph().traverse(PatchForEachSelectedWalker<Functor>(functor));
2040 template<typename Functor>
2041 class PatchForEachInstanceWalker : public scene::Graph::Walker
2043 const Functor& m_functor;
2045 PatchForEachInstanceWalker(const Functor& functor) : m_functor(functor)
2048 bool pre(const scene::Path& path, scene::Instance& instance) const
2050 if(path.top().get().visible())
2052 PatchInstance* patch = Instance_getPatch(instance);
2062 template<typename Functor>
2063 inline void Scene_forEachVisiblePatchInstance(const Functor& functor)
2065 GlobalSceneGraph().traverse(PatchForEachInstanceWalker<Functor>(functor));