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.
33 #include "globaldefs.h"
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"
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 )
117 const std::size_t BEZIERCURVETREE_MAX_INDEX = std::size_t(1) << (std::numeric_limits<std::size_t>::digits - 1);
119 struct BezierCurveTree {
121 BezierCurveTree *left;
122 BezierCurveTree *right;
125 inline bool BezierCurveTree_isLeaf(const BezierCurveTree *node)
127 return node->left == 0 && node->right == 0;
130 void BezierCurveTree_Delete(BezierCurveTree *pCurve);
133 inline VertexPointer vertexpointer_arbitrarymeshvertex(const ArbitraryMeshVertex *array)
135 return VertexPointer(VertexPointer::pointer(&array->vertex), sizeof(ArbitraryMeshVertex));
138 typedef PatchControl *PatchControlIter;
139 typedef const PatchControl *PatchControlConstIter;
141 inline void copy_ctrl(PatchControlIter ctrl, PatchControlConstIter begin, PatchControlConstIter end)
143 std::copy(begin, end, ctrl);
146 const Colour4b colour_corner(0, 255, 0, 255);
147 const Colour4b colour_inside(255, 0, 255, 255);
153 virtual bool filter(const Patch &patch) const = 0;
156 bool patch_filtered(Patch &patch);
158 void add_patch_filter(PatchFilter &filter, int mask, bool invert = false);
160 void Patch_addTextureChangedCallback(const SignalHandler &handler);
162 void Patch_textureChanged();
164 inline void BezierCurveTreeArray_deleteAll(Array<BezierCurveTree *> &curveTrees)
166 for (Array<BezierCurveTree *>::iterator i = curveTrees.begin(); i != curveTrees.end(); ++i) {
167 BezierCurveTree_Delete(*i);
171 inline void PatchControlArray_invert(Array<PatchControl> &ctrl, std::size_t width, std::size_t height)
173 Array<PatchControl> tmp(width);
175 PatchControlIter from = ctrl.data() + (width * (height - 1));
176 PatchControlIter to = ctrl.data();
177 for (std::size_t h = 0; h != ((height - 1) >> 1); ++h, to += width, from -= width) {
178 copy_ctrl(tmp.data(), to, to + width);
179 copy_ctrl(to, from, from + width);
180 copy_ctrl(from, tmp.data(), tmp.data() + width);
184 class PatchTesselation {
187 : m_numStrips(0), m_lenStrips(0), m_nArrayWidth(0), m_nArrayHeight(0)
191 Array<ArbitraryMeshVertex> m_vertices;
192 Array<RenderIndex> m_indices;
193 std::size_t m_numStrips;
194 std::size_t m_lenStrips;
196 Array<std::size_t> m_arrayWidth;
197 std::size_t m_nArrayWidth;
198 Array<std::size_t> m_arrayHeight;
199 std::size_t m_nArrayHeight;
201 Array<BezierCurveTree *> m_curveTreeU;
202 Array<BezierCurveTree *> m_curveTreeV;
205 class RenderablePatchWireframe : public OpenGLRenderable {
206 PatchTesselation &m_tess;
208 RenderablePatchWireframe(PatchTesselation &tess) : m_tess(tess)
212 void render(RenderStateFlags state) const
216 glVertexPointer(3, GL_FLOAT, 0, 0);
217 glDrawArrays(GL_TRIANGLE_FAN, 0, 0);
221 glVertexPointer(3, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->vertex);
222 for (std::size_t i = 0; i <= m_tess.m_curveTreeV.size(); ++i) {
223 glDrawArrays(GL_LINE_STRIP, GLint(n), GLsizei(m_tess.m_nArrayWidth));
225 if (i == m_tess.m_curveTreeV.size()) {
229 if (!BezierCurveTree_isLeaf(m_tess.m_curveTreeV[i])) {
230 glDrawArrays(GL_LINE_STRIP, GLint(m_tess.m_curveTreeV[i]->index), GLsizei(m_tess.m_nArrayWidth));
233 n += (m_tess.m_arrayHeight[i] * m_tess.m_nArrayWidth);
239 const ArbitraryMeshVertex *p = m_tess.m_vertices.data();
240 std::size_t n = m_tess.m_nArrayWidth * sizeof(ArbitraryMeshVertex);
241 for (std::size_t i = 0; i <= m_tess.m_curveTreeU.size(); ++i) {
242 glVertexPointer(3, GL_FLOAT, GLsizei(n), &p->vertex);
243 glDrawArrays(GL_LINE_STRIP, 0, GLsizei(m_tess.m_nArrayHeight));
245 if (i == m_tess.m_curveTreeU.size()) {
249 if (!BezierCurveTree_isLeaf(m_tess.m_curveTreeU[i])) {
250 glVertexPointer(3, GL_FLOAT, GLsizei(n),
251 &(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 {
262 PatchTesselation &m_tess;
264 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) {
273 glDrawElements(GL_QUAD_STRIP, GLsizei(m_tess.m_lenStrips), RenderIndexTypeID, strip_indices);
278 class RenderablePatchSolid : public OpenGLRenderable {
279 PatchTesselation &m_tess;
281 RenderablePatchSolid(PatchTesselation &tess) : m_tess(tess)
285 void RenderNormals() const;
287 void render(RenderStateFlags state) const
290 if ( ( state & RENDER_FILL ) == 0 ) {
291 RenderablePatchWireframe( m_tess ).render( state );
296 if ((state & RENDER_BUMP) != 0) {
297 if (GlobalShaderCache().useShaderLanguage()) {
298 glNormalPointer(GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_tess.m_vertices.data()->normal);
299 glVertexAttribPointerARB(c_attr_TexCoord0, 2, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex),
300 &m_tess.m_vertices.data()->texcoord);
301 glVertexAttribPointerARB(c_attr_Tangent, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex),
302 &m_tess.m_vertices.data()->tangent);
303 glVertexAttribPointerARB(c_attr_Binormal, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex),
304 &m_tess.m_vertices.data()->bitangent);
306 glVertexAttribPointerARB(11, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex),
307 &m_tess.m_vertices.data()->normal);
308 glVertexAttribPointerARB(8, 2, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex),
309 &m_tess.m_vertices.data()->texcoord);
310 glVertexAttribPointerARB(9, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex),
311 &m_tess.m_vertices.data()->tangent);
312 glVertexAttribPointerARB(10, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex),
313 &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) {
322 glDrawElements(GL_QUAD_STRIP, GLsizei(m_tess.m_lenStrips), RenderIndexTypeID, strip_indices);
332 // parametric surface defined by quadratic bezier control curves
336 public TransformNode,
352 xml_state_t(EState state)
361 const char *content() const
363 return m_content.c_str();
366 std::size_t write(const char *buffer, std::size_t length)
368 return m_content.write(buffer, length);
373 StringOutputStream m_content;
376 std::vector<xml_state_t> m_xml_state;
378 typedef Array<PatchControl> PatchControlArray;
380 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;
417 virtual void allocate(std::size_t size) = 0;
421 typedef UniqueSet<Observer *> Observers;
422 Observers m_observers;
426 AABB m_aabb_local; // local bbox
428 CopiedString m_shader;
432 std::size_t m_height;
435 std::size_t m_subdivisions_x;
436 std::size_t m_subdivisions_y;
439 UndoObserver *m_undoable_observer;
442 // dynamically allocated array of control points, size is m_width*m_height
443 PatchControlArray m_ctrl;
444 PatchControlArray m_ctrlTransformed;
446 PatchTesselation m_tess;
447 RenderablePatchSolid m_render_solid;
448 RenderablePatchWireframe m_render_wireframe;
449 RenderablePatchFixedWireframe m_render_wireframe_fixed;
451 static Shader *m_state_ctrl;
452 static Shader *m_state_lattice;
453 VertexBuffer<PointVertex> m_ctrl_vertices;
454 RenderableVertexBuffer m_render_ctrl;
455 IndexBuffer m_lattice_indices;
456 RenderableIndexBuffer m_render_lattice;
460 bool m_transformChanged;
461 Callback<void()> m_evaluateTransform;
462 Callback<void()> m_boundsChanged;
467 m_width = m_height = 0;
470 m_subdivisions_x = 0;
471 m_subdivisions_y = 0;
476 m_xml_state.push_back(xml_state_t::eDefault);
480 Callback<void()> m_lightsChanged;
482 static int m_CycleCapIndex; // = 0;
483 static EPatchType m_type;
485 STRING_CONSTANT(Name, "Patch");
487 Patch(scene::Node &node, const Callback<void()> &evaluateTransform, const Callback<void()> &boundsChanged) :
489 m_shader(texdef_name_default()),
491 m_undoable_observer(0),
493 m_render_solid(m_tess),
494 m_render_wireframe(m_tess),
495 m_render_wireframe_fixed(m_tess),
496 m_render_ctrl(GL_POINTS, m_ctrl_vertices),
497 m_render_lattice(GL_LINES, m_lattice_indices, m_ctrl_vertices),
498 m_transformChanged(false),
499 m_evaluateTransform(evaluateTransform),
500 m_boundsChanged(boundsChanged)
505 Patch(const Patch &other, scene::Node &node, const Callback<void()> &evaluateTransform,
506 const Callback<void()> &boundsChanged) :
508 m_shader(texdef_name_default()),
510 m_undoable_observer(0),
512 m_render_solid(m_tess),
513 m_render_wireframe(m_tess),
514 m_render_wireframe_fixed(m_tess),
515 m_render_ctrl(GL_POINTS, m_ctrl_vertices),
516 m_render_lattice(GL_LINES, m_lattice_indices, m_ctrl_vertices),
517 m_transformChanged(false),
518 m_evaluateTransform(evaluateTransform),
519 m_boundsChanged(boundsChanged)
523 m_patchDef3 = other.m_patchDef3;
524 m_subdivisions_x = other.m_subdivisions_x;
525 m_subdivisions_y = other.m_subdivisions_y;
526 setDims(other.m_width, other.m_height);
527 copy_ctrl(m_ctrl.data(), other.m_ctrl.data(), other.m_ctrl.data() + (m_width * m_height));
528 SetShader(other.m_shader.c_str());
529 controlPointsChanged();
532 Patch(const Patch &other) :
535 TransformNode(other),
543 m_undoable_observer(0),
545 m_render_solid(m_tess),
546 m_render_wireframe(m_tess),
547 m_render_wireframe_fixed(m_tess),
548 m_render_ctrl(GL_POINTS, m_ctrl_vertices),
549 m_render_lattice(GL_LINES, m_lattice_indices, m_ctrl_vertices),
550 m_transformChanged(false),
551 m_evaluateTransform(other.m_evaluateTransform),
552 m_boundsChanged(other.m_boundsChanged)
556 m_patchDef3 = other.m_patchDef3;
557 m_subdivisions_x = other.m_subdivisions_x;
558 m_subdivisions_y = other.m_subdivisions_y;
559 setDims(other.m_width, other.m_height);
560 copy_ctrl(m_ctrl.data(), other.m_ctrl.data(), other.m_ctrl.data() + (m_width * m_height));
561 SetShader(other.m_shader.c_str());
562 controlPointsChanged();
567 BezierCurveTreeArray_deleteAll(m_tess.m_curveTreeU);
568 BezierCurveTreeArray_deleteAll(m_tess.m_curveTreeV);
572 ASSERT_MESSAGE(m_observers.empty(), "Patch::~Patch: observers still attached");
575 InstanceCounter m_instanceCounter;
577 void instanceAttach(const scene::Path &path)
579 if (++m_instanceCounter.m_count == 1) {
580 m_state->incrementUsed();
581 m_map = path_find_mapfile(path.begin(), path.end());
582 m_undoable_observer = GlobalUndoSystem().observer(this);
583 GlobalFilterSystem().registerFilterable(*this);
585 ASSERT_MESSAGE(path_find_mapfile(path.begin(), path.end()) == m_map,
586 "node is instanced across more than one file");
590 void instanceDetach(const scene::Path &path)
592 if (--m_instanceCounter.m_count == 0) {
594 m_undoable_observer = 0;
595 GlobalUndoSystem().release(this);
596 GlobalFilterSystem().unregisterFilterable(*this);
597 m_state->decrementUsed();
601 const char *name() const
606 void attach(const NameCallback &callback)
610 void detach(const NameCallback &callback)
614 void attach(Observer *observer)
616 observer->allocate(m_width * m_height);
618 m_observers.insert(observer);
621 void detach(Observer *observer)
623 m_observers.erase(observer);
626 void updateFiltered()
629 if (patch_filtered(*this)) {
630 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) {
640 (*i)->allocate(size);
644 const Matrix4 &localToParent() const
646 return g_matrix4_identity;
649 const AABB &localAABB() const
654 VolumeIntersectionValue intersectVolume(const VolumeTest &test, const Matrix4 &localToWorld) const
656 return test.TestAABB(m_aabb_local, localToWorld);
659 void render_solid(Renderer &renderer, const VolumeTest &volume, const Matrix4 &localToWorld) const
661 renderer.SetState(m_state, Renderer::eFullMaterials);
662 renderer.addRenderable(m_render_solid, localToWorld);
665 void render_wireframe(Renderer &renderer, const VolumeTest &volume, const Matrix4 &localToWorld) const
667 renderer.SetState(m_state, Renderer::eFullMaterials);
669 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);
686 void testSelect(Selector &selector, SelectionTest &test)
688 SelectionIntersection best;
689 IndexPointer::index_type *pIndex = m_tess.m_indices.data();
690 for (std::size_t s = 0; s < m_tess.m_numStrips; s++) {
691 test.TestQuadStrip(vertexpointer_arbitrarymeshvertex(m_tess.m_vertices.data()),
692 IndexPointer(pIndex, m_tess.m_lenStrips), best);
693 pIndex += m_tess.m_lenStrips;
696 selector.addIntersection(best);
700 void transform(const Matrix4 &matrix)
702 for (PatchControlIter i = m_ctrlTransformed.data();
703 i != m_ctrlTransformed.data() + m_ctrlTransformed.size(); ++i) {
704 matrix4_transform_point(matrix, (*i).m_vertex);
707 if (matrix4_handedness(matrix) == MATRIX4_LEFTHANDED) {
708 PatchControlArray_invert(m_ctrlTransformed, m_width, m_height);
713 void transformChanged()
715 m_transformChanged = true;
720 typedef MemberCaller<Patch, void(), &Patch::transformChanged> TransformChangedCaller;
722 void evaluateTransform()
724 if (m_transformChanged) {
725 m_transformChanged = false;
727 m_evaluateTransform();
731 void revertTransform()
733 m_ctrlTransformed = m_ctrl;
736 void freezeTransform()
740 ASSERT_MESSAGE(m_ctrlTransformed.size() == m_ctrl.size(), "Patch::freeze: size mismatch");
741 std::copy(m_ctrlTransformed.begin(), m_ctrlTransformed.end(), m_ctrl.begin());
744 void controlPointsChanged()
751 bool isValid() const;
753 void snapto(float snap)
757 for (PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i) {
758 vector3_snap((*i).m_vertex, snap);
761 controlPointsChanged();
765 void RenderDebug(RenderStateFlags state) const;
767 void RenderNormals(RenderStateFlags state) const;
769 void pushElement(const XMLElement &element)
771 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")) {
778 setDims(atoi(element.attribute("width")), atoi(element.attribute("height")));
779 m_xml_state.push_back(xml_state_t::eMatrix);
780 } else if (string_equal(element.name(), "shader")) {
781 m_xml_state.push_back(xml_state_t::eShader);
785 ERROR_MESSAGE("parse error");
790 void popElement(const char *name)
792 switch (m_xml_state.back().state()) {
793 case xml_state_t::eDefault:
794 ERROR_MESSAGE("parse error");
796 case xml_state_t::ePatch:
798 case xml_state_t::eMatrix: {
799 StringTokeniser content(m_xml_state.back().content());
801 for (PatchControlIter i = m_ctrl.data(), end = m_ctrl.data() + m_ctrl.size(); i != end; ++i) {
802 (*i).m_vertex[0] = string_read_float(content.getToken());
803 (*i).m_vertex[1] = string_read_float(content.getToken());
804 (*i).m_vertex[2] = string_read_float(content.getToken());
805 (*i).m_texcoord[0] = string_read_float(content.getToken());
806 (*i).m_texcoord[1] = string_read_float(content.getToken());
808 controlPointsChanged();
811 case xml_state_t::eShader: {
812 SetShader(m_xml_state.back().content());
816 ERROR_MESSAGE("parse error");
819 ASSERT_MESSAGE(!m_xml_state.empty(), "popping empty stack");
820 m_xml_state.pop_back();
823 std::size_t write(const char *buffer, std::size_t length)
825 switch (m_xml_state.back().state()) {
826 case xml_state_t::eDefault:
828 case xml_state_t::ePatch:
830 case xml_state_t::eMatrix:
831 case xml_state_t::eShader:
832 return m_xml_state.back().write(buffer, length);
835 ERROR_MESSAGE("parse error");
840 void exportXML(XMLImporter &importer)
842 StaticElement patchElement("patch");
843 importer.pushElement(patchElement);
846 const StaticElement element("shader");
847 importer.pushElement(element);
848 importer.write(m_shader.c_str(), strlen(m_shader.c_str()));
849 importer.popElement(element.name());
853 char width[16], height[16];
854 sprintf(width, "%u", Unsigned(m_width));
855 sprintf(height, "%u", Unsigned(m_height));
856 StaticElement element("matrix");
857 element.insertAttribute("width", width);
858 element.insertAttribute("height", height);
860 importer.pushElement(element);
862 for (PatchControlIter i = m_ctrl.data(), end = m_ctrl.data() + m_ctrl.size(); i != end; ++i) {
863 importer << (*i).m_vertex[0]
864 << ' ' << (*i).m_vertex[1]
865 << ' ' << (*i).m_vertex[2]
866 << ' ' << (*i).m_texcoord[0]
867 << ' ' << (*i).m_texcoord[1];
870 importer.popElement(element.name());
873 importer.popElement(patchElement.name());
876 void UpdateCachedData();
878 const char *GetShader() const
880 return m_shader.c_str();
883 void SetShader(const char *name)
885 ASSERT_NOTNULL(name);
887 if (shader_equal(m_shader.c_str(), name)) {
893 if (m_instanceCounter.m_count != 0) {
894 m_state->decrementUsed();
899 if (m_instanceCounter.m_count != 0) {
900 m_state->incrementUsed();
904 Patch_textureChanged();
907 int getShaderFlags() const
910 return m_state->getFlags();
915 typedef PatchControl *iterator;
916 typedef const PatchControl *const_iterator;
920 return m_ctrl.data();
923 const_iterator begin() const
925 return m_ctrl.data();
930 return m_ctrl.data() + m_ctrl.size();
933 const_iterator end() const
935 return m_ctrl.data() + m_ctrl.size();
938 PatchControlArray &getControlPoints()
943 PatchControlArray &getControlPointsTransformed()
945 return m_ctrlTransformed;
948 void setDims(std::size_t w, std::size_t h);
950 std::size_t getWidth() const
955 std::size_t getHeight() const
960 PatchControl &ctrlAt(std::size_t row, std::size_t col)
962 return m_ctrl[row * m_width + col];
965 const PatchControl &ctrlAt(std::size_t row, std::size_t col) const
967 return m_ctrl[row * m_width + col];
970 void ConstructPrefab(const AABB &aabb, EPatchPrefab eType, int axis, std::size_t width = 3, std::size_t height = 3);
972 void constructPlane(const AABB &aabb, int axis, std::size_t width, std::size_t height);
976 void TransposeMatrix();
978 void Redisperse(EMatrixMajor mt);
980 void Smooth(EMatrixMajor mt);
982 void InsertRemove(bool bInsert, bool bColumn, bool bFirst);
984 Patch *MakeCap(Patch *patch, EPatchCap eType, EMatrixMajor mt, bool bFirst);
986 void ConstructSeam(EPatchCap eType, Vector3 *p, std::size_t width);
988 void FlipTexture(int nAxis);
990 void TranslateTexture(float s, float t);
992 void ScaleTexture(float s, float t);
994 void RotateTexture(float angle);
996 void SetTextureRepeat(float s, float t); // call with s=1 t=1 for FIT
999 void NaturalTexture();
1001 void ProjectTexture(int nAxis);
1008 if (m_undoable_observer != 0) {
1009 m_undoable_observer->save(this);
1013 UndoMemento *exportState() const
1015 return new SavedState(m_width, m_height, m_ctrl, m_shader.c_str(), m_patchDef3, m_subdivisions_x,
1019 void importState(const UndoMemento *state)
1023 const SavedState &other = *(static_cast<const SavedState *>( state ));
1025 // begin duplicate of SavedState copy constructor, needs refactoring
1029 m_width = other.m_width;
1030 m_height = other.m_height;
1031 SetShader(other.m_shader.c_str());
1032 m_ctrl = other.m_ctrl;
1033 onAllocate(m_ctrl.size());
1034 m_patchDef3 = other.m_patchDef3;
1035 m_subdivisions_x = other.m_subdivisions_x;
1036 m_subdivisions_y = other.m_subdivisions_y;
1039 // end duplicate code
1041 Patch_textureChanged();
1043 controlPointsChanged();
1046 static void constructStatic(EPatchType type)
1048 Patch::m_type = type;
1049 Patch::m_state_ctrl = GlobalShaderCache().capture("$POINT");
1050 Patch::m_state_lattice = GlobalShaderCache().capture("$LATTICE");
1053 static void destroyStatic()
1055 GlobalShaderCache().release("$LATTICE");
1056 GlobalShaderCache().release("$POINT");
1060 void captureShader()
1062 m_state = GlobalShaderCache().capture(m_shader.c_str());
1065 void releaseShader()
1067 GlobalShaderCache().release(m_shader.c_str());
1072 if (!shader_valid(GetShader())) {
1073 globalErrorStream() << "patch has invalid texture name: '" << GetShader() << "'\n";
1077 void InsertPoints(EMatrixMajor mt, bool bFirst);
1079 void RemovePoints(EMatrixMajor mt, bool bFirst);
1081 void AccumulateBBox();
1083 void TesselateSubMatrixFixed(ArbitraryMeshVertex *vertices, std::size_t strideX, std::size_t strideY,
1084 unsigned int nFlagsX, unsigned int nFlagsY, PatchControl *subMatrix[3][3]);
1086 // uses binary trees representing bezier curves to recursively tesselate a bezier sub-patch
1087 void TesselateSubMatrix(const BezierCurveTree *BX, const BezierCurveTree *BY,
1088 std::size_t offStartX, std::size_t offStartY,
1089 std::size_t offEndX, std::size_t offEndY,
1090 std::size_t nFlagsX, std::size_t nFlagsY,
1091 Vector3 &left, Vector3 &mid, Vector3 &right,
1092 Vector2 &texLeft, Vector2 &texMid, Vector2 &texRight,
1095 // tesselates the entire surface
1096 void BuildTesselationCurves(EMatrixMajor major);
1098 void accumulateVertexTangentSpace(std::size_t index, Vector3 tangentX[6], Vector3 tangentY[6], Vector2 tangentS[6],
1099 Vector2 tangentT[6], std::size_t index0, std::size_t index1);
1101 void BuildVertexArray();
1104 inline bool Patch_importHeader(Patch &patch, Tokeniser &tokeniser)
1106 tokeniser.nextLine();
1107 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "{"));
1111 inline bool Patch_importShader(Patch &patch, Tokeniser &tokeniser)
1113 // parse shader name
1114 tokeniser.nextLine();
1115 const char *texture = tokeniser.getToken();
1117 Tokeniser_unexpectedError(tokeniser, texture, "#texture-name");
1120 if (string_equal(texture, "NULL")) {
1121 patch.SetShader(texdef_name_default());
1123 StringOutputStream shader(string_length(GlobalTexturePrefix_get()) + string_length(texture));
1124 shader << GlobalTexturePrefix_get() << texture;
1125 patch.SetShader(shader.c_str());
1130 inline bool PatchDoom3_importShader(Patch &patch, Tokeniser &tokeniser)
1132 // parse shader name
1133 tokeniser.nextLine();
1134 const char *shader = tokeniser.getToken();
1136 Tokeniser_unexpectedError(tokeniser, shader, "#shader-name");
1139 if (string_equal(shader, "_emptyname")) {
1140 shader = texdef_name_default();
1142 patch.SetShader(shader);
1146 inline bool Patch_importParams(Patch &patch, Tokeniser &tokeniser)
1148 tokeniser.nextLine();
1149 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
1151 // parse matrix dimensions
1154 RETURN_FALSE_IF_FAIL(Tokeniser_getSize(tokeniser, c));
1155 RETURN_FALSE_IF_FAIL(Tokeniser_getSize(tokeniser, r));
1157 patch.setDims(c, r);
1160 if (patch.m_patchDef3) {
1161 RETURN_FALSE_IF_FAIL(Tokeniser_getSize(tokeniser, patch.m_subdivisions_x));
1162 RETURN_FALSE_IF_FAIL(Tokeniser_getSize(tokeniser, patch.m_subdivisions_y));
1165 // ignore contents/flags/value
1167 RETURN_FALSE_IF_FAIL(Tokeniser_getInteger(tokeniser, tmp));
1168 RETURN_FALSE_IF_FAIL(Tokeniser_getInteger(tokeniser, tmp));
1169 RETURN_FALSE_IF_FAIL(Tokeniser_getInteger(tokeniser, tmp));
1171 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
1175 inline bool Patch_importMatrix(Patch &patch, Tokeniser &tokeniser)
1178 tokeniser.nextLine();
1179 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
1181 for (std::size_t c = 0; c < patch.getWidth(); c++) {
1182 tokeniser.nextLine();
1183 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
1184 for (std::size_t r = 0; r < patch.getHeight(); r++) {
1185 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
1187 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r, c).m_vertex[0]));
1188 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r, c).m_vertex[1]));
1189 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r, c).m_vertex[2]));
1190 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r, c).m_texcoord[0]));
1191 RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, patch.ctrlAt(r, c).m_texcoord[1]));
1193 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
1195 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
1198 tokeniser.nextLine();
1199 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
1203 inline bool Patch_importFooter(Patch &patch, Tokeniser &tokeniser)
1205 patch.controlPointsChanged();
1207 tokeniser.nextLine();
1208 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "}"));
1210 tokeniser.nextLine();
1211 RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "}"));
1215 class PatchTokenImporter : public MapImporter {
1218 PatchTokenImporter(Patch &patch) : m_patch(patch)
1222 bool importTokens(Tokeniser &tokeniser)
1224 RETURN_FALSE_IF_FAIL(Patch_importHeader(m_patch, tokeniser));
1225 RETURN_FALSE_IF_FAIL(Patch_importShader(m_patch, tokeniser));
1226 RETURN_FALSE_IF_FAIL(Patch_importParams(m_patch, tokeniser));
1227 RETURN_FALSE_IF_FAIL(Patch_importMatrix(m_patch, tokeniser));
1228 RETURN_FALSE_IF_FAIL(Patch_importFooter(m_patch, tokeniser));
1234 class PatchDoom3TokenImporter : public MapImporter {
1237 PatchDoom3TokenImporter(Patch &patch) : m_patch(patch)
1241 bool importTokens(Tokeniser &tokeniser)
1243 RETURN_FALSE_IF_FAIL(Patch_importHeader(m_patch, tokeniser));
1244 RETURN_FALSE_IF_FAIL(PatchDoom3_importShader(m_patch, tokeniser));
1245 RETURN_FALSE_IF_FAIL(Patch_importParams(m_patch, tokeniser));
1246 RETURN_FALSE_IF_FAIL(Patch_importMatrix(m_patch, tokeniser));
1247 RETURN_FALSE_IF_FAIL(Patch_importFooter(m_patch, tokeniser));
1253 inline void Patch_exportHeader(const Patch &patch, TokenWriter &writer)
1255 writer.writeToken("{");
1257 writer.writeToken(patch.m_patchDef3 ? "patchDef3" : "patchDef2");
1259 writer.writeToken("{");
1263 inline void Patch_exportShader(const Patch &patch, TokenWriter &writer)
1265 // write shader name
1266 if (*(shader_get_textureName(patch.GetShader())) == '\0') {
1267 writer.writeToken("NULL");
1269 writer.writeToken(shader_get_textureName(patch.GetShader()));
1274 inline void PatchDoom3_exportShader(const Patch &patch, TokenWriter &writer)
1276 // write shader name
1277 if (*(shader_get_textureName(patch.GetShader())) == '\0') {
1278 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) {
1292 writer.writeUnsigned(patch.m_subdivisions_x);
1293 writer.writeUnsigned(patch.m_subdivisions_y);
1295 writer.writeInteger(0);
1296 writer.writeInteger(0);
1297 writer.writeInteger(0);
1298 writer.writeToken(")");
1302 inline void Patch_exportMatrix(const Patch &patch, TokenWriter &writer)
1305 writer.writeToken("(");
1307 for (std::size_t c = 0; c < patch.getWidth(); c++) {
1308 writer.writeToken("(");
1309 for (std::size_t r = 0; r < patch.getHeight(); r++) {
1310 writer.writeToken("(");
1312 writer.writeFloat(patch.ctrlAt(r, c).m_vertex[0]);
1313 writer.writeFloat(patch.ctrlAt(r, c).m_vertex[1]);
1314 writer.writeFloat(patch.ctrlAt(r, c).m_vertex[2]);
1315 writer.writeFloat(patch.ctrlAt(r, c).m_texcoord[0]);
1316 writer.writeFloat(patch.ctrlAt(r, c).m_texcoord[1]);
1318 writer.writeToken(")");
1320 writer.writeToken(")");
1323 writer.writeToken(")");
1327 inline void Patch_exportFooter(const Patch &patch, TokenWriter &writer)
1329 writer.writeToken("}");
1331 writer.writeToken("}");
1335 class PatchTokenExporter : public MapExporter {
1336 const Patch &m_patch;
1338 PatchTokenExporter(Patch &patch) : m_patch(patch)
1342 void exportTokens(TokenWriter &writer) const
1344 Patch_exportHeader(m_patch, writer);
1345 Patch_exportShader(m_patch, writer);
1346 Patch_exportParams(m_patch, writer);
1347 Patch_exportMatrix(m_patch, writer);
1348 Patch_exportFooter(m_patch, writer);
1352 class PatchDoom3TokenExporter : public MapExporter {
1353 const Patch &m_patch;
1355 PatchDoom3TokenExporter(Patch &patch) : m_patch(patch)
1359 void exportTokens(TokenWriter &writer) const
1361 Patch_exportHeader(m_patch, writer);
1362 PatchDoom3_exportShader(m_patch, writer);
1363 Patch_exportParams(m_patch, writer);
1364 Patch_exportMatrix(m_patch, writer);
1365 Patch_exportFooter(m_patch, writer);
1369 class PatchControlInstance {
1371 PatchControl *m_ctrl;
1372 ObservedSelectable m_selectable;
1374 PatchControlInstance(PatchControl *ctrl, const SelectionChangeCallback &observer)
1375 : m_ctrl(ctrl), m_selectable(observer)
1379 void testSelect(Selector &selector, SelectionTest &test)
1381 SelectionIntersection best;
1382 test.TestPoint(m_ctrl->m_vertex, best);
1384 Selector_add(selector, m_selectable, best);
1388 void snapto(float snap)
1390 vector3_snap(m_ctrl->m_vertex, snap);
1395 class PatchInstance :
1396 public Patch::Observer,
1397 public scene::Instance,
1400 public SelectionTestable,
1401 public ComponentSelectionTestable,
1402 public ComponentEditable,
1403 public ComponentSnappable,
1404 public PlaneSelectable,
1405 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);
1424 InstanceTypeCastTable &get()
1432 typedef std::vector<PatchControlInstance> PatchControlInstances;
1433 PatchControlInstances m_ctrl_instances;
1435 ObservedSelectable m_selectable;
1437 DragPlanes m_dragPlanes;
1439 mutable RenderablePointVector m_render_selected;
1440 mutable AABB m_aabb_component;
1442 static Shader *m_state_selpoint;
1444 const LightList *m_lightList;
1446 TransformModifier m_transform;
1449 typedef LazyStatic<TypeCasts> StaticTypeCasts;
1451 void lightsChanged()
1453 m_lightList->lightsChanged();
1456 typedef MemberCaller<PatchInstance, void(), &PatchInstance::lightsChanged> LightsChangedCaller;
1458 STRING_CONSTANT(Name, "PatchInstance");
1460 PatchInstance(const scene::Path &path, scene::Instance *parent, Patch &patch) :
1461 Instance(path, parent, this, StaticTypeCasts::instance().get()),
1463 m_selectable(SelectedChangedCaller(*this)),
1464 m_dragPlanes(SelectedChangedComponentCaller(*this)),
1465 m_render_selected(GL_POINTS),
1466 m_transform(Patch::TransformChangedCaller(m_patch), ApplyTransformCaller(*this))
1468 m_patch.instanceAttach(Instance::path());
1469 m_patch.attach(this);
1471 m_lightList = &GlobalShaderCache().attach(*this);
1472 m_patch.m_lightsChanged = LightsChangedCaller(*this);
1474 Instance::setTransformChangedCallback(LightsChangedCaller(*this));
1479 Instance::setTransformChangedCallback(Callback<void()>());
1481 m_patch.m_lightsChanged = Callback<void()>();
1482 GlobalShaderCache().detach(*this);
1484 m_patch.detach(this);
1485 m_patch.instanceDetach(Instance::path());
1488 void selectedChanged(const Selectable &selectable)
1490 GlobalSelectionSystem().getObserver(SelectionSystem::ePrimitive)(selectable);
1491 GlobalSelectionSystem().onSelectedChanged(*this, selectable);
1493 Instance::selectedChanged();
1496 typedef MemberCaller<PatchInstance, void(
1497 const Selectable &), &PatchInstance::selectedChanged> SelectedChangedCaller;
1499 void selectedChangedComponent(const Selectable &selectable)
1501 GlobalSelectionSystem().getObserver(SelectionSystem::eComponent)(selectable);
1502 GlobalSelectionSystem().onComponentSelection(*this, selectable);
1505 typedef MemberCaller<PatchInstance, void(
1506 const Selectable &), &PatchInstance::selectedChangedComponent> SelectedChangedComponentCaller;
1513 Bounded &get(NullType<Bounded>)
1518 Cullable &get(NullType<Cullable>)
1523 Transformable &get(NullType<Transformable>)
1528 static void constructStatic()
1530 m_state_selpoint = GlobalShaderCache().capture("$SELPOINT");
1533 static void destroyStatic()
1535 GlobalShaderCache().release("$SELPOINT");
1539 void allocate(std::size_t size)
1541 m_ctrl_instances.clear();
1542 m_ctrl_instances.reserve(size);
1543 for (Patch::iterator i = m_patch.begin(); i != m_patch.end(); ++i) {
1544 m_ctrl_instances.push_back(PatchControlInstance(&(*i), SelectedChangedComponentCaller(*this)));
1548 void setSelected(bool select)
1550 m_selectable.setSelected(select);
1553 bool isSelected() const
1555 return m_selectable.isSelected();
1559 void update_selected() const
1561 m_render_selected.clear();
1562 Patch::iterator ctrl = m_patch.getControlPointsTransformed().begin();
1563 for (PatchControlInstances::const_iterator i = m_ctrl_instances.begin();
1564 i != m_ctrl_instances.end(); ++i, ++ctrl) {
1565 if ((*i).m_selectable.isSelected()) {
1566 const Colour4b colour_selected(0, 0, 255, 255);
1567 m_render_selected.push_back(
1568 PointVertex(reinterpret_cast<Vertex3f &>((*ctrl).m_vertex ), colour_selected));
1574 void render( Renderer& renderer, const VolumeTest& volume ) const {
1575 if ( GlobalSelectionSystem().Mode() == SelectionSystem::eComponent
1576 && m_selectable.isSelected() ) {
1577 renderer.Highlight( Renderer::eFace, false );
1579 m_patch.render( renderer, volume, localToWorld() );
1581 if ( GlobalSelectionSystem().ComponentMode() == SelectionSystem::eVertex ) {
1582 renderer.Highlight( Renderer::ePrimitive, false );
1584 m_patch.render_component( renderer, volume, localToWorld() );
1586 renderComponentsSelected( renderer, volume );
1590 m_patch.render( renderer, volume, localToWorld() );
1595 void renderSolid(Renderer &renderer, const VolumeTest &volume) const
1597 m_patch.evaluateTransform();
1598 renderer.setLights(*m_lightList);
1599 m_patch.render_solid(renderer, volume, localToWorld());
1601 renderComponentsSelected(renderer, volume);
1604 void renderWireframe(Renderer &renderer, const VolumeTest &volume) const
1606 m_patch.evaluateTransform();
1607 m_patch.render_wireframe(renderer, volume, localToWorld());
1609 renderComponentsSelected(renderer, volume);
1612 void renderComponentsSelected(Renderer &renderer, const VolumeTest &volume) const
1614 m_patch.evaluateTransform();
1616 if (!m_render_selected.empty()) {
1617 renderer.Highlight(Renderer::ePrimitive, false);
1618 renderer.SetState(m_state_selpoint, Renderer::eWireframeOnly);
1619 renderer.SetState(m_state_selpoint, Renderer::eFullMaterials);
1620 renderer.addRenderable(m_render_selected, localToWorld());
1624 void renderComponents(Renderer &renderer, const VolumeTest &volume) const
1626 m_patch.evaluateTransform();
1627 if (GlobalSelectionSystem().ComponentMode() == SelectionSystem::eVertex) {
1628 m_patch.render_component(renderer, volume, localToWorld());
1632 void testSelect(Selector &selector, SelectionTest &test)
1634 test.BeginMesh(localToWorld(), true);
1635 m_patch.testSelect(selector, test);
1638 void selectCtrl(bool select)
1640 for (PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i) {
1641 (*i).m_selectable.setSelected(select);
1645 bool isSelectedComponents() const
1647 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) {
1659 } else if (mode == SelectionSystem::eFace) {
1660 m_dragPlanes.setSelected(select);
1664 const AABB &getSelectedComponentsBounds() const
1666 m_aabb_component = AABB();
1668 for (PatchControlInstances::const_iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i) {
1669 if ((*i).m_selectable.isSelected()) {
1670 aabb_extend_by_point_safe(m_aabb_component, (*i).m_ctrl->m_vertex);
1674 return m_aabb_component;
1677 void testSelectComponents(Selector &selector, SelectionTest &test, SelectionSystem::EComponentMode mode)
1679 test.BeginMesh(localToWorld());
1682 case SelectionSystem::eVertex: {
1683 for (PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i) {
1684 (*i).testSelect(selector, test);
1693 bool selectedVertices()
1695 for (PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i) {
1696 if ((*i).m_selectable.isSelected()) {
1703 void transformComponents(const Matrix4 &matrix)
1705 if (selectedVertices()) {
1706 PatchControlIter ctrl = m_patch.getControlPointsTransformed().begin();
1707 for (PatchControlInstances::iterator i = m_ctrl_instances.begin();
1708 i != m_ctrl_instances.end(); ++i, ++ctrl) {
1709 if ((*i).m_selectable.isSelected()) {
1710 matrix4_transform_point(matrix, (*ctrl).m_vertex);
1713 m_patch.UpdateCachedData();
1716 if (m_dragPlanes.isSelected()) { // this should only be true when the transform is a pure translation.
1717 m_patch.transform(m_dragPlanes.evaluateTransform(vector4_to_vector3(matrix.t())));
1722 void selectPlanes(Selector &selector, SelectionTest &test, const PlaneCallback &selectedPlaneCallback)
1724 test.BeginMesh(localToWorld());
1726 m_dragPlanes.selectPlanes(m_patch.localAABB(), selector, test, selectedPlaneCallback);
1729 void selectReversedPlanes(Selector &selector, const SelectedPlanes &selectedPlanes)
1731 m_dragPlanes.selectReversedPlanes(m_patch.localAABB(), selector, selectedPlanes);
1735 void snapComponents(float snap)
1737 if (selectedVertices()) {
1739 for (PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i) {
1740 if ((*i).m_selectable.isSelected()) {
1744 m_patch.controlPointsChanged();
1748 void evaluateTransform()
1750 Matrix4 matrix(m_transform.calculateTransform());
1752 if (m_transform.getType() == TRANSFORM_PRIMITIVE) {
1753 m_patch.transform(matrix);
1755 transformComponents(matrix);
1759 void applyTransform()
1761 m_patch.revertTransform();
1762 evaluateTransform();
1763 m_patch.freezeTransform();
1766 typedef MemberCaller<PatchInstance, void(), &PatchInstance::applyTransform> ApplyTransformCaller;
1769 bool testLight(const RendererLight &light) const
1771 return light.testAABB(worldAABB());
1776 template<typename TokenImporter, typename TokenExporter>
1778 public scene::Node::Symbiot,
1779 public scene::Instantiable,
1780 public scene::Cloneable {
1781 typedef PatchNode<TokenImporter, TokenExporter> Self;
1784 InstanceTypeCastTable m_casts;
1788 NodeStaticCast<PatchNode, scene::Instantiable>::install(m_casts);
1789 NodeStaticCast<PatchNode, scene::Cloneable>::install(m_casts);
1790 NodeContainedCast<PatchNode, Snappable>::install(m_casts);
1791 NodeContainedCast<PatchNode, TransformNode>::install(m_casts);
1792 NodeContainedCast<PatchNode, Patch>::install(m_casts);
1793 NodeContainedCast<PatchNode, XMLImporter>::install(m_casts);
1794 NodeContainedCast<PatchNode, XMLExporter>::install(m_casts);
1795 NodeContainedCast<PatchNode, MapImporter>::install(m_casts);
1796 NodeContainedCast<PatchNode, MapExporter>::install(m_casts);
1797 NodeContainedCast<PatchNode, Nameable>::install(m_casts);
1800 InstanceTypeCastTable &get()
1808 InstanceSet m_instances;
1810 TokenImporter m_importMap;
1811 TokenExporter m_exportMap;
1815 typedef LazyStatic<TypeCasts> StaticTypeCasts;
1817 Snappable &get(NullType<Snappable>)
1822 TransformNode &get(NullType<TransformNode>)
1827 Patch &get(NullType<Patch>)
1832 XMLImporter &get(NullType<XMLImporter>)
1837 XMLExporter &get(NullType<XMLExporter>)
1842 MapImporter &get(NullType<MapImporter>)
1847 MapExporter &get(NullType<MapExporter>)
1852 Nameable &get(NullType<Nameable>)
1857 PatchNode(bool patchDef3 = false) :
1858 m_node(this, this, StaticTypeCasts::instance().get()),
1859 m_patch(m_node, InstanceSetEvaluateTransform<PatchInstance>::Caller(m_instances),
1860 InstanceSet::BoundsChangedCaller(m_instances)),
1861 m_importMap(m_patch),
1862 m_exportMap(m_patch)
1864 m_patch.m_patchDef3 = patchDef3;
1867 PatchNode(const PatchNode &other) :
1868 scene::Node::Symbiot(other),
1869 scene::Instantiable(other),
1870 scene::Cloneable(other),
1871 m_node(this, this, StaticTypeCasts::instance().get()),
1872 m_patch(other.m_patch, m_node, InstanceSetEvaluateTransform<PatchInstance>::Caller(m_instances),
1873 InstanceSet::BoundsChangedCaller(m_instances)),
1874 m_importMap(m_patch),
1875 m_exportMap(m_patch)
1894 const Patch &get() const
1899 scene::Node &clone() const
1901 return (new PatchNode(*this))->node();
1904 scene::Instance *create(const scene::Path &path, scene::Instance *parent)
1906 return new PatchInstance(path, parent, m_patch);
1909 void forEachInstance(const scene::Instantiable::Visitor &visitor)
1911 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);
1919 scene::Instance *erase(scene::Instantiable::Observer *observer, const scene::Path &path)
1921 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 {
1941 const Functor &m_functor;
1943 PatchSelectedVisitor(const Functor &functor) : m_functor(functor)
1947 void visit(scene::Instance &instance) const
1949 PatchInstance *patch = Instance_getPatch(instance);
1956 template<typename Functor>
1957 inline void Scene_forEachSelectedPatch(const Functor &functor)
1959 GlobalSelectionSystem().foreachSelected(PatchSelectedVisitor<Functor>(functor));
1963 template<typename Functor>
1964 class PatchVisibleSelectedVisitor : public SelectionSystem::Visitor {
1965 const Functor &m_functor;
1967 PatchVisibleSelectedVisitor(const Functor &functor) : m_functor(functor)
1971 void visit(scene::Instance &instance) const
1973 PatchInstance *patch = Instance_getPatch(instance);
1975 && instance.path().top().get().visible()) {
1981 template<typename Functor>
1982 inline void Scene_forEachVisibleSelectedPatchInstance(const Functor &functor)
1984 GlobalSelectionSystem().foreachSelected(PatchVisibleSelectedVisitor<Functor>(functor));
1987 template<typename Functor>
1988 class PatchForEachWalker : public scene::Graph::Walker {
1989 const Functor &m_functor;
1991 PatchForEachWalker(const Functor &functor) : m_functor(functor)
1995 bool pre(const scene::Path &path, scene::Instance &instance) const
1997 if (path.top().get().visible()) {
1998 Patch *patch = Node_getPatch(path.top());
2007 template<typename Functor>
2008 inline void Scene_forEachVisiblePatch(const Functor &functor)
2010 GlobalSceneGraph().traverse(PatchForEachWalker<Functor>(functor));
2013 template<typename Functor>
2014 class PatchForEachSelectedWalker : public scene::Graph::Walker {
2015 const Functor &m_functor;
2017 PatchForEachSelectedWalker(const Functor &functor) : m_functor(functor)
2021 bool pre(const scene::Path &path, scene::Instance &instance) const
2023 if (path.top().get().visible()) {
2024 Patch *patch = Node_getPatch(path.top());
2026 && 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 {
2042 const Functor &m_functor;
2044 PatchForEachInstanceWalker(const Functor &functor) : m_functor(functor)
2048 bool pre(const scene::Path &path, scene::Instance &instance) const
2050 if (path.top().get().visible()) {
2051 PatchInstance *patch = Instance_getPatch(instance);
2060 template<typename Functor>
2061 inline void Scene_forEachVisiblePatchInstance(const Functor &functor)
2063 GlobalSceneGraph().traverse(PatchForEachInstanceWalker<Functor>(functor));