diff --git a/plugins/entity/angles.h b/plugins/entity/angles.h index ed594bc1..12fee419 100644 --- a/plugins/entity/angles.h +++ b/plugins/entity/angles.h @@ -116,7 +116,7 @@ inline Vector3 angles_rotated( const Vector3& angles, const Quaternion& rotation ) ); } - +#if 0 inline Vector3 angles_rotated_for_rotated_pivot( const Vector3& angles, const Quaternion& rotation ){ return angles_snapped_to_zero( matrix4_get_rotation_euler_xyz_degrees( @@ -127,7 +127,7 @@ inline Vector3 angles_rotated_for_rotated_pivot( const Vector3& angles, const Qu ) ); } - +#endif class AnglesKey { Callback m_anglesChanged; diff --git a/plugins/entity/entity.cpp b/plugins/entity/entity.cpp index 0053c668..6d81463e 100644 --- a/plugins/entity/entity.cpp +++ b/plugins/entity/entity.cpp @@ -338,6 +338,7 @@ bool filter( const Entity& entity ) const { //filter_entity_classname g_filter_entity_world( "worldspawn" ); filter_entity_classname g_filter_entity_func_group( "func_group" ); +filter_entity_classname g_filter_entity_func_detail( "func_detail" ); filter_entity_classname g_filter_entity_light( "light" ); filter_entity_classname g_filter_entity_misc_model( "misc_model" ); filter_entity_classname g_filter_entity_misc_gamemodel( "misc_gamemodel" ); @@ -360,8 +361,10 @@ class filter_entity_world : public EntityFilter { public: bool filter( const Entity& entity ) const { - return string_equal( entity.getKeyValue( "classname" ), "worldspawn" ) - || string_equal( entity.getKeyValue( "classname" ), "func_group" ); + const char* value = entity.getKeyValue( "classname" ); + return string_equal( value, "worldspawn" ) + || string_equal( value, "func_group" ) + || string_equal( value, "func_detail" ); } }; @@ -370,6 +373,7 @@ filter_entity_world g_filter_entity_world; void Entity_InitFilters(){ add_entity_filter( g_filter_entity_world, EXCLUDE_WORLD ); add_entity_filter( g_filter_entity_func_group, EXCLUDE_FUNC_GROUPS ); + add_entity_filter( g_filter_entity_func_detail, EXCLUDE_DETAILS ); add_entity_filter( g_filter_entity_world, EXCLUDE_ENT, true ); add_entity_filter( g_filter_entity_trigger, EXCLUDE_TRIGGERS ); add_entity_filter( g_filter_entity_misc_model, EXCLUDE_MODELS ); diff --git a/plugins/entity/generic.cpp b/plugins/entity/generic.cpp index e6d98021..4b1e4ee1 100644 --- a/plugins/entity/generic.cpp +++ b/plugins/entity/generic.cpp @@ -118,7 +118,6 @@ public: void updateTransform(){ m_transform.localToParent() = g_matrix4_identity; matrix4_translate_by_vec3( m_transform.localToParent(), m_origin ); - //matrix4_transform_by_euler_xyz_degrees( m_transform.localToParent(), m_origin, m_angles, Vector3( 1, 1, 1 ) ); m_transformChanged(); } typedef MemberCaller UpdateTransformCaller; diff --git a/plugins/entity/miscmodel.cpp b/plugins/entity/miscmodel.cpp index 79ad58a2..302542c6 100644 --- a/plugins/entity/miscmodel.cpp +++ b/plugins/entity/miscmodel.cpp @@ -207,10 +207,18 @@ void translate( const Vector3& translation ){ m_origin = origin_translated( m_origin, translation ); } void rotate( const Quaternion& rotation ){ - m_angles = angles_rotated_for_rotated_pivot( m_angles, rotation ); + //m_angles = angles_rotated_for_rotated_pivot( m_angles, rotation ); + m_angles = angles_rotated( m_angles, rotation ); } void scale( const Vector3& scaling ){ - m_scale = scale_scaled( m_scale, scaling ); + //m_scale = scale_scaled( m_scale, scaling ); + + Matrix4 mat( matrix4_scale_for_vec3( scaling ) ); + matrix4_multiply_by_matrix4( mat, matrix4_rotation_for_euler_xyz_degrees( m_anglesKey.m_angles ) ); + matrix4_scale_by_vec3( mat, m_scale ); + + m_scale = matrix4_get_scale_vec3( mat ); + //m_angles = angles_snapped_to_zero( matrix4_get_rotation_euler_xyz_degrees( mat ) ); } void snapto( float snap ){ m_originKey.m_origin = origin_snapped( m_originKey.m_origin, snap ); @@ -285,7 +293,9 @@ void evaluateTransform(){ if( getRotation() != c_quaternion_identity ){ m_contained.rotate( getRotation() ); } - m_contained.scale( getScale() ); + if( getScale() != c_scale_identity ){ + m_contained.scale( getScale() ); + } } } void applyTransform(){ diff --git a/plugins/entity/scale.h b/plugins/entity/scale.h index 9d2759c1..c7221459 100644 --- a/plugins/entity/scale.h +++ b/plugins/entity/scale.h @@ -84,7 +84,6 @@ inline Vector3 scale_scaled( const Vector3& scale, const Vector3& scaling ){ ); } - class ScaleKey { Callback m_scaleChanged; diff --git a/radiant/brushmanip.cpp b/radiant/brushmanip.cpp index 3a02277c..f43cecd8 100644 --- a/radiant/brushmanip.cpp +++ b/radiant/brushmanip.cpp @@ -320,6 +320,74 @@ void Brush_ConstructRock( Brush& brush, const AABB& bounds, std::size_t sides, c } } +namespace icosahedron{ + +#define X .525731112119133606 +#define Z .850650808352039932 + +static float vdata[12][3] = { + { -X, 0.0, Z}, {X, 0.0, Z}, { -X, 0.0, -Z}, {X, 0.0, -Z}, + {0.0, Z, X}, {0.0, Z, -X}, {0.0, -Z, X}, {0.0, -Z, -X}, + {Z, X, 0.0}, { -Z, X, 0.0}, {Z, -X, 0.0}, { -Z, -X, 0.0} +}; +static unsigned int tindices[20][3] = { + {0, 4, 1}, {0, 9, 4}, {9, 5, 4}, {4, 5, 8}, {4, 8, 1}, + {8, 10, 1}, {8, 3, 10}, {5, 3, 8}, {5, 2, 3}, {2, 7, 3}, + {7, 10, 3}, {7, 6, 10}, {7, 11, 6}, {11, 0, 6}, {0, 1, 6}, + {6, 1, 10}, {9, 0, 11}, {9, 11, 2}, {9, 2, 5}, {7, 2, 11} +}; + +void normalize( float* a ) { + float d = sqrt( a[0] * a[0] + a[1] * a[1] + a[2] * a[2] ); + a[0] /= d; + a[1] /= d; + a[2] /= d; +} + +void drawtri( float* a, float* b, float* c, std::size_t subdivisions, Brush& brush, float radius, const Vector3& mid, const char* shader, const TextureProjection& projection ) { + if( subdivisions <= 0 ) { + brush.addPlane( Vector3( a[0], a[1], a[2] ) * radius + mid, + Vector3( b[0], b[1], b[2] ) * radius + mid, + Vector3( c[0], c[1], c[2] ) * radius + mid, + shader, projection ); + } + else{ + float ab[3], ac[3], bc[3]; + for( int i = 0; i < 3; i++ ) { + ab[i] = ( a[i] + b[i] ) / 2; + ac[i] = ( a[i] + c[i] ) / 2; + bc[i] = ( b[i] + c[i] ) / 2; + } + normalize( ab ); + normalize( ac ); + normalize( bc ); + drawtri( a, ab, ac, subdivisions - 1, brush, radius, mid, shader, projection ); + drawtri( b, bc, ab, subdivisions - 1, brush, radius, mid, shader, projection ); + drawtri( c, ac, bc, subdivisions - 1, brush, radius, mid, shader, projection ); + drawtri( ab, bc, ac, subdivisions - 1, brush, radius, mid, shader, projection ); //<--Comment this line and sphere looks really cool! + } +} + + +void Brush_ConstructIcosahedron( Brush& brush, const AABB& bounds, std::size_t subdivisions, const char* shader, const TextureProjection& projection ){ + if ( Unsigned( 20 * ( 4 << subdivisions ) ) > c_brush_maxFaces ) { + globalErrorStream() << "brushIcosahedron" << ": subdivisions " << Unsigned( subdivisions ) << ": wrong sides count requested\n"; + return; + } + + brush.clear(); + brush.reserve( 20 * ( 4 << subdivisions ) ); + + float radius = max_extent( bounds.extents ); + const Vector3& mid = bounds.origin; + + for( int i = 0; i < 20; i++ ){ + drawtri( vdata[tindices[i][0]], vdata[tindices[i][1]], vdata[tindices[i][2]], subdivisions, brush, radius, mid, shader, projection ); + } +} + +} //namespace icosahedron + int GetViewAxis(){ switch ( GlobalXYWnd_getCurrentViewType() ) { @@ -380,6 +448,15 @@ void Brush_ConstructPrefab( Brush& brush, EBrushPrefab type, const AABB& bounds, Brush_ConstructRock( brush, bounds, sides, shader, projection ); } break; + case eBrushIcosahedron: + { + StringOutputStream command; + command << "brushIcosahedron" << " -subdivisions " << Unsigned( sides ); + UndoableCommand undo( command.c_str() ); + + icosahedron::Brush_ConstructIcosahedron( brush, bounds, sides, shader, projection ); + } + break; } } @@ -707,6 +784,12 @@ void Scene_BrushResize_Selected( scene::Graph& graph, const AABB& bounds, const } } +void Brush_ConstructPlacehoderCuboid( scene::Node& node, const AABB& bounds ){ + scene::Node* brush = &GlobalBrushCreator().createBrush(); + Node_getTraversable( node )->insert( NodeSmartReference( *brush ) ); + Brush_ConstructCuboid( *Node_getBrush( *brush ), bounds, texdef_name_default(), TextureTransform_getDefault() ); +} + bool Brush_hasShader( const Brush& brush, const char* name ){ for ( Brush::const_iterator i = brush.begin(); i != brush.end(); ++i ) { @@ -1325,18 +1408,6 @@ BrushMakeSided g_brushmakesided7( 7 ); BrushMakeSided g_brushmakesided8( 8 ); BrushMakeSided g_brushmakesided9( 9 ); -inline int axis_for_viewtype( int viewtype ){ - switch ( viewtype ) - { - case XY: - return 2; - case XZ: - return 1; - case YZ: - return 0; - } - return 2; -} class BrushPrefab { @@ -1346,7 +1417,7 @@ BrushPrefab( EBrushPrefab type ) : m_type( type ){ } void set(){ - DoSides( m_type, axis_for_viewtype( GetViewAxis() ) ); + DoSides( m_type, GetViewAxis() ); } typedef MemberCaller SetCaller; }; @@ -1355,6 +1426,7 @@ BrushPrefab g_brushprism( eBrushPrism ); BrushPrefab g_brushcone( eBrushCone ); BrushPrefab g_brushsphere( eBrushSphere ); BrushPrefab g_brushrock( eBrushRock ); +BrushPrefab g_brushicosahedron( eBrushIcosahedron ); /* void FlipClip(); @@ -1404,6 +1476,7 @@ void Brush_registerCommands(){ GlobalCommands_insert( "BrushCone", BrushPrefab::SetCaller( g_brushcone ) ); GlobalCommands_insert( "BrushSphere", BrushPrefab::SetCaller( g_brushsphere ) ); GlobalCommands_insert( "BrushRock", BrushPrefab::SetCaller( g_brushrock ) ); + GlobalCommands_insert( "BrushIcosahedron", BrushPrefab::SetCaller( g_brushicosahedron ) ); GlobalCommands_insert( "Brush3Sided", BrushMakeSided::SetCaller( g_brushmakesided3 ), Accelerator( '3', (GdkModifierType)GDK_CONTROL_MASK ) ); GlobalCommands_insert( "Brush4Sided", BrushMakeSided::SetCaller( g_brushmakesided4 ), Accelerator( '4', (GdkModifierType)GDK_CONTROL_MASK ) ); @@ -1426,6 +1499,7 @@ void Brush_constructMenu( GtkMenu* menu ){ create_menu_item_with_mnemonic( menu, "Cone...", "BrushCone" ); create_menu_item_with_mnemonic( menu, "Sphere...", "BrushSphere" ); create_menu_item_with_mnemonic( menu, "Rock...", "BrushRock" ); + create_menu_item_with_mnemonic( menu, "Icosahedron...", "BrushIcosahedron" ); menu_separator( menu ); { GtkMenu* menu_in_menu = create_sub_menu_with_mnemonic( menu, "CSG" ); diff --git a/radiant/brushmanip.h b/radiant/brushmanip.h index 7302460d..605348a8 100644 --- a/radiant/brushmanip.h +++ b/radiant/brushmanip.h @@ -33,6 +33,7 @@ enum EBrushPrefab eBrushCone, eBrushSphere, eBrushRock, + eBrushIcosahedron, }; class TextureProjection; @@ -40,10 +41,12 @@ class ContentsFlagsValue; namespace scene { class Graph; +class Node; } void Scene_BrushConstructPrefab( scene::Graph& graph, EBrushPrefab type, std::size_t sides, const char* shader ); class AABB; void Scene_BrushResize_Selected( scene::Graph& graph, const AABB& bounds, const char* shader ); +void Brush_ConstructPlacehoderCuboid( scene::Node& node, const AABB& bounds ); void Scene_BrushSetTexdef_Selected( scene::Graph& graph, const TextureProjection& projection ); void Scene_BrushSetTexdef_Component_Selected( scene::Graph& graph, const TextureProjection& projection ); void Scene_BrushGetTexdef_Selected( scene::Graph& graph, TextureProjection& projection ); diff --git a/radiant/csg.cpp b/radiant/csg.cpp index 7653e64d..fc2daefa 100644 --- a/radiant/csg.cpp +++ b/radiant/csg.cpp @@ -63,341 +63,338 @@ void Face_extrude( Face& face, const Brush& brush, brush_vector_t& out, float of typedef std::vector doublevector_vector_t; -enum eHollowType +enum EHollowType { - diag = 0, - wrap = 1, - extrude = 2, - pull = 3, - room = 4, + eDiag = 0, + eWrap = 1, + eExtrude = 2, + ePull = 3, +// eRoom = 4, }; -class CaulkFace +class HollowSettings { -DoubleVector3 ExclusionAxis; -double &mindot; -double &maxdot; -doublevector_vector_t &exclude_vec; public: -CaulkFace( DoubleVector3 ExclusionAxis, - double &mindot, - double &maxdot, - doublevector_vector_t &exclude_vec ): - ExclusionAxis( ExclusionAxis ), - mindot( mindot ), - maxdot( maxdot ), - exclude_vec( exclude_vec ){} -void operator()( Face& face ) const { - double dot = vector3_dot( face.getPlane().plane3().normal(), ExclusionAxis ); - if( dot == 0 || ( dot > mindot + 0.005 && dot < maxdot - 0.005 ) ){ - if( !exclude_vec.empty() ){ - for ( doublevector_vector_t::const_iterator i = exclude_vec.begin(); i != exclude_vec.end(); ++i ){ - if( ( *i ) == face.getPlane().plane3().normal() ){ - return; - } - } - } - face.SetShader( GetCaulkShader() ); + EHollowType m_hollowType; + float m_offset; + Vector3 m_exclusionAxis; + double m_mindot; + double m_maxdot; + bool m_caulk; + bool m_removeInner; +}; + + +class CaulkFace { + const HollowSettings& m_settings; + const doublevector_vector_t& m_exclude_vec; +public: + CaulkFace( const HollowSettings& settings, const doublevector_vector_t& exclude_vec ): + m_settings( settings ), m_exclude_vec( exclude_vec ) { } -} -}; - -class FaceMakeBrush -{ -const Brush& brush; -brush_vector_t& out; -float offset; -eHollowType HollowType; -DoubleVector3 ExclusionAxis; -double &mindot; -double &maxdot; -doublevector_vector_t &exclude_vec; -bool caulk; -bool RemoveInner; -public: -FaceMakeBrush( const Brush& brush, - brush_vector_t& out, - float offset, - eHollowType HollowType, - DoubleVector3 ExclusionAxis, - double &mindot, - double &maxdot, - doublevector_vector_t &exclude_vec, - bool caulk, - bool RemoveInner ) - : brush( brush ), - out( out ), - offset( offset ), - HollowType( HollowType ), - ExclusionAxis( ExclusionAxis ), - mindot( mindot ), - maxdot( maxdot ), - exclude_vec( exclude_vec ), - caulk( caulk ), - RemoveInner( RemoveInner ){ -} -void operator()( Face& face ) const { - double dot = vector3_dot( face.getPlane().plane3().normal(), ExclusionAxis ); - if( dot == 0 || ( dot > mindot + 0.005 && dot < maxdot - 0.005 ) ){ - if( !exclude_vec.empty() ){ - for ( doublevector_vector_t::const_iterator i = exclude_vec.begin(); i != exclude_vec.end(); ++i ){ - if( ( *i ) == face.getPlane().plane3().normal() ){ + void operator()( Face& face ) const { + double dot = vector3_dot( face.getPlane().plane3().normal(), m_settings.m_exclusionAxis ); + if( dot == 0 || ( dot > m_settings.m_mindot + 0.001 && dot < m_settings.m_maxdot - 0.001 ) ) { + for( doublevector_vector_t::const_iterator i = m_exclude_vec.begin(); i != m_exclude_vec.end(); ++i ) { + if( ( *i ) == face.getPlane().plane3().normal() ) { return; } } + face.SetShader( GetCaulkShader() ); } + } +}; - if( HollowType == pull ){ - if ( face.contributes() ) { - face.getPlane().offset( offset ); - face.planeChanged(); - out.push_back( new Brush( brush ) ); - face.getPlane().offset( -offset ); - face.planeChanged(); +class FaceMakeBrush { + const Brush& m_brush; + brush_vector_t& m_out; + const HollowSettings& m_settings; + doublevector_vector_t& exclude_vec; - if( caulk ){ - Brush_forEachFace( *out.back(), CaulkFace( ExclusionAxis, mindot, maxdot, exclude_vec ) ); - } - Face* newFace = out.back()->addFace( face ); - if ( newFace != 0 ) { - newFace->flipWinding(); +public: + FaceMakeBrush( const Brush& brush, brush_vector_t& out, const HollowSettings& settings, doublevector_vector_t& exclude_vec ) + : m_brush( brush ), + m_out( out ), + m_settings( settings ), + exclude_vec( exclude_vec ) { + } + void operator()( Face& face ) const { + double dot = vector3_dot( face.getPlane().plane3().normal(), m_settings.m_exclusionAxis ); + if( dot == 0 || ( dot > m_settings.m_mindot + 0.001 && dot < m_settings.m_maxdot - 0.001 ) ) { + for( doublevector_vector_t::const_iterator i = exclude_vec.begin(); i != exclude_vec.end(); ++i ) { + if( ( *i ) == face.getPlane().plane3().normal() ) { + return; } } - } - else if( HollowType == wrap ){ - //Face_makeBrush( face, brush, out, offset ); - if ( face.contributes() ) { - face.undoSave(); - out.push_back( new Brush( brush ) ); - if( !RemoveInner && caulk ) - face.SetShader( GetCaulkShader() ); - Face* newFace = out.back()->addFace( face ); - face.getPlane().offset( -offset ); - face.planeChanged(); - if( caulk ) - face.SetShader( GetCaulkShader() ); - if ( newFace != 0 ) { - newFace->flipWinding(); - newFace->getPlane().offset( offset ); - newFace->planeChanged(); + + if( m_settings.m_hollowType == ePull ) { + if( face.contributes() ) { + face.getPlane().offset( m_settings.m_offset ); + face.planeChanged(); + m_out.push_back( new Brush( m_brush ) ); + face.getPlane().offset( -m_settings.m_offset ); + face.planeChanged(); + + if( m_settings.m_caulk ) { + Brush_forEachFace( *m_out.back(), CaulkFace( m_settings, exclude_vec ) ); + } + Face* newFace = m_out.back()->addFace( face ); + if( newFace != 0 ) { + newFace->flipWinding(); + } } } - } - else if( HollowType == extrude ){ - if ( face.contributes() ) { - //face.undoSave(); - out.push_back( new Brush( brush ) ); - out.back()->clear(); - - Face* newFace = out.back()->addFace( face ); - if ( newFace != 0 ) { - newFace->getPlane().offset( offset ); - newFace->planeChanged(); - } - - if( !RemoveInner && caulk ) - face.SetShader( GetCaulkShader() ); - newFace = out.back()->addFace( face ); - if ( newFace != 0 ) { - newFace->flipWinding(); - } - Winding& winding = face.getWinding(); - TextureProjection projection; - TexDef_Construct_Default( projection ); - for ( Winding::iterator j = winding.begin(); j != winding.end(); ++j ){ - std::size_t index = std::distance( winding.begin(), j ); - std::size_t next = Winding_next( winding, index ); - - out.back()->addPlane( winding[index].vertex, winding[next].vertex, winding[next].vertex + face.getPlane().plane3().normal() * offset, TextureBrowser_GetSelectedShader( GlobalTextureBrowser() ), projection ); + else if( m_settings.m_hollowType == eWrap ) { + //Face_makeBrush( face, brush, m_out, offset ); + if( face.contributes() ) { + face.undoSave(); + m_out.push_back( new Brush( m_brush ) ); + if( !m_settings.m_removeInner && m_settings.m_caulk ) + face.SetShader( GetCaulkShader() ); + Face* newFace = m_out.back()->addFace( face ); + face.getPlane().offset( -m_settings.m_offset ); + face.planeChanged(); + if( m_settings.m_caulk ) + face.SetShader( GetCaulkShader() ); + if( newFace != 0 ) { + newFace->flipWinding(); + newFace->getPlane().offset( m_settings.m_offset ); + newFace->planeChanged(); + } } } - } - else if( HollowType == diag ){ - if ( face.contributes() ) { - out.push_back( new Brush( brush ) ); - out.back()->clear(); + else if( m_settings.m_hollowType == eExtrude ) { + if( face.contributes() ) { + //face.undoSave(); + m_out.push_back( new Brush( m_brush ) ); + m_out.back()->clear(); - Face* newFace = out.back()->addFace( face ); - if ( newFace != 0 ) { + Face* newFace = m_out.back()->addFace( face ); + if( newFace != 0 ) { + newFace->getPlane().offset( m_settings.m_offset ); + newFace->planeChanged(); + } - newFace->planeChanged(); + if( !m_settings.m_removeInner && m_settings.m_caulk ) + face.SetShader( GetCaulkShader() ); + newFace = m_out.back()->addFace( face ); + if( newFace != 0 ) { + newFace->flipWinding(); + } + Winding& winding = face.getWinding(); + TextureProjection projection; + TexDef_Construct_Default( projection ); + for( Winding::iterator j = winding.begin(); j != winding.end(); ++j ) { + std::size_t index = std::distance( winding.begin(), j ); + std::size_t next = Winding_next( winding, index ); + + m_out.back()->addPlane( winding[index].vertex, + winding[next].vertex, + winding[next].vertex + face.getPlane().plane3().normal() * m_settings.m_offset, + TextureBrowser_GetSelectedShader( GlobalTextureBrowser() ), + projection ); + } } - newFace = out.back()->addFace( face ); + } + else if( m_settings.m_hollowType == eDiag ) { + if( face.contributes() ) { + m_out.push_back( new Brush( m_brush ) ); + m_out.back()->clear(); - if ( newFace != 0 ) { - if( !RemoveInner && caulk ) - newFace->SetShader( GetCaulkShader() ); - newFace->flipWinding(); - newFace->getPlane().offset( offset ); - newFace->planeChanged(); - } + Face* newFace = m_out.back()->addFace( face ); + if( newFace != 0 ) { + newFace->planeChanged(); + } + newFace = m_out.back()->addFace( face ); - Winding& winding = face.getWinding(); - TextureProjection projection; - TexDef_Construct_Default( projection ); - for ( Winding::iterator i = winding.begin(); i != winding.end(); ++i ){ - std::size_t index = std::distance( winding.begin(), i ); - std::size_t next = Winding_next( winding, index ); - Vector3 BestPoint; - float bestdist = 999999; + if( newFace != 0 ) { + if( !m_settings.m_removeInner && m_settings.m_caulk ){ + newFace->SetShader( GetCaulkShader() ); + } + newFace->flipWinding(); + newFace->getPlane().offset( m_settings.m_offset ); + newFace->planeChanged(); + } - for( Brush::const_iterator j = brush.begin(); j != brush.end(); ++j ){ - Winding& winding2 = ( *j )->getWinding(); - for ( Winding::iterator k = winding2.begin(); k != winding2.end(); ++k ){ - std::size_t index2 = std::distance( winding2.begin(), k ); - float testdist = vector3_length( winding[index].vertex - winding2[index2].vertex ); - if( testdist < bestdist ){ - bestdist = testdist; - BestPoint = winding2[index2].vertex; + Winding& winding = face.getWinding(); + TextureProjection projection; + TexDef_Construct_Default( projection ); + for( Winding::iterator i = winding.begin(); i != winding.end(); ++i ) { + std::size_t index = std::distance( winding.begin(), i ); + std::size_t next = Winding_next( winding, index ); + Vector3 BestPoint; + float bestdist = 999999; + + Face* parallel_face = 0; + for( Brush::const_iterator j = m_brush.begin(); j != m_brush.end(); ++j ) { + if( vector3_equal_epsilon( face.getPlane().plane3().normal(), ( *j )->getPlane().plane3().normal(), 1e-6 ) ){ + parallel_face = ( *j ); + break; } } + + if( parallel_face ){ + Winding& winding2 = parallel_face->getWinding(); + float bestdot = -1; + for( Winding::iterator k = winding2.begin(); k != winding2.end(); ++k ) { + std::size_t index2 = std::distance( winding2.begin(), k ); + float dot = vector3_dot( + vector3_normalised( + vector3_cross( + winding[index].vertex - winding[next].vertex, + winding[index].vertex - winding2[index2].vertex + ) + ), + face.getPlane().plane3().normal() + ); + if( dot > bestdot ) { + bestdot = dot; + BestPoint = winding2[index2].vertex; + } + } + } + else{ + for( Brush::const_iterator j = m_brush.begin(); j != m_brush.end(); ++j ) { + Winding& winding2 = ( *j )->getWinding(); + for( Winding::iterator k = winding2.begin(); k != winding2.end(); ++k ) { + std::size_t index2 = std::distance( winding2.begin(), k ); + float testdist = vector3_length( winding[index].vertex - winding2[index2].vertex ); + if( testdist < bestdist ) { + bestdist = testdist; + BestPoint = winding2[index2].vertex; + } + } + } + } + m_out.back()->addPlane( winding[next].vertex, + winding[index].vertex, + BestPoint, + m_settings.m_caulk ? GetCaulkShader() : TextureBrowser_GetSelectedShader( GlobalTextureBrowser() ), + projection ); } - out.back()->addPlane( winding[next].vertex, winding[index].vertex, BestPoint, caulk? GetCaulkShader() : TextureBrowser_GetSelectedShader( GlobalTextureBrowser() ), projection ); } } } } -} }; -class FaceExclude -{ -DoubleVector3 ExclusionAxis; -double &mindot; -double &maxdot; +class FaceExclude { + HollowSettings& m_settings; public: -FaceExclude( DoubleVector3 ExclusionAxis, double &mindot, double &maxdot ) - : ExclusionAxis( ExclusionAxis ), mindot( mindot ), maxdot( maxdot ){ -} -void operator()( Face& face ) const { - if( vector3_length_squared( ExclusionAxis ) != 0 ){ - double dot = vector3_dot( face.getPlane().plane3().normal(), ExclusionAxis ); - if( dot < mindot ){ - mindot = dot; + FaceExclude( HollowSettings& settings ) + : m_settings( settings ) { + } + void operator()( Face& face ) const { + double dot = vector3_dot( face.getPlane().plane3().normal(), m_settings.m_exclusionAxis ); + if( dot < m_settings.m_mindot ) { + m_settings.m_mindot = dot; } - else if( dot > maxdot ){ - maxdot = dot; + else if( dot > m_settings.m_maxdot ) { + m_settings.m_maxdot = dot; } } -} }; -class FaceOffset -{ -float offset; -DoubleVector3 ExclusionAxis; -double &mindot; -double &maxdot; -doublevector_vector_t &exclude_vec; +class FaceOffset { + const HollowSettings& m_settings; + const doublevector_vector_t& m_exclude_vec; public: -FaceOffset( float offset, DoubleVector3 ExclusionAxis, double &mindot, double &maxdot, doublevector_vector_t &exclude_vec ) - : offset( offset ), ExclusionAxis( ExclusionAxis ), mindot( mindot ), maxdot( maxdot ), exclude_vec( exclude_vec ){ -} -void operator()( Face& face ) const { - double dot = vector3_dot( face.getPlane().plane3().normal(), ExclusionAxis ); - if( dot == 0 || ( dot > mindot + 0.005 && dot < maxdot - 0.005 ) ){ - if( !exclude_vec.empty() ){ - for ( doublevector_vector_t::const_iterator i = exclude_vec.begin(); i != exclude_vec.end(); ++i ){ - if( ( *i ) == face.getPlane().plane3().normal() ){ + FaceOffset( const HollowSettings& settings, const doublevector_vector_t& exclude_vec ) + : m_settings( settings ), m_exclude_vec( exclude_vec ) { + } + void operator()( Face& face ) const { + const double dot = vector3_dot( face.getPlane().plane3().normal(), m_settings.m_exclusionAxis ); + if( dot == 0 || ( dot > m_settings.m_mindot + 0.001 && dot < m_settings.m_maxdot - 0.001 ) ) { + for( doublevector_vector_t::const_iterator i = m_exclude_vec.begin(); i != m_exclude_vec.end(); ++i ) { + if( ( *i ) == face.getPlane().plane3().normal() ) { return; } } + face.undoSave(); + face.getPlane().offset( m_settings.m_offset ); + face.planeChanged(); } - face.undoSave(); - face.getPlane().offset( offset ); - face.planeChanged(); } -} }; -class FaceExcludeSelected -{ -doublevector_vector_t &outvec; +class FaceExcludeSelected { + doublevector_vector_t& m_outvec; public: -FaceExcludeSelected( doublevector_vector_t &outvec ): outvec( outvec ){ -} -void operator()( FaceInstance& face ) const { - if( face.isSelected() ){ - outvec.push_back( face.getFace().getPlane().plane3().normal() ); + FaceExcludeSelected( doublevector_vector_t& outvec ): m_outvec( outvec ) { + } + void operator()( FaceInstance& face ) const { + if( face.isSelected() ) { + m_outvec.push_back( face.getFace().getPlane().plane3().normal() ); + } } -} }; -DoubleVector3 getExclusion(); -bool getCaulk(); -bool getRemoveInner(); +class BrushHollowSelectedWalker : public scene::Graph::Walker { + HollowSettings& m_settings; -class BrushHollowSelectedWalker : public scene::Graph::Walker -{ -float offset; -eHollowType HollowType; + float offset; + EHollowType HollowType; public: -BrushHollowSelectedWalker( float offset, eHollowType HollowType ) - : offset( offset ), HollowType( HollowType ){ -} -bool pre( const scene::Path& path, scene::Instance& instance ) const { - if ( path.top().get().visible() ) { - Brush* brush = Node_getBrush( path.top() ); - if ( brush != 0 - && Instance_getSelectable( instance )->isSelected() - && path.size() > 1 ) { - brush_vector_t out; - doublevector_vector_t exclude_vec; - double mindot = 0; - double maxdot = 0; - if( HollowType != room ){ - Brush_forEachFace( *brush, FaceExclude( getExclusion(), mindot, maxdot ) ); - if( mindot == 0 && maxdot == 0 ){ + BrushHollowSelectedWalker( HollowSettings& settings ) + : m_settings( settings ) { + } + bool pre( const scene::Path& path, scene::Instance& instance ) const { + if( path.top().get().visible() ) { + Brush* brush = Node_getBrush( path.top() ); + if( brush != 0 + && Instance_getSelectable( instance )->isSelected() + && path.size() > 1 ) { + brush_vector_t out; + doublevector_vector_t exclude_vec; + m_settings.m_mindot = m_settings.m_maxdot = 0; + + if( m_settings.m_exclusionAxis != g_vector3_identity ) { + Brush_forEachFace( *brush, FaceExclude( m_settings ) ); + } + else { Brush_ForEachFaceInstance( *Instance_getBrush( instance ), FaceExcludeSelected( exclude_vec ) ); } - } - if( HollowType == room ){ - Brush* tmpbrush = new Brush( *brush ); - tmpbrush->removeEmptyFaces(); - Brush_forEachFace( *brush, FaceMakeBrush( *brush, out, offset, pull, DoubleVector3( 0, 0, 0 ), mindot, maxdot, exclude_vec, true, true ) ); - delete tmpbrush; - } - else if( HollowType == pull ){ - if( !getRemoveInner() && getCaulk() ){ - Brush_forEachFace( *brush, CaulkFace( getExclusion(), mindot, maxdot, exclude_vec ) ); + + if( m_settings.m_hollowType == ePull ) { + if( !m_settings.m_removeInner && m_settings.m_caulk ) { + Brush_forEachFace( *brush, CaulkFace( m_settings, exclude_vec ) ); + } + Brush* tmpbrush = new Brush( *brush ); + tmpbrush->removeEmptyFaces(); + Brush_forEachFace( *tmpbrush, FaceMakeBrush( *tmpbrush, out, m_settings, exclude_vec ) ); + delete tmpbrush; } - Brush* tmpbrush = new Brush( *brush ); - tmpbrush->removeEmptyFaces(); - Brush_forEachFace( *tmpbrush, FaceMakeBrush( *tmpbrush, out, offset, HollowType, getExclusion(), mindot, maxdot, exclude_vec, getCaulk(), getRemoveInner() ) ); - delete tmpbrush; - } - else if( HollowType == diag ){ - Brush* tmpbrush = new Brush( *brush ); - Brush_forEachFace( *tmpbrush, FaceOffset( offset, getExclusion(), mindot, maxdot, exclude_vec ) ); - tmpbrush->removeEmptyFaces(); - Brush_forEachFace( *tmpbrush, FaceMakeBrush( *brush, out, offset, HollowType, getExclusion(), mindot, maxdot, exclude_vec, getCaulk(), getRemoveInner() ) ); - delete tmpbrush; - if( !getRemoveInner() && getCaulk() ){ - Brush_forEachFace( *brush, CaulkFace( getExclusion(), mindot, maxdot, exclude_vec ) ); + else if( m_settings.m_hollowType == eDiag ) { + Brush* tmpbrush = new Brush( *brush ); + Brush_forEachFace( *tmpbrush, FaceOffset( m_settings, exclude_vec ) ); + tmpbrush->removeEmptyFaces(); + Brush_forEachFace( *tmpbrush, FaceMakeBrush( *brush, out, m_settings, exclude_vec ) ); + delete tmpbrush; + if( !m_settings.m_removeInner && m_settings.m_caulk ) { + Brush_forEachFace( *brush, CaulkFace( m_settings, exclude_vec ) ); + } } - } - else{ - Brush_forEachFace( *brush, FaceMakeBrush( *brush, out, offset, HollowType, getExclusion(), mindot, maxdot, exclude_vec, getCaulk(), getRemoveInner() ) ); - } - for ( brush_vector_t::const_iterator i = out.begin(); i != out.end(); ++i ) - { - ( *i )->removeEmptyFaces(); - if( ( *i )->hasContributingFaces() ){ - NodeSmartReference node( ( new BrushNode() )->node() ); - Node_getBrush( node )->copy( *( *i ) ); - delete ( *i ); - Node_getTraversable( path.parent() )->insert( node ); - //path.push( makeReference( node.get() ) ); - //selectPath( path, true ); - //Instance_getSelectable( *GlobalSceneGraph().find( path ) )->setSelected( true ); - //Path_deleteTop( path ); + else { + Brush_forEachFace( *brush, FaceMakeBrush( *brush, out, m_settings, exclude_vec ) ); + } + for( brush_vector_t::const_iterator i = out.begin(); i != out.end(); ++i ) { + ( *i )->removeEmptyFaces(); + if( ( *i )->hasContributingFaces() ) { + NodeSmartReference node( ( new BrushNode() )->node() ); + Node_getBrush( node )->copy( *( *i ) ); + delete( *i ); + Node_getTraversable( path.parent() )->insert( node ); + //path.push( makeReference( node.get() ) ); + //selectPath( path, true ); + //Instance_getSelectable( *GlobalSceneGraph().find( path ) )->setSelected( true ); + //Path_deleteTop( path ); + } } } } + return true; } - return true; -} }; typedef std::list brushlist_t; @@ -481,17 +478,6 @@ void post( const scene::Path& path, scene::Instance& instance ) const { } }; -/* - ============= - CSG_MakeRoom - ============= - */ -void CSG_MakeRoom( void ){ - UndoableCommand undo( "makeRoom" ); - GlobalSceneGraph().traverse( BrushHollowSelectedWalker( GetGridSize(), room ) ); - GlobalSceneGraph().traverse( BrushDeleteSelected() ); - SceneChangeNotify(); -} template class RemoveReference @@ -1006,6 +992,7 @@ struct CSGToolDialog CSGToolDialog g_csgtool_dialog; +#if 0 DoubleVector3 getExclusion(){ if( gtk_toggle_button_get_active( g_csgtool_dialog.radProj ) ){ if( GlobalXYWnd_getCurrentViewType() == YZ ){ @@ -1035,101 +1022,113 @@ DoubleVector3 getExclusion(){ } return DoubleVector3( 0, 0, 0 ); } +#endif -bool getCaulk(){ - if( gtk_toggle_button_get_active( g_csgtool_dialog.caulk ) ){ - return true; - } - return false; -} - -bool getRemoveInner(){ - if( gtk_toggle_button_get_active( g_csgtool_dialog.removeInner ) ){ - return true; - } - return false; -} - -class BrushFaceOffset -{ -float offset; +class BrushFaceOffset { + HollowSettings& m_settings; public: -BrushFaceOffset( float offset ) - : offset( offset ){ -} -void operator()( BrushInstance& brush ) const { - double mindot = 0; - double maxdot = 0; - doublevector_vector_t exclude_vec; - Brush_forEachFace( brush, FaceExclude( getExclusion(), mindot, maxdot ) ); - if( mindot == 0 && maxdot == 0 ){ - Brush_ForEachFaceInstance( brush, FaceExcludeSelected( exclude_vec ) ); + BrushFaceOffset( HollowSettings& settings ) + : m_settings( settings ) { + } + void operator()( BrushInstance& brush ) const { + m_settings.m_mindot = m_settings.m_maxdot = 0; + doublevector_vector_t exclude_vec; + if( m_settings.m_exclusionAxis != g_vector3_identity ) { + Brush_forEachFace( brush, FaceExclude( m_settings ) ); + } + else { + Brush_ForEachFaceInstance( brush, FaceExcludeSelected( exclude_vec ) ); + } + Brush_forEachFace( brush, FaceOffset( m_settings, exclude_vec ) ); } - Brush_forEachFace( brush, FaceOffset( offset, getExclusion(), mindot, maxdot, exclude_vec ) ); -} }; +/* + ============= + CSG_MakeRoom + ============= + */ +void CSG_MakeRoom(){ + HollowSettings settings; + settings.m_offset = GetGridSize(); + settings.m_exclusionAxis = g_vector3_identity; + settings.m_caulk = true; + settings.m_removeInner = true; + settings.m_hollowType = ePull; + + UndoableCommand undo( "makeRoom" ); + GlobalSceneGraph().traverse( BrushHollowSelectedWalker( settings ) ); + GlobalSceneGraph().traverse( BrushDeleteSelected() ); + SceneChangeNotify(); +} + +void CSGdlg_getSettings( HollowSettings& settings, const CSGToolDialog& dialog ){ + gtk_spin_button_update( dialog.spin ); + settings.m_offset = static_cast( gtk_spin_button_get_value( dialog.spin ) ); + settings.m_exclusionAxis = g_vector3_identity; + if( gtk_toggle_button_get_active( dialog.radProj ) ){ + settings.m_exclusionAxis[ static_cast( GlobalXYWnd_getCurrentViewType() ) ] = 1; + } + else if( gtk_toggle_button_get_active( dialog.radCam ) ){ + settings.m_exclusionAxis = Camera_getViewVector( *g_pParentWnd->GetCamWnd() ); + } + settings.m_caulk = gtk_toggle_button_get_active( dialog.caulk ); + settings.m_removeInner = gtk_toggle_button_get_active( dialog.removeInner ); +} + +void CSG_Hollow( EHollowType type, const char* undoString, const CSGToolDialog& dialog ){ + HollowSettings settings; + CSGdlg_getSettings( settings, dialog ); + settings.m_hollowType = type; + UndoableCommand undo( undoString ); + GlobalSceneGraph().traverse( BrushHollowSelectedWalker( settings ) ); + if( settings.m_removeInner ){ + GlobalSceneGraph().traverse( BrushDeleteSelected() ); + } + SceneChangeNotify(); +} + //=================DLG static gboolean CSGdlg_HollowDiag( GtkWidget *widget, CSGToolDialog* dialog ){ - float offset = static_cast( gtk_spin_button_get_value( dialog->spin ) ); - UndoableCommand undo( "brushHollow::Diag" ); - GlobalSceneGraph().traverse( BrushHollowSelectedWalker( offset, diag ) ); - if( getRemoveInner() ) - GlobalSceneGraph().traverse( BrushDeleteSelected() ); - SceneChangeNotify(); + CSG_Hollow( eDiag, "brushHollow::Diag", *dialog ); return TRUE; } static gboolean CSGdlg_HollowWrap( GtkWidget *widget, CSGToolDialog* dialog ){ - float offset = static_cast( gtk_spin_button_get_value( dialog->spin ) ); - UndoableCommand undo( "brushHollow::Wrap" ); - GlobalSceneGraph().traverse( BrushHollowSelectedWalker( offset, wrap ) ); - if( getRemoveInner() ) - GlobalSceneGraph().traverse( BrushDeleteSelected() ); - SceneChangeNotify(); + CSG_Hollow( eWrap, "brushHollow::Wrap", *dialog ); return TRUE; } static gboolean CSGdlg_HollowExtrude( GtkWidget *widget, CSGToolDialog* dialog ){ - float offset = static_cast( gtk_spin_button_get_value( dialog->spin ) ); - UndoableCommand undo( "brushHollow::Extrude" ); - GlobalSceneGraph().traverse( BrushHollowSelectedWalker( offset, extrude ) ); - if( getRemoveInner() ) - GlobalSceneGraph().traverse( BrushDeleteSelected() ); - SceneChangeNotify(); + CSG_Hollow( eExtrude, "brushHollow::Extrude", *dialog ); return TRUE; } static gboolean CSGdlg_HollowPull( GtkWidget *widget, CSGToolDialog* dialog ){ - float offset = static_cast( gtk_spin_button_get_value( dialog->spin ) ); - UndoableCommand undo( "brushHollow::Pull" ); - GlobalSceneGraph().traverse( BrushHollowSelectedWalker( offset, pull ) ); - if( getRemoveInner() ) - GlobalSceneGraph().traverse( BrushDeleteSelected() ); - SceneChangeNotify(); + CSG_Hollow( ePull, "brushHollow::Pull", *dialog ); return TRUE; } static gboolean CSGdlg_BrushShrink( GtkWidget *widget, CSGToolDialog* dialog ){ - gtk_spin_button_update ( dialog->spin ); - float offset = static_cast( gtk_spin_button_get_value( dialog->spin ) ); - offset *= -1; + HollowSettings settings; + CSGdlg_getSettings( settings, *dialog ); + settings.m_offset *= -1; UndoableCommand undo( "Shrink brush" ); // GlobalSceneGraph().traverse( OffsetBrushFacesSelectedWalker( offset ) ); //Scene_ForEachSelectedBrush_ForEachFace( GlobalSceneGraph(), BrushFaceOffset( offset ) ); - Scene_forEachSelectedBrush( BrushFaceOffset( offset ) ); + Scene_forEachSelectedBrush( BrushFaceOffset( settings ) ); SceneChangeNotify(); return TRUE; } static gboolean CSGdlg_BrushExpand( GtkWidget *widget, CSGToolDialog* dialog ){ - gtk_spin_button_update ( dialog->spin ); - float offset = static_cast( gtk_spin_button_get_value( dialog->spin ) ); + HollowSettings settings; + CSGdlg_getSettings( settings, *dialog ); UndoableCommand undo( "Expand brush" ); // GlobalSceneGraph().traverse( OffsetBrushFacesSelectedWalker( offset ) ); //Scene_ForEachSelectedBrush_ForEachFace( GlobalSceneGraph(), BrushFaceOffset( offset ) ); - Scene_forEachSelectedBrush( BrushFaceOffset( offset ) ); + Scene_forEachSelectedBrush( BrushFaceOffset( settings ) ); SceneChangeNotify(); return TRUE; } diff --git a/radiant/entity.cpp b/radiant/entity.cpp index 75abd75b..78b433f7 100644 --- a/radiant/entity.cpp +++ b/radiant/entity.cpp @@ -93,19 +93,23 @@ void post( const scene::Path& path, scene::Instance& instance ) const { Entity* entity = Node_getEntity( path.top() ); if ( entity != 0 && ( instance.childSelected() || Instance_getSelectable( instance )->isSelected() ) ) { - if( string_equal_nocase( entity->getKeyValue( "classname" ), "worldspawn" ) ){ + if( string_equal( entity->getKeyValue( "classname" ), "worldspawn" ) ){ globalErrorStream() << "do not want to convert worldspawn entity\n"; return; } EntityClass* eclass = GlobalEntityClassManager().findOrInsert( m_classname, node_is_group( path.top() ) ); - if( !eclass->fixedsize && !entity->isContainer() ){ - globalErrorStream() << "can't convert point to group entity\n"; - return; - } //NodeSmartReference node( GlobalEntityCreator().createEntity( GlobalEntityClassManager().findOrInsert( m_classname, node_is_group( path.top() ) ) ) ); NodeSmartReference node( GlobalEntityCreator().createEntity( eclass ) ); + if( eclass->fixedsize && entity->isContainer() ){ + //group to point entity + char value[64]; + sprintf( value, "%g %g %g", instance.worldAABB().origin[0], instance.worldAABB().origin[1], instance.worldAABB().origin[2] ); + entity->setKeyValue( "origin", value ); + } + + EntityCopyingVisitor visitor( *Node_getEntity( node ) ); //entity->forEachKeyValue( visitor ); @@ -121,6 +125,16 @@ void post( const scene::Path& path, scene::Instance& instance ) const { Node_getTraversable( parent )->insert( node ); /* must do this after inserting node, otherwise problem: targeted + having model + not loaded b4 new entities aren't selectable normally + rendered only while 0 0 0 is rendered */ entity->forEachKeyValue( visitor ); + if( !eclass->fixedsize && !entity->isContainer() ){ + //globalErrorStream() << "can't convert point to group entity\n"; + //return; + AABB bounds( g_vector3_identity, Vector3( 16, 16, 16 ) ); + if ( !string_parse_vector3( entity->getKeyValue( "origin" ), bounds.origin ) ) { + bounds.origin = g_vector3_identity; + } + Brush_ConstructPlacehoderCuboid( node.get(), bounds ); + Node_getEntity( node )->setKeyValue( "origin", "" ); + } Node_getTraversable( parent )->erase( child ); } } @@ -131,7 +145,21 @@ void Scene_EntitySetKeyValue_Selected( const char* key, const char* value ){ } void Scene_EntitySetClassname_Selected( const char* classname ){ - GlobalSceneGraph().traverse( EntitySetClassnameSelected( classname ) ); + if ( GlobalSelectionSystem().countSelected() < 1 ) { + return; + } + + if( string_equal( classname, "worldspawn" ) ){ + UndoableCommand undo( "ungroupSelectedPrimitives" ); + Scene_parentSelectedBrushesToEntity( GlobalSceneGraph(), Map_FindOrInsertWorldspawn( g_map ) ); //=no action, if no worldspawn (but one inserted) + //Scene_parentSelectedBrushesToEntity( GlobalSceneGraph(), *Map_FindWorldspawn( g_map )); = crash, if no worldspawn + } + else{ + StringOutputStream command; + command << "entitySetClass -class " << classname; + UndoableCommand undo( command.c_str() ); + GlobalSceneGraph().traverse( EntitySetClassnameSelected( classname ) ); + } } diff --git a/radiant/entityinspector.cpp b/radiant/entityinspector.cpp index 05d4ba1e..2040ffd7 100644 --- a/radiant/entityinspector.cpp +++ b/radiant/entityinspector.cpp @@ -1184,12 +1184,9 @@ void EntityInspector_selectionChanged( const Selectable& ){ EntityInspector_keyValueChanged(); } -// Creates a new entity based on the currently selected brush and entity type. -// -void EntityClassList_createEntity(){ +void EntityClassList_convertEntity(){ GtkTreeView* view = g_entityClassList; - // find out what type of entity we are trying to create GtkTreeModel* model; GtkTreeIter iter; if ( gtk_tree_selection_get_selected( gtk_tree_view_get_selection( view ), &model, &iter ) == FALSE ) { @@ -1201,12 +1198,7 @@ void EntityClassList_createEntity(){ gtk_tree_model_get( model, &iter, 0, &text, -1 ); { - StringOutputStream command; - command << "entityCreate -class " << text; - - UndoableCommand undo( command.c_str() ); - - Entity_createFromSelection( text, g_vector3_identity ); + Scene_EntitySetClassname_Selected( text ); } g_free( text ); } @@ -1218,13 +1210,11 @@ void EntityInspector_applyKeyValue(){ StringOutputStream value( 64 ); value << gtk_entry_get_text( g_entityValueEntry ); - // TTimo: if you change the classname to worldspawn you won't merge back in the structural brushes but create a parasite entity - if ( !strcmp( key.c_str(), "classname" ) && !strcmp( value.c_str(), "worldspawn" ) ) { - gtk_MessageBox( gtk_widget_get_toplevel( GTK_WIDGET( g_entityKeyEntry ) ), "Cannot change \"classname\" key back to worldspawn.", 0, eMB_OK ); - return; - } - +// if ( !strcmp( key.c_str(), "classname" ) && !strcmp( value.c_str(), "worldspawn" ) ) { +// gtk_MessageBox( gtk_widget_get_toplevel( GTK_WIDGET( g_entityKeyEntry ) ), "Cannot change \"classname\" key back to worldspawn.", 0, eMB_OK ); +// return; +// } // RR2DO2: we don't want spaces in entity keys if ( strstr( key.c_str(), " " ) ) { @@ -1233,9 +1223,6 @@ void EntityInspector_applyKeyValue(){ } if ( strcmp( key.c_str(), "classname" ) == 0 ) { - StringOutputStream command; - command << "entitySetClass -class " << value.c_str(); - UndoableCommand undo( command.c_str() ); Scene_EntitySetClassname_Selected( value.c_str() ); } else @@ -1298,7 +1285,7 @@ static void EntityClassList_selection_changed( GtkTreeSelection* selection, gpoi static gint EntityClassList_button_press( GtkWidget *widget, GdkEventButton *event, gpointer data ){ if ( event->type == GDK_2BUTTON_PRESS ) { - EntityClassList_createEntity(); + EntityClassList_convertEntity(); return TRUE; } return FALSE; @@ -1306,7 +1293,7 @@ static gint EntityClassList_button_press( GtkWidget *widget, GdkEventButton *eve static gint EntityClassList_keypress( GtkWidget* widget, GdkEventKey* event, gpointer data ){ if ( event->keyval == GDK_Return ) { - EntityClassList_createEntity(); + EntityClassList_convertEntity(); return TRUE; } diff --git a/radiant/gtkdlgs.cpp b/radiant/gtkdlgs.cpp index fe5135a0..d418958d 100644 --- a/radiant/gtkdlgs.cpp +++ b/radiant/gtkdlgs.cpp @@ -425,6 +425,9 @@ void DoSides( int type, int axis ){ case eBrushRock : adj = GTK_ADJUSTMENT( gtk_adjustment_new( 32, 10, 1000, 1, 10, 0 ) ); break; + case eBrushIcosahedron : + adj = GTK_ADJUSTMENT( gtk_adjustment_new( 1, 0, 2, 1, 10, 0 ) ); //possible with 3, but buggy + break; default: adj = GTK_ADJUSTMENT( gtk_adjustment_new( 8, 3, 31, 1, 10, 0 ) ); break; diff --git a/radiant/map.cpp b/radiant/map.cpp index c3141c1c..90c7f9b5 100644 --- a/radiant/map.cpp +++ b/radiant/map.cpp @@ -1622,16 +1622,13 @@ void Map_RegionSelectedBrushes( void ){ Map_RegionXY =========== */ -void Map_RegionXY( float x_min, float y_min, float x_max, float y_max ){ - Map_RegionOff(); - - g_region_mins[0] = x_min; - g_region_maxs[0] = x_max; - g_region_mins[1] = y_min; - g_region_maxs[1] = y_max; - g_region_mins[2] = g_MinWorldCoord + 64; - g_region_maxs[2] = g_MaxWorldCoord - 64; +void Map_RegionXY( const Vector3& min, const Vector3& max ){ + //Map_RegionOff(); + for( std::size_t i = 0; i < 3; ++i ){ + g_region_mins[i] = std::max( g_region_mins[i], min[i] ); + g_region_maxs[i] = std::min( g_region_maxs[i], max[i] ); + } Map_ApplyRegion(); } @@ -2057,12 +2054,20 @@ void RegionOff(){ } void RegionXY(){ - Map_RegionXY( - g_pParentWnd->GetXYWnd()->GetOrigin()[0] - 0.5f * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(), - g_pParentWnd->GetXYWnd()->GetOrigin()[1] - 0.5f * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale(), - g_pParentWnd->GetXYWnd()->GetOrigin()[0] + 0.5f * g_pParentWnd->GetXYWnd()->Width() / g_pParentWnd->GetXYWnd()->Scale(), - g_pParentWnd->GetXYWnd()->GetOrigin()[1] + 0.5f * g_pParentWnd->GetXYWnd()->Height() / g_pParentWnd->GetXYWnd()->Scale() - ); + VIEWTYPE viewtype = GlobalXYWnd_getCurrentViewType(); + int nDim1 = ( viewtype == YZ ) ? 1 : 0; + int nDim2 = ( viewtype == XY ) ? 1 : 2; + int nDim = static_cast( viewtype ); + XYWnd* wnd = g_pParentWnd->ActiveXY(); + Vector3 min, max; + min[nDim1] = wnd->GetOrigin()[nDim1] - 0.5f * wnd->Width() / wnd->Scale(); + min[nDim2] = wnd->GetOrigin()[nDim2] - 0.5f * wnd->Height() / wnd->Scale(); + min[nDim] = g_MinWorldCoord + 64; + max[nDim1] = wnd->GetOrigin()[nDim1] + 0.5f * wnd->Width() / wnd->Scale(); + max[nDim2] = wnd->GetOrigin()[nDim2] + 0.5f * wnd->Height() / wnd->Scale(); + max[nDim] = g_MaxWorldCoord - 64; + + Map_RegionXY( min, max ); SceneChangeNotify(); } diff --git a/radiant/selection.cpp b/radiant/selection.cpp index f76f5e69..71c6e5b8 100644 --- a/radiant/selection.cpp +++ b/radiant/selection.cpp @@ -2267,8 +2267,9 @@ inline void matrix4_assign_rotation( Matrix4& matrix, const Matrix4& other ){ matrix[9] = other[9]; matrix[10] = other[10]; } - +#define SELECTIONSYSTEM_AXIAL_PIVOTS void matrix4_assign_rotation_for_pivot( Matrix4& matrix, scene::Instance& instance ){ +#ifndef SELECTIONSYSTEM_AXIAL_PIVOTS Editable* editable = Node_getEditable( instance.path().top() ); if ( editable != 0 ) { matrix4_assign_rotation( matrix, matrix4_multiplied_by_matrix4( instance.localToWorld(), editable->getLocalPivot() ) ); @@ -2277,6 +2278,7 @@ void matrix4_assign_rotation_for_pivot( Matrix4& matrix, scene::Instance& instan { matrix4_assign_rotation( matrix, instance.localToWorld() ); } +#endif } inline bool Instance_isSelectedComponents( scene::Instance& instance ){ @@ -2408,8 +2410,13 @@ void visit( scene::Instance& instance ) const { parent_translation, m_rotate, m_world_pivot, +#ifdef SELECTIONSYSTEM_AXIAL_PIVOTS + matrix4_multiplied_by_matrix4( matrix4_translation_for_vec3( matrix4_get_translation_vec3( instance.localToWorld() ) ), localPivot ), + matrix4_multiplied_by_matrix4( matrix4_translation_for_vec3( matrix4_get_translation_vec3( transformNode->localToParent() ) ), localPivot ) +#else matrix4_multiplied_by_matrix4( instance.localToWorld(), localPivot ), matrix4_multiplied_by_matrix4( transformNode->localToParent(), localPivot ) +#endif ); transform->setTranslation( parent_translation ); @@ -3876,6 +3883,7 @@ void RadiantSelectionSystem::ConstructPivot() const { default: break; } + } } diff --git a/radiant/xywindow.cpp b/radiant/xywindow.cpp index f2a6a52e..cc9c4d64 100644 --- a/radiant/xywindow.cpp +++ b/radiant/xywindow.cpp @@ -1059,7 +1059,7 @@ void XYWnd::Clipper_Crosshair_OnMouseMoved( int x, int y ){ void XYWnd::SetCustomPivotOrigin( int pointx, int pointy ){ Vector3 point; XY_ToPoint( pointx, pointy, point ); - VIEWTYPE viewtype = static_cast( GetViewType() ); + VIEWTYPE viewtype = GetViewType(); const int nDim = ( viewtype == YZ ) ? 0 : ( ( viewtype == XZ ) ? 1 : 2 ); //vector3_snap( point, GetSnapGridSize() ); point[nDim] = 999999; @@ -1157,7 +1157,7 @@ void XYWnd::NewBrushDrag_End( int x, int y ){ } } -void XYWnd::NewBrushDrag( int x, int y, bool square ){ +void XYWnd::NewBrushDrag( int x, int y, bool square, bool cube ){ Vector3 mins, maxs; XY_ToPoint( m_nNewBrushPressx, m_nNewBrushPressy, mins ); XY_SnapToGrid( mins ); @@ -1173,10 +1173,13 @@ void XYWnd::NewBrushDrag( int x, int y, bool square ){ maxs[nDim] = mins[nDim] + GetGridSize(); } - if( square ){ + if( square || cube ){ float squaresize = std::max( fabs( maxs[(nDim + 1) % 3] - mins[(nDim + 1) % 3] ), fabs( maxs[(nDim + 2) % 3] - mins[(nDim + 2) % 3] ) ); maxs[(nDim + 1) % 3] = ( maxs[(nDim + 1) % 3] - mins[(nDim + 1) % 3] ) > 0.f ? ( mins[(nDim + 1) % 3] + squaresize ) : ( mins[(nDim + 1) % 3] - squaresize ); maxs[(nDim + 2) % 3] = ( maxs[(nDim + 2) % 3] - mins[(nDim + 2) % 3] ) > 0.f ? ( mins[(nDim + 2) % 3] + squaresize ) : ( mins[(nDim + 2) % 3] - squaresize ); + if( cube ){ + maxs[nDim] = ( maxs[nDim] - mins[nDim] ) > 0.f ? ( mins[nDim] + squaresize ) : ( mins[nDim] - squaresize ); + } } for ( int i = 0 ; i < 3 ; i++ ) @@ -1222,13 +1225,16 @@ void entitycreate_activated( GtkMenuItem* item, gpointer user_data ){ StringOutputStream command; command << "entityCreate -class " << entity_name; UndoableCommand undo( command.c_str() ); - +#if 0 Vector3 angles( Camera_getAngles( *g_pParentWnd->GetCamWnd() ) ); Vector3 radangles( degrees_to_radians( angles[0] ), degrees_to_radians( angles[1] ), degrees_to_radians( angles[2] ) ); Vector3 viewvector; viewvector[0] = cos( radangles[1] ) * cos( radangles[0] ); viewvector[1] = sin( radangles[1] ) * cos( radangles[0] ); viewvector[2] = sin( radangles[0] ); +#else + Vector3 viewvector = -Camera_getViewVector( *g_pParentWnd->GetCamWnd() ); +#endif float offset_for_multiple = ( GetSnapGridSize() < 8.f ? 8.f : GetSnapGridSize() ) * g_entityCreationOffset; Vector3 point = viewvector * ( 64.f + offset_for_multiple ) + Camera_getOrigin( *g_pParentWnd->GetCamWnd() ); @@ -1241,26 +1247,19 @@ void entitycreate_activated( GtkMenuItem* item, gpointer user_data ){ ++g_entityCreationOffset; } else { - GlobalRadiant().m_pfnMessageBox( GTK_WIDGET( MainFrame_getWindow() ), "There's already a worldspawn in your map!" - "", - "Info", - eMB_OK, - eMB_ICONDEFAULT ); +// GlobalRadiant().m_pfnMessageBox( GTK_WIDGET( MainFrame_getWindow() ), "There's already a worldspawn in your map!" +// "", +// "Info", +// eMB_OK, +// eMB_ICONDEFAULT ); + Scene_EntitySetClassname_Selected( entity_name ); //ungroupSelectedPrimitives } } gboolean entitycreate_rightClicked( GtkWidget* widget, GdkEvent* event, gpointer user_data ) { /* convert entities */ if ( event->button.button == 3 ) { -// globalOutputStream() << "yo+\n"; - - const char* entity_name = gtk_label_get_text( GTK_LABEL( GTK_BIN( widget )->child ) ); - StringOutputStream command; - command << "entitySetClass -class " << entity_name; - UndoableCommand undo( command.c_str() ); - - Scene_EntitySetClassname_Selected( entity_name ); - + Scene_EntitySetClassname_Selected( gtk_label_get_text( GTK_LABEL( GTK_BIN( widget )->child ) ) ); if( ( event->button.state & GDK_CONTROL_MASK ) == 0 ){ gtk_menu_popdown( XYWnd::m_mnuDrop ); } @@ -1277,7 +1276,6 @@ gboolean entitycreate_rightClicked( GtkWidget* widget, GdkEvent* event, gpointer /* This handles unwanted rightclick release, that can occur with low res display, while activating menu from camera (=activate top menu entry) */ gboolean entitycreate_rightUnClicked( GtkWidget* widget, GdkEvent* event, gpointer user_data ) { if ( event->button.button == 3 ) { -// globalOutputStream() << "yo-\n"; return TRUE; } else if ( event->button.button == 1 && ( ( event->button.state & GDK_CONTROL_MASK ) != 0 || gtk_menu_get_tearoff_state( XYWnd::m_mnuDrop ) == TRUE ) ) { @@ -1572,7 +1570,7 @@ void XYWnd::XY_MouseMoved( int x, int y, unsigned int buttons ){ } // lbutton without selection = drag new brush else if ( m_bNewBrushDrag ) { - NewBrushDrag( x, y, buttons == ( RAD_LBUTTON | RAD_SHIFT ) ); + NewBrushDrag( x, y, buttons & RAD_SHIFT, buttons & RAD_CONTROL ); } // control mbutton = move camera diff --git a/radiant/xywindow.h b/radiant/xywindow.h index 94be7b3d..fe1cf685 100644 --- a/radiant/xywindow.h +++ b/radiant/xywindow.h @@ -118,7 +118,7 @@ void XY_MouseDown( int x, int y, unsigned int buttons ); void XY_MouseMoved( int x, int y, unsigned int buttons ); void NewBrushDrag_Begin( int x, int y ); -void NewBrushDrag( int x, int y, bool square ); +void NewBrushDrag( int x, int y, bool square, bool cube ); void NewBrushDrag_End( int x, int y ); void XY_ToPoint( int x, int y, Vector3& point ); diff --git a/setup/data/tools/bitmaps/view_cubicclipping.png b/setup/data/tools/bitmaps/view_cubicclipping.png index e01508ac..f48edac9 100644 Binary files a/setup/data/tools/bitmaps/view_cubicclipping.png and b/setup/data/tools/bitmaps/view_cubicclipping.png differ