]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - radiant/camwindow.cpp
Merge branch 'NateEag-master-patch-12920' into 'master'
[xonotic/netradiant.git] / radiant / camwindow.cpp
index 376a31fbedb791c970c297756c57a315acef4aca..0257fa55205390dfc2de8b63b41b384362dd2a93 100644 (file)
@@ -76,6 +76,7 @@ void CameraMovedNotify(){
 
 struct camwindow_globals_private_t
 {
+       int m_nFOV;
        int m_nMoveSpeed;
        bool m_bCamLinkSpeed;
        int m_nAngleSpeed;
@@ -86,6 +87,7 @@ struct camwindow_globals_private_t
        int m_nStrafeMode;
 
        camwindow_globals_private_t() :
+               m_nFOV( 110 ),
                m_nMoveSpeed( 100 ),
                m_bCamLinkSpeed( true ),
                m_nAngleSpeed( 3 ),
@@ -93,7 +95,7 @@ struct camwindow_globals_private_t
                m_bCamDiscrete( true ),
                m_bCubicClipping( false ),
                m_showStats( true ),
-               m_nStrafeMode( 0 ){
+               m_nStrafeMode( 3 ){
        }
 
 };
@@ -145,14 +147,13 @@ struct camera_t
 
        bool m_strafe; // true when in strafemode toggled by the ctrl-key
        bool m_strafe_forward; // true when in strafemode by ctrl-key and shift is pressed for forward strafing
+       bool m_strafe_forward_invert; //silly option to invert forward strafing to support old fegs
 
        unsigned int movementflags; // movement flags
        Timer m_keycontrol_timer;
        guint m_keymove_handler;
 
 
-       float fieldOfView;
-
        DeferredMotionDelta m_mouseMove;
 
        static void motionDelta( int x, int y, void* data ){
@@ -171,9 +172,11 @@ struct camera_t
                origin( 0, 0, 0 ),
                angles( 0, 0, 0 ),
                color( 0, 0, 0 ),
+               projection( g_matrix4_identity ),
+               modelview( g_matrix4_identity ),
                movementflags( 0 ),
+               m_keycontrol_timer(),
                m_keymove_handler( 0 ),
-               fieldOfView( 110.0f ),
                m_mouseMove( motionDelta, this ),
                m_view( view ),
                m_update( update ){
@@ -202,7 +205,7 @@ float Camera_getFarClipPlane( camera_t& camera ){
 
 void Camera_updateProjection( camera_t& camera ){
        float farClip = Camera_getFarClipPlane( camera );
-       camera.projection = projection_for_camera( farClip / 4096.0f, farClip, camera.fieldOfView, camera.width, camera.height );
+       camera.projection = projection_for_camera( farClip / 4096.0f, farClip, (float)g_camwindow_globals_private.m_nFOV, camera.width, camera.height );
 
        camera.m_view->Construct( camera.projection, camera.modelview, camera.width, camera.height );
 }
@@ -283,7 +286,7 @@ void Camera_FreeMove( camera_t& camera, int dx, int dy ){
 
                camera.origin -= camera.vright * strafespeed * dx;
                if ( camera.m_strafe_forward ) {
-                       camera.origin -= camera.vpn * strafespeed * dy;
+                       camera.origin += camera.m_strafe_forward_invert ? ( camera.vpn * strafespeed * dy ) : ( -camera.vpn * strafespeed * dy );
                }
                else{
                        camera.origin += camera.vup * strafespeed * dy;
@@ -364,7 +367,10 @@ const unsigned int MOVE_UP = 1 << 6;
 const unsigned int MOVE_DOWN = 1 << 7;
 const unsigned int MOVE_PITCHUP = 1 << 8;
 const unsigned int MOVE_PITCHDOWN = 1 << 9;
-const unsigned int MOVE_ALL = MOVE_FORWARD | MOVE_BACK | MOVE_ROTRIGHT | MOVE_ROTLEFT | MOVE_STRAFERIGHT | MOVE_STRAFELEFT | MOVE_UP | MOVE_DOWN | MOVE_PITCHUP | MOVE_PITCHDOWN;
+const unsigned int MOVE_FOCUS = 1 << 10;
+const unsigned int MOVE_ALL = MOVE_FORWARD | MOVE_BACK | MOVE_ROTRIGHT | MOVE_ROTLEFT | MOVE_STRAFERIGHT | MOVE_STRAFELEFT | MOVE_UP | MOVE_DOWN | MOVE_PITCHUP | MOVE_PITCHDOWN | MOVE_FOCUS;
+
+Vector3 Camera_getFocusPos( camera_t& camera );
 
 void Cam_KeyControl( camera_t& camera, float dtime ){
        // Update angles
@@ -409,6 +415,9 @@ void Cam_KeyControl( camera_t& camera, float dtime ){
        if ( camera.movementflags & MOVE_DOWN ) {
                vector3_add( camera.origin, vector3_scaled( g_vector3_axis_z, -dtime * g_camwindow_globals_private.m_nMoveSpeed ) );
        }
+       if ( camera.movementflags & MOVE_FOCUS ) {
+               camera.origin = Camera_getFocusPos( camera );
+       }
 
        Camera_updateModelview( camera );
 }
@@ -512,6 +521,12 @@ void Camera_PitchDown_KeyUp( camera_t& camera ){
        Camera_clearMovementFlags( camera, MOVE_PITCHDOWN );
 }
 
+void Camera_Focus_KeyDown( camera_t& camera ){
+       Camera_setMovementFlags( camera, MOVE_FOCUS );
+}
+void Camera_Focus_KeyUp( camera_t& camera ){
+       Camera_clearMovementFlags( camera, MOVE_FOCUS );
+}
 
 typedef ReferenceCaller<camera_t, void(), &Camera_MoveForward_KeyDown> FreeMoveCameraMoveForwardKeyDownCaller;
 typedef ReferenceCaller<camera_t, void(), &Camera_MoveForward_KeyUp> FreeMoveCameraMoveForwardKeyUpCaller;
@@ -526,7 +541,12 @@ typedef ReferenceCaller<camera_t, void(), &Camera_MoveUp_KeyUp> FreeMoveCameraMo
 typedef ReferenceCaller<camera_t, void(), &Camera_MoveDown_KeyDown> FreeMoveCameraMoveDownKeyDownCaller;
 typedef ReferenceCaller<camera_t, void(), &Camera_MoveDown_KeyUp> FreeMoveCameraMoveDownKeyUpCaller;
 
+typedef ReferenceCaller<camera_t, void(), &Camera_Focus_KeyDown> FreeMoveCameraFocusKeyDownCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_Focus_KeyUp> FreeMoveCameraFocusKeyUpCaller;
 
+const float MIN_FOV = 60;
+const float MAX_FOV = 179;
+const float FOV_STEP = 10;
 const float SPEED_MOVE = 32;
 const float SPEED_TURN = 22.5;
 const float MIN_CAM_SPEED = 10;
@@ -623,16 +643,12 @@ void Camera_motionDelta( int x, int y, unsigned int state, void* data ){
 
        cam->m_mouseMove.motion_delta( x, y, state );
 
+       cam->m_strafe_forward_invert = false;
+
        switch ( g_camwindow_globals_private.m_nStrafeMode )
        {
        case 0:
-               cam->m_strafe = ( state & GDK_CONTROL_MASK ) != 0;
-               if ( cam->m_strafe ) {
-                       cam->m_strafe_forward = ( state & GDK_SHIFT_MASK ) != 0;
-               }
-               else{
-                       cam->m_strafe_forward = false;
-               }
+               cam->m_strafe = false;
                break;
        case 1:
                cam->m_strafe = ( state & GDK_CONTROL_MASK ) != 0 && ( state & GDK_SHIFT_MASK ) == 0;
@@ -642,9 +658,24 @@ void Camera_motionDelta( int x, int y, unsigned int state, void* data ){
                cam->m_strafe = ( state & GDK_CONTROL_MASK ) != 0 && ( state & GDK_SHIFT_MASK ) == 0;
                cam->m_strafe_forward = cam->m_strafe;
                break;
+       case 4:
+               cam->m_strafe_forward_invert = true; // fall through
+       default: /* 3 & 4 */
+               cam->m_strafe = ( state & GDK_CONTROL_MASK ) != 0;
+               if ( cam->m_strafe ) {
+                       cam->m_strafe_forward = ( state & GDK_SHIFT_MASK ) != 0;
+               }
+               else{
+                       cam->m_strafe_forward = false;
+               }
+               break;
        }
 }
 
+
+
+
+
 class CamWnd
 {
 View m_view;
@@ -827,6 +858,7 @@ void camwnd_update_xor_rectangle( CamWnd& self, rect_t area ){
 
 gboolean selection_button_press( ui::Widget widget, GdkEventButton* event, WindowObserver* observer ){
        if ( event->type == GDK_BUTTON_PRESS ) {
+               gtk_widget_grab_focus( widget );
                observer->onMouseDown( WindowVector_forDouble( event->x, event->y ), button_for_button( event->button ), modifiers_for_state( event->state ) );
        }
        return FALSE;
@@ -869,9 +901,39 @@ gboolean selection_motion_freemove( ui::Widget widget, GdkEventMotion *event, Wi
 }
 
 gboolean wheelmove_scroll( ui::Widget widget, GdkEventScroll* event, CamWnd* camwnd ){
+       //gtk_window_set_focus( camwnd->m_parent, camwnd->m_gl_widget );
+       gtk_widget_grab_focus( camwnd->m_gl_widget );
+       if( !gtk_window_is_active( camwnd->m_parent ) )
+               gtk_window_present( camwnd->m_parent );
+
        if ( event->direction == GDK_SCROLL_UP ) {
                Camera_Freemove_updateAxes( camwnd->getCamera() );
-               Camera_setOrigin( *camwnd, vector3_added( Camera_getOrigin( *camwnd ), vector3_scaled( camwnd->getCamera().forward, static_cast<float>( g_camwindow_globals_private.m_nMoveSpeed ) ) ) );
+               if( camwnd->m_bFreeMove || !g_camwindow_globals.m_bZoomInToPointer ){
+                       Camera_setOrigin( *camwnd, vector3_added( Camera_getOrigin( *camwnd ), vector3_scaled( camwnd->getCamera().forward, static_cast<float>( g_camwindow_globals_private.m_nMoveSpeed ) ) ) );
+               }
+               else{
+                       //Matrix4 maa = matrix4_multiplied_by_matrix4( camwnd->getCamera().projection, camwnd->getCamera().modelview );
+                       Matrix4 maa = camwnd->getCamera().m_view->GetViewMatrix();
+                       matrix4_affine_invert( maa );
+
+                       float x = static_cast<float>( event->x );
+                       float y = static_cast<float>( event->y );
+                       Vector3 normalized;
+
+                       normalized[0] = 2.0f * ( x ) / static_cast<float>( camwnd->getCamera().width ) - 1.0f;
+                       normalized[1] = 2.0f * ( y )/ static_cast<float>( camwnd->getCamera().height ) - 1.0f;
+                       normalized[1] *= -1.f;
+                       normalized[2] = 0.f;
+
+                       normalized *= 16.0f;
+                               //globalOutputStream() << normalized << " normalized    ";
+                       matrix4_transform_point( maa, normalized );
+                               //globalOutputStream() << normalized << "\n";
+                       Vector3 norm = vector3_normalised( normalized - Camera_getOrigin( *camwnd ) );
+                               //globalOutputStream() << normalized - Camera_getOrigin( *camwnd ) << "  normalized - Camera_getOrigin( *camwnd )\n";
+                               //globalOutputStream() << norm << "  norm\n";
+                       Camera_setOrigin( *camwnd, vector3_added( Camera_getOrigin( *camwnd ), vector3_scaled( norm, static_cast<float>( g_camwindow_globals_private.m_nMoveSpeed ) ) ) );
+               }
        }
        else if ( event->direction == GDK_SCROLL_DOWN ) {
                Camera_Freemove_updateAxes( camwnd->getCamera() );
@@ -993,6 +1055,11 @@ void CamWnd_registerCommands( CamWnd& camwnd ){
                                                        FreeMoveCameraMoveDownKeyUpCaller( camwnd.getCamera() )
                                                        );
 
+       GlobalKeyEvents_insert( "CameraFreeFocus", accelerator_null(),
+                                                       FreeMoveCameraFocusKeyDownCaller( camwnd.getCamera() ),
+                                                       FreeMoveCameraFocusKeyUpCaller( camwnd.getCamera() )
+                                                       );
+
        GlobalCommands_insert( "CameraForward", ReferenceCaller<camera_t, void(), Camera_MoveForward_Discrete>( camwnd.getCamera() ) );
        GlobalCommands_insert( "CameraBack", ReferenceCaller<camera_t, void(), Camera_MoveBack_Discrete>( camwnd.getCamera() ) );
        GlobalCommands_insert( "CameraLeft", ReferenceCaller<camera_t, void(), Camera_RotateLeft_Discrete>( camwnd.getCamera() ) );
@@ -1140,6 +1207,8 @@ void CamWnd_Add_Handlers_FreeMove( CamWnd& camwnd ){
 
        KeyEvent_connect( "CameraFreeMoveUp" );
        KeyEvent_connect( "CameraFreeMoveDown" );
+
+       KeyEvent_connect( "CameraFreeFocus" );
 }
 
 void CamWnd_Remove_Handlers_FreeMove( CamWnd& camwnd ){
@@ -1156,6 +1225,8 @@ void CamWnd_Remove_Handlers_FreeMove( CamWnd& camwnd ){
        KeyEvent_disconnect( "CameraFreeMoveUp" );
        KeyEvent_disconnect( "CameraFreeMoveDown" );
 
+       KeyEvent_disconnect( "CameraFreeFocus" );
+
        g_signal_handler_disconnect( G_OBJECT( camwnd.m_gl_widget ), camwnd.m_selection_button_press_handler );
        g_signal_handler_disconnect( G_OBJECT( camwnd.m_gl_widget ), camwnd.m_selection_button_release_handler );
        g_signal_handler_disconnect( G_OBJECT( camwnd.m_gl_widget ), camwnd.m_selection_motion_handler );
@@ -1298,7 +1369,7 @@ void CamWnd::Cam_PositionDrag(){
                CamWnd_Update( camwnd );
                CameraMovedNotify();
 
-               Sys_SetCursorPos( m_parent, m_PositionDragCursorX, m_PositionDragCursorY );
+               Sys_SetCursorPos( m_gl_widget, m_PositionDragCursorX, m_PositionDragCursorY );
        }
 }
 #endif
@@ -1323,7 +1394,9 @@ void CamWnd::EnableFreeMove(){
 
        gtk_window_set_focus( m_parent, m_gl_widget );
        m_freemove_handle_focusout = m_gl_widget.connect( "focus_out_event", G_CALLBACK( camwindow_freemove_focusout ), this );
-       m_freezePointer.freeze_pointer( m_parent, m_gl_widget, Camera_motionDelta, &m_Camera );
+       /* We chose to replace m_parent by m_gl_widget but NetRadiantCustom does:
+       m_freezePointer.freeze_pointer( m_parent, m_gl_widget, Camera_motionDelta, &m_Camera ); */
+       m_freezePointer.freeze_pointer( m_gl_widget, Camera_motionDelta, &m_Camera );
 
        CamWnd_Update( *this );
 }
@@ -1338,7 +1411,8 @@ void CamWnd::DisableFreeMove(){
        CamWnd_Remove_Handlers_FreeMove( *this );
        CamWnd_Add_Handlers_Move( *this );
 
-       m_freezePointer.unfreeze_pointer( m_parent, true );
+       m_freezePointer.unfreeze_pointer( m_gl_widget, true );
+
        g_signal_handler_disconnect( G_OBJECT( m_gl_widget ), m_freemove_handle_focusout );
 
        CamWnd_Update( *this );
@@ -1392,9 +1466,11 @@ void PopState(){
        m_state_stack.pop_back();
 }
 void Highlight( EHighlightMode mode, bool bEnable = true ){
-       ( bEnable )
-       ? m_state_stack.back().m_highlight |= mode
-                                                                                 : m_state_stack.back().m_highlight &= ~mode;
+       if ( bEnable ) {
+               m_state_stack.back().m_highlight |= mode;
+       } else {
+               m_state_stack.back().m_highlight &= ~mode;
+       }
 }
 void setLights( const LightList& lights ){
        m_state_stack.back().m_lights = &lights;
@@ -1633,7 +1709,7 @@ void CamWnd::BenchMark(){
                Vector3 angles;
                angles[CAMERA_ROLL] = 0;
                angles[CAMERA_PITCH] = 0;
-               angles[CAMERA_YAW] = static_cast<float>( i * ( 360.0 / 100.0 ) );
+               angles[CAMERA_YAW] = i * 360.0f / 100.0f;
                Camera_setAngles( *this, angles );
        }
        double dEnd = Sys_DoubleTime();
@@ -1645,27 +1721,28 @@ void GlobalCamera_ResetAngles(){
        CamWnd& camwnd = *g_camwnd;
        Vector3 angles;
        angles[CAMERA_ROLL] = angles[CAMERA_PITCH] = 0;
-       angles[CAMERA_YAW] = static_cast<float>( 22.5 * floor( ( Camera_getAngles( camwnd )[CAMERA_YAW] + 11 ) / 22.5 ) );
+       angles[CAMERA_YAW] = 22.5f * floorf( ( Camera_getAngles( camwnd )[CAMERA_YAW] + 11 ) / 22.5f );
        Camera_setAngles( camwnd, angles );
 }
 
 #include "select.h"
 
-void GlobalCamera_FocusOnSelected(){
-       CamWnd& camwnd = *g_camwnd;
-
-       Vector3 angles( Camera_getAngles( camwnd ) );
+Vector3 Camera_getFocusPos( camera_t& camera ){
+       Vector3 camorigin( Camera_getOrigin( camera ) );
+       AABB aabb( aabb_for_minmax( Select_getWorkZone().d_work_min, Select_getWorkZone().d_work_max ) );
+       View& view = *( camera.m_view );
+#if 0
+       Vector3 angles( Camera_getAngles( camera ) );
        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 );
+#elif 0
+       Vector3 viewvector( -view.GetModelview()[2], -view.GetModelview()[6], -view.GetModelview()[10] );
+#elif 1
+       Vector3 viewvector( -camera.vpn );
+#endif
 
        Plane3 frustumPlanes[4];
        frustumPlanes[0] = plane3_translated( view.getFrustum().left, camorigin - aabb.origin );
@@ -1690,7 +1767,11 @@ void GlobalCamera_FocusOnSelected(){
                        }
                }
        }
-       Camera_setOrigin( camwnd, aabb.origin - viewvector * offset );
+       return ( aabb.origin - viewvector * offset );
+}
+
+void GlobalCamera_FocusOnSelected(){
+       Camera_setOrigin( *g_camwnd, Camera_getFocusPos( g_camwnd->getCamera() ) );
 }
 
 void Camera_ChangeFloorUp(){
@@ -1717,8 +1798,8 @@ void Camera_CubeIn(){
 void Camera_CubeOut(){
        CamWnd& camwnd = *g_camwnd;
        g_camwindow_globals.m_nCubicScale++;
-       if ( g_camwindow_globals.m_nCubicScale > 23 ) {
-               g_camwindow_globals.m_nCubicScale = 23;
+       if ( g_camwindow_globals.m_nCubicScale > 46 ) {
+               g_camwindow_globals.m_nCubicScale = 46;
        }
        Camera_updateProjection( camwnd.getCamera() );
        CamWnd_Update( camwnd );
@@ -1766,6 +1847,8 @@ void CamWnd_registerShortcuts(){
                command_connect_accelerator( "TogglePreview" );
        }
 
+       command_connect_accelerator( "FOVInc" );
+       command_connect_accelerator( "FOVDec" );
        command_connect_accelerator( "CameraSpeedInc" );
        command_connect_accelerator( "CameraSpeedDec" );
 }
@@ -1883,10 +1966,12 @@ struct RenderMode {
 };
 
 void Camera_constructPreferences( PreferencesPage& page ){
+       page.appendSlider( "FOV", g_camwindow_globals_private.m_nFOV, TRUE, 0, 0, 100, MIN_FOV, MAX_FOV, 1, 10 );
        page.appendSlider( "Movement Speed", g_camwindow_globals_private.m_nMoveSpeed, TRUE, 0, 0, 100, MIN_CAM_SPEED, MAX_CAM_SPEED, 1, 10 );
        page.appendCheckBox( "", "Link strafe speed to movement speed", g_camwindow_globals_private.m_bCamLinkSpeed );
        page.appendSlider( "Rotation Speed", g_camwindow_globals_private.m_nAngleSpeed, TRUE, 0, 0, 3, 1, 180, 1, 10 );
        page.appendCheckBox( "", "Invert mouse vertical axis", g_camwindow_globals_private.m_bCamInverseMouse );
+       page.appendCheckBox( "", "Zoom In to Mouse pointer", g_camwindow_globals.m_bZoomInToPointer );
        page.appendCheckBox(
                "", "Discrete movement",
                make_property<CamWnd_Move_Discrete>()
@@ -1916,7 +2001,7 @@ void Camera_constructPreferences( PreferencesPage& page ){
                        );
        }
 
-       const char* strafe_mode[] = { "Both", "Forward", "Up" };
+       const char* strafe_mode[] = { "None", "Up", "Forward", "Both", "Both Inverted" };
 
        page.appendCombo(
                "Strafe Mode",
@@ -1936,6 +2021,31 @@ void Camera_registerPreferencesPage(){
 #include "stringio.h"
 #include "dialog.h"
 
+void FOV_increase(){
+       CamWnd& camwnd = *g_camwnd;
+       if ( g_camwindow_globals_private.m_nFOV <= ( MAX_FOV - FOV_STEP - 10 ) ) {
+               g_camwindow_globals_private.m_nFOV += FOV_STEP;
+       }
+       else {
+               g_camwindow_globals_private.m_nFOV = MAX_FOV - 10;
+       }
+       Camera_updateProjection( camwnd.getCamera() );
+       CamWnd_Update( camwnd );
+}
+
+void FOV_decrease(){
+       CamWnd& camwnd = *g_camwnd;
+       if ( g_camwindow_globals_private.m_nFOV >= ( MIN_FOV + FOV_STEP ) ) {
+               g_camwindow_globals_private.m_nFOV -= FOV_STEP;
+       }
+       else {
+               g_camwindow_globals_private.m_nFOV = MIN_FOV;
+       }
+       Camera_updateProjection( camwnd.getCamera() );
+       CamWnd_Update( camwnd );
+}
+
+
 void CameraSpeed_increase(){
        if ( g_camwindow_globals_private.m_nMoveSpeed <= ( MAX_CAM_SPEED - CAM_SPEED_STEP - 10 ) ) {
                g_camwindow_globals_private.m_nMoveSpeed += CAM_SPEED_STEP;
@@ -1957,7 +2067,7 @@ void CameraSpeed_decrease(){
 /// \brief Initialisation for things that have the same lifespan as this module.
 void CamWnd_Construct(){
        GlobalCommands_insert( "CenterView", makeCallbackF(GlobalCamera_ResetAngles), Accelerator( GDK_KEY_End ) );
-       GlobalCommands_insert( "CameraFocusOnSelected", makeCallbackF( GlobalCamera_FocusOnSelected ), Accelerator( GDK_Tab ) );
+       GlobalCommands_insert( "CameraFocusOnSelected", makeCallbackF( GlobalCamera_FocusOnSelected ), Accelerator( GDK_KEY_Tab ) );
 
        GlobalToggles_insert( "ToggleCubicClip", makeCallbackF(Camera_ToggleFarClip), ToggleItem::AddCallbackCaller( g_getfarclip_item ), Accelerator( '\\', (GdkModifierType)GDK_CONTROL_MASK ) );
        GlobalCommands_insert( "CubicClipZoomIn", makeCallbackF(Camera_CubeIn), Accelerator( '[', (GdkModifierType)GDK_CONTROL_MASK ) );
@@ -1974,6 +2084,9 @@ void CamWnd_Construct(){
                GlobalCommands_insert( "TogglePreview", makeCallbackF(CamWnd_TogglePreview), Accelerator( GDK_KEY_F3 ) );
        }
 
+       GlobalCommands_insert( "FOVInc", makeCallbackF(FOV_increase), Accelerator( GDK_KEY_KP_Multiply, (GdkModifierType)GDK_SHIFT_MASK ) );
+       GlobalCommands_insert( "FOVDec", makeCallbackF(FOV_decrease), Accelerator( GDK_KEY_KP_Divide, (GdkModifierType)GDK_SHIFT_MASK ) );
+
        GlobalCommands_insert( "CameraSpeedInc", makeCallbackF(CameraSpeed_increase), Accelerator( GDK_KEY_KP_Add, (GdkModifierType)GDK_SHIFT_MASK ) );
        GlobalCommands_insert( "CameraSpeedDec", makeCallbackF(CameraSpeed_decrease), Accelerator( GDK_KEY_KP_Subtract, (GdkModifierType)GDK_SHIFT_MASK ) );
 
@@ -1981,30 +2094,33 @@ void CamWnd_Construct(){
        GlobalShortcuts_insert( "CameraBack", Accelerator( GDK_KEY_Down ) );
        GlobalShortcuts_insert( "CameraLeft", Accelerator( GDK_KEY_Left ) );
        GlobalShortcuts_insert( "CameraRight", Accelerator( GDK_KEY_Right ) );
-       GlobalShortcuts_insert( "CameraStrafeRight", Accelerator( GDK_KEY_period ) );
-       GlobalShortcuts_insert( "CameraStrafeLeft", Accelerator( GDK_KEY_comma ) );
+       GlobalShortcuts_insert( "CameraStrafeRight", Accelerator( 'D' ) );
+       GlobalShortcuts_insert( "CameraStrafeLeft", Accelerator( 'A' ) );
 
        GlobalShortcuts_insert( "CameraUp", accelerator_null() );
        GlobalShortcuts_insert( "CameraDown", accelerator_null() );
        GlobalShortcuts_insert( "CameraAngleUp", accelerator_null() );
        GlobalShortcuts_insert( "CameraAngleDown", accelerator_null() );
 
-       GlobalShortcuts_insert( "CameraFreeMoveForward", Accelerator( GDK_Up ) );
-       GlobalShortcuts_insert( "CameraFreeMoveBack", Accelerator( GDK_Down ) );
-       GlobalShortcuts_insert( "CameraFreeMoveLeft", Accelerator( GDK_Left ) );
-       GlobalShortcuts_insert( "CameraFreeMoveRight", Accelerator( GDK_Right ) );
+       GlobalShortcuts_insert( "CameraFreeMoveForward", Accelerator( 'W' ) );
+       GlobalShortcuts_insert( "CameraFreeMoveBack", Accelerator( 'S' ) );
+       GlobalShortcuts_insert( "CameraFreeMoveLeft", Accelerator( 'A' ) );
+       GlobalShortcuts_insert( "CameraFreeMoveRight", Accelerator( 'D' ) );
 
-       GlobalShortcuts_insert( "CameraFreeMoveForward2", Accelerator( GDK_Up ) );
-       GlobalShortcuts_insert( "CameraFreeMoveBack2", Accelerator( GDK_Down ) );
-       GlobalShortcuts_insert( "CameraFreeMoveLeft2", Accelerator( GDK_Left ) );
-       GlobalShortcuts_insert( "CameraFreeMoveRight2", Accelerator( GDK_Right ) );
+       GlobalShortcuts_insert( "CameraFreeMoveForward2", Accelerator( GDK_KEY_Up ) );
+       GlobalShortcuts_insert( "CameraFreeMoveBack2", Accelerator( GDK_KEY_Down ) );
+       GlobalShortcuts_insert( "CameraFreeMoveLeft2", Accelerator( GDK_KEY_Left ) );
+       GlobalShortcuts_insert( "CameraFreeMoveRight2", Accelerator( GDK_KEY_Right ) );
 
        GlobalShortcuts_insert( "CameraFreeMoveUp", accelerator_null() );
        GlobalShortcuts_insert( "CameraFreeMoveDown", accelerator_null() );
 
+       GlobalShortcuts_insert( "CameraFreeFocus", Accelerator( GDK_KEY_Tab ) );
+
        GlobalToggles_insert( "ShowStats", makeCallbackF(ShowStatsToggle), ToggleItem::AddCallbackCaller( g_show_stats ) );
 
        GlobalPreferenceSystem().registerPreference( "ShowStats", make_property_string( g_camwindow_globals_private.m_showStats ) );
+       GlobalPreferenceSystem().registerPreference( "FOV", make_property_string( g_camwindow_globals_private.m_nFOV ) );
        GlobalPreferenceSystem().registerPreference( "MoveSpeed", make_property_string( g_camwindow_globals_private.m_nMoveSpeed ) );
        GlobalPreferenceSystem().registerPreference( "CamLinkSpeed", make_property_string( g_camwindow_globals_private.m_bCamLinkSpeed ) );
        GlobalPreferenceSystem().registerPreference( "AngleSpeed", make_property_string( g_camwindow_globals_private.m_nAngleSpeed ) );
@@ -2016,6 +2132,7 @@ void CamWnd_Construct(){
        GlobalPreferenceSystem().registerPreference( "SI_Colors12", make_property_string( g_camwindow_globals.color_selbrushes3d ) );
        GlobalPreferenceSystem().registerPreference( "CameraRenderMode", make_property_string<RenderMode>() );
        GlobalPreferenceSystem().registerPreference( "StrafeMode", make_property_string( g_camwindow_globals_private.m_nStrafeMode ) );
+       GlobalPreferenceSystem().registerPreference( "3DZoomInToPointer", make_property_string( g_camwindow_globals.m_bZoomInToPointer ) );
 
        CamWnd_constructStatic();