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