1 #include "CamWnd.h"
2 
3 #include "iscenegraph.h"
4 #include "ieventmanager.h"
5 #include "iclipper.h"
6 
7 #include <gdk/gdkkeysyms.h>
8 
9 #include "gtkutil/glwidget.h"
10 #include "gtkutil/widget.h"
11 #include "gtkutil/GLWidgetSentry.h"
12 
13 #include "../windowobservers.h"
14 #include "../plugin.h"
15 #include "../ui/mainframe/mainframe.h"
16 #include "../renderer.h"
17 #include "../render/RenderStatistics.h"
18 
19 #include "CamRenderer.h"
20 #include "CameraSettings.h"
21 #include "GlobalCamera.h"
22 
23 class ObjectFinder: public scene::Graph::Walker
24 {
25 		scene::Instance*& _instance;
26 		SelectionTest& _selectionTest;
27 
28 		// To store the best intersection candidate
29 		mutable SelectionIntersection _bestIntersection;
30 	public:
31 		// Constructor
ObjectFinder(SelectionTest & test,scene::Instance * & instance)32 		ObjectFinder (SelectionTest& test, scene::Instance*& instance) :
33 			_instance(instance), _selectionTest(test)
34 		{
35 			_instance = NULL;
36 		}
37 
38 		// The visitor function
pre(const scene::Path & path,scene::Instance & instance) const39 		bool pre (const scene::Path& path, scene::Instance& instance) const
40 		{
41 			// Check if the node is filtered
42 			if (path.top().get().visible()) {
43 				SelectionTestable* selectionTestable = Instance_getSelectionTestable(instance);
44 
45 				if (selectionTestable != NULL) {
46 					bool occluded;
47 					OccludeSelector selector(_bestIntersection, occluded);
48 					selectionTestable->testSelect(selector, _selectionTest);
49 
50 					if (occluded) {
51 						_instance = &instance;
52 					}
53 				}
54 			}
55 
56 			return true;
57 		}
58 };
59 
60 
windowvector_for_widget_centre(GtkWidget * widget)61 inline WindowVector windowvector_for_widget_centre(GtkWidget* widget) {
62 	return WindowVector(static_cast<float>(widget->allocation.width / 2), static_cast<float>(widget->allocation.height / 2));
63 }
64 
65 class FloorHeightWalker : public scene::Graph::Walker
66 {
67 	float m_current;
68 	float& m_bestUp;
69 	float& m_bestDown;
70 
71 public:
FloorHeightWalker(float current,float & bestUp,float & bestDown)72 	FloorHeightWalker(float current, float& bestUp, float& bestDown) :
73 			m_current(current), m_bestUp(bestUp), m_bestDown(bestDown) {
74 		bestUp = GlobalRegistry().getFloat("game/defaults/maxWorldCoord");
75 		bestDown = -GlobalRegistry().getFloat("game/defaults/maxWorldCoord");
76 	}
77 
pre(const scene::Path & path,scene::Instance & instance) const78 	bool pre(const scene::Path& path, scene::Instance& instance) const {
79 		if (path.top().get().visible() && Node_isBrush(path.top())) // this node is a floor
80 		{
81 
82 			const AABB& aabb = instance.worldAABB();
83 
84 			float floorHeight = aabb.origin.z() + aabb.extents.z();
85 
86 			if (floorHeight > m_current && floorHeight < m_bestUp) {
87 				m_bestUp = floorHeight;
88 			}
89 
90 			if (floorHeight < m_current && floorHeight > m_bestDown) {
91 				m_bestDown = floorHeight;
92 			}
93 		}
94 
95 		return true;
96 	}
97 };
98 
99 // --------------- Callbacks ---------------------------------------------------------
100 
selection_motion(gdouble x,gdouble y,guint state,void * data)101 static void selection_motion(gdouble x, gdouble y, guint state, void* data) {
102 	//globalOutputStream() << "motion... ";
103 	reinterpret_cast<WindowObserver*>(data)->onMouseMotion(WindowVector(x, y), state);
104 }
105 
106 namespace {
107 
camwnd_update_xor_rectangle(CamWnd & self,SelectionRectangle area)108 void camwnd_update_xor_rectangle(CamWnd& self, SelectionRectangle area) {
109 	if (GTK_WIDGET_VISIBLE(self.m_gl_widget)) {
110 		self.m_XORRectangle.set(rectangle_from_area(area.min, area.max, self.getCamera().width, self.getCamera().height));
111 	}
112 }
113 
114 }
115 
camera_size_allocate(GtkWidget * widget,GtkAllocation * allocation,CamWnd * camwnd)116 gboolean CamWnd::camera_size_allocate(GtkWidget* widget, GtkAllocation* allocation, CamWnd* camwnd) {
117 	camwnd->getCamera().width = allocation->width;
118 	camwnd->getCamera().height = allocation->height;
119 	camwnd->getCamera().updateProjection();
120 	camwnd->m_window_observer->onSizeChanged(camwnd->getCamera().width, camwnd->getCamera().height);
121 	camwnd->queueDraw();
122 	return FALSE;
123 }
124 
camera_expose(GtkWidget * widget,GdkEventExpose * event,gpointer data)125 gboolean CamWnd::camera_expose(GtkWidget* widget, GdkEventExpose* event, gpointer data) {
126 	reinterpret_cast<CamWnd*>(data)->draw();
127 	return FALSE;
128 }
129 
Camera_motionDelta(int x,int y,unsigned int state,void * data)130 static void Camera_motionDelta(int x, int y, unsigned int state, void* data) {
131 	Camera* cam = reinterpret_cast<Camera*>(data);
132 
133 	cam->m_mouseMove.motion_delta(x, y, state);
134 	cam->m_strafe = GlobalEventManager().MouseEvents().strafeActive(state);
135 
136 	if (cam->m_strafe) {
137 		cam->m_strafe_forward = GlobalEventManager().MouseEvents().strafeForwardActive(state);
138 	} else {
139 		cam->m_strafe_forward = false;
140 	}
141 }
142 
143 // greebo: The GTK Callback during freemove mode for mouseDown. Passes the call on to the Windowobserver
selection_button_press_freemove(GtkWidget * widget,GdkEventButton * event,WindowObserver * observer)144 gboolean CamWnd::selection_button_press_freemove(GtkWidget* widget, GdkEventButton* event, WindowObserver* observer) {
145 	// Check for the correct event type
146 	if (event->type == GDK_BUTTON_PRESS) {
147 		observer->onMouseDown(windowvector_for_widget_centre(widget), event);
148 	}
149 	return FALSE;
150 }
151 
152 // greebo: The GTK Callback during freemove mode for mouseUp. Passes the call on to the Windowobserver
selection_button_release_freemove(GtkWidget * widget,GdkEventButton * event,WindowObserver * observer)153 gboolean CamWnd::selection_button_release_freemove(GtkWidget* widget, GdkEventButton* event, WindowObserver* observer) {
154 	if (event->type == GDK_BUTTON_RELEASE) {
155 		observer->onMouseUp(windowvector_for_widget_centre(widget), event);
156 	}
157 	return FALSE;
158 }
159 
160 // greebo: The GTK Callback during freemove mode for mouseMoved. Passes the call on to the Windowobserver
selection_motion_freemove(GtkWidget * widget,GdkEventMotion * event,WindowObserver * observer)161 gboolean CamWnd::selection_motion_freemove(GtkWidget *widget, GdkEventMotion *event, WindowObserver* observer) {
162 	observer->onMouseMotion(windowvector_for_widget_centre(widget), event->state);
163 	return FALSE;
164 }
165 
166 // greebo: The GTK Callback during freemove mode for scroll events.
wheelmove_scroll(GtkWidget * widget,GdkEventScroll * event,CamWnd * camwnd)167 gboolean CamWnd::wheelmove_scroll(GtkWidget* widget, GdkEventScroll* event, CamWnd* camwnd) {
168 
169 	// Set the GTK focus to this widget
170 	gtk_widget_grab_focus(widget);
171 
172 	// Determine the direction we are moving.
173 	if (event->direction == GDK_SCROLL_UP) {
174 		camwnd->getCamera().freemoveUpdateAxes();
175 		camwnd->setCameraOrigin(camwnd->getCameraOrigin() + camwnd->getCamera().forward * static_cast<float>(getCameraSettings()->movementSpeed()));
176 	}
177 	else if (event->direction == GDK_SCROLL_DOWN) {
178 		camwnd->getCamera().freemoveUpdateAxes();
179 		camwnd->setCameraOrigin(camwnd->getCameraOrigin() + camwnd->getCamera().forward * (-static_cast<float>(getCameraSettings()->movementSpeed())));
180 	}
181 
182 	return FALSE;
183 }
184 
185 /* greebo: GTK Callback: This gets called on "button_press_event" and basically just passes the call on
186  * to the according window observer. */
selection_button_press(GtkWidget * widget,GdkEventButton * event,WindowObserver * observer)187 gboolean CamWnd::selection_button_press(GtkWidget* widget, GdkEventButton* event, WindowObserver* observer) {
188 
189 	// Set the GTK focus to this widget
190 	gtk_widget_grab_focus(widget);
191 
192 	// Check for the correct event type
193 	if (event->type == GDK_BUTTON_PRESS) {
194 		observer->onMouseDown(WindowVector(event->x, event->y), event);
195 	}
196 	return FALSE;
197 }
198 
199 /* greebo: GTK Callback: This gets called on "button_release_event" and basically just passes the call on
200  * to the according window observer. */
selection_button_release(GtkWidget * widget,GdkEventButton * event,WindowObserver * observer)201 gboolean CamWnd::selection_button_release(GtkWidget* widget, GdkEventButton* event, WindowObserver* observer) {
202 	if (event->type == GDK_BUTTON_RELEASE) {
203 		observer->onMouseUp(WindowVector(event->x, event->y), event);
204 	}
205 	return FALSE;
206 }
207 
enable_freelook_button_press(GtkWidget * widget,GdkEventButton * event,CamWnd * camwnd)208 gboolean CamWnd::enable_freelook_button_press(GtkWidget* widget, GdkEventButton* event, CamWnd* camwnd) {
209 	if (event->type == GDK_BUTTON_PRESS) {
210 
211 		if (GlobalEventManager().MouseEvents().stateMatchesCameraViewEvent(ui::camEnableFreeLookMode, event)) {
212 			camwnd->enableFreeMove();
213 			return TRUE;
214 		}
215 	}
216 	return FALSE;
217 }
218 
disable_freelook_button_press(GtkWidget * widget,GdkEventButton * event,CamWnd * camwnd)219 gboolean CamWnd::disable_freelook_button_press(GtkWidget* widget, GdkEventButton* event, CamWnd* camwnd) {
220 	if (event->type == GDK_BUTTON_PRESS) {
221 		if (GlobalEventManager().MouseEvents().stateMatchesCameraViewEvent(ui::camDisableFreeLookMode, event)) {
222 			camwnd->disableFreeMove();
223 			return TRUE;
224 		}
225 	}
226 	return FALSE;
227 }
228 
229 // ---------- CamWnd Implementation --------------------------------------------------
230 
CamWnd()231 CamWnd::CamWnd() :
232 		m_view(true),
233 		m_Camera(&m_view, CamWndQueueDraw(*this)),
234 		m_cameraview(m_Camera, &m_view, CamWndUpdate(*this)),
235 		m_drawing(false),
236 		_glWidget(true), m_gl_widget(static_cast<GtkWidget*>(_glWidget)),
237 		m_window_observer(NewWindowObserver()),
238 		m_XORRectangle(m_gl_widget),
239 		m_deferredDraw(WidgetQueueDrawCaller(*m_gl_widget)),
240 		m_deferred_motion(selection_motion, m_window_observer),
241 		m_selection_button_press_handler(0),
242 		m_selection_button_release_handler(0),
243 		m_selection_motion_handler(0),
244 		m_freelook_button_press_handler(0) {
245 	m_bFreeMove = false;
246 
247 	GlobalWindowObservers_add(m_window_observer);
248 	GlobalWindowObservers_connectWidget(m_gl_widget);
249 
250 	m_window_observer->setRectangleDrawCallback(ReferenceCaller1<CamWnd, SelectionRectangle, camwnd_update_xor_rectangle>(*this));
251 	m_window_observer->setView(m_view);
252 
253 	gtk_widget_ref(m_gl_widget);
254 
255 	gtk_widget_set_events(m_gl_widget, GDK_DESTROY | GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK);
256 	GTK_WIDGET_SET_FLAGS (m_gl_widget, GTK_CAN_FOCUS);
257 	gtk_widget_set_size_request(m_gl_widget, CAMWND_MINSIZE_X, CAMWND_MINSIZE_Y);
258 	g_object_set(m_gl_widget, "can-focus", TRUE, NULL);
259 
260 	m_sizeHandler = g_signal_connect(G_OBJECT(m_gl_widget), "size_allocate", G_CALLBACK(camera_size_allocate), this);
261 	m_exposeHandler = g_signal_connect(G_OBJECT(m_gl_widget), "expose_event", G_CALLBACK(camera_expose), this);
262 
263 	GlobalMap().addValidCallback(DeferredDrawOnMapValidChangedCaller(m_deferredDraw));
264 
265 	// Deactivate all commands, just to make sure
266 	disableDiscreteMoveEvents();
267 	disableFreeMoveEvents();
268 
269 	// Now add the handlers for the non-freelook mode, the events are activated by this
270 	addHandlersMove();
271 
272 	g_signal_connect(G_OBJECT(m_gl_widget), "scroll_event", G_CALLBACK(wheelmove_scroll), this);
273 
274 	GlobalSceneGraph().addSceneObserver(this);
275 
276 	GlobalEventManager().connect(GTK_OBJECT(m_gl_widget));
277 }
278 
onSceneGraphChange()279 void CamWnd::onSceneGraphChange ()
280 {
281 	update();
282 }
283 
jumpToObject(SelectionTest & selectionTest)284 void CamWnd::jumpToObject(SelectionTest& selectionTest) {
285 	// Find a suitable target Instance
286 	scene::Instance* instance;
287 	GlobalSceneGraph().traverse(ObjectFinder(selectionTest, instance));
288 
289 	if (instance != NULL) {
290 		// An instance has been found, get the bounding box
291 		AABB found = instance->worldAABB();
292 
293 		// Focuse the view at the center of the found AABB
294 		GlobalMap().FocusViews(found.origin, getCameraAngles()[CAMERA_YAW]);
295 	}
296 }
297 
changeFloor(bool up)298 void CamWnd::changeFloor(bool up) {
299 	float current = m_Camera.getOrigin()[2] - 48;
300 	float bestUp;
301 	float bestDown;
302 	GlobalSceneGraph().traverse(FloorHeightWalker(current, bestUp, bestDown));
303 
304 	if (up && bestUp != GlobalRegistry().getFloat("game/defaults/maxWorldCoord")) {
305 		current = bestUp;
306 	}
307 
308 	if (!up && bestDown != -GlobalRegistry().getFloat("game/defaults/maxWorldCoord")) {
309 		current = bestDown;
310 	}
311 
312 	const Vector3& org = m_Camera.getOrigin();
313 	m_Camera.setOrigin(Vector3(org[0], org[1], current + 48));
314 
315 	m_Camera.updateModelview();
316 	update();
317 	GlobalCamera().movedNotify();
318 }
319 
320 // NOTE TTimo if there's an OS-level focus out of the application
321 //   then we can release the camera cursor grab
camwindow_freemove_focusout(GtkWidget * widget,GdkEventFocus * event,gpointer data)322 static gboolean camwindow_freemove_focusout(GtkWidget* widget, GdkEventFocus* event, gpointer data) {
323 	reinterpret_cast<CamWnd*>(data)->disableFreeMove();
324 	return FALSE;
325 }
326 
enableFreeMove()327 void CamWnd::enableFreeMove() {
328 	ASSERT_MESSAGE(!m_bFreeMove, "EnableFreeMove: free-move was already enabled");
329 	m_bFreeMove = true;
330 	m_Camera.clearMovementFlags(MOVE_ALL);
331 
332 	removeHandlersMove();
333 
334 	m_selection_button_press_handler = g_signal_connect(G_OBJECT(m_gl_widget), "button_press_event", G_CALLBACK(selection_button_press_freemove), m_window_observer);
335 	m_selection_button_release_handler = g_signal_connect(G_OBJECT(m_gl_widget), "button_release_event", G_CALLBACK(selection_button_release_freemove), m_window_observer);
336 	m_selection_motion_handler = g_signal_connect(G_OBJECT(m_gl_widget), "motion_notify_event", G_CALLBACK(selection_motion_freemove), m_window_observer);
337 	m_freelook_button_press_handler = g_signal_connect(G_OBJECT(m_gl_widget), "button_press_event", G_CALLBACK(disable_freelook_button_press), this);
338 
339 	enableFreeMoveEvents();
340 
341 	gtk_window_set_focus(m_parent, m_gl_widget);
342 	m_freemove_handle_focusout = g_signal_connect(G_OBJECT(m_gl_widget), "focus_out_event", G_CALLBACK(camwindow_freemove_focusout), this);
343 	m_freezePointer.freeze_pointer(m_parent, Camera_motionDelta, &m_Camera);
344 
345 	update();
346 }
347 
disableFreeMove()348 void CamWnd::disableFreeMove() {
349 	ASSERT_MESSAGE(m_bFreeMove, "DisableFreeMove: free-move was not enabled");
350 	m_bFreeMove = false;
351 	m_Camera.clearMovementFlags(MOVE_ALL);
352 
353 	disableFreeMoveEvents();
354 
355 	g_signal_handler_disconnect(G_OBJECT(m_gl_widget), m_selection_button_press_handler);
356 	g_signal_handler_disconnect(G_OBJECT(m_gl_widget), m_selection_button_release_handler);
357 	g_signal_handler_disconnect(G_OBJECT(m_gl_widget), m_selection_motion_handler);
358 	g_signal_handler_disconnect(G_OBJECT(m_gl_widget), m_freelook_button_press_handler);
359 
360 	addHandlersMove();
361 
362 	m_freezePointer.unfreeze_pointer(m_parent);
363 	g_signal_handler_disconnect(G_OBJECT(m_gl_widget), m_freemove_handle_focusout);
364 
365 	update();
366 }
367 
Cam_Draw()368 void CamWnd::Cam_Draw() {
369 	glViewport(0, 0, m_Camera.width, m_Camera.height);
370 
371 	// enable depth buffer writes
372 	glDepthMask(GL_TRUE);
373 
374 	Vector3 clearColour(0, 0, 0);
375 	clearColour = ColourSchemes().getColourVector3("camera_background");
376 
377 	glClearColor(clearColour[0], clearColour[1], clearColour[2], 0);
378 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
379 
380 	render::RenderStatistics::Instance().resetStats();
381 
382 	Cull_ResetStats();
383 
384 	glMatrixMode(GL_PROJECTION);
385 	glLoadMatrixf(m_Camera.projection);
386 
387 	glMatrixMode(GL_MODELVIEW);
388 	glLoadMatrixf(m_Camera.modelview);
389 
390 	// one directional light source directly behind the viewer
391 	{
392 		GLfloat inverse_cam_dir[4], ambient[4], diffuse[4];//, material[4];
393 
394 		ambient[0] = ambient[1] = ambient[2] = 0.4f;
395 		ambient[3] = 1.0f;
396 		diffuse[0] = diffuse[1] = diffuse[2] = 0.4f;
397 		diffuse[3] = 1.0f;
398 
399 		inverse_cam_dir[0] = m_Camera.vpn[0];
400 		inverse_cam_dir[1] = m_Camera.vpn[1];
401 		inverse_cam_dir[2] = m_Camera.vpn[2];
402 		inverse_cam_dir[3] = 0;
403 
404 		glLightfv(GL_LIGHT0, GL_POSITION, inverse_cam_dir);
405 
406 		glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
407 		glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
408 
409 		glEnable(GL_LIGHT0);
410 	}
411 
412 	unsigned int globalstate = RENDER_DEPTHTEST | RENDER_COLOURWRITE | RENDER_DEPTHWRITE | RENDER_ALPHATEST
413 			| RENDER_BLEND | RENDER_CULLFACE | RENDER_COLOURARRAY | RENDER_COLOURCHANGE;
414 	switch (getCameraSettings()->getMode()) {
415 	case drawWire:
416 		break;
417 	case drawSolid:
418 		globalstate |= (RENDER_FILL | RENDER_LIGHTING | RENDER_SMOOTH | RENDER_SCALED);
419 		break;
420 	case drawTexture:
421 		globalstate |= (RENDER_FILL | RENDER_LIGHTING | RENDER_TEXTURE_2D | RENDER_SMOOTH | RENDER_SCALED);
422 		break;
423 	default:
424 		globalstate = 0;
425 		break;
426 	}
427 
428 	if (!getCameraSettings()->solidSelectionBoxes()) {
429 		globalstate |= RENDER_LINESTIPPLE;
430 	}
431 
432 	{
433 		CamRenderer renderer(globalstate, m_state_select2, m_state_select1, m_view.getViewer());
434 
435 		Scene_Render(renderer, m_view);
436 
437 		renderer.render(m_Camera.modelview, m_Camera.projection);
438 	}
439 
440 	// greebo: Draw the clipper's points (skipping the depth-test)
441 	{
442 		glDisable(GL_DEPTH_TEST);
443 
444 		glColor4f(1, 1, 1, 1);
445 
446 		glPointSize(5);
447 
448 		if (GlobalClipper().clipMode()) {
449 			GlobalClipper().draw(1.0f);
450 		}
451 
452 		glPointSize(1);
453 	}
454 
455 	// prepare for 2d stuff
456 	glColor4f(1, 1, 1, 1);
457 	glDisable(GL_BLEND);
458 	glMatrixMode(GL_PROJECTION);
459 	glLoadIdentity();
460 	glOrtho(0, (float) m_Camera.width, 0, (float) m_Camera.height, -100, 100);
461 	glScalef(1, -1, 1);
462 	glTranslatef(0, -(float) m_Camera.height, 0);
463 	glMatrixMode(GL_MODELVIEW);
464 	glLoadIdentity();
465 
466 	if (GlobalOpenGL().GL_1_3()) {
467 		glClientActiveTexture(GL_TEXTURE0);
468 		glActiveTexture(GL_TEXTURE0);
469 	}
470 
471 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
472 	glDisableClientState(GL_NORMAL_ARRAY);
473 	glDisableClientState(GL_COLOR_ARRAY);
474 
475 	glDisable(GL_TEXTURE_2D);
476 	glDisable(GL_LIGHTING);
477 	glDisable(GL_COLOR_MATERIAL);
478 	glDisable(GL_DEPTH_TEST);
479 	glLineWidth(1);
480 
481 	// draw the crosshair
482 	if (m_bFreeMove) {
483 		glBegin(GL_LINES);
484 		glVertex2f((float) m_Camera.width / 2.f, (float) m_Camera.height / 2.f + 6);
485 		glVertex2f((float) m_Camera.width / 2.f, (float) m_Camera.height / 2.f + 2);
486 		glVertex2f((float) m_Camera.width / 2.f, (float) m_Camera.height / 2.f - 6);
487 		glVertex2f((float) m_Camera.width / 2.f, (float) m_Camera.height / 2.f - 2);
488 		glVertex2f((float) m_Camera.width / 2.f + 6, (float) m_Camera.height / 2.f);
489 		glVertex2f((float) m_Camera.width / 2.f + 2, (float) m_Camera.height / 2.f);
490 		glVertex2f((float) m_Camera.width / 2.f - 6, (float) m_Camera.height / 2.f);
491 		glVertex2f((float) m_Camera.width / 2.f - 2, (float) m_Camera.height / 2.f);
492 		glEnd();
493 	}
494 
495 	glRasterPos3f(1.0f, static_cast<float> (m_Camera.height) - 1.0f, 0.0f);
496 	GlobalOpenGL().drawString(render::RenderStatistics::Instance().getStatString());
497 
498 	glRasterPos3f(1.0f, static_cast<float> (m_Camera.height) - 11.0f, 0.0f);
499 	GlobalOpenGL().drawString(Cull_GetStats());
500 
501 	// bind back to the default texture so that we don't have problems
502 	// elsewhere using/modifying texture maps between contexts
503 	glBindTexture(GL_TEXTURE_2D, 0);
504 }
505 
draw()506 void CamWnd::draw() {
507 	m_drawing = true;
508 
509 	gtkutil::GLWidgetSentry sentry(m_gl_widget);
510 	if (GlobalMap().isValid() && ScreenUpdates_Enabled()) {
511 		Cam_Draw();
512 
513 		m_XORRectangle.set(rectangle_t());
514 	}
515 
516 	m_drawing = false;
517 }
518 
~CamWnd()519 CamWnd::~CamWnd() {
520 	// Subscribe to the global scene graph update
521 	GlobalSceneGraph().removeSceneObserver(this);
522 
523 	if (m_bFreeMove) {
524 		disableFreeMove();
525 	}
526 
527 	removeHandlersMove();
528 
529 	g_signal_handler_disconnect(G_OBJECT(m_gl_widget), m_sizeHandler);
530 	g_signal_handler_disconnect(G_OBJECT(m_gl_widget), m_exposeHandler);
531 
532 	gtk_widget_unref(m_gl_widget);
533 
534 	// Disconnect self from EventManager\r
535 	GlobalEventManager().disconnect(GTK_OBJECT(m_gl_widget));
536 	GlobalEventManager().disconnect(GTK_OBJECT(m_parent));
537 
538 	delete m_window_observer;
539 }
540 
541 // ----------------------------------------------------------
542 
enableFreeMoveEvents()543 void CamWnd::enableFreeMoveEvents() {
544 	GlobalEventManager().enableEvent("CameraFreeMoveForward");
545 	GlobalEventManager().enableEvent("CameraFreeMoveBack");
546 	GlobalEventManager().enableEvent("CameraFreeMoveLeft");
547 	GlobalEventManager().enableEvent("CameraFreeMoveRight");
548 	GlobalEventManager().enableEvent("CameraFreeMoveUp");
549 	GlobalEventManager().enableEvent("CameraFreeMoveDown");
550 }
551 
disableFreeMoveEvents()552 void CamWnd::disableFreeMoveEvents() {
553 	GlobalEventManager().disableEvent("CameraFreeMoveForward");
554 	GlobalEventManager().disableEvent("CameraFreeMoveBack");
555 	GlobalEventManager().disableEvent("CameraFreeMoveLeft");
556 	GlobalEventManager().disableEvent("CameraFreeMoveRight");
557 	GlobalEventManager().disableEvent("CameraFreeMoveUp");
558 	GlobalEventManager().disableEvent("CameraFreeMoveDown");
559 }
560 
enableDiscreteMoveEvents()561 void CamWnd::enableDiscreteMoveEvents() {
562 	GlobalEventManager().enableEvent("CameraForward");
563 	GlobalEventManager().enableEvent("CameraBack");
564 	GlobalEventManager().enableEvent("CameraLeft");
565 	GlobalEventManager().enableEvent("CameraRight");
566 	GlobalEventManager().enableEvent("CameraStrafeRight");
567 	GlobalEventManager().enableEvent("CameraStrafeLeft");
568 	GlobalEventManager().enableEvent("CameraUp");
569 	GlobalEventManager().enableEvent("CameraDown");
570 	GlobalEventManager().enableEvent("CameraAngleUp");
571 	GlobalEventManager().enableEvent("CameraAngleDown");
572 }
573 
disableDiscreteMoveEvents()574 void CamWnd::disableDiscreteMoveEvents() {
575 	GlobalEventManager().disableEvent("CameraForward");
576 	GlobalEventManager().disableEvent("CameraBack");
577 	GlobalEventManager().disableEvent("CameraLeft");
578 	GlobalEventManager().disableEvent("CameraRight");
579 	GlobalEventManager().disableEvent("CameraStrafeRight");
580 	GlobalEventManager().disableEvent("CameraStrafeLeft");
581 	GlobalEventManager().disableEvent("CameraUp");
582 	GlobalEventManager().disableEvent("CameraDown");
583 	GlobalEventManager().disableEvent("CameraAngleUp");
584 	GlobalEventManager().disableEvent("CameraAngleDown");
585 }
586 
addHandlersMove()587 void CamWnd::addHandlersMove() {
588 	m_selection_button_press_handler = g_signal_connect(G_OBJECT(m_gl_widget), "button_press_event", G_CALLBACK(selection_button_press), m_window_observer);
589 	m_selection_button_release_handler = g_signal_connect(G_OBJECT(m_gl_widget), "button_release_event", G_CALLBACK(selection_button_release), m_window_observer);
590 	m_selection_motion_handler = g_signal_connect(G_OBJECT(m_gl_widget), "motion_notify_event", G_CALLBACK(DeferredMotion::gtk_motion), &m_deferred_motion);
591 
592 	m_freelook_button_press_handler = g_signal_connect(G_OBJECT(m_gl_widget), "button_press_event", G_CALLBACK(enable_freelook_button_press), this);
593 
594 	// Enable either the free-look movement commands or the discrete ones, depending on the selection
595 	if (getCameraSettings()->discreteMovement()) {
596 		enableDiscreteMoveEvents();
597 	} else {
598 		enableFreeMoveEvents();
599 	}
600 }
601 
removeHandlersMove()602 void CamWnd::removeHandlersMove() {
603 	g_signal_handler_disconnect(G_OBJECT(m_gl_widget), m_selection_button_press_handler);
604 	g_signal_handler_disconnect(G_OBJECT(m_gl_widget), m_selection_button_release_handler);
605 	g_signal_handler_disconnect(G_OBJECT(m_gl_widget), m_selection_motion_handler);
606 
607 	g_signal_handler_disconnect(G_OBJECT(m_gl_widget), m_freelook_button_press_handler);
608 
609 	// Disable either the free-look movement commands or the discrete ones, depending on the selection
610 	if (getCameraSettings()->discreteMovement()) {
611 		disableDiscreteMoveEvents();
612 	} else {
613 		disableFreeMoveEvents();
614 	}
615 }
616 
update()617 void CamWnd::update() {
618 	queueDraw();
619 }
620 
getCamera()621 Camera& CamWnd::getCamera() {
622 	return m_Camera;
623 }
624 
captureStates()625 void CamWnd::captureStates() {
626 	m_state_select1 = GlobalShaderCache().capture("$CAM_HIGHLIGHT");
627 	m_state_select2 = GlobalShaderCache().capture("$CAM_OVERLAY");
628 }
629 
releaseStates()630 void CamWnd::releaseStates() {
631 	GlobalShaderCache().release("$CAM_HIGHLIGHT");
632 	GlobalShaderCache().release("$CAM_OVERLAY");
633 }
634 
queueDraw()635 void CamWnd::queueDraw() {
636 	if (m_drawing) {
637 		return;
638 	}
639 
640 	m_deferredDraw.draw();
641 }
642 
getCameraOrigin() const643 const Vector3& CamWnd::getCameraOrigin () const {
644 	return m_Camera.getOrigin();
645 }
646 
setCameraOrigin(const Vector3 & origin)647 void CamWnd::setCameraOrigin (const Vector3& origin) {
648 	m_Camera.setOrigin(origin);
649 }
650 
getCameraAngles() const651 const Vector3& CamWnd::getCameraAngles () const {
652 	return m_Camera.getAngles();
653 }
654 
setCameraAngles(const Vector3 & angles)655 void CamWnd::setCameraAngles (const Vector3& angles) {
656 	m_Camera.setAngles(angles);
657 }
658 
cubicScaleIn()659 void CamWnd::cubicScaleIn ()
660 {
661 	getCameraSettings()->setCubicScale( getCameraSettings()->cubicScale() - 1 );
662 	m_Camera.updateProjection();
663 	update();
664 }
665 
cubicScaleOut()666 void CamWnd::cubicScaleOut ()
667 {
668 	getCameraSettings()->setCubicScale( getCameraSettings()->cubicScale() + 1 );
669 	m_Camera.updateProjection();
670 	update();
671 }
672 
getCameraView()673 CameraView* CamWnd::getCameraView() {
674 	return &m_cameraview;
675 }
676 
getWidget()677 GtkWidget* CamWnd::getWidget()
678 {
679 	return m_gl_widget;
680 }
681 
setParent(GtkWindow * parent)682 void CamWnd::setParent(GtkWindow* parent) {
683 	m_parent = parent;
684 	GlobalEventManager().connect(GTK_OBJECT(m_parent));
685 }
686 
getParent()687 GtkWindow* CamWnd::getParent() {
688 	return m_parent;
689 }
690 
691 Shader* CamWnd::m_state_select1 = 0;
692 Shader* CamWnd::m_state_select2 = 0;
693