From dfce2da577f1e56886ad26e58e37d9eda2d7c8a3 Mon Sep 17 00:00:00 2001 From: Garux Date: Wed, 2 Aug 2017 09:21:32 +0300 Subject: [PATCH] Q3map2: disable fastnormalize for light: was increasing dirt from arealights, lighting with acute angle Radiant: binds... * QE tool: alt + m1 drag in primitives mode: click face = clicked faces shear * m3 in texbro: select texture w/o applying to selection * `: XYFocusOnSelected * ctrl + shift + e: Select Connected Entities misc... * search in shortcuts list * edit shortcuts on m1 dbl click * edit shortcuts fix: could highlight a few rows for editing * texbro: toggle off hideUnused on loading a tag * fix of: undo something, select tex in texbro, no redo available * epsilon in resize brush selector to prevent perpendicular faces pickup * clone group entity primitives to separate entity on cloneSelectedMakeUnique * Focus on Selected option in Entity List (focus cam and center xy) * entity inspector: connected entities walker (select target / targeting / both)(focus) --- libs/mathlib.h | 11 ++++- libs/mathlib/mathlib.c | 2 +- libs/splines/math_matrix.h | 7 +++- radiant/brush.h | 58 +++++++++++++++++++++++++- radiant/camwindow.cpp | 13 +++++- radiant/camwindow.h | 2 + radiant/commands.cpp | 17 +++++++- radiant/entityinspector.cpp | 60 ++++++++++++++++++++++++++- radiant/entitylist.cpp | 23 +++++++++- radiant/mainframe.cpp | 13 ++++++ radiant/mainframe.h | 2 + radiant/map.cpp | 44 ++++++++++++++++++++ radiant/map.h | 1 + radiant/patchmanip.cpp | 6 ++- radiant/select.cpp | 83 +++++++++++++++++++++++++++++++++++++ radiant/select.h | 4 ++ radiant/selection.cpp | 18 ++++---- radiant/texwindow.cpp | 19 ++++----- radiant/xywindow.cpp | 83 +++++++++++++++++++++++++++++++------ radiant/xywindow.h | 2 + 20 files changed, 424 insertions(+), 44 deletions(-) diff --git a/libs/mathlib.h b/libs/mathlib.h index fb135b8a..8ed115d6 100644 --- a/libs/mathlib.h +++ b/libs/mathlib.h @@ -102,12 +102,19 @@ void _CrossProduct( vec3_t v1, vec3_t v2, vec3_t cross ); // This define affect the precision of VectorNormalize() function only. #define MATHLIB_VECTOR_NORMALIZE_PRECISION_FIX 1 vec_t VectorAccurateNormalize( const vec3_t in, vec3_t out ); -vec_t VectorFastNormalize( const vec3_t in, vec3_t out ); +vec_t VectorFastNormalize_( const vec3_t in, vec3_t out ); #if MATHLIB_VECTOR_NORMALIZE_PRECISION_FIX #define VectorNormalize VectorAccurateNormalize #else -#define VectorNormalize VectorFastNormalize +#define VectorNormalize VectorFastNormalize_ #endif + +#if 0 //use fastnormalize in a few -light spots + #define VectorFastNormalize VectorFastNormalize_ +#else + #define VectorFastNormalize VectorNormalize +#endif + vec_t ColorNormalize( const vec3_t in, vec3_t out ); void VectorInverse( vec3_t v ); void VectorPolar( vec3_t v, float radius, float theta, float phi ); diff --git a/libs/mathlib/mathlib.c b/libs/mathlib/mathlib.c index 642f9842..dbc2a0f2 100644 --- a/libs/mathlib/mathlib.c +++ b/libs/mathlib/mathlib.c @@ -179,7 +179,7 @@ vec_t VectorAccurateNormalize( const vec3_t in, vec3_t out ) { return (vec_t) length; } -vec_t VectorFastNormalize( const vec3_t in, vec3_t out ) { +vec_t VectorFastNormalize_( const vec3_t in, vec3_t out ) { // SmileTheory: This is ioquake3's VectorNormalize2 // for when accuracy matters less than speed diff --git a/libs/splines/math_matrix.h b/libs/splines/math_matrix.h index 597f1d02..8b653b0e 100644 --- a/libs/splines/math_matrix.h +++ b/libs/splines/math_matrix.h @@ -84,7 +84,12 @@ ID_INLINE mat3_t::mat3_t() { } ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) { - memcpy( mat, src, sizeof( src ) ); + //memcpy( mat, src, sizeof( src ) ); + for( unsigned int i = 0; i < 3; i++ ) { + mat[i].x = src[i][0]; + mat[i].y = src[i][1]; + mat[i].z = src[i][2]; + } } ID_INLINE mat3_t::mat3_t( idVec3 const &x, idVec3 const &y, idVec3 const &z ) { diff --git a/radiant/brush.h b/radiant/brush.h index c467af92..a7229119 100644 --- a/radiant/brush.h +++ b/radiant/brush.h @@ -2425,6 +2425,34 @@ void forEachLight( const RendererLightCallback& callback ) const { } }; +class BoolSelector : public Selector +{ +bool m_selected; +SelectionIntersection m_intersection; +Selectable* m_selectable; +public: +BoolSelector() : m_selected( false ){ +} + +void pushSelectable( Selectable& selectable ){ + m_intersection = SelectionIntersection(); + m_selectable = &selectable; +} +void popSelectable(){ + if ( m_intersection.valid() ) { + m_selected = true; + } + m_intersection = SelectionIntersection(); +} +void addIntersection( const SelectionIntersection& intersection ){ + assign_if_closer( m_intersection, intersection ); +} + +bool isSelected(){ + return m_selected; +} +}; + class FaceInstance { Face* m_face; @@ -2624,7 +2652,9 @@ void selectPlane( Selector& selector, const Line& line, const PlaneCallback& sel { Vector3 v( vector3_subtracted( line_closest_point( line, ( *i ).vertex ), ( *i ).vertex ) ); double dot = vector3_dot( getFace().plane3().normal(), v ); - if ( dot <= 0 ) { + //globalOutputStream() << dot << "\n"; + //epsilon to prevent perpendicular faces pickup + if ( dot <= 0.005 ) { return; } } @@ -2643,7 +2673,8 @@ bool trySelectPlane( const Line& line ){ for ( Winding::const_iterator i = getFace().getWinding().begin(); i != getFace().getWinding().end(); ++i ){ Vector3 v( vector3_subtracted( line_closest_point( line, ( *i ).vertex ), ( *i ).vertex ) ); double dot = vector3_dot( getFace().plane3().normal(), v ); - if ( dot <= 0 ) { + //epsilon to prevent perpendicular faces pickup + if ( dot <= 0.005 ) { return false; } } @@ -3020,6 +3051,20 @@ void selectVerticesOnPlanes( SelectionTest& test ){ } while ( faceVertex.getFace() != m_vertex->m_faceVertex.getFace() ); } + +void selectVerticesOnTestedFaces( SelectionTest& test ){ + FaceVertexId faceVertex = m_vertex->m_faceVertex; + do + { + BoolSelector selector; + m_faceInstances[faceVertex.getFace()].testSelect( selector, test ); + if( selector.isSelected() ){ + setSelected( true ); + } + faceVertex = next_vertex( m_vertex->m_faces, faceVertex ); + } + while ( faceVertex.getFace() != m_vertex->m_faceVertex.getFace() ); +} }; class BrushInstanceVisitor @@ -3486,6 +3531,15 @@ void selectVerticesOnPlanes( SelectionTest& test ){ } +void selectVerticesOnTestedFaces( SelectionTest& test ){ + test.BeginMesh( localToWorld() ); + + for ( VertexInstances::iterator i = m_vertexInstances.begin(); i != m_vertexInstances.end(); ++i ){ + ( *i ).selectVerticesOnTestedFaces( test ); + } +} + + void transformComponents( const Matrix4& matrix ){ for ( FaceInstances::iterator i = m_faceInstances.begin(); i != m_faceInstances.end(); ++i ) { diff --git a/radiant/camwindow.cpp b/radiant/camwindow.cpp index 1c782e43..99210352 100644 --- a/radiant/camwindow.cpp +++ b/radiant/camwindow.cpp @@ -1695,20 +1695,22 @@ void GlobalCamera_ResetAngles(){ void GlobalCamera_FocusOnSelected(){ CamWnd& camwnd = *g_camwnd; - +/* Vector3 angles( Camera_getAngles( camwnd ) ); 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] ); - +*/ Vector3 camorigin( Camera_getOrigin( camwnd ) ); AABB aabb( aabb_for_minmax( Select_getWorkZone().d_work_min, Select_getWorkZone().d_work_max ) ); View& view = *( camwnd.getCamera().m_view ); + Vector3 viewvector( -view.GetModelview()[2], -view.GetModelview()[6], -view.GetModelview()[10] ); + Plane3 frustumPlanes[4]; frustumPlanes[0] = plane3_translated( view.getFrustum().left, camorigin - aabb.origin ); frustumPlanes[1] = plane3_translated( view.getFrustum().right, camorigin - aabb.origin ); @@ -1732,6 +1734,13 @@ void GlobalCamera_FocusOnSelected(){ } } } +/* + globalOutputStream() << viewvector << "\n"; + globalOutputStream() << view.GetModelview()[0] << " " << view.GetModelview()[1] << " " << view.GetModelview()[2] << " " << view.GetModelview()[3] << "\n" + << view.GetModelview()[4] << " " << view.GetModelview()[5] << " " << view.GetModelview()[6] << " " << view.GetModelview()[7] << "\n" + << view.GetModelview()[8] << " " << view.GetModelview()[9] << " " << view.GetModelview()[10] << " " << view.GetModelview()[11] << "\n" + << view.GetModelview()[12] << " " << view.GetModelview()[13] << " " << view.GetModelview()[14] << " " << view.GetModelview()[15] << "\n"; +*/ Camera_setOrigin( camwnd, aabb.origin - viewvector * offset ); } diff --git a/radiant/camwindow.h b/radiant/camwindow.h index ce8db6e2..14610550 100644 --- a/radiant/camwindow.h +++ b/radiant/camwindow.h @@ -50,6 +50,8 @@ void GlobalCamera_Benchmark(); const Vector3& Camera_getOrigin( CamWnd& camwnd ); void Camera_setOrigin( CamWnd& camwnd, const Vector3& origin ); +void GlobalCamera_FocusOnSelected(); + enum { CAMERA_PITCH = 0, // up / down diff --git a/radiant/commands.cpp b/radiant/commands.cpp index f608ea49..0b802451 100644 --- a/radiant/commands.cpp +++ b/radiant/commands.cpp @@ -226,6 +226,11 @@ void accelerator_edit_button_clicked( GtkButton *btn, gpointer dialogptr ){ if ( !gtk_tree_selection_get_selected( sel, &model, &iter ) ) { return; } + if ( dialog.m_waiting_for_key ) { + // unhighlight highlit + dialog.m_waiting_for_key = false; + gtk_list_store_set( GTK_LIST_STORE( dialog.m_model ), &dialog.m_command_iter, 2, false, -1 ); + } dialog.m_command_iter = iter; dialog.m_model = model; @@ -239,6 +244,14 @@ void accelerator_edit_button_clicked( GtkButton *btn, gpointer dialogptr ){ dialog.m_waiting_for_key = true; } +gboolean accelerator_tree_butt_press( GtkWidget* widget, GdkEventButton* event, gpointer dialogptr ){ + if ( event->type == GDK_2BUTTON_PRESS && event->button == 1 ) { + accelerator_edit_button_clicked( 0, dialogptr ); + return TRUE; + } + return FALSE; +} + gboolean accelerator_window_key_press( GtkWidget *widget, GdkEventKey *event, gpointer dialogptr ){ command_list_dialog_t &dialog = *(command_list_dialog_t *) dialogptr; @@ -413,7 +426,9 @@ void DoCommandListDlg(){ GtkWidget* view = gtk_tree_view_new_with_model( GTK_TREE_MODEL( store ) ); dialog.m_list = GTK_TREE_VIEW( view ); - gtk_tree_view_set_enable_search( GTK_TREE_VIEW( view ), false ); // annoying + //gtk_tree_view_set_enable_search( GTK_TREE_VIEW( view ), false ); // annoying + + g_signal_connect( G_OBJECT( view ), "button_press_event", G_CALLBACK( accelerator_tree_butt_press ), &dialog ); { GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); diff --git a/radiant/entityinspector.cpp b/radiant/entityinspector.cpp index 4905cf01..201a4f12 100644 --- a/radiant/entityinspector.cpp +++ b/radiant/entityinspector.cpp @@ -49,6 +49,7 @@ #include #include #include +#include #include "os/path.h" @@ -78,6 +79,8 @@ #include "textureentry.h" #include "groupdialog.h" +#include "select.h" + GtkEntry* numeric_entry_new(){ GtkEntry* entry = GTK_ENTRY( gtk_entry_new() ); gtk_widget_show( GTK_WIDGET( entry ) ); @@ -778,6 +781,8 @@ GtkCheckButton* g_entitySpawnflagsCheck[MAX_FLAGS]; GtkEntry* g_entityKeyEntry; GtkEntry* g_entityValueEntry; +GtkToggleButton* g_focusToggleButton; + GtkListStore* g_entlist_store; GtkListStore* g_entprops_store; const EntityClass* g_current_flags = 0; @@ -1411,6 +1416,21 @@ static gint EntityInspector_hideWindowKB( GtkWidget* widget, GdkEventKey* event, return FALSE; } +void EntityInspector_selectTargeting( GtkButton *button, gpointer user_data ){ + bool focus = gtk_toggle_button_get_active( g_focusToggleButton ); + Select_ConnectedEntities( true, false, focus ); +} + +void EntityInspector_selectTargets( GtkButton *button, gpointer user_data ){ + bool focus = gtk_toggle_button_get_active( g_focusToggleButton ); + Select_ConnectedEntities( false, true, focus ); +} + +void EntityInspector_selectConnected( GtkButton *button, gpointer user_data ){ + bool focus = gtk_toggle_button_get_active( g_focusToggleButton ); + Select_ConnectedEntities( true, true, focus ); +} + GtkWidget* EntityInspector_constructWindow( GtkWindow* toplevel ){ GtkWidget* vbox = gtk_vbox_new( FALSE, 2 ); gtk_widget_show( vbox ); @@ -1619,22 +1639,60 @@ GtkWidget* EntityInspector_constructWindow( GtkWindow* toplevel ){ } { - GtkBox* hbox = GTK_BOX( gtk_hbox_new( TRUE, 4 ) ); + GtkBox* hbox = GTK_BOX( gtk_hbox_new( FALSE, 4 ) ); gtk_widget_show( GTK_WIDGET( hbox ) ); gtk_box_pack_start( GTK_BOX( vbox2 ), GTK_WIDGET( hbox ), FALSE, TRUE, 0 ); { GtkButton* button = GTK_BUTTON( gtk_button_new_with_label( "Clear All" ) ); + GTK_WIDGET_UNSET_FLAGS( GTK_WIDGET( button ), GTK_CAN_FOCUS ); gtk_widget_show( GTK_WIDGET( button ) ); g_signal_connect( G_OBJECT( button ), "clicked", G_CALLBACK( EntityInspector_clearAllKeyValues ), 0 ); gtk_box_pack_start( hbox, GTK_WIDGET( button ), TRUE, TRUE, 0 ); } { GtkButton* button = GTK_BUTTON( gtk_button_new_with_label( "Delete Key" ) ); + GTK_WIDGET_UNSET_FLAGS( GTK_WIDGET( button ), GTK_CAN_FOCUS ); gtk_widget_show( GTK_WIDGET( button ) ); g_signal_connect( G_OBJECT( button ), "clicked", G_CALLBACK( EntityInspector_clearKeyValue ), 0 ); gtk_box_pack_start( hbox, GTK_WIDGET( button ), TRUE, TRUE, 0 ); } + { + GtkButton* button = GTK_BUTTON( gtk_button_new_with_label( "<" ) ); + gtk_widget_set_tooltip_text( GTK_WIDGET( button ), "Select targeting entities" ); + GTK_WIDGET_UNSET_FLAGS( GTK_WIDGET( button ), GTK_CAN_FOCUS ); + gtk_widget_show( GTK_WIDGET( button ) ); + g_signal_connect( G_OBJECT( button ), "clicked", G_CALLBACK( EntityInspector_selectTargeting ), 0 ); + gtk_box_pack_start( hbox, GTK_WIDGET( button ), FALSE, FALSE, 0 ); + } + { + GtkButton* button = GTK_BUTTON( gtk_button_new_with_label( ">" ) ); + gtk_widget_set_tooltip_text( GTK_WIDGET( button ), "Select targets" ); + GTK_WIDGET_UNSET_FLAGS( GTK_WIDGET( button ), GTK_CAN_FOCUS ); + gtk_widget_show( GTK_WIDGET( button ) ); + g_signal_connect( G_OBJECT( button ), "clicked", G_CALLBACK( EntityInspector_selectTargets ), 0 ); + gtk_box_pack_start( hbox, GTK_WIDGET( button ), FALSE, FALSE, 0 ); + } + { + GtkButton* button = GTK_BUTTON( gtk_button_new_with_label( "<->" ) ); + gtk_widget_set_tooltip_text( GTK_WIDGET( button ), "Select connected entities" ); + GTK_WIDGET_UNSET_FLAGS( GTK_WIDGET( button ), GTK_CAN_FOCUS ); + gtk_widget_show( GTK_WIDGET( button ) ); + g_signal_connect( G_OBJECT( button ), "clicked", G_CALLBACK( EntityInspector_selectConnected ), 0 ); + gtk_box_pack_start( hbox, GTK_WIDGET( button ), FALSE, FALSE, 0 ); + } + { + GtkWidget* button = gtk_toggle_button_new(); + GtkImage* image = GTK_IMAGE( gtk_image_new_from_stock( GTK_STOCK_ZOOM_IN, GTK_ICON_SIZE_SMALL_TOOLBAR ) ); + gtk_widget_show( GTK_WIDGET( image ) ); + gtk_container_add( GTK_CONTAINER( button ), GTK_WIDGET( image ) ); + gtk_button_set_relief( GTK_BUTTON( button ), GTK_RELIEF_NONE ); + GTK_WIDGET_UNSET_FLAGS( button, GTK_CAN_FOCUS ); + gtk_box_pack_start( hbox, button, FALSE, FALSE, 0 ); + gtk_widget_set_tooltip_text( button, "Focus on Selected" ); + gtk_widget_show( button ); + g_focusToggleButton = GTK_TOGGLE_BUTTON( button ); + } } } diff --git a/radiant/entitylist.cpp b/radiant/entitylist.cpp index 4fdc5b4e..7f93b44f 100644 --- a/radiant/entitylist.cpp +++ b/radiant/entitylist.cpp @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include "string/string.h" #include "scenelib.h" @@ -42,6 +44,8 @@ #include "treemodel.h" +#include "mainframe.h" + void RedrawEntityList(); typedef FreeCaller RedrawEntityListCaller; @@ -63,6 +67,7 @@ IdleDraw m_idleDraw; WindowPositionTracker m_positionTracker; GtkWindow* m_window; +GtkWidget* m_check; GtkTreeView* m_tree_view; GraphTreeModel* m_tree_model; bool m_selection_disabled; @@ -157,6 +162,9 @@ static gboolean entitylist_tree_select( GtkTreeSelection *selection, GtkTreeMode getEntityList().m_selection_disabled = true; selectable->setSelected( path_currently_selected == FALSE ); getEntityList().m_selection_disabled = false; + if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( getEntityList().m_check ) ) ){ + FocusAllViews(); + } return TRUE; } @@ -295,8 +303,14 @@ void EntityList_constructWindow( GtkWindow* main_window ){ getEntityList().m_window = window; { + GtkVBox* vbox = GTK_VBOX( gtk_vbox_new( FALSE, 0 ) ); + gtk_container_set_border_width( GTK_CONTAINER( vbox ), 0 ); + gtk_widget_show( GTK_WIDGET( vbox ) ); + gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( vbox ) ); + GtkScrolledWindow* scr = create_scrolled_window( GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); - gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( scr ) ); + //gtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( scr ) ); + gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET( scr ), TRUE, TRUE, 0 ); { GtkWidget* view = gtk_tree_view_new(); @@ -319,6 +333,13 @@ void EntityList_constructWindow( GtkWindow* main_window ){ gtk_container_add( GTK_CONTAINER( scr ), view ); getEntityList().m_tree_view = GTK_TREE_VIEW( view ); } + { + GtkWidget* check = gtk_check_button_new_with_label( "Focus on Selected" ); + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check ), FALSE ); + gtk_widget_show( check ); + gtk_box_pack_start( GTK_BOX( vbox ), check, FALSE, FALSE, 0 ); + getEntityList().m_check = check; + } } EntityList_ConnectSignals( getEntityList().m_tree_view ); diff --git a/radiant/mainframe.cpp b/radiant/mainframe.cpp index 1c956db0..5e7ccc16 100644 --- a/radiant/mainframe.cpp +++ b/radiant/mainframe.cpp @@ -1163,6 +1163,12 @@ bool pre( const scene::Path& path, scene::Instance& instance ) const { && selectable->isSelected() ) { return false; } + if( doMakeUnique && instance.childSelected() ){ + NodeSmartReference clone( Node_Clone_Selected( path.top() ) ); + Map_gatherNamespaced( clone ); + Node_getTraversable( path.parent().get() )->insert( clone ); + return false; + } } return true; @@ -1916,6 +1922,7 @@ GtkMenuItem* create_edit_menu(){ // } create_menu_item_with_mnemonic( menu, "Select All Of Type", "SelectAllOfType" ); create_menu_item_with_mnemonic( menu, "_Expand Selection To Entities", "ExpandSelectionToEntities" ); + create_menu_item_with_mnemonic( menu, "Select Connected Entities", "SelectConnectedEntities" ); menu_separator( menu ); create_menu_item_with_mnemonic( menu, "Pre_ferences...", "Preferences" ); @@ -1994,6 +2001,7 @@ GtkMenuItem* create_view_menu( MainFrame::EViewStyle style ){ create_menu_item_with_mnemonic( orthographic_menu, "Center on Selected", "NextView" ); } + create_menu_item_with_mnemonic( orthographic_menu, "Focus on Selected", "XYFocusOnSelected" ); create_menu_item_with_mnemonic( orthographic_menu, "Center on Selected", "CenterXYView" ); menu_separator( orthographic_menu ); create_menu_item_with_mnemonic( orthographic_menu, "_XY 100%", "Zoom100" ); @@ -3393,6 +3401,10 @@ void Maximize_View(){ g_maximizeview.toggle(); } +void FocusAllViews(){ + XY_Centralize(); //using centralizing here, not focusing function + GlobalCamera_FocusOnSelected(); +} #include "preferencesystem.h" #include "stringio.h" @@ -3431,6 +3443,7 @@ void MainFrame_Construct(){ GlobalCommands_insert( "SelectInside", FreeCaller() ); GlobalCommands_insert( "SelectTouching", FreeCaller() ); GlobalCommands_insert( "ExpandSelectionToEntities", FreeCaller(), Accelerator( 'E', (GdkModifierType)GDK_SHIFT_MASK ) ); + GlobalCommands_insert( "SelectConnectedEntities", FreeCaller(), Accelerator( 'E', (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) ); GlobalCommands_insert( "Preferences", FreeCaller(), Accelerator( 'P' ) ); GlobalCommands_insert( "ToggleConsole", FreeCaller(), Accelerator( 'O' ) ); diff --git a/radiant/mainframe.h b/radiant/mainframe.h index 1d9cfad7..93c9ef59 100644 --- a/radiant/mainframe.h +++ b/radiant/mainframe.h @@ -277,4 +277,6 @@ void XYWindowMouseDown_disconnect( MouseEventHandlerId id ); extern GtkWidget* g_page_entity; +void FocusAllViews(); + #endif diff --git a/radiant/map.cpp b/radiant/map.cpp index 73fceb5d..93d8a67f 100644 --- a/radiant/map.cpp +++ b/radiant/map.cpp @@ -734,6 +734,50 @@ scene::Node& Node_Clone( scene::Node& node ){ return clone; } +bool Node_instanceSelected( scene::Node& node ); + +class CloneAllSelected : public scene::Traversable::Walker +{ +mutable scene::Path m_path; +public: +CloneAllSelected( scene::Node& root ) + : m_path( makeReference( root ) ){ +} +bool pre( scene::Node& node ) const { + if ( node.isRoot() ) { + return false; + } + + if( Node_instanceSelected( node ) ){ + m_path.push( makeReference( node_clone( node ) ) ); + m_path.top().get().IncRef(); + } + + return true; +} +void post( scene::Node& node ) const { + if ( node.isRoot() ) { + return; + } + + if( Node_instanceSelected( node ) ){ + Node_getTraversable( m_path.parent() )->insert( m_path.top() ); + + m_path.top().get().DecRef(); + m_path.pop(); + } +} +}; + +scene::Node& Node_Clone_Selected( scene::Node& node ){ + scene::Node& clone = node_clone( node ); + scene::Traversable* traversable = Node_getTraversable( node ); + if ( traversable != 0 ) { + traversable->traverse( CloneAllSelected( clone ) ); + } + return clone; +} + typedef std::map EntityBreakdown; diff --git a/radiant/map.h b/radiant/map.h index a359d461..6e705f6c 100644 --- a/radiant/map.h +++ b/radiant/map.h @@ -125,6 +125,7 @@ bool Map_Save(); bool Map_SaveAs(); scene::Node& Node_Clone( scene::Node& node ); +scene::Node& Node_Clone_Selected( scene::Node& node ); void DoMapInfo(); diff --git a/radiant/patchmanip.cpp b/radiant/patchmanip.cpp index be74d66a..ef22c53c 100644 --- a/radiant/patchmanip.cpp +++ b/radiant/patchmanip.cpp @@ -841,8 +841,10 @@ void Patch_registerCommands(){ GlobalCommands_insert( "PatchDeleteFirstRow", FreeCaller() ); GlobalCommands_insert( "PatchDeleteLastRow", FreeCaller(), Accelerator( GDK_KP_Subtract, (GdkModifierType)GDK_CONTROL_MASK ) ); GlobalCommands_insert( "InvertCurve", FreeCaller(), Accelerator( 'I', (GdkModifierType)GDK_CONTROL_MASK ) ); - GlobalCommands_insert( "RedisperseRows", FreeCaller(), Accelerator( 'E', (GdkModifierType)GDK_CONTROL_MASK ) ); - GlobalCommands_insert( "RedisperseCols", FreeCaller(), Accelerator( 'E', (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) ); + //GlobalCommands_insert( "RedisperseRows", FreeCaller(), Accelerator( 'E', (GdkModifierType)GDK_CONTROL_MASK ) ); + GlobalCommands_insert( "RedisperseRows", FreeCaller() ); + //GlobalCommands_insert( "RedisperseCols", FreeCaller(), Accelerator( 'E', (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) ); + GlobalCommands_insert( "RedisperseCols", FreeCaller() ); GlobalCommands_insert( "SmoothRows", FreeCaller(), Accelerator( 'W', (GdkModifierType)GDK_CONTROL_MASK ) ); GlobalCommands_insert( "SmoothCols", FreeCaller(), Accelerator( 'W', (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) ); GlobalCommands_insert( "MatrixTranspose", FreeCaller(), Accelerator( 'M', (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) ); diff --git a/radiant/select.cpp b/radiant/select.cpp index 1de2c1d0..651397ea 100644 --- a/radiant/select.cpp +++ b/radiant/select.cpp @@ -463,6 +463,13 @@ void Select_SetShader( const char* shader ){ Scene_BrushSetShader_Component_Selected( GlobalSceneGraph(), shader ); } +void Select_SetShader_Undo( const char* shader ){ + if ( GlobalSelectionSystem().countSelectedComponents() != 0 || GlobalSelectionSystem().countSelected() != 0 ) { + UndoableCommand undo( "textureNameSetSelected" ); + Select_SetShader( shader ); + } +} + void Select_SetTexdef( const TextureProjection& projection ){ if ( GlobalSelectionSystem().Mode() != SelectionSystem::eComponent ) { Scene_BrushSetTexdef_Selected( GlobalSceneGraph(), projection ); @@ -1390,3 +1397,79 @@ void DoScaleDlg(){ gtk_widget_show( GTK_WIDGET( g_scale_dialog.window ) ); } + + +class EntityGetSelectedPropertyValuesWalker_nonEmpty : public scene::Graph::Walker +{ +PropertyValues& m_propertyvalues; +const char *m_prop; +const NodeSmartReference worldspawn; +public: +EntityGetSelectedPropertyValuesWalker_nonEmpty( const char *prop, PropertyValues& propertyvalues ) + : m_propertyvalues( propertyvalues ), m_prop( prop ), worldspawn( Map_FindOrInsertWorldspawn( g_map ) ){ +} +bool pre( const scene::Path& path, scene::Instance& instance ) const { + Entity* entity = Node_getEntity( path.top() ); + if ( entity != 0 ){ + if( path.top().get() != worldspawn ){ + Selectable* selectable = Instance_getSelectable( instance ); + if ( ( selectable != 0 && selectable->isSelected() ) || instance.childSelected() ) { + const char* keyvalue = entity->getKeyValue( m_prop ); + if ( !string_empty( keyvalue ) && !propertyvalues_contain( m_propertyvalues, keyvalue ) ) { + m_propertyvalues.push_back( keyvalue ); + } + } + } + return false; + } + return true; +} +}; + +void Scene_EntityGetPropertyValues_nonEmpty( scene::Graph& graph, const char *prop, PropertyValues& propertyvalues ){ + graph.traverse( EntityGetSelectedPropertyValuesWalker_nonEmpty( prop, propertyvalues ) ); +} + +#include "preferences.h" + +void Select_ConnectedEntities( bool targeting, bool targets, bool focus ){ + PropertyValues target_propertyvalues; + PropertyValues targetname_propertyvalues; + const char *target_prop = "target"; + const char *targetname_prop; + if ( g_pGameDescription->mGameType == "doom3" ) { + targetname_prop = "name"; + } + else{ + targetname_prop = "targetname"; + } + + if( targeting ){ + Scene_EntityGetPropertyValues_nonEmpty( GlobalSceneGraph(), targetname_prop, targetname_propertyvalues ); + } + if( targets ){ + Scene_EntityGetPropertyValues_nonEmpty( GlobalSceneGraph(), target_prop, target_propertyvalues ); + } + + if( target_propertyvalues.empty() && targetname_propertyvalues.empty() ){ + globalErrorStream() << "SelectConnectedEntities: nothing found\n"; + return; + } + + if( !targeting || !targets ){ + GlobalSelectionSystem().setSelectedAll( false ); + } + if ( targeting && !targetname_propertyvalues.empty() ) { + Scene_EntitySelectByPropertyValues( GlobalSceneGraph(), target_prop, targetname_propertyvalues ); + } + if ( targets && !target_propertyvalues.empty() ) { + Scene_EntitySelectByPropertyValues( GlobalSceneGraph(), targetname_prop, target_propertyvalues ); + } + if( focus ){ + FocusAllViews(); + } +} + +void SelectConnectedEntities(){ + Select_ConnectedEntities( true, true, false ); +} diff --git a/radiant/select.h b/radiant/select.h index 5a602742..88d25f68 100644 --- a/radiant/select.h +++ b/radiant/select.h @@ -46,11 +46,15 @@ void Selection_MoveUp(); void Select_AllOfType(); +void Select_ConnectedEntities( bool targeting, bool targets, bool focus ); +void SelectConnectedEntities(); + void DoRotateDlg(); void DoScaleDlg(); void Select_SetShader( const char* shader ); +void Select_SetShader_Undo( const char* shader ); class TextureProjection; void Select_SetTexdef( const TextureProjection& projection ); diff --git a/radiant/selection.cpp b/radiant/selection.cpp index a08659b4..71c747bf 100644 --- a/radiant/selection.cpp +++ b/radiant/selection.cpp @@ -1889,12 +1889,12 @@ bool Scene_forEachPlaneSelectable_selectPlanes( scene::Graph& graph, Selector& s #include "brush.h" -/* -class TestedBrushPlanesSelectVeritces : public scene::Graph::Walker + +class TestedBrushFacesSelectVeritces : public scene::Graph::Walker { SelectionTest& m_test; public: -TestedBrushPlanesSelectVeritces( SelectionTest& test ) +TestedBrushFacesSelectVeritces( SelectionTest& test ) : m_test( test ){ } bool pre( const scene::Path& path, scene::Instance& instance ) const { @@ -1903,7 +1903,7 @@ bool pre( const scene::Path& path, scene::Instance& instance ) const { if ( selectable != 0 && selectable->isSelected() ) { BrushInstance* brushInstance = Instance_getBrush( instance ); if ( brushInstance != 0 ) { - brushInstance->selectVerticesOnPlanes( m_test ); + brushInstance->selectVerticesOnTestedFaces( m_test ); } } } @@ -1911,10 +1911,10 @@ bool pre( const scene::Path& path, scene::Instance& instance ) const { } }; -void Scene_forEachTestedBrushPlane_selectVertices( scene::Graph& graph, SelectionTest& test ){ - graph.traverse( TestedBrushPlanesSelectVeritces( test ) ); +void Scene_forEachTestedBrushFace_selectVertices( scene::Graph& graph, SelectionTest& test ){ + graph.traverse( TestedBrushFacesSelectVeritces( test ) ); } -*/ + class BrushPlanesSelectVeritces : public scene::Graph::Walker { SelectionTest& m_test; @@ -2683,8 +2683,8 @@ void testSelect( const View& view, const Matrix4& pivot2world ){ m_dragSelectable.setSelected( false ); } if( deepSelector.best().empty() ){ - //Scene_forEachTestedBrushPlane_selectVertices( GlobalSceneGraph(), test ); //todo? drag clicked face - Scene_forEachBrushPlane_selectVertices( GlobalSceneGraph(), test ); + Scene_forEachTestedBrushFace_selectVertices( GlobalSceneGraph(), test ); //drag clicked face + //Scene_forEachBrushPlane_selectVertices( GlobalSceneGraph(), test ); m_selected = true; } } diff --git a/radiant/texwindow.cpp b/radiant/texwindow.cpp index efc5f432..a9d542bc 100644 --- a/radiant/texwindow.cpp +++ b/radiant/texwindow.cpp @@ -974,16 +974,15 @@ IShader* Texture_At( TextureBrowser& textureBrowser, int mx, int my ){ By mouse click ============== */ -void SelectTexture( TextureBrowser& textureBrowser, int mx, int my, guint32 flags ){ +void SelectTexture( TextureBrowser& textureBrowser, int mx, int my, guint32 flags, bool texturizeSelection ){ if ( ( flags & GDK_SHIFT_MASK ) == 0 ) { IShader* shader = Texture_At( textureBrowser, mx, my ); if ( shader != 0 ) { TextureBrowser_SetSelectedShader( textureBrowser, shader->getName() ); TextureBrowser_textureSelected( shader->getName() ); - if ( !FindTextureDialog_isOpen() && !textureBrowser.m_rmbSelected ) { - UndoableCommand undo( "textureNameSetSelected" ); - Select_SetShader( shader->getName() ); + if ( !FindTextureDialog_isOpen() && !textureBrowser.m_rmbSelected && !texturizeSelection ) { + Select_SetShader_Undo( shader->getName() ); } } } @@ -1025,8 +1024,8 @@ void TextureBrowser_Tracking_MouseDown( TextureBrowser& textureBrowser ){ textureBrowser.m_freezePointer.freeze_pointer( textureBrowser.m_parent, textureBrowser.m_gl_widget, TextureBrowser_trackingDelta, &textureBrowser ); } -void TextureBrowser_Selection_MouseDown( TextureBrowser& textureBrowser, guint32 flags, int pointx, int pointy ){ - SelectTexture( textureBrowser, pointx, textureBrowser.height - 1 - pointy, flags ); +void TextureBrowser_Selection_MouseDown( TextureBrowser& textureBrowser, guint32 flags, int pointx, int pointy, bool texturizeSelection ){ + SelectTexture( textureBrowser, pointx, textureBrowser.height - 1 - pointy, flags, texturizeSelection ); } void TextureBrowser_Selection_MouseUp( TextureBrowser& textureBrowser, guint32 flags, int pointx, int pointy ){ @@ -1382,7 +1381,7 @@ gboolean TextureBrowser_button_press( GtkWidget* widget, GdkEventButton* event, if ( event->button == 3 ) { if ( GlobalTextureBrowser().m_tags ) { textureBrowser->m_rmbSelected = true; - TextureBrowser_Selection_MouseDown( *textureBrowser, event->state, static_cast( event->x ), static_cast( event->y ) ); + TextureBrowser_Selection_MouseDown( *textureBrowser, event->state, static_cast( event->x ), static_cast( event->y ), false ); BuildStoreAssignedTags( textureBrowser->m_assigned_store, textureBrowser->shader.c_str(), textureBrowser ); BuildStoreAvailableTags( textureBrowser->m_available_store, textureBrowser->m_assigned_store, textureBrowser->m_all_tags, textureBrowser ); @@ -1398,8 +1397,8 @@ gboolean TextureBrowser_button_press( GtkWidget* widget, GdkEventButton* event, TextureBrowser_Tracking_MouseDown( *textureBrowser ); } } - else if ( event->button == 1 ) { - TextureBrowser_Selection_MouseDown( *textureBrowser, event->state, static_cast( event->x ), static_cast( event->y ) ); + else if ( event->button == 1 || event->button == 2 ) { + TextureBrowser_Selection_MouseDown( *textureBrowser, event->state, static_cast( event->x ), static_cast( event->y ), event->button == 2 ); if ( GlobalTextureBrowser().m_tags ) { textureBrowser->m_rmbSelected = false; @@ -1409,7 +1408,6 @@ gboolean TextureBrowser_button_press( GtkWidget* widget, GdkEventButton* event, } else if ( event->type == GDK_2BUTTON_PRESS && event->button == 1 ) { CopiedString texName = textureBrowser->shader; - //const char* sh = texName.c_str(); char* sh = const_cast( texName.c_str() ); char* dir = strrchr( sh, '/' ); if( dir != NULL ){ @@ -1966,6 +1964,7 @@ void TextureBrowser_searchTags(){ TextureDirectory_loadTexture( path.c_str(), name.c_str() ); } } + TextureBrowser_SetHideUnused( g_TextureBrowser, false ); g_TextureBrowser.m_searchedTags = true; g_TextureBrowser_currentDirectory = tags_searched; diff --git a/radiant/xywindow.cpp b/radiant/xywindow.cpp index 9a1be033..dd0e45a3 100644 --- a/radiant/xywindow.cpp +++ b/radiant/xywindow.cpp @@ -550,6 +550,20 @@ void XYWnd::ZoomInWithMouse( int pointx, int pointy ){ } } +void XYWnd::FocusOnBounds( AABB& bounds ){ + SetOrigin( bounds.origin ); + int nDim1 = ( m_viewType == YZ ) ? 1 : 0; + int nDim2 = ( m_viewType == XY ) ? 1 : 2; + if( bounds.extents[ nDim1 ] < 128.f ) + bounds.extents[ nDim1 ] = 128.f; + if( bounds.extents[ nDim2 ] < 128.f ) + bounds.extents[ nDim2 ] = 128.f; + float scale1 = Width() / ( 3.f * bounds.extents[ nDim1 ] ); + float scale2 = Height() / ( 3.f * bounds.extents[ nDim2 ] ); + SetScale( MIN( scale1, scale2 ) ); + +} + VIEWTYPE GlobalXYWnd_getCurrentViewType(){ ASSERT_NOTNULL( g_pParentWnd ); ASSERT_NOTNULL( g_pParentWnd->ActiveXY() ); @@ -2703,7 +2717,7 @@ void XYWnd::OnEntityCreate( const char* item ){ -void GetFocusPosition( Vector3& position ){ +void GetCenterPosition( Vector3& position ){ if ( GlobalSelectionSystem().countSelected() != 0 ) { Select_GetMid( position ); } @@ -2713,15 +2727,15 @@ void GetFocusPosition( Vector3& position ){ } } -void XYWnd_Focus( XYWnd* xywnd ){ +void XYWnd_Centralize( XYWnd* xywnd ){ Vector3 position; - GetFocusPosition( position ); + GetCenterPosition( position ); xywnd->PositionView( position ); } -void XY_Split_Focus(){ +void XY_Split_Centralize(){ Vector3 position; - GetFocusPosition( position ); + GetCenterPosition( position ); if ( g_pParentWnd->GetXYWnd() ) { g_pParentWnd->GetXYWnd()->PositionView( position ); } @@ -2733,10 +2747,52 @@ void XY_Split_Focus(){ } } +void XY_Centralize(){ + if ( g_pParentWnd->CurrentStyle() == MainFrame::eSplit || g_pParentWnd->CurrentStyle() == MainFrame::eFloating ) { + // centralize all + XY_Split_Centralize(); + return; + } + + XYWnd* xywnd = g_pParentWnd->GetXYWnd(); + XYWnd_Centralize( xywnd ); +} + + + +void GetSelectionBbox( AABB& bounds ){ + if ( GlobalSelectionSystem().countSelected() != 0 ) { + Scene_BoundsSelected( GlobalSceneGraph(), bounds ); + } + else + { + bounds = AABB( Camera_getOrigin( *g_pParentWnd->GetCamWnd() ), Vector3( 128.f, 128.f, 128.f ) ); + } +} + +void XYWnd_Focus( XYWnd* xywnd ){ + AABB bounds; + GetSelectionBbox( bounds ); + xywnd->FocusOnBounds( bounds ); +} + +void XY_Split_Focus(){ + AABB bounds; + GetSelectionBbox( bounds ); + if ( g_pParentWnd->GetXYWnd() ) { + g_pParentWnd->GetXYWnd()->FocusOnBounds( bounds ); + } + if ( g_pParentWnd->GetXZWnd() ) { + g_pParentWnd->GetXZWnd()->FocusOnBounds( bounds ); + } + if ( g_pParentWnd->GetYZWnd() ) { + g_pParentWnd->GetYZWnd()->FocusOnBounds( bounds ); + } +} + void XY_Focus(){ if ( g_pParentWnd->CurrentStyle() == MainFrame::eSplit || g_pParentWnd->CurrentStyle() == MainFrame::eFloating ) { - // cannot do this in a split window - // do something else that the user may want here + // focus all XY_Split_Focus(); return; } @@ -2745,16 +2801,18 @@ void XY_Focus(){ XYWnd_Focus( xywnd ); } + + void XY_TopFrontSide( VIEWTYPE viewtype ){ if ( g_pParentWnd->CurrentStyle() == MainFrame::eSplit ) { // cannot do this in a split window // do something else that the user may want here - XY_Split_Focus(); + XY_Split_Centralize(); return; } XYWnd* xywnd = g_pParentWnd->CurrentStyle() == MainFrame::eFloating ? g_pParentWnd->ActiveXY() : g_pParentWnd->GetXYWnd(); xywnd->SetViewType( viewtype ); - XYWnd_Focus( xywnd ); + XYWnd_Centralize( xywnd ); } void XY_Top(){ @@ -2779,14 +2837,14 @@ void XY_NextView( XYWnd* xywnd ){ else{ xywnd->SetViewType( XY ); } - XYWnd_Focus( xywnd ); + XYWnd_Centralize( xywnd ); } void XY_Next(){ if ( g_pParentWnd->CurrentStyle() == MainFrame::eSplit ) { // cannot do this in a split window // do something else that the user may want here - XY_Split_Focus(); + XY_Split_Centralize(); return; } XYWnd* xywnd = g_pParentWnd->CurrentStyle() == MainFrame::eFloating ? g_pParentWnd->ActiveXY() : g_pParentWnd->GetXYWnd(); @@ -3070,7 +3128,8 @@ void XYWindow_Construct(){ GlobalCommands_insert( "ViewSide", FreeCaller(), Accelerator( GDK_KP_Page_Down ) ); GlobalCommands_insert( "ViewFront", FreeCaller(), Accelerator( GDK_KP_End ) ); GlobalCommands_insert( "Zoom100", FreeCaller() ); - GlobalCommands_insert( "CenterXYView", FreeCaller(), Accelerator( GDK_Tab, (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) ); + GlobalCommands_insert( "CenterXYView", FreeCaller(), Accelerator( GDK_Tab, (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) ); + GlobalCommands_insert( "XYFocusOnSelected", FreeCaller(), Accelerator( GDK_grave ) ); GlobalPreferenceSystem().registerPreference( "ClipCaulk", BoolImportStringCaller( g_clip_useCaulk ), BoolExportStringCaller( g_clip_useCaulk ) ); diff --git a/radiant/xywindow.h b/radiant/xywindow.h index a3fbd301..5c25847d 100644 --- a/radiant/xywindow.h +++ b/radiant/xywindow.h @@ -129,6 +129,7 @@ guint m_zoom_focusOut; void ZoomIn(); void ZoomOut(); void ZoomInWithMouse( int pointx, int pointy ); +void FocusOnBounds( AABB& bounds ); void RenderActive(); void SetActive( bool b ){ @@ -251,6 +252,7 @@ inline void XYWnd_Update( XYWnd& xywnd ){ xywnd.queueDraw(); } +void XY_Centralize(); struct xywindow_globals_t { -- 2.39.2