2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #if !defined( INCLUDED_PATCH_H )
23 #define INCLUDED_PATCH_H
26 /// \brief The patch primitive.
28 /// A 2-dimensional matrix of vertices that define a quadratic bezier surface.
29 /// The Boundary-Representation of this primitive is a triangle mesh.
30 /// The surface is recursively tesselated until the angle between each triangle
31 /// edge is smaller than a specified tolerance.
39 #include "renderable.h"
41 #include "selectable.h"
43 #include "debugging/debugging.h"
48 #include "math/frustum.h"
49 #include "string/string.h"
50 #include "stream/stringstream.h"
51 #include "stream/textstream.h"
52 #include "xml/xmlelement.h"
54 #include "transformlib.h"
55 #include "instancelib.h"
56 #include "selectionlib.h"
57 #include "traverselib.h"
60 #include "shaderlib.h"
61 #include "generic/callback.h"
62 #include "signal/signalfwd.h"
63 #include "texturelib.h"
65 #include "dragplanes.h"
73 extern int g_PatchSubdivideThreshold;
76 #define MIN_PATCH_WIDTH 3
77 #define MIN_PATCH_HEIGHT 3
79 extern std::size_t MAX_PATCH_WIDTH;
80 extern std::size_t MAX_PATCH_HEIGHT;
82 #define MAX_PATCH_ROWCTRL ( ( ( MAX_PATCH_WIDTH - 1 ) - 1 ) / 2 )
83 #define MAX_PATCH_COLCTRL ( ( ( MAX_PATCH_HEIGHT - 1 ) - 1 ) / 2 )
122 const std::size_t BEZIERCURVETREE_MAX_INDEX = std::size_t( 1 ) << ( std::numeric_limits<std::size_t>::digits - 1 );
124 struct BezierCurveTree
127 BezierCurveTree* left;
128 BezierCurveTree* right;
131 inline bool BezierCurveTree_isLeaf( const BezierCurveTree* node ){
132 return node->left == 0 && node->right == 0;
135 void BezierCurveTree_Delete( BezierCurveTree *pCurve );
138 inline VertexPointer vertexpointer_arbitrarymeshvertex( const ArbitraryMeshVertex* array ){
139 return VertexPointer( VertexPointer::pointer( &array->vertex ), sizeof( ArbitraryMeshVertex ) );
142 typedef PatchControl* PatchControlIter;
143 typedef const PatchControl* PatchControlConstIter;
145 inline void copy_ctrl( PatchControlIter ctrl, PatchControlConstIter begin, PatchControlConstIter end ){
146 std::copy( begin, end, ctrl );
149 const Colour4b colour_corner( 0, 255, 0, 255 );
150 const Colour4b colour_inside( 255, 0, 255, 255 );
157 virtual bool filter( const Patch& patch ) const = 0;
160 bool patch_filtered( Patch& patch );
161 void add_patch_filter( PatchFilter& filter, int mask, bool invert = false );
163 void Patch_addTextureChangedCallback( const SignalHandler& handler );
164 void Patch_textureChanged();
166 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 ){
174 Array<PatchControl> tmp( width );
176 PatchControlIter from = ctrl.data() + ( width * ( height - 1 ) );
177 PatchControlIter to = ctrl.data();
178 for ( std::size_t h = 0; h != ( ( height - 1 ) >> 1 ); ++h, to += width, from -= width )
180 copy_ctrl( tmp.data(), to, to + width );
181 copy_ctrl( to, from, from + width );
182 copy_ctrl( from, tmp.data(), tmp.data() + width );
186 class PatchTesselation
190 : m_numStrips( 0 ), m_lenStrips( 0 ), m_nArrayWidth( 0 ), m_nArrayHeight( 0 ){
192 Array<ArbitraryMeshVertex> m_vertices;
193 Array<RenderIndex> m_indices;
194 std::size_t m_numStrips;
195 std::size_t m_lenStrips;
197 Array<std::size_t> m_arrayWidth;
198 std::size_t m_nArrayWidth;
199 Array<std::size_t> m_arrayHeight;
200 std::size_t m_nArrayHeight;
202 Array<BezierCurveTree*> m_curveTreeU;
203 Array<BezierCurveTree*> m_curveTreeV;
206 class RenderablePatchWireframe : public OpenGLRenderable
208 PatchTesselation& m_tess;
210 RenderablePatchWireframe( PatchTesselation& tess ) : m_tess( tess ){
212 void render( RenderStateFlags state ) const {
215 glVertexPointer( 3, GL_FLOAT, 0, 0 );
216 glDrawArrays( GL_TRIANGLE_FAN, 0, 0 );
220 glVertexPointer( 3, GL_FLOAT, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->vertex );
221 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 )
243 glVertexPointer( 3, GL_FLOAT, GLsizei( n ), &p->vertex );
244 glDrawArrays( GL_LINE_STRIP, 0, GLsizei( m_tess.m_nArrayHeight ) );
246 if ( i == m_tess.m_curveTreeU.size() ) {
250 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 ){
267 void render( RenderStateFlags state ) const {
268 glVertexPointer( 3, GL_FLOAT, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->vertex );
269 const RenderIndex* strip_indices = m_tess.m_indices.data();
270 for ( std::size_t i = 0; i < m_tess.m_numStrips; i++, strip_indices += m_tess.m_lenStrips )
272 glDrawElements( GL_QUAD_STRIP, GLsizei( m_tess.m_lenStrips ), RenderIndexTypeID, strip_indices );
277 class RenderablePatchSolid : public OpenGLRenderable
279 PatchTesselation& m_tess;
281 RenderablePatchSolid( PatchTesselation& tess ) : m_tess( tess ){
283 void render( RenderStateFlags state ) const {
284 if ( ( state & RENDER_BUMP ) != 0 ) {
285 if ( GlobalShaderCache().useShaderLanguage() ) {
286 glNormalPointer( GL_FLOAT, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->normal );
287 glVertexAttribPointerARB( c_attr_TexCoord0, 2, GL_FLOAT, 0, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->texcoord );
288 glVertexAttribPointerARB( c_attr_Tangent, 3, GL_FLOAT, 0, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->tangent );
289 glVertexAttribPointerARB( c_attr_Binormal, 3, GL_FLOAT, 0, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->bitangent );
293 glVertexAttribPointerARB( 11, 3, GL_FLOAT, 0, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->normal );
294 glVertexAttribPointerARB( 8, 2, GL_FLOAT, 0, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->texcoord );
295 glVertexAttribPointerARB( 9, 3, GL_FLOAT, 0, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->tangent );
296 glVertexAttribPointerARB( 10, 3, GL_FLOAT, 0, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->bitangent );
301 glNormalPointer( GL_FLOAT, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->normal );
302 glTexCoordPointer( 2, GL_FLOAT, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->texcoord );
304 glVertexPointer( 3, GL_FLOAT, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->vertex );
305 const RenderIndex* strip_indices = m_tess.m_indices.data();
306 for ( std::size_t i = 0; i < m_tess.m_numStrips; i++, strip_indices += m_tess.m_lenStrips )
308 glDrawElements( GL_QUAD_STRIP, GLsizei( m_tess.m_lenStrips ), RenderIndexTypeID, strip_indices );
313 // parametric surface defined by quadratic bezier control curves
317 public TransformNode,
335 xml_state_t( EState state )
338 EState state() const {
341 const char* content() const {
342 return m_content.c_str();
344 std::size_t write( const char* buffer, std::size_t length ){
345 return m_content.write( buffer, length );
349 StringOutputStream m_content;
352 std::vector<xml_state_t> m_xml_state;
354 typedef Array<PatchControl> PatchControlArray;
356 class SavedState : public UndoMemento
362 const PatchControlArray& ctrl,
365 std::size_t subdivisions_x,
366 std::size_t subdivisions_y
372 m_patchDef3( patchDef3 ),
373 m_subdivisions_x( subdivisions_x ),
374 m_subdivisions_y( subdivisions_y ){
381 std::size_t m_width, m_height;
382 CopiedString m_shader;
383 PatchControlArray m_ctrl;
385 std::size_t m_subdivisions_x;
386 std::size_t m_subdivisions_y;
393 virtual void allocate( std::size_t size ) = 0;
397 typedef UniqueSet<Observer*> Observers;
398 Observers m_observers;
402 AABB m_aabb_local; // local bbox
404 CopiedString m_shader;
408 std::size_t m_height;
411 std::size_t m_subdivisions_x;
412 std::size_t m_subdivisions_y;
415 UndoObserver* m_undoable_observer;
418 // dynamically allocated array of control points, size is m_width*m_height
419 PatchControlArray m_ctrl;
420 PatchControlArray m_ctrlTransformed;
422 PatchTesselation m_tess;
423 RenderablePatchSolid m_render_solid;
424 RenderablePatchWireframe m_render_wireframe;
425 RenderablePatchFixedWireframe m_render_wireframe_fixed;
427 static Shader* m_state_ctrl;
428 static Shader* m_state_lattice;
429 VertexBuffer<PointVertex> m_ctrl_vertices;
430 RenderableVertexBuffer m_render_ctrl;
431 IndexBuffer m_lattice_indices;
432 RenderableIndexBuffer m_render_lattice;
436 bool m_transformChanged;
437 Callback m_evaluateTransform;
438 Callback m_boundsChanged;
442 m_width = m_height = 0;
445 m_subdivisions_x = 0;
446 m_subdivisions_y = 0;
451 m_xml_state.push_back( xml_state_t::eDefault );
455 Callback m_lightsChanged;
457 static int m_CycleCapIndex; // = 0;
458 static EPatchType m_type;
460 STRING_CONSTANT( Name, "Patch" );
462 Patch( scene::Node& node, const Callback& evaluateTransform, const Callback& boundsChanged ) :
464 m_shader( texdef_name_default() ),
466 m_undoable_observer( 0 ),
468 m_render_solid( m_tess ),
469 m_render_wireframe( m_tess ),
470 m_render_wireframe_fixed( m_tess ),
471 m_render_ctrl( GL_POINTS, m_ctrl_vertices ),
472 m_render_lattice( GL_LINES, m_lattice_indices, m_ctrl_vertices ),
473 m_transformChanged( false ),
474 m_evaluateTransform( evaluateTransform ),
475 m_boundsChanged( boundsChanged ){
478 Patch( const Patch& other, scene::Node& node, const Callback& evaluateTransform, const Callback& boundsChanged ) :
480 m_shader( texdef_name_default() ),
482 m_undoable_observer( 0 ),
484 m_render_solid( m_tess ),
485 m_render_wireframe( m_tess ),
486 m_render_wireframe_fixed( m_tess ),
487 m_render_ctrl( GL_POINTS, m_ctrl_vertices ),
488 m_render_lattice( GL_LINES, m_lattice_indices, m_ctrl_vertices ),
489 m_transformChanged( false ),
490 m_evaluateTransform( evaluateTransform ),
491 m_boundsChanged( boundsChanged ){
494 m_patchDef3 = other.m_patchDef3;
495 m_subdivisions_x = other.m_subdivisions_x;
496 m_subdivisions_y = other.m_subdivisions_y;
497 setDims( other.m_width, other.m_height );
498 copy_ctrl( m_ctrl.data(), other.m_ctrl.data(), other.m_ctrl.data() + ( m_width * m_height ) );
499 SetShader( other.m_shader.c_str() );
500 controlPointsChanged();
503 Patch( const Patch& other ) :
504 XMLImporter( other ),
505 XMLExporter( other ),
506 TransformNode( other ),
514 m_undoable_observer( 0 ),
516 m_render_solid( m_tess ),
517 m_render_wireframe( m_tess ),
518 m_render_wireframe_fixed( m_tess ),
519 m_render_ctrl( GL_POINTS, m_ctrl_vertices ),
520 m_render_lattice( GL_LINES, m_lattice_indices, m_ctrl_vertices ),
521 m_transformChanged( false ),
522 m_evaluateTransform( other.m_evaluateTransform ),
523 m_boundsChanged( other.m_boundsChanged ){
526 m_patchDef3 = other.m_patchDef3;
527 m_subdivisions_x = other.m_subdivisions_x;
528 m_subdivisions_y = other.m_subdivisions_y;
529 setDims( other.m_width, other.m_height );
530 copy_ctrl( m_ctrl.data(), other.m_ctrl.data(), other.m_ctrl.data() + ( m_width * m_height ) );
531 SetShader( other.m_shader.c_str() );
532 controlPointsChanged();
536 BezierCurveTreeArray_deleteAll( m_tess.m_curveTreeU );
537 BezierCurveTreeArray_deleteAll( m_tess.m_curveTreeV );
541 ASSERT_MESSAGE( m_observers.empty(), "Patch::~Patch: observers still attached" );
544 InstanceCounter m_instanceCounter;
545 void instanceAttach( const scene::Path& path ){
546 if ( ++m_instanceCounter.m_count == 1 ) {
547 m_state->incrementUsed();
548 m_map = path_find_mapfile( path.begin(), path.end() );
549 m_undoable_observer = GlobalUndoSystem().observer( this );
550 GlobalFilterSystem().registerFilterable( *this );
554 ASSERT_MESSAGE( path_find_mapfile( path.begin(), path.end() ) == m_map, "node is instanced across more than one file" );
557 void instanceDetach( const scene::Path& path ){
558 if ( --m_instanceCounter.m_count == 0 ) {
560 m_undoable_observer = 0;
561 GlobalUndoSystem().release( this );
562 GlobalFilterSystem().unregisterFilterable( *this );
563 m_state->decrementUsed();
567 const char* name() const {
570 void attach( const NameCallback& callback ){
572 void detach( const NameCallback& callback ){
575 void attach( Observer* observer ){
576 observer->allocate( m_width * m_height );
578 m_observers.insert( observer );
580 void detach( Observer* observer ){
581 m_observers.erase( observer );
584 void updateFiltered(){
586 if ( patch_filtered( *this ) ) {
587 m_node->enable( scene::Node::eFiltered );
591 m_node->disable( scene::Node::eFiltered );
596 void onAllocate( std::size_t size ){
597 for ( Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i )
599 ( *i )->allocate( size );
603 const Matrix4& localToParent() const {
604 return g_matrix4_identity;
606 const AABB& localAABB() const {
609 VolumeIntersectionValue intersectVolume( const VolumeTest& test, const Matrix4& localToWorld ) const {
610 return test.TestAABB( m_aabb_local, localToWorld );
612 void render_solid( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld ) const {
613 renderer.SetState( m_state, Renderer::eFullMaterials );
614 renderer.addRenderable( m_render_solid, localToWorld );
616 void render_wireframe( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld ) const {
617 renderer.SetState( m_state, Renderer::eFullMaterials );
619 renderer.addRenderable( m_render_wireframe_fixed, localToWorld );
623 renderer.addRenderable( m_render_wireframe, localToWorld );
627 void render_component( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld ) const {
628 renderer.SetState( m_state_lattice, Renderer::eWireframeOnly );
629 renderer.SetState( m_state_lattice, Renderer::eFullMaterials );
630 renderer.addRenderable( m_render_lattice, localToWorld );
632 renderer.SetState( m_state_ctrl, Renderer::eWireframeOnly );
633 renderer.SetState( m_state_ctrl, Renderer::eFullMaterials );
634 renderer.addRenderable( m_render_ctrl, localToWorld );
636 void testSelect( Selector& selector, SelectionTest& test ){
637 SelectionIntersection best;
638 IndexPointer::index_type* pIndex = m_tess.m_indices.data();
639 for ( std::size_t s = 0; s < m_tess.m_numStrips; s++ )
641 test.TestQuadStrip( vertexpointer_arbitrarymeshvertex( m_tess.m_vertices.data() ), IndexPointer( pIndex, m_tess.m_lenStrips ), best );
642 pIndex += m_tess.m_lenStrips;
644 if ( best.valid() ) {
645 selector.addIntersection( best );
648 void transform( const Matrix4& matrix ){
649 for ( PatchControlIter i = m_ctrlTransformed.data(); i != m_ctrlTransformed.data() + m_ctrlTransformed.size(); ++i )
651 matrix4_transform_point( matrix, ( *i ).m_vertex );
654 if ( matrix4_handedness( matrix ) == MATRIX4_LEFTHANDED ) {
655 PatchControlArray_invert( m_ctrlTransformed, m_width, m_height );
659 void transformChanged(){
660 m_transformChanged = true;
664 typedef MemberCaller<Patch, &Patch::transformChanged> TransformChangedCaller;
666 void evaluateTransform(){
667 if ( m_transformChanged ) {
668 m_transformChanged = false;
670 m_evaluateTransform();
674 void revertTransform(){
675 m_ctrlTransformed = m_ctrl;
677 void freezeTransform(){
680 ASSERT_MESSAGE( m_ctrlTransformed.size() == m_ctrl.size(), "Patch::freeze: size mismatch" );
681 std::copy( m_ctrlTransformed.begin(), m_ctrlTransformed.end(), m_ctrl.begin() );
684 void controlPointsChanged(){
689 bool isValid() const;
691 void snapto( float snap ){
694 for ( PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i )
696 vector3_snap( ( *i ).m_vertex, snap );
699 controlPointsChanged();
705 void RenderDebug( RenderStateFlags state ) const;
707 void pushElement( const XMLElement& element ){
708 switch ( m_xml_state.back().state() )
710 case xml_state_t::eDefault:
711 ASSERT_MESSAGE( string_equal( element.name(), "patch" ), "parse error" );
712 m_xml_state.push_back( xml_state_t::ePatch );
714 case xml_state_t::ePatch:
715 if ( string_equal( element.name(), "matrix" ) ) {
716 setDims( atoi( element.attribute( "width" ) ), atoi( element.attribute( "height" ) ) );
717 m_xml_state.push_back( xml_state_t::eMatrix );
719 else if ( string_equal( element.name(), "shader" ) ) {
720 m_xml_state.push_back( xml_state_t::eShader );
724 ERROR_MESSAGE( "parse error" );
728 void popElement( const char* name ){
729 switch ( m_xml_state.back().state() )
731 case xml_state_t::eDefault:
732 ERROR_MESSAGE( "parse error" );
734 case xml_state_t::ePatch:
736 case xml_state_t::eMatrix:
738 StringTokeniser content( m_xml_state.back().content() );
740 for ( PatchControlIter i = m_ctrl.data(), end = m_ctrl.data() + m_ctrl.size(); i != end; ++i )
742 ( *i ).m_vertex[0] = string_read_float( content.getToken() );
743 ( *i ).m_vertex[1] = string_read_float( content.getToken() );
744 ( *i ).m_vertex[2] = string_read_float( content.getToken() );
745 ( *i ).m_texcoord[0] = string_read_float( content.getToken() );
746 ( *i ).m_texcoord[1] = string_read_float( content.getToken() );
748 controlPointsChanged();
751 case xml_state_t::eShader:
753 SetShader( m_xml_state.back().content() );
757 ERROR_MESSAGE( "parse error" );
760 ASSERT_MESSAGE( !m_xml_state.empty(), "popping empty stack" );
761 m_xml_state.pop_back();
763 std::size_t write( const char* buffer, std::size_t length ){
764 switch ( m_xml_state.back().state() )
766 case xml_state_t::eDefault:
768 case xml_state_t::ePatch:
770 case xml_state_t::eMatrix:
771 case xml_state_t::eShader:
772 return m_xml_state.back().write( buffer, length );
775 ERROR_MESSAGE( "parse error" );
780 void exportXML( XMLImporter& importer ){
781 StaticElement patchElement( "patch" );
782 importer.pushElement( patchElement );
785 const StaticElement element( "shader" );
786 importer.pushElement( element );
787 importer.write( m_shader.c_str(), strlen( m_shader.c_str() ) );
788 importer.popElement( element.name() );
792 char width[16], height[16];
793 sprintf( width, "%u", Unsigned( m_width ) );
794 sprintf( height, "%u", Unsigned( m_height ) );
795 StaticElement element( "matrix" );
796 element.insertAttribute( "width", width );
797 element.insertAttribute( "height", height );
799 importer.pushElement( element );
801 for ( PatchControlIter i = m_ctrl.data(), end = m_ctrl.data() + m_ctrl.size(); i != end; ++i )
803 importer << ( *i ).m_vertex[0]
804 << ' ' << ( *i ).m_vertex[1]
805 << ' ' << ( *i ).m_vertex[2]
806 << ' ' << ( *i ).m_texcoord[0]
807 << ' ' << ( *i ).m_texcoord[1];
810 importer.popElement( element.name() );
813 importer.popElement( patchElement.name() );
816 void UpdateCachedData();
818 const char *GetShader() const {
819 return m_shader.c_str();
821 void SetShader( const char* name ){
822 ASSERT_NOTNULL( name );
824 if ( shader_equal( m_shader.c_str(), name ) ) {
830 if ( m_instanceCounter.m_count != 0 ) {
831 m_state->decrementUsed();
836 if ( m_instanceCounter.m_count != 0 ) {
837 m_state->incrementUsed();
841 Patch_textureChanged();
843 int getShaderFlags() const {
844 if ( m_state != 0 ) {
845 return m_state->getFlags();
850 typedef PatchControl* iterator;
851 typedef const PatchControl* const_iterator;
854 return m_ctrl.data();
856 const_iterator begin() const {
857 return m_ctrl.data();
860 return m_ctrl.data() + m_ctrl.size();
862 const_iterator end() const {
863 return m_ctrl.data() + m_ctrl.size();
866 PatchControlArray& getControlPoints(){
869 PatchControlArray& getControlPointsTransformed(){
870 return m_ctrlTransformed;
873 void setDims( std::size_t w, std::size_t h );
874 std::size_t getWidth() const {
877 std::size_t getHeight() const {
880 PatchControl& ctrlAt( std::size_t row, std::size_t col ){
881 return m_ctrl[row * m_width + col];
883 const PatchControl& ctrlAt( std::size_t row, std::size_t col ) const {
884 return m_ctrl[row * m_width + col];
887 void ConstructPrefab( const AABB& aabb, EPatchPrefab eType, int axis, std::size_t width = 3, std::size_t height = 3 );
888 void constructPlane( const AABB& aabb, int axis, std::size_t width, std::size_t height );
890 void TransposeMatrix();
891 void Redisperse( EMatrixMajor mt );
892 void Smooth( EMatrixMajor mt );
893 void InsertRemove( bool bInsert, bool bColumn, bool bFirst );
894 Patch* MakeCap( Patch* patch, EPatchCap eType, EMatrixMajor mt, bool bFirst );
895 void ConstructSeam( EPatchCap eType, Vector3* p, std::size_t width );
897 void FlipTexture( int nAxis );
898 void TranslateTexture( float s, float t );
899 void ScaleTexture( float s, float t );
900 void RotateTexture( float angle );
901 void SetTextureRepeat( float s, float t ); // call with s=1 t=1 for FIT
903 void NaturalTexture();
904 void ProjectTexture( int nAxis );
910 if ( m_undoable_observer != 0 ) {
911 m_undoable_observer->save( this );
915 UndoMemento* exportState() const {
916 return new SavedState( m_width, m_height, m_ctrl, m_shader.c_str(), m_patchDef3, m_subdivisions_x, m_subdivisions_y );
918 void importState( const UndoMemento* state ){
921 const SavedState& other = *( static_cast<const SavedState*>( state ) );
923 // begin duplicate of SavedState copy constructor, needs refactoring
927 m_width = other.m_width;
928 m_height = other.m_height;
929 SetShader( other.m_shader.c_str() );
930 m_ctrl = other.m_ctrl;
931 onAllocate( m_ctrl.size() );
932 m_patchDef3 = other.m_patchDef3;
933 m_subdivisions_x = other.m_subdivisions_x;
934 m_subdivisions_y = other.m_subdivisions_y;
937 // end duplicate code
939 Patch_textureChanged();
941 controlPointsChanged();
944 static void constructStatic( EPatchType type ){
945 Patch::m_type = type;
946 Patch::m_state_ctrl = GlobalShaderCache().capture( "$POINT" );
947 Patch::m_state_lattice = GlobalShaderCache().capture( "$LATTICE" );
950 static void destroyStatic(){
951 GlobalShaderCache().release( "$LATTICE" );
952 GlobalShaderCache().release( "$POINT" );
955 void captureShader(){
956 m_state = GlobalShaderCache().capture( m_shader.c_str() );
959 void releaseShader(){
960 GlobalShaderCache().release( m_shader.c_str() );
964 if ( !shader_valid( GetShader() ) ) {
965 globalErrorStream() << "patch has invalid texture name: '" << GetShader() << "'\n";
969 void InsertPoints( EMatrixMajor mt, bool bFirst );
970 void RemovePoints( EMatrixMajor mt, bool bFirst );
972 void AccumulateBBox();
974 void TesselateSubMatrixFixed( ArbitraryMeshVertex * vertices, std::size_t strideX, std::size_t strideY, unsigned int nFlagsX, unsigned int nFlagsY, PatchControl * subMatrix[3][3] );
976 // uses binary trees representing bezier curves to recursively tesselate a bezier sub-patch
977 void TesselateSubMatrix( const BezierCurveTree *BX, const BezierCurveTree *BY,
978 std::size_t offStartX, std::size_t offStartY,
979 std::size_t offEndX, std::size_t offEndY,
980 std::size_t nFlagsX, std::size_t nFlagsY,
981 Vector3& left, Vector3& mid, Vector3& right,
982 Vector2& texLeft, Vector2& texMid, Vector2& texRight,
985 // tesselates the entire surface
986 void BuildTesselationCurves( EMatrixMajor major );
987 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 );
988 void BuildVertexArray();
991 inline bool Patch_importHeader( Patch& patch, Tokeniser& tokeniser ){
992 tokeniser.nextLine();
993 RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "{" ) );
997 inline bool Patch_importShader( Patch& patch, Tokeniser& tokeniser ){
999 tokeniser.nextLine();
1000 const char* texture = tokeniser.getToken();
1001 if ( texture == 0 ) {
1002 Tokeniser_unexpectedError( tokeniser, texture, "#texture-name" );
1005 if ( string_equal( texture, "NULL" ) ) {
1006 patch.SetShader( texdef_name_default() );
1010 StringOutputStream shader( string_length( GlobalTexturePrefix_get() ) + string_length( texture ) );
1011 shader << GlobalTexturePrefix_get() << texture;
1012 patch.SetShader( shader.c_str() );
1017 inline bool PatchDoom3_importShader( Patch& patch, Tokeniser& tokeniser ){
1018 // parse shader name
1019 tokeniser.nextLine();
1020 const char *shader = tokeniser.getToken();
1021 if ( shader == 0 ) {
1022 Tokeniser_unexpectedError( tokeniser, shader, "#shader-name" );
1025 if ( string_equal( shader, "_emptyname" ) ) {
1026 shader = texdef_name_default();
1028 patch.SetShader( shader );
1032 inline bool Patch_importParams( Patch& patch, Tokeniser& tokeniser ){
1033 tokeniser.nextLine();
1034 RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "(" ) );
1036 // parse matrix dimensions
1039 RETURN_FALSE_IF_FAIL( Tokeniser_getSize( tokeniser, c ) );
1040 RETURN_FALSE_IF_FAIL( Tokeniser_getSize( tokeniser, r ) );
1042 patch.setDims( c, r );
1045 if ( patch.m_patchDef3 ) {
1046 RETURN_FALSE_IF_FAIL( Tokeniser_getSize( tokeniser, patch.m_subdivisions_x ) );
1047 RETURN_FALSE_IF_FAIL( Tokeniser_getSize( tokeniser, patch.m_subdivisions_y ) );
1050 // ignore contents/flags/value
1052 RETURN_FALSE_IF_FAIL( Tokeniser_getInteger( tokeniser, tmp ) );
1053 RETURN_FALSE_IF_FAIL( Tokeniser_getInteger( tokeniser, tmp ) );
1054 RETURN_FALSE_IF_FAIL( Tokeniser_getInteger( tokeniser, tmp ) );
1056 RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, ")" ) );
1060 inline bool Patch_importMatrix( Patch& patch, Tokeniser& tokeniser ){
1062 tokeniser.nextLine();
1063 RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "(" ) );
1065 for ( std::size_t c = 0; c < patch.getWidth(); c++ )
1067 tokeniser.nextLine();
1068 RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "(" ) );
1069 for ( std::size_t r = 0; r < patch.getHeight(); r++ )
1071 RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "(" ) );
1073 RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, patch.ctrlAt( r,c ).m_vertex[0] ) );
1074 RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, patch.ctrlAt( r,c ).m_vertex[1] ) );
1075 RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, patch.ctrlAt( r,c ).m_vertex[2] ) );
1076 RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, patch.ctrlAt( r,c ).m_texcoord[0] ) );
1077 RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, patch.ctrlAt( r,c ).m_texcoord[1] ) );
1079 RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, ")" ) );
1081 RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, ")" ) );
1084 tokeniser.nextLine();
1085 RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, ")" ) );
1089 inline bool Patch_importFooter( Patch& patch, Tokeniser& tokeniser ){
1090 patch.controlPointsChanged();
1092 tokeniser.nextLine();
1093 RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "}" ) );
1095 tokeniser.nextLine();
1096 RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "}" ) );
1100 class PatchTokenImporter : public MapImporter
1104 PatchTokenImporter( Patch& patch ) : m_patch( patch ){
1106 bool importTokens( Tokeniser& tokeniser ){
1107 RETURN_FALSE_IF_FAIL( Patch_importHeader( m_patch, tokeniser ) );
1108 RETURN_FALSE_IF_FAIL( Patch_importShader( m_patch, tokeniser ) );
1109 RETURN_FALSE_IF_FAIL( Patch_importParams( m_patch, tokeniser ) );
1110 RETURN_FALSE_IF_FAIL( Patch_importMatrix( m_patch, tokeniser ) );
1111 RETURN_FALSE_IF_FAIL( Patch_importFooter( m_patch, tokeniser ) );
1117 class PatchDoom3TokenImporter : public MapImporter
1121 PatchDoom3TokenImporter( Patch& patch ) : m_patch( patch ){
1123 bool importTokens( Tokeniser& tokeniser ){
1124 RETURN_FALSE_IF_FAIL( Patch_importHeader( m_patch, tokeniser ) );
1125 RETURN_FALSE_IF_FAIL( PatchDoom3_importShader( m_patch, tokeniser ) );
1126 RETURN_FALSE_IF_FAIL( Patch_importParams( m_patch, tokeniser ) );
1127 RETURN_FALSE_IF_FAIL( Patch_importMatrix( m_patch, tokeniser ) );
1128 RETURN_FALSE_IF_FAIL( Patch_importFooter( m_patch, tokeniser ) );
1134 inline void Patch_exportHeader( const Patch& patch, TokenWriter& writer ){
1135 writer.writeToken( "{" );
1137 writer.writeToken( patch.m_patchDef3 ? "patchDef3" : "patchDef2" );
1139 writer.writeToken( "{" );
1143 inline void Patch_exportShader( const Patch& patch, TokenWriter& writer ){
1144 // write shader name
1145 if ( *( shader_get_textureName( patch.GetShader() ) ) == '\0' ) {
1146 writer.writeToken( "NULL" );
1150 writer.writeToken( shader_get_textureName( patch.GetShader() ) );
1155 inline void PatchDoom3_exportShader( const Patch& patch, TokenWriter& writer ){
1156 // write shader name
1157 if ( *( shader_get_textureName( patch.GetShader() ) ) == '\0' ) {
1158 writer.writeString( "_emptyname" );
1162 writer.writeString( patch.GetShader() );
1167 inline void Patch_exportParams( const Patch& patch, TokenWriter& writer ){
1168 // write matrix dimensions
1169 writer.writeToken( "(" );
1170 writer.writeUnsigned( patch.getWidth() );
1171 writer.writeUnsigned( patch.getHeight() );
1172 if ( patch.m_patchDef3 ) {
1173 writer.writeUnsigned( patch.m_subdivisions_x );
1174 writer.writeUnsigned( patch.m_subdivisions_y );
1176 writer.writeInteger( 0 );
1177 writer.writeInteger( 0 );
1178 writer.writeInteger( 0 );
1179 writer.writeToken( ")" );
1183 inline void Patch_exportMatrix( const Patch& patch, TokenWriter& writer ){
1185 writer.writeToken( "(" );
1187 for ( std::size_t c = 0; c < patch.getWidth(); c++ )
1189 writer.writeToken( "(" );
1190 for ( std::size_t r = 0; r < patch.getHeight(); r++ )
1192 writer.writeToken( "(" );
1194 writer.writeFloat( patch.ctrlAt( r,c ).m_vertex[0] );
1195 writer.writeFloat( patch.ctrlAt( r,c ).m_vertex[1] );
1196 writer.writeFloat( patch.ctrlAt( r,c ).m_vertex[2] );
1197 writer.writeFloat( patch.ctrlAt( r,c ).m_texcoord[0] );
1198 writer.writeFloat( patch.ctrlAt( r,c ).m_texcoord[1] );
1200 writer.writeToken( ")" );
1202 writer.writeToken( ")" );
1205 writer.writeToken( ")" );
1209 inline void Patch_exportFooter( const Patch& patch, TokenWriter& writer ){
1210 writer.writeToken( "}" );
1212 writer.writeToken( "}" );
1216 class PatchTokenExporter : public MapExporter
1218 const Patch& m_patch;
1220 PatchTokenExporter( Patch& patch ) : m_patch( patch ){
1222 void exportTokens( TokenWriter& writer ) const {
1223 Patch_exportHeader( m_patch, writer );
1224 Patch_exportShader( m_patch, writer );
1225 Patch_exportParams( m_patch, writer );
1226 Patch_exportMatrix( m_patch, writer );
1227 Patch_exportFooter( m_patch, writer );
1231 class PatchDoom3TokenExporter : public MapExporter
1233 const Patch& m_patch;
1235 PatchDoom3TokenExporter( Patch& patch ) : m_patch( patch ){
1237 void exportTokens( TokenWriter& writer ) const {
1238 Patch_exportHeader( m_patch, writer );
1239 PatchDoom3_exportShader( m_patch, writer );
1240 Patch_exportParams( m_patch, writer );
1241 Patch_exportMatrix( m_patch, writer );
1242 Patch_exportFooter( m_patch, writer );
1246 class PatchControlInstance
1249 PatchControl* m_ctrl;
1250 ObservedSelectable m_selectable;
1252 PatchControlInstance( PatchControl* ctrl, const SelectionChangeCallback& observer )
1253 : m_ctrl( ctrl ), m_selectable( observer ){
1256 void testSelect( Selector& selector, SelectionTest& test ){
1257 SelectionIntersection best;
1258 test.TestPoint( m_ctrl->m_vertex, best );
1259 if ( best.valid() ) {
1260 Selector_add( selector, m_selectable, best );
1263 void snapto( float snap ){
1264 vector3_snap( m_ctrl->m_vertex, snap );
1269 class PatchInstance :
1270 public Patch::Observer,
1271 public scene::Instance,
1274 public SelectionTestable,
1275 public ComponentSelectionTestable,
1276 public ComponentEditable,
1277 public ComponentSnappable,
1278 public PlaneSelectable,
1279 public LightCullable
1283 InstanceTypeCastTable m_casts;
1286 InstanceStaticCast<PatchInstance, Selectable>::install( m_casts );
1287 InstanceContainedCast<PatchInstance, Bounded>::install( m_casts );
1288 InstanceContainedCast<PatchInstance, Cullable>::install( m_casts );
1289 InstanceStaticCast<PatchInstance, Renderable>::install( m_casts );
1290 InstanceStaticCast<PatchInstance, SelectionTestable>::install( m_casts );
1291 InstanceStaticCast<PatchInstance, ComponentSelectionTestable>::install( m_casts );
1292 InstanceStaticCast<PatchInstance, ComponentEditable>::install( m_casts );
1293 InstanceStaticCast<PatchInstance, ComponentSnappable>::install( m_casts );
1294 InstanceStaticCast<PatchInstance, PlaneSelectable>::install( m_casts );
1295 InstanceIdentityCast<PatchInstance>::install( m_casts );
1296 InstanceContainedCast<PatchInstance, Transformable>::install( m_casts );
1298 InstanceTypeCastTable& get(){
1305 typedef std::vector<PatchControlInstance> PatchControlInstances;
1306 PatchControlInstances m_ctrl_instances;
1308 ObservedSelectable m_selectable;
1310 DragPlanes m_dragPlanes;
1312 mutable RenderablePointVector m_render_selected;
1313 mutable AABB m_aabb_component;
1315 static Shader* m_state_selpoint;
1317 const LightList* m_lightList;
1319 TransformModifier m_transform;
1322 typedef LazyStatic<TypeCasts> StaticTypeCasts;
1324 void lightsChanged(){
1325 m_lightList->lightsChanged();
1327 typedef MemberCaller<PatchInstance, &PatchInstance::lightsChanged> LightsChangedCaller;
1329 STRING_CONSTANT( Name, "PatchInstance" );
1331 PatchInstance( const scene::Path& path, scene::Instance* parent, Patch& patch ) :
1332 Instance( path, parent, this, StaticTypeCasts::instance().get() ),
1334 m_selectable( SelectedChangedCaller( *this ) ),
1335 m_dragPlanes( SelectedChangedComponentCaller( *this ) ),
1336 m_render_selected( GL_POINTS ),
1337 m_transform( Patch::TransformChangedCaller( m_patch ), ApplyTransformCaller( *this ) ){
1338 m_patch.instanceAttach( Instance::path() );
1339 m_patch.attach( this );
1341 m_lightList = &GlobalShaderCache().attach( *this );
1342 m_patch.m_lightsChanged = LightsChangedCaller( *this );
1344 Instance::setTransformChangedCallback( LightsChangedCaller( *this ) );
1347 Instance::setTransformChangedCallback( Callback() );
1349 m_patch.m_lightsChanged = Callback();
1350 GlobalShaderCache().detach( *this );
1352 m_patch.detach( this );
1353 m_patch.instanceDetach( Instance::path() );
1356 void selectedChanged( const Selectable& selectable ){
1357 GlobalSelectionSystem().getObserver ( SelectionSystem::ePrimitive )( selectable );
1358 GlobalSelectionSystem().onSelectedChanged( *this, selectable );
1360 Instance::selectedChanged();
1362 typedef MemberCaller1<PatchInstance, const Selectable&, &PatchInstance::selectedChanged> SelectedChangedCaller;
1364 void selectedChangedComponent( const Selectable& selectable ){
1365 GlobalSelectionSystem().getObserver ( SelectionSystem::eComponent )( selectable );
1366 GlobalSelectionSystem().onComponentSelection( *this, selectable );
1368 typedef MemberCaller1<PatchInstance, const Selectable&, &PatchInstance::selectedChangedComponent> SelectedChangedComponentCaller;
1373 Bounded& get( NullType<Bounded>){
1376 Cullable& get( NullType<Cullable>){
1379 Transformable& get( NullType<Transformable>){
1383 static void constructStatic(){
1384 m_state_selpoint = GlobalShaderCache().capture( "$SELPOINT" );
1387 static void destroyStatic(){
1388 GlobalShaderCache().release( "$SELPOINT" );
1392 void allocate( std::size_t size ){
1393 m_ctrl_instances.clear();
1394 m_ctrl_instances.reserve( size );
1395 for ( Patch::iterator i = m_patch.begin(); i != m_patch.end(); ++i )
1397 m_ctrl_instances.push_back( PatchControlInstance( &( *i ), SelectedChangedComponentCaller( *this ) ) );
1401 void setSelected( bool select ){
1402 m_selectable.setSelected( select );
1404 bool isSelected() const {
1405 return m_selectable.isSelected();
1409 void update_selected() const {
1410 m_render_selected.clear();
1411 Patch::iterator ctrl = m_patch.getControlPointsTransformed().begin();
1412 for ( PatchControlInstances::const_iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i, ++ctrl )
1414 if ( ( *i ).m_selectable.isSelected() ) {
1415 const Colour4b colour_selected( 0, 0, 255, 255 );
1416 m_render_selected.push_back( PointVertex( reinterpret_cast<Vertex3f&>( ( *ctrl ).m_vertex ), colour_selected ) );
1421 void renderSolid( Renderer& renderer, const VolumeTest& volume ) const {
1422 m_patch.evaluateTransform();
1423 renderer.setLights( *m_lightList );
1424 m_patch.render_solid( renderer, volume, localToWorld() );
1426 renderComponentsSelected( renderer, volume );
1429 void renderWireframe( Renderer& renderer, const VolumeTest& volume ) const {
1430 m_patch.evaluateTransform();
1431 m_patch.render_wireframe( renderer, volume, localToWorld() );
1433 renderComponentsSelected( renderer, volume );
1436 void renderComponentsSelected( Renderer& renderer, const VolumeTest& volume ) const {
1437 m_patch.evaluateTransform();
1439 if ( !m_render_selected.empty() ) {
1440 renderer.Highlight( Renderer::ePrimitive, false );
1441 renderer.SetState( m_state_selpoint, Renderer::eWireframeOnly );
1442 renderer.SetState( m_state_selpoint, Renderer::eFullMaterials );
1443 renderer.addRenderable( m_render_selected, localToWorld() );
1446 void renderComponents( Renderer& renderer, const VolumeTest& volume ) const {
1447 m_patch.evaluateTransform();
1448 if ( GlobalSelectionSystem().ComponentMode() == SelectionSystem::eVertex ) {
1449 m_patch.render_component( renderer, volume, localToWorld() );
1453 void testSelect( Selector& selector, SelectionTest& test ){
1454 test.BeginMesh( localToWorld(), true );
1455 m_patch.testSelect( selector, test );
1458 void selectCtrl( bool select ){
1459 for ( PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i )
1461 ( *i ).m_selectable.setSelected( select );
1464 bool isSelectedComponents() const {
1465 for ( PatchControlInstances::const_iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i )
1467 if ( ( *i ).m_selectable.isSelected() ) {
1473 void setSelectedComponents( bool select, SelectionSystem::EComponentMode mode ){
1474 if ( mode == SelectionSystem::eVertex ) {
1475 selectCtrl( select );
1477 else if ( mode == SelectionSystem::eFace ) {
1478 m_dragPlanes.setSelected( select );
1481 const AABB& getSelectedComponentsBounds() const {
1482 m_aabb_component = AABB();
1484 for ( PatchControlInstances::const_iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i )
1486 if ( ( *i ).m_selectable.isSelected() ) {
1487 aabb_extend_by_point_safe( m_aabb_component, ( *i ).m_ctrl->m_vertex );
1491 return m_aabb_component;
1494 void testSelectComponents( Selector& selector, SelectionTest& test, SelectionSystem::EComponentMode mode ){
1495 test.BeginMesh( localToWorld() );
1499 case SelectionSystem::eVertex:
1501 for ( PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i )
1503 ( *i ).testSelect( selector, test );
1512 bool selectedVertices(){
1513 for ( PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i )
1515 if ( ( *i ).m_selectable.isSelected() ) {
1522 void transformComponents( const Matrix4& matrix ){
1523 if ( selectedVertices() ) {
1524 PatchControlIter ctrl = m_patch.getControlPointsTransformed().begin();
1525 for ( PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i, ++ctrl )
1527 if ( ( *i ).m_selectable.isSelected() ) {
1528 matrix4_transform_point( matrix, ( *ctrl ).m_vertex );
1531 m_patch.UpdateCachedData();
1534 if ( m_dragPlanes.isSelected() ) { // this should only be true when the transform is a pure translation.
1535 m_patch.transform( m_dragPlanes.evaluateTransform( vector4_to_vector3( matrix.t() ) ) );
1540 void selectPlanes( Selector& selector, SelectionTest& test, const PlaneCallback& selectedPlaneCallback ){
1541 test.BeginMesh( localToWorld() );
1543 m_dragPlanes.selectPlanes( m_patch.localAABB(), selector, test, selectedPlaneCallback );
1545 void selectReversedPlanes( Selector& selector, const SelectedPlanes& selectedPlanes ){
1546 m_dragPlanes.selectReversedPlanes( m_patch.localAABB(), selector, selectedPlanes );
1550 void snapComponents( float snap ){
1551 if ( selectedVertices() ) {
1553 for ( PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i )
1555 if ( ( *i ).m_selectable.isSelected() ) {
1556 ( *i ).snapto( snap );
1559 m_patch.controlPointsChanged();
1563 void evaluateTransform(){
1564 Matrix4 matrix( m_transform.calculateTransform() );
1566 if ( m_transform.getType() == TRANSFORM_PRIMITIVE ) {
1567 m_patch.transform( matrix );
1571 transformComponents( matrix );
1574 void applyTransform(){
1575 m_patch.revertTransform();
1576 evaluateTransform();
1577 m_patch.freezeTransform();
1579 typedef MemberCaller<PatchInstance, &PatchInstance::applyTransform> ApplyTransformCaller;
1582 bool testLight( const RendererLight& light ) const {
1583 return light.testAABB( worldAABB() );
1588 template<typename TokenImporter, typename TokenExporter>
1590 public scene::Node::Symbiot,
1591 public scene::Instantiable,
1592 public scene::Cloneable
1594 typedef PatchNode<TokenImporter, TokenExporter> Self;
1598 InstanceTypeCastTable m_casts;
1601 NodeStaticCast<PatchNode, scene::Instantiable>::install( m_casts );
1602 NodeStaticCast<PatchNode, scene::Cloneable>::install( m_casts );
1603 NodeContainedCast<PatchNode, Snappable>::install( m_casts );
1604 NodeContainedCast<PatchNode, TransformNode>::install( m_casts );
1605 NodeContainedCast<PatchNode, Patch>::install( m_casts );
1606 NodeContainedCast<PatchNode, XMLImporter>::install( m_casts );
1607 NodeContainedCast<PatchNode, XMLExporter>::install( m_casts );
1608 NodeContainedCast<PatchNode, MapImporter>::install( m_casts );
1609 NodeContainedCast<PatchNode, MapExporter>::install( m_casts );
1610 NodeContainedCast<PatchNode, Nameable>::install( m_casts );
1612 InstanceTypeCastTable& get(){
1619 InstanceSet m_instances;
1621 TokenImporter m_importMap;
1622 TokenExporter m_exportMap;
1626 typedef LazyStatic<TypeCasts> StaticTypeCasts;
1628 Snappable& get( NullType<Snappable>){
1631 TransformNode& get( NullType<TransformNode>){
1634 Patch& get( NullType<Patch>){
1637 XMLImporter& get( NullType<XMLImporter>){
1640 XMLExporter& get( NullType<XMLExporter>){
1643 MapImporter& get( NullType<MapImporter>){
1646 MapExporter& get( NullType<MapExporter>){
1649 Nameable& get( NullType<Nameable>){
1653 PatchNode( bool patchDef3 = false ) :
1654 m_node( this, this, StaticTypeCasts::instance().get() ),
1655 m_patch( m_node, InstanceSetEvaluateTransform<PatchInstance>::Caller( m_instances ), InstanceSet::BoundsChangedCaller( m_instances ) ),
1656 m_importMap( m_patch ),
1657 m_exportMap( m_patch ){
1658 m_patch.m_patchDef3 = patchDef3;
1660 PatchNode( const PatchNode& other ) :
1661 scene::Node::Symbiot( other ),
1662 scene::Instantiable( other ),
1663 scene::Cloneable( other ),
1664 m_node( this, this, StaticTypeCasts::instance().get() ),
1665 m_patch( other.m_patch, m_node, InstanceSetEvaluateTransform<PatchInstance>::Caller( m_instances ), InstanceSet::BoundsChangedCaller( m_instances ) ),
1666 m_importMap( m_patch ),
1667 m_exportMap( m_patch ){
1672 scene::Node& node(){
1678 const Patch& get() const {
1682 scene::Node& clone() const {
1683 return ( new PatchNode( *this ) )->node();
1686 scene::Instance* create( const scene::Path& path, scene::Instance* parent ){
1687 return new PatchInstance( path, parent, m_patch );
1689 void forEachInstance( const scene::Instantiable::Visitor& visitor ){
1690 m_instances.forEachInstance( visitor );
1692 void insert( scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance ){
1693 m_instances.insert( observer, path, instance );
1695 scene::Instance* erase( scene::Instantiable::Observer* observer, const scene::Path& path ){
1696 return m_instances.erase( observer, path );
1702 typedef PatchNode<PatchTokenImporter, PatchTokenExporter> PatchNodeQuake3;
1703 typedef PatchNode<PatchDoom3TokenImporter, PatchDoom3TokenExporter> PatchNodeDoom3;
1705 inline Patch* Node_getPatch( scene::Node& node ){
1706 return NodeTypeCast<Patch>::cast( node );
1709 inline PatchInstance* Instance_getPatch( scene::Instance& instance ){
1710 return InstanceTypeCast<PatchInstance>::cast( instance );
1713 template<typename Functor>
1714 class PatchSelectedVisitor : public SelectionSystem::Visitor
1716 const Functor& m_functor;
1718 PatchSelectedVisitor( const Functor& functor ) : m_functor( functor ){
1720 void visit( scene::Instance& instance ) const {
1721 PatchInstance* patch = Instance_getPatch( instance );
1723 m_functor( *patch );
1728 template<typename Functor>
1729 inline void Scene_forEachSelectedPatch( const Functor& functor ){
1730 GlobalSelectionSystem().foreachSelected( PatchSelectedVisitor<Functor>( functor ) );
1734 template<typename Functor>
1735 class PatchVisibleSelectedVisitor : public SelectionSystem::Visitor
1737 const Functor& m_functor;
1739 PatchVisibleSelectedVisitor( const Functor& functor ) : m_functor( functor ){
1741 void visit( scene::Instance& instance ) const {
1742 PatchInstance* patch = Instance_getPatch( instance );
1744 && instance.path().top().get().visible() ) {
1745 m_functor( *patch );
1750 template<typename Functor>
1751 inline void Scene_forEachVisibleSelectedPatchInstance( const Functor& functor ){
1752 GlobalSelectionSystem().foreachSelected( PatchVisibleSelectedVisitor<Functor>( functor ) );
1755 template<typename Functor>
1756 class PatchForEachWalker : public scene::Graph::Walker
1758 const Functor& m_functor;
1760 PatchForEachWalker( const Functor& functor ) : m_functor( functor ){
1762 bool pre( const scene::Path& path, scene::Instance& instance ) const {
1763 if ( path.top().get().visible() ) {
1764 Patch* patch = Node_getPatch( path.top() );
1766 m_functor( *patch );
1773 template<typename Functor>
1774 inline void Scene_forEachVisiblePatch( const Functor& functor ){
1775 GlobalSceneGraph().traverse( PatchForEachWalker<Functor>( functor ) );
1778 template<typename Functor>
1779 class PatchForEachSelectedWalker : public scene::Graph::Walker
1781 const Functor& m_functor;
1783 PatchForEachSelectedWalker( const Functor& functor ) : m_functor( functor ){
1785 bool pre( const scene::Path& path, scene::Instance& instance ) const {
1786 if ( path.top().get().visible() ) {
1787 Patch* patch = Node_getPatch( path.top() );
1789 && Instance_getSelectable( instance )->isSelected() ) {
1790 m_functor( *patch );
1797 template<typename Functor>
1798 inline void Scene_forEachVisibleSelectedPatch( const Functor& functor ){
1799 GlobalSceneGraph().traverse( PatchForEachSelectedWalker<Functor>( functor ) );
1802 template<typename Functor>
1803 class PatchForEachInstanceWalker : public scene::Graph::Walker
1805 const Functor& m_functor;
1807 PatchForEachInstanceWalker( const Functor& functor ) : m_functor( functor ){
1809 bool pre( const scene::Path& path, scene::Instance& instance ) const {
1810 if ( path.top().get().visible() ) {
1811 PatchInstance* patch = Instance_getPatch( instance );
1813 m_functor( *patch );
1820 template<typename Functor>
1821 inline void Scene_forEachVisiblePatchInstance( const Functor& functor ){
1822 GlobalSceneGraph().traverse( PatchForEachInstanceWalker<Functor>( functor ) );