2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #if !defined( INCLUDED_PATCH_H )
23 #define INCLUDED_PATCH_H
26 /// \brief The patch primitive.
28 /// A 2-dimensional matrix of vertices that define a quadratic bezier surface.
29 /// The Boundary-Representation of this primitive is a triangle mesh.
30 /// The surface is recursively tesselated until the angle between each triangle
31 /// edge is smaller than a specified tolerance.
39 #include "renderable.h"
41 #include "selectable.h"
43 #include "debugging/debugging.h"
47 #include <util/buffer.h>
49 #include "math/frustum.h"
50 #include "string/string.h"
51 #include "stream/stringstream.h"
52 #include "stream/textstream.h"
53 #include "xml/xmlelement.h"
55 #include "transformlib.h"
56 #include "instancelib.h"
57 #include "selectionlib.h"
58 #include "traverselib.h"
61 #include "shaderlib.h"
62 #include "generic/callback.h"
63 #include "signal/signalfwd.h"
64 #include "texturelib.h"
66 #include "dragplanes.h"
74 extern int g_PatchSubdivideThreshold;
77 #define MIN_PATCH_WIDTH 3
78 #define MIN_PATCH_HEIGHT 3
80 extern std::size_t MAX_PATCH_WIDTH;
81 extern std::size_t MAX_PATCH_HEIGHT;
83 #define MAX_PATCH_ROWCTRL ( ( ( MAX_PATCH_WIDTH - 1 ) - 1 ) / 2 )
84 #define MAX_PATCH_COLCTRL ( ( ( MAX_PATCH_HEIGHT - 1 ) - 1 ) / 2 )
123 const std::size_t BEZIERCURVETREE_MAX_INDEX = std::size_t( 1 ) << ( std::numeric_limits<std::size_t>::digits - 1 );
125 struct BezierCurveTree
128 BezierCurveTree* left;
129 BezierCurveTree* right;
132 inline bool BezierCurveTree_isLeaf( const BezierCurveTree* node ){
133 return node->left == 0 && node->right == 0;
136 void BezierCurveTree_Delete( BezierCurveTree *pCurve );
139 inline VertexPointer vertexpointer_arbitrarymeshvertex( const ArbitraryMeshVertex* array ){
140 return VertexPointer( VertexPointer::pointer( &array->vertex ), sizeof( ArbitraryMeshVertex ) );
143 typedef PatchControl* PatchControlIter;
144 typedef const PatchControl* PatchControlConstIter;
146 inline void copy_ctrl( PatchControlIter ctrl, PatchControlConstIter begin, PatchControlConstIter end ){
147 std::copy( begin, end, ctrl );
150 const Colour4b colour_corner( 0, 255, 0, 255 );
151 const Colour4b colour_inside( 255, 0, 255, 255 );
158 virtual bool filter( const Patch& patch ) const = 0;
161 bool patch_filtered( Patch& patch );
162 void add_patch_filter( PatchFilter& filter, int mask, bool invert = false );
164 void Patch_addTextureChangedCallback( const SignalHandler& handler );
165 void Patch_textureChanged();
167 inline void BezierCurveTreeArray_deleteAll( Array<BezierCurveTree*>& curveTrees ){
168 for ( Array<BezierCurveTree*>::iterator i = curveTrees.begin(); i != curveTrees.end(); ++i )
170 BezierCurveTree_Delete( *i );
174 inline void PatchControlArray_invert( Array<PatchControl>& ctrl, std::size_t width, std::size_t height ){
175 Array<PatchControl> tmp( width );
177 PatchControlIter from = ctrl.data() + ( width * ( height - 1 ) );
178 PatchControlIter to = ctrl.data();
179 for ( std::size_t h = 0; h != ( ( height - 1 ) >> 1 ); ++h, to += width, from -= width )
181 copy_ctrl( tmp.data(), to, to + width );
182 copy_ctrl( to, from, from + width );
183 copy_ctrl( from, tmp.data(), tmp.data() + width );
187 class PatchTesselation
191 : m_numStrips( 0 ), m_lenStrips( 0 ), m_nArrayWidth( 0 ), m_nArrayHeight( 0 ){
193 Array<ArbitraryMeshVertex> m_vertices;
194 Array<RenderIndex> m_indices;
195 std::size_t m_numStrips;
196 std::size_t m_lenStrips;
198 Array<std::size_t> m_arrayWidth;
199 std::size_t m_nArrayWidth;
200 Array<std::size_t> m_arrayHeight;
201 std::size_t m_nArrayHeight;
203 Array<BezierCurveTree*> m_curveTreeU;
204 Array<BezierCurveTree*> m_curveTreeV;
207 class RenderablePatchWireframe : public OpenGLRenderable
209 PatchTesselation& m_tess;
211 RenderablePatchWireframe( PatchTesselation& tess ) : m_tess( tess ){
213 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 )
224 glDrawArrays( GL_LINE_STRIP, GLint( n ), GLsizei( m_tess.m_nArrayWidth ) );
226 if ( i == m_tess.m_curveTreeV.size() ) {
230 if ( !BezierCurveTree_isLeaf( m_tess.m_curveTreeV[i] ) ) {
231 glDrawArrays( GL_LINE_STRIP, GLint( m_tess.m_curveTreeV[i]->index ), GLsizei( m_tess.m_nArrayWidth ) );
234 n += ( m_tess.m_arrayHeight[i] * m_tess.m_nArrayWidth );
240 const ArbitraryMeshVertex* p = m_tess.m_vertices.data();
241 std::size_t n = m_tess.m_nArrayWidth * sizeof( ArbitraryMeshVertex );
242 for ( std::size_t i = 0; i <= m_tess.m_curveTreeU.size(); ++i )
244 glVertexPointer( 3, GL_FLOAT, GLsizei( n ), &p->vertex );
245 glDrawArrays( GL_LINE_STRIP, 0, GLsizei( m_tess.m_nArrayHeight ) );
247 if ( i == m_tess.m_curveTreeU.size() ) {
251 if ( !BezierCurveTree_isLeaf( m_tess.m_curveTreeU[i] ) ) {
252 glVertexPointer( 3, GL_FLOAT, GLsizei( n ), &( m_tess.m_vertices.data() + ( m_tess.m_curveTreeU[i]->index ) )->vertex );
253 glDrawArrays( GL_LINE_STRIP, 0, GLsizei( m_tess.m_nArrayHeight ) );
256 p += m_tess.m_arrayWidth[i];
262 class RenderablePatchFixedWireframe : public OpenGLRenderable
264 PatchTesselation& m_tess;
266 RenderablePatchFixedWireframe( PatchTesselation& tess ) : m_tess( tess ){
268 void render( RenderStateFlags state ) const {
269 glVertexPointer( 3, GL_FLOAT, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->vertex );
270 const RenderIndex* strip_indices = m_tess.m_indices.data();
271 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
280 PatchTesselation& m_tess;
282 RenderablePatchSolid( PatchTesselation& tess ) : m_tess( tess ){
284 void RenderNormals() const;
285 void render( RenderStateFlags state ) const {
287 if ( ( state & RENDER_FILL ) == 0 ) {
288 RenderablePatchWireframe( m_tess ).render( state );
293 if ( ( state & RENDER_BUMP ) != 0 ) {
294 if ( GlobalShaderCache().useShaderLanguage() ) {
295 glNormalPointer( GL_FLOAT, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->normal );
296 glVertexAttribPointerARB( c_attr_TexCoord0, 2, GL_FLOAT, 0, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->texcoord );
297 glVertexAttribPointerARB( c_attr_Tangent, 3, GL_FLOAT, 0, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->tangent );
298 glVertexAttribPointerARB( c_attr_Binormal, 3, GL_FLOAT, 0, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->bitangent );
302 glVertexAttribPointerARB( 11, 3, GL_FLOAT, 0, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->normal );
303 glVertexAttribPointerARB( 8, 2, GL_FLOAT, 0, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->texcoord );
304 glVertexAttribPointerARB( 9, 3, GL_FLOAT, 0, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->tangent );
305 glVertexAttribPointerARB( 10, 3, GL_FLOAT, 0, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->bitangent );
310 glNormalPointer( GL_FLOAT, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->normal );
311 glTexCoordPointer( 2, GL_FLOAT, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->texcoord );
313 glVertexPointer( 3, GL_FLOAT, sizeof( ArbitraryMeshVertex ), &m_tess.m_vertices.data()->vertex );
314 const RenderIndex* strip_indices = m_tess.m_indices.data();
315 for ( std::size_t i = 0; i < m_tess.m_numStrips; i++, strip_indices += m_tess.m_lenStrips )
317 glDrawElements( GL_QUAD_STRIP, GLsizei( m_tess.m_lenStrips ), RenderIndexTypeID, strip_indices );
321 #if defined( _DEBUG )
327 // parametric surface defined by quadratic bezier control curves
331 public TransformNode,
349 xml_state_t( EState state )
352 EState state() const {
355 const char* content() const {
356 return m_content.c_str();
358 std::size_t write( const char* buffer, std::size_t length ){
359 return m_content.write( buffer, length );
363 StringOutputStream m_content;
366 std::vector<xml_state_t> m_xml_state;
368 typedef Array<PatchControl> PatchControlArray;
370 class SavedState : public UndoMemento
376 const PatchControlArray& ctrl,
379 std::size_t subdivisions_x,
380 std::size_t subdivisions_y
386 m_patchDef3( patchDef3 ),
387 m_subdivisions_x( subdivisions_x ),
388 m_subdivisions_y( subdivisions_y ){
395 std::size_t m_width, m_height;
396 CopiedString m_shader;
397 PatchControlArray m_ctrl;
399 std::size_t m_subdivisions_x;
400 std::size_t m_subdivisions_y;
407 virtual void allocate( std::size_t size ) = 0;
411 typedef UniqueSet<Observer*> Observers;
412 Observers m_observers;
416 AABB m_aabb_local; // local bbox
418 CopiedString m_shader;
422 std::size_t m_height;
425 std::size_t m_subdivisions_x;
426 std::size_t m_subdivisions_y;
429 UndoObserver* m_undoable_observer;
432 // dynamically allocated array of control points, size is m_width*m_height
433 PatchControlArray m_ctrl;
434 PatchControlArray m_ctrlTransformed;
436 PatchTesselation m_tess;
437 RenderablePatchSolid m_render_solid;
438 RenderablePatchWireframe m_render_wireframe;
439 RenderablePatchFixedWireframe m_render_wireframe_fixed;
441 static Shader* m_state_ctrl;
442 static Shader* m_state_lattice;
443 VertexBuffer<PointVertex> m_ctrl_vertices;
444 RenderableVertexBuffer m_render_ctrl;
445 IndexBuffer m_lattice_indices;
446 RenderableIndexBuffer m_render_lattice;
450 bool m_transformChanged;
451 Callback m_evaluateTransform;
452 Callback m_boundsChanged;
456 m_width = m_height = 0;
459 m_subdivisions_x = 0;
460 m_subdivisions_y = 0;
465 m_xml_state.push_back( xml_state_t::eDefault );
469 Callback m_lightsChanged;
471 static int m_CycleCapIndex; // = 0;
472 static EPatchType m_type;
474 STRING_CONSTANT( Name, "Patch" );
476 Patch( scene::Node& node, const Callback& evaluateTransform, const Callback& boundsChanged ) :
478 m_shader( texdef_name_default() ),
480 m_undoable_observer( 0 ),
482 m_render_solid( m_tess ),
483 m_render_wireframe( m_tess ),
484 m_render_wireframe_fixed( m_tess ),
485 m_render_ctrl( GL_POINTS, m_ctrl_vertices ),
486 m_render_lattice( GL_LINES, m_lattice_indices, m_ctrl_vertices ),
487 m_transformChanged( false ),
488 m_evaluateTransform( evaluateTransform ),
489 m_boundsChanged( boundsChanged ){
492 Patch( const Patch& other, scene::Node& node, const Callback& evaluateTransform, const Callback& boundsChanged ) :
494 m_shader( texdef_name_default() ),
496 m_undoable_observer( 0 ),
498 m_render_solid( m_tess ),
499 m_render_wireframe( m_tess ),
500 m_render_wireframe_fixed( m_tess ),
501 m_render_ctrl( GL_POINTS, m_ctrl_vertices ),
502 m_render_lattice( GL_LINES, m_lattice_indices, m_ctrl_vertices ),
503 m_transformChanged( false ),
504 m_evaluateTransform( evaluateTransform ),
505 m_boundsChanged( boundsChanged ){
508 m_patchDef3 = other.m_patchDef3;
509 m_subdivisions_x = other.m_subdivisions_x;
510 m_subdivisions_y = other.m_subdivisions_y;
511 setDims( other.m_width, other.m_height );
512 copy_ctrl( m_ctrl.data(), other.m_ctrl.data(), other.m_ctrl.data() + ( m_width * m_height ) );
513 SetShader( other.m_shader.c_str() );
514 controlPointsChanged();
517 Patch( const Patch& other ) :
518 XMLImporter( other ),
519 XMLExporter( other ),
520 TransformNode( other ),
528 m_undoable_observer( 0 ),
530 m_render_solid( m_tess ),
531 m_render_wireframe( m_tess ),
532 m_render_wireframe_fixed( m_tess ),
533 m_render_ctrl( GL_POINTS, m_ctrl_vertices ),
534 m_render_lattice( GL_LINES, m_lattice_indices, m_ctrl_vertices ),
535 m_transformChanged( false ),
536 m_evaluateTransform( other.m_evaluateTransform ),
537 m_boundsChanged( other.m_boundsChanged ){
540 m_patchDef3 = other.m_patchDef3;
541 m_subdivisions_x = other.m_subdivisions_x;
542 m_subdivisions_y = other.m_subdivisions_y;
543 setDims( other.m_width, other.m_height );
544 copy_ctrl( m_ctrl.data(), other.m_ctrl.data(), other.m_ctrl.data() + ( m_width * m_height ) );
545 SetShader( other.m_shader.c_str() );
546 controlPointsChanged();
550 BezierCurveTreeArray_deleteAll( m_tess.m_curveTreeU );
551 BezierCurveTreeArray_deleteAll( m_tess.m_curveTreeV );
555 ASSERT_MESSAGE( m_observers.empty(), "Patch::~Patch: observers still attached" );
558 InstanceCounter m_instanceCounter;
559 void instanceAttach( const scene::Path& path ){
560 if ( ++m_instanceCounter.m_count == 1 ) {
561 m_state->incrementUsed();
562 m_map = path_find_mapfile( path.begin(), path.end() );
563 m_undoable_observer = GlobalUndoSystem().observer( this );
564 GlobalFilterSystem().registerFilterable( *this );
568 ASSERT_MESSAGE( path_find_mapfile( path.begin(), path.end() ) == m_map, "node is instanced across more than one file" );
571 void instanceDetach( const scene::Path& path ){
572 if ( --m_instanceCounter.m_count == 0 ) {
574 m_undoable_observer = 0;
575 GlobalUndoSystem().release( this );
576 GlobalFilterSystem().unregisterFilterable( *this );
577 m_state->decrementUsed();
581 const char* name() const {
584 void attach( const NameCallback& callback ){
586 void detach( const NameCallback& callback ){
589 void attach( Observer* observer ){
590 observer->allocate( m_width * m_height );
592 m_observers.insert( observer );
594 void detach( Observer* observer ){
595 m_observers.erase( observer );
598 void updateFiltered(){
600 if ( patch_filtered( *this ) ) {
601 m_node->enable( scene::Node::eFiltered );
605 m_node->disable( scene::Node::eFiltered );
610 void onAllocate( std::size_t size ){
611 for ( Observers::iterator i = m_observers.begin(); i != m_observers.end(); ++i )
613 ( *i )->allocate( size );
617 const Matrix4& localToParent() const {
618 return g_matrix4_identity;
620 const AABB& localAABB() const {
623 VolumeIntersectionValue intersectVolume( const VolumeTest& test, const Matrix4& localToWorld ) const {
624 return test.TestAABB( m_aabb_local, localToWorld );
626 void render_solid( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld ) const {
627 renderer.SetState( m_state, Renderer::eFullMaterials );
628 renderer.addRenderable( m_render_solid, localToWorld );
630 void render_wireframe( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld ) const {
631 renderer.SetState( m_state, Renderer::eFullMaterials );
633 renderer.addRenderable( m_render_wireframe_fixed, localToWorld );
637 renderer.addRenderable( m_render_wireframe, localToWorld );
641 void render_component( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld ) const {
642 renderer.SetState( m_state_lattice, Renderer::eWireframeOnly );
643 renderer.SetState( m_state_lattice, Renderer::eFullMaterials );
644 renderer.addRenderable( m_render_lattice, localToWorld );
646 renderer.SetState( m_state_ctrl, Renderer::eWireframeOnly );
647 renderer.SetState( m_state_ctrl, Renderer::eFullMaterials );
648 renderer.addRenderable( m_render_ctrl, localToWorld );
650 void testSelect( Selector& selector, SelectionTest& test ){
651 SelectionIntersection best;
652 IndexPointer::index_type* pIndex = m_tess.m_indices.data();
653 for ( std::size_t s = 0; s < m_tess.m_numStrips; s++ )
655 test.TestQuadStrip( vertexpointer_arbitrarymeshvertex( m_tess.m_vertices.data() ), IndexPointer( pIndex, m_tess.m_lenStrips ), best );
656 pIndex += m_tess.m_lenStrips;
658 if ( best.valid() ) {
659 selector.addIntersection( best );
662 void transform( const Matrix4& matrix ){
663 for ( PatchControlIter i = m_ctrlTransformed.data(); i != m_ctrlTransformed.data() + m_ctrlTransformed.size(); ++i )
665 matrix4_transform_point( matrix, ( *i ).m_vertex );
668 if ( matrix4_handedness( matrix ) == MATRIX4_LEFTHANDED ) {
669 PatchControlArray_invert( m_ctrlTransformed, m_width, m_height );
673 void transformChanged(){
674 m_transformChanged = true;
678 typedef MemberCaller<Patch, &Patch::transformChanged> TransformChangedCaller;
680 void evaluateTransform(){
681 if ( m_transformChanged ) {
682 m_transformChanged = false;
684 m_evaluateTransform();
688 void revertTransform(){
689 m_ctrlTransformed = m_ctrl;
691 void freezeTransform(){
694 ASSERT_MESSAGE( m_ctrlTransformed.size() == m_ctrl.size(), "Patch::freeze: size mismatch" );
695 std::copy( m_ctrlTransformed.begin(), m_ctrlTransformed.end(), m_ctrl.begin() );
698 void controlPointsChanged(){
703 bool isValid() const;
705 void snapto( float snap ){
708 for ( PatchControlIter i = m_ctrl.data(); i != m_ctrl.data() + m_ctrl.size(); ++i )
710 vector3_snap( ( *i ).m_vertex, snap );
713 controlPointsChanged();
719 void RenderDebug( RenderStateFlags state ) const;
720 void RenderNormals( RenderStateFlags state ) const;
722 void pushElement( const XMLElement& element ){
723 switch ( m_xml_state.back().state() )
725 case xml_state_t::eDefault:
726 ASSERT_MESSAGE( string_equal( element.name(), "patch" ), "parse error" );
727 m_xml_state.push_back( xml_state_t::ePatch );
729 case xml_state_t::ePatch:
730 if ( string_equal( element.name(), "matrix" ) ) {
731 setDims( atoi( element.attribute( "width" ) ), atoi( element.attribute( "height" ) ) );
732 m_xml_state.push_back( xml_state_t::eMatrix );
734 else if ( string_equal( element.name(), "shader" ) ) {
735 m_xml_state.push_back( xml_state_t::eShader );
739 ERROR_MESSAGE( "parse error" );
743 void popElement( const char* name ){
744 switch ( m_xml_state.back().state() )
746 case xml_state_t::eDefault:
747 ERROR_MESSAGE( "parse error" );
749 case xml_state_t::ePatch:
751 case xml_state_t::eMatrix:
753 StringTokeniser content( m_xml_state.back().content() );
755 for ( PatchControlIter i = m_ctrl.data(), end = m_ctrl.data() + m_ctrl.size(); i != end; ++i )
757 ( *i ).m_vertex[0] = string_read_float( content.getToken() );
758 ( *i ).m_vertex[1] = string_read_float( content.getToken() );
759 ( *i ).m_vertex[2] = string_read_float( content.getToken() );
760 ( *i ).m_texcoord[0] = string_read_float( content.getToken() );
761 ( *i ).m_texcoord[1] = string_read_float( content.getToken() );
763 controlPointsChanged();
766 case xml_state_t::eShader:
768 SetShader( m_xml_state.back().content() );
772 ERROR_MESSAGE( "parse error" );
775 ASSERT_MESSAGE( !m_xml_state.empty(), "popping empty stack" );
776 m_xml_state.pop_back();
778 std::size_t write( const char* buffer, std::size_t length ){
779 switch ( m_xml_state.back().state() )
781 case xml_state_t::eDefault:
783 case xml_state_t::ePatch:
785 case xml_state_t::eMatrix:
786 case xml_state_t::eShader:
787 return m_xml_state.back().write( buffer, length );
790 ERROR_MESSAGE( "parse error" );
795 void exportXML( XMLImporter& importer ){
796 StaticElement patchElement( "patch" );
797 importer.pushElement( patchElement );
800 const StaticElement element( "shader" );
801 importer.pushElement( element );
802 importer.write( m_shader.c_str(), strlen( m_shader.c_str() ) );
803 importer.popElement( element.name() );
807 auto width = u::buffer<16>();
808 auto height = u::buffer<16>();
809 sprintf( width, "%u", Unsigned( m_width ) );
810 sprintf( height, "%u", Unsigned( m_height ) );
811 StaticElement element( "matrix" );
812 element.insertAttribute( "width", width );
813 element.insertAttribute( "height", height );
815 importer.pushElement( element );
817 for ( PatchControlIter i = m_ctrl.data(), end = m_ctrl.data() + m_ctrl.size(); i != end; ++i )
819 importer << ( *i ).m_vertex[0]
820 << ' ' << ( *i ).m_vertex[1]
821 << ' ' << ( *i ).m_vertex[2]
822 << ' ' << ( *i ).m_texcoord[0]
823 << ' ' << ( *i ).m_texcoord[1];
826 importer.popElement( element.name() );
829 importer.popElement( patchElement.name() );
832 void UpdateCachedData();
834 const char *GetShader() const {
835 return m_shader.c_str();
837 void SetShader( const char* name ){
838 ASSERT_NOTNULL( name );
840 if ( shader_equal( m_shader.c_str(), name ) ) {
846 if ( m_instanceCounter.m_count != 0 ) {
847 m_state->decrementUsed();
852 if ( m_instanceCounter.m_count != 0 ) {
853 m_state->incrementUsed();
857 Patch_textureChanged();
859 int getShaderFlags() const {
860 if ( m_state != 0 ) {
861 return m_state->getFlags();
866 typedef PatchControl* iterator;
867 typedef const PatchControl* const_iterator;
870 return m_ctrl.data();
872 const_iterator begin() const {
873 return m_ctrl.data();
876 return m_ctrl.data() + m_ctrl.size();
878 const_iterator end() const {
879 return m_ctrl.data() + m_ctrl.size();
882 PatchControlArray& getControlPoints(){
885 PatchControlArray& getControlPointsTransformed(){
886 return m_ctrlTransformed;
889 void setDims( std::size_t w, std::size_t h );
890 std::size_t getWidth() const {
893 std::size_t getHeight() const {
896 PatchControl& ctrlAt( std::size_t row, std::size_t col ){
897 return m_ctrl[row * m_width + col];
899 const PatchControl& ctrlAt( std::size_t row, std::size_t col ) const {
900 return m_ctrl[row * m_width + col];
903 void ConstructPrefab( const AABB& aabb, EPatchPrefab eType, int axis, std::size_t width = 3, std::size_t height = 3 );
904 void constructPlane( const AABB& aabb, int axis, std::size_t width, std::size_t height );
906 void TransposeMatrix();
907 void Redisperse( EMatrixMajor mt );
908 void Smooth( EMatrixMajor mt );
909 void InsertRemove( bool bInsert, bool bColumn, bool bFirst );
910 Patch* MakeCap( Patch* patch, EPatchCap eType, EMatrixMajor mt, bool bFirst );
911 void ConstructSeam( EPatchCap eType, Vector3* p, std::size_t width );
913 void FlipTexture( int nAxis );
914 void TranslateTexture( float s, float t );
915 void ScaleTexture( float s, float t );
916 void RotateTexture( float angle );
917 void SetTextureRepeat( float s, float t ); // call with s=1 t=1 for FIT
919 void NaturalTexture();
920 void ProjectTexture( int nAxis );
926 if ( m_undoable_observer != 0 ) {
927 m_undoable_observer->save( this );
931 UndoMemento* exportState() const {
932 return new SavedState( m_width, m_height, m_ctrl, m_shader.c_str(), m_patchDef3, m_subdivisions_x, m_subdivisions_y );
934 void importState( const UndoMemento* state ){
937 const SavedState& other = *( static_cast<const SavedState*>( state ) );
939 // begin duplicate of SavedState copy constructor, needs refactoring
943 m_width = other.m_width;
944 m_height = other.m_height;
945 SetShader( other.m_shader.c_str() );
946 m_ctrl = other.m_ctrl;
947 onAllocate( m_ctrl.size() );
948 m_patchDef3 = other.m_patchDef3;
949 m_subdivisions_x = other.m_subdivisions_x;
950 m_subdivisions_y = other.m_subdivisions_y;
953 // end duplicate code
955 Patch_textureChanged();
957 controlPointsChanged();
960 static void constructStatic( EPatchType type ){
961 Patch::m_type = type;
962 Patch::m_state_ctrl = GlobalShaderCache().capture( "$POINT" );
963 Patch::m_state_lattice = GlobalShaderCache().capture( "$LATTICE" );
966 static void destroyStatic(){
967 GlobalShaderCache().release( "$LATTICE" );
968 GlobalShaderCache().release( "$POINT" );
971 void captureShader(){
972 m_state = GlobalShaderCache().capture( m_shader.c_str() );
975 void releaseShader(){
976 GlobalShaderCache().release( m_shader.c_str() );
980 if ( !shader_valid( GetShader() ) ) {
981 globalErrorStream() << "patch has invalid texture name: '" << GetShader() << "'\n";
985 void InsertPoints( EMatrixMajor mt, bool bFirst );
986 void RemovePoints( EMatrixMajor mt, bool bFirst );
988 void AccumulateBBox();
990 void TesselateSubMatrixFixed( ArbitraryMeshVertex * vertices, std::size_t strideX, std::size_t strideY, unsigned int nFlagsX, unsigned int nFlagsY, PatchControl * subMatrix[3][3] );
992 // uses binary trees representing bezier curves to recursively tesselate a bezier sub-patch
993 void TesselateSubMatrix( const BezierCurveTree *BX, const BezierCurveTree *BY,
994 std::size_t offStartX, std::size_t offStartY,
995 std::size_t offEndX, std::size_t offEndY,
996 std::size_t nFlagsX, std::size_t nFlagsY,
997 Vector3& left, Vector3& mid, Vector3& right,
998 Vector2& texLeft, Vector2& texMid, Vector2& texRight,
1001 // tesselates the entire surface
1002 void BuildTesselationCurves( EMatrixMajor major );
1003 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 );
1004 void BuildVertexArray();
1007 inline bool Patch_importHeader( Patch& patch, Tokeniser& tokeniser ){
1008 tokeniser.nextLine();
1009 RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "{" ) );
1013 inline bool Patch_importShader( Patch& patch, Tokeniser& tokeniser ){
1014 // parse shader name
1015 tokeniser.nextLine();
1016 const char* texture = tokeniser.getToken();
1017 if ( texture == 0 ) {
1018 Tokeniser_unexpectedError( tokeniser, texture, "#texture-name" );
1021 if ( string_equal( texture, "NULL" ) ) {
1022 patch.SetShader( texdef_name_default() );
1026 StringOutputStream shader( string_length( GlobalTexturePrefix_get() ) + string_length( texture ) );
1027 shader << GlobalTexturePrefix_get() << texture;
1028 patch.SetShader( shader.c_str() );
1033 inline bool PatchDoom3_importShader( Patch& patch, Tokeniser& tokeniser ){
1034 // parse shader name
1035 tokeniser.nextLine();
1036 const char *shader = tokeniser.getToken();
1037 if ( shader == 0 ) {
1038 Tokeniser_unexpectedError( tokeniser, shader, "#shader-name" );
1041 if ( string_equal( shader, "_emptyname" ) ) {
1042 shader = texdef_name_default();
1044 patch.SetShader( shader );
1048 inline bool Patch_importParams( Patch& patch, Tokeniser& tokeniser ){
1049 tokeniser.nextLine();
1050 RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "(" ) );
1052 // parse matrix dimensions
1055 RETURN_FALSE_IF_FAIL( Tokeniser_getSize( tokeniser, c ) );
1056 RETURN_FALSE_IF_FAIL( Tokeniser_getSize( tokeniser, r ) );
1058 patch.setDims( c, r );
1061 if ( patch.m_patchDef3 ) {
1062 RETURN_FALSE_IF_FAIL( Tokeniser_getSize( tokeniser, patch.m_subdivisions_x ) );
1063 RETURN_FALSE_IF_FAIL( Tokeniser_getSize( tokeniser, patch.m_subdivisions_y ) );
1066 // ignore contents/flags/value
1068 RETURN_FALSE_IF_FAIL( Tokeniser_getInteger( tokeniser, tmp ) );
1069 RETURN_FALSE_IF_FAIL( Tokeniser_getInteger( tokeniser, tmp ) );
1070 RETURN_FALSE_IF_FAIL( Tokeniser_getInteger( tokeniser, tmp ) );
1072 RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, ")" ) );
1076 inline bool Patch_importMatrix( Patch& patch, Tokeniser& tokeniser ){
1078 tokeniser.nextLine();
1079 RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "(" ) );
1081 for ( std::size_t c = 0; c < patch.getWidth(); c++ )
1083 tokeniser.nextLine();
1084 RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "(" ) );
1085 for ( std::size_t r = 0; r < patch.getHeight(); r++ )
1087 RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "(" ) );
1089 RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, patch.ctrlAt( r,c ).m_vertex[0] ) );
1090 RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, patch.ctrlAt( r,c ).m_vertex[1] ) );
1091 RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, patch.ctrlAt( r,c ).m_vertex[2] ) );
1092 RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, patch.ctrlAt( r,c ).m_texcoord[0] ) );
1093 RETURN_FALSE_IF_FAIL( Tokeniser_getFloat( tokeniser, patch.ctrlAt( r,c ).m_texcoord[1] ) );
1095 RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, ")" ) );
1097 RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, ")" ) );
1100 tokeniser.nextLine();
1101 RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, ")" ) );
1105 inline bool Patch_importFooter( Patch& patch, Tokeniser& tokeniser ){
1106 patch.controlPointsChanged();
1108 tokeniser.nextLine();
1109 RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "}" ) );
1111 tokeniser.nextLine();
1112 RETURN_FALSE_IF_FAIL( Tokeniser_parseToken( tokeniser, "}" ) );
1116 class PatchTokenImporter : public MapImporter
1120 PatchTokenImporter( Patch& patch ) : m_patch( patch ){
1122 bool importTokens( Tokeniser& tokeniser ){
1123 RETURN_FALSE_IF_FAIL( Patch_importHeader( m_patch, tokeniser ) );
1124 RETURN_FALSE_IF_FAIL( Patch_importShader( m_patch, tokeniser ) );
1125 RETURN_FALSE_IF_FAIL( Patch_importParams( m_patch, tokeniser ) );
1126 RETURN_FALSE_IF_FAIL( Patch_importMatrix( m_patch, tokeniser ) );
1127 RETURN_FALSE_IF_FAIL( Patch_importFooter( m_patch, tokeniser ) );
1133 class PatchDoom3TokenImporter : public MapImporter
1137 PatchDoom3TokenImporter( Patch& patch ) : m_patch( patch ){
1139 bool importTokens( Tokeniser& tokeniser ){
1140 RETURN_FALSE_IF_FAIL( Patch_importHeader( m_patch, tokeniser ) );
1141 RETURN_FALSE_IF_FAIL( PatchDoom3_importShader( m_patch, tokeniser ) );
1142 RETURN_FALSE_IF_FAIL( Patch_importParams( m_patch, tokeniser ) );
1143 RETURN_FALSE_IF_FAIL( Patch_importMatrix( m_patch, tokeniser ) );
1144 RETURN_FALSE_IF_FAIL( Patch_importFooter( m_patch, tokeniser ) );
1150 inline void Patch_exportHeader( const Patch& patch, TokenWriter& writer ){
1151 writer.writeToken( "{" );
1153 writer.writeToken( patch.m_patchDef3 ? "patchDef3" : "patchDef2" );
1155 writer.writeToken( "{" );
1159 inline void Patch_exportShader( const Patch& patch, TokenWriter& writer ){
1160 // write shader name
1161 if ( *( shader_get_textureName( patch.GetShader() ) ) == '\0' ) {
1162 writer.writeToken( "NULL" );
1166 writer.writeToken( shader_get_textureName( patch.GetShader() ) );
1171 inline void PatchDoom3_exportShader( const Patch& patch, TokenWriter& writer ){
1172 // write shader name
1173 if ( *( shader_get_textureName( patch.GetShader() ) ) == '\0' ) {
1174 writer.writeString( "_emptyname" );
1178 writer.writeString( patch.GetShader() );
1183 inline void Patch_exportParams( const Patch& patch, TokenWriter& writer ){
1184 // write matrix dimensions
1185 writer.writeToken( "(" );
1186 writer.writeUnsigned( patch.getWidth() );
1187 writer.writeUnsigned( patch.getHeight() );
1188 if ( patch.m_patchDef3 ) {
1189 writer.writeUnsigned( patch.m_subdivisions_x );
1190 writer.writeUnsigned( patch.m_subdivisions_y );
1192 writer.writeInteger( 0 );
1193 writer.writeInteger( 0 );
1194 writer.writeInteger( 0 );
1195 writer.writeToken( ")" );
1199 inline void Patch_exportMatrix( const Patch& patch, TokenWriter& writer ){
1201 writer.writeToken( "(" );
1203 for ( std::size_t c = 0; c < patch.getWidth(); c++ )
1205 writer.writeToken( "(" );
1206 for ( std::size_t r = 0; r < patch.getHeight(); r++ )
1208 writer.writeToken( "(" );
1210 writer.writeFloat( patch.ctrlAt( r,c ).m_vertex[0] );
1211 writer.writeFloat( patch.ctrlAt( r,c ).m_vertex[1] );
1212 writer.writeFloat( patch.ctrlAt( r,c ).m_vertex[2] );
1213 writer.writeFloat( patch.ctrlAt( r,c ).m_texcoord[0] );
1214 writer.writeFloat( patch.ctrlAt( r,c ).m_texcoord[1] );
1216 writer.writeToken( ")" );
1218 writer.writeToken( ")" );
1221 writer.writeToken( ")" );
1225 inline void Patch_exportFooter( const Patch& patch, TokenWriter& writer ){
1226 writer.writeToken( "}" );
1228 writer.writeToken( "}" );
1232 class PatchTokenExporter : public MapExporter
1234 const Patch& m_patch;
1236 PatchTokenExporter( Patch& patch ) : m_patch( patch ){
1238 void exportTokens( TokenWriter& writer ) const {
1239 Patch_exportHeader( m_patch, writer );
1240 Patch_exportShader( m_patch, writer );
1241 Patch_exportParams( m_patch, writer );
1242 Patch_exportMatrix( m_patch, writer );
1243 Patch_exportFooter( m_patch, writer );
1247 class PatchDoom3TokenExporter : public MapExporter
1249 const Patch& m_patch;
1251 PatchDoom3TokenExporter( Patch& patch ) : m_patch( patch ){
1253 void exportTokens( TokenWriter& writer ) const {
1254 Patch_exportHeader( m_patch, writer );
1255 PatchDoom3_exportShader( m_patch, writer );
1256 Patch_exportParams( m_patch, writer );
1257 Patch_exportMatrix( m_patch, writer );
1258 Patch_exportFooter( m_patch, writer );
1262 class PatchControlInstance
1265 PatchControl* m_ctrl;
1266 ObservedSelectable m_selectable;
1268 PatchControlInstance( PatchControl* ctrl, const SelectionChangeCallback& observer )
1269 : m_ctrl( ctrl ), m_selectable( observer ){
1272 void testSelect( Selector& selector, SelectionTest& test ){
1273 SelectionIntersection best;
1274 test.TestPoint( m_ctrl->m_vertex, best );
1275 if ( best.valid() ) {
1276 Selector_add( selector, m_selectable, best );
1279 void snapto( float snap ){
1280 vector3_snap( m_ctrl->m_vertex, snap );
1285 class PatchInstance :
1286 public Patch::Observer,
1287 public scene::Instance,
1290 public SelectionTestable,
1291 public ComponentSelectionTestable,
1292 public ComponentEditable,
1293 public ComponentSnappable,
1294 public PlaneSelectable,
1295 public LightCullable
1299 InstanceTypeCastTable m_casts;
1302 InstanceStaticCast<PatchInstance, Selectable>::install( m_casts );
1303 InstanceContainedCast<PatchInstance, Bounded>::install( m_casts );
1304 InstanceContainedCast<PatchInstance, Cullable>::install( m_casts );
1305 InstanceStaticCast<PatchInstance, Renderable>::install( m_casts );
1306 InstanceStaticCast<PatchInstance, SelectionTestable>::install( m_casts );
1307 InstanceStaticCast<PatchInstance, ComponentSelectionTestable>::install( m_casts );
1308 InstanceStaticCast<PatchInstance, ComponentEditable>::install( m_casts );
1309 InstanceStaticCast<PatchInstance, ComponentSnappable>::install( m_casts );
1310 InstanceStaticCast<PatchInstance, PlaneSelectable>::install( m_casts );
1311 InstanceIdentityCast<PatchInstance>::install( m_casts );
1312 InstanceContainedCast<PatchInstance, Transformable>::install( m_casts );
1314 InstanceTypeCastTable& get(){
1321 typedef std::vector<PatchControlInstance> PatchControlInstances;
1322 PatchControlInstances m_ctrl_instances;
1324 ObservedSelectable m_selectable;
1326 DragPlanes m_dragPlanes;
1328 mutable RenderablePointVector m_render_selected;
1329 mutable AABB m_aabb_component;
1331 static Shader* m_state_selpoint;
1333 const LightList* m_lightList;
1335 TransformModifier m_transform;
1338 typedef LazyStatic<TypeCasts> StaticTypeCasts;
1340 void lightsChanged(){
1341 m_lightList->lightsChanged();
1343 typedef MemberCaller<PatchInstance, &PatchInstance::lightsChanged> LightsChangedCaller;
1345 STRING_CONSTANT( Name, "PatchInstance" );
1347 PatchInstance( const scene::Path& path, scene::Instance* parent, Patch& patch ) :
1348 Instance( path, parent, this, StaticTypeCasts::instance().get() ),
1350 m_selectable( SelectedChangedCaller( *this ) ),
1351 m_dragPlanes( SelectedChangedComponentCaller( *this ) ),
1352 m_render_selected( GL_POINTS ),
1353 m_transform( Patch::TransformChangedCaller( m_patch ), ApplyTransformCaller( *this ) ){
1354 m_patch.instanceAttach( Instance::path() );
1355 m_patch.attach( this );
1357 m_lightList = &GlobalShaderCache().attach( *this );
1358 m_patch.m_lightsChanged = LightsChangedCaller( *this );
1360 Instance::setTransformChangedCallback( LightsChangedCaller( *this ) );
1363 Instance::setTransformChangedCallback( Callback() );
1365 m_patch.m_lightsChanged = Callback();
1366 GlobalShaderCache().detach( *this );
1368 m_patch.detach( this );
1369 m_patch.instanceDetach( Instance::path() );
1372 void selectedChanged( const Selectable& selectable ){
1373 GlobalSelectionSystem().getObserver ( SelectionSystem::ePrimitive )( selectable );
1374 GlobalSelectionSystem().onSelectedChanged( *this, selectable );
1376 Instance::selectedChanged();
1378 typedef MemberCaller1<PatchInstance, const Selectable&, &PatchInstance::selectedChanged> SelectedChangedCaller;
1380 void selectedChangedComponent( const Selectable& selectable ){
1381 GlobalSelectionSystem().getObserver ( SelectionSystem::eComponent )( selectable );
1382 GlobalSelectionSystem().onComponentSelection( *this, selectable );
1384 typedef MemberCaller1<PatchInstance, const Selectable&, &PatchInstance::selectedChangedComponent> SelectedChangedComponentCaller;
1389 Bounded& get( NullType<Bounded>){
1392 Cullable& get( NullType<Cullable>){
1395 Transformable& get( NullType<Transformable>){
1399 static void constructStatic(){
1400 m_state_selpoint = GlobalShaderCache().capture( "$SELPOINT" );
1403 static void destroyStatic(){
1404 GlobalShaderCache().release( "$SELPOINT" );
1408 void allocate( std::size_t size ){
1409 m_ctrl_instances.clear();
1410 m_ctrl_instances.reserve( size );
1411 for ( Patch::iterator i = m_patch.begin(); i != m_patch.end(); ++i )
1413 m_ctrl_instances.push_back( PatchControlInstance( &( *i ), SelectedChangedComponentCaller( *this ) ) );
1417 void setSelected( bool select ){
1418 m_selectable.setSelected( select );
1420 bool isSelected() const {
1421 return m_selectable.isSelected();
1425 void update_selected() const {
1426 m_render_selected.clear();
1427 Patch::iterator ctrl = m_patch.getControlPointsTransformed().begin();
1428 for ( PatchControlInstances::const_iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i, ++ctrl )
1430 if ( ( *i ).m_selectable.isSelected() ) {
1431 const Colour4b colour_selected( 0, 0, 255, 255 );
1432 m_render_selected.push_back( PointVertex( reinterpret_cast<Vertex3f&>( ( *ctrl ).m_vertex ), colour_selected ) );
1438 void render( Renderer& renderer, const VolumeTest& volume ) const {
1439 if ( GlobalSelectionSystem().Mode() == SelectionSystem::eComponent
1440 && m_selectable.isSelected() ) {
1441 renderer.Highlight( Renderer::eFace, false );
1443 m_patch.render( renderer, volume, localToWorld() );
1445 if ( GlobalSelectionSystem().ComponentMode() == SelectionSystem::eVertex ) {
1446 renderer.Highlight( Renderer::ePrimitive, false );
1448 m_patch.render_component( renderer, volume, localToWorld() );
1450 renderComponentsSelected( renderer, volume );
1454 m_patch.render( renderer, volume, localToWorld() );
1459 void renderSolid( Renderer& renderer, const VolumeTest& volume ) const {
1460 m_patch.evaluateTransform();
1461 renderer.setLights( *m_lightList );
1462 m_patch.render_solid( renderer, volume, localToWorld() );
1464 renderComponentsSelected( renderer, volume );
1467 void renderWireframe( Renderer& renderer, const VolumeTest& volume ) const {
1468 m_patch.evaluateTransform();
1469 m_patch.render_wireframe( renderer, volume, localToWorld() );
1471 renderComponentsSelected( renderer, volume );
1474 void renderComponentsSelected( Renderer& renderer, const VolumeTest& volume ) const {
1475 m_patch.evaluateTransform();
1477 if ( !m_render_selected.empty() ) {
1478 renderer.Highlight( Renderer::ePrimitive, false );
1479 renderer.SetState( m_state_selpoint, Renderer::eWireframeOnly );
1480 renderer.SetState( m_state_selpoint, Renderer::eFullMaterials );
1481 renderer.addRenderable( m_render_selected, localToWorld() );
1484 void renderComponents( Renderer& renderer, const VolumeTest& volume ) const {
1485 m_patch.evaluateTransform();
1486 if ( GlobalSelectionSystem().ComponentMode() == SelectionSystem::eVertex ) {
1487 m_patch.render_component( renderer, volume, localToWorld() );
1491 void testSelect( Selector& selector, SelectionTest& test ){
1492 test.BeginMesh( localToWorld(), true );
1493 m_patch.testSelect( selector, test );
1496 void selectCtrl( bool select ){
1497 for ( PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i )
1499 ( *i ).m_selectable.setSelected( select );
1502 bool isSelectedComponents() const {
1503 for ( PatchControlInstances::const_iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i )
1505 if ( ( *i ).m_selectable.isSelected() ) {
1511 void setSelectedComponents( bool select, SelectionSystem::EComponentMode mode ){
1512 if ( mode == SelectionSystem::eVertex ) {
1513 selectCtrl( select );
1515 else if ( mode == SelectionSystem::eFace ) {
1516 m_dragPlanes.setSelected( select );
1519 const AABB& getSelectedComponentsBounds() const {
1520 m_aabb_component = AABB();
1522 for ( PatchControlInstances::const_iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i )
1524 if ( ( *i ).m_selectable.isSelected() ) {
1525 aabb_extend_by_point_safe( m_aabb_component, ( *i ).m_ctrl->m_vertex );
1529 return m_aabb_component;
1532 void testSelectComponents( Selector& selector, SelectionTest& test, SelectionSystem::EComponentMode mode ){
1533 test.BeginMesh( localToWorld() );
1537 case SelectionSystem::eVertex:
1539 for ( PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i )
1541 ( *i ).testSelect( selector, test );
1550 bool selectedVertices(){
1551 for ( PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i )
1553 if ( ( *i ).m_selectable.isSelected() ) {
1560 void transformComponents( const Matrix4& matrix ){
1561 if ( selectedVertices() ) {
1562 PatchControlIter ctrl = m_patch.getControlPointsTransformed().begin();
1563 for ( PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i, ++ctrl )
1565 if ( ( *i ).m_selectable.isSelected() ) {
1566 matrix4_transform_point( matrix, ( *ctrl ).m_vertex );
1569 m_patch.UpdateCachedData();
1572 if ( m_dragPlanes.isSelected() ) { // this should only be true when the transform is a pure translation.
1573 m_patch.transform( m_dragPlanes.evaluateTransform( vector4_to_vector3( matrix.t() ) ) );
1578 void selectPlanes( Selector& selector, SelectionTest& test, const PlaneCallback& selectedPlaneCallback ){
1579 test.BeginMesh( localToWorld() );
1581 m_dragPlanes.selectPlanes( m_patch.localAABB(), selector, test, selectedPlaneCallback );
1583 void selectReversedPlanes( Selector& selector, const SelectedPlanes& selectedPlanes ){
1584 m_dragPlanes.selectReversedPlanes( m_patch.localAABB(), selector, selectedPlanes );
1588 void snapComponents( float snap ){
1589 if ( selectedVertices() ) {
1591 for ( PatchControlInstances::iterator i = m_ctrl_instances.begin(); i != m_ctrl_instances.end(); ++i )
1593 if ( ( *i ).m_selectable.isSelected() ) {
1594 ( *i ).snapto( snap );
1597 m_patch.controlPointsChanged();
1601 void evaluateTransform(){
1602 Matrix4 matrix( m_transform.calculateTransform() );
1604 if ( m_transform.getType() == TRANSFORM_PRIMITIVE ) {
1605 m_patch.transform( matrix );
1609 transformComponents( matrix );
1612 void applyTransform(){
1613 m_patch.revertTransform();
1614 evaluateTransform();
1615 m_patch.freezeTransform();
1617 typedef MemberCaller<PatchInstance, &PatchInstance::applyTransform> ApplyTransformCaller;
1620 bool testLight( const RendererLight& light ) const {
1621 return light.testAABB( worldAABB() );
1626 template<typename TokenImporter, typename TokenExporter>
1628 public scene::Node::Symbiot,
1629 public scene::Instantiable,
1630 public scene::Cloneable
1632 typedef PatchNode<TokenImporter, TokenExporter> Self;
1636 InstanceTypeCastTable m_casts;
1639 NodeStaticCast<PatchNode, scene::Instantiable>::install( m_casts );
1640 NodeStaticCast<PatchNode, scene::Cloneable>::install( m_casts );
1641 NodeContainedCast<PatchNode, Snappable>::install( m_casts );
1642 NodeContainedCast<PatchNode, TransformNode>::install( m_casts );
1643 NodeContainedCast<PatchNode, Patch>::install( m_casts );
1644 NodeContainedCast<PatchNode, XMLImporter>::install( m_casts );
1645 NodeContainedCast<PatchNode, XMLExporter>::install( m_casts );
1646 NodeContainedCast<PatchNode, MapImporter>::install( m_casts );
1647 NodeContainedCast<PatchNode, MapExporter>::install( m_casts );
1648 NodeContainedCast<PatchNode, Nameable>::install( m_casts );
1650 InstanceTypeCastTable& get(){
1657 InstanceSet m_instances;
1659 TokenImporter m_importMap;
1660 TokenExporter m_exportMap;
1664 typedef LazyStatic<TypeCasts> StaticTypeCasts;
1666 Snappable& get( NullType<Snappable>){
1669 TransformNode& get( NullType<TransformNode>){
1672 Patch& get( NullType<Patch>){
1675 XMLImporter& get( NullType<XMLImporter>){
1678 XMLExporter& get( NullType<XMLExporter>){
1681 MapImporter& get( NullType<MapImporter>){
1684 MapExporter& get( NullType<MapExporter>){
1687 Nameable& get( NullType<Nameable>){
1691 PatchNode( bool patchDef3 = false ) :
1692 m_node( this, this, StaticTypeCasts::instance().get() ),
1693 m_patch( m_node, InstanceSetEvaluateTransform<PatchInstance>::Caller( m_instances ), InstanceSet::BoundsChangedCaller( m_instances ) ),
1694 m_importMap( m_patch ),
1695 m_exportMap( m_patch ){
1696 m_patch.m_patchDef3 = patchDef3;
1698 PatchNode( const PatchNode& other ) :
1699 scene::Node::Symbiot( other ),
1700 scene::Instantiable( other ),
1701 scene::Cloneable( other ),
1702 m_node( this, this, StaticTypeCasts::instance().get() ),
1703 m_patch( other.m_patch, m_node, InstanceSetEvaluateTransform<PatchInstance>::Caller( m_instances ), InstanceSet::BoundsChangedCaller( m_instances ) ),
1704 m_importMap( m_patch ),
1705 m_exportMap( m_patch ){
1710 scene::Node& node(){
1716 const Patch& get() const {
1720 scene::Node& clone() const {
1721 return ( new PatchNode( *this ) )->node();
1724 scene::Instance* create( const scene::Path& path, scene::Instance* parent ){
1725 return new PatchInstance( path, parent, m_patch );
1727 void forEachInstance( const scene::Instantiable::Visitor& visitor ){
1728 m_instances.forEachInstance( visitor );
1730 void insert( scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance ){
1731 m_instances.insert( observer, path, instance );
1733 scene::Instance* erase( scene::Instantiable::Observer* observer, const scene::Path& path ){
1734 return m_instances.erase( observer, path );
1740 typedef PatchNode<PatchTokenImporter, PatchTokenExporter> PatchNodeQuake3;
1741 typedef PatchNode<PatchDoom3TokenImporter, PatchDoom3TokenExporter> PatchNodeDoom3;
1743 inline Patch* Node_getPatch( scene::Node& node ){
1744 return NodeTypeCast<Patch>::cast( node );
1747 inline PatchInstance* Instance_getPatch( scene::Instance& instance ){
1748 return InstanceTypeCast<PatchInstance>::cast( instance );
1751 template<typename Functor>
1752 class PatchSelectedVisitor : public SelectionSystem::Visitor
1754 const Functor& m_functor;
1756 PatchSelectedVisitor( const Functor& functor ) : m_functor( functor ){
1758 void visit( scene::Instance& instance ) const {
1759 PatchInstance* patch = Instance_getPatch( instance );
1761 m_functor( *patch );
1766 template<typename Functor>
1767 inline void Scene_forEachSelectedPatch( const Functor& functor ){
1768 GlobalSelectionSystem().foreachSelected( PatchSelectedVisitor<Functor>( functor ) );
1772 template<typename Functor>
1773 class PatchVisibleSelectedVisitor : public SelectionSystem::Visitor
1775 const Functor& m_functor;
1777 PatchVisibleSelectedVisitor( const Functor& functor ) : m_functor( functor ){
1779 void visit( scene::Instance& instance ) const {
1780 PatchInstance* patch = Instance_getPatch( instance );
1782 && instance.path().top().get().visible() ) {
1783 m_functor( *patch );
1788 template<typename Functor>
1789 inline void Scene_forEachVisibleSelectedPatchInstance( const Functor& functor ){
1790 GlobalSelectionSystem().foreachSelected( PatchVisibleSelectedVisitor<Functor>( functor ) );
1793 template<typename Functor>
1794 class PatchForEachWalker : public scene::Graph::Walker
1796 const Functor& m_functor;
1798 PatchForEachWalker( const Functor& functor ) : m_functor( functor ){
1800 bool pre( const scene::Path& path, scene::Instance& instance ) const {
1801 if ( path.top().get().visible() ) {
1802 Patch* patch = Node_getPatch( path.top() );
1804 m_functor( *patch );
1811 template<typename Functor>
1812 inline void Scene_forEachVisiblePatch( const Functor& functor ){
1813 GlobalSceneGraph().traverse( PatchForEachWalker<Functor>( functor ) );
1816 template<typename Functor>
1817 class PatchForEachSelectedWalker : public scene::Graph::Walker
1819 const Functor& m_functor;
1821 PatchForEachSelectedWalker( const Functor& functor ) : m_functor( functor ){
1823 bool pre( const scene::Path& path, scene::Instance& instance ) const {
1824 if ( path.top().get().visible() ) {
1825 Patch* patch = Node_getPatch( path.top() );
1827 && Instance_getSelectable( instance )->isSelected() ) {
1828 m_functor( *patch );
1835 template<typename Functor>
1836 inline void Scene_forEachVisibleSelectedPatch( const Functor& functor ){
1837 GlobalSceneGraph().traverse( PatchForEachSelectedWalker<Functor>( functor ) );
1840 template<typename Functor>
1841 class PatchForEachInstanceWalker : public scene::Graph::Walker
1843 const Functor& m_functor;
1845 PatchForEachInstanceWalker( const Functor& functor ) : m_functor( functor ){
1847 bool pre( const scene::Path& path, scene::Instance& instance ) const {
1848 if ( path.top().get().visible() ) {
1849 PatchInstance* patch = Instance_getPatch( instance );
1851 m_functor( *patch );
1858 template<typename Functor>
1859 inline void Scene_forEachVisiblePatchInstance( const Functor& functor ){
1860 GlobalSceneGraph().traverse( PatchForEachInstanceWalker<Functor>( functor ) );