]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - radiant/camwindow.cpp
radiant: make camera FOV modifiable and add slider in preferences
[xonotic/netradiant.git] / radiant / camwindow.cpp
index 8d42b71540a3bde3e19e1c27f7b474052b6af224..27ae274e8749d768df3bc4e97a455471d0f5534b 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 ),
@@ -151,8 +153,6 @@ struct camera_t
        guint m_keymove_handler;
 
 
-       float fieldOfView;
-
        DeferredMotionDelta m_mouseMove;
 
        static void motionDelta( int x, int y, void* data ){
@@ -160,20 +160,22 @@ struct camera_t
        }
 
        View* m_view;
-       Callback m_update;
+       Callback<void()> m_update;
 
        static camera_draw_mode draw_mode;
 
-       camera_t( View* view, const Callback& update )
+       camera_t( View* view, const Callback<void()>& update )
                : width( 0 ),
                height( 0 ),
                timing( false ),
                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( 90.0f ),
                m_mouseMove( motionDelta, this ),
                m_view( view ),
                m_update( update ){
@@ -202,7 +204,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 );
 }
@@ -513,20 +515,23 @@ void Camera_PitchDown_KeyUp( camera_t& camera ){
 }
 
 
-typedef ReferenceCaller<camera_t, &Camera_MoveForward_KeyDown> FreeMoveCameraMoveForwardKeyDownCaller;
-typedef ReferenceCaller<camera_t, &Camera_MoveForward_KeyUp> FreeMoveCameraMoveForwardKeyUpCaller;
-typedef ReferenceCaller<camera_t, &Camera_MoveBack_KeyDown> FreeMoveCameraMoveBackKeyDownCaller;
-typedef ReferenceCaller<camera_t, &Camera_MoveBack_KeyUp> FreeMoveCameraMoveBackKeyUpCaller;
-typedef ReferenceCaller<camera_t, &Camera_MoveLeft_KeyDown> FreeMoveCameraMoveLeftKeyDownCaller;
-typedef ReferenceCaller<camera_t, &Camera_MoveLeft_KeyUp> FreeMoveCameraMoveLeftKeyUpCaller;
-typedef ReferenceCaller<camera_t, &Camera_MoveRight_KeyDown> FreeMoveCameraMoveRightKeyDownCaller;
-typedef ReferenceCaller<camera_t, &Camera_MoveRight_KeyUp> FreeMoveCameraMoveRightKeyUpCaller;
-typedef ReferenceCaller<camera_t, &Camera_MoveUp_KeyDown> FreeMoveCameraMoveUpKeyDownCaller;
-typedef ReferenceCaller<camera_t, &Camera_MoveUp_KeyUp> FreeMoveCameraMoveUpKeyUpCaller;
-typedef ReferenceCaller<camera_t, &Camera_MoveDown_KeyDown> FreeMoveCameraMoveDownKeyDownCaller;
-typedef ReferenceCaller<camera_t, &Camera_MoveDown_KeyUp> FreeMoveCameraMoveDownKeyUpCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveForward_KeyDown> FreeMoveCameraMoveForwardKeyDownCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveForward_KeyUp> FreeMoveCameraMoveForwardKeyUpCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveBack_KeyDown> FreeMoveCameraMoveBackKeyDownCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveBack_KeyUp> FreeMoveCameraMoveBackKeyUpCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveLeft_KeyDown> FreeMoveCameraMoveLeftKeyDownCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveLeft_KeyUp> FreeMoveCameraMoveLeftKeyUpCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveRight_KeyDown> FreeMoveCameraMoveRightKeyDownCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveRight_KeyUp> FreeMoveCameraMoveRightKeyUpCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveUp_KeyDown> FreeMoveCameraMoveUpKeyDownCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveUp_KeyUp> FreeMoveCameraMoveUpKeyUpCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveDown_KeyDown> FreeMoveCameraMoveDownKeyDownCaller;
+typedef ReferenceCaller<camera_t, void(), &Camera_MoveDown_KeyUp> FreeMoveCameraMoveDownKeyUpCaller;
 
 
+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;
@@ -595,9 +600,9 @@ class RadiantCameraView : public CameraView
 {
 camera_t& m_camera;
 View* m_view;
-Callback m_update;
+Callback<void()> m_update;
 public:
-RadiantCameraView( camera_t& camera, View* view, const Callback& update ) : m_camera( camera ), m_view( view ), m_update( update ){
+RadiantCameraView( camera_t& camera, View* view, const Callback<void()>& update ) : m_camera( camera ), m_view( view ), m_update( update ){
 }
 void update(){
        m_view->Construct( m_camera.projection, m_camera.modelview, m_camera.width, m_camera.height );
@@ -723,7 +728,7 @@ private:
 void Cam_Draw();
 };
 
-typedef MemberCaller<CamWnd, &CamWnd::queue_draw> CamWndQueueDraw;
+typedef MemberCaller<CamWnd, void(), &CamWnd::queue_draw> CamWndQueueDraw;
 
 Shader* CamWnd::m_state_select1 = 0;
 Shader* CamWnd::m_state_select2 = 0;
@@ -909,44 +914,44 @@ void KeyEvent_disconnect( const char* name ){
 
 void CamWnd_registerCommands( CamWnd& camwnd ){
        GlobalKeyEvents_insert( "CameraForward", Accelerator( GDK_KEY_Up ),
-                                                       ReferenceCaller<camera_t, Camera_MoveForward_KeyDown>( camwnd.getCamera() ),
-                                                       ReferenceCaller<camera_t, Camera_MoveForward_KeyUp>( camwnd.getCamera() )
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveForward_KeyDown>( camwnd.getCamera() ),
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveForward_KeyUp>( camwnd.getCamera() )
                                                        );
        GlobalKeyEvents_insert( "CameraBack", Accelerator( GDK_KEY_Down ),
-                                                       ReferenceCaller<camera_t, Camera_MoveBack_KeyDown>( camwnd.getCamera() ),
-                                                       ReferenceCaller<camera_t, Camera_MoveBack_KeyUp>( camwnd.getCamera() )
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveBack_KeyDown>( camwnd.getCamera() ),
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveBack_KeyUp>( camwnd.getCamera() )
                                                        );
        GlobalKeyEvents_insert( "CameraLeft", Accelerator( GDK_KEY_Left ),
-                                                       ReferenceCaller<camera_t, Camera_RotateLeft_KeyDown>( camwnd.getCamera() ),
-                                                       ReferenceCaller<camera_t, Camera_RotateLeft_KeyUp>( camwnd.getCamera() )
+                                                       ReferenceCaller<camera_t, void(), Camera_RotateLeft_KeyDown>( camwnd.getCamera() ),
+                                                       ReferenceCaller<camera_t, void(), Camera_RotateLeft_KeyUp>( camwnd.getCamera() )
                                                        );
        GlobalKeyEvents_insert( "CameraRight", Accelerator( GDK_KEY_Right ),
-                                                       ReferenceCaller<camera_t, Camera_RotateRight_KeyDown>( camwnd.getCamera() ),
-                                                       ReferenceCaller<camera_t, Camera_RotateRight_KeyUp>( camwnd.getCamera() )
+                                                       ReferenceCaller<camera_t, void(), Camera_RotateRight_KeyDown>( camwnd.getCamera() ),
+                                                       ReferenceCaller<camera_t, void(), Camera_RotateRight_KeyUp>( camwnd.getCamera() )
                                                        );
        GlobalKeyEvents_insert( "CameraStrafeRight", Accelerator( GDK_KEY_period ),
-                                                       ReferenceCaller<camera_t, Camera_MoveRight_KeyDown>( camwnd.getCamera() ),
-                                                       ReferenceCaller<camera_t, Camera_MoveRight_KeyUp>( camwnd.getCamera() )
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveRight_KeyDown>( camwnd.getCamera() ),
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveRight_KeyUp>( camwnd.getCamera() )
                                                        );
        GlobalKeyEvents_insert( "CameraStrafeLeft", Accelerator( GDK_KEY_comma ),
-                                                       ReferenceCaller<camera_t, Camera_MoveLeft_KeyDown>( camwnd.getCamera() ),
-                                                       ReferenceCaller<camera_t, Camera_MoveLeft_KeyUp>( camwnd.getCamera() )
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveLeft_KeyDown>( camwnd.getCamera() ),
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveLeft_KeyUp>( camwnd.getCamera() )
                                                        );
        GlobalKeyEvents_insert( "CameraUp", Accelerator( 'D' ),
-                                                       ReferenceCaller<camera_t, Camera_MoveUp_KeyDown>( camwnd.getCamera() ),
-                                                       ReferenceCaller<camera_t, Camera_MoveUp_KeyUp>( camwnd.getCamera() )
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveUp_KeyDown>( camwnd.getCamera() ),
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveUp_KeyUp>( camwnd.getCamera() )
                                                        );
        GlobalKeyEvents_insert( "CameraDown", Accelerator( 'C' ),
-                                                       ReferenceCaller<camera_t, Camera_MoveDown_KeyDown>( camwnd.getCamera() ),
-                                                       ReferenceCaller<camera_t, Camera_MoveDown_KeyUp>( camwnd.getCamera() )
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveDown_KeyDown>( camwnd.getCamera() ),
+                                                       ReferenceCaller<camera_t, void(), Camera_MoveDown_KeyUp>( camwnd.getCamera() )
                                                        );
        GlobalKeyEvents_insert( "CameraAngleDown", Accelerator( 'A' ),
-                                                       ReferenceCaller<camera_t, Camera_PitchDown_KeyDown>( camwnd.getCamera() ),
-                                                       ReferenceCaller<camera_t, Camera_PitchDown_KeyUp>( camwnd.getCamera() )
+                                                       ReferenceCaller<camera_t, void(), Camera_PitchDown_KeyDown>( camwnd.getCamera() ),
+                                                       ReferenceCaller<camera_t, void(), Camera_PitchDown_KeyUp>( camwnd.getCamera() )
                                                        );
        GlobalKeyEvents_insert( "CameraAngleUp", Accelerator( 'Z' ),
-                                                       ReferenceCaller<camera_t, Camera_PitchUp_KeyDown>( camwnd.getCamera() ),
-                                                       ReferenceCaller<camera_t, Camera_PitchUp_KeyUp>( camwnd.getCamera() )
+                                                       ReferenceCaller<camera_t, void(), Camera_PitchUp_KeyDown>( camwnd.getCamera() ),
+                                                       ReferenceCaller<camera_t, void(), Camera_PitchUp_KeyUp>( camwnd.getCamera() )
                                                        );
 
        GlobalKeyEvents_insert( "CameraFreeMoveForward", Accelerator( GDK_KEY_Up ),
@@ -974,17 +979,17 @@ void CamWnd_registerCommands( CamWnd& camwnd ){
                                                        FreeMoveCameraMoveDownKeyUpCaller( camwnd.getCamera() )
                                                        );
 
-       GlobalCommands_insert( "CameraForward", ReferenceCaller<camera_t, Camera_MoveForward_Discrete>( camwnd.getCamera() ), Accelerator( GDK_KEY_Up ) );
-       GlobalCommands_insert( "CameraBack", ReferenceCaller<camera_t, Camera_MoveBack_Discrete>( camwnd.getCamera() ), Accelerator( GDK_KEY_Down ) );
-       GlobalCommands_insert( "CameraLeft", ReferenceCaller<camera_t, Camera_RotateLeft_Discrete>( camwnd.getCamera() ), Accelerator( GDK_KEY_Left ) );
-       GlobalCommands_insert( "CameraRight", ReferenceCaller<camera_t, Camera_RotateRight_Discrete>( camwnd.getCamera() ), Accelerator( GDK_KEY_Right ) );
-       GlobalCommands_insert( "CameraStrafeRight", ReferenceCaller<camera_t, Camera_MoveRight_Discrete>( camwnd.getCamera() ), Accelerator( GDK_KEY_period ) );
-       GlobalCommands_insert( "CameraStrafeLeft", ReferenceCaller<camera_t, Camera_MoveLeft_Discrete>( camwnd.getCamera() ), Accelerator( GDK_KEY_comma ) );
+       GlobalCommands_insert( "CameraForward", ReferenceCaller<camera_t, void(), Camera_MoveForward_Discrete>( camwnd.getCamera() ), Accelerator( GDK_KEY_Up ) );
+       GlobalCommands_insert( "CameraBack", ReferenceCaller<camera_t, void(), Camera_MoveBack_Discrete>( camwnd.getCamera() ), Accelerator( GDK_KEY_Down ) );
+       GlobalCommands_insert( "CameraLeft", ReferenceCaller<camera_t, void(), Camera_RotateLeft_Discrete>( camwnd.getCamera() ), Accelerator( GDK_KEY_Left ) );
+       GlobalCommands_insert( "CameraRight", ReferenceCaller<camera_t, void(), Camera_RotateRight_Discrete>( camwnd.getCamera() ), Accelerator( GDK_KEY_Right ) );
+       GlobalCommands_insert( "CameraStrafeRight", ReferenceCaller<camera_t, void(), Camera_MoveRight_Discrete>( camwnd.getCamera() ), Accelerator( GDK_KEY_period ) );
+       GlobalCommands_insert( "CameraStrafeLeft", ReferenceCaller<camera_t, void(), Camera_MoveLeft_Discrete>( camwnd.getCamera() ), Accelerator( GDK_KEY_comma ) );
 
-       GlobalCommands_insert( "CameraUp", ReferenceCaller<camera_t, Camera_MoveUp_Discrete>( camwnd.getCamera() ), Accelerator( 'D' ) );
-       GlobalCommands_insert( "CameraDown", ReferenceCaller<camera_t, Camera_MoveDown_Discrete>( camwnd.getCamera() ), Accelerator( 'C' ) );
-       GlobalCommands_insert( "CameraAngleUp", ReferenceCaller<camera_t, Camera_PitchUp_Discrete>( camwnd.getCamera() ), Accelerator( 'A' ) );
-       GlobalCommands_insert( "CameraAngleDown", ReferenceCaller<camera_t, Camera_PitchDown_Discrete>( camwnd.getCamera() ), Accelerator( 'Z' ) );
+       GlobalCommands_insert( "CameraUp", ReferenceCaller<camera_t, void(), Camera_MoveUp_Discrete>( camwnd.getCamera() ), Accelerator( 'D' ) );
+       GlobalCommands_insert( "CameraDown", ReferenceCaller<camera_t, void(), Camera_MoveDown_Discrete>( camwnd.getCamera() ), Accelerator( 'C' ) );
+       GlobalCommands_insert( "CameraAngleUp", ReferenceCaller<camera_t, void(), Camera_PitchUp_Discrete>( camwnd.getCamera() ), Accelerator( 'A' ) );
+       GlobalCommands_insert( "CameraAngleDown", ReferenceCaller<camera_t, void(), Camera_PitchDown_Discrete>( camwnd.getCamera() ), Accelerator( 'Z' ) );
 }
 
 void CamWnd_Move_Enable( CamWnd& camwnd ){
@@ -1039,36 +1044,35 @@ void CamWnd_Move_Discrete_Disable( CamWnd& camwnd ){
        command_disconnect_accelerator( "CameraAngleDown" );
 }
 
-void CamWnd_Move_Discrete_Import( CamWnd& camwnd, bool value ){
-       if ( g_camwindow_globals_private.m_bCamDiscrete ) {
-               CamWnd_Move_Discrete_Disable( camwnd );
-       }
-       else
-       {
-               CamWnd_Move_Disable( camwnd );
+struct CamWnd_Move_Discrete {
+       static void Export(const Callback<void(bool)> &returnz) {
+               returnz(g_camwindow_globals_private.m_bCamDiscrete);
        }
 
-       g_camwindow_globals_private.m_bCamDiscrete = value;
-
-       if ( g_camwindow_globals_private.m_bCamDiscrete ) {
-               CamWnd_Move_Discrete_Enable( camwnd );
-       }
-       else
-       {
-               CamWnd_Move_Enable( camwnd );
+       static void Import(bool value) {
+               if (g_camwnd) {
+                       Import_(*g_camwnd, value);
+               } else {
+                       g_camwindow_globals_private.m_bCamDiscrete = value;
+               }
        }
-}
 
-void CamWnd_Move_Discrete_Import( bool value ){
-       if ( g_camwnd != 0 ) {
-               CamWnd_Move_Discrete_Import( *g_camwnd, value );
-       }
-       else
-       {
+       static void Import_(CamWnd &camwnd, bool value) {
+               if (g_camwindow_globals_private.m_bCamDiscrete) {
+                       CamWnd_Move_Discrete_Disable(camwnd);
+               } else {
+                       CamWnd_Move_Disable(camwnd);
+               }
+
                g_camwindow_globals_private.m_bCamDiscrete = value;
-       }
-}
 
+               if (g_camwindow_globals_private.m_bCamDiscrete) {
+                       CamWnd_Move_Discrete_Enable(camwnd);
+               } else {
+                       CamWnd_Move_Enable(camwnd);
+               }
+       }
+};
 
 
 void CamWnd_Add_Handlers_Move( CamWnd& camwnd ){
@@ -1136,7 +1140,7 @@ void CamWnd_Remove_Handlers_FreeMove( CamWnd& camwnd ){
 CamWnd::CamWnd() :
        m_view( true ),
        m_Camera( &m_view, CamWndQueueDraw( *this ) ),
-       m_cameraview( m_Camera, &m_view, ReferenceCaller<CamWnd, CamWnd_Update>( *this ) ),
+       m_cameraview( m_Camera, &m_view, ReferenceCaller<CamWnd, void(), CamWnd_Update>( *this ) ),
        m_gl_widget( glwidget_new( TRUE ) ),
        m_window_observer( NewWindowObserver() ),
        m_XORRectangle( m_gl_widget ),
@@ -1152,7 +1156,7 @@ CamWnd::CamWnd() :
        GlobalWindowObservers_add( m_window_observer );
        GlobalWindowObservers_connectWidget( m_gl_widget );
 
-       m_window_observer->setRectangleDrawCallback( ReferenceCaller1<CamWnd, rect_t, camwnd_update_xor_rectangle>( *this ) );
+       m_window_observer->setRectangleDrawCallback( ReferenceCaller<CamWnd, void(rect_t), camwnd_update_xor_rectangle>( *this ) );
        m_window_observer->setView( m_view );
 
        g_object_ref( m_gl_widget._handle );
@@ -1171,7 +1175,7 @@ CamWnd::CamWnd() :
 
        m_gl_widget.connect( "scroll_event", G_CALLBACK( wheelmove_scroll ), this );
 
-       AddSceneChangeCallback( ReferenceCaller<CamWnd, CamWnd_Update>( *this ) );
+       AddSceneChangeCallback( ReferenceCaller<CamWnd, void(), CamWnd_Update>( *this ) );
 
        PressedButtons_connect( g_pressedButtons, m_gl_widget );
 }
@@ -1265,7 +1269,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
@@ -1290,7 +1294,7 @@ 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, Camera_motionDelta, &m_Camera );
+       m_freezePointer.freeze_pointer( m_gl_widget, Camera_motionDelta, &m_Camera );
 
        CamWnd_Update( *this );
 }
@@ -1305,7 +1309,7 @@ void CamWnd::DisableFreeMove(){
        CamWnd_Remove_Handlers_FreeMove( *this );
        CamWnd_Add_Handlers_Move( *this );
 
-       m_freezePointer.unfreeze_pointer( m_parent );
+       m_freezePointer.unfreeze_pointer( m_gl_widget );
        g_signal_handler_disconnect( G_OBJECT( m_gl_widget ), m_freemove_handle_focusout );
 
        CamWnd_Update( *this );
@@ -1359,9 +1363,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;
@@ -1391,15 +1397,13 @@ void render( const Matrix4& modelview, const Matrix4& projection ){
 void ShowStatsToggle(){
        g_camwindow_globals_private.m_showStats ^= 1;
 }
-typedef FreeCaller<ShowStatsToggle> ShowStatsToggleCaller;
 
-void ShowStatsExport( const BoolImportCallback& importer ){
+void ShowStatsExport( const Callback<void(bool)> &importer ){
        importer( g_camwindow_globals_private.m_showStats );
 }
-typedef FreeCaller1<const BoolImportCallback&, ShowStatsExport> ShowStatsExportCaller;
 
-ShowStatsExportCaller g_show_stats_caller;
-BoolExportCallback g_show_stats_callback( g_show_stats_caller );
+FreeCaller<void(const Callback<void(bool)>&), ShowStatsExport> g_show_stats_caller;
+Callback<void(const Callback<void(bool)> &)> g_show_stats_callback( g_show_stats_caller );
 ToggleItem g_show_stats( g_show_stats_callback );
 
 void CamWnd::Cam_Draw(){
@@ -1586,7 +1590,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();
@@ -1602,7 +1606,7 @@ 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 );
 }
 
@@ -1630,8 +1634,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 );
@@ -1642,7 +1646,7 @@ bool Camera_GetFarClip(){
        return g_camwindow_globals_private.m_bCubicClipping;
 }
 
-BoolExportCaller g_getfarclip_caller( g_camwindow_globals_private.m_bCubicClipping );
+ConstReferenceCaller<bool, void(const Callback<void(bool)> &), PropertyImpl<bool>::Export> g_getfarclip_caller( g_camwindow_globals_private.m_bCubicClipping );
 ToggleItem g_getfarclip_item( g_getfarclip_caller );
 
 void Camera_SetFarClip( bool value ){
@@ -1653,6 +1657,16 @@ void Camera_SetFarClip( bool value ){
        CamWnd_Update( camwnd );
 }
 
+struct Camera_FarClip {
+       static void Export(const Callback<void(bool)> &returnz) {
+               returnz(g_camwindow_globals_private.m_bCubicClipping);
+       }
+
+       static void Import(bool value) {
+               Camera_SetFarClip(value);
+       }
+};
+
 void Camera_ToggleFarClip(){
        Camera_SetFarClip( !Camera_GetFarClip() );
 }
@@ -1669,6 +1683,8 @@ void CamWnd_registerShortcuts(){
                command_connect_accelerator( "TogglePreview" );
        }
 
+       command_connect_accelerator( "FOVInc" );
+       command_connect_accelerator( "FOVDec" );
        command_connect_accelerator( "CameraSpeedInc" );
        command_connect_accelerator( "CameraSpeedDec" );
 }
@@ -1711,7 +1727,7 @@ CameraModel* g_camera_model = 0;
 void CamWnd_LookThroughCamera( CamWnd& camwnd ){
        if ( g_camera_model != 0 ) {
                CamWnd_Add_Handlers_Move( camwnd );
-               g_camera_model->setCameraView( 0, Callback() );
+               g_camera_model->setCameraView( 0, Callback<void()>() );
                g_camera_model = 0;
                Camera_updateModelview( camwnd.getCamera() );
                Camera_updateProjection( camwnd.getCamera() );
@@ -1734,7 +1750,7 @@ void CamWnd_LookThroughSelected( CamWnd& camwnd ){
                if ( cameraModel != 0 ) {
                        CamWnd_Remove_Handlers_Move( camwnd );
                        g_camera_model = cameraModel;
-                       g_camera_model->setCameraView( &camwnd.getCameraView(), ReferenceCaller<CamWnd, CamWnd_LookThroughCamera>( camwnd ) );
+                       g_camera_model->setCameraView( &camwnd.getCameraView(), ReferenceCaller<CamWnd, void(), CamWnd_LookThroughCamera>( camwnd ) );
                }
        }
 }
@@ -1747,61 +1763,57 @@ void GlobalCamera_LookThroughCamera(){
        CamWnd_LookThroughCamera( *g_camwnd );
 }
 
-
-void RenderModeImport( int value ){
-       switch ( value )
-       {
-       case 0:
-               CamWnd_SetMode( cd_wire );
-               break;
-       case 1:
-               CamWnd_SetMode( cd_solid );
-               break;
-       case 2:
-               CamWnd_SetMode( cd_texture );
-               break;
-       case 3:
-               CamWnd_SetMode( cd_lighting );
-               break;
-       default:
-               CamWnd_SetMode( cd_texture );
+struct RenderMode {
+       static void Export(const Callback<void(int)> &returnz) {
+               switch (CamWnd_GetMode()) {
+                       case cd_wire:
+                               returnz(0);
+                               break;
+                       case cd_solid:
+                               returnz(1);
+                               break;
+                       case cd_texture:
+                               returnz(2);
+                               break;
+                       case cd_lighting:
+                               returnz(3);
+                               break;
+               }
        }
-}
-typedef FreeCaller1<int, RenderModeImport> RenderModeImportCaller;
 
-void RenderModeExport( const IntImportCallback& importer ){
-       switch ( CamWnd_GetMode() )
-       {
-       case cd_wire:
-               importer( 0 );
-               break;
-       case cd_solid:
-               importer( 1 );
-               break;
-       case cd_texture:
-               importer( 2 );
-               break;
-       case cd_lighting:
-               importer( 3 );
-               break;
+       static void Import(int value) {
+               switch (value) {
+                       case 0:
+                               CamWnd_SetMode(cd_wire);
+                               break;
+                       case 1:
+                               CamWnd_SetMode(cd_solid);
+                               break;
+                       case 2:
+                               CamWnd_SetMode(cd_texture);
+                               break;
+                       case 3:
+                               CamWnd_SetMode(cd_lighting);
+                               break;
+                       default:
+                               CamWnd_SetMode(cd_texture);
+               }
        }
-}
-typedef FreeCaller1<const IntImportCallback&, RenderModeExport> RenderModeExportCaller;
+};
 
 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(
                "", "Discrete movement",
-               FreeCaller1<bool, CamWnd_Move_Discrete_Import>(),
-               BoolExportCaller( g_camwindow_globals_private.m_bCamDiscrete )
+               make_property<CamWnd_Move_Discrete>()
                );
        page.appendCheckBox(
                "", "Enable far-clip plane",
-               FreeCaller1<bool, Camera_SetFarClip>(),
-               BoolExportCaller( g_camwindow_globals_private.m_bCubicClipping )
+               make_property<Camera_FarClip>()
                );
 
        if ( g_pGameDescription->mGameType == "doom3" ) {
@@ -1810,8 +1822,7 @@ void Camera_constructPreferences( PreferencesPage& page ){
                page.appendCombo(
                        "Render Mode",
                        STRING_ARRAY_RANGE( render_mode ),
-                       IntImportCallback( RenderModeImportCaller() ),
-                       IntExportCallback( RenderModeExportCaller() )
+                       make_property<RenderMode>()
                        );
        }
        else
@@ -1821,8 +1832,7 @@ void Camera_constructPreferences( PreferencesPage& page ){
                page.appendCombo(
                        "Render Mode",
                        STRING_ARRAY_RANGE( render_mode ),
-                       IntImportCallback( RenderModeImportCaller() ),
-                       IntExportCallback( RenderModeExportCaller() )
+                       make_property<RenderMode>()
                        );
        }
 
@@ -1839,14 +1849,37 @@ void Camera_constructPage( PreferenceGroup& group ){
        Camera_constructPreferences( page );
 }
 void Camera_registerPreferencesPage(){
-       PreferencesDialog_addSettingsPage( FreeCaller1<PreferenceGroup&, Camera_constructPage>() );
+       PreferencesDialog_addSettingsPage( makeCallbackF(Camera_constructPage) );
 }
 
 #include "preferencesystem.h"
 #include "stringio.h"
 #include "dialog.h"
 
-typedef FreeCaller1<bool, CamWnd_Move_Discrete_Import> CamWndMoveDiscreteImportCaller;
+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 ) ) {
@@ -1868,25 +1901,28 @@ void CameraSpeed_decrease(){
 
 /// \brief Initialisation for things that have the same lifespan as this module.
 void CamWnd_Construct(){
-       GlobalCommands_insert( "CenterView", FreeCaller<GlobalCamera_ResetAngles>(), Accelerator( GDK_KEY_End ) );
+       GlobalCommands_insert( "CenterView", makeCallbackF(GlobalCamera_ResetAngles), Accelerator( GDK_KEY_End ) );
 
-       GlobalToggles_insert( "ToggleCubicClip", FreeCaller<Camera_ToggleFarClip>(), ToggleItem::AddCallbackCaller( g_getfarclip_item ), Accelerator( '\\', (GdkModifierType)GDK_CONTROL_MASK ) );
-       GlobalCommands_insert( "CubicClipZoomIn", FreeCaller<Camera_CubeIn>(), Accelerator( '[', (GdkModifierType)GDK_CONTROL_MASK ) );
-       GlobalCommands_insert( "CubicClipZoomOut", FreeCaller<Camera_CubeOut>(), Accelerator( ']', (GdkModifierType)GDK_CONTROL_MASK ) );
+       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 ) );
+       GlobalCommands_insert( "CubicClipZoomOut", makeCallbackF(Camera_CubeOut), Accelerator( ']', (GdkModifierType)GDK_CONTROL_MASK ) );
 
-       GlobalCommands_insert( "UpFloor", FreeCaller<Camera_ChangeFloorUp>(), Accelerator( GDK_KEY_Prior ) );
-       GlobalCommands_insert( "DownFloor", FreeCaller<Camera_ChangeFloorDown>(), Accelerator( GDK_KEY_Next ) );
+       GlobalCommands_insert( "UpFloor", makeCallbackF(Camera_ChangeFloorUp), Accelerator( GDK_KEY_Prior ) );
+       GlobalCommands_insert( "DownFloor", makeCallbackF(Camera_ChangeFloorDown), Accelerator( GDK_KEY_Next ) );
 
        GlobalToggles_insert( "ToggleCamera", ToggleShown::ToggleCaller( g_camera_shown ), ToggleItem::AddCallbackCaller( g_camera_shown.m_item ), Accelerator( 'C', (GdkModifierType)( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) ) );
-       GlobalCommands_insert( "LookThroughSelected", FreeCaller<GlobalCamera_LookThroughSelected>() );
-       GlobalCommands_insert( "LookThroughCamera", FreeCaller<GlobalCamera_LookThroughCamera>() );
+       GlobalCommands_insert( "LookThroughSelected", makeCallbackF(GlobalCamera_LookThroughSelected) );
+       GlobalCommands_insert( "LookThroughCamera", makeCallbackF(GlobalCamera_LookThroughCamera) );
 
        if ( g_pGameDescription->mGameType == "doom3" ) {
-               GlobalCommands_insert( "TogglePreview", FreeCaller<CamWnd_TogglePreview>(), Accelerator( GDK_KEY_F3 ) );
+               GlobalCommands_insert( "TogglePreview", makeCallbackF(CamWnd_TogglePreview), Accelerator( GDK_KEY_F3 ) );
        }
 
-       GlobalCommands_insert( "CameraSpeedInc", FreeCaller<CameraSpeed_increase>(), Accelerator( GDK_KEY_KP_Add, (GdkModifierType)GDK_SHIFT_MASK ) );
-       GlobalCommands_insert( "CameraSpeedDec", FreeCaller<CameraSpeed_decrease>(), Accelerator( GDK_KEY_KP_Subtract, (GdkModifierType)GDK_SHIFT_MASK ) );
+       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 ) );
 
        GlobalShortcuts_insert( "CameraForward", Accelerator( GDK_KEY_Up ) );
        GlobalShortcuts_insert( "CameraBack", Accelerator( GDK_KEY_Down ) );
@@ -1905,20 +1941,21 @@ void CamWnd_Construct(){
        GlobalShortcuts_insert( "CameraFreeMoveLeft", Accelerator( GDK_KEY_Left ) );
        GlobalShortcuts_insert( "CameraFreeMoveRight", Accelerator( GDK_KEY_Right ) );
 
-       GlobalToggles_insert( "ShowStats", ShowStatsToggleCaller(), ToggleItem::AddCallbackCaller( g_show_stats ) );
-
-       GlobalPreferenceSystem().registerPreference( "ShowStats", BoolImportStringCaller( g_camwindow_globals_private.m_showStats ), BoolExportStringCaller( g_camwindow_globals_private.m_showStats ) );
-       GlobalPreferenceSystem().registerPreference( "MoveSpeed", IntImportStringCaller( g_camwindow_globals_private.m_nMoveSpeed ), IntExportStringCaller( g_camwindow_globals_private.m_nMoveSpeed ) );
-       GlobalPreferenceSystem().registerPreference( "CamLinkSpeed", BoolImportStringCaller( g_camwindow_globals_private.m_bCamLinkSpeed ), BoolExportStringCaller( g_camwindow_globals_private.m_bCamLinkSpeed ) );
-       GlobalPreferenceSystem().registerPreference( "AngleSpeed", IntImportStringCaller( g_camwindow_globals_private.m_nAngleSpeed ), IntExportStringCaller( g_camwindow_globals_private.m_nAngleSpeed ) );
-       GlobalPreferenceSystem().registerPreference( "CamInverseMouse", BoolImportStringCaller( g_camwindow_globals_private.m_bCamInverseMouse ), BoolExportStringCaller( g_camwindow_globals_private.m_bCamInverseMouse ) );
-       GlobalPreferenceSystem().registerPreference( "CamDiscrete", makeBoolStringImportCallback( CamWndMoveDiscreteImportCaller() ), BoolExportStringCaller( g_camwindow_globals_private.m_bCamDiscrete ) );
-       GlobalPreferenceSystem().registerPreference( "CubicClipping", BoolImportStringCaller( g_camwindow_globals_private.m_bCubicClipping ), BoolExportStringCaller( g_camwindow_globals_private.m_bCubicClipping ) );
-       GlobalPreferenceSystem().registerPreference( "CubicScale", IntImportStringCaller( g_camwindow_globals.m_nCubicScale ), IntExportStringCaller( g_camwindow_globals.m_nCubicScale ) );
-       GlobalPreferenceSystem().registerPreference( "SI_Colors4", Vector3ImportStringCaller( g_camwindow_globals.color_cameraback ), Vector3ExportStringCaller( g_camwindow_globals.color_cameraback ) );
-       GlobalPreferenceSystem().registerPreference( "SI_Colors12", Vector3ImportStringCaller( g_camwindow_globals.color_selbrushes3d ), Vector3ExportStringCaller( g_camwindow_globals.color_selbrushes3d ) );
-       GlobalPreferenceSystem().registerPreference( "CameraRenderMode", makeIntStringImportCallback( RenderModeImportCaller() ), makeIntStringExportCallback( RenderModeExportCaller() ) );
-       GlobalPreferenceSystem().registerPreference( "StrafeMode", IntImportStringCaller( g_camwindow_globals_private.m_nStrafeMode ), IntExportStringCaller( g_camwindow_globals_private.m_nStrafeMode ) );
+       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 ) );
+       GlobalPreferenceSystem().registerPreference( "CamInverseMouse", make_property_string( g_camwindow_globals_private.m_bCamInverseMouse ) );
+       GlobalPreferenceSystem().registerPreference( "CamDiscrete", make_property_string<CamWnd_Move_Discrete>());
+       GlobalPreferenceSystem().registerPreference( "CubicClipping", make_property_string( g_camwindow_globals_private.m_bCubicClipping ) );
+       GlobalPreferenceSystem().registerPreference( "CubicScale", make_property_string( g_camwindow_globals.m_nCubicScale ) );
+       GlobalPreferenceSystem().registerPreference( "SI_Colors4", make_property_string( g_camwindow_globals.color_cameraback ) );
+       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 ) );
 
        CamWnd_constructStatic();