2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
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 #include "brushmanip.h"
25 #include "gtkutil/widget.h"
26 #include "gtkutil/menu.h"
28 #include "brushnode.h"
30 #include "texwindow.h"
33 #include "mainframe.h"
36 #include "preferences.h"
40 void Brush_ConstructCuboid( Brush& brush, const AABB& bounds, const char* shader, const TextureProjection& projection ){
41 const unsigned char box[3][2] = { { 0, 1 }, { 2, 0 }, { 1, 2 } };
42 Vector3 mins( vector3_subtracted( bounds.origin, bounds.extents ) );
43 Vector3 maxs( vector3_added( bounds.origin, bounds.extents ) );
49 for ( int i = 0; i < 3; ++i )
51 Vector3 planepts1( maxs );
52 Vector3 planepts2( maxs );
53 planepts2[box[i][0]] = mins[box[i][0]];
54 planepts1[box[i][1]] = mins[box[i][1]];
56 brush.addPlane( maxs, planepts1, planepts2, shader, projection );
60 for ( int i = 0; i < 3; ++i )
62 Vector3 planepts1( mins );
63 Vector3 planepts2( mins );
64 planepts1[box[i][0]] = maxs[box[i][0]];
65 planepts2[box[i][1]] = maxs[box[i][1]];
67 brush.addPlane( mins, planepts1, planepts2, shader, projection );
72 inline float max_extent( const Vector3& extents ){
73 return std::max( std::max( extents[0], extents[1] ), extents[2] );
76 inline float max_extent_2d( const Vector3& extents, int axis ){
80 return std::max( extents[1], extents[2] );
82 return std::max( extents[0], extents[2] );
84 return std::max( extents[0], extents[1] );
88 const std::size_t c_brushPrism_minSides = 3;
89 const std::size_t c_brushPrism_maxSides = c_brush_maxFaces - 2;
90 const char* const c_brushPrism_name = "brushPrism";
92 void Brush_ConstructPrism( Brush& brush, const AABB& bounds, std::size_t sides, int axis, const char* shader, const TextureProjection& projection ){
93 if ( sides < c_brushPrism_minSides ) {
94 globalErrorStream() << c_brushPrism_name << ": sides " << Unsigned( sides ) << ": too few sides, minimum is " << Unsigned( c_brushPrism_minSides ) << "\n";
97 if ( sides > c_brushPrism_maxSides ) {
98 globalErrorStream() << c_brushPrism_name << ": sides " << Unsigned( sides ) << ": too many sides, maximum is " << Unsigned( c_brushPrism_maxSides ) << "\n";
103 brush.reserve( sides + 2 );
105 Vector3 mins( vector3_subtracted( bounds.origin, bounds.extents ) );
106 Vector3 maxs( vector3_added( bounds.origin, bounds.extents ) );
108 float radius = max_extent_2d( bounds.extents, axis );
109 const Vector3& mid = bounds.origin;
112 planepts[2][( axis + 1 ) % 3] = mins[( axis + 1 ) % 3];
113 planepts[2][( axis + 2 ) % 3] = mins[( axis + 2 ) % 3];
114 planepts[2][axis] = maxs[axis];
115 planepts[1][( axis + 1 ) % 3] = maxs[( axis + 1 ) % 3];
116 planepts[1][( axis + 2 ) % 3] = mins[( axis + 2 ) % 3];
117 planepts[1][axis] = maxs[axis];
118 planepts[0][( axis + 1 ) % 3] = maxs[( axis + 1 ) % 3];
119 planepts[0][( axis + 2 ) % 3] = maxs[( axis + 2 ) % 3];
120 planepts[0][axis] = maxs[axis];
122 brush.addPlane( planepts[0], planepts[1], planepts[2], shader, projection );
124 planepts[0][( axis + 1 ) % 3] = mins[( axis + 1 ) % 3];
125 planepts[0][( axis + 2 ) % 3] = mins[( axis + 2 ) % 3];
126 planepts[0][axis] = mins[axis];
127 planepts[1][( axis + 1 ) % 3] = maxs[( axis + 1 ) % 3];
128 planepts[1][( axis + 2 ) % 3] = mins[( axis + 2 ) % 3];
129 planepts[1][axis] = mins[axis];
130 planepts[2][( axis + 1 ) % 3] = maxs[( axis + 1 ) % 3];
131 planepts[2][( axis + 2 ) % 3] = maxs[( axis + 2 ) % 3];
132 planepts[2][axis] = mins[axis];
134 brush.addPlane( planepts[0], planepts[1], planepts[2], shader, projection );
136 for ( std::size_t i = 0 ; i < sides ; ++i )
138 double sv = sin( i * 3.14159265 * 2 / sides );
139 double cv = cos( i * 3.14159265 * 2 / sides );
141 planepts[0][( axis + 1 ) % 3] = static_cast<float>( floor( mid[( axis + 1 ) % 3] + radius * cv + 0.5 ) );
142 planepts[0][( axis + 2 ) % 3] = static_cast<float>( floor( mid[( axis + 2 ) % 3] + radius * sv + 0.5 ) );
143 planepts[0][axis] = mins[axis];
145 planepts[1][( axis + 1 ) % 3] = planepts[0][( axis + 1 ) % 3];
146 planepts[1][( axis + 2 ) % 3] = planepts[0][( axis + 2 ) % 3];
147 planepts[1][axis] = maxs[axis];
149 planepts[2][( axis + 1 ) % 3] = static_cast<float>( floor( planepts[0][( axis + 1 ) % 3] - radius * sv + 0.5 ) );
150 planepts[2][( axis + 2 ) % 3] = static_cast<float>( floor( planepts[0][( axis + 2 ) % 3] + radius * cv + 0.5 ) );
151 planepts[2][axis] = maxs[axis];
153 brush.addPlane( planepts[0], planepts[1], planepts[2], shader, projection );
157 const std::size_t c_brushCone_minSides = 3;
158 const std::size_t c_brushCone_maxSides = 32;
159 const char* const c_brushCone_name = "brushCone";
161 void Brush_ConstructCone( Brush& brush, const AABB& bounds, std::size_t sides, const char* shader, const TextureProjection& projection ){
162 if ( sides < c_brushCone_minSides ) {
163 globalErrorStream() << c_brushCone_name << ": sides " << Unsigned( sides ) << ": too few sides, minimum is " << Unsigned( c_brushCone_minSides ) << "\n";
166 if ( sides > c_brushCone_maxSides ) {
167 globalErrorStream() << c_brushCone_name << ": sides " << Unsigned( sides ) << ": too many sides, maximum is " << Unsigned( c_brushCone_maxSides ) << "\n";
172 brush.reserve( sides + 1 );
174 Vector3 mins( vector3_subtracted( bounds.origin, bounds.extents ) );
175 Vector3 maxs( vector3_added( bounds.origin, bounds.extents ) );
177 float radius = max_extent( bounds.extents );
178 const Vector3& mid = bounds.origin;
181 planepts[0][0] = mins[0]; planepts[0][1] = mins[1]; planepts[0][2] = mins[2];
182 planepts[1][0] = maxs[0]; planepts[1][1] = mins[1]; planepts[1][2] = mins[2];
183 planepts[2][0] = maxs[0]; planepts[2][1] = maxs[1]; planepts[2][2] = mins[2];
185 brush.addPlane( planepts[0], planepts[1], planepts[2], shader, projection );
187 for ( std::size_t i = 0 ; i < sides ; ++i )
189 double sv = sin( i * 3.14159265 * 2 / sides );
190 double cv = cos( i * 3.14159265 * 2 / sides );
192 planepts[0][0] = static_cast<float>( floor( mid[0] + radius * cv + 0.5 ) );
193 planepts[0][1] = static_cast<float>( floor( mid[1] + radius * sv + 0.5 ) );
194 planepts[0][2] = mins[2];
196 planepts[1][0] = mid[0];
197 planepts[1][1] = mid[1];
198 planepts[1][2] = maxs[2];
200 planepts[2][0] = static_cast<float>( floor( planepts[0][0] - radius * sv + 0.5 ) );
201 planepts[2][1] = static_cast<float>( floor( planepts[0][1] + radius * cv + 0.5 ) );
202 planepts[2][2] = maxs[2];
204 brush.addPlane( planepts[0], planepts[1], planepts[2], shader, projection );
208 const std::size_t c_brushSphere_minSides = 3;
209 const std::size_t c_brushSphere_maxSides = 31;
210 const char* const c_brushSphere_name = "brushSphere";
212 void Brush_ConstructSphere( Brush& brush, const AABB& bounds, std::size_t sides, const char* shader, const TextureProjection& projection ){
213 if ( sides < c_brushSphere_minSides ) {
214 globalErrorStream() << c_brushSphere_name << ": sides " << Unsigned( sides ) << ": too few sides, minimum is " << Unsigned( c_brushSphere_minSides ) << "\n";
217 if ( sides > c_brushSphere_maxSides ) {
218 globalErrorStream() << c_brushSphere_name << ": sides " << Unsigned( sides ) << ": too many sides, maximum is " << Unsigned( c_brushSphere_maxSides ) << "\n";
223 brush.reserve( sides * sides );
225 float radius = max_extent( bounds.extents );
226 const Vector3& mid = bounds.origin;
229 double dt = 2 * c_pi / sides;
230 double dp = c_pi / sides;
231 for ( std::size_t i = 0; i < sides; i++ )
233 for ( std::size_t j = 0; j < sides - 1; j++ )
236 double p = float(j * dp - c_pi / 2);
238 planepts[0] = vector3_added( mid, vector3_scaled( vector3_for_spherical( t, p ), radius ) );
239 planepts[1] = vector3_added( mid, vector3_scaled( vector3_for_spherical( t, p + dp ), radius ) );
240 planepts[2] = vector3_added( mid, vector3_scaled( vector3_for_spherical( t + dt, p + dp ), radius ) );
242 brush.addPlane( planepts[0], planepts[1], planepts[2], shader, projection );
247 double p = ( sides - 1 ) * dp - c_pi / 2;
248 for ( std::size_t i = 0; i < sides; i++ )
252 planepts[0] = vector3_added( mid, vector3_scaled( vector3_for_spherical( t, p ), radius ) );
253 planepts[1] = vector3_added( mid, vector3_scaled( vector3_for_spherical( t + dt, p + dp ), radius ) );
254 planepts[2] = vector3_added( mid, vector3_scaled( vector3_for_spherical( t + dt, p ), radius ) );
256 brush.addPlane( planepts[0], planepts[1], planepts[2], shader, projection );
261 const std::size_t c_brushRock_minSides = 10;
262 const std::size_t c_brushRock_maxSides = 1000;
263 const char* const c_brushRock_name = "brushRock";
265 void Brush_ConstructRock( Brush& brush, const AABB& bounds, std::size_t sides, const char* shader, const TextureProjection& projection ){
266 if ( sides < c_brushRock_minSides ) {
267 globalErrorStream() << c_brushRock_name << ": sides " << Unsigned( sides ) << ": too few sides, minimum is " << Unsigned( c_brushRock_minSides ) << "\n";
270 if ( sides > c_brushRock_maxSides ) {
271 globalErrorStream() << c_brushRock_name << ": sides " << Unsigned( sides ) << ": too many sides, maximum is " << Unsigned( c_brushRock_maxSides ) << "\n";
276 brush.reserve( sides * sides );
278 float radius = max_extent( bounds.extents );
279 const Vector3& mid = bounds.origin;
282 for ( std::size_t j = 0; j < sides; j++ )
284 planepts[0][0] = rand() - ( RAND_MAX / 2 );
285 planepts[0][1] = rand() - ( RAND_MAX / 2 );
286 planepts[0][2] = rand() - ( RAND_MAX / 2 );
287 vector3_normalise( planepts[0] );
289 // find two vectors that are perpendicular to planepts[0]
290 ComputeAxisBase( planepts[0], planepts[1], planepts[2] );
292 planepts[0] = vector3_added( mid, vector3_scaled( planepts[0], radius ) );
293 planepts[1] = vector3_added( planepts[0], vector3_scaled( planepts[1], radius ) );
294 planepts[2] = vector3_added( planepts[0], vector3_scaled( planepts[2], radius ) );
296 brush.addPlane( planepts[0], planepts[1], planepts[2], shader, projection );
301 switch ( GlobalXYWnd_getCurrentViewType() )
313 void Brush_ConstructPrefab( Brush& brush, EBrushPrefab type, const AABB& bounds, std::size_t sides, const char* shader, const TextureProjection& projection ){
318 UndoableCommand undo( "brushCuboid" );
320 Brush_ConstructCuboid( brush, bounds, shader, projection );
325 int axis = GetViewAxis();
326 StringOutputStream command;
327 command << c_brushPrism_name << " -sides " << Unsigned( sides ) << " -axis " << axis;
328 UndoableCommand undo( command.c_str() );
330 Brush_ConstructPrism( brush, bounds, sides, axis, shader, projection );
335 StringOutputStream command;
336 command << c_brushCone_name << " -sides " << Unsigned( sides );
337 UndoableCommand undo( command.c_str() );
339 Brush_ConstructCone( brush, bounds, sides, shader, projection );
344 StringOutputStream command;
345 command << c_brushSphere_name << " -sides " << Unsigned( sides );
346 UndoableCommand undo( command.c_str() );
348 Brush_ConstructSphere( brush, bounds, sides, shader, projection );
353 StringOutputStream command;
354 command << c_brushRock_name << " -sides " << Unsigned( sides );
355 UndoableCommand undo( command.c_str() );
357 Brush_ConstructRock( brush, bounds, sides, shader, projection );
364 void ConstructRegionBrushes( scene::Node* brushes[6], const Vector3& region_mins, const Vector3& region_maxs ){
367 Vector3 mins( region_mins[0] - 32, region_mins[1] - 32, region_mins[2] - 32 );
370 for ( std::size_t i = 0; i < 3; i++ )
372 Vector3 maxs( region_maxs[0] + 32, region_maxs[1] + 32, region_maxs[2] + 32 );
373 maxs[i] = region_mins[i];
374 Brush_ConstructCuboid( *Node_getBrush( *brushes[i] ), aabb_for_minmax( mins, maxs ), texdef_name_default(), TextureProjection() );
380 Vector3 maxs( region_maxs[0] + 32, region_maxs[1] + 32, region_maxs[2] + 32 );
383 for ( std::size_t i = 0; i < 3; i++ )
385 Vector3 mins( region_mins[0] - 32, region_mins[1] - 32, region_mins[2] - 32 );
386 mins[i] = region_maxs[i];
387 Brush_ConstructCuboid( *Node_getBrush( *brushes[i + 3] ), aabb_for_minmax( mins, maxs ), texdef_name_default(), TextureProjection() );
395 const TextureProjection& m_projection;
397 FaceSetTexdef( const TextureProjection& projection ) : m_projection( projection ){
399 void operator()( Face& face ) const {
400 face.SetTexdef( m_projection );
404 void Scene_BrushSetTexdef_Selected( scene::Graph& graph, const TextureProjection& projection ){
405 Scene_ForEachSelectedBrush_ForEachFace( graph, FaceSetTexdef( projection ) );
409 void Scene_BrushSetTexdef_Component_Selected( scene::Graph& graph, const TextureProjection& projection ){
410 Scene_ForEachSelectedBrushFace( graph, FaceSetTexdef( projection ) );
417 const ContentsFlagsValue& m_projection;
419 FaceSetFlags( const ContentsFlagsValue& flags ) : m_projection( flags ){
421 void operator()( Face& face ) const {
422 face.SetFlags( m_projection );
426 void Scene_BrushSetFlags_Selected( scene::Graph& graph, const ContentsFlagsValue& flags ){
427 Scene_ForEachSelectedBrush_ForEachFace( graph, FaceSetFlags( flags ) );
431 void Scene_BrushSetFlags_Component_Selected( scene::Graph& graph, const ContentsFlagsValue& flags ){
432 Scene_ForEachSelectedBrushFace( graph, FaceSetFlags( flags ) );
436 class FaceShiftTexdef
440 FaceShiftTexdef( float s, float t ) : m_s( s ), m_t( t ){
442 void operator()( Face& face ) const {
443 face.ShiftTexdef( m_s, m_t );
447 void Scene_BrushShiftTexdef_Selected( scene::Graph& graph, float s, float t ){
448 Scene_ForEachSelectedBrush_ForEachFace( graph, FaceShiftTexdef( s, t ) );
452 void Scene_BrushShiftTexdef_Component_Selected( scene::Graph& graph, float s, float t ){
453 Scene_ForEachSelectedBrushFace( graph, FaceShiftTexdef( s, t ) );
457 class FaceScaleTexdef
461 FaceScaleTexdef( float s, float t ) : m_s( s ), m_t( t ){
463 void operator()( Face& face ) const {
464 face.ScaleTexdef( m_s, m_t );
468 void Scene_BrushScaleTexdef_Selected( scene::Graph& graph, float s, float t ){
469 Scene_ForEachSelectedBrush_ForEachFace( graph, FaceScaleTexdef( s, t ) );
473 void Scene_BrushScaleTexdef_Component_Selected( scene::Graph& graph, float s, float t ){
474 Scene_ForEachSelectedBrushFace( graph, FaceScaleTexdef( s, t ) );
478 class FaceRotateTexdef
482 FaceRotateTexdef( float angle ) : m_angle( angle ){
484 void operator()( Face& face ) const {
485 face.RotateTexdef( m_angle );
489 void Scene_BrushRotateTexdef_Selected( scene::Graph& graph, float angle ){
490 Scene_ForEachSelectedBrush_ForEachFace( graph, FaceRotateTexdef( angle ) );
494 void Scene_BrushRotateTexdef_Component_Selected( scene::Graph& graph, float angle ){
495 Scene_ForEachSelectedBrushFace( graph, FaceRotateTexdef( angle ) );
504 FaceSetShader( const char* name ) : m_name( name ) {}
505 void operator()( Face& face ) const {
506 face.SetShader( m_name );
510 void Scene_BrushSetShader_Selected( scene::Graph& graph, const char* name ){
511 Scene_ForEachSelectedBrush_ForEachFace( graph, FaceSetShader( name ) );
515 void Scene_BrushSetShader_Component_Selected( scene::Graph& graph, const char* name ){
516 Scene_ForEachSelectedBrushFace( graph, FaceSetShader( name ) );
524 FaceSetDetail( bool detail ) : m_detail( detail ){
526 void operator()( Face& face ) const {
527 face.setDetail( m_detail );
531 void Scene_BrushSetDetail_Selected( scene::Graph& graph, bool detail ){
532 Scene_ForEachSelectedBrush_ForEachFace( graph, FaceSetDetail( detail ) );
536 bool Face_FindReplaceShader( Face& face, const char* find, const char* replace ){
537 if ( shader_equal( face.GetShader(), find ) ) {
538 face.SetShader( replace );
544 class FaceFindReplaceShader
547 const char* m_replace;
549 FaceFindReplaceShader( const char* find, const char* replace ) : m_find( find ), m_replace( replace ){
551 void operator()( Face& face ) const {
552 Face_FindReplaceShader( face, m_find, m_replace );
559 const char* m_replace;
561 FaceFindShader( const char* find ) : m_find( find ){
563 void operator()( FaceInstance& faceinst ) const {
564 if ( shader_equal( faceinst.getFace().GetShader(), m_find ) ) {
565 faceinst.setSelected( SelectionSystem::eFace, true );
570 bool DoingSearch( const char *repl ){
571 return ( repl == NULL || ( strcmp( "textures/", repl ) == 0 ) );
574 void Scene_BrushFindReplaceShader( scene::Graph& graph, const char* find, const char* replace ){
575 if ( DoingSearch( replace ) ) {
576 Scene_ForEachBrush_ForEachFaceInstance( graph, FaceFindShader( find ) );
580 Scene_ForEachBrush_ForEachFace( graph, FaceFindReplaceShader( find, replace ) );
584 void Scene_BrushFindReplaceShader_Selected( scene::Graph& graph, const char* find, const char* replace ){
585 if ( DoingSearch( replace ) ) {
586 Scene_ForEachSelectedBrush_ForEachFaceInstance( graph,
587 FaceFindShader( find ) );
591 Scene_ForEachSelectedBrush_ForEachFace( graph,
592 FaceFindReplaceShader( find, replace ) );
596 // TODO: find for components
597 // d1223m: dont even know what they are...
598 void Scene_BrushFindReplaceShader_Component_Selected( scene::Graph& graph, const char* find, const char* replace ){
599 if ( DoingSearch( replace ) ) {
604 Scene_ForEachSelectedBrushFace( graph, FaceFindReplaceShader( find, replace ) );
611 float m_s_repeat, m_t_repeat;
613 FaceFitTexture( float s_repeat, float t_repeat ) : m_s_repeat( s_repeat ), m_t_repeat( t_repeat ){
615 void operator()( Face& face ) const {
616 face.FitTexture( m_s_repeat, m_t_repeat );
620 void Scene_BrushFitTexture_Selected( scene::Graph& graph, float s_repeat, float t_repeat ){
621 Scene_ForEachSelectedBrush_ForEachFace( graph, FaceFitTexture( s_repeat, t_repeat ) );
625 void Scene_BrushFitTexture_Component_Selected( scene::Graph& graph, float s_repeat, float t_repeat ){
626 Scene_ForEachSelectedBrushFace( graph, FaceFitTexture( s_repeat, t_repeat ) );
630 TextureProjection g_defaultTextureProjection;
631 const TextureProjection& TextureTransform_getDefault(){
632 TexDef_Construct_Default( g_defaultTextureProjection );
633 return g_defaultTextureProjection;
636 void Scene_BrushConstructPrefab( scene::Graph& graph, EBrushPrefab type, std::size_t sides, const char* shader ){
637 if ( GlobalSelectionSystem().countSelected() != 0 ) {
638 const scene::Path& path = GlobalSelectionSystem().ultimateSelected().path();
640 Brush* brush = Node_getBrush( path.top() );
642 AABB bounds = brush->localAABB(); // copy bounds because the brush will be modified
643 Brush_ConstructPrefab( *brush, type, bounds, sides, shader, TextureTransform_getDefault() );
649 void Scene_BrushResize_Selected( scene::Graph& graph, const AABB& bounds, const char* shader ){
650 if ( GlobalSelectionSystem().countSelected() != 0 ) {
651 const scene::Path& path = GlobalSelectionSystem().ultimateSelected().path();
653 Brush* brush = Node_getBrush( path.top() );
655 Brush_ConstructCuboid( *brush, bounds, shader, TextureTransform_getDefault() );
661 bool Brush_hasShader( const Brush& brush, const char* name ){
662 for ( Brush::const_iterator i = brush.begin(); i != brush.end(); ++i )
664 if ( shader_equal( ( *i )->GetShader(), name ) ) {
671 class BrushSelectByShaderWalker : public scene::Graph::Walker
675 BrushSelectByShaderWalker( const char* name )
678 bool pre( const scene::Path& path, scene::Instance& instance ) const {
679 if ( path.top().get().visible() ) {
680 Brush* brush = Node_getBrush( path.top() );
681 if ( brush != 0 && Brush_hasShader( *brush, m_name ) ) {
682 Instance_getSelectable( instance )->setSelected( true );
689 void Scene_BrushSelectByShader( scene::Graph& graph, const char* name ){
690 graph.traverse( BrushSelectByShaderWalker( name ) );
693 class FaceSelectByShader
697 FaceSelectByShader( const char* name )
700 void operator()( FaceInstance& face ) const {
701 printf( "checking %s = %s\n", face.getFace().GetShader(), m_name );
702 if ( shader_equal( face.getFace().GetShader(), m_name ) ) {
703 face.setSelected( SelectionSystem::eFace, true );
708 void Scene_BrushSelectByShader_Component( scene::Graph& graph, const char* name ){
709 Scene_ForEachSelectedBrush_ForEachFaceInstance( graph, FaceSelectByShader( name ) );
714 TextureProjection& m_projection;
717 FaceGetTexdef( TextureProjection& projection )
718 : m_projection( projection ), m_done( false ){
720 void operator()( Face& face ) const {
723 face.GetTexdef( m_projection );
729 void Scene_BrushGetTexdef_Selected( scene::Graph& graph, TextureProjection& projection ){
730 Scene_ForEachSelectedBrush_ForEachFace( graph, FaceGetTexdef( projection ) );
733 void Scene_BrushGetTexdef_Component_Selected( scene::Graph& graph, TextureProjection& projection ){
735 if ( !g_SelectedFaceInstances.empty() ) {
736 FaceInstance& faceInstance = g_SelectedFaceInstances.last();
737 faceInstance.getFace().GetTexdef( projection );
740 FaceGetTexdef visitor( projection );
741 Scene_ForEachSelectedBrushFace( graph, visitor );
745 void Scene_BrushGetShaderSize_Component_Selected( scene::Graph& graph, size_t& width, size_t& height ){
746 if ( !g_SelectedFaceInstances.empty() ) {
747 FaceInstance& faceInstance = g_SelectedFaceInstances.last();
748 width = faceInstance.getFace().getShader().width();
749 height = faceInstance.getFace().getShader().height();
756 ContentsFlagsValue& m_flags;
759 FaceGetFlags( ContentsFlagsValue& flags )
760 : m_flags( flags ), m_done( false ){
762 void operator()( Face& face ) const {
765 face.GetFlags( m_flags );
771 void Scene_BrushGetFlags_Selected( scene::Graph& graph, ContentsFlagsValue& flags ){
773 if ( GlobalSelectionSystem().countSelected() != 0 ) {
774 BrushInstance* brush = Instance_getBrush( GlobalSelectionSystem().ultimateSelected() );
776 Brush_forEachFace( *brush, FaceGetFlags( flags ) );
780 Scene_ForEachSelectedBrush_ForEachFace( graph, FaceGetFlags( flags ) );
784 void Scene_BrushGetFlags_Component_Selected( scene::Graph& graph, ContentsFlagsValue& flags ){
786 if ( !g_SelectedFaceInstances.empty() ) {
787 FaceInstance& faceInstance = g_SelectedFaceInstances.last();
788 faceInstance.getFace().GetFlags( flags );
791 Scene_ForEachSelectedBrushFace( graph, FaceGetFlags( flags ) );
798 CopiedString& m_shader;
801 FaceGetShader( CopiedString& shader )
802 : m_shader( shader ), m_done( false ){
804 void operator()( Face& face ) const {
807 m_shader = face.GetShader();
812 void Scene_BrushGetShader_Selected( scene::Graph& graph, CopiedString& shader ){
814 if ( GlobalSelectionSystem().countSelected() != 0 ) {
815 BrushInstance* brush = Instance_getBrush( GlobalSelectionSystem().ultimateSelected() );
817 Brush_forEachFace( *brush, FaceGetShader( shader ) );
821 Scene_ForEachSelectedBrush_ForEachFace( graph, FaceGetShader( shader ) );
825 void Scene_BrushGetShader_Component_Selected( scene::Graph& graph, CopiedString& shader ){
827 if ( !g_SelectedFaceInstances.empty() ) {
828 FaceInstance& faceInstance = g_SelectedFaceInstances.last();
829 shader = faceInstance.getFace().GetShader();
832 FaceGetShader visitor( shader );
833 Scene_ForEachSelectedBrushFace( graph, visitor );
838 class filter_face_shader : public FaceFilter
840 const char* m_shader;
842 filter_face_shader( const char* shader ) : m_shader( shader ){
844 bool filter( const Face& face ) const {
845 return shader_equal( face.GetShader(), m_shader );
849 class filter_face_shader_prefix : public FaceFilter
851 const char* m_prefix;
853 filter_face_shader_prefix( const char* prefix ) : m_prefix( prefix ){
855 bool filter( const Face& face ) const {
856 return shader_equal_n( face.GetShader(), m_prefix, strlen( m_prefix ) );
860 class filter_face_flags : public FaceFilter
864 filter_face_flags( int flags ) : m_flags( flags ){
866 bool filter( const Face& face ) const {
867 return ( face.getShader().shaderFlags() & m_flags ) != 0;
871 class filter_face_contents : public FaceFilter
875 filter_face_contents( int contents ) : m_contents( contents ){
877 bool filter( const Face& face ) const {
878 return ( face.getShader().m_flags.m_contentFlags & m_contents ) != 0;
886 FaceFilter* m_filter;
889 FaceFilterAny( FaceFilter* filter, bool& filtered ) : m_filter( filter ), m_filtered( filtered ){
892 void operator()( Face& face ) const {
893 if ( m_filter->filter( face ) ) {
899 class filter_brush_any_face : public BrushFilter
901 FaceFilter* m_filter;
903 filter_brush_any_face( FaceFilter* filter ) : m_filter( filter ){
905 bool filter( const Brush& brush ) const {
907 Brush_forEachFace( brush, FaceFilterAny( m_filter, filtered ) );
914 FaceFilter* m_filter;
917 FaceFilterAll( FaceFilter* filter, bool& filtered ) : m_filter( filter ), m_filtered( filtered ){
920 void operator()( Face& face ) const {
921 if ( !m_filter->filter( face ) ) {
927 class filter_brush_all_faces : public BrushFilter
929 FaceFilter* m_filter;
931 filter_brush_all_faces( FaceFilter* filter ) : m_filter( filter ){
933 bool filter( const Brush& brush ) const {
935 Brush_forEachFace( brush, FaceFilterAll( m_filter, filtered ) );
941 filter_face_flags g_filter_face_clip( QER_CLIP );
942 filter_brush_all_faces g_filter_brush_clip( &g_filter_face_clip );
944 filter_face_shader g_filter_face_clip_q2( "textures/clip" );
945 filter_brush_all_faces g_filter_brush_clip_q2( &g_filter_face_clip_q2 );
947 filter_face_shader g_filter_face_weapclip( "textures/common/weapclip" );
948 filter_brush_all_faces g_filter_brush_weapclip( &g_filter_face_weapclip );
950 filter_face_shader g_filter_face_commonclip( "textures/common/clip" );
951 filter_brush_all_faces g_filter_brush_commonclip( &g_filter_face_commonclip );
953 filter_face_shader g_filter_face_fullclip( "textures/common/fullclip" );
954 filter_brush_all_faces g_filter_brush_fullclip( &g_filter_face_fullclip );
956 filter_face_shader g_filter_face_botclip( "textures/common/botclip" );
957 filter_brush_all_faces g_filter_brush_botclip( &g_filter_face_botclip );
959 filter_face_shader_prefix g_filter_face_caulk( "textures/common/caulk" );
960 filter_brush_all_faces g_filter_brush_caulk( &g_filter_face_caulk );
962 filter_face_shader_prefix g_filter_face_caulk_ja( "textures/system/caulk" );
963 filter_brush_all_faces g_filter_brush_caulk_ja( &g_filter_face_caulk_ja );
965 filter_face_shader_prefix g_filter_face_liquids( "textures/liquids/" );
966 filter_brush_any_face g_filter_brush_liquids( &g_filter_face_liquids );
968 filter_face_shader g_filter_face_hint( "textures/common/hint" );
969 filter_brush_any_face g_filter_brush_hint( &g_filter_face_hint );
971 filter_face_shader g_filter_face_hint_q2( "textures/hint" );
972 filter_brush_any_face g_filter_brush_hint_q2( &g_filter_face_hint_q2 );
974 filter_face_shader g_filter_face_hint_ja( "textures/system/hint" );
975 filter_brush_any_face g_filter_brush_hint_ja( &g_filter_face_hint_ja );
977 filter_face_shader g_filter_face_areaportal( "textures/common/areaportal" );
978 filter_brush_all_faces g_filter_brush_areaportal( &g_filter_face_areaportal );
980 filter_face_shader g_filter_face_visportal( "textures/editor/visportal" );
981 filter_brush_any_face g_filter_brush_visportal( &g_filter_face_visportal );
983 filter_face_shader g_filter_face_clusterportal( "textures/common/clusterportal" );
984 filter_brush_all_faces g_filter_brush_clusterportal( &g_filter_face_clusterportal );
986 filter_face_shader g_filter_face_lightgrid( "textures/common/lightgrid" );
987 filter_brush_all_faces g_filter_brush_lightgrid( &g_filter_face_lightgrid );
989 filter_face_flags g_filter_face_translucent( QER_TRANS );
990 filter_brush_all_faces g_filter_brush_translucent( &g_filter_face_translucent );
992 filter_face_contents g_filter_face_detail( BRUSH_DETAIL_MASK );
993 filter_brush_all_faces g_filter_brush_detail( &g_filter_face_detail );
995 filter_face_shader_prefix g_filter_face_decals( "textures/decals/" );
996 filter_brush_any_face g_filter_brush_decals( &g_filter_face_decals );
999 void BrushFilters_construct(){
1000 add_brush_filter( g_filter_brush_clip, EXCLUDE_CLIP );
1001 add_brush_filter( g_filter_brush_clip_q2, EXCLUDE_CLIP );
1002 add_brush_filter( g_filter_brush_weapclip, EXCLUDE_CLIP );
1003 add_brush_filter( g_filter_brush_fullclip, EXCLUDE_CLIP );
1004 add_brush_filter( g_filter_brush_commonclip, EXCLUDE_CLIP );
1005 add_brush_filter( g_filter_brush_botclip, EXCLUDE_BOTCLIP );
1006 add_brush_filter( g_filter_brush_caulk, EXCLUDE_CAULK );
1007 add_brush_filter( g_filter_brush_caulk_ja, EXCLUDE_CAULK );
1008 add_face_filter( g_filter_face_caulk, EXCLUDE_CAULK );
1009 add_face_filter( g_filter_face_caulk_ja, EXCLUDE_CAULK );
1010 add_brush_filter( g_filter_brush_liquids, EXCLUDE_LIQUIDS );
1011 add_brush_filter( g_filter_brush_hint, EXCLUDE_HINTSSKIPS );
1012 add_brush_filter( g_filter_brush_hint_q2, EXCLUDE_HINTSSKIPS );
1013 add_brush_filter( g_filter_brush_hint_ja, EXCLUDE_HINTSSKIPS );
1014 add_brush_filter( g_filter_brush_clusterportal, EXCLUDE_CLUSTERPORTALS );
1015 add_brush_filter( g_filter_brush_visportal, EXCLUDE_VISPORTALS );
1016 add_brush_filter( g_filter_brush_areaportal, EXCLUDE_AREAPORTALS );
1017 add_brush_filter( g_filter_brush_translucent, EXCLUDE_TRANSLUCENT );
1018 add_brush_filter( g_filter_brush_detail, EXCLUDE_DETAILS );
1019 add_brush_filter( g_filter_brush_detail, EXCLUDE_STRUCTURAL, true );
1020 add_brush_filter( g_filter_brush_lightgrid, EXCLUDE_LIGHTGRID );
1021 add_brush_filter( g_filter_brush_decals, EXCLUDE_DECALS );
1024 void Select_MakeDetail(){
1025 UndoableCommand undo( "brushSetDetail" );
1026 Scene_BrushSetDetail_Selected( GlobalSceneGraph(), true );
1029 void Select_MakeStructural(){
1030 UndoableCommand undo( "brushClearDetail" );
1031 Scene_BrushSetDetail_Selected( GlobalSceneGraph(), false );
1034 class BrushMakeSided
1036 std::size_t m_count;
1038 BrushMakeSided( std::size_t count )
1042 Scene_BrushConstructPrefab( GlobalSceneGraph(), eBrushPrism, m_count, TextureBrowser_GetSelectedShader( GlobalTextureBrowser() ) );
1044 typedef MemberCaller<BrushMakeSided, &BrushMakeSided::set> SetCaller;
1048 BrushMakeSided g_brushmakesided3( 3 );
1049 BrushMakeSided g_brushmakesided4( 4 );
1050 BrushMakeSided g_brushmakesided5( 5 );
1051 BrushMakeSided g_brushmakesided6( 6 );
1052 BrushMakeSided g_brushmakesided7( 7 );
1053 BrushMakeSided g_brushmakesided8( 8 );
1054 BrushMakeSided g_brushmakesided9( 9 );
1056 inline int axis_for_viewtype( int viewtype ){
1071 EBrushPrefab m_type;
1073 BrushPrefab( EBrushPrefab type )
1077 DoSides( m_type, axis_for_viewtype( GetViewAxis() ) );
1079 typedef MemberCaller<BrushPrefab, &BrushPrefab::set> SetCaller;
1082 BrushPrefab g_brushprism( eBrushPrism );
1083 BrushPrefab g_brushcone( eBrushCone );
1084 BrushPrefab g_brushsphere( eBrushSphere );
1085 BrushPrefab g_brushrock( eBrushRock );
1091 void OnClipMode( bool enable );
1095 void ClipSelected(){
1097 UndoableCommand undo( "clipperClip" );
1102 void SplitSelected(){
1104 UndoableCommand undo( "clipperSplit" );
1114 Callback g_texture_lock_status_changed;
1115 BoolExportCaller g_texdef_movelock_caller( g_brush_texturelock_enabled );
1116 ToggleItem g_texdef_movelock_item( g_texdef_movelock_caller );
1118 void Texdef_ToggleMoveLock(){
1119 g_brush_texturelock_enabled = !g_brush_texturelock_enabled;
1120 g_texdef_movelock_item.update();
1121 g_texture_lock_status_changed();
1128 void Brush_registerCommands(){
1129 GlobalToggles_insert( "TogTexLock", FreeCaller<Texdef_ToggleMoveLock>(), ToggleItem::AddCallbackCaller( g_texdef_movelock_item ), Accelerator( 'T', (GdkModifierType)GDK_SHIFT_MASK ) );
1131 GlobalCommands_insert( "BrushPrism", BrushPrefab::SetCaller( g_brushprism ) );
1132 GlobalCommands_insert( "BrushCone", BrushPrefab::SetCaller( g_brushcone ) );
1133 GlobalCommands_insert( "BrushSphere", BrushPrefab::SetCaller( g_brushsphere ) );
1134 GlobalCommands_insert( "BrushRock", BrushPrefab::SetCaller( g_brushrock ) );
1136 GlobalCommands_insert( "Brush3Sided", BrushMakeSided::SetCaller( g_brushmakesided3 ), Accelerator( '3', (GdkModifierType)GDK_CONTROL_MASK ) );
1137 GlobalCommands_insert( "Brush4Sided", BrushMakeSided::SetCaller( g_brushmakesided4 ), Accelerator( '4', (GdkModifierType)GDK_CONTROL_MASK ) );
1138 GlobalCommands_insert( "Brush5Sided", BrushMakeSided::SetCaller( g_brushmakesided5 ), Accelerator( '5', (GdkModifierType)GDK_CONTROL_MASK ) );
1139 GlobalCommands_insert( "Brush6Sided", BrushMakeSided::SetCaller( g_brushmakesided6 ), Accelerator( '6', (GdkModifierType)GDK_CONTROL_MASK ) );
1140 GlobalCommands_insert( "Brush7Sided", BrushMakeSided::SetCaller( g_brushmakesided7 ), Accelerator( '7', (GdkModifierType)GDK_CONTROL_MASK ) );
1141 GlobalCommands_insert( "Brush8Sided", BrushMakeSided::SetCaller( g_brushmakesided8 ), Accelerator( '8', (GdkModifierType)GDK_CONTROL_MASK ) );
1142 GlobalCommands_insert( "Brush9Sided", BrushMakeSided::SetCaller( g_brushmakesided9 ), Accelerator( '9', (GdkModifierType)GDK_CONTROL_MASK ) );
1144 GlobalCommands_insert( "ClipSelected", FreeCaller<ClipSelected>(), Accelerator( GDK_Return ) );
1145 GlobalCommands_insert( "SplitSelected", FreeCaller<SplitSelected>(), Accelerator( GDK_Return, (GdkModifierType)GDK_SHIFT_MASK ) );
1146 GlobalCommands_insert( "FlipClip", FreeCaller<FlipClipper>(), Accelerator( GDK_Return, (GdkModifierType)GDK_CONTROL_MASK ) );
1148 GlobalCommands_insert( "MakeDetail", FreeCaller<Select_MakeDetail>(), Accelerator( 'M', (GdkModifierType)GDK_CONTROL_MASK ) );
1149 GlobalCommands_insert( "MakeStructural", FreeCaller<Select_MakeStructural>(), Accelerator( 'S', (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) );
1152 void Brush_constructMenu( GtkMenu* menu ){
1153 create_menu_item_with_mnemonic( menu, "Prism...", "BrushPrism" );
1154 create_menu_item_with_mnemonic( menu, "Cone...", "BrushCone" );
1155 create_menu_item_with_mnemonic( menu, "Sphere...", "BrushSphere" );
1156 create_menu_item_with_mnemonic( menu, "Rock...", "BrushRock" );
1157 menu_separator( menu );
1159 GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic( menu, "CSG" );
1160 if ( g_Layout_enableDetachableMenus.m_value ) {
1161 menu_tearoff( menu_in_menu );
1163 create_menu_item_with_mnemonic( menu_in_menu, "Make _Hollow", "CSGHollow" );
1164 create_menu_item_with_mnemonic( menu_in_menu, "CSG _Subtract", "CSGSubtract" );
1165 create_menu_item_with_mnemonic( menu_in_menu, "CSG _Merge", "CSGMerge" );
1167 menu_separator( menu );
1169 GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic( menu, "Clipper" );
1170 if ( g_Layout_enableDetachableMenus.m_value ) {
1171 menu_tearoff( menu_in_menu );
1174 create_menu_item_with_mnemonic( menu_in_menu, "Clip selection", "ClipSelected" );
1175 create_menu_item_with_mnemonic( menu_in_menu, "Split selection", "SplitSelected" );
1176 create_menu_item_with_mnemonic( menu_in_menu, "Flip Clip orientation", "FlipClip" );
1178 menu_separator( menu );
1179 create_menu_item_with_mnemonic( menu, "Make detail", "MakeDetail" );
1180 create_menu_item_with_mnemonic( menu, "Make structural", "MakeStructural" );
1181 create_menu_item_with_mnemonic( menu, "Snap selection to _grid", "SnapToGrid" );
1183 create_check_menu_item_with_mnemonic( menu, "Texture Lock", "TogTexLock" );
1184 menu_separator( menu );
1185 create_menu_item_with_mnemonic( menu, "Copy Face Texture", "FaceCopyTexture" );
1186 create_menu_item_with_mnemonic( menu, "Paste Face Texture", "FacePasteTexture" );
1188 command_connect_accelerator( "Brush3Sided" );
1189 command_connect_accelerator( "Brush4Sided" );
1190 command_connect_accelerator( "Brush5Sided" );
1191 command_connect_accelerator( "Brush6Sided" );
1192 command_connect_accelerator( "Brush7Sided" );
1193 command_connect_accelerator( "Brush8Sided" );
1194 command_connect_accelerator( "Brush9Sided" );