Undo revision 23130 which was a merge with 2.5, a messy one because I did something...
[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, int argc, char **argv)
155 {
156         bool result = false;
157
158         if (maggie != NULL && scene != NULL)
159         {
160 // XXX          G.scene = scene;
161                 m_maggie = maggie;
162                 m_startSceneName = scene->id.name+2;
163                 m_startScene = scene;
164                 result = true;
165         }
166         
167         /* Python needs these */
168         m_argc= argc;
169         m_argv= argv;
170
171         return result;
172 }
173
174
175 #ifdef WIN32
176 #define SCR_SAVE_MOUSE_MOVE_THRESHOLD 15
177
178 static HWND found_ghost_window_hwnd;
179 static GHOST_IWindow* ghost_window_to_find;
180 static WNDPROC ghost_wnd_proc;
181 static POINT scr_save_mouse_pos;
182
183 static LRESULT CALLBACK screenSaverWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
184 {
185         BOOL close = FALSE;
186         switch (uMsg)
187         {
188                 case WM_MOUSEMOVE:
189                 { 
190                         POINT pt; 
191                         GetCursorPos(&pt);
192                         LONG dx = scr_save_mouse_pos.x - pt.x;
193                         LONG dy = scr_save_mouse_pos.y - pt.y;
194                         if (abs(dx) > SCR_SAVE_MOUSE_MOVE_THRESHOLD
195                             || abs(dy) > SCR_SAVE_MOUSE_MOVE_THRESHOLD)
196                         {
197                                 close = TRUE;
198                         }
199                         scr_save_mouse_pos = pt;
200                         break;
201                 }
202                 case WM_LBUTTONDOWN: 
203                 case WM_MBUTTONDOWN: 
204                 case WM_RBUTTONDOWN: 
205                 case WM_KEYDOWN:
206                         close = TRUE;
207         }
208         if (close)
209                 PostMessage(hwnd,WM_CLOSE,0,0);
210         return CallWindowProc(ghost_wnd_proc, hwnd, uMsg, wParam, lParam);
211 }
212
213 BOOL CALLBACK findGhostWindowHWNDProc(HWND hwnd, LPARAM lParam)
214 {
215         GHOST_IWindow *p = (GHOST_IWindow*) GetWindowLongPtr(hwnd, GWLP_USERDATA);
216         BOOL ret = TRUE;
217         if (p == ghost_window_to_find)
218         {
219                 found_ghost_window_hwnd = hwnd;
220                 ret = FALSE;
221         }
222         return ret;
223 }
224
225 static HWND findGhostWindowHWND(GHOST_IWindow* window)
226 {
227         found_ghost_window_hwnd = NULL;
228         ghost_window_to_find = window;
229         EnumWindows(findGhostWindowHWNDProc, NULL);
230         return found_ghost_window_hwnd;
231 }
232
233 bool GPG_Application::startScreenSaverPreview(
234         HWND parentWindow,
235         const bool stereoVisual,
236         const int stereoMode)
237 {
238         bool success = false;
239
240         RECT rc;
241         if (GetWindowRect(parentWindow, &rc))
242         {
243                 int windowWidth = rc.right - rc.left;
244                 int windowHeight = rc.bottom - rc.top;
245                 STR_String title = "";
246                                                         
247                 m_mainWindow = fSystem->createWindow(title, 0, 0, windowWidth, windowHeight, GHOST_kWindowStateMinimized,
248                         GHOST_kDrawingContextTypeOpenGL, stereoVisual);
249                 if (!m_mainWindow) {
250                         printf("error: could not create main window\n");
251                         exit(-1);
252                 }
253
254                 HWND ghost_hwnd = findGhostWindowHWND(m_mainWindow);
255                 if (!ghost_hwnd) {
256                         printf("error: could find main window\n");
257                         exit(-1);
258                 }
259
260                 SetParent(ghost_hwnd, parentWindow);
261                 LONG style = GetWindowLong(ghost_hwnd, GWL_STYLE);
262                 LONG exstyle = GetWindowLong(ghost_hwnd, GWL_EXSTYLE);
263
264                 RECT adjrc = { 0, 0, windowWidth, windowHeight };
265                 AdjustWindowRectEx(&adjrc, style, FALSE, exstyle);
266
267                 style = (style & (~(WS_POPUP|WS_OVERLAPPEDWINDOW|WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_TILEDWINDOW ))) | WS_CHILD;
268                 SetWindowLong(ghost_hwnd, GWL_STYLE, style);
269                 SetWindowPos(ghost_hwnd, NULL, adjrc.left, adjrc.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE);
270
271                 /* Check the size of the client rectangle of the window and resize the window
272                  * so that the client rectangle has the size requested.
273                  */
274                 m_mainWindow->setClientSize(windowWidth, windowHeight);
275
276                 success = initEngine(m_mainWindow, stereoMode);
277                 if (success) {
278                         success = startEngine();
279                 }
280
281         }
282         return success;
283 }
284
285 bool GPG_Application::startScreenSaverFullScreen(
286                 int width,
287                 int height,
288                 int bpp,int frequency,
289                 const bool stereoVisual,
290                 const int stereoMode)
291 {
292         bool ret = startFullScreen(width, height, bpp, frequency, stereoVisual, stereoMode);
293         if (ret)
294         {
295                 HWND ghost_hwnd = findGhostWindowHWND(m_mainWindow);
296                 if (ghost_hwnd != NULL)
297                 {
298                         GetCursorPos(&scr_save_mouse_pos);
299                         ghost_wnd_proc = (WNDPROC) GetWindowLongPtr(ghost_hwnd, GWLP_WNDPROC);
300                         SetWindowLongPtr(ghost_hwnd,GWLP_WNDPROC, (uintptr_t) screenSaverWindowProc);
301                 }
302         }
303         return ret;
304 }
305
306 #endif
307
308 bool GPG_Application::startWindow(STR_String& title,
309         int windowLeft,
310         int windowTop,
311         int windowWidth,
312         int windowHeight,
313         const bool stereoVisual,
314         const int stereoMode)
315 {
316         bool success;
317         // Create the main window
318         //STR_String title ("Blender Player - GHOST");
319         m_mainWindow = fSystem->createWindow(title, windowLeft, windowTop, windowWidth, windowHeight, GHOST_kWindowStateNormal,
320                 GHOST_kDrawingContextTypeOpenGL, stereoVisual);
321         if (!m_mainWindow) {
322                 printf("error: could not create main window\n");
323                 exit(-1);
324         }
325
326         /* Check the size of the client rectangle of the window and resize the window
327          * so that the client rectangle has the size requested.
328          */
329         m_mainWindow->setClientSize(windowWidth, windowHeight);
330         m_mainWindow->setCursorVisibility(false);
331
332         success = initEngine(m_mainWindow, stereoMode);
333         if (success) {
334                 success = startEngine();
335         }
336         return success;
337 }
338
339 bool GPG_Application::startEmbeddedWindow(STR_String& title,
340         const GHOST_TEmbedderWindowID parentWindow, 
341         const bool stereoVisual, 
342         const int stereoMode) {
343
344         m_mainWindow = fSystem->createWindow(title, 0, 0, 0, 0, GHOST_kWindowStateNormal,
345                 GHOST_kDrawingContextTypeOpenGL, stereoVisual, parentWindow);
346
347         if (!m_mainWindow) {
348                 printf("error: could not create main window\n");
349                 exit(-1);
350         }
351         m_isEmbedded = true;
352
353         bool success = initEngine(m_mainWindow, stereoMode);
354         if (success) {
355                 success = startEngine();
356         }
357         return success;
358 }
359
360
361 bool GPG_Application::startFullScreen(
362                 int width,
363                 int height,
364                 int bpp,int frequency,
365                 const bool stereoVisual,
366                 const int stereoMode)
367 {
368         bool success;
369         // Create the main window
370         GHOST_DisplaySetting setting;
371         setting.xPixels = width;
372         setting.yPixels = height;
373         setting.bpp = bpp;
374         setting.frequency = frequency;
375
376         fSystem->beginFullScreen(setting, &m_mainWindow, stereoVisual);
377         m_mainWindow->setCursorVisibility(false);
378
379         success = initEngine(m_mainWindow, stereoMode);
380         if (success) {
381                 success = startEngine();
382         }
383         return success;
384 }
385
386
387
388
389 bool GPG_Application::StartGameEngine(int stereoMode)
390 {
391         bool success = initEngine(m_mainWindow, stereoMode);
392         
393         if (success)
394                 success = startEngine();
395
396         return success;
397 }
398
399
400
401 void GPG_Application::StopGameEngine()
402 {
403         exitEngine();
404 }
405
406
407
408 bool GPG_Application::processEvent(GHOST_IEvent* event)
409 {
410         bool handled = true;
411
412         switch (event->getType())
413         {
414                 case GHOST_kEventUnknown:
415                         break;
416
417                 case GHOST_kEventButtonDown:
418                         handled = handleButton(event, true);
419                         break;
420
421                 case GHOST_kEventButtonUp:
422                         handled = handleButton(event, false);
423                         break;
424                         
425                 case GHOST_kEventWheel:
426                         handled = handleWheel(event);
427                         break;
428
429                 case GHOST_kEventCursorMove:
430                         handled = handleCursorMove(event);
431                         break;
432
433                 case GHOST_kEventKeyDown:
434                         handleKey(event, true);
435                         break;
436
437                 case GHOST_kEventKeyUp:
438                         handleKey(event, false);
439                         break;
440
441
442                 case GHOST_kEventWindowClose:
443                         m_exitRequested = KX_EXIT_REQUEST_OUTSIDE;
444                         break;
445
446                 case GHOST_kEventWindowActivate:
447                         handled = false;
448                         break;
449                 case GHOST_kEventWindowDeactivate:
450                         handled = false;
451                         break;
452
453                 case GHOST_kEventWindowUpdate:
454                         {
455                                 GHOST_IWindow* window = event->getWindow();
456                                 if (!m_system->validWindow(window)) break;
457                                 // Update the state of the game engine
458                                 if (m_kxsystem && !m_exitRequested)
459                                 {
460                                         // Proceed to next frame
461                                         window->activateDrawingContext();
462
463                                         // first check if we want to exit
464                                         m_exitRequested = m_ketsjiengine->GetExitCode();
465                                         
466                                         // kick the engine
467                                         bool renderFrame = m_ketsjiengine->NextFrame();
468                                         if (renderFrame)
469                                         {
470                                                 // render the frame
471                                                 m_ketsjiengine->Render();
472                                         }
473                                 }
474                                 m_exitString = m_ketsjiengine->GetExitString();
475                         }
476                         break;
477                 
478                 case GHOST_kEventWindowSize:
479                         {
480                         GHOST_IWindow* window = event->getWindow();
481                         if (!m_system->validWindow(window)) break;
482                         if (m_canvas) {
483                                 GHOST_Rect bnds;
484                                 window->getClientBounds(bnds);
485                                 m_canvas->Resize(bnds.getWidth(), bnds.getHeight());
486                         }
487                         }
488                         break;
489                 
490                 default:
491                         handled = false;
492                         break;
493         }
494         return handled;
495 }
496
497
498
499 int GPG_Application::getExitRequested(void)
500 {
501         return m_exitRequested;
502 }
503
504
505
506 const STR_String& GPG_Application::getExitString(void)
507 {
508         return m_exitString;
509 }
510
511
512
513 bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode)
514 {
515         if (!m_engineInitialized)
516         {
517                 GPU_extensions_init();
518                 bgl::InitExtensions(true);
519
520                 // get and set the preferences
521                 SYS_SystemHandle syshandle = SYS_GetSystem();
522                 if (!syshandle)
523                         return false;
524                 
525                 // SYS_WriteCommandLineInt(syshandle, "fixedtime", 0);
526                 // SYS_WriteCommandLineInt(syshandle, "vertexarrays",1);                
527                 GameData *gm= &m_startScene->gm;
528                 bool properties = (SYS_GetCommandLineInt(syshandle, "show_properties", 0) != 0);
529                 bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0);
530                 bool fixedFr = (gm->flag & GAME_ENABLE_ALL_FRAMES);
531
532                 bool showPhysics = (gm->flag & GAME_SHOW_PHYSICS);
533                 SYS_WriteCommandLineInt(syshandle, "show_physics", showPhysics);
534
535                 bool fixed_framerate= (SYS_GetCommandLineInt(syshandle, "fixed_framerate", fixedFr) != 0);
536                 bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0);
537                 bool useLists = (SYS_GetCommandLineInt(syshandle, "displaylists", gm->flag & GAME_DISPLAY_LISTS) != 0);
538                 bool nodepwarnings = (SYS_GetCommandLineInt(syshandle, "ignore_deprecation_warnings", 1) != 0);
539
540                 if(GLEW_ARB_multitexture && GLEW_VERSION_1_1)
541                         m_blendermat = (SYS_GetCommandLineInt(syshandle, "blender_material", 1) != 0);
542
543                 if(GPU_extensions_minimum_support())
544                         m_blenderglslmat = (SYS_GetCommandLineInt(syshandle, "blender_glsl_material", 1) != 0);
545                 else if(gm->matmode == GAME_MAT_GLSL)
546                         m_blendermat = false;
547
548                 // create the canvas, rasterizer and rendertools
549                 m_canvas = new GPG_Canvas(window);
550                 if (!m_canvas)
551                         return false;
552                                 
553                 m_canvas->Init();                               
554                 m_rendertools = new GPC_RenderTools();
555                 if (!m_rendertools)
556                         goto initFailed;
557                 
558                 if(useLists) {
559                         if(GLEW_VERSION_1_1)
560                                 m_rasterizer = new RAS_ListRasterizer(m_canvas, true);
561                         else
562                                 m_rasterizer = new RAS_ListRasterizer(m_canvas);
563                 }
564                 else if (GLEW_VERSION_1_1)
565                         m_rasterizer = new RAS_VAOpenGLRasterizer(m_canvas);
566                 else
567                         m_rasterizer = new RAS_OpenGLRasterizer(m_canvas);
568
569                 m_rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) stereoMode);
570                 if (!m_rasterizer)
571                         goto initFailed;
572                                                 
573                 // create the inputdevices
574                 m_keyboard = new GPG_KeyboardDevice();
575                 if (!m_keyboard)
576                         goto initFailed;
577                         
578                 m_mouse = new GPC_MouseDevice();
579                 if (!m_mouse)
580                         goto initFailed;
581                         
582                 // create a networkdevice
583                 m_networkdevice = new NG_LoopBackNetworkDeviceInterface();
584                 if (!m_networkdevice)
585                         goto initFailed;
586                         
587                 // get an audiodevice
588                 SND_DeviceManager::Subscribe();
589                 m_audiodevice = SND_DeviceManager::Instance();
590                 if (!m_audiodevice)
591                         goto initFailed;
592                 m_audiodevice->UseCD();
593                 
594                 // create a ketsjisystem (only needed for timing and stuff)
595                 m_kxsystem = new GPG_System (m_system);
596                 if (!m_kxsystem)
597                         goto initFailed;
598                 
599                 // create the ketsjiengine
600                 m_ketsjiengine = new KX_KetsjiEngine(m_kxsystem);
601                 
602                 // set the devices
603                 m_ketsjiengine->SetKeyboardDevice(m_keyboard);
604                 m_ketsjiengine->SetMouseDevice(m_mouse);
605                 m_ketsjiengine->SetNetworkDevice(m_networkdevice);
606                 m_ketsjiengine->SetCanvas(m_canvas);
607                 m_ketsjiengine->SetRenderTools(m_rendertools);
608                 m_ketsjiengine->SetRasterizer(m_rasterizer);
609                 m_ketsjiengine->SetNetworkDevice(m_networkdevice);
610                 m_ketsjiengine->SetAudioDevice(m_audiodevice);
611                 m_ketsjiengine->SetTimingDisplay(frameRate, false, false);
612
613                 CValue::SetDeprecationWarnings(nodepwarnings);
614
615                 m_ketsjiengine->SetUseFixedTime(fixed_framerate);
616                 m_ketsjiengine->SetTimingDisplay(frameRate, profile, properties);
617
618                 m_engineInitialized = true;
619         }
620
621         return m_engineInitialized;
622 initFailed:
623         delete m_kxsystem;
624         delete m_audiodevice;
625         delete m_networkdevice;
626         delete m_mouse;
627         delete m_keyboard;
628         delete m_rasterizer;
629         delete m_rendertools;
630         delete m_canvas;
631         m_canvas = NULL;
632         m_rendertools = NULL;
633         m_rasterizer = NULL;
634         m_keyboard = NULL;
635         m_mouse = NULL;
636         m_networkdevice = NULL;
637         m_audiodevice = NULL;
638         m_kxsystem = NULL;
639         return false;
640 }
641
642
643
644 bool GPG_Application::startEngine(void)
645 {
646         if (m_engineRunning) {
647                 return false;
648         }
649         
650         // Temporary hack to disable banner display for NaN approved content.
651         /*
652         m_canvas->SetBannerDisplayEnabled(true);        
653         Camera* cam;
654         cam = (Camera*)scene->camera->data;
655         if (cam) {
656         if (((cam->flag) & 48)==48) {
657         m_canvas->SetBannerDisplayEnabled(false);
658         }
659         }
660         else {
661         showError(CString("Camera data invalid."));
662         return false;
663         }
664         */
665         
666         // create a scene converter, create and convert the stratingscene
667         m_sceneconverter = new KX_BlenderSceneConverter(m_maggie, m_ketsjiengine);
668         if (m_sceneconverter)
669         {
670                 STR_String startscenename = m_startSceneName.Ptr();
671                 m_ketsjiengine->SetSceneConverter(m_sceneconverter);
672
673                 //      if (always_use_expand_framing)
674                 //              sceneconverter->SetAlwaysUseExpandFraming(true);
675                 if(m_blendermat && (m_startScene->gm.matmode != GAME_MAT_TEXFACE))
676                         m_sceneconverter->SetMaterials(true);
677                 if(m_blenderglslmat && (m_startScene->gm.matmode == GAME_MAT_GLSL))
678                         m_sceneconverter->SetGLSLMaterials(true);
679
680                 KX_Scene* startscene = new KX_Scene(m_keyboard,
681                         m_mouse,
682                         m_networkdevice,
683                         m_audiodevice,
684                         startscenename,
685                         m_startScene);
686                 
687                 
688                 // some python things
689                 PyObject* dictionaryobject = initGamePlayerPythonScripting("Ketsji", psl_Lowest, m_maggie, m_argc, m_argv);
690                 m_ketsjiengine->SetPythonDictionary(dictionaryobject);
691                 initRasterizer(m_rasterizer, m_canvas);
692                 PyObject *gameLogic = initGameLogic(m_ketsjiengine, startscene);
693                 PyDict_SetItemString(dictionaryobject, "GameLogic", gameLogic); // Same as importing the module
694                 initGameKeys();
695                 initPythonConstraintBinding();
696                 initMathutils();
697                 initGeometry();
698                 initBGL();
699 #ifdef WITH_FFMPEG
700         initVideoTexture();
701 #endif
702
703                 //initialize Dome Settings
704                 if(m_startScene->gm.stereoflag == STEREO_DOME)
705                         m_ketsjiengine->InitDome(m_startScene->gm.dome.res, m_startScene->gm.dome.mode, m_startScene->gm.dome.angle, m_startScene->gm.dome.resbuf, m_startScene->gm.dome.tilt, m_startScene->gm.dome.warptext);
706
707                 // Set the GameLogic.globalDict from marshal'd data, so we can
708                 // load new blend files and keep data in GameLogic.globalDict
709                 loadGamePythonConfig(m_pyGlobalDictString, m_pyGlobalDictString_Length);
710                 
711                 m_sceneconverter->ConvertScene(
712                         startscene,
713                         dictionaryobject,
714                         m_rendertools,
715                         m_canvas);
716                 m_ketsjiengine->AddScene(startscene);
717                 
718                 // Create a timer that is used to kick the engine
719                 if (!m_frameTimer) {
720                         m_frameTimer = m_system->installTimer(0, kTimerFreq, frameTimerProc, m_mainWindow);
721                 }
722                 m_rasterizer->Init();
723                 m_ketsjiengine->StartEngine(true);
724                 m_engineRunning = true;
725                 
726                 // Set the animation playback rate for ipo's and actions
727                 // the framerate below should patch with FPS macro defined in blendef.h
728                 // Could be in StartEngine set the framerate, we need the scene to do this
729 // XXX          m_ketsjiengine->SetAnimFrameRate( (((double) scene->r.frs_sec) / scene->r.frs_sec_base) );
730                 
731         }
732         
733         if (!m_engineRunning)
734         {
735                 stopEngine();
736         }
737         
738         return m_engineRunning;
739 }
740
741
742 void GPG_Application::stopEngine()
743 {
744         // GameLogic.globalDict gets converted into a buffer, and sorted in
745         // m_pyGlobalDictString so we can restore after python has stopped
746         // and started between .blend file loads.
747         if(m_pyGlobalDictString) {
748                 delete [] m_pyGlobalDictString;
749                 m_pyGlobalDictString = 0;
750         }
751
752         m_pyGlobalDictString_Length = saveGamePythonConfig(&m_pyGlobalDictString);
753         
754         // when exiting the mainloop
755         exitGamePythonScripting();
756         m_ketsjiengine->StopEngine();
757         m_networkdevice->Disconnect();
758
759         if (m_sceneconverter) {
760                 delete m_sceneconverter;
761                 m_sceneconverter = 0;
762         }
763         if (m_system && m_frameTimer) {
764                 m_system->removeTimer(m_frameTimer);
765                 m_frameTimer = 0;
766         }
767         m_engineRunning = false;
768 }
769
770
771 void GPG_Application::exitEngine()
772 {
773         if (m_ketsjiengine)
774         {
775                 stopEngine();
776                 delete m_ketsjiengine;
777                 m_ketsjiengine = 0;
778         }
779         if (m_kxsystem)
780         {
781                 delete m_kxsystem;
782                 m_kxsystem = 0;
783         }
784         if (m_audiodevice)
785         {
786                 SND_DeviceManager::Unsubscribe();
787                 m_audiodevice = 0;
788         }
789         if (m_networkdevice)
790         {
791                 delete m_networkdevice;
792                 m_networkdevice = 0;
793         }
794         if (m_mouse)
795         {
796                 delete m_mouse;
797                 m_mouse = 0;
798         }
799         if (m_keyboard)
800         {
801                 delete m_keyboard;
802                 m_keyboard = 0;
803         }
804         if (m_rasterizer)
805         {
806                 delete m_rasterizer;
807                 m_rasterizer = 0;
808         }
809         if (m_rendertools)
810         {
811                 delete m_rendertools;
812                 m_rendertools = 0;
813         }
814         if (m_canvas)
815         {
816                 delete m_canvas;
817                 m_canvas = 0;
818         }
819
820         libtiff_exit();
821 #ifdef WITH_QUICKTIME
822         quicktime_exit();
823 #endif
824         GPU_extensions_exit();
825
826         m_exitRequested = 0;
827         m_engineInitialized = false;
828 }
829
830 bool GPG_Application::handleWheel(GHOST_IEvent* event)
831 {
832         bool handled = false;
833         MT_assert(event);
834         if (m_mouse) 
835         {
836                 GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
837                 GHOST_TEventWheelData* wheelData = static_cast<GHOST_TEventWheelData*>(eventData);
838                 GPC_MouseDevice::TButtonId button;
839                 if (wheelData->z > 0)
840                         button = GPC_MouseDevice::buttonWheelUp;
841                 else
842                         button = GPC_MouseDevice::buttonWheelDown;
843                 m_mouse->ConvertButtonEvent(button, true);
844                 handled = true;
845         }
846         return handled;
847 }
848
849 bool GPG_Application::handleButton(GHOST_IEvent* event, bool isDown)
850 {
851         bool handled = false;
852         MT_assert(event);
853         if (m_mouse) 
854         {
855                 GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
856                 GHOST_TEventButtonData* buttonData = static_cast<GHOST_TEventButtonData*>(eventData);
857                 GPC_MouseDevice::TButtonId button;
858                 switch (buttonData->button)
859                 {
860                 case GHOST_kButtonMaskMiddle:
861                         button = GPC_MouseDevice::buttonMiddle;
862                         break;
863                 case GHOST_kButtonMaskRight:
864                         button = GPC_MouseDevice::buttonRight;
865                         break;
866                 case GHOST_kButtonMaskLeft:
867                 default:
868                         button = GPC_MouseDevice::buttonLeft;
869                         break;
870                 }
871                 m_mouse->ConvertButtonEvent(button, isDown);
872                 handled = true;
873         }
874         return handled;
875 }
876
877
878 bool GPG_Application::handleCursorMove(GHOST_IEvent* event)
879 {
880         bool handled = false;
881         MT_assert(event);
882         if (m_mouse && m_mainWindow)
883         {
884                 GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
885                 GHOST_TEventCursorData* cursorData = static_cast<GHOST_TEventCursorData*>(eventData);
886                 GHOST_TInt32 x, y;
887                 m_mainWindow->screenToClient(cursorData->x, cursorData->y, x, y);
888                 m_mouse->ConvertMoveEvent(x, y);
889                 handled = true;
890         }
891         return handled;
892 }
893
894
895 bool GPG_Application::handleKey(GHOST_IEvent* event, bool isDown)
896 {
897         bool handled = false;
898         MT_assert(event);
899         if (m_keyboard)
900         {
901                 GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
902                 GHOST_TEventKeyData* keyData = static_cast<GHOST_TEventKeyData*>(eventData);
903                 //no need for this test
904                 //if (fSystem->getFullScreen()) {
905                         if (keyData->key == GHOST_kKeyEsc && !m_keyboard->m_hookesc && !m_isEmbedded) {
906                                 m_exitRequested = KX_EXIT_REQUEST_OUTSIDE;
907                         }
908                 //}
909                 m_keyboard->ConvertEvent(keyData->key, isDown);
910                 handled = true;
911         }
912         return handled;
913 }
914
915
916
917 static void frameTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 time)
918 {
919         GHOST_IWindow* window = (GHOST_IWindow*)task->getUserData();
920         if (fSystem->validWindow(window)) {
921                 window->invalidate();
922         }
923 }