binds...
	* doubleClick/Enter in Entity inspector Class list = convert entities
	* ctrl during creating brush = cube brush

misc...
	* on worldspawn entity create/convert to one do most expected move-selected-primitives-to-worldspawn
	* convert point entity to group one = placeholder brush at origin + remove origin key
	* convert group entity to point one: set origin key to contained primitives center
	* fix uniform rotation operations for eclassmodel, miscmodel entities
	* scale miscmodel entities uniformly
	* added func_detail to world and detail filters
	* region->set_xy: using active projection, not just xy one; is subtractive (no region off before applying)
	* new brush prefab: icosahedron
	* refactored CSGTool, improved Hollow::diagonal algorithm stability

	improved view_cubiclipping.png
This commit is contained in:
Garux 2017-08-02 09:44:13 +03:00
parent 335dcb2fa8
commit 0139fa9de6
16 changed files with 547 additions and 430 deletions

View File

@ -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;

View File

@ -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 );

View File

@ -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<GenericEntity, &GenericEntity::updateTransform> UpdateTransformCaller;

View File

@ -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,9 +293,11 @@ void evaluateTransform(){
if( getRotation() != c_quaternion_identity ){
m_contained.rotate( getRotation() );
}
if( getScale() != c_scale_identity ){
m_contained.scale( getScale() );
}
}
}
void applyTransform(){
m_contained.revertTransform();
evaluateTransform();

View File

@ -84,7 +84,6 @@ inline Vector3 scale_scaled( const Vector3& scale, const Vector3& scaling ){
);
}
class ScaleKey
{
Callback m_scaleChanged;

View File

@ -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<BrushPrefab, &BrushPrefab::set> 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" );

View File

@ -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 );

View File

@ -63,141 +63,121 @@ void Face_extrude( Face& face, const Brush& brush, brush_vector_t& out, float of
typedef std::vector<DoubleVector3> 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 ){}
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 ) {
}
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 ){
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() );
}
}
};
class FaceMakeBrush
{
const Brush& brush;
brush_vector_t& out;
float offset;
eHollowType HollowType;
DoubleVector3 ExclusionAxis;
double &mindot;
double &maxdot;
class FaceMakeBrush {
const Brush& m_brush;
brush_vector_t& m_out;
const HollowSettings& m_settings;
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 ){
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(), ExclusionAxis );
if( dot == 0 || ( dot > mindot + 0.005 && dot < maxdot - 0.005 ) ){
if( !exclude_vec.empty() ){
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;
}
}
}
if( HollowType == pull ){
if( m_settings.m_hollowType == ePull ) {
if( face.contributes() ) {
face.getPlane().offset( offset );
face.getPlane().offset( m_settings.m_offset );
face.planeChanged();
out.push_back( new Brush( brush ) );
face.getPlane().offset( -offset );
m_out.push_back( new Brush( m_brush ) );
face.getPlane().offset( -m_settings.m_offset );
face.planeChanged();
if( caulk ){
Brush_forEachFace( *out.back(), CaulkFace( ExclusionAxis, mindot, maxdot, exclude_vec ) );
if( m_settings.m_caulk ) {
Brush_forEachFace( *m_out.back(), CaulkFace( m_settings, exclude_vec ) );
}
Face* newFace = out.back()->addFace( face );
Face* newFace = m_out.back()->addFace( face );
if( newFace != 0 ) {
newFace->flipWinding();
}
}
}
else if( HollowType == wrap ){
//Face_makeBrush( face, brush, out, offset );
else if( m_settings.m_hollowType == eWrap ) {
//Face_makeBrush( face, brush, m_out, offset );
if( face.contributes() ) {
face.undoSave();
out.push_back( new Brush( brush ) );
if( !RemoveInner && caulk )
m_out.push_back( new Brush( m_brush ) );
if( !m_settings.m_removeInner && m_settings.m_caulk )
face.SetShader( GetCaulkShader() );
Face* newFace = out.back()->addFace( face );
face.getPlane().offset( -offset );
Face* newFace = m_out.back()->addFace( face );
face.getPlane().offset( -m_settings.m_offset );
face.planeChanged();
if( caulk )
if( m_settings.m_caulk )
face.SetShader( GetCaulkShader() );
if( newFace != 0 ) {
newFace->flipWinding();
newFace->getPlane().offset( offset );
newFace->getPlane().offset( m_settings.m_offset );
newFace->planeChanged();
}
}
}
else if( HollowType == extrude ){
else if( m_settings.m_hollowType == eExtrude ) {
if( face.contributes() ) {
//face.undoSave();
out.push_back( new Brush( brush ) );
out.back()->clear();
m_out.push_back( new Brush( m_brush ) );
m_out.back()->clear();
Face* newFace = out.back()->addFace( face );
Face* newFace = m_out.back()->addFace( face );
if( newFace != 0 ) {
newFace->getPlane().offset( offset );
newFace->getPlane().offset( m_settings.m_offset );
newFace->planeChanged();
}
if( !RemoveInner && caulk )
if( !m_settings.m_removeInner && m_settings.m_caulk )
face.SetShader( GetCaulkShader() );
newFace = out.back()->addFace( face );
newFace = m_out.back()->addFace( face );
if( newFace != 0 ) {
newFace->flipWinding();
}
@ -208,27 +188,31 @@ void operator()( Face& face ) const {
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 );
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 );
}
}
}
else if( HollowType == diag ){
else if( m_settings.m_hollowType == eDiag ) {
if( face.contributes() ) {
out.push_back( new Brush( brush ) );
out.back()->clear();
m_out.push_back( new Brush( m_brush ) );
m_out.back()->clear();
Face* newFace = out.back()->addFace( face );
Face* newFace = m_out.back()->addFace( face );
if( newFace != 0 ) {
newFace->planeChanged();
}
newFace = out.back()->addFace( face );
newFace = m_out.back()->addFace( face );
if( newFace != 0 ) {
if( !RemoveInner && caulk )
if( !m_settings.m_removeInner && m_settings.m_caulk ){
newFace->SetShader( GetCaulkShader() );
}
newFace->flipWinding();
newFace->getPlane().offset( offset );
newFace->getPlane().offset( m_settings.m_offset );
newFace->planeChanged();
}
@ -241,7 +225,36 @@ void operator()( Face& face ) const {
Vector3 BestPoint;
float bestdist = 999999;
for( Brush::const_iterator j = brush.begin(); j != brush.end(); ++j ){
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 );
@ -252,7 +265,12 @@ void operator()( Face& face ) const {
}
}
}
out.back()->addPlane( winding[next].vertex, winding[index].vertex, BestPoint, caulk? GetCaulkShader() : TextureBrowser_GetSelectedShader( GlobalTextureBrowser() ), projection );
}
m_out.back()->addPlane( winding[next].vertex,
winding[index].vertex,
BestPoint,
m_settings.m_caulk ? GetCaulkShader() : TextureBrowser_GetSelectedShader( GlobalTextureBrowser() ),
projection );
}
}
}
@ -260,81 +278,66 @@ void operator()( Face& face ) const {
}
};
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 ){
FaceExclude( HollowSettings& settings )
: m_settings( settings ) {
}
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;
}
else if( dot > maxdot ){
maxdot = dot;
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 > 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 ){
FaceOffset( const HollowSettings& settings, const doublevector_vector_t& exclude_vec )
: m_settings( settings ), m_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 ){
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( offset );
face.getPlane().offset( m_settings.m_offset );
face.planeChanged();
}
}
};
class FaceExcludeSelected
{
doublevector_vector_t &outvec;
class FaceExcludeSelected {
doublevector_vector_t& m_outvec;
public:
FaceExcludeSelected( doublevector_vector_t &outvec ): outvec( outvec ){
FaceExcludeSelected( doublevector_vector_t& outvec ): m_outvec( outvec ) {
}
void operator()( FaceInstance& face ) const {
if( face.isSelected() ) {
outvec.push_back( face.getFace().getPlane().plane3().normal() );
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;
EHollowType HollowType;
public:
BrushHollowSelectedWalker( float offset, eHollowType HollowType )
: offset( offset ), HollowType( HollowType ){
BrushHollowSelectedWalker( HollowSettings& settings )
: m_settings( settings ) {
}
bool pre( const scene::Path& path, scene::Instance& instance ) const {
if( path.top().get().visible() ) {
@ -344,44 +347,38 @@ bool pre( const scene::Path& path, scene::Instance& instance ) const {
&& 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 ){
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, offset, HollowType, getExclusion(), mindot, maxdot, exclude_vec, getCaulk(), getRemoveInner() ) );
Brush_forEachFace( *tmpbrush, FaceMakeBrush( *tmpbrush, out, m_settings, exclude_vec ) );
delete tmpbrush;
}
else if( HollowType == diag ){
else if( m_settings.m_hollowType == eDiag ) {
Brush* tmpbrush = new Brush( *brush );
Brush_forEachFace( *tmpbrush, FaceOffset( offset, getExclusion(), mindot, maxdot, exclude_vec ) );
Brush_forEachFace( *tmpbrush, FaceOffset( m_settings, exclude_vec ) );
tmpbrush->removeEmptyFaces();
Brush_forEachFace( *tmpbrush, FaceMakeBrush( *brush, out, offset, HollowType, getExclusion(), mindot, maxdot, exclude_vec, getCaulk(), getRemoveInner() ) );
Brush_forEachFace( *tmpbrush, FaceMakeBrush( *brush, out, m_settings, exclude_vec ) );
delete tmpbrush;
if( !getRemoveInner() && getCaulk() ){
Brush_forEachFace( *brush, CaulkFace( getExclusion(), mindot, maxdot, exclude_vec ) );
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() ) );
Brush_forEachFace( *brush, FaceMakeBrush( *brush, out, m_settings, exclude_vec ) );
}
for ( brush_vector_t::const_iterator i = out.begin(); i != out.end(); ++i )
{
for( brush_vector_t::const_iterator i = out.begin(); i != out.end(); ++i ) {
( *i )->removeEmptyFaces();
if( ( *i )->hasContributingFaces() ) {
NodeSmartReference node( ( new BrushNode() )->node() );
@ -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<typename Type>
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 ){
BrushFaceOffset( HollowSettings& settings )
: m_settings( settings ) {
}
void operator()( BrushInstance& brush ) const {
double mindot = 0;
double maxdot = 0;
m_settings.m_mindot = m_settings.m_maxdot = 0;
doublevector_vector_t exclude_vec;
Brush_forEachFace( brush, FaceExclude( getExclusion(), mindot, maxdot ) );
if( mindot == 0 && maxdot == 0 ){
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( offset, getExclusion(), mindot, maxdot, exclude_vec ) );
Brush_forEachFace( brush, FaceOffset( m_settings, 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<float>( 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<int>( 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<float>( 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<float>( 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<float>( 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<float>( 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<float>( 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<float>( 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;
}

View File

@ -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,8 +145,22 @@ void Scene_EntitySetKeyValue_Selected( const char* key, const char* value ){
}
void Scene_EntitySetClassname_Selected( const char* 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 ) );
}
}
void Entity_ungroupSelected(){

View File

@ -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;
}

View File

@ -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;

View File

@ -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<int>( 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();
}

View File

@ -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;
}
}
}

View File

@ -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<VIEWTYPE>( 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

View File

@ -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 );

Binary file not shown.

Before

Width:  |  Height:  |  Size: 240 B

After

Width:  |  Height:  |  Size: 438 B