Bugfix: the game player did not initialize tiff and quicktime, so loading
[blender.git] / source / gameengine / GamePlayer / ghost / GPG_Application.cpp
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  * GHOST Blender Player application implementation file.
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34
35 #ifdef WIN32
36         #pragma warning (disable:4786) // suppress stl-MSVC debug info warning
37         #include <windows.h>
38 #endif
39
40 #include "GL/glew.h"
41 #include "GPU_extensions.h"
42
43 #include "GPG_Application.h"
44
45 #include <iostream>
46 #include <MT_assert.h>
47 #include <stdlib.h>
48
49 /**********************************
50  * Begin Blender include block
51  **********************************/
52 #ifdef __cplusplus
53 extern "C"
54 {
55 #endif  // __cplusplus
56 #include "BLI_blenlib.h"
57 #include "BLO_readfile.h"
58 #include "BKE_global.h"
59 #include "BKE_main.h"
60 #include "IMB_imbuf.h"
61 #include "DNA_scene_types.h"
62 #ifdef __cplusplus
63 }
64 #endif // __cplusplus
65 /**********************************
66  * End Blender include block
67  **********************************/
68
69
70 #include "SYS_System.h"
71 #include "KX_KetsjiEngine.h"
72
73 // include files needed by "KX_BlenderSceneConverter.h"
74 #include "GEN_Map.h"
75 #include "SCA_IActuator.h"
76 #include "RAS_MeshObject.h"
77 #include "RAS_OpenGLRasterizer.h"
78 #include "RAS_VAOpenGLRasterizer.h"
79 #include "RAS_ListRasterizer.h"
80 #include "RAS_GLExtensionManager.h"
81 #include "KX_PythonInit.h"
82 #include "KX_PyConstraintBinding.h"
83 #include "BL_Material.h" // MAXTEX
84
85 #include "KX_BlenderSceneConverter.h"
86 #include "NG_LoopBackNetworkDeviceInterface.h"
87 #include "SND_DeviceManager.h"
88
89 #include "GPC_MouseDevice.h"
90 #include "GPC_RenderTools.h"
91 #include "GPG_Canvas.h" 
92 #include "GPG_KeyboardDevice.h"
93 #include "GPG_System.h"
94
95 #include "STR_String.h"
96
97 #include "GHOST_ISystem.h"
98 #include "GHOST_IEvent.h"
99 #include "GHOST_IEventConsumer.h"
100 #include "GHOST_IWindow.h"
101 #include "GHOST_Rect.h"
102
103 static void frameTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 time);
104
105 static GHOST_ISystem* fSystem = 0;
106 static const int kTimerFreq = 10;
107
108 GPG_Application::GPG_Application(GHOST_ISystem* system)
109         : m_startSceneName(""), 
110           m_startScene(0),
111           m_maggie(0),
112           m_exitRequested(0),
113           m_system(system), 
114           m_mainWindow(0), 
115           m_frameTimer(0), 
116           m_cursor(GHOST_kStandardCursorFirstCursor),
117           m_engineInitialized(0), 
118           m_engineRunning(0), 
119           m_isEmbedded(false),
120           m_ketsjiengine(0),
121           m_kxsystem(0), 
122           m_keyboard(0), 
123           m_mouse(0), 
124           m_canvas(0), 
125           m_rendertools(0), 
126           m_rasterizer(0), 
127           m_sceneconverter(0),
128           m_networkdevice(0), 
129           m_audiodevice(0),
130           m_blendermat(0),
131           m_blenderglslmat(0),
132           m_pyGlobalDictString(0),
133           m_pyGlobalDictString_Length(0)
134 {
135         fSystem = system;
136 }
137
138
139
140 GPG_Application::~GPG_Application(void)
141 {
142     if(m_pyGlobalDictString) {
143                 delete [] m_pyGlobalDictString;
144                 m_pyGlobalDictString = 0;
145                 m_pyGlobalDictString_Length = 0;
146         }
147
148         exitEngine();
149         fSystem->disposeWindow(m_mainWindow);
150 }
151
152
153
154 bool GPG_Application::SetGameEngineData(struct Main* maggie, Scene *scene)
155 {
156         bool result = false;
157
158         if (maggie != NULL && scene != NULL)
159         {
160                 G.scene = scene;
161                 m_maggie = maggie;
162                 m_startSceneName = scene->id.name+2;
163                 m_startScene = scene;
164                 result = true;
165         }
166
167         return result;
168 }
169
170
171 #ifdef WIN32
172 #define SCR_SAVE_MOUSE_MOVE_THRESHOLD 15
173
174 static HWND found_ghost_window_hwnd;
175 static GHOST_IWindow* ghost_window_to_find;
176 static WNDPROC ghost_wnd_proc;
177 static POINT scr_save_mouse_pos;
178
179 static LRESULT CALLBACK screenSaverWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
180 {
181         BOOL close = FALSE;
182         switch (uMsg)
183         {
184                 case WM_MOUSEMOVE:
185                 { 
186                         POINT pt; 
187                         GetCursorPos(&pt);
188                         LONG dx = scr_save_mouse_pos.x - pt.x;
189                         LONG dy = scr_save_mouse_pos.y - pt.y;
190                         if (abs(dx) > SCR_SAVE_MOUSE_MOVE_THRESHOLD
191                             || abs(dy) > SCR_SAVE_MOUSE_MOVE_THRESHOLD)
192                         {
193                                 close = TRUE;
194                         }
195                         scr_save_mouse_pos = pt;
196                         break;
197                 }
198                 case WM_LBUTTONDOWN: 
199                 case WM_MBUTTONDOWN: 
200                 case WM_RBUTTONDOWN: 
201                 case WM_KEYDOWN:
202                         close = TRUE;
203         }
204         if (close)
205                 PostMessage(hwnd,WM_CLOSE,0,0);
206         return CallWindowProc(ghost_wnd_proc, hwnd, uMsg, wParam, lParam);
207 }
208
209 BOOL CALLBACK findGhostWindowHWNDProc(HWND hwnd, LPARAM lParam)
210 {
211         GHOST_IWindow *p = (GHOST_IWindow*) GetWindowLong(hwnd, GWL_USERDATA);
212         BOOL ret = TRUE;
213         if (p == ghost_window_to_find)
214         {
215                 found_ghost_window_hwnd = hwnd;
216                 ret = FALSE;
217         }
218         return ret;
219 }
220
221 static HWND findGhostWindowHWND(GHOST_IWindow* window)
222 {
223         found_ghost_window_hwnd = NULL;
224         ghost_window_to_find = window;
225         EnumWindows(findGhostWindowHWNDProc, NULL);
226         return found_ghost_window_hwnd;
227 }
228
229 bool GPG_Application::startScreenSaverPreview(
230         HWND parentWindow,
231         const bool stereoVisual,
232         const int stereoMode)
233 {
234         bool success = false;
235
236         RECT rc;
237         if (GetWindowRect(parentWindow, &rc))
238         {
239                 int windowWidth = rc.right - rc.left;
240                 int windowHeight = rc.bottom - rc.top;
241                 STR_String title = "";
242                                                         
243                 m_mainWindow = fSystem->createWindow(title, 0, 0, windowWidth, windowHeight, GHOST_kWindowStateMinimized,
244                         GHOST_kDrawingContextTypeOpenGL, stereoVisual);
245                 if (!m_mainWindow) {
246                         printf("error: could not create main window\n");
247                         exit(-1);
248                 }
249
250                 HWND ghost_hwnd = findGhostWindowHWND(m_mainWindow);
251                 if (!ghost_hwnd) {
252                         printf("error: could find main window\n");
253                         exit(-1);
254                 }
255
256                 SetParent(ghost_hwnd, parentWindow);
257                 LONG style = GetWindowLong(ghost_hwnd, GWL_STYLE);
258                 LONG exstyle = GetWindowLong(ghost_hwnd, GWL_EXSTYLE);
259
260                 RECT adjrc = { 0, 0, windowWidth, windowHeight };
261                 AdjustWindowRectEx(&adjrc, style, FALSE, exstyle);
262
263                 style = (style & (~(WS_POPUP|WS_OVERLAPPEDWINDOW|WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_TILEDWINDOW ))) | WS_CHILD;
264                 SetWindowLong(ghost_hwnd, GWL_STYLE, style);
265                 SetWindowPos(ghost_hwnd, NULL, adjrc.left, adjrc.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE);
266
267                 /* Check the size of the client rectangle of the window and resize the window
268                  * so that the client rectangle has the size requested.
269                  */
270                 m_mainWindow->setClientSize(windowWidth, windowHeight);
271
272                 success = initEngine(m_mainWindow, stereoMode);
273                 if (success) {
274                         success = startEngine();
275                 }
276
277         }
278         return success;
279 }
280
281 bool GPG_Application::startScreenSaverFullScreen(
282                 int width,
283                 int height,
284                 int bpp,int frequency,
285                 const bool stereoVisual,
286                 const int stereoMode)
287 {
288         bool ret = startFullScreen(width, height, bpp, frequency, stereoVisual, stereoMode);
289         if (ret)
290         {
291                 HWND ghost_hwnd = findGhostWindowHWND(m_mainWindow);
292                 if (ghost_hwnd != NULL)
293                 {
294                         GetCursorPos(&scr_save_mouse_pos);
295                         ghost_wnd_proc = (WNDPROC) GetWindowLong(ghost_hwnd, GWL_WNDPROC);
296                         SetWindowLong(ghost_hwnd,GWL_WNDPROC, (LONG) screenSaverWindowProc);
297                 }
298         }
299         return ret;
300 }
301
302 #endif
303
304 bool GPG_Application::startWindow(STR_String& title,
305         int windowLeft,
306         int windowTop,
307         int windowWidth,
308         int windowHeight,
309         const bool stereoVisual,
310         const int stereoMode)
311 {
312         bool success;
313         // Create the main window
314         //STR_String title ("Blender Player - GHOST");
315         m_mainWindow = fSystem->createWindow(title, windowLeft, windowTop, windowWidth, windowHeight, GHOST_kWindowStateNormal,
316                 GHOST_kDrawingContextTypeOpenGL, stereoVisual);
317         if (!m_mainWindow) {
318                 printf("error: could not create main window\n");
319                 exit(-1);
320         }
321
322         /* Check the size of the client rectangle of the window and resize the window
323          * so that the client rectangle has the size requested.
324          */
325         m_mainWindow->setClientSize(windowWidth, windowHeight);
326         m_mainWindow->setCursorVisibility(false);
327
328         success = initEngine(m_mainWindow, stereoMode);
329         if (success) {
330                 success = startEngine();
331         }
332         return success;
333 }
334
335 bool GPG_Application::startEmbeddedWindow(STR_String& title,
336         const GHOST_TEmbedderWindowID parentWindow, 
337         const bool stereoVisual, 
338         const int stereoMode) {
339
340         m_mainWindow = fSystem->createWindow(title, 0, 0, 0, 0, GHOST_kWindowStateNormal,
341                 GHOST_kDrawingContextTypeOpenGL, stereoVisual, parentWindow);
342
343         if (!m_mainWindow) {
344                 printf("error: could not create main window\n");
345                 exit(-1);
346         }
347         m_isEmbedded = true;
348
349         bool success = initEngine(m_mainWindow, stereoMode);
350         if (success) {
351                 success = startEngine();
352         }
353         return success;
354 }
355
356
357 bool GPG_Application::startFullScreen(
358                 int width,
359                 int height,
360                 int bpp,int frequency,
361                 const bool stereoVisual,
362                 const int stereoMode)
363 {
364         bool success;
365         // Create the main window
366         GHOST_DisplaySetting setting;
367         setting.xPixels = width;
368         setting.yPixels = height;
369         setting.bpp = bpp;
370         setting.frequency = frequency;
371
372         fSystem->beginFullScreen(setting, &m_mainWindow, stereoVisual);
373         m_mainWindow->setCursorVisibility(false);
374
375         success = initEngine(m_mainWindow, stereoMode);
376         if (success) {
377                 success = startEngine();
378         }
379         return success;
380 }
381
382
383
384
385 bool GPG_Application::StartGameEngine(int stereoMode)
386 {
387         bool success = initEngine(m_mainWindow, stereoMode);
388         
389         if (success)
390                 success = startEngine();
391
392         return success;
393 }
394
395
396
397 void GPG_Application::StopGameEngine()
398 {
399         exitEngine();
400 }
401
402
403
404 bool GPG_Application::processEvent(GHOST_IEvent* event)
405 {
406         bool handled = true;
407
408         switch (event->getType())
409         {
410                 case GHOST_kEventUnknown:
411                         break;
412
413                 case GHOST_kEventButtonDown:
414                         handled = handleButton(event, true);
415                         break;
416
417                 case GHOST_kEventButtonUp:
418                         handled = handleButton(event, false);
419                         break;
420                         
421                 case GHOST_kEventWheel:
422                         handled = handleWheel(event);
423                         break;
424
425                 case GHOST_kEventCursorMove:
426                         handled = handleCursorMove(event);
427                         break;
428
429                 case GHOST_kEventKeyDown:
430                         handleKey(event, true);
431                         break;
432
433                 case GHOST_kEventKeyUp:
434                         handleKey(event, false);
435                         break;
436
437
438                 case GHOST_kEventWindowClose:
439                         m_exitRequested = KX_EXIT_REQUEST_OUTSIDE;
440                         break;
441
442                 case GHOST_kEventWindowActivate:
443                         handled = false;
444                         break;
445                 case GHOST_kEventWindowDeactivate:
446                         handled = false;
447                         break;
448
449                 case GHOST_kEventWindowUpdate:
450                         {
451                                 GHOST_IWindow* window = event->getWindow();
452                                 if (!m_system->validWindow(window)) break;
453                                 // Update the state of the game engine
454                                 if (m_kxsystem && !m_exitRequested)
455                                 {
456                                         // Proceed to next frame
457                                         window->activateDrawingContext();
458
459                                         // first check if we want to exit
460                                         m_exitRequested = m_ketsjiengine->GetExitCode();
461                                         
462                                         // kick the engine
463                                         bool renderFrame = m_ketsjiengine->NextFrame();
464                                         if (renderFrame)
465                                         {
466                                                 // render the frame
467                                                 m_ketsjiengine->Render();
468                                         }
469                                 }
470                                 m_exitString = m_ketsjiengine->GetExitString();
471                         }
472                         break;
473                 
474                 case GHOST_kEventWindowSize:
475                         {
476                         GHOST_IWindow* window = event->getWindow();
477                         if (!m_system->validWindow(window)) break;
478                         if (m_canvas) {
479                                 GHOST_Rect bnds;
480                                 window->getClientBounds(bnds);
481                                 m_canvas->Resize(bnds.getWidth(), bnds.getHeight());
482                         }
483                         }
484                         break;
485                 
486                 default:
487                         handled = false;
488                         break;
489         }
490         return handled;
491 }
492
493
494
495 int GPG_Application::getExitRequested(void)
496 {
497         return m_exitRequested;
498 }
499
500
501
502 const STR_String& GPG_Application::getExitString(void)
503 {
504         return m_exitString;
505 }
506
507
508
509 bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode)
510 {
511         if (!m_engineInitialized)
512         {
513                 GPU_extensions_init();
514                 bgl::InitExtensions(true);
515
516                 // get and set the preferences
517                 SYS_SystemHandle syshandle = SYS_GetSystem();
518                 if (!syshandle)
519                         return false;
520                 
521                 // SYS_WriteCommandLineInt(syshandle, "fixedtime", 0);
522                 // SYS_WriteCommandLineInt(syshandle, "vertexarrays",1);                
523                 bool properties = (SYS_GetCommandLineInt(syshandle, "show_properties", 0) != 0);
524                 bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0);
525                 bool fixedFr = (G.fileflags & G_FILE_ENABLE_ALL_FRAMES);
526
527                 bool showPhysics = (G.fileflags & G_FILE_SHOW_PHYSICS);
528                 SYS_WriteCommandLineInt(syshandle, "show_physics", showPhysics);
529
530                 bool fixed_framerate= (SYS_GetCommandLineInt(syshandle, "fixed_framerate", fixedFr) != 0);
531                 bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0);
532                 bool useLists = (SYS_GetCommandLineInt(syshandle, "displaylists", G.fileflags & G_FILE_DISPLAY_LISTS) != 0);
533
534                 if(GLEW_ARB_multitexture && GLEW_VERSION_1_1)
535                         m_blendermat = (SYS_GetCommandLineInt(syshandle, "blender_material", 1) != 0);
536
537                 if(GPU_extensions_minimum_support())
538                         m_blenderglslmat = (SYS_GetCommandLineInt(syshandle, "blender_glsl_material", 1) != 0);
539                 else if(G.fileflags & G_FILE_GAME_MAT_GLSL)
540                         m_blendermat = false;
541
542                 // create the canvas, rasterizer and rendertools
543                 m_canvas = new GPG_Canvas(window);
544                 if (!m_canvas)
545                         return false;
546                                 
547                 m_canvas->Init();                               
548                 m_rendertools = new GPC_RenderTools();
549                 if (!m_rendertools)
550                         goto initFailed;
551                 
552                 if(useLists) {
553                         if(GLEW_VERSION_1_1)
554                                 m_rasterizer = new RAS_ListRasterizer(m_canvas, true);
555                         else
556                                 m_rasterizer = new RAS_ListRasterizer(m_canvas);
557                 }
558                 else if (GLEW_VERSION_1_1)
559                         m_rasterizer = new RAS_VAOpenGLRasterizer(m_canvas);
560                 else
561                         m_rasterizer = new RAS_OpenGLRasterizer(m_canvas);
562
563                 m_rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) stereoMode);
564                 if (!m_rasterizer)
565                         goto initFailed;
566                                                 
567                 // create the inputdevices
568                 m_keyboard = new GPG_KeyboardDevice();
569                 if (!m_keyboard)
570                         goto initFailed;
571                         
572                 m_mouse = new GPC_MouseDevice();
573                 if (!m_mouse)
574                         goto initFailed;
575                         
576                 // create a networkdevice
577                 m_networkdevice = new NG_LoopBackNetworkDeviceInterface();
578                 if (!m_networkdevice)
579                         goto initFailed;
580                         
581                 // get an audiodevice
582                 SND_DeviceManager::Subscribe();
583                 m_audiodevice = SND_DeviceManager::Instance();
584                 if (!m_audiodevice)
585                         goto initFailed;
586                 m_audiodevice->UseCD();
587                 
588                 // create a ketsjisystem (only needed for timing and stuff)
589                 m_kxsystem = new GPG_System (m_system);
590                 if (!m_kxsystem)
591                         goto initFailed;
592                 
593                 // create the ketsjiengine
594                 m_ketsjiengine = new KX_KetsjiEngine(m_kxsystem);
595                 
596                 // set the devices
597                 m_ketsjiengine->SetKeyboardDevice(m_keyboard);
598                 m_ketsjiengine->SetMouseDevice(m_mouse);
599                 m_ketsjiengine->SetNetworkDevice(m_networkdevice);
600                 m_ketsjiengine->SetCanvas(m_canvas);
601                 m_ketsjiengine->SetRenderTools(m_rendertools);
602                 m_ketsjiengine->SetRasterizer(m_rasterizer);
603                 m_ketsjiengine->SetNetworkDevice(m_networkdevice);
604                 m_ketsjiengine->SetAudioDevice(m_audiodevice);
605                 m_ketsjiengine->SetTimingDisplay(frameRate, false, false);
606
607                 m_ketsjiengine->SetUseFixedTime(fixed_framerate);
608                 m_ketsjiengine->SetTimingDisplay(frameRate, profile, properties);
609
610                 m_engineInitialized = true;
611         }
612
613         return m_engineInitialized;
614 initFailed:
615         delete m_kxsystem;
616         delete m_audiodevice;
617         delete m_networkdevice;
618         delete m_mouse;
619         delete m_keyboard;
620         delete m_rasterizer;
621         delete m_rendertools;
622         delete m_canvas;
623         m_canvas = NULL;
624         m_rendertools = NULL;
625         m_rasterizer = NULL;
626         m_keyboard = NULL;
627         m_mouse = NULL;
628         m_networkdevice = NULL;
629         m_audiodevice = NULL;
630         m_kxsystem = NULL;
631         return false;
632 }
633
634
635
636 bool GPG_Application::startEngine(void)
637 {
638         if (m_engineRunning) {
639                 return false;
640         }
641         
642         // Temporary hack to disable banner display for NaN approved content.
643         /*
644         m_canvas->SetBannerDisplayEnabled(true);        
645         Camera* cam;
646         cam = (Camera*)G.scene->camera->data;
647         if (cam) {
648         if (((cam->flag) & 48)==48) {
649         m_canvas->SetBannerDisplayEnabled(false);
650         }
651         }
652         else {
653         showError(CString("Camera data invalid."));
654         return false;
655         }
656         */
657         
658         // create a scene converter, create and convert the stratingscene
659         m_sceneconverter = new KX_BlenderSceneConverter(m_maggie,0, m_ketsjiengine);
660         if (m_sceneconverter)
661         {
662                 STR_String startscenename = m_startSceneName.Ptr();
663                 m_ketsjiengine->SetSceneConverter(m_sceneconverter);
664
665                 //      if (always_use_expand_framing)
666                 //              sceneconverter->SetAlwaysUseExpandFraming(true);
667                 if(m_blendermat && (G.fileflags & G_FILE_GAME_MAT))
668                         m_sceneconverter->SetMaterials(true);
669                 if(m_blenderglslmat && (G.fileflags & G_FILE_GAME_MAT_GLSL))
670                         m_sceneconverter->SetGLSLMaterials(true);
671
672                 KX_Scene* startscene = new KX_Scene(m_keyboard,
673                         m_mouse,
674                         m_networkdevice,
675                         m_audiodevice,
676                         startscenename,
677                         m_startScene);
678                 
679                 
680                 // some python things
681                 PyObject* dictionaryobject = initGamePlayerPythonScripting("Ketsji", psl_Lowest);
682                 m_ketsjiengine->SetPythonDictionary(dictionaryobject);
683                 initRasterizer(m_rasterizer, m_canvas);
684                 PyObject *gameLogic = initGameLogic(m_ketsjiengine, startscene);
685                 PyDict_SetItemString(dictionaryobject, "GameLogic", gameLogic); // Same as importing the module
686                 initGameKeys();
687                 initPythonConstraintBinding();
688                 initMathutils();
689
690                 // Set the GameLogic.globalDict from marshal'd data, so we can
691                 // load new blend files and keep data in GameLogic.globalDict
692                 loadGamePythonConfig(m_pyGlobalDictString, m_pyGlobalDictString_Length);
693                 
694                 m_sceneconverter->ConvertScene(
695                         startscenename,
696                         startscene,
697                         dictionaryobject,
698                         m_keyboard,
699                         m_rendertools,
700                         m_canvas);
701                 m_ketsjiengine->AddScene(startscene);
702                 
703                 // Create a timer that is used to kick the engine
704                 if (!m_frameTimer) {
705                         m_frameTimer = m_system->installTimer(0, kTimerFreq, frameTimerProc, m_mainWindow);
706                 }
707                 m_rasterizer->Init();
708                 m_ketsjiengine->StartEngine(true);
709                 m_engineRunning = true;
710                 
711                 // Set the animation playback rate for ipo's and actions
712                 // the framerate below should patch with FPS macro defined in blendef.h
713                 // Could be in StartEngine set the framerate, we need the scene to do this
714                 m_ketsjiengine->SetAnimFrameRate( (((double) G.scene->r.frs_sec) / G.scene->r.frs_sec_base) );
715                 
716         }
717         
718         if (!m_engineRunning)
719         {
720                 stopEngine();
721         }
722         
723         return m_engineRunning;
724 }
725
726
727 void GPG_Application::stopEngine()
728 {
729         // GameLogic.globalDict gets converted into a buffer, and sorted in
730         // m_pyGlobalDictString so we can restore after python has stopped
731         // and started between .blend file loads.
732         if(m_pyGlobalDictString) {
733                 delete [] m_pyGlobalDictString;
734                 m_pyGlobalDictString = 0;
735         }
736
737         m_pyGlobalDictString_Length = saveGamePythonConfig(&m_pyGlobalDictString);
738         
739         // when exiting the mainloop
740         exitGamePythonScripting();
741         m_ketsjiengine->StopEngine();
742         m_networkdevice->Disconnect();
743
744         if (m_sceneconverter) {
745                 delete m_sceneconverter;
746                 m_sceneconverter = 0;
747         }
748         if (m_system && m_frameTimer) {
749                 m_system->removeTimer(m_frameTimer);
750                 m_frameTimer = 0;
751         }
752         m_engineRunning = false;
753 }
754
755
756 void GPG_Application::exitEngine()
757 {
758         if (m_ketsjiengine)
759         {
760                 stopEngine();
761                 delete m_ketsjiengine;
762                 m_ketsjiengine = 0;
763         }
764         if (m_kxsystem)
765         {
766                 delete m_kxsystem;
767                 m_kxsystem = 0;
768         }
769         if (m_audiodevice)
770         {
771                 SND_DeviceManager::Unsubscribe();
772                 m_audiodevice = 0;
773         }
774         if (m_networkdevice)
775         {
776                 delete m_networkdevice;
777                 m_networkdevice = 0;
778         }
779         if (m_mouse)
780         {
781                 delete m_mouse;
782                 m_mouse = 0;
783         }
784         if (m_keyboard)
785         {
786                 delete m_keyboard;
787                 m_keyboard = 0;
788         }
789         if (m_rasterizer)
790         {
791                 delete m_rasterizer;
792                 m_rasterizer = 0;
793         }
794         if (m_rendertools)
795         {
796                 delete m_rendertools;
797                 m_rendertools = 0;
798         }
799         if (m_canvas)
800         {
801                 delete m_canvas;
802                 m_canvas = 0;
803         }
804
805         libtiff_exit();
806 #ifdef WITH_QUICKTIME
807         quicktime_exit();
808 #endif
809         GPU_extensions_exit();
810
811         m_exitRequested = 0;
812         m_engineInitialized = false;
813 }
814
815 bool GPG_Application::handleWheel(GHOST_IEvent* event)
816 {
817         bool handled = false;
818         MT_assert(event);
819         if (m_mouse) 
820         {
821                 GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
822                 GHOST_TEventWheelData* wheelData = static_cast<GHOST_TEventWheelData*>(eventData);
823                 GPC_MouseDevice::TButtonId button;
824                 if (wheelData->z > 0)
825                         button = GPC_MouseDevice::buttonWheelUp;
826                 else
827                         button = GPC_MouseDevice::buttonWheelDown;
828                 m_mouse->ConvertButtonEvent(button, true);
829                 handled = true;
830         }
831         return handled;
832 }
833
834 bool GPG_Application::handleButton(GHOST_IEvent* event, bool isDown)
835 {
836         bool handled = false;
837         MT_assert(event);
838         if (m_mouse) 
839         {
840                 GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
841                 GHOST_TEventButtonData* buttonData = static_cast<GHOST_TEventButtonData*>(eventData);
842                 GPC_MouseDevice::TButtonId button;
843                 switch (buttonData->button)
844                 {
845                 case GHOST_kButtonMaskMiddle:
846                         button = GPC_MouseDevice::buttonMiddle;
847                         break;
848                 case GHOST_kButtonMaskRight:
849                         button = GPC_MouseDevice::buttonRight;
850                         break;
851                 case GHOST_kButtonMaskLeft:
852                 default:
853                         button = GPC_MouseDevice::buttonLeft;
854                         break;
855                 }
856                 m_mouse->ConvertButtonEvent(button, isDown);
857                 handled = true;
858         }
859         return handled;
860 }
861
862
863 bool GPG_Application::handleCursorMove(GHOST_IEvent* event)
864 {
865         bool handled = false;
866         MT_assert(event);
867         if (m_mouse && m_mainWindow)
868         {
869                 GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
870                 GHOST_TEventCursorData* cursorData = static_cast<GHOST_TEventCursorData*>(eventData);
871                 GHOST_TInt32 x, y;
872                 m_mainWindow->screenToClient(cursorData->x, cursorData->y, x, y);
873                 m_mouse->ConvertMoveEvent(x, y);
874                 handled = true;
875         }
876         return handled;
877 }
878
879
880 bool GPG_Application::handleKey(GHOST_IEvent* event, bool isDown)
881 {
882         bool handled = false;
883         MT_assert(event);
884         if (m_keyboard)
885         {
886                 GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
887                 GHOST_TEventKeyData* keyData = static_cast<GHOST_TEventKeyData*>(eventData);
888                 //no need for this test
889                 //if (fSystem->getFullScreen()) {
890                         if (keyData->key == GHOST_kKeyEsc && !m_keyboard->m_hookesc && !m_isEmbedded) {
891                                 m_exitRequested = KX_EXIT_REQUEST_OUTSIDE;
892                         }
893                 //}
894                 m_keyboard->ConvertEvent(keyData->key, isDown);
895                 handled = true;
896         }
897         return handled;
898 }
899
900
901
902 static void frameTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 time)
903 {
904         GHOST_IWindow* window = (GHOST_IWindow*)task->getUserData();
905         if (fSystem->validWindow(window)) {
906                 window->invalidate();
907         }
908 }