From 53f343edd785f346dccdf39dedfe7626260b63a5 Mon Sep 17 00:00:00 2001 From: Benoit Bolsee Date: Sat, 1 Sep 2012 21:23:05 +0000 Subject: ..\commmit_hive.txt --- .../BlenderRoutines/BL_KetsjiEmbedStart.cpp | 184 ++++++++++++++------- source/gameengine/GamePlayer/ghost/GPG_ghost.cpp | 76 ++++++++- source/gameengine/Ketsji/CMakeLists.txt | 2 + source/gameengine/Ketsji/KX_PythonInit.cpp | 19 ++- source/gameengine/Ketsji/KX_PythonInit.h | 10 ++ source/gameengine/Ketsji/KX_PythonMain.cpp | 78 +++++++++ source/gameengine/Ketsji/KX_PythonMain.h | 41 +++++ 7 files changed, 343 insertions(+), 67 deletions(-) create mode 100644 source/gameengine/Ketsji/KX_PythonMain.cpp create mode 100644 source/gameengine/Ketsji/KX_PythonMain.h (limited to 'source/gameengine') diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp index 1b8f857c2cb..feec67b509a 100644 --- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp +++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp @@ -54,6 +54,7 @@ #include "KX_BlenderSceneConverter.h" #include "KX_PythonInit.h" #include "KX_PyConstraintBinding.h" +#include "KX_PythonMain.h" #include "RAS_GLExtensionManager.h" #include "RAS_OpenGLRasterizer.h" @@ -79,6 +80,9 @@ extern "C" { #include "DNA_windowmanager_types.h" #include "BKE_global.h" #include "BKE_report.h" + +#include "MEM_guardedalloc.h" + /* #include "BKE_screen.h" */ /* cant include this because of 'new' function name */ extern float BKE_screen_view3d_zoom_to_fac(float camzoom); @@ -121,6 +125,95 @@ static BlendFileData *load_game_data(char *filename) return bfd; } +int BL_KetsjiNextFrame(struct KX_KetsjiEngine* ketsjiengine, struct bContext *C, struct wmWindow* win, struct Scene* scene, struct ARegion *ar, + KX_BlenderKeyboardDevice* keyboarddevice, KX_BlenderMouseDevice* mousedevice, int draw_letterbox) +{ + int exitrequested; + + // first check if we want to exit + exitrequested = ketsjiengine->GetExitCode(); + + // kick the engine + bool render = ketsjiengine->NextFrame(); + + if (render) + { + if(draw_letterbox) { + // Clear screen to border color + // We do this here since we set the canvas to be within the frames. This means the engine + // itself is unaware of the extra space, so we clear the whole region for it. + glClearColor(scene->gm.framing.col[0], scene->gm.framing.col[1], scene->gm.framing.col[2], 1.0f); + glViewport(ar->winrct.xmin, ar->winrct.ymin, + BLI_RCT_SIZE_X(&ar->winrct), BLI_RCT_SIZE_Y(&ar->winrct)); + glClear(GL_COLOR_BUFFER_BIT); + } + + // render the frame + ketsjiengine->Render(); + } + + wm_window_process_events_nosleep(); + + // test for the ESC key + //XXX while (qtest()) + while(wmEvent *event= (wmEvent *)win->queue.first) + { + short val = 0; + //unsigned short event = 0; //XXX extern_qread(&val); + + if (keyboarddevice->ConvertBlenderEvent(event->type,event->val)) + exitrequested = KX_EXIT_REQUEST_BLENDER_ESC; + + /* Coordinate conversion... where + * should this really be? + */ + if (event->type==MOUSEMOVE) { + /* Note, not nice! XXX 2.5 event hack */ + val = event->x - ar->winrct.xmin; + mousedevice->ConvertBlenderEvent(MOUSEX, val); + + val = ar->winy - (event->y - ar->winrct.ymin) - 1; + mousedevice->ConvertBlenderEvent(MOUSEY, val); + } + else { + mousedevice->ConvertBlenderEvent(event->type,event->val); + } + + BLI_remlink(&win->queue, event); + wm_event_free(event); + } + + if(win != CTX_wm_window(C)) { + exitrequested= KX_EXIT_REQUEST_OUTSIDE; /* window closed while bge runs */ + } + return exitrequested; +} + +struct BL_KetsjiNextFrameState { + struct KX_KetsjiEngine* ketsjiengine; + struct bContext *C; + struct wmWindow* win; + struct Scene* scene; + struct ARegion *ar; + KX_BlenderKeyboardDevice* keyboarddevice; + KX_BlenderMouseDevice* mousedevice; + int draw_letterbox; +} ketsjinextframestate; + +int BL_KetsjiPyNextFrame(void *state0) +{ + BL_KetsjiNextFrameState *state = (BL_KetsjiNextFrameState *) state0; + return BL_KetsjiNextFrame( + state->ketsjiengine, + state->C, + state->win, + state->scene, + state->ar, + state->keyboarddevice, + state->mousedevice, + state->draw_letterbox); +} + extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *cam_frame, int always_use_expand_framing) { /* context values */ @@ -346,6 +439,7 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c rasterizer->SetBackColor(scene->gm.framing.col[0], scene->gm.framing.col[1], scene->gm.framing.col[2], 0.0f); } + char *python_main = NULL; if (exitrequested != KX_EXIT_REQUEST_QUIT_GAME) { if (rv3d->persp != RV3D_CAMOB) @@ -440,71 +534,47 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c // Could be in StartEngine set the framerate, we need the scene to do this ketsjiengine->SetAnimFrameRate(FPS); + char *python_main = NULL; + pynextframestate.state = NULL; + pynextframestate.func = NULL; +#ifdef WITH_PYTHON + python_main = KX_GetPythonMain(scene); +#endif // WITH_PYTHON // the mainloop printf("\nBlender Game Engine Started\n"); - while (!exitrequested) - { - // first check if we want to exit - exitrequested = ketsjiengine->GetExitCode(); - - // kick the engine - bool render = ketsjiengine->NextFrame(); - - if (render) - { - if (draw_letterbox) { - // Clear screen to border color - // We do this here since we set the canvas to be within the frames. This means the engine - // itself is unaware of the extra space, so we clear the whole region for it. - glClearColor(scene->gm.framing.col[0], scene->gm.framing.col[1], scene->gm.framing.col[2], 1.0f); - glViewport(ar->winrct.xmin, ar->winrct.ymin, - BLI_RCT_SIZE_X(&ar->winrct), BLI_RCT_SIZE_Y(&ar->winrct)); - glClear(GL_COLOR_BUFFER_BIT); - } - - // render the frame - ketsjiengine->Render(); - } - - wm_window_process_events_nosleep(); - - // test for the ESC key - //XXX while (qtest()) - while(wmEvent *event= (wmEvent *)win->queue.first) + if (python_main) { + char *python_code = KX_GetPythonCode(blenderdata, python_main); + if (python_code) { +#ifdef WITH_PYTHON + ketsjinextframestate.ketsjiengine = ketsjiengine; + ketsjinextframestate.C = C; + ketsjinextframestate.win = win; + ketsjinextframestate.scene = scene; + ketsjinextframestate.ar = ar; + ketsjinextframestate.keyboarddevice = keyboarddevice; + ketsjinextframestate.mousedevice = mousedevice; + ketsjinextframestate.draw_letterbox = draw_letterbox; + + pynextframestate.state = &ketsjinextframestate; + pynextframestate.func = &BL_KetsjiPyNextFrame; + printf("Yielding control to Python script '%s'...\n", python_main); + PyRun_SimpleString(python_code); + printf("Exit Python script '%s'\n", python_main); +#endif // WITH_PYTHON + MEM_freeN(python_code); + } + } + else { + while (!exitrequested) { - short val = 0; - //unsigned short event = 0; //XXX extern_qread(&val); - - if (keyboarddevice->ConvertBlenderEvent(event->type,event->val)) - exitrequested = KX_EXIT_REQUEST_BLENDER_ESC; - - /* Coordinate conversion... where - * should this really be? - */ - if (event->type==MOUSEMOVE) { - /* Note, not nice! XXX 2.5 event hack */ - val = event->x - ar->winrct.xmin; - mousedevice->ConvertBlenderEvent(MOUSEX, val); - - val = ar->winy - (event->y - ar->winrct.ymin) - 1; - mousedevice->ConvertBlenderEvent(MOUSEY, val); - } - else { - mousedevice->ConvertBlenderEvent(event->type,event->val); - } - - BLI_remlink(&win->queue, event); - wm_event_free(event); - } - - if (win != CTX_wm_window(C)) { - exitrequested= KX_EXIT_REQUEST_OUTSIDE; /* window closed while bge runs */ + exitrequested = BL_KetsjiNextFrame(ketsjiengine, C, win, scene, ar, keyboarddevice, mousedevice, draw_letterbox); } } printf("Blender Game Engine Finished\n"); exitstring = ketsjiengine->GetExitString(); - gs = *(ketsjiengine->GetGlobalSettings()); + if (python_main) MEM_freeN(python_main); + gs = *(ketsjiengine->GetGlobalSettings()); // when exiting the mainloop #ifdef WITH_PYTHON diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp index 41f641b4368..f4d4f774db2 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp @@ -47,6 +47,7 @@ #endif // __APPLE__ #include "KX_KetsjiEngine.h" #include "KX_PythonInit.h" +#include "KX_PythonMain.h" /********************************** * Begin Blender include block @@ -332,6 +333,40 @@ static BlendFileData *load_game_data(const char *progname, char *filename = NULL return bfd; } +bool GPG_NextFrame(GHOST_ISystem* system, GPG_Application *app, int &exitcode, STR_String &exitstring, GlobalSettings *gs) +{ + bool run = true; + system->processEvents(false); + system->dispatchEvents(); + if ((exitcode = app->getExitRequested())) + { + run = false; + exitstring = app->getExitString(); + *gs = *app->getGlobalSettings(); + } + return run; +} + +struct GPG_NextFrameState { + GHOST_ISystem* system; + GPG_Application *app; + GlobalSettings *gs; +} gpg_nextframestate; + +int GPG_PyNextFrame(void *state0) +{ + GPG_NextFrameState *state = (GPG_NextFrameState *) state0; + int exitcode; + STR_String exitstring; + bool run = GPG_NextFrame(state->system, state->app, exitcode, exitstring, state->gs); + if (run) return 0; + else { + if (exitcode) + fprintf(stderr, "Exit code %d: %s\n", exitcode, exitstring.ReadPtr()); + return 1; + } +} + int main(int argc, char** argv) { int i; @@ -966,17 +1001,39 @@ int main(int argc, char** argv) // Enter main loop bool run = true; - while (run) + char *python_main = NULL; + pynextframestate.state = NULL; + pynextframestate.func = NULL; +#ifdef WITH_PYTHON + python_main = KX_GetPythonMain(scene); +#endif // WITH_PYTHON + if (python_main) { - system->processEvents(false); - system->dispatchEvents(); - app.EngineNextFrame(); - - if ((exitcode = app.getExitRequested())) + char *python_code = KX_GetPythonCode(maggie, python_main); + if (python_code) + { +#ifdef WITH_PYTHON + gpg_nextframestate.system = system; + gpg_nextframestate.app = &app; + gpg_nextframestate.gs = &gs; + pynextframestate.state = &gpg_nextframestate; + pynextframestate.func = &GPG_PyNextFrame; + + printf("Yielding control to Python script '%s'...\n", python_main); + PyRun_SimpleString(python_code); + printf("Exit Python script '%s'\n", python_main); +#endif // WITH_PYTHON + MEM_freeN(python_code); + } + else { + fprintf(stderr, "ERROR: cannot yield control to Python: no Python text data block named '%s'\n", python_main); + } + } + else + { + while (run) { - run = false; - exitstring = app.getExitString(); - gs = *app.getGlobalSettings(); + run = GPG_NextFrame(system, &app, exitcode, exitstring, &gs); } } app.StopGameEngine(); @@ -986,6 +1043,7 @@ int main(int argc, char** argv) system->removeEventConsumer(&app); BLO_blendfiledata_free(bfd); + if (python_main) MEM_freeN(python_main); } } while (exitcode == KX_EXIT_REQUEST_RESTART_GAME || exitcode == KX_EXIT_REQUEST_START_OTHER_GAME); } diff --git a/source/gameengine/Ketsji/CMakeLists.txt b/source/gameengine/Ketsji/CMakeLists.txt index 4b3426e0784..269311b7e00 100644 --- a/source/gameengine/Ketsji/CMakeLists.txt +++ b/source/gameengine/Ketsji/CMakeLists.txt @@ -107,6 +107,7 @@ set(SRC KX_PyMath.cpp KX_PythonInit.cpp KX_PythonInitTypes.cpp + KX_PythonMain.cpp KX_PythonSeq.cpp KX_RadarSensor.cpp KX_RayCast.cpp @@ -189,6 +190,7 @@ set(SRC KX_PyMath.h KX_PythonInit.h KX_PythonInitTypes.h + KX_PythonMain.h KX_PythonSeq.h KX_RadarSensor.h KX_RayCast.h diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index 581b3712f97..86928803502 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -811,6 +811,23 @@ static PyObject *gLibList(PyObject*, PyObject* args) return list; } +struct PyNextFrameState pynextframestate; +static PyObject *gPyNextFrame(PyObject *) +{ + if (pynextframestate.func == NULL) Py_RETURN_NONE; + if (pynextframestate.state == NULL) Py_RETURN_NONE; //should never happen; raise exception instead? + + if (pynextframestate.func(pynextframestate.state)) //nonzero = stop + { + Py_RETURN_TRUE; + } + else // 0 = go on + { + Py_RETURN_FALSE; + } +} + + static struct PyMethodDef game_methods[] = { {"expandPath", (PyCFunction)gPyExpandPath, METH_VARARGS, (const char *)gPyExpandPath_doc}, {"startGame", (PyCFunction)gPyStartGame, METH_VARARGS, (const char *)gPyStartGame_doc}, @@ -840,7 +857,7 @@ static struct PyMethodDef game_methods[] = { {"getBlendFileList", (PyCFunction)gPyGetBlendFileList, METH_VARARGS, (const char *)"Gets a list of blend files in the same directory as the current blend file"}, {"PrintGLInfo", (PyCFunction)pyPrintExt, METH_NOARGS, (const char *)"Prints GL Extension Info"}, {"PrintMemInfo", (PyCFunction)pyPrintStats, METH_NOARGS, (const char *)"Print engine statistics"}, - + {"NextFrame", (PyCFunction)gPyNextFrame, METH_NOARGS, (const char *)"Render next frame (if Python has control)"}, /* library functions */ {"LibLoad", (PyCFunction)gLibLoad, METH_VARARGS|METH_KEYWORDS, (const char *)""}, {"LibNew", (PyCFunction)gLibNew, METH_VARARGS, (const char *)""}, diff --git a/source/gameengine/Ketsji/KX_PythonInit.h b/source/gameengine/Ketsji/KX_PythonInit.h index 866681b9da7..1500dd97ae1 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.h +++ b/source/gameengine/Ketsji/KX_PythonInit.h @@ -70,6 +70,16 @@ class KX_Scene; void KX_SetActiveScene(class KX_Scene* scene); class KX_Scene* KX_GetActiveScene(); class KX_KetsjiEngine* KX_GetActiveEngine(); + +typedef int (*PyNextFrameFunc)(void *); +struct PyNextFrameState { + //state: can be either a GPG_NextFrameState or a BL_KetsjiNextFrameState + void *state; + //func: can be either GPG_PyNextFrame or BL_KetsjiPyNextFrame + PyNextFrameFunc func; +}; +extern struct PyNextFrameState pynextframestate; + #include "MT_Vector3.h" void KX_RasterizerDrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,const MT_Vector3& color); diff --git a/source/gameengine/Ketsji/KX_PythonMain.cpp b/source/gameengine/Ketsji/KX_PythonMain.cpp new file mode 100644 index 00000000000..969ecbea5a9 --- /dev/null +++ b/source/gameengine/Ketsji/KX_PythonMain.cpp @@ -0,0 +1,78 @@ +/* + * $Id: KX_PythonMain.cpp 37750 2011-06-27 09:27:56Z sjoerd $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ +/** \file gameengine/Ketsji/KX_KetsjiPythonMain.cpp + * \ingroup ketsji + */ + +#include "KX_PythonMain.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include "RNA_access.h" +#include "MEM_guardedalloc.h" +#include "BKE_text.h" +#include "BKE_main.h" + +#ifdef __cplusplus +} +#endif + +extern "C" char *KX_GetPythonMain(struct Scene* scene) +{ + //examine custom scene properties + + PointerRNA sceneptr; + RNA_id_pointer_create(&scene->id, &sceneptr); + + PropertyRNA *pymain = RNA_struct_find_property(&sceneptr, "[\"__main__\"]"); + if (pymain == NULL) return NULL; + char *python_main; + int len; + python_main = RNA_property_string_get_alloc(&sceneptr, pymain, NULL, 0, &len); + return python_main; +} + +extern "C" char *KX_GetPythonCode(Main *main, char *python_main) +{ + PointerRNA mainptr, txtptr; + PropertyRNA *texts; + + RNA_main_pointer_create(main, &mainptr); + texts = RNA_struct_find_property(&mainptr, "texts"); + char *python_code = NULL; + int ok = RNA_property_collection_lookup_string(&mainptr, texts, python_main, &txtptr); + if (ok) { + Text *text = (Text *) txtptr.data; + python_code = txt_to_buf(text); + } + return python_code; +} + diff --git a/source/gameengine/Ketsji/KX_PythonMain.h b/source/gameengine/Ketsji/KX_PythonMain.h new file mode 100644 index 00000000000..1460ea2ca96 --- /dev/null +++ b/source/gameengine/Ketsji/KX_PythonMain.h @@ -0,0 +1,41 @@ +/* + * $Id: KX_PythonMain.h 37750 2011-06-27 09:27:56Z sjoerd $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file KX_PythonMain.h + * \ingroup ketsji + */ + +#ifndef __KX_PYTHON_MAIN +#define __KX_PYTHON_MAIN + +#include "BKE_main.h" +#include "DNA_scene_types.h" +extern "C" char *KX_GetPythonMain(struct Scene* scene); +extern "C" char *KX_GetPythonCode(struct Main *main, char *python_main); +#endif -- cgit v1.2.3