2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 // Leonardo Zide (leo@lokigames.com)
28 #include "camwindow.h"
31 #include <gdk/gdkkeysyms.h>
33 #include "debugging/debugging.h"
35 #include "iscenegraph.h"
40 #include "renderable.h"
41 #include "preferencesystem.h"
43 #include "signal/signal.h"
44 #include "container/array.h"
48 #include "math/frustum.h"
50 #include "gtkutil/widget.h"
51 #include "gtkutil/button.h"
52 #include "gtkutil/toolbar.h"
53 #include "gtkutil/glwidget.h"
54 #include "gtkutil/xorrectangle.h"
56 #include "selection.h"
57 #include "mainframe.h"
58 #include "preferences.h"
61 #include "windowobservers.h"
62 #include "renderstate.h"
66 Signal0 g_cameraMoved_callbacks;
68 void AddCameraMovedCallback(const SignalHandler &handler)
70 g_cameraMoved_callbacks.connectLast(handler);
73 void CameraMovedNotify()
75 g_cameraMoved_callbacks();
79 struct camwindow_globals_private_t {
83 bool m_bCamInverseMouse;
85 bool m_bCubicClipping;
89 camwindow_globals_private_t() :
91 m_bCamLinkSpeed(true),
93 m_bCamInverseMouse(false),
95 m_bCubicClipping(true),
103 camwindow_globals_private_t g_camwindow_globals_private;
106 const Matrix4 g_opengl2radiant(
113 const Matrix4 g_radiant2opengl(
122 void Camera_mouseMove(camera_t &camera, int x, int y);
124 enum camera_draw_mode {
139 Vector3 color; // background
141 Vector3 forward, right; // move matrix (TTimo: used to have up but it was not updated)
142 Vector3 vup, vpn, vright; // view matrix (taken from the modelview matrix)
147 bool m_strafe; // true when in strafemode toggled by the ctrl-key
148 bool m_strafe_forward; // true when in strafemode by ctrl-key and shift is pressed for forward strafing
150 unsigned int movementflags; // movement flags
151 Timer m_keycontrol_timer;
152 guint m_keymove_handler;
157 DeferredMotionDelta m_mouseMove;
159 static void motionDelta(int x, int y, void *data)
161 Camera_mouseMove(*reinterpret_cast<camera_t *>( data ), x, y);
165 Callback<void()> m_update;
167 static camera_draw_mode draw_mode;
169 camera_t(View *view, const Callback<void()> &update)
177 m_keymove_handler(0),
179 m_mouseMove(motionDelta, this),
186 camera_draw_mode camera_t::draw_mode = cd_texture;
188 inline Matrix4 projection_for_camera(float near_z, float far_z, float fieldOfView, int width, int height)
190 const float half_width = static_cast<float>( near_z * tan(degrees_to_radians(fieldOfView * 0.5)));
191 const float half_height = half_width * (static_cast<float>( height ) / static_cast<float>( width ));
193 return matrix4_frustum(
203 float Camera_getFarClipPlane(camera_t &camera)
205 return (g_camwindow_globals_private.m_bCubicClipping) ? pow(2.0, (g_camwindow_globals.m_nCubicScale + 7) / 2.0)
209 void Camera_updateProjection(camera_t &camera)
211 float farClip = Camera_getFarClipPlane(camera);
212 camera.projection = projection_for_camera(farClip / 4096.0f, farClip, camera.fieldOfView, camera.width,
215 camera.m_view->Construct(camera.projection, camera.modelview, camera.width, camera.height);
218 void Camera_updateVectors(camera_t &camera)
220 for (int i = 0; i < 3; i++) {
221 camera.vright[i] = camera.modelview[(i << 2) + 0];
222 camera.vup[i] = camera.modelview[(i << 2) + 1];
223 camera.vpn[i] = camera.modelview[(i << 2) + 2];
227 void Camera_updateModelview(camera_t &camera)
229 camera.modelview = g_matrix4_identity;
232 Vector3 radiant_eulerXYZ(0, -camera.angles[CAMERA_PITCH], camera.angles[CAMERA_YAW]);
234 matrix4_translate_by_vec3(camera.modelview, camera.origin);
235 matrix4_rotate_by_euler_xyz_degrees(camera.modelview, radiant_eulerXYZ);
236 matrix4_multiply_by_matrix4(camera.modelview, g_radiant2opengl);
237 matrix4_affine_invert(camera.modelview);
239 Camera_updateVectors(camera);
241 camera.m_view->Construct(camera.projection, camera.modelview, camera.width, camera.height);
245 void Camera_Move_updateAxes(camera_t &camera)
247 double ya = degrees_to_radians(camera.angles[CAMERA_YAW]);
249 // the movement matrix is kept 2d
250 camera.forward[0] = static_cast<float>( cos(ya));
251 camera.forward[1] = static_cast<float>( sin(ya));
252 camera.forward[2] = 0;
253 camera.right[0] = camera.forward[1];
254 camera.right[1] = -camera.forward[0];
257 void Camera_Freemove_updateAxes(camera_t &camera)
259 camera.right = camera.vright;
260 camera.forward = vector3_negated(camera.vpn);
263 const Vector3 &Camera_getOrigin(camera_t &camera)
265 return camera.origin;
268 void Camera_setOrigin(camera_t &camera, const Vector3 &origin)
270 camera.origin = origin;
271 Camera_updateModelview(camera);
276 const Vector3 &Camera_getAngles(camera_t &camera)
278 return camera.angles;
281 void Camera_setAngles(camera_t &camera, const Vector3 &angles)
283 camera.angles = angles;
284 Camera_updateModelview(camera);
290 void Camera_FreeMove(camera_t &camera, int dx, int dy)
292 // free strafe mode, toggled by the ctrl key with optional shift for forward movement
293 if (camera.m_strafe) {
294 float strafespeed = 0.65f;
296 if (g_camwindow_globals_private.m_bCamLinkSpeed) {
297 strafespeed = (float) g_camwindow_globals_private.m_nMoveSpeed / 100;
300 camera.origin -= camera.vright * strafespeed * dx;
301 if (camera.m_strafe_forward) {
302 camera.origin += camera.vpn * strafespeed * dy;
304 camera.origin += camera.vup * strafespeed * dy;
306 } else // free rotation
308 const float dtime = 0.1f;
310 if (g_camwindow_globals_private.m_bCamInverseMouse) {
311 camera.angles[CAMERA_PITCH] -= dy * dtime * g_camwindow_globals_private.m_nAngleSpeed;
313 camera.angles[CAMERA_PITCH] += dy * dtime * g_camwindow_globals_private.m_nAngleSpeed;
316 camera.angles[CAMERA_YAW] += dx * dtime * g_camwindow_globals_private.m_nAngleSpeed;
318 if (camera.angles[CAMERA_PITCH] > 90) {
319 camera.angles[CAMERA_PITCH] = 90;
320 } else if (camera.angles[CAMERA_PITCH] < -90) {
321 camera.angles[CAMERA_PITCH] = -90;
324 if (camera.angles[CAMERA_YAW] >= 360) {
325 camera.angles[CAMERA_YAW] -= 360;
326 } else if (camera.angles[CAMERA_YAW] <= 0) {
327 camera.angles[CAMERA_YAW] += 360;
331 Camera_updateModelview(camera);
332 Camera_Freemove_updateAxes(camera);
335 void Cam_MouseControl(camera_t &camera, int x, int y)
337 float xf = (float) (x - camera.width / 2) / (camera.width / 2);
338 float yf = (float) (y - camera.height / 2) / (camera.height / 2);
340 xf *= 1.0f - fabsf(yf);
353 vector3_add(camera.origin, vector3_scaled(camera.forward, yf * 0.1f * g_camwindow_globals_private.m_nMoveSpeed));
354 camera.angles[CAMERA_YAW] += xf * -0.1f * g_camwindow_globals_private.m_nAngleSpeed;
356 Camera_updateModelview(camera);
359 void Camera_mouseMove(camera_t &camera, int x, int y)
361 //globalOutputStream() << "mousemove... ";
362 Camera_FreeMove(camera, -x, -y);
367 const unsigned int MOVE_NONE = 0;
368 const unsigned int MOVE_FORWARD = 1 << 0;
369 const unsigned int MOVE_BACK = 1 << 1;
370 const unsigned int MOVE_ROTRIGHT = 1 << 2;
371 const unsigned int MOVE_ROTLEFT = 1 << 3;
372 const unsigned int MOVE_STRAFERIGHT = 1 << 4;
373 const unsigned int MOVE_STRAFELEFT = 1 << 5;
374 const unsigned int MOVE_UP = 1 << 6;
375 const unsigned int MOVE_DOWN = 1 << 7;
376 const unsigned int MOVE_PITCHUP = 1 << 8;
377 const unsigned int MOVE_PITCHDOWN = 1 << 9;
378 const unsigned int MOVE_ALL =
379 MOVE_FORWARD | MOVE_BACK | MOVE_ROTRIGHT | MOVE_ROTLEFT | MOVE_STRAFERIGHT | MOVE_STRAFELEFT | MOVE_UP |
380 MOVE_DOWN | MOVE_PITCHUP | MOVE_PITCHDOWN;
382 void Cam_KeyControl(camera_t &camera, float dtime)
385 if (camera.movementflags & MOVE_ROTLEFT) {
386 camera.angles[CAMERA_YAW] += 15 * dtime * g_camwindow_globals_private.m_nAngleSpeed;
388 if (camera.movementflags & MOVE_ROTRIGHT) {
389 camera.angles[CAMERA_YAW] -= 15 * dtime * g_camwindow_globals_private.m_nAngleSpeed;
391 if (camera.movementflags & MOVE_PITCHUP) {
392 camera.angles[CAMERA_PITCH] += 15 * dtime * g_camwindow_globals_private.m_nAngleSpeed;
393 if (camera.angles[CAMERA_PITCH] > 90) {
394 camera.angles[CAMERA_PITCH] = 90;
397 if (camera.movementflags & MOVE_PITCHDOWN) {
398 camera.angles[CAMERA_PITCH] -= 15 * dtime * g_camwindow_globals_private.m_nAngleSpeed;
399 if (camera.angles[CAMERA_PITCH] < -90) {
400 camera.angles[CAMERA_PITCH] = -90;
404 Camera_updateModelview(camera);
405 Camera_Freemove_updateAxes(camera);
408 if (camera.movementflags & MOVE_FORWARD) {
409 vector3_add(camera.origin, vector3_scaled(camera.forward, dtime * g_camwindow_globals_private.m_nMoveSpeed));
411 if (camera.movementflags & MOVE_BACK) {
412 vector3_add(camera.origin, vector3_scaled(camera.forward, -dtime * g_camwindow_globals_private.m_nMoveSpeed));
414 if (camera.movementflags & MOVE_STRAFELEFT) {
415 vector3_add(camera.origin, vector3_scaled(camera.right, -dtime * g_camwindow_globals_private.m_nMoveSpeed));
417 if (camera.movementflags & MOVE_STRAFERIGHT) {
418 vector3_add(camera.origin, vector3_scaled(camera.right, dtime * g_camwindow_globals_private.m_nMoveSpeed));
420 if (camera.movementflags & MOVE_UP) {
421 vector3_add(camera.origin, vector3_scaled(g_vector3_axis_z, dtime * g_camwindow_globals_private.m_nMoveSpeed));
423 if (camera.movementflags & MOVE_DOWN) {
424 vector3_add(camera.origin, vector3_scaled(g_vector3_axis_z, -dtime * g_camwindow_globals_private.m_nMoveSpeed));
427 Camera_updateModelview(camera);
430 void Camera_keyMove(camera_t &camera)
432 camera.m_mouseMove.flush();
434 //globalOutputStream() << "keymove... ";
435 float time_seconds = camera.m_keycontrol_timer.elapsed_msec() / static_cast<float>( msec_per_sec );
436 camera.m_keycontrol_timer.start();
437 if (time_seconds > 0.05f) {
438 time_seconds = 0.05f; // 20fps
440 Cam_KeyControl(camera, time_seconds * 5.0f);
446 gboolean camera_keymove(gpointer data)
448 Camera_keyMove(*reinterpret_cast<camera_t *>( data ));
452 void Camera_setMovementFlags(camera_t &camera, unsigned int mask)
454 if ((~camera.movementflags & mask) != 0 && camera.movementflags == 0) {
455 camera.m_keymove_handler = g_idle_add(camera_keymove, &camera);
457 camera.movementflags |= mask;
460 void Camera_clearMovementFlags(camera_t &camera, unsigned int mask)
462 if ((camera.movementflags & ~mask) == 0 && camera.movementflags != 0) {
463 g_source_remove(camera.m_keymove_handler);
464 camera.m_keymove_handler = 0;
466 camera.movementflags &= ~mask;
469 void Camera_MoveForward_KeyDown(camera_t &camera)
471 Camera_setMovementFlags(camera, MOVE_FORWARD);
474 void Camera_MoveForward_KeyUp(camera_t &camera)
476 Camera_clearMovementFlags(camera, MOVE_FORWARD);
479 void Camera_MoveBack_KeyDown(camera_t &camera)
481 Camera_setMovementFlags(camera, MOVE_BACK);
484 void Camera_MoveBack_KeyUp(camera_t &camera)
486 Camera_clearMovementFlags(camera, MOVE_BACK);
489 void Camera_MoveLeft_KeyDown(camera_t &camera)
491 Camera_setMovementFlags(camera, MOVE_STRAFELEFT);
494 void Camera_MoveLeft_KeyUp(camera_t &camera)
496 Camera_clearMovementFlags(camera, MOVE_STRAFELEFT);
499 void Camera_MoveRight_KeyDown(camera_t &camera)
501 Camera_setMovementFlags(camera, MOVE_STRAFERIGHT);
504 void Camera_MoveRight_KeyUp(camera_t &camera)
506 Camera_clearMovementFlags(camera, MOVE_STRAFERIGHT);
509 void Camera_MoveUp_KeyDown(camera_t &camera)
511 Camera_setMovementFlags(camera, MOVE_UP);
514 void Camera_MoveUp_KeyUp(camera_t &camera)
516 Camera_clearMovementFlags(camera, MOVE_UP);
519 void Camera_MoveDown_KeyDown(camera_t &camera)
521 Camera_setMovementFlags(camera, MOVE_DOWN);
524 void Camera_MoveDown_KeyUp(camera_t &camera)
526 Camera_clearMovementFlags(camera, MOVE_DOWN);
529 void Camera_RotateLeft_KeyDown(camera_t &camera)
531 Camera_setMovementFlags(camera, MOVE_ROTLEFT);
534 void Camera_RotateLeft_KeyUp(camera_t &camera)
536 Camera_clearMovementFlags(camera, MOVE_ROTLEFT);
539 void Camera_RotateRight_KeyDown(camera_t &camera)
541 Camera_setMovementFlags(camera, MOVE_ROTRIGHT);
544 void Camera_RotateRight_KeyUp(camera_t &camera)
546 Camera_clearMovementFlags(camera, MOVE_ROTRIGHT);
549 void Camera_PitchUp_KeyDown(camera_t &camera)
551 Camera_setMovementFlags(camera, MOVE_PITCHUP);
554 void Camera_PitchUp_KeyUp(camera_t &camera)
556 Camera_clearMovementFlags(camera, MOVE_PITCHUP);
559 void Camera_PitchDown_KeyDown(camera_t &camera)
561 Camera_setMovementFlags(camera, MOVE_PITCHDOWN);
564 void Camera_PitchDown_KeyUp(camera_t &camera)
566 Camera_clearMovementFlags(camera, MOVE_PITCHDOWN);
570 typedef ReferenceCaller<camera_t, void(), &Camera_MoveForward_KeyDown> FreeMoveCameraMoveForwardKeyDownCaller;
571 typedef ReferenceCaller<camera_t, void(), &Camera_MoveForward_KeyUp> FreeMoveCameraMoveForwardKeyUpCaller;
572 typedef ReferenceCaller<camera_t, void(), &Camera_MoveBack_KeyDown> FreeMoveCameraMoveBackKeyDownCaller;
573 typedef ReferenceCaller<camera_t, void(), &Camera_MoveBack_KeyUp> FreeMoveCameraMoveBackKeyUpCaller;
574 typedef ReferenceCaller<camera_t, void(), &Camera_MoveLeft_KeyDown> FreeMoveCameraMoveLeftKeyDownCaller;
575 typedef ReferenceCaller<camera_t, void(), &Camera_MoveLeft_KeyUp> FreeMoveCameraMoveLeftKeyUpCaller;
576 typedef ReferenceCaller<camera_t, void(), &Camera_MoveRight_KeyDown> FreeMoveCameraMoveRightKeyDownCaller;
577 typedef ReferenceCaller<camera_t, void(), &Camera_MoveRight_KeyUp> FreeMoveCameraMoveRightKeyUpCaller;
578 typedef ReferenceCaller<camera_t, void(), &Camera_MoveUp_KeyDown> FreeMoveCameraMoveUpKeyDownCaller;
579 typedef ReferenceCaller<camera_t, void(), &Camera_MoveUp_KeyUp> FreeMoveCameraMoveUpKeyUpCaller;
580 typedef ReferenceCaller<camera_t, void(), &Camera_MoveDown_KeyDown> FreeMoveCameraMoveDownKeyDownCaller;
581 typedef ReferenceCaller<camera_t, void(), &Camera_MoveDown_KeyUp> FreeMoveCameraMoveDownKeyUpCaller;
584 const float SPEED_MOVE = 32;
585 const float SPEED_TURN = 22.5;
586 const float MIN_CAM_SPEED = 10;
587 const float MAX_CAM_SPEED = 610;
588 const float CAM_SPEED_STEP = 50;
590 void Camera_MoveForward_Discrete(camera_t &camera)
592 Camera_Move_updateAxes(camera);
593 Camera_setOrigin(camera, vector3_added(Camera_getOrigin(camera), vector3_scaled(camera.forward, SPEED_MOVE)));
596 void Camera_MoveBack_Discrete(camera_t &camera)
598 Camera_Move_updateAxes(camera);
599 Camera_setOrigin(camera, vector3_added(Camera_getOrigin(camera), vector3_scaled(camera.forward, -SPEED_MOVE)));
602 void Camera_MoveUp_Discrete(camera_t &camera)
604 Vector3 origin(Camera_getOrigin(camera));
605 origin[2] += SPEED_MOVE;
606 Camera_setOrigin(camera, origin);
609 void Camera_MoveDown_Discrete(camera_t &camera)
611 Vector3 origin(Camera_getOrigin(camera));
612 origin[2] -= SPEED_MOVE;
613 Camera_setOrigin(camera, origin);
616 void Camera_MoveLeft_Discrete(camera_t &camera)
618 Camera_Move_updateAxes(camera);
619 Camera_setOrigin(camera, vector3_added(Camera_getOrigin(camera), vector3_scaled(camera.right, -SPEED_MOVE)));
622 void Camera_MoveRight_Discrete(camera_t &camera)
624 Camera_Move_updateAxes(camera);
625 Camera_setOrigin(camera, vector3_added(Camera_getOrigin(camera), vector3_scaled(camera.right, SPEED_MOVE)));
628 void Camera_RotateLeft_Discrete(camera_t &camera)
630 Vector3 angles(Camera_getAngles(camera));
631 angles[CAMERA_YAW] += SPEED_TURN;
632 Camera_setAngles(camera, angles);
635 void Camera_RotateRight_Discrete(camera_t &camera)
637 Vector3 angles(Camera_getAngles(camera));
638 angles[CAMERA_YAW] -= SPEED_TURN;
639 Camera_setAngles(camera, angles);
642 void Camera_PitchUp_Discrete(camera_t &camera)
644 Vector3 angles(Camera_getAngles(camera));
645 angles[CAMERA_PITCH] += SPEED_TURN;
646 if (angles[CAMERA_PITCH] > 90) {
647 angles[CAMERA_PITCH] = 90;
649 Camera_setAngles(camera, angles);
652 void Camera_PitchDown_Discrete(camera_t &camera)
654 Vector3 angles(Camera_getAngles(camera));
655 angles[CAMERA_PITCH] -= SPEED_TURN;
656 if (angles[CAMERA_PITCH] < -90) {
657 angles[CAMERA_PITCH] = -90;
659 Camera_setAngles(camera, angles);
663 class RadiantCameraView : public CameraView {
666 Callback<void()> m_update;
668 RadiantCameraView(camera_t &camera, View *view, const Callback<void()> &update) : m_camera(camera), m_view(view),
675 m_view->Construct(m_camera.projection, m_camera.modelview, m_camera.width, m_camera.height);
679 void setModelview(const Matrix4 &modelview)
681 m_camera.modelview = modelview;
682 matrix4_multiply_by_matrix4(m_camera.modelview, g_radiant2opengl);
683 matrix4_affine_invert(m_camera.modelview);
684 Camera_updateVectors(m_camera);
688 void setFieldOfView(float fieldOfView)
690 float farClip = Camera_getFarClipPlane(m_camera);
691 m_camera.projection = projection_for_camera(farClip / 4096.0f, farClip, fieldOfView, m_camera.width,
698 void Camera_motionDelta(int x, int y, unsigned int state, void *data)
700 camera_t *cam = reinterpret_cast<camera_t *>( data );
702 cam->m_mouseMove.motion_delta(x, y, state);
704 switch (g_camwindow_globals_private.m_nStrafeMode) {
706 cam->m_strafe = (state & GDK_CONTROL_MASK) != 0;
708 cam->m_strafe_forward = (state & GDK_SHIFT_MASK) != 0;
710 cam->m_strafe_forward = false;
714 cam->m_strafe = (state & GDK_CONTROL_MASK) != 0 && (state & GDK_SHIFT_MASK) == 0;
715 cam->m_strafe_forward = false;
718 cam->m_strafe = (state & GDK_CONTROL_MASK) != 0 && (state & GDK_SHIFT_MASK) == 0;
719 cam->m_strafe_forward = cam->m_strafe;
727 RadiantCameraView m_cameraview;
729 int m_PositionDragCursorX;
730 int m_PositionDragCursorY;
733 guint m_freemove_handle_focusout;
735 static Shader *m_state_select1;
736 static Shader *m_state_select2;
738 FreezePointer m_freezePointer;
741 ui::GLArea m_gl_widget;
742 ui::Window m_parent{ui::null};
744 SelectionSystemWindowObserver *m_window_observer;
745 XORRectangle m_XORRectangle;
747 DeferredDraw m_deferredDraw;
748 DeferredMotion m_deferred_motion;
750 guint m_selection_button_press_handler;
751 guint m_selection_button_release_handler;
752 guint m_selection_motion_handler;
754 guint m_freelook_button_press_handler;
757 guint m_exposeHandler;
767 //ASSERT_MESSAGE(!m_drawing, "CamWnd::queue_draw(): called while draw is already in progress");
771 //globalOutputStream() << "queue... ";
772 m_deferredDraw.draw();
777 static void captureStates()
779 m_state_select1 = GlobalShaderCache().capture("$CAM_HIGHLIGHT");
780 m_state_select2 = GlobalShaderCache().capture("$CAM_OVERLAY");
783 static void releaseStates()
785 GlobalShaderCache().release("$CAM_HIGHLIGHT");
786 GlobalShaderCache().release("$CAM_OVERLAY");
789 camera_t &getCamera()
796 void Cam_ChangeFloor(bool up);
798 void DisableFreeMove();
800 void EnableFreeMove();
804 CameraView &getCameraView()
813 typedef MemberCaller<CamWnd, void(), &CamWnd::queue_draw> CamWndQueueDraw;
815 Shader *CamWnd::m_state_select1 = 0;
816 Shader *CamWnd::m_state_select2 = 0;
823 void DeleteCamWnd(CamWnd *camwnd)
828 void CamWnd_constructStatic()
830 CamWnd::captureStates();
833 void CamWnd_destroyStatic()
835 CamWnd::releaseStates();
838 static CamWnd *g_camwnd = 0;
840 void GlobalCamera_setCamWnd(CamWnd &camwnd)
846 ui::GLArea CamWnd_getWidget(CamWnd &camwnd)
848 return camwnd.m_gl_widget;
851 ui::Window CamWnd_getParent(CamWnd &camwnd)
853 return camwnd.m_parent;
856 ToggleShown g_camera_shown(true);
858 void CamWnd_setParent(CamWnd &camwnd, ui::Window parent)
860 camwnd.m_parent = parent;
861 g_camera_shown.connect(camwnd.m_parent);
864 void CamWnd_Update(CamWnd &camwnd)
870 camwindow_globals_t g_camwindow_globals;
872 const Vector3 &Camera_getOrigin(CamWnd &camwnd)
874 return Camera_getOrigin(camwnd.getCamera());
877 void Camera_setOrigin(CamWnd &camwnd, const Vector3 &origin)
879 Camera_setOrigin(camwnd.getCamera(), origin);
882 const Vector3 &Camera_getAngles(CamWnd &camwnd)
884 return Camera_getAngles(camwnd.getCamera());
887 void Camera_setAngles(CamWnd &camwnd, const Vector3 &angles)
889 Camera_setAngles(camwnd.getCamera(), angles);
893 // =============================================================================
896 gboolean enable_freelook_button_press(ui::Widget widget, GdkEventButton *event, CamWnd *camwnd)
898 if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
899 camwnd->EnableFreeMove();
905 gboolean disable_freelook_button_press(ui::Widget widget, GdkEventButton *event, CamWnd *camwnd)
907 if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
908 camwnd->DisableFreeMove();
915 gboolean mousecontrol_button_press( ui::Widget widget, GdkEventButton* event, CamWnd* camwnd ){
916 if ( event->type == GDK_BUTTON_PRESS && event->button == 3 ) {
917 Cam_MouseControl( camwnd->getCamera(), event->x, widget->allocation.height - 1 - event->y );
923 void camwnd_update_xor_rectangle(CamWnd &self, rect_t area)
925 if (self.m_gl_widget.visible()) {
926 self.m_XORRectangle.set(
927 rectangle_from_area(area.min, area.max, self.getCamera().width, self.getCamera().height));
932 gboolean selection_button_press(ui::Widget widget, GdkEventButton *event, WindowObserver *observer)
934 if (event->type == GDK_BUTTON_PRESS) {
935 observer->onMouseDown(WindowVector_forDouble(event->x, event->y), button_for_button(event->button),
936 modifiers_for_state(event->state));
941 gboolean selection_button_release(ui::Widget widget, GdkEventButton *event, WindowObserver *observer)
943 if (event->type == GDK_BUTTON_RELEASE) {
944 observer->onMouseUp(WindowVector_forDouble(event->x, event->y), button_for_button(event->button),
945 modifiers_for_state(event->state));
950 void selection_motion(gdouble x, gdouble y, guint state, void *data)
952 //globalOutputStream() << "motion... ";
953 reinterpret_cast<WindowObserver *>( data )->onMouseMotion(WindowVector_forDouble(x, y), modifiers_for_state(state));
956 inline WindowVector windowvector_for_widget_centre(ui::Widget widget)
958 auto allocation = widget.dimensions();
959 return WindowVector(static_cast<float>( allocation.width / 2 ), static_cast<float>(allocation.height / 2 ));
962 gboolean selection_button_press_freemove(ui::Widget widget, GdkEventButton *event, WindowObserver *observer)
964 if (event->type == GDK_BUTTON_PRESS) {
965 observer->onMouseDown(windowvector_for_widget_centre(widget), button_for_button(event->button),
966 modifiers_for_state(event->state));
971 gboolean selection_button_release_freemove(ui::Widget widget, GdkEventButton *event, WindowObserver *observer)
973 if (event->type == GDK_BUTTON_RELEASE) {
974 observer->onMouseUp(windowvector_for_widget_centre(widget), button_for_button(event->button),
975 modifiers_for_state(event->state));
980 gboolean selection_motion_freemove(ui::Widget widget, GdkEventMotion *event, WindowObserver *observer)
982 observer->onMouseMotion(windowvector_for_widget_centre(widget), modifiers_for_state(event->state));
986 gboolean wheelmove_scroll(ui::Widget widget, GdkEventScroll *event, CamWnd *camwnd)
988 if (event->direction == GDK_SCROLL_UP) {
989 Camera_Freemove_updateAxes(camwnd->getCamera());
990 Camera_setOrigin(*camwnd, vector3_added(Camera_getOrigin(*camwnd), vector3_scaled(camwnd->getCamera().forward,
991 static_cast<float>( g_camwindow_globals_private.m_nMoveSpeed ))));
992 } else if (event->direction == GDK_SCROLL_DOWN) {
993 Camera_Freemove_updateAxes(camwnd->getCamera());
994 Camera_setOrigin(*camwnd, vector3_added(Camera_getOrigin(*camwnd), vector3_scaled(camwnd->getCamera().forward,
995 -static_cast<float>( g_camwindow_globals_private.m_nMoveSpeed ))));
1001 gboolean camera_size_allocate(ui::Widget widget, GtkAllocation *allocation, CamWnd *camwnd)
1003 camwnd->getCamera().width = allocation->width;
1004 camwnd->getCamera().height = allocation->height;
1005 Camera_updateProjection(camwnd->getCamera());
1006 camwnd->m_window_observer->onSizeChanged(camwnd->getCamera().width, camwnd->getCamera().height);
1007 camwnd->queue_draw();
1011 gboolean camera_expose(ui::Widget widget, GdkEventExpose *event, gpointer data)
1013 reinterpret_cast<CamWnd *>( data )->draw();
1017 void KeyEvent_connect(const char *name)
1019 const KeyEvent &keyEvent = GlobalKeyEvents_find(name);
1020 keydown_accelerators_add(keyEvent.m_accelerator, keyEvent.m_keyDown);
1021 keyup_accelerators_add(keyEvent.m_accelerator, keyEvent.m_keyUp);
1024 void KeyEvent_disconnect(const char *name)
1026 const KeyEvent &keyEvent = GlobalKeyEvents_find(name);
1027 keydown_accelerators_remove(keyEvent.m_accelerator);
1028 keyup_accelerators_remove(keyEvent.m_accelerator);
1031 void CamWnd_registerCommands(CamWnd &camwnd)
1033 GlobalKeyEvents_insert("CameraForward", Accelerator(GDK_KEY_Up),
1034 ReferenceCaller<camera_t, void(), Camera_MoveForward_KeyDown>(camwnd.getCamera()),
1035 ReferenceCaller<camera_t, void(), Camera_MoveForward_KeyUp>(camwnd.getCamera())
1037 GlobalKeyEvents_insert("CameraBack", Accelerator(GDK_KEY_Down),
1038 ReferenceCaller<camera_t, void(), Camera_MoveBack_KeyDown>(camwnd.getCamera()),
1039 ReferenceCaller<camera_t, void(), Camera_MoveBack_KeyUp>(camwnd.getCamera())
1041 GlobalKeyEvents_insert("CameraLeft", Accelerator(GDK_KEY_Left),
1042 ReferenceCaller<camera_t, void(), Camera_RotateLeft_KeyDown>(camwnd.getCamera()),
1043 ReferenceCaller<camera_t, void(), Camera_RotateLeft_KeyUp>(camwnd.getCamera())
1045 GlobalKeyEvents_insert("CameraRight", Accelerator(GDK_KEY_Right),
1046 ReferenceCaller<camera_t, void(), Camera_RotateRight_KeyDown>(camwnd.getCamera()),
1047 ReferenceCaller<camera_t, void(), Camera_RotateRight_KeyUp>(camwnd.getCamera())
1049 GlobalKeyEvents_insert("CameraStrafeRight", Accelerator(GDK_KEY_period),
1050 ReferenceCaller<camera_t, void(), Camera_MoveRight_KeyDown>(camwnd.getCamera()),
1051 ReferenceCaller<camera_t, void(), Camera_MoveRight_KeyUp>(camwnd.getCamera())
1053 GlobalKeyEvents_insert("CameraStrafeLeft", Accelerator(GDK_KEY_comma),
1054 ReferenceCaller<camera_t, void(), Camera_MoveLeft_KeyDown>(camwnd.getCamera()),
1055 ReferenceCaller<camera_t, void(), Camera_MoveLeft_KeyUp>(camwnd.getCamera())
1057 GlobalKeyEvents_insert("CameraUp", Accelerator('D'),
1058 ReferenceCaller<camera_t, void(), Camera_MoveUp_KeyDown>(camwnd.getCamera()),
1059 ReferenceCaller<camera_t, void(), Camera_MoveUp_KeyUp>(camwnd.getCamera())
1061 GlobalKeyEvents_insert("CameraDown", Accelerator('C'),
1062 ReferenceCaller<camera_t, void(), Camera_MoveDown_KeyDown>(camwnd.getCamera()),
1063 ReferenceCaller<camera_t, void(), Camera_MoveDown_KeyUp>(camwnd.getCamera())
1065 GlobalKeyEvents_insert("CameraAngleDown", Accelerator('A'),
1066 ReferenceCaller<camera_t, void(), Camera_PitchDown_KeyDown>(camwnd.getCamera()),
1067 ReferenceCaller<camera_t, void(), Camera_PitchDown_KeyUp>(camwnd.getCamera())
1069 GlobalKeyEvents_insert("CameraAngleUp", Accelerator('Z'),
1070 ReferenceCaller<camera_t, void(), Camera_PitchUp_KeyDown>(camwnd.getCamera()),
1071 ReferenceCaller<camera_t, void(), Camera_PitchUp_KeyUp>(camwnd.getCamera())
1074 GlobalKeyEvents_insert("CameraFreeMoveForward", Accelerator(GDK_KEY_Up),
1075 FreeMoveCameraMoveForwardKeyDownCaller(camwnd.getCamera()),
1076 FreeMoveCameraMoveForwardKeyUpCaller(camwnd.getCamera())
1078 GlobalKeyEvents_insert("CameraFreeMoveBack", Accelerator(GDK_KEY_Down),
1079 FreeMoveCameraMoveBackKeyDownCaller(camwnd.getCamera()),
1080 FreeMoveCameraMoveBackKeyUpCaller(camwnd.getCamera())
1082 GlobalKeyEvents_insert("CameraFreeMoveLeft", Accelerator(GDK_KEY_Left),
1083 FreeMoveCameraMoveLeftKeyDownCaller(camwnd.getCamera()),
1084 FreeMoveCameraMoveLeftKeyUpCaller(camwnd.getCamera())
1086 GlobalKeyEvents_insert("CameraFreeMoveRight", Accelerator(GDK_KEY_Right),
1087 FreeMoveCameraMoveRightKeyDownCaller(camwnd.getCamera()),
1088 FreeMoveCameraMoveRightKeyUpCaller(camwnd.getCamera())
1090 GlobalKeyEvents_insert("CameraFreeMoveUp", Accelerator('D'),
1091 FreeMoveCameraMoveUpKeyDownCaller(camwnd.getCamera()),
1092 FreeMoveCameraMoveUpKeyUpCaller(camwnd.getCamera())
1094 GlobalKeyEvents_insert("CameraFreeMoveDown", Accelerator('C'),
1095 FreeMoveCameraMoveDownKeyDownCaller(camwnd.getCamera()),
1096 FreeMoveCameraMoveDownKeyUpCaller(camwnd.getCamera())
1099 GlobalCommands_insert("CameraForward",
1100 ReferenceCaller<camera_t, void(), Camera_MoveForward_Discrete>(camwnd.getCamera()),
1101 Accelerator(GDK_KEY_Up));
1102 GlobalCommands_insert("CameraBack", ReferenceCaller<camera_t, void(), Camera_MoveBack_Discrete>(camwnd.getCamera()),
1103 Accelerator(GDK_KEY_Down));
1104 GlobalCommands_insert("CameraLeft",
1105 ReferenceCaller<camera_t, void(), Camera_RotateLeft_Discrete>(camwnd.getCamera()),
1106 Accelerator(GDK_KEY_Left));
1107 GlobalCommands_insert("CameraRight",
1108 ReferenceCaller<camera_t, void(), Camera_RotateRight_Discrete>(camwnd.getCamera()),
1109 Accelerator(GDK_KEY_Right));
1110 GlobalCommands_insert("CameraStrafeRight",
1111 ReferenceCaller<camera_t, void(), Camera_MoveRight_Discrete>(camwnd.getCamera()),
1112 Accelerator(GDK_KEY_period));
1113 GlobalCommands_insert("CameraStrafeLeft",
1114 ReferenceCaller<camera_t, void(), Camera_MoveLeft_Discrete>(camwnd.getCamera()),
1115 Accelerator(GDK_KEY_comma));
1117 GlobalCommands_insert("CameraUp", ReferenceCaller<camera_t, void(), Camera_MoveUp_Discrete>(camwnd.getCamera()),
1119 GlobalCommands_insert("CameraDown", ReferenceCaller<camera_t, void(), Camera_MoveDown_Discrete>(camwnd.getCamera()),
1121 GlobalCommands_insert("CameraAngleUp",
1122 ReferenceCaller<camera_t, void(), Camera_PitchUp_Discrete>(camwnd.getCamera()),
1124 GlobalCommands_insert("CameraAngleDown",
1125 ReferenceCaller<camera_t, void(), Camera_PitchDown_Discrete>(camwnd.getCamera()),
1129 void CamWnd_Move_Enable(CamWnd &camwnd)
1131 KeyEvent_connect("CameraForward");
1132 KeyEvent_connect("CameraBack");
1133 KeyEvent_connect("CameraLeft");
1134 KeyEvent_connect("CameraRight");
1135 KeyEvent_connect("CameraStrafeRight");
1136 KeyEvent_connect("CameraStrafeLeft");
1137 KeyEvent_connect("CameraUp");
1138 KeyEvent_connect("CameraDown");
1139 KeyEvent_connect("CameraAngleUp");
1140 KeyEvent_connect("CameraAngleDown");
1143 void CamWnd_Move_Disable(CamWnd &camwnd)
1145 KeyEvent_disconnect("CameraForward");
1146 KeyEvent_disconnect("CameraBack");
1147 KeyEvent_disconnect("CameraLeft");
1148 KeyEvent_disconnect("CameraRight");
1149 KeyEvent_disconnect("CameraStrafeRight");
1150 KeyEvent_disconnect("CameraStrafeLeft");
1151 KeyEvent_disconnect("CameraUp");
1152 KeyEvent_disconnect("CameraDown");
1153 KeyEvent_disconnect("CameraAngleUp");
1154 KeyEvent_disconnect("CameraAngleDown");
1157 void CamWnd_Move_Discrete_Enable(CamWnd &camwnd)
1159 command_connect_accelerator("CameraForward");
1160 command_connect_accelerator("CameraBack");
1161 command_connect_accelerator("CameraLeft");
1162 command_connect_accelerator("CameraRight");
1163 command_connect_accelerator("CameraStrafeRight");
1164 command_connect_accelerator("CameraStrafeLeft");
1165 command_connect_accelerator("CameraUp");
1166 command_connect_accelerator("CameraDown");
1167 command_connect_accelerator("CameraAngleUp");
1168 command_connect_accelerator("CameraAngleDown");
1171 void CamWnd_Move_Discrete_Disable(CamWnd &camwnd)
1173 command_disconnect_accelerator("CameraForward");
1174 command_disconnect_accelerator("CameraBack");
1175 command_disconnect_accelerator("CameraLeft");
1176 command_disconnect_accelerator("CameraRight");
1177 command_disconnect_accelerator("CameraStrafeRight");
1178 command_disconnect_accelerator("CameraStrafeLeft");
1179 command_disconnect_accelerator("CameraUp");
1180 command_disconnect_accelerator("CameraDown");
1181 command_disconnect_accelerator("CameraAngleUp");
1182 command_disconnect_accelerator("CameraAngleDown");
1185 struct CamWnd_Move_Discrete {
1186 static void Export(const Callback<void(bool)> &returnz)
1188 returnz(g_camwindow_globals_private.m_bCamDiscrete);
1191 static void Import(bool value)
1194 Import_(*g_camwnd, value);
1196 g_camwindow_globals_private.m_bCamDiscrete = value;
1200 static void Import_(CamWnd &camwnd, bool value)
1202 if (g_camwindow_globals_private.m_bCamDiscrete) {
1203 CamWnd_Move_Discrete_Disable(camwnd);
1205 CamWnd_Move_Disable(camwnd);
1208 g_camwindow_globals_private.m_bCamDiscrete = value;
1210 if (g_camwindow_globals_private.m_bCamDiscrete) {
1211 CamWnd_Move_Discrete_Enable(camwnd);
1213 CamWnd_Move_Enable(camwnd);
1219 void CamWnd_Add_Handlers_Move(CamWnd &camwnd)
1221 camwnd.m_selection_button_press_handler = camwnd.m_gl_widget.connect("button_press_event",
1222 G_CALLBACK(selection_button_press),
1223 camwnd.m_window_observer);
1224 camwnd.m_selection_button_release_handler = camwnd.m_gl_widget.connect("button_release_event",
1225 G_CALLBACK(selection_button_release),
1226 camwnd.m_window_observer);
1227 camwnd.m_selection_motion_handler = camwnd.m_gl_widget.connect("motion_notify_event",
1228 G_CALLBACK(DeferredMotion::gtk_motion),
1229 &camwnd.m_deferred_motion);
1231 camwnd.m_freelook_button_press_handler = camwnd.m_gl_widget.connect("button_press_event",
1232 G_CALLBACK(enable_freelook_button_press),
1235 if (g_camwindow_globals_private.m_bCamDiscrete) {
1236 CamWnd_Move_Discrete_Enable(camwnd);
1238 CamWnd_Move_Enable(camwnd);
1242 void CamWnd_Remove_Handlers_Move(CamWnd &camwnd)
1244 g_signal_handler_disconnect(G_OBJECT(camwnd.m_gl_widget), camwnd.m_selection_button_press_handler);
1245 g_signal_handler_disconnect(G_OBJECT(camwnd.m_gl_widget), camwnd.m_selection_button_release_handler);
1246 g_signal_handler_disconnect(G_OBJECT(camwnd.m_gl_widget), camwnd.m_selection_motion_handler);
1248 g_signal_handler_disconnect(G_OBJECT(camwnd.m_gl_widget), camwnd.m_freelook_button_press_handler);
1250 if (g_camwindow_globals_private.m_bCamDiscrete) {
1251 CamWnd_Move_Discrete_Disable(camwnd);
1253 CamWnd_Move_Disable(camwnd);
1257 void CamWnd_Add_Handlers_FreeMove(CamWnd &camwnd)
1259 camwnd.m_selection_button_press_handler = camwnd.m_gl_widget.connect("button_press_event",
1260 G_CALLBACK(selection_button_press_freemove),
1261 camwnd.m_window_observer);
1262 camwnd.m_selection_button_release_handler = camwnd.m_gl_widget.connect("button_release_event", G_CALLBACK(
1263 selection_button_release_freemove), camwnd.m_window_observer);
1264 camwnd.m_selection_motion_handler = camwnd.m_gl_widget.connect("motion_notify_event",
1265 G_CALLBACK(selection_motion_freemove),
1266 camwnd.m_window_observer);
1268 camwnd.m_freelook_button_press_handler = camwnd.m_gl_widget.connect("button_press_event",
1269 G_CALLBACK(disable_freelook_button_press),
1272 KeyEvent_connect("CameraFreeMoveForward");
1273 KeyEvent_connect("CameraFreeMoveBack");
1274 KeyEvent_connect("CameraFreeMoveLeft");
1275 KeyEvent_connect("CameraFreeMoveRight");
1276 KeyEvent_connect("CameraFreeMoveUp");
1277 KeyEvent_connect("CameraFreeMoveDown");
1280 void CamWnd_Remove_Handlers_FreeMove(CamWnd &camwnd)
1282 KeyEvent_disconnect("CameraFreeMoveForward");
1283 KeyEvent_disconnect("CameraFreeMoveBack");
1284 KeyEvent_disconnect("CameraFreeMoveLeft");
1285 KeyEvent_disconnect("CameraFreeMoveRight");
1286 KeyEvent_disconnect("CameraFreeMoveUp");
1287 KeyEvent_disconnect("CameraFreeMoveDown");
1289 g_signal_handler_disconnect(G_OBJECT(camwnd.m_gl_widget), camwnd.m_selection_button_press_handler);
1290 g_signal_handler_disconnect(G_OBJECT(camwnd.m_gl_widget), camwnd.m_selection_button_release_handler);
1291 g_signal_handler_disconnect(G_OBJECT(camwnd.m_gl_widget), camwnd.m_selection_motion_handler);
1293 g_signal_handler_disconnect(G_OBJECT(camwnd.m_gl_widget), camwnd.m_freelook_button_press_handler);
1298 m_Camera(&m_view, CamWndQueueDraw(*this)),
1299 m_cameraview(m_Camera, &m_view, ReferenceCaller<CamWnd, void(), CamWnd_Update>(*this)),
1300 m_gl_widget(glwidget_new(TRUE)),
1301 m_window_observer(NewWindowObserver()),
1302 m_XORRectangle(m_gl_widget),
1303 m_deferredDraw(WidgetQueueDrawCaller(m_gl_widget)),
1304 m_deferred_motion(selection_motion, m_window_observer),
1305 m_selection_button_press_handler(0),
1306 m_selection_button_release_handler(0),
1307 m_selection_motion_handler(0),
1308 m_freelook_button_press_handler(0),
1311 m_bFreeMove = false;
1313 GlobalWindowObservers_add(m_window_observer);
1314 GlobalWindowObservers_connectWidget(m_gl_widget);
1316 m_window_observer->setRectangleDrawCallback(
1317 ReferenceCaller<CamWnd, void(rect_t), camwnd_update_xor_rectangle>(*this));
1318 m_window_observer->setView(m_view);
1320 g_object_ref(m_gl_widget._handle);
1322 gtk_widget_set_events(m_gl_widget,
1323 GDK_DESTROY | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
1324 GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK);
1325 gtk_widget_set_can_focus(m_gl_widget, true);
1327 m_sizeHandler = m_gl_widget.connect("size_allocate", G_CALLBACK(camera_size_allocate), this);
1328 m_exposeHandler = m_gl_widget.on_render(G_CALLBACK(camera_expose), this);
1330 Map_addValidCallback(g_map, DeferredDrawOnMapValidChangedCaller(m_deferredDraw));
1332 CamWnd_registerCommands(*this);
1334 CamWnd_Add_Handlers_Move(*this);
1336 m_gl_widget.connect("scroll_event", G_CALLBACK(wheelmove_scroll), this);
1338 AddSceneChangeCallback(ReferenceCaller<CamWnd, void(), CamWnd_Update>(*this));
1340 PressedButtons_connect(g_pressedButtons, m_gl_widget);
1349 CamWnd_Remove_Handlers_Move(*this);
1351 g_signal_handler_disconnect(G_OBJECT(m_gl_widget), m_sizeHandler);
1352 g_signal_handler_disconnect(G_OBJECT(m_gl_widget), m_exposeHandler);
1354 m_gl_widget.unref();
1356 m_window_observer->release();
1359 class FloorHeightWalker : public scene::Graph::Walker {
1364 FloorHeightWalker(float current, float &bestUp, float &bestDown) :
1365 m_current(current), m_bestUp(bestUp), m_bestDown(bestDown)
1367 bestUp = g_MaxWorldCoord;
1368 bestDown = -g_MaxWorldCoord;
1371 bool pre(const scene::Path &path, scene::Instance &instance) const
1373 if (path.top().get().visible()
1374 && Node_isBrush(path.top())) { // this node is a floor
1375 const AABB &aabb = instance.worldAABB();
1376 float floorHeight = aabb.origin.z() + aabb.extents.z();
1377 if (floorHeight > m_current && floorHeight < m_bestUp) {
1378 m_bestUp = floorHeight;
1380 if (floorHeight < m_current && floorHeight > m_bestDown) {
1381 m_bestDown = floorHeight;
1388 void CamWnd::Cam_ChangeFloor(bool up)
1390 float current = m_Camera.origin[2] - 48;
1393 GlobalSceneGraph().traverse(FloorHeightWalker(current, bestUp, bestDown));
1395 if (up && bestUp != g_MaxWorldCoord) {
1398 if (!up && bestDown != -g_MaxWorldCoord) {
1402 m_Camera.origin[2] = current + 48;
1403 Camera_updateModelview(getCamera());
1404 CamWnd_Update(*this);
1405 CameraMovedNotify();
1412 Sys_GetCursorPos( &m_PositionDragCursorX, &m_PositionDragCursorY );
1415 if ( ( m_bFreeMove && ( buttons == ( RAD_CONTROL | RAD_SHIFT ) ) )
1416 || ( !m_bFreeMove && ( buttons == ( RAD_RBUTTON | RAD_CONTROL ) ) ) ) {
1418 CamWnd_Update( camwnd );
1419 CameraMovedNotify();
1423 void CamWnd::Cam_PositionDrag(){
1426 Sys_GetCursorPos( m_gl_widget, &x, &y );
1427 if ( x != m_PositionDragCursorX || y != m_PositionDragCursorY ) {
1428 x -= m_PositionDragCursorX;
1429 vector3_add( m_Camera.origin, vector3_scaled( m_Camera.vright, x ) );
1430 y -= m_PositionDragCursorY;
1431 m_Camera.origin[2] -= y;
1432 Camera_updateModelview();
1433 CamWnd_Update( camwnd );
1434 CameraMovedNotify();
1436 Sys_SetCursorPos( m_parent, m_PositionDragCursorX, m_PositionDragCursorY );
1442 // NOTE TTimo if there's an OS-level focus out of the application
1443 // then we can release the camera cursor grab
1444 static gboolean camwindow_freemove_focusout(ui::Widget widget, GdkEventFocus *event, gpointer data)
1446 reinterpret_cast<CamWnd *>( data )->DisableFreeMove();
1450 void CamWnd::EnableFreeMove()
1452 //globalOutputStream() << "EnableFreeMove\n";
1454 ASSERT_MESSAGE(!m_bFreeMove, "EnableFreeMove: free-move was already enabled");
1456 Camera_clearMovementFlags(getCamera(), MOVE_ALL);
1458 CamWnd_Remove_Handlers_Move(*this);
1459 CamWnd_Add_Handlers_FreeMove(*this);
1461 gtk_window_set_focus(m_parent, m_gl_widget);
1462 m_freemove_handle_focusout = m_gl_widget.connect("focus_out_event", G_CALLBACK(camwindow_freemove_focusout), this);
1463 m_freezePointer.freeze_pointer(m_parent, Camera_motionDelta, &m_Camera);
1465 CamWnd_Update(*this);
1468 void CamWnd::DisableFreeMove()
1470 //globalOutputStream() << "DisableFreeMove\n";
1472 ASSERT_MESSAGE(m_bFreeMove, "DisableFreeMove: free-move was not enabled");
1473 m_bFreeMove = false;
1474 Camera_clearMovementFlags(getCamera(), MOVE_ALL);
1476 CamWnd_Remove_Handlers_FreeMove(*this);
1477 CamWnd_Add_Handlers_Move(*this);
1479 m_freezePointer.unfreeze_pointer(m_parent);
1480 g_signal_handler_disconnect(G_OBJECT(m_gl_widget), m_freemove_handle_focusout);
1482 CamWnd_Update(*this);
1486 #include "renderer.h"
1488 class CamRenderer : public Renderer {
1490 state_type() : m_highlight(0), m_state(0), m_lights(0)
1494 unsigned int m_highlight;
1496 const LightList *m_lights;
1499 std::vector<state_type> m_state_stack;
1500 RenderStateFlags m_globalstate;
1501 Shader *m_state_select0;
1502 Shader *m_state_select1;
1503 const Vector3 &m_viewer;
1506 CamRenderer(RenderStateFlags globalstate, Shader *select0, Shader *select1, const Vector3 &viewer) :
1507 m_globalstate(globalstate),
1508 m_state_select0(select0),
1509 m_state_select1(select1),
1512 ASSERT_NOTNULL(select0);
1513 ASSERT_NOTNULL(select1);
1514 m_state_stack.push_back(state_type());
1517 void SetState(Shader *state, EStyle style)
1519 ASSERT_NOTNULL(state);
1520 if (style == eFullMaterials) {
1521 m_state_stack.back().m_state = state;
1525 EStyle getStyle() const
1527 return eFullMaterials;
1532 m_state_stack.push_back(m_state_stack.back());
1537 ASSERT_MESSAGE(!m_state_stack.empty(), "popping empty stack");
1538 m_state_stack.pop_back();
1541 void Highlight(EHighlightMode mode, bool bEnable = true)
1544 ? m_state_stack.back().m_highlight |= mode
1545 : m_state_stack.back().m_highlight &= ~mode;
1548 void setLights(const LightList &lights)
1550 m_state_stack.back().m_lights = &lights;
1553 void addRenderable(const OpenGLRenderable &renderable, const Matrix4 &world)
1555 if (m_state_stack.back().m_highlight & ePrimitive) {
1556 m_state_select0->addRenderable(renderable, world, m_state_stack.back().m_lights);
1558 if (m_state_stack.back().m_highlight & eFace) {
1559 m_state_select1->addRenderable(renderable, world, m_state_stack.back().m_lights);
1562 m_state_stack.back().m_state->addRenderable(renderable, world, m_state_stack.back().m_lights);
1565 void render(const Matrix4 &modelview, const Matrix4 &projection)
1567 GlobalShaderCache().render(m_globalstate, modelview, projection, m_viewer);
1577 void ShowStatsToggle()
1579 g_camwindow_globals_private.m_showStats ^= 1;
1582 void ShowStatsExport(const Callback<void(bool)> &importer)
1584 importer(g_camwindow_globals_private.m_showStats);
1587 FreeCaller<void(const Callback<void(bool)> &), ShowStatsExport> g_show_stats_caller;
1588 Callback<void(const Callback<void(bool)> &)> g_show_stats_callback(g_show_stats_caller);
1589 ToggleItem g_show_stats(g_show_stats_callback);
1591 void CamWnd::Cam_Draw()
1593 glViewport(0, 0, m_Camera.width, m_Camera.height);
1596 glGetIntegerv( GL_VIEWPORT, viewprt );
1599 // enable depth buffer writes
1600 glDepthMask(GL_TRUE);
1601 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1603 Vector3 clearColour(0, 0, 0);
1604 if (m_Camera.draw_mode != cd_lighting) {
1605 clearColour = g_camwindow_globals.color_cameraback;
1608 glClearColor(clearColour[0], clearColour[1], clearColour[2], 0);
1609 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1611 extern void Renderer_ResetStats();
1612 Renderer_ResetStats();
1613 extern void Cull_ResetStats();
1616 glMatrixMode(GL_PROJECTION);
1617 glLoadMatrixf(reinterpret_cast<const float *>( &m_Camera.projection ));
1619 glMatrixMode(GL_MODELVIEW);
1620 glLoadMatrixf(reinterpret_cast<const float *>( &m_Camera.modelview ));
1623 // one directional light source directly behind the viewer
1625 GLfloat inverse_cam_dir[4], ambient[4], diffuse[4]; //, material[4];
1627 ambient[0] = ambient[1] = ambient[2] = 0.4f;
1629 diffuse[0] = diffuse[1] = diffuse[2] = 0.4f;
1631 //material[0] = material[1] = material[2] = 0.8f;
1632 //material[3] = 1.0f;
1634 inverse_cam_dir[0] = m_Camera.vpn[0];
1635 inverse_cam_dir[1] = m_Camera.vpn[1];
1636 inverse_cam_dir[2] = m_Camera.vpn[2];
1637 inverse_cam_dir[3] = 0;
1639 glLightfv(GL_LIGHT0, GL_POSITION, inverse_cam_dir);
1641 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
1642 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
1644 glEnable(GL_LIGHT0);
1648 unsigned int globalstate =
1649 RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_ALPHATEST | RENDER_BLEND |
1650 RENDER_CULLFACE | RENDER_COLOURARRAY | RENDER_OFFSETLINE | RENDER_POLYGONSMOOTH | RENDER_LINESMOOTH |
1651 RENDER_FOG | RENDER_COLOURCHANGE;
1652 switch (m_Camera.draw_mode) {
1656 globalstate |= RENDER_FILL
1662 globalstate |= RENDER_FILL
1669 globalstate |= RENDER_FILL
1683 if (!g_xywindow_globals.m_bNoStipple) {
1684 globalstate |= RENDER_LINESTIPPLE | RENDER_POLYGONSTIPPLE;
1688 CamRenderer renderer(globalstate, m_state_select2, m_state_select1, m_view.getViewer());
1690 Scene_Render(renderer, m_view);
1692 renderer.render(m_Camera.modelview, m_Camera.projection);
1695 // prepare for 2d stuff
1696 glColor4f(1, 1, 1, 1);
1697 glDisable(GL_BLEND);
1698 glMatrixMode(GL_PROJECTION);
1700 glOrtho(0, (float) m_Camera.width, 0, (float) m_Camera.height, -100, 100);
1702 glTranslatef(0, -(float) m_Camera.height, 0);
1703 glMatrixMode(GL_MODELVIEW);
1706 if (GlobalOpenGL().GL_1_3()) {
1707 glClientActiveTexture(GL_TEXTURE0);
1708 glActiveTexture(GL_TEXTURE0);
1711 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1712 glDisableClientState(GL_NORMAL_ARRAY);
1713 glDisableClientState(GL_COLOR_ARRAY);
1715 glDisable(GL_TEXTURE_2D);
1716 glDisable(GL_LIGHTING);
1717 glDisable(GL_COLOR_MATERIAL);
1718 glDisable(GL_DEPTH_TEST);
1719 glColor3f(1.f, 1.f, 1.f);
1722 // draw the crosshair
1725 glVertex2f((float) m_Camera.width / 2.f, (float) m_Camera.height / 2.f + 6);
1726 glVertex2f((float) m_Camera.width / 2.f, (float) m_Camera.height / 2.f + 2);
1727 glVertex2f((float) m_Camera.width / 2.f, (float) m_Camera.height / 2.f - 6);
1728 glVertex2f((float) m_Camera.width / 2.f, (float) m_Camera.height / 2.f - 2);
1729 glVertex2f((float) m_Camera.width / 2.f + 6, (float) m_Camera.height / 2.f);
1730 glVertex2f((float) m_Camera.width / 2.f + 2, (float) m_Camera.height / 2.f);
1731 glVertex2f((float) m_Camera.width / 2.f - 6, (float) m_Camera.height / 2.f);
1732 glVertex2f((float) m_Camera.width / 2.f - 2, (float) m_Camera.height / 2.f);
1736 if (g_camwindow_globals_private.m_showStats) {
1737 glRasterPos3f(1.0f, static_cast<float>( m_Camera.height ) - GlobalOpenGL().m_font->getPixelDescent(), 0.0f);
1738 extern const char *Renderer_GetStats();
1739 GlobalOpenGL().drawString(Renderer_GetStats());
1741 glRasterPos3f(1.0f, static_cast<float>( m_Camera.height ) - GlobalOpenGL().m_font->getPixelDescent() -
1742 GlobalOpenGL().m_font->getPixelHeight(), 0.0f);
1743 extern const char *Cull_GetStats();
1744 GlobalOpenGL().drawString(Cull_GetStats());
1747 // bind back to the default texture so that we don't have problems
1748 // elsewhere using/modifying texture maps between contexts
1749 glBindTexture(GL_TEXTURE_2D, 0);
1756 //globalOutputStream() << "draw...\n";
1757 if (glwidget_make_current(m_gl_widget) != FALSE) {
1758 if (Map_Valid(g_map) && ScreenUpdates_Enabled()) {
1759 GlobalOpenGL_debugAssertNoErrors();
1761 GlobalOpenGL_debugAssertNoErrors();
1764 m_XORRectangle.set(rectangle_t());
1767 glwidget_swap_buffers(m_gl_widget);
1773 void CamWnd::BenchMark()
1775 double dStart = Sys_DoubleTime();
1776 for (int i = 0; i < 100; i++) {
1778 angles[CAMERA_ROLL] = 0;
1779 angles[CAMERA_PITCH] = 0;
1780 angles[CAMERA_YAW] = static_cast<float>( i * (360.0 / 100.0));
1781 Camera_setAngles(*this, angles);
1783 double dEnd = Sys_DoubleTime();
1784 globalOutputStream() << FloatFormat(dEnd - dStart, 5, 2) << " seconds\n";
1788 void fill_view_camera_menu(ui::Menu menu)
1790 create_check_menu_item_with_mnemonic(menu, "Camera View", "ToggleCamera");
1793 void GlobalCamera_ResetAngles()
1795 CamWnd &camwnd = *g_camwnd;
1797 angles[CAMERA_ROLL] = angles[CAMERA_PITCH] = 0;
1798 angles[CAMERA_YAW] = static_cast<float>( 22.5 * floor((Camera_getAngles(camwnd)[CAMERA_YAW] + 11) / 22.5));
1799 Camera_setAngles(camwnd, angles);
1802 void Camera_ChangeFloorUp()
1804 CamWnd &camwnd = *g_camwnd;
1805 camwnd.Cam_ChangeFloor(true);
1808 void Camera_ChangeFloorDown()
1810 CamWnd &camwnd = *g_camwnd;
1811 camwnd.Cam_ChangeFloor(false);
1814 void Camera_CubeIn()
1816 CamWnd &camwnd = *g_camwnd;
1817 g_camwindow_globals.m_nCubicScale--;
1818 if (g_camwindow_globals.m_nCubicScale < 1) {
1819 g_camwindow_globals.m_nCubicScale = 1;
1821 Camera_updateProjection(camwnd.getCamera());
1822 CamWnd_Update(camwnd);
1823 g_pParentWnd->SetGridStatus();
1826 void Camera_CubeOut()
1828 CamWnd &camwnd = *g_camwnd;
1829 g_camwindow_globals.m_nCubicScale++;
1830 if (g_camwindow_globals.m_nCubicScale > 23) {
1831 g_camwindow_globals.m_nCubicScale = 23;
1833 Camera_updateProjection(camwnd.getCamera());
1834 CamWnd_Update(camwnd);
1835 g_pParentWnd->SetGridStatus();
1838 bool Camera_GetFarClip()
1840 return g_camwindow_globals_private.m_bCubicClipping;
1843 ConstReferenceCaller<bool, void(const Callback<void(bool)> &), PropertyImpl<bool>::Export> g_getfarclip_caller(
1844 g_camwindow_globals_private.m_bCubicClipping);
1845 ToggleItem g_getfarclip_item(g_getfarclip_caller);
1847 void Camera_SetFarClip(bool value)
1849 CamWnd &camwnd = *g_camwnd;
1850 g_camwindow_globals_private.m_bCubicClipping = value;
1851 g_getfarclip_item.update();
1852 Camera_updateProjection(camwnd.getCamera());
1853 CamWnd_Update(camwnd);
1856 struct Camera_FarClip {
1857 static void Export(const Callback<void(bool)> &returnz)
1859 returnz(g_camwindow_globals_private.m_bCubicClipping);
1862 static void Import(bool value)
1864 Camera_SetFarClip(value);
1868 void Camera_ToggleFarClip()
1870 Camera_SetFarClip(!Camera_GetFarClip());
1874 void CamWnd_constructToolbar(ui::Toolbar toolbar)
1876 toolbar_append_toggle_button(toolbar, "Cubic clip the camera view (\\)", "view_cubicclipping.png",
1880 void CamWnd_registerShortcuts()
1882 toggle_add_accelerator("ToggleCubicClip");
1884 if (g_pGameDescription->mGameType == "doom3") {
1885 command_connect_accelerator("TogglePreview");
1888 command_connect_accelerator("CameraSpeedInc");
1889 command_connect_accelerator("CameraSpeedDec");
1893 void GlobalCamera_Benchmark()
1895 CamWnd &camwnd = *g_camwnd;
1899 void GlobalCamera_Update()
1901 CamWnd &camwnd = *g_camwnd;
1902 CamWnd_Update(camwnd);
1905 camera_draw_mode CamWnd_GetMode()
1907 return camera_t::draw_mode;
1910 void CamWnd_SetMode(camera_draw_mode mode)
1912 ShaderCache_setBumpEnabled(mode == cd_lighting);
1913 camera_t::draw_mode = mode;
1914 if (g_camwnd != 0) {
1915 CamWnd_Update(*g_camwnd);
1919 void CamWnd_TogglePreview(void)
1921 // gametype must be doom3 for this function to work
1922 // if the gametype is not doom3 something is wrong with the
1923 // global command list or somebody else calls this function.
1924 ASSERT_MESSAGE(g_pGameDescription->mGameType == "doom3",
1925 "CamWnd_TogglePreview called although mGameType is not doom3 compatible");
1927 // switch between textured and lighting mode
1928 CamWnd_SetMode((CamWnd_GetMode() == cd_lighting) ? cd_texture : cd_lighting);
1932 CameraModel *g_camera_model = 0;
1934 void CamWnd_LookThroughCamera(CamWnd &camwnd)
1936 if (g_camera_model != 0) {
1937 CamWnd_Add_Handlers_Move(camwnd);
1938 g_camera_model->setCameraView(0, Callback<void()>());
1940 Camera_updateModelview(camwnd.getCamera());
1941 Camera_updateProjection(camwnd.getCamera());
1942 CamWnd_Update(camwnd);
1946 inline CameraModel *Instance_getCameraModel(scene::Instance &instance)
1948 return InstanceTypeCast<CameraModel>::cast(instance);
1951 void CamWnd_LookThroughSelected(CamWnd &camwnd)
1953 if (g_camera_model != 0) {
1954 CamWnd_LookThroughCamera(camwnd);
1957 if (GlobalSelectionSystem().countSelected() != 0) {
1958 scene::Instance &instance = GlobalSelectionSystem().ultimateSelected();
1959 CameraModel *cameraModel = Instance_getCameraModel(instance);
1960 if (cameraModel != 0) {
1961 CamWnd_Remove_Handlers_Move(camwnd);
1962 g_camera_model = cameraModel;
1963 g_camera_model->setCameraView(&camwnd.getCameraView(),
1964 ReferenceCaller<CamWnd, void(), CamWnd_LookThroughCamera>(camwnd));
1969 void GlobalCamera_LookThroughSelected()
1971 CamWnd_LookThroughSelected(*g_camwnd);
1974 void GlobalCamera_LookThroughCamera()
1976 CamWnd_LookThroughCamera(*g_camwnd);
1980 static void Export(const Callback<void(int)> &returnz)
1982 switch (CamWnd_GetMode()) {
1998 static void Import(int value)
2002 CamWnd_SetMode(cd_wire);
2005 CamWnd_SetMode(cd_solid);
2008 CamWnd_SetMode(cd_texture);
2011 CamWnd_SetMode(cd_lighting);
2014 CamWnd_SetMode(cd_texture);
2019 void Camera_constructPreferences(PreferencesPage &page)
2021 page.appendSlider("Movement Speed", g_camwindow_globals_private.m_nMoveSpeed, TRUE, 0, 0, 100, MIN_CAM_SPEED,
2022 MAX_CAM_SPEED, 1, 10);
2023 page.appendCheckBox("", "Link strafe speed to movement speed", g_camwindow_globals_private.m_bCamLinkSpeed);
2024 page.appendSlider("Rotation Speed", g_camwindow_globals_private.m_nAngleSpeed, TRUE, 0, 0, 3, 1, 180, 1, 10);
2025 page.appendCheckBox("", "Invert mouse vertical axis", g_camwindow_globals_private.m_bCamInverseMouse);
2026 page.appendCheckBox(
2027 "", "Discrete movement",
2028 make_property<CamWnd_Move_Discrete>()
2030 page.appendCheckBox(
2031 "", "Enable far-clip plane",
2032 make_property<Camera_FarClip>()
2035 if (g_pGameDescription->mGameType == "doom3") {
2036 const char *render_mode[] = {"Wireframe", "Flatshade", "Textured", "Lighting"};
2040 STRING_ARRAY_RANGE(render_mode),
2041 make_property<RenderMode>()
2044 const char *render_mode[] = {"Wireframe", "Flatshade", "Textured"};
2048 STRING_ARRAY_RANGE(render_mode),
2049 make_property<RenderMode>()
2053 const char *strafe_mode[] = {"Both", "Forward", "Up"};
2057 g_camwindow_globals_private.m_nStrafeMode,
2058 STRING_ARRAY_RANGE(strafe_mode)
2062 void Camera_constructPage(PreferenceGroup &group)
2064 PreferencesPage page(group.createPage("Camera", "Camera View Preferences"));
2065 Camera_constructPreferences(page);
2068 void Camera_registerPreferencesPage()
2070 PreferencesDialog_addSettingsPage(makeCallbackF(Camera_constructPage));
2073 #include "preferencesystem.h"
2074 #include "stringio.h"
2077 void CameraSpeed_increase()
2079 if (g_camwindow_globals_private.m_nMoveSpeed <= (MAX_CAM_SPEED - CAM_SPEED_STEP - 10)) {
2080 g_camwindow_globals_private.m_nMoveSpeed += CAM_SPEED_STEP;
2082 g_camwindow_globals_private.m_nMoveSpeed = MAX_CAM_SPEED - 10;
2086 void CameraSpeed_decrease()
2088 if (g_camwindow_globals_private.m_nMoveSpeed >= (MIN_CAM_SPEED + CAM_SPEED_STEP)) {
2089 g_camwindow_globals_private.m_nMoveSpeed -= CAM_SPEED_STEP;
2091 g_camwindow_globals_private.m_nMoveSpeed = MIN_CAM_SPEED;
2095 /// \brief Initialisation for things that have the same lifespan as this module.
2096 void CamWnd_Construct()
2098 GlobalCommands_insert("CenterView", makeCallbackF(GlobalCamera_ResetAngles), Accelerator(GDK_KEY_End));
2100 GlobalToggles_insert("ToggleCubicClip", makeCallbackF(Camera_ToggleFarClip),
2101 ToggleItem::AddCallbackCaller(g_getfarclip_item),
2102 Accelerator('\\', (GdkModifierType) GDK_CONTROL_MASK));
2103 GlobalCommands_insert("CubicClipZoomIn", makeCallbackF(Camera_CubeIn),
2104 Accelerator('[', (GdkModifierType) GDK_CONTROL_MASK));
2105 GlobalCommands_insert("CubicClipZoomOut", makeCallbackF(Camera_CubeOut),
2106 Accelerator(']', (GdkModifierType) GDK_CONTROL_MASK));
2108 GlobalCommands_insert("UpFloor", makeCallbackF(Camera_ChangeFloorUp), Accelerator(GDK_KEY_Prior));
2109 GlobalCommands_insert("DownFloor", makeCallbackF(Camera_ChangeFloorDown), Accelerator(GDK_KEY_Next));
2111 GlobalToggles_insert("ToggleCamera", ToggleShown::ToggleCaller(g_camera_shown),
2112 ToggleItem::AddCallbackCaller(g_camera_shown.m_item),
2113 Accelerator('C', (GdkModifierType) (GDK_SHIFT_MASK | GDK_CONTROL_MASK)));
2114 GlobalCommands_insert("LookThroughSelected", makeCallbackF(GlobalCamera_LookThroughSelected));
2115 GlobalCommands_insert("LookThroughCamera", makeCallbackF(GlobalCamera_LookThroughCamera));
2117 if (g_pGameDescription->mGameType == "doom3") {
2118 GlobalCommands_insert("TogglePreview", makeCallbackF(CamWnd_TogglePreview), Accelerator(GDK_KEY_F3));
2121 GlobalCommands_insert("CameraSpeedInc", makeCallbackF(CameraSpeed_increase),
2122 Accelerator(GDK_KEY_KP_Add, (GdkModifierType) GDK_SHIFT_MASK));
2123 GlobalCommands_insert("CameraSpeedDec", makeCallbackF(CameraSpeed_decrease),
2124 Accelerator(GDK_KEY_KP_Subtract, (GdkModifierType) GDK_SHIFT_MASK));
2126 GlobalShortcuts_insert("CameraForward", Accelerator(GDK_KEY_Up));
2127 GlobalShortcuts_insert("CameraBack", Accelerator(GDK_KEY_Down));
2128 GlobalShortcuts_insert("CameraLeft", Accelerator(GDK_KEY_Left));
2129 GlobalShortcuts_insert("CameraRight", Accelerator(GDK_KEY_Right));
2130 GlobalShortcuts_insert("CameraStrafeRight", Accelerator(GDK_KEY_period));
2131 GlobalShortcuts_insert("CameraStrafeLeft", Accelerator(GDK_KEY_comma));
2133 GlobalShortcuts_insert("CameraUp", Accelerator('D'));
2134 GlobalShortcuts_insert("CameraDown", Accelerator('C'));
2135 GlobalShortcuts_insert("CameraAngleUp", Accelerator('A'));
2136 GlobalShortcuts_insert("CameraAngleDown", Accelerator('Z'));
2138 GlobalShortcuts_insert("CameraFreeMoveForward", Accelerator(GDK_KEY_Up));
2139 GlobalShortcuts_insert("CameraFreeMoveBack", Accelerator(GDK_KEY_Down));
2140 GlobalShortcuts_insert("CameraFreeMoveLeft", Accelerator(GDK_KEY_Left));
2141 GlobalShortcuts_insert("CameraFreeMoveRight", Accelerator(GDK_KEY_Right));
2143 GlobalToggles_insert("ShowStats", makeCallbackF(ShowStatsToggle), ToggleItem::AddCallbackCaller(g_show_stats));
2145 GlobalPreferenceSystem().registerPreference("ShowStats",
2146 make_property_string(g_camwindow_globals_private.m_showStats));
2147 GlobalPreferenceSystem().registerPreference("MoveSpeed",
2148 make_property_string(g_camwindow_globals_private.m_nMoveSpeed));
2149 GlobalPreferenceSystem().registerPreference("CamLinkSpeed",
2150 make_property_string(g_camwindow_globals_private.m_bCamLinkSpeed));
2151 GlobalPreferenceSystem().registerPreference("AngleSpeed",
2152 make_property_string(g_camwindow_globals_private.m_nAngleSpeed));
2153 GlobalPreferenceSystem().registerPreference("CamInverseMouse",
2154 make_property_string(g_camwindow_globals_private.m_bCamInverseMouse));
2155 GlobalPreferenceSystem().registerPreference("CamDiscrete", make_property_string<CamWnd_Move_Discrete>());
2156 GlobalPreferenceSystem().registerPreference("CubicClipping",
2157 make_property_string(g_camwindow_globals_private.m_bCubicClipping));
2158 GlobalPreferenceSystem().registerPreference("CubicScale", make_property_string(g_camwindow_globals.m_nCubicScale));
2159 GlobalPreferenceSystem().registerPreference("SI_Colors4",
2160 make_property_string(g_camwindow_globals.color_cameraback));
2161 GlobalPreferenceSystem().registerPreference("SI_Colors12",
2162 make_property_string(g_camwindow_globals.color_selbrushes3d));
2163 GlobalPreferenceSystem().registerPreference("CameraRenderMode", make_property_string<RenderMode>());
2164 GlobalPreferenceSystem().registerPreference("StrafeMode",
2165 make_property_string(g_camwindow_globals_private.m_nStrafeMode));
2167 CamWnd_constructStatic();
2169 Camera_registerPreferencesPage();
2172 void CamWnd_Destroy()
2174 CamWnd_destroyStatic();