Code cleanup: remove readblenfile module, only contained some utility functions
[blender-staging.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 /** \file gameengine/GamePlayer/ghost/GPG_Application.cpp
32  *  \ingroup player
33  */
34
35
36 #ifdef WIN32
37         #pragma warning (disable:4786) // suppress stl-MSVC debug info warning
38         #include <windows.h>
39 #endif
40
41 #include "GL/glew.h"
42 #include "GPU_extensions.h"
43
44 #include "GPG_Application.h"
45
46 #include <iostream>
47 #include <MT_assert.h>
48 #include <stdlib.h>
49
50 /**********************************
51  * Begin Blender include block
52  **********************************/
53 #ifdef __cplusplus
54 extern "C"
55 {
56 #endif  // __cplusplus
57 #include "BLI_blenlib.h"
58 #include "BLO_readfile.h"
59 #include "BKE_global.h"
60 #include "BKE_main.h"
61 #include "BKE_sound.h"
62 #include "IMB_imbuf.h"
63 #include "DNA_scene_types.h"
64 #ifdef __cplusplus
65 }
66 #endif // __cplusplus
67 /**********************************
68  * End Blender include block
69  **********************************/
70
71
72 #include "BL_System.h"
73 #include "KX_KetsjiEngine.h"
74
75 // include files needed by "KX_BlenderSceneConverter.h"
76 #include "CTR_Map.h"
77 #include "SCA_IActuator.h"
78 #include "RAS_MeshObject.h"
79 #include "RAS_OpenGLRasterizer.h"
80 #include "RAS_VAOpenGLRasterizer.h"
81 #include "RAS_ListRasterizer.h"
82 #include "RAS_GLExtensionManager.h"
83 #include "KX_PythonInit.h"
84 #include "KX_PyConstraintBinding.h"
85 #include "BL_Material.h" // MAXTEX
86
87 #include "KX_BlenderSceneConverter.h"
88 #include "NG_LoopBackNetworkDeviceInterface.h"
89
90 #include "GPC_MouseDevice.h"
91 #include "GPC_RenderTools.h"
92 #include "GPG_Canvas.h" 
93 #include "GPG_KeyboardDevice.h"
94 #include "GPG_System.h"
95
96 #include "STR_String.h"
97
98 #include "GHOST_ISystem.h"
99 #include "GHOST_IEvent.h"
100 #include "GHOST_IEventConsumer.h"
101 #include "GHOST_IWindow.h"
102 #include "GHOST_Rect.h"
103
104 static void frameTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 time);
105
106 static GHOST_ISystem* fSystem = 0;
107 static const int kTimerFreq = 10;
108
109 GPG_Application::GPG_Application(GHOST_ISystem* system)
110         : m_startSceneName(""), 
111           m_startScene(0),
112           m_maggie(0),
113           m_exitRequested(0),
114           m_system(system), 
115           m_mainWindow(0), 
116           m_frameTimer(0), 
117           m_cursor(GHOST_kStandardCursorFirstCursor),
118           m_engineInitialized(0), 
119           m_engineRunning(0), 
120           m_isEmbedded(false),
121           m_ketsjiengine(0),
122           m_kxsystem(0), 
123           m_keyboard(0), 
124           m_mouse(0), 
125           m_canvas(0), 
126           m_rendertools(0), 
127           m_rasterizer(0), 
128           m_sceneconverter(0),
129           m_networkdevice(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         const GHOST_TUns16 samples)
238 {
239         bool success = false;
240
241         RECT rc;
242         if (GetWindowRect(parentWindow, &rc))
243         {
244                 int windowWidth = rc.right - rc.left;
245                 int windowHeight = rc.bottom - rc.top;
246                 STR_String title = "";
247                                                         
248                 m_mainWindow = fSystem->createWindow(title, 0, 0, windowWidth, windowHeight, GHOST_kWindowStateMinimized,
249                         GHOST_kDrawingContextTypeOpenGL, stereoVisual, samples);
250                 if (!m_mainWindow) {
251                         printf("error: could not create main window\n");
252                         exit(-1);
253                 }
254
255                 HWND ghost_hwnd = findGhostWindowHWND(m_mainWindow);
256                 if (!ghost_hwnd) {
257                         printf("error: could find main window\n");
258                         exit(-1);
259                 }
260
261                 SetParent(ghost_hwnd, parentWindow);
262                 LONG style = GetWindowLong(ghost_hwnd, GWL_STYLE);
263                 LONG exstyle = GetWindowLong(ghost_hwnd, GWL_EXSTYLE);
264
265                 RECT adjrc = { 0, 0, windowWidth, windowHeight };
266                 AdjustWindowRectEx(&adjrc, style, FALSE, exstyle);
267
268                 style = (style & (~(WS_POPUP|WS_OVERLAPPEDWINDOW|WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_TILEDWINDOW ))) | WS_CHILD;
269                 SetWindowLong(ghost_hwnd, GWL_STYLE, style);
270                 SetWindowPos(ghost_hwnd, NULL, adjrc.left, adjrc.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE);
271
272                 /* Check the size of the client rectangle of the window and resize the window
273                  * so that the client rectangle has the size requested.
274                  */
275                 m_mainWindow->setClientSize(windowWidth, windowHeight);
276
277                 success = initEngine(m_mainWindow, stereoMode);
278                 if (success) {
279                         success = startEngine();
280                 }
281
282         }
283         return success;
284 }
285
286 bool GPG_Application::startScreenSaverFullScreen(
287                 int width,
288                 int height,
289                 int bpp,int frequency,
290                 const bool stereoVisual,
291                 const int stereoMode,
292                 const GHOST_TUns16 samples)
293 {
294         bool ret = startFullScreen(width, height, bpp, frequency, stereoVisual, stereoMode, samples);
295         if (ret)
296         {
297                 HWND ghost_hwnd = findGhostWindowHWND(m_mainWindow);
298                 if (ghost_hwnd != NULL)
299                 {
300                         GetCursorPos(&scr_save_mouse_pos);
301                         ghost_wnd_proc = (WNDPROC) GetWindowLongPtr(ghost_hwnd, GWLP_WNDPROC);
302                         SetWindowLongPtr(ghost_hwnd,GWLP_WNDPROC, (uintptr_t) screenSaverWindowProc);
303                 }
304         }
305         return ret;
306 }
307
308 #endif
309
310 bool GPG_Application::startWindow(STR_String& title,
311         int windowLeft,
312         int windowTop,
313         int windowWidth,
314         int windowHeight,
315         const bool stereoVisual,
316         const int stereoMode,
317         const GHOST_TUns16 samples)
318 {
319         bool success;
320         // Create the main window
321         //STR_String title ("Blender Player - GHOST");
322         m_mainWindow = fSystem->createWindow(title, windowLeft, windowTop, windowWidth, windowHeight, GHOST_kWindowStateNormal,
323                 GHOST_kDrawingContextTypeOpenGL, stereoVisual, samples);
324         if (!m_mainWindow) {
325                 printf("error: could not create main window\n");
326                 exit(-1);
327         }
328
329         /* Check the size of the client rectangle of the window and resize the window
330          * so that the client rectangle has the size requested.
331          */
332         m_mainWindow->setClientSize(windowWidth, windowHeight);
333         m_mainWindow->setCursorVisibility(false);
334
335         success = initEngine(m_mainWindow, stereoMode);
336         if (success) {
337                 success = startEngine();
338         }
339         return success;
340 }
341
342 bool GPG_Application::startEmbeddedWindow(STR_String& title,
343         const GHOST_TEmbedderWindowID parentWindow, 
344         const bool stereoVisual, 
345         const int stereoMode,
346         const GHOST_TUns16 samples) {
347         GHOST_TWindowState state = GHOST_kWindowStateNormal;
348         if (parentWindow != 0)
349                 state = GHOST_kWindowStateEmbedded;
350         m_mainWindow = fSystem->createWindow(title, 0, 0, 0, 0, state,
351                 GHOST_kDrawingContextTypeOpenGL, stereoVisual, samples, parentWindow);
352
353         if (!m_mainWindow) {
354                 printf("error: could not create main window\n");
355                 exit(-1);
356         }
357         m_isEmbedded = true;
358
359         bool success = initEngine(m_mainWindow, stereoMode);
360         if (success) {
361                 success = startEngine();
362         }
363         return success;
364 }
365
366
367 bool GPG_Application::startFullScreen(
368                 int width,
369                 int height,
370                 int bpp,int frequency,
371                 const bool stereoVisual,
372                 const int stereoMode,
373                 const GHOST_TUns16 samples)
374 {
375         bool success;
376         // Create the main window
377         GHOST_DisplaySetting setting;
378         setting.xPixels = width;
379         setting.yPixels = height;
380         setting.bpp = bpp;
381         setting.frequency = frequency;
382
383         fSystem->beginFullScreen(setting, &m_mainWindow, stereoVisual);
384         m_mainWindow->setCursorVisibility(false);
385         m_mainWindow->setState(GHOST_kWindowStateFullScreen);
386
387         success = initEngine(m_mainWindow, stereoMode);
388         if (success) {
389                 success = startEngine();
390         }
391         return success;
392 }
393
394
395
396
397 bool GPG_Application::StartGameEngine(int stereoMode)
398 {
399         bool success = initEngine(m_mainWindow, stereoMode);
400         
401         if (success)
402                 success = startEngine();
403
404         return success;
405 }
406
407
408
409 void GPG_Application::StopGameEngine()
410 {
411         exitEngine();
412 }
413
414
415
416 bool GPG_Application::processEvent(GHOST_IEvent* event)
417 {
418         bool handled = true;
419
420         switch (event->getType())
421         {
422                 case GHOST_kEventUnknown:
423                         break;
424
425                 case GHOST_kEventButtonDown:
426                         handled = handleButton(event, true);
427                         break;
428
429                 case GHOST_kEventButtonUp:
430                         handled = handleButton(event, false);
431                         break;
432                         
433                 case GHOST_kEventWheel:
434                         handled = handleWheel(event);
435                         break;
436
437                 case GHOST_kEventCursorMove:
438                         handled = handleCursorMove(event);
439                         break;
440
441                 case GHOST_kEventKeyDown:
442                         handleKey(event, true);
443                         break;
444
445                 case GHOST_kEventKeyUp:
446                         handleKey(event, false);
447                         break;
448
449
450                 case GHOST_kEventWindowClose:
451                         m_exitRequested = KX_EXIT_REQUEST_OUTSIDE;
452                         break;
453
454                 case GHOST_kEventWindowActivate:
455                         handled = false;
456                         break;
457                 case GHOST_kEventWindowDeactivate:
458                         handled = false;
459                         break;
460
461                 case GHOST_kEventWindowUpdate:
462                         {
463                                 GHOST_IWindow* window = event->getWindow();
464                                 if (!m_system->validWindow(window)) break;
465                                 // Update the state of the game engine
466                                 if (m_kxsystem && !m_exitRequested)
467                                 {
468                                         // Proceed to next frame
469                                         window->activateDrawingContext();
470
471                                         // first check if we want to exit
472                                         m_exitRequested = m_ketsjiengine->GetExitCode();
473                                         
474                                         // kick the engine
475                                         bool renderFrame = m_ketsjiengine->NextFrame();
476                                         if (renderFrame)
477                                         {
478                                                 // render the frame
479                                                 m_ketsjiengine->Render();
480                                         }
481                                 }
482                                 m_exitString = m_ketsjiengine->GetExitString();
483                         }
484                         break;
485                 
486                 case GHOST_kEventWindowSize:
487                         {
488                         GHOST_IWindow* window = event->getWindow();
489                         if (!m_system->validWindow(window)) break;
490                         if (m_canvas) {
491                                 GHOST_Rect bnds;
492                                 window->getClientBounds(bnds);
493                                 m_canvas->Resize(bnds.getWidth(), bnds.getHeight());
494                         }
495                         }
496                         break;
497                 
498                 default:
499                         handled = false;
500                         break;
501         }
502         return handled;
503 }
504
505
506
507 int GPG_Application::getExitRequested(void)
508 {
509         return m_exitRequested;
510 }
511
512
513
514 const STR_String& GPG_Application::getExitString(void)
515 {
516         return m_exitString;
517 }
518
519
520
521 bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode)
522 {
523         if (!m_engineInitialized)
524         {
525                 GPU_extensions_init();
526                 bgl::InitExtensions(true);
527
528                 // get and set the preferences
529                 SYS_SystemHandle syshandle = SYS_GetSystem();
530                 if (!syshandle)
531                         return false;
532                 
533                 // SYS_WriteCommandLineInt(syshandle, "fixedtime", 0);
534                 // SYS_WriteCommandLineInt(syshandle, "vertexarrays",1);                
535                 GameData *gm= &m_startScene->gm;
536                 bool properties = (SYS_GetCommandLineInt(syshandle, "show_properties", 0) != 0);
537                 bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0);
538                 bool fixedFr = (gm->flag & GAME_ENABLE_ALL_FRAMES);
539
540                 bool showPhysics = (gm->flag & GAME_SHOW_PHYSICS);
541                 SYS_WriteCommandLineInt(syshandle, "show_physics", showPhysics);
542
543                 bool fixed_framerate= (SYS_GetCommandLineInt(syshandle, "fixed_framerate", fixedFr) != 0);
544                 bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0);
545                 bool useLists = (SYS_GetCommandLineInt(syshandle, "displaylists", gm->flag & GAME_DISPLAY_LISTS) != 0);
546                 bool nodepwarnings = (SYS_GetCommandLineInt(syshandle, "ignore_deprecation_warnings", 1) != 0);
547
548                 if(GLEW_ARB_multitexture && GLEW_VERSION_1_1)
549                         m_blendermat = (SYS_GetCommandLineInt(syshandle, "blender_material", 1) != 0);
550
551                 if(GPU_glsl_support())
552                         m_blenderglslmat = (SYS_GetCommandLineInt(syshandle, "blender_glsl_material", 1) != 0);
553                 else if(gm->matmode == GAME_MAT_GLSL)
554                         m_blendermat = false;
555
556                 // create the canvas, rasterizer and rendertools
557                 m_canvas = new GPG_Canvas(window);
558                 if (!m_canvas)
559                         return false;
560                                 
561                 m_canvas->Init();
562                 if (gm->flag & GAME_SHOW_MOUSE)
563                         m_canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL);                             
564
565                 m_rendertools = new GPC_RenderTools();
566                 if (!m_rendertools)
567                         goto initFailed;
568                 
569                 if(useLists) {
570                         if(GLEW_VERSION_1_1)
571                                 m_rasterizer = new RAS_ListRasterizer(m_canvas, true);
572                         else
573                                 m_rasterizer = new RAS_ListRasterizer(m_canvas);
574                 }
575                 else if (GLEW_VERSION_1_1)
576                         m_rasterizer = new RAS_VAOpenGLRasterizer(m_canvas);
577                 else
578                         m_rasterizer = new RAS_OpenGLRasterizer(m_canvas);
579
580                 /* Stereo parameters - Eye Separation from the UI - stereomode from the command-line/UI */
581                 m_rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) stereoMode);
582                 m_rasterizer->SetEyeSeparation(m_startScene->gm.eyeseparation);
583                 
584                 if (!m_rasterizer)
585                         goto initFailed;
586                                                 
587                 // create the inputdevices
588                 m_keyboard = new GPG_KeyboardDevice();
589                 if (!m_keyboard)
590                         goto initFailed;
591                         
592                 m_mouse = new GPC_MouseDevice();
593                 if (!m_mouse)
594                         goto initFailed;
595                         
596                 // create a networkdevice
597                 m_networkdevice = new NG_LoopBackNetworkDeviceInterface();
598                 if (!m_networkdevice)
599                         goto initFailed;
600                         
601                 sound_init(m_maggie);
602
603                 // create a ketsjisystem (only needed for timing and stuff)
604                 m_kxsystem = new GPG_System (m_system);
605                 if (!m_kxsystem)
606                         goto initFailed;
607                 
608                 // create the ketsjiengine
609                 m_ketsjiengine = new KX_KetsjiEngine(m_kxsystem);
610                 
611                 // set the devices
612                 m_ketsjiengine->SetKeyboardDevice(m_keyboard);
613                 m_ketsjiengine->SetMouseDevice(m_mouse);
614                 m_ketsjiengine->SetNetworkDevice(m_networkdevice);
615                 m_ketsjiengine->SetCanvas(m_canvas);
616                 m_ketsjiengine->SetRenderTools(m_rendertools);
617                 m_ketsjiengine->SetRasterizer(m_rasterizer);
618                 m_ketsjiengine->SetNetworkDevice(m_networkdevice);
619
620                 m_ketsjiengine->SetTimingDisplay(frameRate, false, false);
621 #ifdef WITH_PYTHON
622                 CValue::SetDeprecationWarnings(nodepwarnings);
623 #else
624                 (void)nodepwarnings;
625 #endif
626
627                 m_ketsjiengine->SetUseFixedTime(fixed_framerate);
628                 m_ketsjiengine->SetTimingDisplay(frameRate, profile, properties);
629
630                 m_engineInitialized = true;
631         }
632
633         return m_engineInitialized;
634 initFailed:
635         sound_exit();
636         delete m_kxsystem;
637         delete m_networkdevice;
638         delete m_mouse;
639         delete m_keyboard;
640         delete m_rasterizer;
641         delete m_rendertools;
642         delete m_canvas;
643         m_canvas = NULL;
644         m_rendertools = NULL;
645         m_rasterizer = NULL;
646         m_keyboard = NULL;
647         m_mouse = NULL;
648         m_networkdevice = NULL;
649         m_kxsystem = NULL;
650         return false;
651 }
652
653
654
655 bool GPG_Application::startEngine(void)
656 {
657         if (m_engineRunning) {
658                 return false;
659         }
660         
661         // Temporary hack to disable banner display for NaN approved content.
662         /*
663         m_canvas->SetBannerDisplayEnabled(true);        
664         Camera* cam;
665         cam = (Camera*)scene->camera->data;
666         if (cam) {
667         if (((cam->flag) & 48)==48) {
668         m_canvas->SetBannerDisplayEnabled(false);
669         }
670         }
671         else {
672         showError(CString("Camera data invalid."));
673         return false;
674         }
675         */
676         
677         // create a scene converter, create and convert the stratingscene
678         m_sceneconverter = new KX_BlenderSceneConverter(m_maggie, m_ketsjiengine);
679         if (m_sceneconverter)
680         {
681                 STR_String startscenename = m_startSceneName.Ptr();
682                 m_ketsjiengine->SetSceneConverter(m_sceneconverter);
683
684                 //      if (always_use_expand_framing)
685                 //              sceneconverter->SetAlwaysUseExpandFraming(true);
686                 if(m_blendermat && (m_startScene->gm.matmode != GAME_MAT_TEXFACE))
687                         m_sceneconverter->SetMaterials(true);
688                 if(m_blenderglslmat && (m_startScene->gm.matmode == GAME_MAT_GLSL))
689                         m_sceneconverter->SetGLSLMaterials(true);
690
691                 KX_Scene* startscene = new KX_Scene(m_keyboard,
692                         m_mouse,
693                         m_networkdevice,
694                         startscenename,
695                         m_startScene,
696                         m_canvas);
697                 
698 #ifdef WITH_PYTHON
699                         // some python things
700                         PyObject *gameLogic, *gameLogic_keys;
701                         setupGamePython(m_ketsjiengine, startscene, m_maggie, NULL, &gameLogic, &gameLogic_keys, m_argc, m_argv);
702 #endif // WITH_PYTHON
703
704                 //initialize Dome Settings
705                 if(m_startScene->gm.stereoflag == STEREO_DOME)
706                         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);
707
708 #ifdef WITH_PYTHON
709                 // Set the GameLogic.globalDict from marshal'd data, so we can
710                 // load new blend files and keep data in GameLogic.globalDict
711                 loadGamePythonConfig(m_pyGlobalDictString, m_pyGlobalDictString_Length);
712 #endif          
713                 m_sceneconverter->ConvertScene(
714                         startscene,
715                         m_rendertools,
716                         m_canvas);
717                 m_ketsjiengine->AddScene(startscene);
718                 
719                 // Create a timer that is used to kick the engine
720                 if (!m_frameTimer) {
721                         m_frameTimer = m_system->installTimer(0, kTimerFreq, frameTimerProc, m_mainWindow);
722                 }
723                 m_rasterizer->Init();
724                 m_ketsjiengine->StartEngine(true);
725                 m_engineRunning = true;
726                 
727                 // Set the animation playback rate for ipo's and actions
728                 // the framerate below should patch with FPS macro defined in blendef.h
729                 // Could be in StartEngine set the framerate, we need the scene to do this
730                 Scene *scene= startscene->GetBlenderScene(); // needed for macro
731                 m_ketsjiengine->SetAnimFrameRate(FPS);
732         }
733         
734         if (!m_engineRunning)
735         {
736                 stopEngine();
737         }
738         
739         return m_engineRunning;
740 }
741
742
743 void GPG_Application::stopEngine()
744 {
745 #ifdef WITH_PYTHON
746         // GameLogic.globalDict gets converted into a buffer, and sorted in
747         // m_pyGlobalDictString so we can restore after python has stopped
748         // and started between .blend file loads.
749         if(m_pyGlobalDictString) {
750                 delete [] m_pyGlobalDictString;
751                 m_pyGlobalDictString = 0;
752         }
753
754         m_pyGlobalDictString_Length = saveGamePythonConfig(&m_pyGlobalDictString);
755         
756         // when exiting the mainloop
757         exitGamePythonScripting();
758 #endif
759         
760         m_ketsjiengine->StopEngine();
761         m_networkdevice->Disconnect();
762
763         if (m_sceneconverter) {
764                 delete m_sceneconverter;
765                 m_sceneconverter = 0;
766         }
767         if (m_system && m_frameTimer) {
768                 m_system->removeTimer(m_frameTimer);
769                 m_frameTimer = 0;
770         }
771         m_engineRunning = false;
772 }
773
774
775 void GPG_Application::exitEngine()
776 {
777         sound_exit();
778         if (m_ketsjiengine)
779         {
780                 stopEngine();
781                 delete m_ketsjiengine;
782                 m_ketsjiengine = 0;
783         }
784         if (m_kxsystem)
785         {
786                 delete m_kxsystem;
787                 m_kxsystem = 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         GPU_extensions_exit();
821
822         m_exitRequested = 0;
823         m_engineInitialized = false;
824 }
825
826 bool GPG_Application::handleWheel(GHOST_IEvent* event)
827 {
828         bool handled = false;
829         MT_assert(event);
830         if (m_mouse) 
831         {
832                 GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
833                 GHOST_TEventWheelData* wheelData = static_cast<GHOST_TEventWheelData*>(eventData);
834                 GPC_MouseDevice::TButtonId button;
835                 if (wheelData->z > 0)
836                         button = GPC_MouseDevice::buttonWheelUp;
837                 else
838                         button = GPC_MouseDevice::buttonWheelDown;
839                 m_mouse->ConvertButtonEvent(button, true);
840                 handled = true;
841         }
842         return handled;
843 }
844
845 bool GPG_Application::handleButton(GHOST_IEvent* event, bool isDown)
846 {
847         bool handled = false;
848         MT_assert(event);
849         if (m_mouse) 
850         {
851                 GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
852                 GHOST_TEventButtonData* buttonData = static_cast<GHOST_TEventButtonData*>(eventData);
853                 GPC_MouseDevice::TButtonId button;
854                 switch (buttonData->button)
855                 {
856                 case GHOST_kButtonMaskMiddle:
857                         button = GPC_MouseDevice::buttonMiddle;
858                         break;
859                 case GHOST_kButtonMaskRight:
860                         button = GPC_MouseDevice::buttonRight;
861                         break;
862                 case GHOST_kButtonMaskLeft:
863                 default:
864                         button = GPC_MouseDevice::buttonLeft;
865                         break;
866                 }
867                 m_mouse->ConvertButtonEvent(button, isDown);
868                 handled = true;
869         }
870         return handled;
871 }
872
873
874 bool GPG_Application::handleCursorMove(GHOST_IEvent* event)
875 {
876         bool handled = false;
877         MT_assert(event);
878         if (m_mouse && m_mainWindow)
879         {
880                 GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
881                 GHOST_TEventCursorData* cursorData = static_cast<GHOST_TEventCursorData*>(eventData);
882                 GHOST_TInt32 x, y;
883                 m_mainWindow->screenToClient(cursorData->x, cursorData->y, x, y);
884                 m_mouse->ConvertMoveEvent(x, y);
885                 handled = true;
886         }
887         return handled;
888 }
889
890
891 bool GPG_Application::handleKey(GHOST_IEvent* event, bool isDown)
892 {
893         bool handled = false;
894         MT_assert(event);
895         if (m_keyboard)
896         {
897                 GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData();
898                 GHOST_TEventKeyData* keyData = static_cast<GHOST_TEventKeyData*>(eventData);
899                 //no need for this test
900                 //if (fSystem->getFullScreen()) {
901                         if (keyData->key == GHOST_kKeyEsc && !m_keyboard->m_hookesc && !m_isEmbedded) {
902                                 m_exitRequested = KX_EXIT_REQUEST_OUTSIDE;
903                         }
904                 //}
905                 m_keyboard->ConvertEvent(keyData->key, isDown);
906                 handled = true;
907         }
908         return handled;
909 }
910
911
912
913 static void frameTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 time)
914 {
915         GHOST_IWindow* window = (GHOST_IWindow*)task->getUserData();
916         if (fSystem->validWindow(window)) {
917                 window->invalidate();
918         }
919 }