svn merge -r 16231:16536 https://svn.blender.org/svnroot/bf-blender/trunk/blender
[blender.git] / source / gameengine / BlenderRoutines / BL_KetsjiEmbedStart.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  * Blender's Ketsji startpoint
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34
35 #include <signal.h>
36 #include <stdlib.h>
37
38 #ifdef WIN32
39 // don't show stl-warnings
40 #pragma warning (disable:4786)
41 #endif
42
43 #include "GL/glew.h"
44
45 #include "KX_BlenderGL.h"
46 #include "KX_BlenderCanvas.h"
47 #include "KX_BlenderKeyboardDevice.h"
48 #include "KX_BlenderMouseDevice.h"
49 #include "KX_BlenderRenderTools.h"
50 #include "KX_BlenderSystem.h"
51 #include "BL_Material.h"
52
53 #include "KX_KetsjiEngine.h"
54 #include "KX_BlenderSceneConverter.h"
55 #include "KX_PythonInit.h"
56 #include "KX_PyConstraintBinding.h"
57
58 #include "RAS_GLExtensionManager.h"
59 #include "RAS_OpenGLRasterizer.h"
60 #include "RAS_VAOpenGLRasterizer.h"
61 #include "RAS_ListRasterizer.h"
62
63 #include "NG_LoopBackNetworkDeviceInterface.h"
64 #include "SND_DeviceManager.h"
65
66 #include "SYS_System.h"
67
68         /***/
69
70 #include "DNA_view3d_types.h"
71 #include "DNA_screen_types.h"
72 #include "BKE_global.h"
73 #include "BIF_screen.h"
74 #include "BIF_scrarea.h"
75
76 #include "BKE_main.h"   
77 #include "BLI_blenlib.h"
78 #include "BLO_readfile.h"
79 #include "DNA_scene_types.h"
80         /***/
81
82 #include "GPU_extensions.h"
83
84 #ifdef __cplusplus
85 extern "C" {
86 #endif
87 #include "BSE_headerbuttons.h"
88 void update_for_newframe();
89 #ifdef __cplusplus
90 }
91 #endif
92
93 static BlendFileData *load_game_data(char *filename) {
94         BlendReadError error;
95         BlendFileData *bfd= BLO_read_from_file(filename, &error);
96         if (!bfd) {
97                 printf("Loading %s failed: %s\n", filename, BLO_bre_as_string(error));
98         }
99         return bfd;
100 }
101
102 extern "C" void StartKetsjiShell(struct ScrArea *area,
103                                                                  char* scenename,
104                                                                  struct Main* maggie1,
105                                                                  struct SpaceIpo *sipo,
106                                                                  int always_use_expand_framing)
107 {
108         int exitrequested = KX_EXIT_REQUEST_NO_REQUEST;
109         
110         Main* blenderdata = maggie1;
111
112         char* startscenename = scenename;
113         char pathname[160];
114         strcpy (pathname, blenderdata->name);
115         STR_String exitstring = "";
116         BlendFileData *bfd= NULL;
117
118         // Acquire Python's GIL (global interpreter lock)
119         // so we can safely run Python code and API calls
120         PyGILState_STATE gilstate = PyGILState_Ensure();
121         
122         PyObject *pyGlobalDict = PyDict_New(); /* python utility storage, spans blend file loading */
123         
124         bgl::InitExtensions(true);
125
126         do
127         {
128                 View3D *v3d= (View3D*) area->spacedata.first;
129
130                 // get some preferences
131                 SYS_SystemHandle syshandle = SYS_GetSystem();
132                 bool properties = (SYS_GetCommandLineInt(syshandle, "show_properties", 0) != 0);
133                 bool usefixed = (SYS_GetCommandLineInt(syshandle, "fixedtime", 0) != 0);
134                 bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0);
135                 bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0);
136                 bool game2ipo = (SYS_GetCommandLineInt(syshandle, "game2ipo", 0) != 0);
137                 bool displaylists = (SYS_GetCommandLineInt(syshandle, "displaylists", 0) != 0);
138                 bool usemat = false, useglslmat = false;
139
140                 if(GLEW_ARB_multitexture && GLEW_VERSION_1_1)
141                         usemat = (SYS_GetCommandLineInt(syshandle, "blender_material", 1) != 0);
142
143                 if(GPU_extensions_minimum_support())
144                         useglslmat = (SYS_GetCommandLineInt(syshandle, "blender_glsl_material", 1) != 0);
145                 else if(G.fileflags & G_FILE_GAME_MAT_GLSL)
146                         usemat = false;
147
148                 // create the canvas, rasterizer and rendertools
149                 RAS_ICanvas* canvas = new KX_BlenderCanvas(area);
150                 canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
151                 RAS_IRenderTools* rendertools = new KX_BlenderRenderTools();
152                 RAS_IRasterizer* rasterizer = NULL;
153                 
154                 if(displaylists) {
155                         if (GLEW_VERSION_1_1)
156                                 rasterizer = new RAS_ListRasterizer(canvas, true, true);
157                         else
158                                 rasterizer = new RAS_ListRasterizer(canvas);
159                 }
160                 else if (GLEW_VERSION_1_1)
161                         rasterizer = new RAS_VAOpenGLRasterizer(canvas, false);
162                 else
163                         rasterizer = new RAS_OpenGLRasterizer(canvas);
164                 
165                 // create the inputdevices
166                 KX_BlenderKeyboardDevice* keyboarddevice = new KX_BlenderKeyboardDevice();
167                 KX_BlenderMouseDevice* mousedevice = new KX_BlenderMouseDevice();
168                 
169                 // create a networkdevice
170                 NG_NetworkDeviceInterface* networkdevice = new
171                         NG_LoopBackNetworkDeviceInterface();
172                 
173                 // get an audiodevice
174                 SND_DeviceManager::Subscribe();
175                 SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance();
176                 audiodevice->UseCD();
177                 
178                 // create a ketsji/blendersystem (only needed for timing and stuff)
179                 KX_BlenderSystem* kxsystem = new KX_BlenderSystem();
180                 
181                 // create the ketsjiengine
182                 KX_KetsjiEngine* ketsjiengine = new KX_KetsjiEngine(kxsystem);
183                 
184                 // set the devices
185                 ketsjiengine->SetKeyboardDevice(keyboarddevice);
186                 ketsjiengine->SetMouseDevice(mousedevice);
187                 ketsjiengine->SetNetworkDevice(networkdevice);
188                 ketsjiengine->SetCanvas(canvas);
189                 ketsjiengine->SetRenderTools(rendertools);
190                 ketsjiengine->SetRasterizer(rasterizer);
191                 ketsjiengine->SetNetworkDevice(networkdevice);
192                 ketsjiengine->SetAudioDevice(audiodevice);
193                 ketsjiengine->SetUseFixedTime(usefixed);
194                 ketsjiengine->SetTimingDisplay(frameRate, profile, properties);
195
196                 
197         
198                 // some blender stuff
199                 MT_CmMatrix4x4 projmat;
200                 MT_CmMatrix4x4 viewmat;
201                 float camzoom;
202                 int i;
203                 
204                 for (i = 0; i < 16; i++)
205                 {
206                         float *viewmat_linear= (float*) v3d->viewmat;
207                         viewmat.setElem(i, viewmat_linear[i]);
208                 }
209                 for (i = 0; i < 16; i++)
210                 {
211                         float *projmat_linear = (float*) area->winmat;
212                         projmat.setElem(i, projmat_linear[i]);
213                 }
214                 
215                 if(v3d->persp==V3D_CAMOB) {
216                         camzoom = (1.41421 + (v3d->camzoom / 50.0));
217                         camzoom *= camzoom;
218                 }
219                 else
220                         camzoom = 2.0;
221
222                 camzoom = 4.0 / camzoom;
223                 
224                 ketsjiengine->SetDrawType(v3d->drawtype);
225                 ketsjiengine->SetCameraZoom(camzoom);
226                 
227                 // if we got an exitcode 3 (KX_EXIT_REQUEST_START_OTHER_GAME) load a different file
228                 if (exitrequested == KX_EXIT_REQUEST_START_OTHER_GAME || exitrequested == KX_EXIT_REQUEST_RESTART_GAME)
229                 {
230                         exitrequested = KX_EXIT_REQUEST_NO_REQUEST;
231                         if (bfd) BLO_blendfiledata_free(bfd);
232                         
233                         char basedpath[240];
234                         // base the actuator filename with respect
235                         // to the original file working directory
236                         if (exitstring != "")
237                                 strcpy(basedpath, exitstring.Ptr());
238
239                         BLI_convertstringcode(basedpath, pathname);
240                         bfd = load_game_data(basedpath);
241                         
242                         // if it wasn't loaded, try it forced relative
243                         if (!bfd)
244                         {
245                                 // just add "//" in front of it
246                                 char temppath[242];
247                                 strcpy(temppath, "//");
248                                 strcat(temppath, basedpath);
249                                 
250                                 BLI_convertstringcode(temppath, pathname);
251                                 bfd = load_game_data(temppath);
252                         }
253                         
254                         // if we got a loaded blendfile, proceed
255                         if (bfd)
256                         {
257                                 blenderdata = bfd->main;
258                                 startscenename = bfd->curscene->id.name + 2;
259                         }
260                         // else forget it, we can't find it
261                         else
262                         {
263                                 exitrequested = KX_EXIT_REQUEST_QUIT_GAME;
264                         }
265                 }
266                 
267                 Scene *blscene = NULL;
268                 if (!bfd)
269                 {
270                         blscene = (Scene*) blenderdata->scene.first;
271                         for (Scene *sce= (Scene*) blenderdata->scene.first; sce; sce= (Scene*) sce->id.next)
272                         {
273                                 if (startscenename == (sce->id.name+2))
274                                 {
275                                         blscene = sce;
276                                         break;
277                                 }
278                         }
279                 } else {
280                         blscene = bfd->curscene;
281                 }
282
283                 if (blscene)
284                 {
285                         int startFrame = blscene->r.cfra;
286                         ketsjiengine->SetGame2IpoMode(game2ipo,startFrame);
287                 }
288
289
290                 // Quad buffered needs a special window.
291                 if (blscene->r.stereomode != RAS_IRasterizer::RAS_STEREO_QUADBUFFERED)
292                         rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) blscene->r.stereomode);
293                 
294                 if (exitrequested != KX_EXIT_REQUEST_QUIT_GAME)
295                 {
296                         if (v3d->persp != V3D_CAMOB)
297                         {
298                                 ketsjiengine->EnableCameraOverride(startscenename);
299                                 ketsjiengine->SetCameraOverrideUseOrtho((v3d->persp == V3D_ORTHO));
300                                 ketsjiengine->SetCameraOverrideProjectionMatrix(projmat);
301                                 ketsjiengine->SetCameraOverrideViewMatrix(viewmat);
302                                 ketsjiengine->SetCameraOverrideClipping(v3d->near, v3d->far);
303                         }
304                         
305                         // create a scene converter, create and convert the startingscene
306                         KX_ISceneConverter* sceneconverter = new KX_BlenderSceneConverter(blenderdata,sipo, ketsjiengine);
307                         ketsjiengine->SetSceneConverter(sceneconverter);
308                         sceneconverter->addInitFromFrame=false;
309                         if (always_use_expand_framing)
310                                 sceneconverter->SetAlwaysUseExpandFraming(true);
311
312                         if(usemat && (G.fileflags & G_FILE_GAME_MAT))
313                                 sceneconverter->SetMaterials(true);
314                         if(useglslmat && (G.fileflags & G_FILE_GAME_MAT_GLSL))
315                                 sceneconverter->SetGLSLMaterials(true);
316                                         
317                         KX_Scene* startscene = new KX_Scene(keyboarddevice,
318                                 mousedevice,
319                                 networkdevice,
320                                 audiodevice,
321                                 startscenename,
322                                 blscene);
323                         
324                         // some python things
325                         PyObject* dictionaryobject = initGamePythonScripting("Ketsji", psl_Lowest);
326                         ketsjiengine->SetPythonDictionary(dictionaryobject);
327                         initRasterizer(rasterizer, canvas);
328                         PyObject *gameLogic = initGameLogic(ketsjiengine, startscene);
329                         PyDict_SetItemString(dictionaryobject, "GameLogic", gameLogic); // Same as importing the module.
330                         PyDict_SetItemString(PyModule_GetDict(gameLogic), "globalDict", pyGlobalDict); // Same as importing the module.
331                         initGameKeys();
332                         initPythonConstraintBinding();
333                         initMathutils();
334
335                         if (sceneconverter)
336                         {
337                                 // convert and add scene
338                                 sceneconverter->ConvertScene(
339                                         startscenename,
340                                         startscene,
341                                         dictionaryobject,
342                                         keyboarddevice,
343                                         rendertools,
344                                         canvas);
345                                 ketsjiengine->AddScene(startscene);
346                                 
347                                 // init the rasterizer
348                                 rasterizer->Init();
349                                 
350                                 // start the engine
351                                 ketsjiengine->StartEngine(true);
352                                 
353
354                                 // Set the animation playback rate for ipo's and actions
355                                 // the framerate below should patch with FPS macro defined in blendef.h
356                                 // Could be in StartEngine set the framerate, we need the scene to do this
357                                 ketsjiengine->SetAnimFrameRate( (((double) blscene->r.frs_sec) / blscene->r.frs_sec_base) );
358                                 
359                                 // the mainloop
360                                 while (!exitrequested)
361                                 {
362                                         // first check if we want to exit
363                                         exitrequested = ketsjiengine->GetExitCode();
364                                         
365                                         // kick the engine
366                                         bool render = ketsjiengine->NextFrame();
367                                         
368                                         if (render)
369                                         {
370                                                 // render the frame
371                                                 ketsjiengine->Render();
372                                         }
373                                         
374                                         // test for the ESC key
375                                         while (qtest())
376                                         {
377                                                 short val; 
378                                                 unsigned short event = extern_qread(&val);
379                                                 
380                                                 if (keyboarddevice->ConvertBlenderEvent(event,val))
381                                                         exitrequested = KX_EXIT_REQUEST_BLENDER_ESC;
382                                                 
383                                                         /* Coordinate conversion... where
384                                                         * should this really be?
385                                                 */
386                                                 if (event==MOUSEX) {
387                                                         val = val - scrarea_get_win_x(area);
388                                                 } else if (event==MOUSEY) {
389                                                         val = scrarea_get_win_height(area) - (val - scrarea_get_win_y(area)) - 1;
390                                                 }
391                                                 
392                                                 mousedevice->ConvertBlenderEvent(event,val);
393                                         }
394                                 }
395                                 exitstring = ketsjiengine->GetExitString();
396                                 
397                                 // when exiting the mainloop
398                                 
399                                 // Clears the dictionary by hand:
400                                 // This prevents, extra references to global variables
401                                 // inside the GameLogic dictionary when the python interpreter is finalized.
402                                 // which allows the scene to safely delete them :)
403                                 // see: (space.c)->start_game
404                                 PyDict_Clear(PyModule_GetDict(gameLogic));
405                                 PyDict_SetItemString(PyModule_GetDict(gameLogic), "globalDict", pyGlobalDict);
406                                 
407                                 ketsjiengine->StopEngine();
408                                 exitGamePythonScripting();
409                                 networkdevice->Disconnect();
410                         }
411                         if (sceneconverter)
412                         {
413                                 delete sceneconverter;
414                                 sceneconverter = NULL;
415                         }
416                 }
417                 // set the cursor back to normal
418                 canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL);
419                 
420                 // clean up some stuff
421                 audiodevice->StopCD();
422                 
423                 if (ketsjiengine)
424                 {
425                         delete ketsjiengine;
426                         ketsjiengine = NULL;
427                 }
428                 if (kxsystem)
429                 {
430                         delete kxsystem;
431                         kxsystem = NULL;
432                 }
433                 if (networkdevice)
434                 {
435                         delete networkdevice;
436                         networkdevice = NULL;
437                 }
438                 if (keyboarddevice)
439                 {
440                         delete keyboarddevice;
441                         keyboarddevice = NULL;
442                 }
443                 if (mousedevice)
444                 {
445                         delete mousedevice;
446                         mousedevice = NULL;
447                 }
448                 if (rasterizer)
449                 {
450                         delete rasterizer;
451                         rasterizer = NULL;
452                 }
453                 if (rendertools)
454                 {
455                         delete rendertools;
456                         rendertools = NULL;
457                 }
458                 if (canvas)
459                 {
460                         delete canvas;
461                         canvas = NULL;
462                 }
463                 SND_DeviceManager::Unsubscribe();
464         
465         } while (exitrequested == KX_EXIT_REQUEST_RESTART_GAME || exitrequested == KX_EXIT_REQUEST_START_OTHER_GAME);
466
467         if (bfd) BLO_blendfiledata_free(bfd);
468
469         // Release Python's GIL
470         PyGILState_Release(gilstate);
471 }
472
473 extern "C" void StartKetsjiShellSimulation(struct ScrArea *area,
474                                                                  char* scenename,
475                                                                  struct Main* maggie,
476                                                                  struct SpaceIpo *sipo,
477                                                                  int always_use_expand_framing)
478 {
479     int exitrequested = KX_EXIT_REQUEST_NO_REQUEST;
480
481         Main* blenderdata = maggie;
482
483         char* startscenename = scenename;
484         char pathname[160];
485         strcpy (pathname, maggie->name);
486         STR_String exitstring = "";
487         BlendFileData *bfd= NULL;
488
489         // Acquire Python's GIL (global interpreter lock)
490         // so we can safely run Python code and API calls
491         PyGILState_STATE gilstate = PyGILState_Ensure();
492
493         bgl::InitExtensions(true);
494
495         do
496         {
497
498                 // get some preferences
499                 SYS_SystemHandle syshandle = SYS_GetSystem();
500                 bool properties = (SYS_GetCommandLineInt(syshandle, "show_properties", 0) != 0);
501                 bool usefixed = (SYS_GetCommandLineInt(syshandle, "fixedtime", 0) != 0);
502                 bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0);
503                 bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0);
504                 bool game2ipo = true;//(SYS_GetCommandLineInt(syshandle, "game2ipo", 0) != 0);
505                 bool displaylists = (SYS_GetCommandLineInt(syshandle, "displaylists", 0) != 0);
506                 bool usemat = false;
507
508                 // create the canvas, rasterizer and rendertools
509                 RAS_ICanvas* canvas = new KX_BlenderCanvas(area);
510                 //canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
511                 RAS_IRenderTools* rendertools = new KX_BlenderRenderTools();
512                 RAS_IRasterizer* rasterizer = NULL;
513
514                 if(displaylists) {
515                         if (GLEW_VERSION_1_1)
516                                 rasterizer = new RAS_ListRasterizer(canvas, true, true);
517                         else
518                                 rasterizer = new RAS_ListRasterizer(canvas);
519                 }
520                 else if (GLEW_VERSION_1_1)
521                         rasterizer = new RAS_VAOpenGLRasterizer(canvas, false);
522                 else
523                         rasterizer = new RAS_OpenGLRasterizer(canvas);
524
525                 // create the inputdevices
526                 KX_BlenderKeyboardDevice* keyboarddevice = new KX_BlenderKeyboardDevice();
527                 KX_BlenderMouseDevice* mousedevice = new KX_BlenderMouseDevice();
528
529                 // create a networkdevice
530                 NG_NetworkDeviceInterface* networkdevice = new
531                         NG_LoopBackNetworkDeviceInterface();
532
533                 // get an audiodevice
534                 SND_DeviceManager::Subscribe();
535                 SND_IAudioDevice* audiodevice = SND_DeviceManager::Instance();
536                 audiodevice->UseCD();
537
538                 // create a ketsji/blendersystem (only needed for timing and stuff)
539                 KX_BlenderSystem* kxsystem = new KX_BlenderSystem();
540
541                 // create the ketsjiengine
542                 KX_KetsjiEngine* ketsjiengine = new KX_KetsjiEngine(kxsystem);
543
544                 Scene *blscene = NULL;
545                 if (!bfd)
546                 {
547                         blscene = (Scene*) maggie->scene.first;
548                         for (Scene *sce= (Scene*) maggie->scene.first; sce; sce= (Scene*) sce->id.next)
549                         {
550                                 if (startscenename == (sce->id.name+2))
551                                 {
552                                         blscene = sce;
553                                         break;
554                                 }
555                         }
556                 } else {
557                         blscene = bfd->curscene;
558                 }
559         int cframe = 1, startFrame;
560                 if (blscene)
561                 {
562                         cframe=blscene->r.cfra;
563                         startFrame = blscene->r.sfra;
564                         blscene->r.cfra=startFrame;
565                         update_for_newframe();
566                         ketsjiengine->SetGame2IpoMode(game2ipo,startFrame);
567                 }
568
569                 // Quad buffered needs a special window.
570                 if (blscene->r.stereomode != RAS_IRasterizer::RAS_STEREO_QUADBUFFERED)
571                         rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) blscene->r.stereomode);
572
573                 if (exitrequested != KX_EXIT_REQUEST_QUIT_GAME)
574                 {
575                         // create a scene converter, create and convert the startingscene
576                         KX_ISceneConverter* sceneconverter = new KX_BlenderSceneConverter(maggie,sipo, ketsjiengine);
577                         ketsjiengine->SetSceneConverter(sceneconverter);
578                         sceneconverter->addInitFromFrame=true;
579                         
580                         if (always_use_expand_framing)
581                                 sceneconverter->SetAlwaysUseExpandFraming(true);
582
583                         if(usemat)
584                                 sceneconverter->SetMaterials(true);
585
586                         KX_Scene* startscene = new KX_Scene(keyboarddevice,
587                                 mousedevice,
588                                 networkdevice,
589                                 audiodevice,
590                                 startscenename,
591                                 blscene);
592
593                         // some python things
594                         PyObject* dictionaryobject = initGamePythonScripting("Ketsji", psl_Lowest);
595                         ketsjiengine->SetPythonDictionary(dictionaryobject);
596                         initRasterizer(rasterizer, canvas);
597                         PyObject *gameLogic = initGameLogic(ketsjiengine, startscene);
598                         PyDict_SetItemString(dictionaryobject, "GameLogic", gameLogic); // Same as importing the module
599                         initGameKeys();
600                         initPythonConstraintBinding();
601                         initMathutils();
602
603                         if (sceneconverter)
604                         {
605                                 // convert and add scene
606                                 sceneconverter->ConvertScene(
607                                         startscenename,
608                                         startscene,
609                                         dictionaryobject,
610                                         keyboarddevice,
611                                         rendertools,
612                                         canvas);
613                                 ketsjiengine->AddScene(startscene);
614
615                                 // start the engine
616                                 ketsjiengine->StartEngine(false);
617                                 
618                                 ketsjiengine->SetUseFixedTime(true);
619                                 
620                                 ketsjiengine->SetTicRate(
621                                         (double) blscene->r.frs_sec /
622                                         (double) blscene->r.frs_sec_base);
623
624                                 // the mainloop
625                                 while ((blscene->r.cfra<=blscene->r.efra)&&(!exitrequested))
626                                 {
627                     printf("frame %i\n",blscene->r.cfra);
628                     // first check if we want to exit
629                                         exitrequested = ketsjiengine->GetExitCode();
630         
631                                         // kick the engine
632                                         ketsjiengine->NextFrame();
633                                     blscene->r.cfra=blscene->r.cfra+1;
634                                     update_for_newframe();
635                                         
636                                 }
637                                 exitstring = ketsjiengine->GetExitString();
638                         }
639                         if (sceneconverter)
640                         {
641                                 delete sceneconverter;
642                                 sceneconverter = NULL;
643                         }
644                 }
645                 blscene->r.cfra=cframe;
646                 // set the cursor back to normal
647                 canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL);
648
649                 // clean up some stuff
650                 audiodevice->StopCD();
651                 if (ketsjiengine)
652                 {
653                         delete ketsjiengine;
654                         ketsjiengine = NULL;
655                 }
656                 if (kxsystem)
657                 {
658                         delete kxsystem;
659                         kxsystem = NULL;
660                 }
661                 if (networkdevice)
662                 {
663                         delete networkdevice;
664                         networkdevice = NULL;
665                 }
666                 if (keyboarddevice)
667                 {
668                         delete keyboarddevice;
669                         keyboarddevice = NULL;
670                 }
671                 if (mousedevice)
672                 {
673                         delete mousedevice;
674                         mousedevice = NULL;
675                 }
676                 SND_DeviceManager::Unsubscribe();
677
678         } while (exitrequested == KX_EXIT_REQUEST_RESTART_GAME || exitrequested == KX_EXIT_REQUEST_START_OTHER_GAME);
679         if (bfd) BLO_blendfiledata_free(bfd);
680
681         // Release Python's GIL
682         PyGILState_Release(gilstate);
683 }